W32单个实例

在讨论禁止多个Win32实例之前,我们先讨论一下WinMain函数。我们知道,任何一个基于GDIWindows程序以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(szClassNameszWndName)     

 

if(hWnd)

{   

MessageBox(NULL, _TEXT("Another Instance is already running."), _TEXT("Information"),   

MB_OK MB_ICONINFORMATION);   

}

     

需要注意的是,很可能程序的各个实例有不同的窗口名,如果下面这样调用FindWindow   

HWND hWnd = FindWindow(szClassNameNULL)   

则查找所有的窗口并匹配窗口类名,如果你能保证你的窗口类名是唯一的,那么你可以信赖FindWindow,否则,你需要用更好的方法。

 

     

方法二    通过在EXE之间共享数据段从而共享数据来判断是否有程序的另一个实例存在。   

每个EXEDLL都是由段的集合组成,在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( !bIsFirstInstance )

{   

MessageBox(NULL, _TEXT("Screen Saver Launcher is already running."), g_szAppName,    MB_OK | MB_ICONINFORMATION);   

}

     

使共享段内变量加1,没使用 g_lInstanceCount ++,而是使用InterlockedIncrement(&g_lInstanceCount),因为InterlockedIncrement函数对变量的访问进行同步(Synchronize),阻止多个线程同时访问同一个变量。有关线程同步的内容请参阅有关Win32 SDK的文档。   

禁止多个Win32实例的方法很多,如Win32核心对象(Mutex, Semaphore)、全局原子等都可以用来禁止多个Win32实例,在这里我们只简单地介绍以上两种方法。

 

#pragma data_seg("Shared")

int volatile g_lAppInstance =0;

#pragma data_seg()

#pragma comment(linker,"/section:Shared,RWS")

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值