{
UINT uID = (UINT)wParam;
UINT uMsg = (UINT)lParam;
if(uID == IDI_SSLAUNCH){
switch(uMsg){
case WM_LBUTTONDOWN :
//Do something
break;
case WM_LBUTTONUP :
//Do something
break;
default :
break;
}
}
}
2.禁止多个Win32实例
在讨论禁止多个Win32实例之前,我们先讨论一下WinMain函数。我们知道,任何一个基于GDI的Windows
程序以WinMain函数作为入口被系统调用。在Win16中,hPrevInstance指向前一个实例的句柄,但在Win32中,每一个进程都有一个独立的4G地址空间,从0到2G属于进程私有,对其他进程来说是不可见的。所以,在Win32中,hPrevInstance总是为NULL。
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // pointer to command line
int nCmdShow // show state of window
);
因而,在Win32下不能通过判断hPrevInstance是否为NULL来判断一个
程序的另一个实例是否存在,要用其他的方法来判断。
方法一
用FindWindow 函数查找指定窗口,如果成功,则返回要找的窗口的句柄,否则返回NULL,由此可判断是否有程序的另一个实例存在。
下图的代码片段演示如何使用FindWindow函数:
TCHAR szClassName = _TEXT("My Wnd Class");
TCHAR szWndName = _TEXT("My Wnd");
HWND hWnd = FindWindow(szClassName,szWndName);
if(hWnd){
MessageBox(NULL, _TEXT("Another Instance is already running."), _TEXT("Information"),
MB_OK | MB_ICONINFORMATION);
}
需要注意的是,很可能程序的各个实例有不同的窗口名,如果象下面这样调用FindWindow
HWND hWnd = FindWindow(szClassName,NULL);
则查找所有的窗口并匹配窗口类名,如果你能保证你的窗口类名是唯一的,那么你可以信赖FindWindow,否则,你需要用更好的方法。
方法二
通过在EXE之间共享数据段从而共享数据来判断是否有程序的另一个实例存在。
每个EXE或DLL都是由段的集合组成,在Win32程序中,每个段以点(.)开头。例如,当编译程序是编译器时,则将所有代码放入一个叫.text的段、将所有未初始化的数据放入.bss段、将所有初始化的数据放入.data段。
可以给每个段赋予一个或多个属性(以下为常用的一些段属性):
READ 段中的数据可读
WRITE 段中的数据可写
SHARED 段中的数据可被多个实例共享
EXECUTE 段中的数据可被执行
可以用以下指令生成段:
#pragma data_seg("Shared")
static LONG g_lInstanceCount = -1;
#pragma data_seg()
编译器生成这段代码时,产生一个新段,并把它所在#pragma data_seg("Shared")指令后的初始化数据放入新段Shared,未初始化的数据放入.bss段。#pragma data_seg()以后的数据放回缺省数据段。
仅告诉编译器把特定数据放入自己的段内还不足以共享它们,还要告诉链接器在某一特定段内变量要共享。可以在
链接时指定这个段的属性。
/section:Shared,rws
段名 属性
程序初始化时,例如调用WinMain函数时,调用InterlockedIncrement函数使共享段内变量加1,就可以通过判断共享段内变量的值来判断一个程序有几个实例在运行。以下代码演示了如何判断一个正在运行的程序实例是这个程序的第一个实例。
BOOL bIsFirstInstance = (InterlockedIncrement(&g_lInstanceCount) == 0);
if