关于“应用程序实例句柄”——HINSTANCE hInstance的疑问
本帖最后由 shipeiyuan 于 2012-05-02 22:04:38 编辑 小弟最近学习MFC,对于主函数 int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE PreInstance,LPSTR lpCmdLine,int nCmdShow) 的HINSTANCE hInstance形参十分不理解。书上说,hInstance表示程序运行的实例句柄,是一个数值,它唯一标识运行中的实例。一个应用程序可以运行多个实例,每运行一个实例,系统都会给该实例分配一个句柄值,并通过hInstance参数传递给WinMain函数。HINSTANCE其实是一个指针,因为分别在WinNT.h 和 windef.h中有如下定义
#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name
DECLARE_HANDLE(HINSTANCE);
貌似书上说的很有逻辑!!!
于是小弟编写一个程序,它能正常运行,而且确实可以同时运行多个实例,没问题。下面是程序代码。各位大侠可以不必全看,只是留意一下程序中我自己写的主函数WinMain即可。此程序只是创建个窗口,鼠标左键按下弹出MessageBox。可以直接跳过代码看问题。
代码:
#include<Windows.h>
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE PreInstance,LPSTR lpCmdLine,int nCmdShow)
{
HWND hwnd;
MSG msg;
char lpszClassName[]="window";
WNDCLASS wc;
wc.style=0;
wc.lpfnWndProc=WndProc;
wc.cbClsExtra=0;
wc.cbWndExtra=0;
wc.hInstance=hInstance;
wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);
wc.hCursor=LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName=NULL;
wc.lpszClassName=lpszClassName;
RegisterClass(&wc);
hwnd=CreateWindow(lpszClassName,"windows",WS_OVERLAPPEDWINDOW,120,50,700,500,NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
switch(message)
{
case WM_LBUTTONDOWN:
{
MessageBox(hwnd,"这是一个 message box",NULL,0);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd,message,wParam,lParam);
}
return 0;
}
以上程序能够正确运行,并可以运行多个实例,因为每次系统传递给主函数的hInstance参量的值不同。但是我对主函数做如下修改:
......//省略之前代码
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE PreInstance,LPSTR lpCmdLine,int nCmdShow)
{
hInstance=HINSTANCE(100); //加入这条语句,让程序每次运行是,hInstance值都相等。
......//省略之后代码
按理说,这样的修改是的每个应用程序实例句柄多相等,因此运行这个程序的多个实例(同时运行这个程序多次)应该出问题。可是,程序依然可以照常运行,没有任何问题,而其同样可以运行多个实例,每个实例都运行正常。这到底是怎么回事?HINSTANCE到底有什么用,它对于应用程序和操作系统到底意味着什么?这些现象和问题困扰小弟多天,希望能得到各位大侠的解答。万分感谢。
[解决办法]
#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name
DECLARE_HANDLE(HINSTANCE);
这个只能说明HINSTANCE和指针一样大,具体是什么这里看不出来,像HWND,HDC都如此定义,但它们根本不是指针
HINSTANCE是exe映像的虚拟地址,HINSTANCE用于区分进程实例仅限于没有隔离进程地址空间的16位windows,现在的windows每个进程有自己的地址空间,两个进程的同一个地址可以是不同的东西,此时HINSTANCE不再具有唯一标识运行中的实例的功能
[解决办法]
楼主看的那本书是孙鑫的《深入理解VC++》吧,上面尽是错误的概念。
hInstance不是什么句柄,而是进程的虚拟地址的基地址,多个进程的虚拟地址空间的基地址完全可能是重叠的,不重叠的是16位实模式,就是windows3.1等16位windows系统下的样子。现在32位系统都使用保护模式,不怕多个进程地址值一样。
[解决办法]
HINSTANCE的值就是这个程序的起始地址。