Overview of the Tool


  • Common controls: Within the context of Microsoft Windows, a set of controlling elements (windows) that are implemented by the common control library (Comctl32.dll), which is included with the Microsoft Windows operating system. Like other control windows, a common control is a child window that an application uses in conjunction with another window to perform input/output (I/O) tasks.

Back in the early 1990s, two different operating systems were in development at Microsoft. The new platform in development at that time, which was first released in 1993 as Microsoft Windows NT 3.1, was based on the Unicode system of encoding. However, Microsoft Windows 95 to use the Windows code-page model. (For more information on Unicode and code pages, see Chapter 3, "Unicode." )

As a result, application programming interfaces (APIs) that take a character or string parameter behave differently depending on the platform. On Microsoft Windows NT/2000/XP1 these APIs have two versions: Unicode and Windows code pages. The APIs that are based on code pages convert all strings to Unicode, call the Unicode version of the API, and then convert all strings back to the Windows code page associated with the system locale.2 The advantage of using Unicode is that only one version (that is, a single binary) of a Unicode application is needed in order to support multiple languages and scripts.

On Microsoft Windows 95/98/Millennium Edition (Me), there are a few APIs within the system that have both a Windows code-page version and a Unicode version, but all other APIs are exclusively based on code pages. As a result, a Unicode application will not run on Windows 95/98/Me unless the application developer writes a conversion layer between Unicode and the appropriate Windows code page for any system APIs that are used. In addition, because of other text-processing requirements particular to a writing system and its corresponding code page, multiple versions of an an application based on code pages had to be released for different languages (such as for languages in Western, Central, and Eastern Europe, as well as East Asia, and the Middle East).

Initially, it was assumed that developers would circumvent these problems by migrating to Windows NT/2000/XP rather than continue developing products for the Windows 95/98/Me platforms. However, it gradually became apparent that developers were writing applications for Windows NT/2000/XP using Unicode, and then writing a Windows code-page version for Windows 95/98/Me. With MSLU, developers do not need to worry about writing two different versions, but can concentrate on creating a single binary that works on both platforms.

MSLU is a generic conversion layer developed in response to an increasing need for globalized applications that worked just as well on code page-based Windows 95/98/Me systems as they did on Unicode-based NT/2000/XP systems. In other words, this tool bridges the development gap between Windows NT/2000/XP and Windows 95/98/Me that exists by virtue of the difference between the Unicode and code-page model. MSLU is intended for use with any language version of Windows 95/98/Me. It is not needed for Windows NT/2000/XP, since there is no reason to translate Unicode APIs to Windows code-page APIs on these Unicode-based systems. Since Unicode facilitates global development much more than a code page-based model ever can, the future of globalized software rests with Unicode. (For more information, see Chapter 3.) This idea is reinforced by the comprehensive international support built into Windows NT/2000/XP platforms. However, as long as developers need to write applications for Windows 95/98/Me, there has to be an easy way to translate between Unicode functions and functions that are based on code pages. MSLU provides an effective solution.

Nonetheless, MSLU is not a panacea for creating well-globalized applications that run just as well on Windows 95/98/Me as on Windows NT/2000/XP. The architectural challenges inherent in creating a multilingual application on Windows code page-based platforms still exist. First, there is considerably less multilingual support available on Windows 95/98/Me than on Windows NT/2000/XP3 even after implementing MSLU (such as when entering Arabic on Korean versions of Windows 98). Second, MSLU does not make these code page-based platforms support Unicode internally. Third, MSLU was not designed to support existing solutions and components for code page-based platforms that provide their own Unicode functionality, such as MLang (see Chapter 17, "MLang"), Uniscribe (see Chapter 24, "Uniscribe"), Rich Edit (see Chapter 21, "Rich Edit"), common controls, and others. Fourth, you must still follow best practices associated with globalization. (For more information, see the chapters within Part II, "Globalization.") Finally, from an international standpoint, MSLU has a distinct disadvantage when compared to a Unicode platform. While MSLU does provide a Unicode "face" to your applications, it must talk internally to a non-Unicode operating system. Therefore, when your Unicode application that is running on Windows 95/98/Me is limited to a single code page, it is important to make sure that the application behaves properly. A good Unicode application would not be expected to have too many problems. However, you should test your application on each of these three platforms to make sure that nothing breaks and that the user does not lose any data. By first seeing what happens if your application is used beyond what the system can support, you can address any problems before the application is shipped.

