Sorting it all Out Michael Kaplan's random stuff of dubious value Be sure to read the disclaimer here first!
Previous posts in this series (including today's!):
(If you are just tuning in and want to start now you can grab the current source from here)
As I mentioned almost from the start, one of the big downsides to converting setup.exe to Unicode is that Win9x doesn't support Unicode.
Lucky for us we have the Microsoft Layer for Unicode on Windows 95, 98, and Me Systems, huh?
Anyway, just as regular reader Dean Harding suggested, a logical step at this point in the series is to add MSLU support to our project. :-)
Now since MSLU makes no sense in the ANSI build, we will start with the makefile.uni that was added yesterday in Part 7 that you can find in the source code download above:
# THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF# ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A# PARTICULAR PURPOSE.## Copyright (c) Microsoft Corporation. All Rights Reserved.### Processor independent Unicode makefile,# perhaps one day intended for Platform SDK## Target only i386# FILE : MAKEFILE.UNI!include <ntwin32.mak>#include support for unicodecflags = $(cflags) -D_UNICODE -DUNICODE!include <makefile>
Now the key to supporting MSLU is making sure to add unicows.lib to the link list prior to all of the .LIB files that it uses (and incidentally prior to the ones that contain source code that use it ,though we do not have any of those in this case).
Some casual spluenking through ntwin32.mak indicates that it is the baselibs variable that includes the basic libraries like kernel32.dll. So all we have to do is add unicows.lib prior to the other lib files in baselibs and then MSLU has been integrated!
To verify this, you can use the following command to look at all of the functions that are imported by our setup.exe:
link -dump -imports WIN2000_DEBUG\setup.exe
(this command works a lot like dumpbin.exe does)
As I have mentioned before talking about dumpbin, when a function that used to come from a regular OS lib starts coming from unicows.lib, it seems to disapear from the list of imported functions. It almost reminds me of that Douglas Adams story I quoted in When you think it couldn't get any harder, it gets easier, where you are using the fact that certain items are not where you expect them as proof of what is going on.
If you run that line with the baselibs line in makefile.uni and compare it to the results of when it isn't there, you will see the bulk of the "W" functions disappear. As if they fell out of the hole in the ship caused by the meteorite or something. :-)
And there is one more interesting thing you might have to do here that the output indicates. We'll look at it really quickly to see what I am talking about (the interesting ones are marked in RED):
E:\setup.exe>link -dump -imports WIN2000_DEBUG\setup.exeMicrosoft (R) COFF/PE Dumper Version 8.00.50727.762Copyright (C) Microsoft Corporation. All rights reserved.Dump of file WIN2000_DEBUG\setup.exeFile Type: EXECUTABLE IMAGE Section contains the following imports: KERNEL32.dll 451014 Import Address Table 45F434 Import Name Table 0 time date stamp 0 Index of first forwarder reference 257 LoadResource 25C LocalFree 1FF GlobalFree 1F8 GlobalAlloc 380 VerifyVersionInfoW 37D VerSetConditionMask 142 GetCurrentProcess 3A CompareStringA 17F GetModuleHandleA 17D GetModuleFileNameA 1F3 GetWindowsDirectoryA 1C1 GetSystemDirectoryA 252 LoadLibraryA 229 InterlockedExchange 265 LockResource 15A GetExitCodeProcess 171 GetLastError 34 CloseHandle EE FlushFileBuffers 388 VirtualQuery 53 CreateFileA 3CC lstrlenA 135 GetConsoleOutputCP 399 WriteConsoleA 337 SetStdHandle 1E2 GetTimeZoneInformation 133 GetConsoleMode 122 GetConsoleCP 31B SetFilePointer 223 InitializeCriticalSection 381 VirtualAlloc 328 SetLastError F8 FreeLibrary 21A HeapReAlloc 244 LCMapStringA 2EE SetConsoleCtrlHandler 28D OutputDebugStringA 78 DebugBreak 2A3 QueryPerformanceCounter 1DF GetTickCount 146 GetCurrentThreadId 143 GetCurrentProcessId 1CA GetSystemTimeAsFileTime 35E TerminateProcess 36E UnhandledExceptionFilter 34A SetUnhandledExceptionFilter 216 HeapFree 1E9 GetVersionExA 210 HeapAlloc 1A3 GetProcessHeap 22C InterlockedIncrement 228 InterlockedDecrement 239 IsDebuggerPresent 2D7 RtlUnwind FD GetACP 193 GetOEMCP 365 TlsGetValue 363 TlsAlloc 366 TlsSetValue 364 TlsFree 145 GetCurrentThread 220 HeapValidate 233 IsBadReadPtr 2A7 RaiseException 81 DeleteCriticalSection 98 EnterCriticalSection 251 LeaveCriticalSection C0 FatalAppExitA B9 ExitProcess F6 FreeEnvironmentStringsA 155 GetEnvironmentStrings 110 GetCommandLineA 111 GetCommandLineW 324 SetHandleCount 1B9 GetStdHandle 166 GetFileType 1B7 GetStartupInfoA 214 HeapDestroy 212 HeapCreate 383 VirtualFree 3A4 WriteFile 1E0 GetTimeFormatA 147 GetDateFormatA 1BA GetStringTypeA 174 GetLocaleInfoA 241 IsValidLocale AF EnumSystemLocalesA 1E3 GetUserDefaultLCID 313 SetEnvironmentVariableA ADVAPI32.dll 451000 Import Address Table 45F420 Import Name Table 0 time date stamp 0 Index of first forwarder reference 1D AllocateAndInitializeSid E2 FreeSid USER32.dll 45117C Import Address Table 45F59C Import Name Table 0 time date stamp 0 Index of first forwarder reference E1 ExitWindowsEx 24D SetCursor 111 GetDlgItem 15D GetSystemMetrics 1ED MsgWaitForMultipleObjects 99 DestroyWindow 1EC MoveWindow 256 SetFocus 292 ShowWindow 257 SetForegroundWindow 2AA TranslateMessage 174 GetWindowRect COMCTL32.dll 45100C Import Address Table 45F42C Import Name Table 0 time date stamp 0 Index of first forwarder reference 5D InitCommonControlsEx urlmon.dll 4511BC Import Address Table 45F5DC Import Name Table 0 time date stamp 0 Index of first forwarder reference 49 URLDownloadToCacheFileW WININET.dll 4511B0 Import Address Table 45F5D0 Import Name Table 0 time date stamp 0 Index of first forwarder reference 65 InternetCanonicalizeUrlW D DeleteUrlCacheEntryW Summary 4000 .data F000 .rdata 3000 .rsrc 50000 .text
Those functions marked in Red are the ones that may either not exist or may only be present as stubs on Win9x (according to either Platform SDK docs or unclear issues in Platform SDK docs e.g. the one I first mentioned in MSLU doesn't support wininet.dll). So in theory there my be a little more work here whether that includes perhaps separately wrapping these functions in a delayload kind of wrapper or sending some email to the Platform SDK folks or just deciding not to go down the MSLU road in the case of a new version of MSKLC that doesn't run on Win9x anyway? :-)
The small number of functions in this case will require some specific investigation:
In any case, although this step is one you should always do when adding MSLU to a project you are converting to Unicode, it is a step that you may not really need to do otherwise....
Plus that first function, which becomes VerifyVersionInfoA on ANSI builds, would indicate that setup.exe won't run on Win9x anyway? More research is definitely needed, I think!
On a slightly unrelated note, a question:
If you have to support MFC or some other library it will change what you do with the baselibs a bit. Anyone care to guess what would have to change? :-)
This post brought to you by ꂨ (U+a0a8, a.k.a. YI SYLLABLE HMUR)
PingBack from http://blogs.msdn.com/michkap/archive/2007/01/04/1409380.aspx
Nothing innacurate here (and a good series Michael!), but as usual the unstated implication is that MSLU adds Unicode support to Win9x, though it really only allows a Unicode exe to run on Win9x ANSI APIs. So not multilingual on those old OSes but MSLU is still very valuable because the same exe can run and support most text likely to be encountered on old Windows boxes.
http://codesnipers.com/?q=node/27
What a great series. It completely makes up for shipping of Raymond Chen's book being delayed until March, according to amazon.com.
There's some juicy material here. I'm anxious to see more in this area.
Although probably no help regarding MSLU and MSKC, I've run into the problem of functions not existing prior to Windows 2000. In my case, I tried running on Windows 9x anyhow, confirming that the loader puts up a nice error message and the program isn't started. The workaround for such API entries is to LoadLibrary kernel32.dll and use GetProcAddress to find the entry. The program can work around any failure to get the address, rather than letting the loader fail. I have some alpha-level code where I need to do that before I complete stabilization and allow the code to be deployed in beta release.
Previous posts in this series (including today's!): Part 0 (The introduction) Part 1 (Business before
PingBack from http://blogs.msdn.com/michkap/archive/2007/01/06/1420754.aspx
And yesterday, I receive an e-mail from amazon.com that says Raymond's book has been shipeed. Wow, now I feel like they are getting it to me early. Actually, it is arriving inside the original schedule. I have no idea why they said "not until March" less than a week ago.
The question from lonelyhawl was: I have create a unicode program in windows XP(using vs 2003) by method
Regular readers might remember my whole Converting a project to Unicode series in nine parts: Part 0