注册窗口类时,有必要填写WNDCLASS
struct,它有一个hInstance
字段:
typedef struct {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS
然后,使用CreateWindow()
创建窗口,其中包含以下参数:
HWND CreateWindow(
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);
hInstance
在课程注册时提供了WNDCLASS
,为什么有必要向hInstance
提供CreateWindow()
?hInstance
的WNDCLASS
是否应该与hInstance
提供的CreateWindow()
相同?WNDCLASS
hInstance
和CreateWindow()
hInstance
不同,它们是什么意思?这是一个演示类注册/窗口创建的示例程序:
#include <windows.h>
LPSTR szClassName = "MyClass";
HINSTANCE hInstance;
LRESULT CALLBACK MyWndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow)
{
WNDCLASS wnd;
MSG msg;
HWND hwnd;
hInstance = hInst;
wnd.style = CS_HREDRAW | CS_VREDRAW; //we will explain this later
wnd.lpfnWndProc = MyWndProc;
wnd.cbClsExtra = 0;
wnd.cbWndExtra = 0;
wnd.hInstance = hInstance;
wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION); //default icon
wnd.hCursor = LoadCursor(NULL, IDC_ARROW); //default arrow mouse cursor
wnd.hbrBackground = (HBRUSH)(COLOR_BACKGROUND+1);
wnd.lpszMenuName = NULL; //no menu
wnd.lpszClassName = szClassName;
if(!RegisterClass(&wnd)) //register the WNDCLASS
{
MessageBox(NULL, "This Program Requires Windows NT",
"Error", MB_OK);
return 0;
}
hwnd = CreateWindow(szClassName,
"Window Title",
WS_OVERLAPPEDWINDOW, //basic window style
CW_USEDEFAULT,
CW_USEDEFAULT, //set starting point to default value
CW_USEDEFAULT,
CW_USEDEFAULT, //set all the dimensions to default value
NULL, //no parent window
NULL, //no menu
hInstance,
NULL); //no parameters to pass
ShowWindow(hwnd, iCmdShow); //display the window on the screen
UpdateWindow(hwnd); //make sure the window is updated correctly
while(GetMessage(&msg, NULL, 0, 0)) //message loop
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK MyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
注册窗口类时,它可以是全局的(设置为CS_GLOBALCLASS
样式),也可以是注册它的模块的本地。对于全局类,类名必须是唯一的,但对于模块本地类,类名可以冲突 - 没有什么能阻止两个DLL注册同名的窗口类,并且可执行文件可以加载这两个DLL。
因此,您需要告诉CreateWindow
函数您要使用哪个模块的命名类实例来创建窗口。
对于32位(和64位)Windows,hInstance可用于标识窗口类所属的DLL。这对全球课程很有用(参见Jonathan Potter的答案)。
在这种情况下,hInstance必须是DLL的句柄,而不是WinMain()函数的hInstance参数。
见这里:http://blogs.msdn.com/b/oldnewthing/archive/2005/04/18/409205.aspx
但是我确信这个论点存在的第二个原因是:
在16位Windows中,这个论点肯定是必需的。当从16位更改为32位Windows时,Microsoft希望尽可能少地更改以保持源代码兼容性。因此,hInstance参数尚未删除。
结构中的HINSTANCE hInstance;
是WNDCLASS
结构的一个元素。可以通过创建结构WNDCLASS
的对象来启动或分配结构的该元素。虽然CreateWindow
是一个函数调用,你已经通过HINSTANCE hInstance
作为参数,如果不是NULL,函数将使用此参数来执行某项任务。
要了解HINSTANCE的作用,请点击此Link
hInstance
-struct(WNDCLASS
)中的link是根据MSDN
包含该类的窗口过程的实例的句柄。
而对于CreateWindow
(link)称之为
要与窗口关联的模块实例的句柄。
正如@IInspectable在评论中提到的,这与应用本地类的class lookup相关:
- 在应用程序本地类的列表中搜索具有指定名称的类,该实例句柄与模块的实例句柄匹配。 (几个模块可以使用相同的名称在同一个进程中注册本地类。)[...]
所以基本上本地类查找只有在你将它设置为相同的值时才有效。