WM_CLOSEメッセージを使用してC#アプリケーションを閉じると、予期しない動作が発生します。私のシナリオでは、MSIインストールパッケージの実行時にC#アプリケーションが閉じていることを確認する必要があります。MSIにはこれに対する適切なアクションがないため、MSIパッケージに埋め込まれ、EnsureApplicationClosed関数を公開するカスタムアクションDLLを作成していました。以下の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#アプリケーションを閉じています。SendMessage(hWnd、WM_CLOSE、(LPARAM)0、(WPARAM)0)がC#アプリケーションでTaskManagerClosing close reasonを生成することがわかったため、このWM_CLOSEメッセージを受信したときに、TaskManagerClosingclosereasonをチェックする必要があります。Console.Beep()は、ハンドラーコードが入力されていることを聞くことができるように、音声信号を生成するためのテストに使用されます。
これが動作するのは、DLLテストアプリケーションを2回実行した場合のみであるという問題。テストアプリケーションを初めて実行したときに、音声信号が聞こえず、C#プロセスがタスクマネージャーに残っています。そのため、C#アプリケーションのFormClosingイベントは発生しません。SendMessageをPostMessageに置き換えようとしましたが、成功しませんでした。GetLastError()は、どちらの場合も常に18を返します。誰かが同じ問題に直面し、それを解決する方法を知っていますか?
前もって感謝します。