使用 WM_CLOSE 消息关闭 C# 应用程序时,我遇到了意外行为。在我的场景中,我需要确保 C# 应用程序在其 MSI 安装包运行时关闭。MSI 对此没有适当的操作,因此我正在编写一个自定义操作 DLL,该 DLL 嵌入到 MSI 包中并公开 EnsureApplicationClosed 函数。DLL相关代码如下:
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>
#include "TlHelp32.h"
std::vector<DWORD> processesList;
//This method is the main point of interest
BOOL CALLBACK enumWindowsProc(__in HWND hWnd, __in LPARAM lParam)
{
if(processesList.size()==0) return FALSE;
DWORD processId;
GetWindowThreadProcessId(hWnd, &processId);
int index=0;
while(index<processesList.size())
{
if(processesList.at(index)==processId)
{
//Remove process id from the list
processesList.erase(processesList.begin()+index);
//Should close main windows of the process found.
SendMessage(hWnd, WM_CLOSE, (LPARAM)0, (WPARAM)0);
}
else
{
index++;
}
}
return TRUE;
}
std::vector<DWORD> FindProcessesId(const LPCWSTR processName)
{
std::vector<DWORD> result;
PROCESSENTRY32 processInfo;
processInfo.dwSize = sizeof(processInfo);
HANDLE processesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if ( processesSnapshot == INVALID_HANDLE_VALUE ) return result;
Process32First(processesSnapshot, &processInfo);
if (wcscmp(processName, processInfo.szExeFile)==0)
{
result.push_back(processInfo.th32ProcessID);
}
while ( Process32Next(processesSnapshot, &processInfo) )
{
if ( wcscmp(processName, processInfo.szExeFile)==0 )
{
result.push_back(processInfo.th32ProcessID);
}
}
CloseHandle(processesSnapshot);
return result;
}
void InnerEnsureApplicationClosed(const LPCWSTR processName)
{
processesList=FindProcessesId(processName);
BOOL enumeratingWindowsSucceeded = ::EnumWindows( enumWindowsProc, NULL );
}
//Function exported by the DLL
UINT __stdcall EnsureApplicationClosed ( MSIHANDLE hModule )
{
InnerEnsureApplicationClosed(L"SomeApplication.exe");
return ERROR_SUCCESS;
}
我正在使用简单的控制台应用程序来测试这个 dll:
#include "stdafx.h"
#include <SomeApplicationCustomActions.h>
int _tmain(int argc, _TCHAR* argv[])
{
EnsureApplicationClosed(NULL);
return 0;
}
C# 应用程序在大多数情况下对用户是不可见的,因为它应该只显示来自第三方应用程序的通知。这就是它具有自定义 FormClosing 处理程序的原因:
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
Console.Beep();
if (e.CloseReason != CloseReason.WindowsShutDown && e.CloseReason!= CloseReason.TaskManagerClosing)
{
e.Cancel = true;
this.Hide();
}
}
我正在使用 SendMessage(hWnd, WM_CLOSE, (LPARAM)0, (WPARAM)0) 关闭 C# 应用程序。当收到此 WM_CLOSE 消息时,需要检查 TaskManagerClosing 关闭原因,因为我发现 SendMessage(hWnd, WM_CLOSE, (LPARAM)0, (WPARAM)0) 在 C# 应用程序中产生 TaskManagerClosing 关闭原因。Console.Beep() 用于测试以产生声音信号,因此我可以听到输入了处理程序代码。
这个问题只有在我第二次运行 DLL 测试应用程序时才有效。当我第一次运行测试应用程序时,我没有听到声音信号并且 C# 进程保留在任务管理器中。所以不会触发 C# 应用程序的 FormClosing 事件。我试图用 PostMessage 替换 SendMessage 但没有成功。GetLastError() 在这两种情况下总是返回 18。有没有人遇到过同样的问题并知道如何解决?
提前致谢。