.endif
.endif
.else
invoke defwindowproc,hwnd,umsg,wparam,lparam
ret
.endif
xor eax,eax
ret
wndproc endp
end start
分析:
应用程序创建主窗口,保存菜单句柄以备后用。当用户在主菜单中选择了“process”菜单项后,消息处理过程中接收到wm_initmenupopup消息,我们在此处修改弹出式菜单中的菜单项的“使能”和“非使能”,以便同一菜单有不同的显示。 .elseif umsg==wm_initmenupopup
invoke getexitcodeprocess,processinfo.hprocess,addr exitcode
.if eax==true
.if exitcode==still_active
invoke enablemenuitem,hmenu,idm_create_process,mf_grayed
invoke enablemenuitem,hmenu,idm_terminate,mf_enabled
.else
invoke enablemenuitem,hmenu,idm_create_process,mf_enabled
invoke enablemenuitem,hmenu,idm_terminate,mf_grayed
.endif
.else
invoke enablemenuitem,hmenu,idm_create_process,mf_enabled
invoke enablemenuitem,hmenu,idm_terminate,mf_grayed
.endif
我们之所以处理该消息的目的就是让菜单显示时有不同的外观以方便用户的使用。譬如;新进程尚未运行时,我们就变亮(使能)“菜单项“start process”,而变灰(非使能)菜单项“terminate process”。当新进程运行起来后,菜单的外观就应该是相反的。
首先我们调用getexitcodeprocess函数,其中传入由createprocess返回的句柄。如果getexitcodeprocess返回false,则表示进程尚未运行,我们就让菜单项“terminate process”变灰;如果返回true,表示新进程已经启动了,我们再检测是否正在运行,这通过比较exitcode是否等于still_active 来完成,如果相等,表示进程仍在运行,我们就让菜单项“start process”变灰,因为在我们的简单的应用程序中不提供同时运行多个进程的能力。
.if ax==idm_create_process
.if processinfo.hprocess!=0
invoke closehandle,processinfo.hprocess
mov processinfo.hprocess,0
.endif
invoke getstartupinfo,addr startinfo
invoke createprocess,addr programname,null,null,null,false,\
normal_priority_class,\
null,null,addr startinfo,addr processinfo
invoke closehandle,processinfo.hthread
当用户选择了菜单项“start process”时,我们先检测结构体process_information中的成员变量hprocess是否已经关闭。如果是第一次启动应用程序,那该变量为0,因为我们在.data分段定义结构体时已经初始化该值为0。如果该值不为0,则表明新进程已经结束,但是我们尚未关闭该进程的句柄(以减少该进程的引用记数),我们在此处完成该动作。
我们调用getstartupinfo函数来填充启动信息的结构体变量,而该变量将被传递到createprocess函数中去。调用createprocess生成新进程,我们不检查该函数的返回值为的是让问题简化一些,在实际应用中,必须做该项工作。在调用createprocess后,我们立即关闭在进程信息结构体参数中返回的主线程句柄,关闭线程句柄为的是减少该内核对象的引用记数,否则即使该线程退出后,其内核对象仍惨存在内核中得不到释放,这会引起资源泄露。进程其实也是一样,之所以我们不在该处关闭进程的句柄是因为稍后我们还要用该句柄去得到一些和进程相关的信息,至于线程,我们的应用程序不需要其相关信息。
.elseif ax==idm_terminate