译者按:老汉当初学习 Windows 编程的时候就对此问题有过疑惑,后来明白了,却懒得写一篇总结性的东西。这是在 The Old New Thing 的 Blog 上发现的,翻译过来,权且为新手释疑。原文的链接为 http://blogs.msdn.com/oldnewthing/archive/2005/04/18/409205.aspx。
CreateWindow 函数和 RegisterClass 函数(译者注:以及这两个函数相应的 Ex 后缀版本)中很少被人理解的一个参数是 HINSTANCE(或者作为参数传递或者作为 WNDCLASS 结构的一部分)。
窗口类名不足以唯一地标志窗口类。每个进程有自己的窗口类列表,窗口类列表中的每一项都由一个实例句柄和一个类名字组成。例如,如果一个程序有两个 DLL,每个都注册了一个名为“MyClass”的窗口类,并且将 DLL 的句柄作为 HINSTANCE 传递,则窗口类列表看起来就象这样:
HINSTANCE Class name
1 USER32.DLL Static
2 USER32.DLL Button
3 USER32.DLL ListBox
4 USER32.DLL ComboBox
5 USER32.DLL Edit
6 A.DLL MyClass
7 B.DLL MyClass
当要创建窗口时,每个模块传递它自己的 HINSTANCE,窗口管理器使用实例句柄和窗口类名的组合来寻找窗口类。
CreateWindow("MyClass", ..., hinstA, ...); // 创建窗口 6
CreateWindow("MyClass", ..., hinstB, ...); // 创建窗口 7
CreateWindow("MyClass", ..., hinstC, ...); // 失败
这就是为什么多个 DLL 都创建名为“MyClass”的类可以成功,实例句柄用来将它们区别开来。
但是上述规则有一个例外。如果在你注册窗口类时指定了 CS_GLOBALCLASS 标志,那么窗口管理器在寻找你的窗口类时将忽略实例句柄。所有的 USER32 窗口类都被注册为全局的。因而,下面所有的调用都会创建 USER32 的编辑框控件:
CreateWindow("edit", ..., hinstA, ...);
CreateWindow("edit", ..., hinstB, ...);
CreateWindow("edit", ..., hinstC, ...);
如果你要注册一个用在其他模块的对话框里的窗口类,你就需要注册为 CS_GLOBALCLASS,因为像我们先前看到的,在对话框创建过程中,创建控件执行的内部 CreateWindow 调用会把对话框的 HINSTANCE 用作 HINSTANCE 参数。因为对话框的实例句柄通常是创建该对话框的 DLL(因为相同的 HINSTANCE 要用来寻找对话框模板),不使用 CS_GLOBALCLASS 标志注册意味着寻找窗口类时将不能找到该类,因为它注册于提供该窗口类的 DLL 的实例句柄名下而不是使用它的那个。
在16 位 Windows 中,实例句柄还要用来做其他事情,但在 Win32 里已经没有关系了。
一个常见的错误是在注册窗口类时传递一些其他的 HINSTANCE 进去(典型地,主执行程序的)。现在了解了 HINSTANCE 的用途,你就应该能够解释用错误的 HINSTANCE 注册窗口类的后果了。
转载自:http://www.somedoc.net/?p=308
—————————————————————————————————————————————————————————————————————————————
注:进程和程序的区别
①进程是程序的一次执行,属于动态概念,而程序是一组有序的指令,是一种静态概念。但进程离开了程序也就失去了存在的意义。
②一个进程可以执行一个或几个程序。反之,同一程序可能由几个进程同时执行。
③程序可作为软件资源长期保留,而进程是程序的一次执行过程,是暂时的。进程具有生命期。
④进程具有并发性,能与其它进程并发运行。而程序不具备这种特征。
⑤进程是一个独立的运行单位,也是系统进行资源分配和调度的一个独立单位。因此,进程具有独立性,但有时进程间又具有相互制约性。