Windows API Tutorial - Part Two 100153
Hello and welcome to the second and final part of our API tutorial!
Last week we introduced the API and how you can use it within Visual Basic. We went on to get down and dirty with a couple of groovy 'calls'. The first returned the number of milliseconds since Windows had started. The second displayed a message box simple, yet it introduced a few neat concepts, such as arguments, constants and using the 'or' statement as API sticky tape.
As ever, I'm your host Karl Moore and this week we'll be concluding the tutorial with a jam-packed look at:
- Using the API to get the MS Office look
- Grabbing the Windows directory
- Throwing the desktop backdrop onto a form
I'll also run through a few test activities for you to have a play with. We'll then conclude with a few words of advice, two short book reviews, one megacool website and a partridge in a pear tree.
What are you waiting for? Let's go!
Go take a peek at Microsoft Word. Doesn't it look groovy with all those floating toolbars and 3D buttons?
Yet unfortunately Visual Basic doesn't support them instead, we get the completely boring and annoyingly unconfigurable Menu Builder. Perhaps we'll see such wizzy features in a few years time, when everyone has moved onto the latest user interface fad but for now, we're stuck.
Unless of course you spell 'stuck', A-P-I.
Let's do something with Visual Basic you simply couldn't without the Windows API. We're going to add pretty little pictures to our menus, just as the Microsoft products do.
OK, let's get straight down to business:
To perform this feat, I've learned that I'll need to use a staggering four separate API calls. You can find out this type of information from www.vb-world.net/api/ or perhaps www.vbapi.com/ref/ - or maybe one of the other sources mentioned last week. Books are also an excellent starting point for such info we'll be reviewing a couple later. But for now, let's continue:
- Locate the following functions and add each to the 'Selected Items' box: GetMenu, GetSubMenu, GetMenuItemID, SetMenuItemBitmaps
Great you now have the required API 'declarations' on the clipboard.
- Create a new Standard Exe in Visual Basic
- Add a Command Button to Form1
- Insert a module in the project and paste the clipboard declarations:
Public Declare Function GetMenu Lib "user32" _(ByVal hwnd As Long) As LongPublic Declare Function GetSubMenu Lib "user32" _(ByVal hMenu As Long, ByVal nPos As Long) As LongPublic Declare Function GetMenuItemID Lib "user32" _(ByVal hMenu As Long, ByVal nPos As Long) As LongPublic Declare Function SetMenuItemBitmaps Lib "user32" _(ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As _Long, ByVal hBitmapUnchecked As Long, ByVal hBitmapChecked _As Long) As Long
Each of these functions perform a special task that take us one step further toward our final goal of getting images on our menus. The first three simply help get a 'pointer' to the menu item you want to add a picture to, while the last one does the actual work.
Let's briefly explain each of these four calls now. Don't worry if some areas feel a little grey at the moment they'll become clearer later:
- GetMenu This function accepts just one argument, hwnd, the window handle (eg Form1.hWnd). It then follows that handle to find a collection of menus (eg your form menus). If it doesn't find such menu(s), it returns a zero. If it finds any, it returns a number a 'handle' (pointer) to the menu(s)
- GetSubMenu This function accepts two arguments first off, the menu collection 'handle' (hMenu) obtained from the above. Plus, it requires nPos. Don't forget that each 'menu collection' usually includes a number of menus ie, File, Edit, View and Help to name but a few. That nPos specifies the number of the menu you're referring to start with 0 for the first one (which may be, say, File). This function returns the 'ID' of that particular menu
- GetMenuItemID This accepts the sub menu ID from above, plus nPos, the position of the item within that menu. In other words, if you were playing with the File menu, you'd typically have 'New' right at the top (number 0), with 'Open' just below it (number 1), and so on. This call returns the 'ID' of that particular menu item
- SetMenuItemBitmaps This is the function that does the work. With all the above calls, we've been able to gather an exact API-friendly 'pointer' to the menu item we want to add the picture to. This call takes a few parameters (such as the 'handles' we collected above), attempts to add the picture - and returns a 1 if successful
Seems a little long-winded just to add a picture to your menu, doesn't it? I agree. But it's the only way, unless you're willing to get out your cheque book and invest in some expensive third party solution. And there's a big gaping chasm where my wallet used to be, so that option's out the window.
But hey, once you've written this code you can reuse it as many times as you like. So an investment now could mean a payoff later.
Let's carry on with our project:
- Open and click on your form
- Press CTRL + E to load the Menu Editor
Let's add a basic menu to our application:
- In the Caption box, enter: &File
- Tab down and in the Name box, enter: mnuFile
- Click the Next button
You've just created the very top-level menu, File. The ampersand (&) underlines the character after it, turning that letter into a hot key in the instance, File. You'll see what I mean when we get the menu up-and-running.
- Enter the next Caption: &Open
- Type in the name: mnuFileOpen
- Click the à button
Your Open menu should be just below and slightly indented of the File option. This Open is a sub item of the File menu.
- Click the Next button
- Enter a single dash as the Caption
Later, you'll see this dash automatically turns into a separator!
- Enter a name of mnuSep
- Click Next
- Enter the caption: &Exit
- Type in the name: mnuFileExit
Phew! That's your basic menu sorted.
- Click OK
- Press F5 to run your application
Test your menu. It should look something like this:
- Stop the project when you've finished
Note: I understand this is getting a little dry now, so it's time for a quick joke to keep you giggling: A guy joins a monastery and takes a vow of silence. He's allowed to say only two words every 7 years. After the first 7 years, the elders bring him in and ask him for his 2 words. "Cold floors", he says. They nod and send him away. 7 more years pass and they bring him in for his 2 words. He clears his throat and says, "Bad food" They nod and send him away. 7 more years pass and they bring him in for his 2 words. "I quit", he says. "That's not surprising", the elders say... "You've done nothing but complain since you got here!"
Now let's add a picture to your application. This will be the little image to appear on your menu.
- Draw a small PictureBox control on your Form
- Changes its' Visible property to False
It's now time for you to choose the picture you want to appear on your menu. Ideally, you want something with a size of 13 x 13 pixels anything else may become a little distorted. You can easily create your own mini graphics in MSPaint or Paint Shop Pro.
If you're having problems, check out the mini Da Vinci I created in the download below or have a browse in the less-than-ideal folder - Program Files/Microsoft Visual Studio/Common/Graphics/Bitmaps/TlBr_W95/
- Change the Picture property of the PictureBox control to hold your image
Your screen should look something like this:
Wow, this is getting to be one heckuva long webpage so let's start afresh...
Brilliant we now have our menu and the image we want to put 'on it'.
Now let's add some code to get it all working:
- Add the following code behind your Command Button:
Private Sub Command1_Click()On Error Resume NextDim lngMenu As LongDim lngSubMenu As LongDim lngMenuItemID As LongDim lngRet As LonglngMenu = GetMenu(Form1.hwnd)lngSubMenu = GetSubMenu(lngMenu, 0)lngMenuItemID = GetMenuItemID(lngSubMenu, 2)lngRet = SetMenuItemBitmaps(lngMenu, lngMenuItemID, 0, _Picture1.Picture, Picture1.Picture)End Sub
Do you understand what's happening here?
lngMenu = GetMenu(Form1.hwnd)
This grabs the menu collection 'handle' for the entire form.
lngSubMenu = GetSubMenu(lngMenu, 0)
This function visits the 'menu collection' specified in the handle lngMenu and gets the handle of the first (0) menu. In this case, File.
Top Tip: Unfortunately most API calls expect you to count in this peculiar way starting with 0 as the first item, 1 for the second and so on. Just stick with it. This zero-based counting is something that can apply to other areas of Visual Basic too, such as Arrays.
lngMenuItemID = GetMenuItemID(lngSubMenu, 2)
This function checks out the menu referenced in lngSubMenu (such as File) and returns a handle to the third item on it (that's number 2 getting used to this yet?).
Note: In our case, that third item is 'Exit'. That's right, the 'separator' you added counts as one item.
lngRet = SetMenuItemBitmaps(lngMenu, lngMenuItemID, 0, _Picture1.Picture, Picture1.Picture)
This final call just runs the SetMenuItemBitmaps function and passes the return value back to lngRet typically, a 1 indicates success.
We're passing this call a handle to the menus (lngMenu) and a handle to the individual menu item (lngMenuItemID). The third argument requests any 'flags' in other words, special extra bits of information a little like the MB_OK or MB_ICONEXCLAMATION from last week's message box. However I'm not really bothered about this right now, so just threw in a 0.
The final two arguments asked for the handle to two images hBitmapUnchecked and hBitmapChecked respectively. Here, we simply pass the Picture property of Picture1.
"Hold on to your leather panties here for one little minute!", I hear you cry. "That function asks for a handle after all, the name begins with 'h' and the data type is Long. So why are you passing the Picture property of the PictureBox control?"
Well, not many people know this but the Picture property of the PictureBox control simply returns a handle to the holding picture. Try doing a simple 'MsgBox Picture1.Picture' it should return a number, the picture handle.
So you see, it's fine to pass this property direct to the API.
Interesting stuff, eh? What was that? No? Oh, I s'pose you're right actually. Anyway, enough theory. Let's test our project!
- Press F5 to run your application
- Hit the Command Button
Check out the File menu. Do you see what has happened? Following your calls to the API, the image in your Picture Box control has been added to your menu!
And that's something you simply can't do in Visual Basic - without the API.
Note: If you're interested in adding the full Office look to your applications, you can get the entire lowdown at VB Thunder.
A good few years ago, I made one rather drastic mistake. I presumed.
Not just any old presumption, but a whopping great huge presumption that ended in unhappy users and unhappy bosses.
You see, I thought hey, my Windows directory is C:\Windows\ - and therefore, that must be the case for every other computer lover in the entire world.
You see, Windows NT users typically have Windows in a directory called C:\WinNT\ - as I learned. And some picky people opt to choose a different installation path such as C:\Windoze\ - as I learned.
And yet others would go ahead and choose completely different drives to install the operating system, such as F:\Windows\
Still others would do both, such as J:\WinDiddlyDonk\ - I hated those the most.
But hey, I was young and innocent as my users figured when the application crashed due to an incorrect path error. Oops. Still, it taught me never to presume in the wacky world of Windows. Instead, use the API.
<Ed groans: Why did I sense that was coming? >
The API provides a couple of groovy little functions that allow us to grab the main directories such as the Windows directory, System directory and Temporary directory. For the moment, we're just going to look at GetWindowsDirectory:
- Load up the API Viewer
- Find and copy the following declarations: GetWindowsDirectory
- Create a new project in Visual Basic and paste the declaration into a module
Now this declaration is a little different to the ones we have uncovered so far. Why? Well, take a look at it:
Public Declare Function GetWindowsDirectory _ Lib "kernel32" _ Alias "GetWindowsDirectoryA" _ (ByVal lpBuffer As String, ByVal nSize As Long) As Long
Notice that the first parameter requires us to pass a string. We've not done that before and unfortunately it ain't all that simple.
Why? Well, alas, most API DLLs were created in the C programming language. And that means peculiarities. For instance, when dealing with strings, the API adds an extra character to the end a null 'terminator' - so it knows where in memory the string stops.
But VB doesn't use those, so when you get strings back from the API, you have to knock off that end terminator. Also, when you're passing the actual string, you need to tell the API how big the string is so it doesn't put too much information in.
You see, the API doesn't really know what a string is. It talks in terms of memory. So if it tried to put more information in than it should, that extra info could run out of your string and into some other area of memory which could result in a system crash. So remember API calls can cause havoc - save your work regularly.
Anyway, we'll see all of this and more by the end of this lesson. Worried yet? Don't be. I'm here to help you. Promise. Let's go:
- Add a Command Button to your Form
- Place the following code behind the button:
Private Sub Command1_Click() Dim strWinDir As String Dim lngSize As Long strWinDir = Space(255) lngSize = 255 Call GetWindowsDirectory(strWinDir, lngSize - 1) strWinDir = TrimNull(strWinDir) MsgBox strWinDirEnd Sub
Don't run it straight away it won't work properly. First, allow me to explain the code so far:
Dim strWinDir As StringDim lngSize As Long
You know this bit. We're just declaring two variables, as required by the API call one a String, the other a Long.
strWinDir = Space(255)
Now this is an interesting piece of code. The Space function just returns a certain number of spaces, dependant on the number you pass to it. In this case, we sent 255 its way so the function returns 255 spaces.
Huh? So we're setting our string to equal 255 spaces? What's the bloomin' point in that? Well, when we're passing strings to the API, we need to 'pad them out' in other words, set aside 255 spaces in memory, reserved for our string.
Before we added these spaces, Visual Basic didn't know how many characters the string would hold. And that's fine, VB handles all that stuff dynamically. But C doesn't. Oh no. Before you can use a string, C needs to know how much memory it has to work with so we pad it out with duff information to create a memory 'buffer'.
lngSize = 255
This line records the size of that memory buffer. In this case, 255 characters worth. You see, when we call this API function, it asks for two things the string (strWinDir) and how much 'memory' in that string it can play with. We're going to use lngSize to hold that information.
Call GetWindowsDirectory(strWinDir, lngSize - 1)
This is the actual API call. We pass the Windows directory string and the Long. Notice that we actually pass in lngSize minus 1, aka 254. Why? Well, remember I said C adds a null terminator to the end of its strings so it knows where they finish in memory?
Well, this is how we handle it. We're saying "Hey API Guy, here's the strWinDir string. You can use 254 characters of it"
And the API thinks to itself, "Sure, you think I'm only going to use 254 characters but I'm actually going to add one extra character on the end, a null terminator, just so I know where to stop. Haha!"
And we think, "I know what that evil API Guy is like. That's why I actually passed it a string that has space to hold 255 characters in memory. But I only told the API to use a maximum of 254, to account for him naughtily adding the one-character terminator!"
Phew! And now the next line:
strWinDir = TrimNull(strWinDir)
This just calls a function I've written called 'TrimNull'. It basically chops that extra terminator character off the end. We'll add this function in a minute.
But hold on for two twitches of a ducks whisker! As the GetWindowsDirectory declaration shows, we're passing strWinDir to the API 'ByVal'. This means we're passing the variable by value (which simply passes the string data) rather than by reference (which passes a pointer to the string variable).
If you were to typically pass the variable by value the thing you're passing it to can't change the original strWinDir variable. But if you pass by reference, the thing you're passing it to can change the original.
Many of you will already be aware of this common Visual Basic concept. And so you're probably asking how can we, on the line after the ByVal API call, use strWinDir in code like that? You see, really, it should still hold that set of 255 spaces we initially set strWinDir to.
But when you pass strings to an API call 'ByVal' - behind the scenes, Visual Basic actually passes a pointer to the original string. In other words, it passes your string ByRef meaning the API code can change the value of the original string.
I know, I know - don't ask me why, it's just another peculiarity but that's how the API changes strWinDir and allows you to use it later in the code. Just thought I'd attempt an explanation, weird though it may be.
But if you're not familiar with ByVal and ByRef whatnots, you can ignore the last few paragraphs.
<Reader: NOW you tell me!>
And now for that finally line of code:
Here, we're just displaying the strWinDir variable after it's been passed in and out of the API call, then trimmed for nulls.
Let's now add that extra TrimNull function I was talking about:
- Add the following code to your module:
Public Function TrimNull(MyString As String) Dim intPosition As Integer intPosition = InStr(MyString, Chr$(0)) If intPosition Then TrimNull = Left(MyString, intPosition - 1) Else: TrimNull = MyString End If End Function
Once again, this simply checks the passed string for a terminator, Chr(0). If it finds one, it deletes it.
Please, take this function and treasure it. You'll be able to use it in many of the API calls involving strings, making it a jolly useful method to have around.
But now, let's get testing!!
- Run your application and hit the Command Button
What happens? Hopefully and I'm keeping my fingers crossed for you this end the message box should display your Windows path! Well done!
Now that may seem like a lot of work just to get a few characters of information, but you only have to write it once. You could, perhaps, throw the code behind a function, residing in a common module and call it from anywhere within your application.
And it's a lot better than... erm... presuming. D'OH!
Next up, I'd like you to go ahead and attempt a few of your own API calls. Try using the below pair to get both the System and Temporary directory:
Public Declare Function GetSystemDirectory Lib "kernel32" _Alias "GetSystemDirectoryA" _(ByVal lpBuffer As String, ByVal nSize As Long) As LongPublic Declare Function GetTempPath Lib "kernel32" _Alias "GetTempPathA" _(ByVal nSize As Long, ByVal lpBuffer As String) As Long
Go on, follow all the rules we've discussed so far and have a go! Make sure you note how the second one declares it's arguments back-to-front.
You might also want to try the GetComputerName call, also rather similar:
Declare Function GetComputerName Lib "kernel32" Alias "GetComputerNameA" _(ByVal lpBuffer As String, nSize As Long) As Long
Note: A download of the GetWindowsDirectory API call is available here.
Fancy a cunning quickie? Hey, who doesn't...
- Create a new VB project
- Lookup and declare the following in the form:
Private Declare Function PaintDesktop _ Lib "user32" _ (ByVal hdc As Long) As Long
I decided to put this behind a form just to show you it can be done. However when you do declare API calls like this, they have to start with the 'private' keyword and can only be called by that one form.
- On your Form, add a Command Button
- Place the following code behind the button:
Here, our API call is asking for hdc. First off, just remember that any argument that starts with h is a handle, a pointer of some kind.
We've already encountered hWnd, which is the handle of a window even though a 'window' can be anything from a form to a control.
Now the dc bit of hdc stands for 'device context' and is, in effect, a pointer to the 'graphical side of stuff'. So whereas hWnd could be a pointer to a form (or rather, a window), hdc is a pointer to the potentially graphical part of the form. Controls such as the PictureBox also have a hdc property.
And as we're talking to user32.dll in this call that's the user interface part of the Win32 API, remember? you could guess we're doing something slightly visual.
So in this code, we're simple passing the PaintDesktop function your form's graphical pointer, hdc. And this function uses it to... to do what?
I'm not telling, you're going to have to find out yourself but it's very cool and usually only used by desktop replacement programs.
Note: A download of the PaintDesktop project is available here.
In this section, I'll be sending you off on five unique tasks from around the Web.
You'll be asked to disable Ctrl-Alt-Delete key combinations, display that lovely 'Browse for Folders' dialog box, force a Windows restart, get information on a drive, plus display the File Open dialog box without the bulky Common Dialog control.
So, five tasks to complete that will boost your API knowledge no end. Some of these teasers are simple, others more complicated. But each will offer something new and challenging, an awareness of some extra functionality or problem yet to be uncovered.
Please, ensure you complete these tasks before continuing to the end of this tutorial. All ready? Good luck!
- Disabling Ctrl-Alt-Delete - Sometimes you don't want users trying to exit your application using that horrid Ctrl-Alt-Delete combination. So stop them!
- Browse for Folders - You've probably seen the 'Browse for Folders' dialog in applications such as Paint Shop Pro or Frontpage. Well, now you can have it too. Note how you use a special data type here, build it up then pass to the API call. Also, notice that you aren't using one of the standard Win32 DLLs (User32, Kernel32, Gdi32) here.
- Restart Windows - Need to restart Windows after that installation routine? Make users log off, shut down, reboot and more — with this groovy API call.
- Get the Drive Type - Is it a bird, is it a plane? Nope, it's a floppy disk drive. How do you know? Well, that's where this groovy GetDriveType call steps in. Check it out!
- File Open Dialog - You can use the API to display a basic file open dialog box to replace the bulky Common Dialog control that bundles with VB. Note the OPENFILENAME type here, too — as with the Browse Folders section above. It also passes strings around, as we did earlier with the GetWindowsDirectory function.
Have you finished already? Wow. How did you find the tasks?
I can imagine the Browse for Folders and File Open Dialog activities were the most difficult. A new concept was introduced in both those samples types, or User Defined Types (UDTs) to most VB'ers. Some API folk also call them structures.
As an example of this, the File Open Dialog activity used a call titled 'GetOpenFileName'. If you open the API Viewer, you should be able to find this under the Declares section. You'll notice it asks for one parameter 'pOpenfilename As OPENFILENAME'.
If you change the API Type combo to Types, you can look up the 'OPENFILENAME' Visual Basic UDT. And hey look, it's exactly the same as the code in that article!
So you can see the thought process behind this. You now know where the author of that particular article got his information.
Of course, before running that function, the writer had to generally know what it did and how to use it. That may have been discovered via the Microsoft API documentation, another Visual Basic website, one of the variety of sources mentioned earlier — or, heck, it could've just been a darn good guess.
What have we learned from this section? Well, you've reinforced all the API skills you've picked up so far, checked out a few neat calls, plus uncovered the concept of 'types', which you may often find yourself passing to the API.
That's the good news. And now...
Unfortunately in the aromatic garden of API calls, not everything smells of roses. You get the occasional pile of manure, dumped by some ignorant sheep farmer.
And in this section, we're going to briefly cover a couple of the big stinks you may encounter plus give a little advice on how to avoid them.
First up on our naughty-naughty list, we have the API Viewer. Sure, it's been nicer than pie with us so far. But that's because we're just starting out. Once it gets to know you, it's start lying. Yep, lying.
For example, one of the best-known instances of the API Viewer telling a little fib is with the GetPrivateProfileString function, which allows developers to peek inside INI files and return values.
Unfortunately, earlier versions of the API Viewer declared this call incorrectly, causing much 'developer distress', a recognised medical condition. Thankfully this problem has been (debatably) fixed in the VB6 API Viewer, though a few lesser-used declarations are still flawed.
So if you're sure that code is correct but the API still insists on being horribly disobedient be sure to check out either the VB API reference site (www.vbapi.com/ref/) or Microsoft's API documentation (www.microsoft.com/api/) for assistance.
If you've not worked with arrays before, ignore this. Even if you have, you'll probably never need to pass one to an API call. But just in case, a warning - don't pass WholeArrays() direct to API calls. Instead, pass the first element of an array, RatherLikeThis(1). If you wanted the function to start work on the third element of the array onwards, you could pass it SomethingLikeThis(3). Either way, pass elements of an array rather than whole arrays. In addition, when doing this you usually have to pass the size of the arrays along with the API call.
You can't pass the Currency data type to an API call. It's a VB-only thang. Instead, convert it to a Long or Double first.
There are a few other issues you may notice cropping up here and there, too. Buzzwords include memory alignment, the LenB function, subclassing and AddressOf function pointers, but that jargon is just beyond the scope of this API tutorial.
But if you're eager to learn more about all that jazz, read on...
Well you've already picked up a helluva lot from this tutorial. But if you're wanting to take your API skills to the next level, read on.
First off, there's always the eternally groovy API tutorial hosted at www.vbapi.com/articles/intro/index.html
It's not so excellent for the beginner, but hey, that's no longer yourself. You should be able to follow this through, taking you to the next level.
If you're looking for examples to play around with, a general Web search will undoubtedly prove fruitful. You can grab a few general links at About.com here.
And if you have a few bucks spare, there's always the traditional tech book route to follow. Here are two of the best-known API publications:
- Win32 API Tutorial #37/$40 - A well put together tutorial by a guy that's been there, done that. Plenty of practical examples with a lightweight writing style. By Jason Bock. Click here for more information.
- Visual Basic Programmer's Guide to the Win32 API #55/$60 - More a reference book of the top Win32 API functions. Expensive, yet a useful addition to any developer's bookshelf. By Dan Appleman. Click here for more information.
Well, that's it for this section time to get all conclusive...
The truth? You wanna know the truth? Hah, you can't handle the truth.
Still, it's going to be a very short conclusion if I don't tell you so here goes: Visual Basic isn't really Visual Basic. Oh no.
<Reader: So who is it, Karl? Who?>
You see Visual Basic is really just... <Karl steps over to VB and pulls off the wig. There is a mass gasp> ... that's right, a whole bunch of API statements in a very good disguise.
Oh yes. Although Visual Basic hides all the intricacies of its complex API calls under the hood, they're always sitting there, waiting.
Every time you run - Form1.Print "Hello" Visual Basic tootles off and calls the TextOut API function, passing all the required parameters.
And when a user clicks your Command Button, Windows sees this. It then sends a message (via the very popular SendMessage function) to Visual Basic saying, "Hey, some geek just clicked your button". VB analyses the message, realises what's happening then raises the Click event of your Command Button, thereby executing any code within it.
And phew! - the list goes on.
As you can see, Visual Basic hides a lot of stuff from you. In fact, Windows is all really just a whole bunch of API calls cobbled on top of each other.
And in this two-part series, we've taken a peek at some of the things our favourite programming language manages to cover up so very well.
More specifically, today we've looked at giving our application the Office look, discovered how to retrieve the Windows path, plus checked out how to display the desktop background on a form all via the API. We went on to fiddle with a few activity projects, plus found out where you can take your skills from here.
I hope this tutorial has helped you understand more about the API and if I've done my job right, you won't feel too nervous about utilising its potential in future projects.
At times it might seem about as pointless as French marriage vows, but bear with it. You're going under the hood, touching those parts regular code can't reach. And that takes a bit of work but it can be very rewarding too.
People have used the API for allsorts. From simply enhancing their regular programs to building little add-ons that run on top of other applications, such as certain AOL utilities. Some even use the API in conjunction with ActiveX controls (see our tutorial here - www.vb-world.net/activex/controls/) to build lightweight, reusable components.
And now you have the knowledge to do this too. Whatever you get up to please let us know by posting feedback on the bulletin board. You can also mail me personally - email@example.com
But until the next time, this is Karl Moore signing off, concluding this API tutorial and wishing you all the very best in anything you may do. Goodnight!