The "Go" tools
     The GoLink manual

The Microsoft Layer for Unicode

(with particular reference to the "Go" tools)

By Jeremy Gordon -

Note: this article applies only to applications which work in languages which do not need to rely on Unicode to represent them.

The Microsoft Layer for Unicode

The Microsoft Layer for Unicode is one way to make just one version of your application to run both under Windows 95, 98 and ME platforms and also under Windows NT, 2000 and XP platforms.

The "Ansi" application

Traditionally the way to do this for programmers who had no need to represent non-Roman characters (typically "Western" languages) was to call only the Ansi APIs instead of their Unicode counterparts. This was the obvious solution because the Unicode versions of the APIs were mostly not available under Windows 95, 98 and ME. And who needed the Unicode versions anyway, since Western languages didn't have to use Unicode? Doing this resulted in what could be described as an "Ansi application". Such applications worked fine both under Windows 95, 98 and ME and Windows NT, 2000 and XP platforms. But it surprises developers to be told that these applications only work naturally under Windows 95, 98 and ME. If you call an Ansi API under Windows NT 2000 and XP, the system actually ends up calling the Unicode version of the API. In order to do this it needs to convert the Ansi strings to Unicode and also any output from the API from Unicode to Ansi. So if under XP you call MessageBoxA, the Ansi string you pass to that API is converted to Unicode and the system calls MessageBoxW instead.

A new approach: the "Unicode" application

With the enlarged support for multilingual applications and almost exclusive use of Unicode in the operating system, Microsoft recommends that developers now do the opposite of the above.
It is now recommended that developers make all their applications using the Unicode versions of the APIs. But you may say, "if I do that my application will not run under Windows 95, 98 and ME because those Windows versions do not support the Unicode APIs". Well this is where the Microsoft Layer for Unicode (or "mslu") comes in. The mslu is contained in a Dll called "unicows.dll". This is redistributable, so the intention is that you will ship this with your executable for placement in the same folder as your executable.

What unicows.dll does

Basically unicows.dll acts as a wrapper around the Ansi APIs so that they can be called as Unicode APIs under Windows 95, 98 and ME. Provided unicows.dll is installed, you can call the Unicode APIs from your application without worrying that they may return with the dreaded error code 120 decimal ("ERROR_CALL_NOT_IMPLEMENTED"). Instead when you call for example, CreateWindowExW under Windows 95, 98 or ME the Unicode strings that you pass to the API will be converted by unicows.dll to Ansi strings, and then unicows.dll will call CreateWindowExA instead.

Unicows.dll ought not to be involved under Windows NT, 2000 and XP

Under Windows NT, 2000 and XP, if your application is properly linked, unicows.dll will not get involved at all and will not even be loaded into memory. The application calls the Unicode APIs in the correct system Dlls directly. So what is happening here is that under Windows 95, 98 and ME unicows.dll is called, but under NT, 2000 and XP unicows.dll is not called and the system Dll is called instead.

How the switching is achieved

Not all tools can achieve this. It is achieved by the linker inserting in your application's code some special "mslu loader" code. This loader code causes the switch to occur. And since in the executable unicows.dll is never named as a Dll holding imports for the application, but is loaded using LoadLibrary under Windows 95, 98 and ME only, it is not loaded at all at load-time under NT, 2000 and XP.

The way Microsoft gets this loader code into your application is via unicows.lib at link-time. Unfortunately not all tools support this and applications written with some tools will still have to call unicows.dll even when running under NT, 2000 or XP. In this case the switching is done inside unicows.dll itself. Unicows.dll knows the version of Windows being used and will simply pass on the call to the appropriate system Dll under NT, 2000 or XP. The disadvantage of this method is that when unicows.dll loads, it also loads a number of other Dlls on which it relies. This, and the extra switching involved, slows down the application.

C and C++ programmers can use unicows.lib at link-time. Unfortunately the file is enormous and must slow down the linking process.

