HOWTO: Subclass a Window in Windows 95

ID: Q125680

The information in this article applies to:

SUMMARY

While sub-classing windows within the same application in Windows 95 is unchanged from Windows version 3.1, sub-classing windows belonging to other applications is somewhat more complicated in Windows 95. This article explains the process.

MORE INFORMATION

For a 16-bit application, sub-classing methods are the same as they were in Windows version 3.1. However, Windows 95 performs some behind-the-scenes magic to make it possible for a 16-bit window to subclass a 32-bit window.

Usually, a subclass consists of saving one window procedure and substituting another in its place. However, this could present a problem when a 16-bit application tries to call a 32-bit window procedure. Windows 95 works around this potential problem by providing 32-bit windows with a 16-bit window procedure. All 32-bit windows will have the same selector for their wndProcs that references code in KRNL386.EXE where the 16-bit wndProcs for all 32-bit windows are stored. Eventually, each of these 16-bit wndProcs will jump to the real 32-bit window procedure.

Sub-classing windows belonging to another process, either 16-bit or 32-bit, from a 32-bit process or application works as it does in Windows NT. The difficulty is that each 32-bit process has its own private address space. Hence, a window procedure's address in one process is not valid in another. To get a window procedure from one process into another, you need to inject the subclass procedure code into the other process's address space. There are a number of ways to do this.

Method 1: Windows 95 and Windows NT

You can use the registry, hooks, or remote threads and the WriteProcessMemory() API to inject code into another process's address space.

Method 2: Windows NT Only

If you use the registry, the code that needs to be injected should reside in a DLL. By either running REGEDIT.EXE or using the registry APIs, add the \HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\AppInit_DLLs key to the registry if it does not exist. Set its value to a string containing the DLL's pathname. This key may contain more than one DLL pathname separated by single spaces. This has the effect, once the machine is restarted, of loading the library with DLL_PROCESS_ATTACH into every process at its creation time. While this method is very easy, it also has several disadvantages. For example, the computer must be restarted before it takes effect, and the DLL will last the lifetime of the process.

Method 3: Windows 95 and Windows NT

You can also use hooks to inject code into another process's address space. When a window hooks another thread belonging to a different process, the system maps the DLL containing the hook procedure into the address space of the hooked thread. Windows will map the entire DLL, not just the hook procedure.

Because of this mapping, the target process will get a fresh copy of all the DLL?s variables. Any changes to variables that are created by one process will not be available to another. One way to share DLL data among processes is to create a shared section:

   #pragma data_seg(?.MyData?)
   HWND hMyWin = NULL
   HHOOK ghMyHookProc = MyProcedureName
   ?other data
   #pragma data_seg()

These items should be initialized when the share is created. Please review the documentation on Win95?s memory management to make sure that your data is sharable.

Be aware that shared sections are a violation of Level B security on WinNT systems, so be careful about what kind of data gets placed in these sections.

To subclass a window in another process, install a WH_GETMESSAGE hook or another such hook on the thread that owns the window to be sub-classed. In the DLL that contains the hook procedure, include the subclass window procedure. In the hook procedure, call SetWindowLong() to enact the subclass. It is important to leave the hook in place until the subclass is no longer needed, so the DLL remains in the target window's address space. When the subclass is removed, the hook would be unhooked, thus un-mapping the DLL.

A third way to inject a DLL into another address space involves the use of remote threads and the WriteProcessMemory() API. It is more flexible and significantly more complicated than the previously mentioned methods, and is described in the following reference.

REFERENCES

"Load Your 32-bit DLL into Another Process's Address Space Using INJLIB" by Jeffrey Richter, MSJ May 1994.

Additional query words:

Keywords          : kbHook kbGrpUser kbWinOS95 kbWndw kbWndwProc 
Issue type        : kbhowto

Last Reviewed: January 2, 1999