防止程序多重启动
   作者:AoGo 于2003-9-12上传 

   此文章是接续怜香的"DOS到Win32"系列教程第14篇的后续,阅读之前推荐查看前续文章

  正如怜香所说,命令行参数在Windows中是无处不在的,只是一般感觉不到,双击一个txt文件,Windows会启动记事本程序并把txt的路径做为参数提供给它,这当然相当的快捷,一般在打开一个文件时会再一次启动相关联的程序,但是你会发现很多多文档(MDI)软件在运行的情况下不会再次启动一个新的实例,而是已经运行的程序打开了你再次需要打开的文件,这就是防止程序的多重启动。
  这一篇先讲如何防止,下一篇再讲如何处理(就是让已经运行的实例打开下个实例的文件)。
  要防止程序多重启动,有很多的方法,如下:
  
  • 1.可以使用FindWindow查找程序的标题,此函数成功返回目标窗口句柄,失败为NULL.
      szWindowName db "Hello World!",0
      ... ...
      invoke FindWindow,NULL,offset szWindowName
      .if eax!=NULL
          invoke WinMain....
      .end if
      invoke ExitProcess,0

      这种方法不是很好,因为会有一些软件的窗口可能与你的窗口标题同名,注意看上面的FindWindow,参考API手册发现第一个参数是ClassName,窗口类名除自身实例一般是唯一的,这种方法一般完全可行:
      
  • 2.使用FindWindow查找程序的窗口类名,函数成功返回目标窗口句柄,失败为NULL.
      szClassName db "WINASM_CLASS!",0
      ... ...
      invoke FindWindow,offset szClassName,NULL
      .if eax!=NULL
          invoke WinMain....
      .end if
      invoke ExitProcess,0

      但是这种方法缺点就是,当程序没有标准的窗口或是以对话框为主窗口的程序就不适用了,没有标准窗口的程序当然没有类名,而以对话框为主窗口的程序的话也不行,因为默认对话框的类名都是#32768,这个当然无法依此来判断实例是否已运行.
      
  • 3.创建一个Mutex(互斥)对象,这是一个系统全局标识,创建后所有的程序都可以访问到.此函数成功返回Mutex对象的句柄,失败返回NULL,但是一般都是通过GetLastError获得错误编号进行判断.
    .data
       szMutex db "_Me?",0
    .data?
       hMutex dd ?
       hInstance dd ?
    .CODE
    START:
       invoke GetModuleHandle,NULL
       mov hInstance,eax
       invoke
    CreateMutex,NULL,TRUE,offset szMutex

       mov hMutex,eax
       invoke GetLastError               获得最后发生的错误编号
       cmp eax,ERROR_ALREADY_EXISTS   已经存在
       jz @F
          invoke WinMain...
          invoke ReleaseMutex,hMutex         只有在正常运行后才释放Mutex对象
       @@:
       invoke ExitProcess,0

      
  • 4.还有其它方法,如在程序启动时在同目录或Windows临时目录下创建一个文件,退出删除它,那么第二个以上的实例运行后首先判断是否存在这个文件,存在则退出,不存在则启动,如果一个程序使用到了INI则更方便,和上面说的一样,在启动时设置某个键,退出时再设为0,第二个以上的实例则以此键为"互斥对象"。还有往注册表中写一个键,方法和上面是一样的。
      
      多重启动的处理见下一篇。


    欢迎访问AoGo汇编小站:http://www.aogosoft.com