Using GoLink you can add the mslu loader code very simply. Just add the /mslu switch to the GoLink command line or file. GoLink does not use unicows.lib but has its own code instead. Since GoLink is written wholly in assembler, this code works fast and is small, at less than 800 bytes plus a dword for each API within unicows.dll which has to be dealt with. This therefore provides a simple way to add an mslu loader to your application so that you can use unicows.dll fully, and make just one application to work under all versions of Windows.

How the mslu loader works: Microsoft

Microsoft's loader is a wrapper (within your executable) for each API which is known potentially to be dealt with by unicows.dll. When your application calls one of these APIs it enters the wrapper. The wrapper checks what platform the application is running on and if it is NT, 2000 or XP the system Dll is called directly. If not, then if unicows.dll has not yet been loaded, an attempt is made to load it. If successful, the API is called within unicows.dll rather than in the system Dll.

How the mslu loader works: GoLink

GoLink's loader code does not work in the same way as Microsoft's. GoLink's code is simpler because it has the advantage of being able directly to manipulate the contents of the executable at link-time, whereas the MS loader has to do this via unicows.lib.
In Exe files GoLink's loader code (within the Exe) is only called once just after the application loads and it is not called again (the beginning of the loader code is given to the system as the entry address for the application). After the loader code has run, execution continues at the original entry point.
In Dlls the arrangement is slightly different because the loader code cannot be run from the Dlls entry point when the Dll attaches. Instead, GoLink creates a function within the Dll called MSLU_LOADER. Your application has the responsibility of calling this loader before using any function in the Dll which might require unicows.dll. The loader should only be called once. A convenient time to call MSLU_LOADER is just after your main Exe starts. Use the syntax CALL  DllName:MSLU_LOADER or just CALL  MSLU_LOADER.
The first job of GoLink's mslu loader is to check whether the application is running under Windows NT, 2000 or XP. If so, the loader has no more work to do and simply hands control back to the application by (in an Exe) jumping to the original starting address, or (in a Dll) returning. The application then works normally without needing unicows.dll. But if the mslu loader finds that the application is running under Windows 95, 98 or ME, it needs to do some work.

Loading unicows.dll

Firstly, the loader tries to load unicows.dll using LoadLibrary. In the first instance it looks for this in the same folder as the application itself. Microsoft recommends that unicows.dll is placed there. This is to try to avoid problems with updated versions of unicows.dll being elsewhere on the machine. This is sensible because you tested your application using a particular version of unicows.dll and so you will want that version to be used at run-time. See also changing the name of unicows.dll. The actual search order is:-
1. the directory from which the application was started
2. if different, the current directory
3. the windows system directory
4. the windows directory
5. directories listed in the PATH environment variable.

Overwriting the call stubs for the APIs found at link-time

If unicows.dll is loaded successfully, then GoLink's mslu loader examines a list of APIs given to it by the linker. This list was created at link-time and is contained within the executable. It contains all those API calls for which unicows.dll was known at link-time to provide a wrapper. The GoLink loader looks for these APIs within unicows.dll as loaded. Using a list acts is an important check on the version and integrity of unicows.dll found at run-time. As each API is found within unicows.dll the loader writes its address in the application's call stubs which are in the memory image in the application's address space (in the Import Address Table). These have already been written to by the system loader, but they hold the addresses of the API calls for the ordinary system Dlls. These have to be changed to the addresses of the APIs in unicows.dll. Once that is done, if the application calls one of these APIs it will call unicows.dll instead of calling the system Dll directly. There will still be many APIs which are not dealt with by unicows.dll and these will continue to be called using the address provided by the system loader. The result of this process is that under Windows 95, 98 and ME the application will rely on unicows.dll to work properly.

Mslu loader error messages

Unlike the Microsoft loader, GoLink provides optional error messages to the user if unicows.dll is not found, is found but is found damaged or if it does not contain the APIs which it was found to contain at link-time. These messages are given to the user by using a message box in a GUI application or using the console in a console application. In GoLink using the /msluerr filename switch you can override this message and provide your own text which will be displayed on the happening of one of these events. Using the /msluerr off switch you can also stop the error message altogether, so that your application can continue to run even if there is a problem with unicows.dll.

Changing the name of unicows.dll

