Visual Basic 6 Win32 API Tutorial, Page 7
Internally, VB handles its strings as Unicode strings. A Unicode string is just like any other string; the difference is that a character is defined as being 2 bytes long, rather than the standard 1 byte that we're used to. The reason for this is that many languages have more than 256 characters in their alphabets, so Unicode was created to support any language currently used by mankind (can you think of a language that has more than 65,535 characters?).
This usually doesn't impact any VB code, but as soon as you tackle the APIs, you may start to see where the Unicode standard effects you. For example, in our extended WeirdType UDT, we noticed that the byte count went up to 20 when we added the fixed string. If we look at the memory layout, we'll see why an extra 5 bytes have been added:
The string is actually taking up 10 bytes of memory. Although we usually don't see this, DLLs really care about memory allocation, especially when strings are involved. In fact, as we'll see in Chapter 3, a UDT that has a String data type has a size parameter as well. This is to inform the DLL how much memory the UDT is taking up.
Although VB handles strings internally as Unicode strings, it will automatically handle the ANSI/Unicode conversions for us. However, if an API call specifically needs a Unicode string, you have to run though some hoops to do this. For now, we can declare a Byte array to retrieve the information, and then use StrConv to convert the Byte array's information to a string that we're comfortable with.
An API call that ends with the letter W needs Unicode strings. In one of the previous sections, we looked at the FindWindow call. There's a counterpart to the declaration that we made, and it's called FindWindowW in the DLL. You'll notice that our FindWindow call is actually calling FindWindowA. Furthermore, if you ever use the OLE or COM APIs, they only take Unicode strings, so you'll have to use the proper calls to communicate with them. However, to keep things simple we'll stick with the ANSI calls whenever possible in this book.
By the way, don't try looking for Unicode calls in the API Viewer. All of the calls are aliased to use the ANSI version of the call. So if you try to search for FindWindowW, you won't find it. Nor, for that matter, would you find FindWindowA. The only call that will show up is FindWindow, which is actually calling FindWindowA. If you want to find out if a call like FindWindow has a Unicode version of the call, check the Microsoft SDK, or do a Quick View on the DLL that contains the call in question.
So Why 20 Bytes?
Before we leave the issue of strings and Unicode, I wanted to address an issue that, as of the writing of this book, is still unresolved. Let's break down the WeirdType structure element by element. The first one is a byte. Since the second element is a long, we know that VB will add three bytes between the byte variable and the long variable. This gives us 8 bytes. Well, we know the string is 10 bytes in length, so shouldn't that lead to 18 bytes?
You might think that LenB is taking into consideration the null-termination character at the end of the string, or something like that. Two odd things counter this idea, though. If you increase the length of the string to 6, you still get 20 from LenB. Plus, if you define WeirdType in a VB 5.0 application, you'll get 18 from LenB!
I hate pleading ignorance on this subject, but unfortunately I don't have a choice. I wish that I could give you a clear-cut answer as to why this is so, but I can't. Plus, I bet somebody out there has a simple answer as to what's going on. But I've asked some real gurus of the language, and they can't answer this dilemma.
I'm not too thrilled that there is this discrepancy, though, between the two languages. Granted, I doubt anyone's figured out what the byte length of their UDTs are, and stores those values in constants. If somebody did that in 5.0, they have a potentially big surprise coming up when the application gets ported over to 6.0! This goes to show you that, from version to version, VB may change things beneath the scenes. It may be subtle or it may be dramatic, but it happens. Something changed with LenB, and I'd really like to know what that is.
I have a hunch that this might have something to do with the fact that you can now pass UDTs as typed arguments from class modules in 6.0. Maybe the VB designers had to do something below the VB level to pull this off. This gets into issues with COM and marshaling, something that's best left for other discussions, but I wouldn't be surprised if this new feature is a part of the problem