Processes, Modules, Top Windows, Instances, and Threads
The Top Windows, Processes, and Modules list boxes of WinWatch show three different views of what’s going on inside Windows. There is no Instances list box, but instances played a big part in the way the 16-bit version of WinWatch created and synchronized the other list boxes. From their starring role in the 16-bit world, instances have been reduced to bit parts in 32-bit Windows. The up and coming stars of the 32-bit world are threads—although they haven’t yet achieved much notoriety in Visual Basic and don’t even merit their own list box in WinWatch.
To understand how all these parts work together, let’s start with some definitions:
-
A process is a running program, along with all the DLLs it uses. In 16-bit Windows, processes were called tasks, but this temporary aberration has gone the way of the difference between you and thou. Every process has a process ID that uniquely identifies it. You can pass a process ID to the OpenProcess API function to get a process handle. Most API functions that provide process information require a handle rather than an ID.
-
A module is the code, data, and resources of an executable file that has been loaded into memory. Executable file can mean an EXE program or a DLL used by a program. Multiple processes can use the same module.
-
A top window is a window providing the visual representation of a process. It’s what we normally think of as the program, although processes can actually have multiple top windows or no top window.
-
A thread follows a single path of execution through a program and is the fundamental unit scheduled by Windows. Every process has at least one thread, and in some languages you can start additional threads within a process. Visual Basic will start and manage separate threads in some kinds of ActiveX servers, but you as the programmer have little control over it. Put another way, processes don’t really exist. They are just holders for threads, which do the real work.
-
Instances no longer exist as separate entities with handles. The value we call an instance handle for historical reasons isn’t really a handle—it’s a pointer. And it probably wouldn’t be used at all if compatibility weren’t an issue. The term instance handle comes from 16-bit Windows, where an instance handle was tied to the data of a program. Each instance
of the program had its own unique data but shared its code with other instances. In 32-bit Windows, each instance of a program has its own separate copy of both the code and the data, and the addresses within that copy are unintelligible to other instances. The function that returned an instance handle in 16-bit Windows (GetWindowLong with GWL_HINSTANCE) now returns the base address of the code, data, and resources of a program (the same thing the module is the handle of). You could do a lot of damage with such a pointer. Windows doesn’t care if you do that damage to yourself, but it makes sure you can’t use the pointer to trash another program.
The three list boxes help show how the different parts work together. Notice that when you select a different top window or process, the module list is regenerated. This is different from the 16-bit version of WinWatch, which displayed one global list of modules. In 32-bit Windows, each process has its own separate module list. You can’t get a global module list (except by merging all the process module lists and eliminating duplicates).
A process usually has one top window, but it can have multiple top windows, no top windows, or invisible top windows. In Visual Basic terms, having one top window means having a startup form; having multiple top windows means starting more than one modal form from Sub Main; having no top windows means doing all processing from Sub Main; having invisible top windows means setting Visible to False on all top-level forms.