最近、2 つの Win32 API 呼び出し "PostMessage" と "SendNotifyMessage" の間に奇妙な違いがありました (少なくとも Win7 64 ビット SP1 で気付きました): 別のプロセスの所有されたトップレベル ウィンドウは、ブロードキャストされたメッセージ (HWND_BROADCAST) を "その WndProc で「SendNotifyMessage」でブロードキャストされたメッセージを受信している間、PostMessage」。
送信されたメッセージは、「RegisterWindowMessage」への呼び出しの助けを借りて登録されています。
Spy++ を使用しても、「PostMessage」を使用するとメッセージが到着するのを確認できません。さらに、「PostMessage」を使用して特定の HWND にメッセージを直接送信すると、期待どおりに到着することにも言及したいと思います。したがって、「PostMessage」のウィンドウ内部実装は、ブロードキャストの実行を反復するときにウィンドウをスキップするだけのようです。
それぞれの MSDN のドキュメントを読んでも、この違いに関する記述は見当たらず、これが PostMessage または SendNotifyMessage のバグなのかどうか、また Windows の将来のバージョンで引き続きこの動作を示すために SendNotifyMessage に依存できるかどうか疑問に思っています。
では、この状況で両方の機能がブロードキャストを異なる方法で処理する理由について、誰かがもっともらしい説明を持っていますか?
さらに、PostMessage を使用して、所有されているトップレベル ウィンドウにブロードキャストする方法があるかどうかを尋ねたいと思います。します)。
トップレベルの所有ウィンドウに到達したい理由に興味がある場合: WPF では、非表示の所有者ウィンドウを持つトップレベル ウィンドウを所有することにより、ウィンドウはタスクバー (Window.ShowInTaskbar プロパティ) から隠されます。
このトピックに関するアイデアやコメントをお寄せいただきありがとうございます。
添付ファイル: ここに動作を示すサンプルがあります...単純にビルドして 2 回開始します...2 番目のプロセスは、最初のプロセスにメッセージを表示する必要があります。ビルド EXE を含む完全なソリューションへのリンクもここにあります:完全な VS ソリューションへのリンク
#include <windows.h>
#include <stdio.h>
#include <string>
#include <vector>
HWND hwndMain = NULL;
HWND ownerHwnd = NULL;
std::vector<std::string> theOutput;
UINT MyRegisteredMessage1 = 0;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc = NULL;
if (message == MyRegisteredMessage1 && wParam != (WPARAM) hwndMain)
{
if (lParam == (LPARAM) 1)
theOutput.push_back("Got a 'MyRegisteredMessage1' via PostMessage");
if (lParam == (LPARAM) 2)
theOutput.push_back("Got a 'MyRegisteredMessage1' via SendNotifyMessage");
InvalidateRect(hwndMain, NULL, TRUE);
}
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
for(size_t i = 0, pos = 0; i < theOutput.size(); ++i, pos += 20)
TextOutA(hdc, 0, pos, theOutput[i].c_str(), theOutput[i].size());
EndPaint (hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK WndProcHidden(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hWnd, message, wParam, lParam);
}
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
MSG msg;
BOOL bRet;
WNDCLASSA wc;
UNREFERENCED_PARAMETER(lpszCmdLine);
if (!hPrevInstance)
{
wc.style = 0;
wc.lpfnWndProc = (WNDPROC) WndProcHidden;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon((HINSTANCE) NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);;
wc.lpszMenuName = "MainMenu";
wc.lpszClassName = "MyOwnerWindowClass";
if (!RegisterClassA(&wc))
return FALSE;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.lpszClassName = "MyOwnedWindowClass";
if (!RegisterClassA(&wc))
return FALSE;
}
ownerHwnd = CreateWindowA("MyOwnerWindowClass", "OwnerWindow",
WS_OVERLAPPEDWINDOW, 0, 0, 800, 400, (HWND) NULL,
(HMENU) NULL, hInstance, (LPVOID) NULL);
hwndMain = CreateWindowA("MyOwnedWindowClass", "OwnedWindow",
WS_OVERLAPPEDWINDOW, 0, 0, 800, 400, ownerHwnd,
(HMENU) NULL, hInstance, (LPVOID) NULL);
// only show the "real" window
ShowWindow(hwndMain, nCmdShow);
UpdateWindow(hwndMain);
MyRegisteredMessage1 = RegisterWindowMessageA("MyRegisteredMessage1");
char infoText[256];
_snprintf_s(infoText, 256,
"HWND = %X, registered message code for 'MyRegisteredMessage1' = %d",
hwndMain, MyRegisteredMessage1);
theOutput.push_back(infoText);
InvalidateRect(hwndMain, NULL, TRUE);
PostMessage(HWND_BROADCAST, MyRegisteredMessage1, (WPARAM) hwndMain, (LPARAM) 1);
Sleep(1000);
SendNotifyMessageA(HWND_BROADCAST, MyRegisteredMessage1, (WPARAM) hwndMain, (LPARAM) 2);
while( (bRet = ::GetMessage( &msg, NULL, 0, 0 )) != 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}