汇编处理程序多重启动
2017-07-23
建议使用MASM for EditPlus进行测试。
正如"防止程序多重启动"一文所说,当已经知道自己的实例在运行了,为了节省资源,下个实例需要退出,可是用户需要打开文件,如果不处理就退出,那用户不破口大骂才怪,所以,就需要退出之前进行处理。
首先要讲一个小知识,当Windows程序退出的时候,Windows会自己清除当前进程所占用的所有资源,除了动态DLL(静态DLL也会自动释放,对于运行时动态加载的DLL,释放工作是由用户完成的,尽管Windows会检查它是否已经没有被使用,但是有时候由于特殊的原因它将不会被释放),这就是一个操作系统所谓的资源回收(忘了英文单词,好像是这么说吧),那么,问题就来了,当程序在退出的时候,尽管可以向其它程序(如自身的实例)发送消息,但是问题是如何传递资源,在这里是传递一个字符串,而传递的资源是又当前进程中的地址,按Windows的资源回收来说,当程序退出时传递的字符串地址已经不存在了,那如何才能传递一个正确的字符串给前一实例呢?
我们可以使用API中的消息WM_SETTEXT与WM_GETTEXT,这两个消息发送后是立即返回的,这样当前进程能在发送完消息后立即退出,而SendMessage函数在发送消息时会判断当前消息是否是WM_SETTEXT与WM_GETTEXT,如果是,则SendMessage并不单单发送一个消息,而会创建一个内存映像(标准叫映射)文件,把需要传递的字符保存到这个内存映像中,然后再把内存映像的地址做为参数传给目标窗体,而内存映像是可以在程序之间共享的,这样就间接的做到了传递资源:
... ...
.DATA
szClassName db "WinASM_Class",0
.data?
lpCommandLine DD ?
.CODE
START:
... ...
invoke GetCommandLine
mov lpCommandLine, eax
invoke FindWindow,offset szClassName,NULL ;查找自身类
cmp eax,0
jnz @F
invoke WinMain....
invoke ExitProcess,0
@@:
invoke SendMessage,eax,WM_SETTEXT,0,lpCommandLine
invoke ExitProcess,1 ;记得发生错误后返回非零值,尽管这个不是错误。
......
因此,我们还需要自己来处理WM_SETTEXT消息:
... ...
.elseif uMsg==WM_SETTEXT
invoke MessageBox,0,lParam,0,0
在模板相关地方添加上述代码后,运行一下,你会发现第二个实例会马上退出,但是第一个实例会在第二个实例退出的那一瞬弹出一个信息框,如果第二个实例启动时你传递了参数,那么你对照一下,信息框中的信息就是第二个实例的尾部参数。
这样你就可以在WM_SETTEXT消息中进行处理了,如打开实例传过来的文件。