为什么我的 Windows API 回调函数不运行?

Why doesn't my Windows API callback function run?

本文关键字:运行 函数 回调 我的 Windows API 为什么      更新时间:2023-10-16

我写了一个终止egui.exe的代码。但是我的回调函数在处理WM_CLOSE消息后不会运行。为什么?

#include <iostream>
#include <windows.h>
#include <psapi.h>
using namespace std;
HWND ESETWindow = 0;    //Variable to store a handle to the main window
// of ESET Smart Security
HWND ConfirmationWindow = 0;    //Variable to store a handle to the
// confirmation dialog box that appears
// when a WM_CLOSE message is sent to
// the ESET window.
DWORD EGUIPID = 0;  //Variable to store the process identifier of egui.exe
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam);
VOID SendAsyncProc(HWND hwnd, UINT uMsg, ULONG_PTR dwData, LRESULT lResult);
int main()
{
cout << "Terminating ESET Smart Security..." << endl;
//Obtain an array of process identifiers including the PID of egui.exe
DWORD PIDs[1024]; //The array of process identifiers
DWORD bytesReturned;
if (!EnumProcesses(PIDs, sizeof(PIDs), &bytesReturned))
{
cerr << "Unable to enumerate the processes." << endl;
return 0;
}
//Enumerate the PIDs array to find the process of egui.exe.
DWORD nProcesses = bytesReturned / sizeof(DWORD);
for (DWORD i = 0;i < nProcesses;i++)
{
//Open the process to examine its executable file name.
HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, PIDs[i]);
//Create a buffer for the name of the executable file.
PSTR processName = (PSTR) VirtualAlloc((LPVOID) NULL, (DWORD) 10, MEM_COMMIT, PAGE_READWRITE);
//Get the name of the executable file name.
GetModuleBaseName(process, NULL, processName, 10);
//Check if the executable file name is egui.exe.
if (!lstrcmpi(processName, TEXT("egui.exe")))
{
EGUIPID = PIDs[i];
break;
}
VirtualFree(processName, 0, MEM_RELEASE);
CloseHandle(process);
}
//Display an error message if the process identifier of egui.exe
//could not be found.
if (!EGUIPID)
{
cerr << "Unable to find process identifier of egui.exe" << endl;
return 0;
}
//Enumerate the top-level windows to find the main window of
// ESET Smart Security and store a handle to that window in the
// ESETWindow variable.
EnumWindows(EnumWindowsProc, 0);
//Display an error message if the window could not be found.
if (!ESETWindow)
{
cerr << "Unable to find the primary window of ESET Smart Security." << endl;
return 0;
}
//Send a WM_CLOSE message to the main window of egui.exe in order
// to display a confirmation dialog box.
if (!SendMessageCallback(ESETWindow, WM_CLOSE, 0, 0, SendAsyncProc, 0))
{
cerr << "Unable to send a WM_CLOSE message to the primary window of ESET Smart Security." << endl;
return 0;
}
//Wait a second for the confirmation dialog box to appear...
Sleep(1000);
//Enumerate the windows again to find the confirmation dialog box.
EnumWindows(EnumWindowsProc, 1);
//Display an error message if the confirmation dialog box
// could not be found.
if (!ConfirmationWindow)
{
cerr << "Unable to find confirmation message." << endl;
cout << "If you have ESET NOD32, it is probably terminated successfully.";
cin.get();
}
//Find the Yes button in the confirmation dialog box and display
// an error message if failed.
HWND button = FindWindowEx(ConfirmationWindow, NULL, NULL, TEXT("&Yes"));
if (!button)
{
cerr << "Unable to find Yes button in the message box." << endl;
return 0;
}
//Activate the confirmation dialog box and simulate a mouse click
// on the Yes button.
SetActiveWindow(ConfirmationWindow);
SendMessage(button, BM_CLICK, 0, 0);
cout << "ESET Smart Security was successfully terminated!";
//Keep the program running until the user presses Enter
// in the console window.
cin.get();
return 0;
}
//If lParam is 0, the function below finds the main window of
//ESET Smart Security, otherwise, it finds the confirmation
//dialog box.
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
//Check if hwnd belongs to a window of egui.exe.
DWORD PID = 0;
GetWindowThreadProcessId(hwnd, &PID);
if (PID != EGUIPID)
return TRUE; //Exit function and continue the enumeration.
//Check if the title of the window is "ESET Smart Security"
// or "ESET Node32 Antivirus".
int len = GetWindowTextLength(hwnd);
PSTR title = (PSTR) VirtualAlloc((LPVOID) NULL, (DWORD) (len + 1), MEM_COMMIT, PAGE_READWRITE);
GetWindowText(hwnd, title, (len + 1));
if ((lstrcmp(title, TEXT("ESET Smart Security"))) && (lstrcmp(title, TEXT("ESET NOD32 Antivirus"))))
return TRUE; //Exit function and continue the enumeration.
if (lParam)
{
//If lParam is nonzero and hwnd refers to the main
// window of egui.exe, exit function and continue
// the enumeration.
if (hwnd == ESETWindow)
return TRUE;
//Otherwise hwnd refers to the confirmation dialog box.
//So store it in the ConfirmationWindow variable.
ConfirmationWindow = hwnd;
return FALSE; //Exit function and stop the enumeration.
}
else
{
//hwnd refers to the main window of ESET Smart Security.
//So store it in the ESETWindow variable.
ESETWindow = hwnd;
return FALSE; //Exit function and stop the enumeration.
}
}
VOID SendAsyncProc(HWND hwnd, UINT uMsg, ULONG_PTR dwData, LRESULT lResult)
{
MessageBox(0, TEXT("ESET Smart Security was successfully terminated."), TEXT("Result"), MB_OK);
}

尽管该程序完美地完成了其任务,但在处理WM_CLOSE消息并终止 egui.exe 后,回调函数 SendAsyncProc 不会运行。你能告诉我为什么吗?

SendMessageCallback 的文档会告诉您为什么永远不会调用您的回调:

如果目标窗口属于与调用方不同的线程,则仅当调用SendMessageCallback的线程也调用GetMessagePeekMessageWaitMessage时,才会调用回调函数。

目标窗口显然属于不同的线程,因为它在不同的进程中运行。代码不执行任何消息检索。无回调。