Despite these limitations, if you want to ensure that Unicode APIs will be correctly converted for use on Windows 95/98/Me without having to write your own conversion layer, MSLU will fit that need very well. Of course, you can always create your own conversion layer between Unicode and Windows code-page APIs. (For more information, see F. Avery Bishop's article entitled "Design a Single Unicode App that Runs on Both Windows 98 and Windows 2000" at http://www.microsoft.com/msj/0499/multilangUnicode/multilangunicode.htm.) However, one thing that MSLU provides that other layers cannot (or do not) is the conversion of messages sent between different Windows operating systems. Not even the Unicode layer written for Office (as described in Chapter 16, "Microsoft Office") could avoid writing special case code for WM_CHAR or other messages sent between Windows NT/2000/XP and Windows 95/98/Me.

The previous section introduced you to what MSLU is and the advantages it provides. The following sections discuss the elements that comprise MSLU and show how MSLU actually works. They will also demonstrate how to override the loading of MSLU as well as how to override an individual API.

How MSLU Works

MSLU actually consists of two parts. The first part is a dynamic-link library (DLL)-Unicows.dll-that is redistributed with the application that the user creates. The second part is a library (LIB) file-Unicows.lib-that is compiled with this same application. This LIB contains the MSLU loader, which determines whether to load the DLL and call it; alternatively, it can call the original operating-system version of the API. (The former scenario would occur on Windows 95/98/Me; the latter would occur on Windows NT/2000/XP.) The loader also contains all of the necessary failure stubs like the operating system itself does, so that in case the DLL cannot be found, you can gracefully handle the failure of the APIs in your code.

From a technical perspective, the only time your code would ever call the functions in Unicows.dll is when you are using Windows 95/98/Me. Even if you circumvent the loader (for instance, by calling LoadLibrary/GetProcAddress yourself, or by using the P/Invoke syntax of the Microsoft .NET Framework) and call the DLL directly, on an NT/2000/XP platform the DLL will simply forward the call to the API rather than call the MLSU "wrapper" function. This is because the wrapper has less functionality than the full operating-system version, which has full Unicode support. If you are using C or C++, it is not a good idea to intentionally slow yourself down by adding a DLL call you do not need that will simply call the operating system anyway. You can instead decide whether to call the operating-system version of a function or the MSLU version yourself, thus avoiding the performance hit.

With every Unicode wrapper function in MSLU, there must obviously be a conversion to a non-Unicode string. This is usually done using the system default code page (CP_ACP) of the computer-a setting that cannot be changed on Windows 95/98/Me. There are some specific APIs that do not use CP_ACP because they have information in another parameter, such as a locale ID (LCID) value or a device context that would suggest a better code page to use. (For more information, see the MSDN Magazine article listed under "Additional Resources" later in this chapter.)

How (and When) to Handle Overrides

For the most typical uses of MSLU, there is no need to write any code, with two exceptions:

  • When you are overriding the loading of MSLU
  • When you are overriding an individual API


Both of these cases assume you are using the MSLU loader.

If you are using Microsoft C# or Microsoft Visual Basic .NET's P/Invoke mechanism instead of the MSLU loader, you can call the APIs in Unicows.dll directly, and the code in the DLL will determine whether to handle the function itself or to call the operating-system version.

Overriding the Loading of MSLU

There are two steps required to override the loading of MSLU:

  1. Set the "hook" that informs the MSLU loader which function it should call.
  2. Provide the function that the loader will call when it first tries to load the DLL.

The callback function shown in the following code attempts to load the DLL without a path first. This way, if any other component in the process has already loaded the DLL, you can be sure to share the same instance. If the function still fails to find the DLL, it will cause the process to exit. This is the same logic that the loader will use even without an override. Ideal usage of the override would build a path from information in the registry or from some other application-defined location. Exiting is important for a Microsoft Foundation Class (MFC) application, since MFC does not handle the failure of Unicode APIs very well. MFC assumes that certain functions will work. For this reason, an MFC application will crash when trying to dereference a NULL pointer during its initialization-after a call to an API fails-since it does not check for failure in this case.

 extern FARPROC _PfnLoadUnicows = (FARPROC) &LoadUnicowsProc; HMODULE LoadUnicowsProc(void) {  HMODULE hMod = LoadLibraryA("unicows.dll");  if(hMod == 0)  {  // Replace <special dir> with your specific path.  hMod = LoadLibraryA("<special dir>\\unicows.dll");  }  if(hMod == 0)  {  // If the load still failed, then exit.  MessageBoxA(0,   "Unicode wrapper not found",   "My Company",   MB_ICONSTOP | MB_OK);  _exit(-1);  }  return(hMod); } 

You must not call any Unicode APIs from the callback function, since the very first Unicode API that is loaded causes the loader to call this function. If you cause another Unicode API to be called, it will try to call itself again, recursively, until it runs out of stack space. Thus no APIs that MSLU wraps should ever be called from this function.

Overriding an Individual API

The syntax for overriding an API is similar to that for overriding the DLL's load. You simply set a hook to inform the loader of which function it should call, and then provide the actual function. The Microsoft Windows Platform SDK documentation, available at http://msdn.microsoft.com, includes a code sample that overrides the LoadCursorW API. However, the sample here provides an override function for an API that is covered by MSLU only in stub form. This API is OleUIInsertObjectW, which calls the InsertObject method that many applications use to support Microsoft ActiveX object insertion.

 static UINT __stdcall  MyOleUIInsertObjectW (LPOLEUIINSERTOBJECTW lpouiiow) {  UINT result = OLEUI_CANCEL;  OLEUIINSERTOBJECTA ouiioa;  memcpy(&ouiioa, lpouiiow, sizeof (OLEUIINSERTOBJECTA));  ouiioa.lpszFile = (char *)alloca (ouiioa.cchFile + 1);  ouiioa.lpszFile [0] = '\0';  result = OleUIInsertObjectA(&ouiioa);  if (result == OLEUI_SUCCESS)  {  memcpy(lpouiiow,   &ouiioa,   sizeof(OLEUIINSERTOBJECTW));   MultiByteToWideChar(CP_ACP,     0,  ouiioa.lpSzFile,  ouiioa.cchFile,  lpowiiow->lpszFile,  lpowiiow->cchFile);  }  return result; } extern "C" FARPROC Unicows_OleUIInsertObjectW =  (FARPROC)&MyOleUIInsertObjectW; 

Note that the preceding override will only be called on Windows 95/98/Me.

One important limitation of this override is that it is a part of the MSLU loader, so it is only available in C and C++. However, within those languages, you can use the syntax described here to override as many APIs you want. In fact, you could override every API and simply use the MSLU loader around your own application. You could even call the MSLU API after some special processing by making calls to LoadLibrary ("unicows.dll") followed by GetProcAddress- ("<your function>").

Microsoft Corporation - Developing International Software
Developing International Software
ISBN: 0735615837
EAN: 2147483647
Year: 2003
Pages: 198

Similar book on Amazon

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net