You may wish to ensure that the version of unicows.dll that you ship with your application will not get mixed up with other versions of the Dll which may be on the destination computer. You tested your application on the version you shipped and you will want your application to use that file only. Changing the name of unicows.dll was suggested by Michael Kaplan (principal developer for mslu) and Cathy Wissack (a Program Manager at Microsoft) in their article "MSLU: Develop Unicode Applications for Windows 9x Platforms with the Microsoft Layer for Unicode". I have checked and double-checked with Michael Kaplan that changing the name of unicows.dll and then distributing it is lawful and not in breach of Microsoft's licence or copyright. If you do change the name, obviously you must tell the mslu loader code the new name for the file so that it loads the correct file at run-time. In GoLink you do this by specifying /msludll newfilename in the command line or file. This also has the effect of amending the error messages if the file is not found or is found damaged or in the wrong version. The filename in those messages is changed and the reference to downloading unicows.dll from the Microsoft site is omitted to avoid confusing the user.

Choosing to use unicows.dll but not the mslu loader

What if you do not want the mslu loader in your executable, can you still use unicows.dll? Yes! However, there will be no run-time switching by your application. You will be relying on the switching within unicows.dll itself. This works perfectly well but the disadvantage is that when running under Windows NT, 2000 or XP your application will have to load unicows.dll into memory. Although unicows.dll is not large, it does also load other Dlls as it itself loads, reducing the overall speed of loading. And you will have to make sure that unicows.dll is shipped with your application even for use under Windows NT, 2000 or XP.
To use unicows.dll in this way with GoLink you need to take just two steps. Remove or comment out the /mslu switch in the command file. And specify unicows.dll in the command file, making sure it is the very first Dll listed (GoLink looks for the API names in the Dlls in the order in which they are listed and once found will not look again).

Overriding the mslu action for selected APIs

You may prefer to use your own wrapper code for certain APIs rather than use the wrapper within unicows.dll. Eventually, though, your wrapper will probably need to call the appropriate Windows API. Now if this API is itself available from unicows.dll, if the /mslu switch is specified at link-time and the application is being run under Windows 95, 98 or ME, the MSLU loader will cause the API within unicows.dll to be called by your wrapper rather than the API within the usual system Dll as you may have intended. To avoid this happening you can force GoLink under all circumstances to link to the API in a specified Dll. This can be done using the syntax NameOfDll:NameOfAPI (this is similar to the syntax used to import by ordinal OrdinalNumber:NameOfAPI). For example if you do not want to call EnableWindow within unicows.dll under any circumstances, you would use User32:EnableWindow. This ensures that only EnableWindow in User32.dll is called at run-time even if the application is running under Windows 95, 98 or ME and the /mslu switch is used at link-time.

Where to get unicows.dll

Unicows.dll can be obtained from Microsoft from here.

More information and links

The Unicode Consortium.

Newsgroups:-
MSDN mslu newsgroup
MSDN international newsgroup

Various MSJ/MSDN articles:-
"MSLU: Develop Unicode Applications for Windows 9x Platforms with the Microsoft Layer for Unicode" by Michael Kaplan and Cathy Wissink (October 2001).
"Design a Single Unicode App that Runs on Both Windows 98 and Windows 2000" by F Avery Bishop (April 1999).
"Supporting Multilanguage Text Layout and Complex Scripts with Windows NT 5.0" by F Avery Bishop, David C Brown and Davis M Meltzer (November 1998).

Microsoft Legal stuff for unicows.dll

Microsoft expect you to adopt its own terms of licence to apply to the distribution of unicows.dll. The safest bet is probably to make it clear to the user that unicows.dll (or the file as renamed) is a Microsoft file and is subject to the Microsoft terms of licence and terms of redistribution. Unfortunately the licence is not at all in "plain English", so that any attempt to incorporate its terms into your own licence terms could be troublesome and dangerous. It is probably prudent therefore, simply to pass on the files License.txt and Redist.txt (which come with unicows.dll) to the user asking them to comply with them.

This article was written from a "Go" tools perspective and may not apply to other tools. You use the information here at your own risk, the author taking no responsibility for errors in this file nor in GoLink.

Copyright Jeremy Gordon 2002/3 [MrDuck Software]