While this book is published by one of our competitors, I feel it is extremely important. Anyone who found my book Unauthorized Windows 95 (also published by IDG Books) useful will want to get Matt's book too.
Matt's previous book, Windows Internals (The Implementation of the Windows Operating Environment), published as part of the series of DOS and Windows programming books I edited for Addison-Wesley.
Before finishing this chapter, I thought I'd throw in a list of bad design decisions and embarrassing information that Microsoft probably won't be publicizing anytime soon. Many issues that I could talk about in this section have already been discussed elsewhere in this chapter, or in other books or magazines. Into this category, I put things like the following:
In subsequent builds of Windows 95 after Andrew's book came out, these functions disappeared from the import library for KERNEL32.DLL. (Surprise! Surprise!) At the same time, these function names disappeared from the exported names of KERNEL32.DLL. These undocumented functions were still exported, however. The difference is that they were exported by ordinal only.
Now, normally this would have been only a small nuisance to work around. You should be able to simply call GetProcAddress and pass in the desired function ordinal as the function name (0 in the HIWORD, the ordinal in the LOWORD) and get back the address. In a normal, sane world, this would work. However, at some point during the beta, Microsoft added code to GetProcAddress to see if it's being called with the ordinal form of the function. If so, and if the HMODULE passed to GetProcAddress is that of KERNEL32.DLL, GetProcAddress fails the call. In the debugging version of KERNEL32.DLL, the code emits a trace diagnostic: "GetProcAddress: kernel32 by id not supported."
Now, let's think about this. Since the undocumented functions aren't exported by name, you can't pass the name of a KERNEL32 function to GetProcAddress to get its entry point. And GetProcAddress specifically refuses to let you pass it an ordinal value. The Microsoft coder responsible for this abomination really didn't want people (Andrew Schulman?, myself?) from calling these undocumented KERNEL32 functions. Apparently, the only way you can call these functions is if you have the magic KERNEL32 import library that Microsoft isn't supplying with the Win32 SDK.
Never fear. As you'll see later in the book, I make extensive use of the KERNEL32 undocumented functions (for good, not evil). With a little bit of work, I was able to coerce the Visual C++ tools to create a KERNEL32 import library that contains these "documentation-challenged" functions. Appendix A contains information about these functions and an import library for them.
[NOTE: In addition to the extensive discussions of the undocumented KERNEL32 functions in Matt's book, also see my online "KERNEL32 export" update to Unauthorized Windows 95.]
Another instance of anti-hacking code put into Windows 95 is the Obsfucator flag. In early versions of Windows 95, GetCurrentProcessId and GetCurrentThreadId returned pointers to the relevant process and thread database structures. Shortly after Andrew's book came out, these functions started returning values that most definitely weren't pointers. A bit of investigative work revealed that the return value was the original pointer value, but XOR'ed with a seemingly random value. Where does this random value come from? Each time the system boots up, it uses the system clock to compute a random value. Interestingly, in the debug build of KERNEL32.DLL, this random value is named "Obsfucator." Seeing as how the KERNEL32 coders misspelled "obsfucator," it's doubtful whether the KERNEL32 sources were subjected to a spell check.
As with the GetProcAddress code, there's no reason for this XOR trick in GetCurrentThreadId and GetCurrentProcessId, other than to attempt to prevent people from getting at system data structures. While Microsoft is certainly allowed to try and hide these things, they shouldn't complain when people who really need this information go in and dig it out anyway. Chapter 3 describes a technique for calculating the Obsfucator value at runtime so you can access the thread and process database structures.
[NOTE: In addition to the extensive discussions of the "Obsfucator" in Matt's book, also see my online "unobfuscator" update to Unauthorized Windows 95.]
The Win32 API farce
While Microsoft would like you to believe that there's one big happy
Win32 API, internally the NT and Windows 95 teams don't communicate
too well. One result of this lack of coordination is that the number
of Win32 functions available on both NT and Windows 95 suffered
needlessly.
Exhibit 1 consists of the new Toolhelp32 functions. I've heard from many sources that the NT management team has vowed to never implement them. Yet if you look closely at the TOOLHELP32 API, you'd find there's just a handful of functions. Of primary interest are the process and thread enumeration functions. This information can be extracted from the Windows NT registry, as the PVIEW program from the Win32 SDK plainly shows. The question in my mind is: Why didn't the Windows 95 team simply implement the same registry keys that NT provides so that PVIEW could work on both? Or, why couldn't the NT team write a layer on top of the registry functions and put the Toolhelp32 functions on Windows NT? If either side really wanted to, they could come up with a portable Win32 API way to do system information enumeration. As I'm finishing the writing of this book, I've heard rumblings from a member of the NT team that the TOOLHELP32 functions might appear in a future version of Windows NT.
Exhibit 2 consists of the heap functions. There are several Win32 heap functions that Windows 95 left unimplemented, although implementing them probably wouldn't have been more than an hour's worth of work. The prime example is the HeapWalk function from Windows NT. This function isn't implemented in Windows 95. Yet, if you look in TLHELP32.H, you'll find two functions that do exactly the same thing: Heap32First and Heap32Next. Rather than simply implementing an existing Win32 API, the Windows 95 coders went off and implemented two entirely new functions. The NT team will no doubt say that they're not going to support those functions. Lunacy!
Exhibit 3 consists of the HeapLock function. In Windows NT, this function simply acquires the mutex of a specified Win32 heap. As you'll see in Chapter 5, Windows 95 has a function that does exactly that. However, the KERNEL32 development team didn't export that function. Thus, the most likely reason the HeapLock function isn't implemented in Windows 95 is because somebody didn't feel like renaming the existing function to HeapLock and exporting it from KERNEL32.DLL.
The point is, while Microsoft is trying to convince everybody to write to the standard Win32 API, two teams at Microsoft are implementing only what they feel like. This will only hurt Microsoft in the long run. I've filed my share of WINBUG reports and sent numerous e-mails. It's now up to the market to see what happens to the supposedly unified Win32 API.
Free system resource fudging
If, after booting Windows 95, you immediately bring up the Windows 95
Explorer and then go to the Help|About Windows 95 dialog box, you'll
see a free system resources value that's quite high; a typical value
is 95%. This is a much higher value than you'd see under Windows 3.1.
Did Windows 95 suddenly gain a whole bunch of free memory in the
16-bit USER and GDI heaps from which the free system resources are
calculated? No! In fact, many new items were added to USER's DGROUP
segment. If anything, the free system resources should have gone down
or stayed about the same in Windows 95.
So what's the story? As I describe in Chapter 4, during the Windows 95 startup sequence, the Explorer causes the desktop window to calculate correct, Windows 3.1-like values for the free system resources. All future calls to GetFreeSystemResources are then biased by these initial values. Thus, when the Explorer says that there's 95% of the system resources available, it means 95% of the resources after the Explorer and other programs have started. This change in the way free system resources are calculated is a blatant attempt to make Windows 95 look better than Windows 3.1 in the eyes of the nontechnical user.
Win16 isn't dead
Although Microsoft is strongly pushing everybody to move to Win32,
much of the underlying support for the Win32 APIs is in 16-bit code.
That's no secret, and not worth bringing up again. However, Microsoft
isn't making much noise about all the new API functions that were
added to the 16-bit DLLs. In many cases, these functions are 16-bit
equivalents to documented Win32 APIs. I'm talking about useful
functions like CreateDirectory and GetPrivateProfileSection. In some
cases, these functions were silently added to the 16- bit WINDOWS.H
without fanfare. In other cases, the functions are exported from the
16-bit DLL, but no prototype is given in the appropriate .H file. In
these cases, the Win32 documentation and some common sense can
usually get you through.
If Microsoft isn't publicizing these 16-bit additions, just who's supposed to be using them? If everyone should be writing Win32 code, why is Microsoft adding new Win16 APIs? It certainly looks like Microsoft knows that Win16 will continue to have a fairly long life even after Windows 95 ships. Yet they're telling developers that Win16 is a dead end, and that Win32 is the only way to go. Personally, I agree that people should focus on Win32 programming if possible. But trying to force people toward Win32 programming in this manner seems like a bad way to go.
Our homepage, with product information, feature articles, and more.
WebSite Central, home of O'Reilly's hot, new, Windows Web server.
The O'Reilly Windows Center has Win 95 programming information, articles, and links. FTP site, with newer versions.