But first, a word from our sponsor, O'Reilly & Associates... [The Whole Internet for Windows 95]

Dirty Little Secrets about Windows 95

by Matt Pietrek

Order the book online * Other books

This is a brief excerpt from Matt Pietrek's new book, Windows 95 System Progamming Secrets, published by IDG Books (November 1995, ISBN 1-56884-318-6).

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.



Copyright (c) 1995 Matt Pietrek. All rights reserved. Reprinted with permission of Matt Pietrek.

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:

Instead of talking about these topics again, I'd like to focus on some other interesting issues in Windows 95 - issues that until now have gone largely unnoticed. The following list gives you a brief preview of each topic discussed in this section:

Anti-hacking code

In Unauthorized Windows 95, Andrew Schulman made extensive use of undocumented functions in KERNEL32.DLL. Although there obviously weren't header files for these functions, the functions appeared in the import library for KERNEL32.DLL. Calling these functions was as simple as providing a prototype and linking with KERNEL32.LIB.

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.


For more information, visit these other O'Reilly online areas:

[O'Reilly Home] Our homepage, with product information, feature articles, and more.

[WebSite Home Page] WebSite Central, home of O'Reilly's hot, new, Windows Web server.

[O'Reilly Windows Center] The O'Reilly Windows Center has Win 95 programming information, articles, and links. FTP site, with newer versions.