最近遇到个问题,写的客户端在升级,或者重新安装时,有时候原始程序无法关闭,导致安装或升级失败,将目前的关闭流程记录如下。
将我们的客户端 命名为"测试客户端",对应的exe文件命名为"test.exe".
首先,我们在客户端程序里面,增加接收关闭消息的代码。(收到2048即关闭窗口)
IntPtr hwnd = new WindowInteropHelper(this).Handle;
HwndSource.FromHwnd(hwnd).AddHook(new HwndSourceHook(WndPrc));
private IntPtr WndPrc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == 2048)
{
this.Tag = "True";
this.Close();
}
return IntPtr.Zero;
}
首先是再次安装时的要关闭原客户端。
打包工具用的是inno setup.
IsTask.dll提供在进程中寻找并杀死进程的函数。(可以直接csdn资源里面下载)
我们将IsTask.dll引入,放到Files 部分。(IsTask.dll一定要放在最上面,如果放在别的文件后面会很影响安装程序加载速度!!!)
[Files]
Source: "..\..\IsTask.dll";Flags:dontcopy noencryption
然后 将函数引入 并编写安装前的逻辑.先按正常逻辑 根据客户端名称"测试客户端" 发送2048给客户端,接下来在进程中检测test.exe,如果仍存在,直接kill掉。
function RunTask(FileName: string; bFullpath: Boolean): Boolean;
external 'RunTask@files:ISTask.dll stdcall delayload';
function KillTask(ExeFileName: string): Integer;
external 'KillTask@files:ISTask.dll stdcall delayload';
function InitializeSetup():Boolean;//在安装前检测应用程序是否已经启动,启动则关闭
begin
Result:=true;
HasRun:=FindWindowByWindowName('测试客户端');
if HasRun<>0 then
begin
SendMessage(HasRun,2048,0,0);
end
else
begin
Result:=true;
end;
if RunTask('test.exe',false) then
begin
KillTask('test.exe');
end
else
begin
Result:=true;
end;
end;
再看升级流程。(我们的在线升级流程 可以简单的理解为文件替换,所以升级前需要把原始客户端关闭)
同样分为两步,第一步发送2048消息,第二步强制kill
IntPtr hWnd = FindWindow(null, "测试客户端");
if (hWnd != IntPtr.Zero)
{
int pid = 0;
int ret = GetWindowThreadProcessId(hWnd, out pid);
Process p = null;
try
{
p = Process.GetProcessById(pid);
}
catch (Exception ex)
{
}
try
{
SendMessage(hWnd.ToInt32(), 2048, new IntPtr(14), IntPtr.Zero);
}
catch (Exception ex)
{
}
if (p != null)
{
p.WaitForExit(3000);
if (!p.HasExited)
{
p.Kill();
}
}
}
try
{
//为保证确实关闭 再加一个直接杀死过程
Process[] prcs = Process.GetProcessesByName("test");
if (prcs != null && prcs.Length != 0)
{
foreach (var item in prcs)
{
//托盘程序,CloseMainWindow只是将程序最小化,不会退出
//if (!item.CloseMainWindow())
{
try
{
item.Kill();
}
catch (Exception ex)
{
}
}
}
}
}
catch (Exception ex)
{ }