Avoid the Dangers that Lie in Wait When You Port Between Win16 and Win32
Major architectural differences between 16-bit and 32-bit Windows are forcing programmers to re-evaluate both their methods and their code, especially in Visual Basic. If you're one of the thousands of developers needing to either port programs to Win32 or maintain applications in both environments, then you need to know how to make 16-bit VB code portable to 32-bit VB.
Code portability to 32-bit Windows will soon be an issue for all VB developers, especially those who must develop for both Win16 and Win32 simultaneously. While some will only have to port once, Win16 isn't dead yet, and many will need to develop for both environments. I expect that most VB developers will develop applications under Win32 but make them portable to--and test them on--Win16. Unfortunately, the two platforms have a number of differences, particularly when you make direct calls to the Windows API. Although I can't speak specifically about the future release of a 32-bit version of VB, I can outline those areas that it will impact the most and give you strategies for dealing with their effects.
Naming
The first issue is the naming convention. The increasing complexity of the Windows API and overall application architectures will hit hardest those developers without rigorous coding standards. Thus, a consistent naming convention for objects, procedures, and variables is the first place you need to establish order.
In general, you need a portable, prefix-based, pseudo-Hungarian set of guidelines that works well for the Basic language. Why prefix-based? Because there's already a syntax for objects--Form.Control.Property--that goes from most important to least important on that basis. It will soon be extended to, for example, App.Form.Control.Property.
Another example is the new mixed-case naming convention for constants. The type library for Excel 5.0 gives you an idea of what these will look like, e.g., xlWeekdayNameChars, and the VBA type library shows similar names--a harbinger of things to come.
In a more familiar vein, developers making calls to the Windows API need to understand the Hungarian naming (so called for its developer, Charles Simonyi) used in the Windows SDK and similar documentation. While every application and add-on supplier can use whatever naming conventions its developers want, the difficulty in using strange systems ultimately helps to weed the non-standard ones out of the commercial marketplace.
Integers (and Long Integers)
Probably the most obvious change you will see when moving from a 16-bit to a 32-bit environment is the change in system integer size from 16 bits (2 bytes) to 32 bits (4 bytes). A 16-bit system uses Integers wherever possible because it takes the system significantly longer to deal with larger values, such as the 4-byte Long Integers in Win16. In the Win32 API, all parameters have been changed to 4 bytes to reflect the increase in system integer size (which is not necessarily the same size as an Integer; Integers remain 16 bits for compatibility reasons).
Handles and INT arguments will all be Longs in Win32 instead of Integers. In addition to changes in many APIs, the basic message structure of SendMessage and PostMessage has changed from the following form in Win16:
hwnd As Integer
message As Integer
wParam As Integer
lParam As Long
to the following form in Win32:
hwnd As Long
message As Long
wParam As Long
lParam As Long
Strings
Strings are zero-terminated in Windows. Thus, strings cannot contain zeroes. VB strings, however, may contain embedded zeroes. When VB sends a string to a Windows function, VB must convert it to the zero-terminated string that Windows expects. This is probably the biggest problem developers face in dealing with the Windows API.
The format of Basic strings, known as high-level strings (HLSTR), changed little from QuickBasic to VB3. Object linking and embedding (OLE), on the other hand, uses binary strings (BSTR). Microsoft tells developers not to manipulate BSTRs directly because their formats may change. Instead, they should use the string routines SysAllocString, SysAllocStringLen, SysReAllocString, SysReAllocStringLen, SysFreeString, and SysStringLen in the OLE system dynamic link libraries (DLLs). Future versions of VB will use BSTRs.
Unicode
Many Win32 APIs--those either using strings as parameters or returning strings--have two versions: ANSI and Unicode. The ANSI functions have an A suffix while the Unicode versions have a W (for wide). In most cases you will use the A version, particularly if you're coding for Windows 95.
Regular Win16 uses a single-byte ANSI character set where each character requires a single 8-bit byte. Each byte can represent up to 256 distinct values. For many foreign-language character sets (e.g., Cyrillic, Hebrew, Latin, Arabic), this is not enough. Double-byte character sets (DBCSs) are needed; thus, each character can be made up of one or two bytes depending on whether the first character's value falls within a certain range. This variability makes it more complex to determine how long a string is (i.e., how many characters it contains).
Unicode has a better approach to internationalization. Unicode is not a new standard; it was established by Apple and Xerox in 1988 and taken over by a worldwide consortium in 1991. All Unicode characters are 16 bits, which translates into 64K distinct characters. These possibilities are broken into regions for each of the Unicode languages; about half of them are currently defined. Windows NT uses Unicode natively (as does OLE); Windows 95--the core of which is largely based on 16-bit Windows--does not, relying instead upon special DBCS ANSI versions for each locale. To write portable code, VB developers must alias their 32-bit API declarations to the ANSI function names.
User-Defined Types
Some Windows functions use structures known as user-defined types in VB. Two UDTs, RECT and POINTAPI, are used so extensively that they're listed at the beginning of WINAPI.TXT (the VB version of the WINDOWS.H header file that C programmers use to define access to the Windows API). Other Windows-related structures with obvious-sounding names include BITMAPINFO, TEXTMETRIC, and WINDOWPLACEMENT. The advantage of using structures is major when the layout of the structure changes as it did for TEXTMETRIC; (see the Win16 and Win32 versions in Listing 1).
A further wrinkle occurs when the structure contains pointers to strings; such as lpszTargetApp, lpszTargetTopic, and lpszItem in Listing 2. It's been a common lament that VB doesn't use pointers; the truth is that VB does use pointers, but they're used internally and not exposed for your use.
To expose a string's pointer, use the Windows lstrcpy API, which copies one string to another and--here's the important part--returns a pointer to the target string. For instance, the declaration Declare Function lstrcpy Lib "KERNEL" (ByVal lpDestination As String, ByVal lpSource As String) As Long and the line lpsFred = lstrcpy(sFred, sFred) copy the string sFred to itself and return its address, or pointer. You can use this function to dereference the pointers returned in a Windows structure. The following lines show the code required to obtain copies of the strings from the NDDESHAREINFO structure:
result& = lstrcpy(ByVal lpszTargetApp, ByVal ShareInfo.lpszTargetApp)
result& = lstrcpy(ByVal lpszTargetTopic, ByVal ShareInfo.lpszTargetTopic)
result& = lstrcpy(ByVal lpszItem, ByVal ShareInfo.lpszItem)