2016-10-13 1 views
0

die Dokumentation für SendMessageTimeout Lese ich das einzig Mal, dachte SendMessageTimeout würde die Timeout-Parameter ignorieren war, wenn entweder:Unter welchen Bedingungen ignoriert SendMessageTimeout (..., SMTO_NORMAL, ...) den Timeout-Parameter beim Senden an einen anderen Prozess?

  1. Das Zielfenster gehört zum selben Thread
  2. Oder „Wenn das Fenster der Nachricht an dem gehört Empfang gleiche Warteschlange wie der aktuelle Thread [...]“

Aber ich habe einen Fall anzutreffen, wo entweder ich bin Missverständnis, was MSDN bedeutet durch‚gleiche Warteschlange‘oder etwas anderes los ist.

Wenn MSDN die gleiche Warteschlange schreibt, denke ich, sie beziehen sich auf die Probleme im Zusammenhang mit der Verwendung AttachThreadInput, die ich aus dem Lesen The Old New Thing ist möglicherweise gefährlich.

Ich habe mein Bestes versucht, ein minimales Beispiel zu erstellen, das hoffentlich immer noch den tatsächlichen Fall widerspiegelt, den ich erlebt habe. Ich bin nicht auf der Suche nach bestimmten Problemumgehungen, da ich bereits viele Möglichkeiten habe, dieses genaue Problem zu vermeiden.

In kurzen Prozess A sendet regelmäßig eine Nachricht an alle Fenster. Prozess B überwacht Prozess A und entscheidet sich irgendwann höflich, ihn zu schließen. Prozess B verwendet SendMessageTimeout, um den Fall zu berücksichtigen, in dem Prozess A nicht gespeicherte Änderungen aufweist, und in seinem WM_CLOSE-Handler einen Dialog zu erstellen.

Ich habe dies auf Win8.1 und Win10 getestet. Kompiliert mit MSVC2015 Update 2 und 3, aber ich denke nicht, dass MSVC/MSVC Version/C (++) spezifisch ist.

kompilieren und ausführen: cl /nologo /W4 /EHsc a.cpp user32.lib && cl /nologo /W4 /EHsc b.cpp user32.lib && a.exe && b.exe

Dies sollte ein „Warten“ Dialog in Verfahren A. bringen Ich war Prozess B erwartet einen Fehlerdialog angezeigt werden sagen SendMessageTimeout gescheitert, aber es funktioniert nicht. Es hängt, bis der Dialog in Verfahren A geschlossen ist

// a.cpp 
#include <windows.h> 

#define CLASS_NAME TEXT("A_WINDOW_CLASS") 

LRESULT CALLBACK WndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) 
{ 
    static UINT uCommonMsg = RegisterWindowMessage(TEXT("CommonMsg")); 
    const int nTimerId = 100; 
    DWORD_PTR dwResult; 
    switch (uiMsg) { 
     case WM_CREATE: 
      return SetTimer(hwnd, nTimerId, 1000, nullptr); 
     case WM_DESTROY: 
      KillTimer(hwnd, nTimerId); 
      PostQuitMessage(0); 
      break; 
     case WM_TIMER: 
      SendMessageTimeout(HWND_BROADCAST, uCommonMsg, 0, 0, SMTO_NORMAL, 1000, &dwResult); 
      return 0; 
     case WM_CLOSE: 
      MessageBox(hwnd, TEXT("Waiting..."), CLASS_NAME, MB_OK); 
      break; 
    } 

    return DefWindowProc(hwnd, uiMsg, wParam, lParam); 
} 

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE, LPSTR, int) 
{ 
    WNDCLASS wc = { 0 }; 
    wc.lpfnWndProc = WndProc; 
    wc.hInstance = hinst; 
    wc.hCursor = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 
    wc.lpszClassName = CLASS_NAME; 

    if (!RegisterClass(&wc)) return GetLastError(); 

    HWND hwnd = CreateWindow(CLASS_NAME, CLASS_NAME, WS_VISIBLE|WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hinst, 0); 
    if (!hwnd) return GetLastError(); 

    MSG msg; 
    while (GetMessage(&msg, NULL, 0, 0)) { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 
    return 0; 
} 
// b.cpp 
#include <windows.h> 

HWND hwndAWindow; 
int nReceived; 

LRESULT CALLBACK WndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) { 
    static UINT uCommonMsg = RegisterWindowMessage(TEXT("CommonMsg")); 

    if (uiMsg == uCommonMsg) { 
     ++nReceived; 
     return 0; 
    } 

    DWORD_PTR dwResult; 
    switch (uiMsg) { 
     case WM_CREATE: return uCommonMsg != 0; 
     case WM_DESTROY: PostQuitMessage(0); break; 
     case WM_USER: 
      // Ask window A to close 
      if (!SendMessageTimeout(hwndAWindow, WM_CLOSE, 0, 0, SMTO_NORMAL, 5000, &dwResult)) { 
       MessageBox(hwnd, TEXT("SendMessageTimeout failed"), TEXT("Error"), MB_ICONERROR|MB_OK); 
      } 
      SendMessage(hwnd, WM_CLOSE, 0, 0); // We're done 
      return 0; 
    } 

    return DefWindowProc(hwnd, uiMsg, wParam, lParam); 
} 

#define CLASS_NAME TEXT("B_WINDOW_CLASS") 

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE, LPSTR, int) { 
    hwndAWindow = FindWindow(TEXT("A_WINDOW_CLASS"), nullptr); 
    if (!hwndAWindow) return -1; 

    WNDCLASS wc = { 0 }; 
    wc.lpfnWndProc = WndProc; 
    wc.hInstance = hinst; 
    wc.hCursor = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 
    wc.lpszClassName = CLASS_NAME; 

    if (!RegisterClass(&wc)) return GetLastError(); 

    HWND hwnd = CreateWindow(CLASS_NAME, CLASS_NAME, WS_VISIBLE|WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hinst, 0); 
    if (!hwnd) return GetLastError(); 

    MSG msg; 
    while (GetMessage(&msg, NULL, 0, 0)) { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 

     // Once we're sure A is up and running ask window B to do its thing 
     if (nReceived) { 
      PostMessage(hwnd, WM_USER, 0, 0); 
     } 
    } 
    return 0; 
} 

Antwort

0

Sie wahrscheinlich

if (!SendMessageTimeout(hwndAWindow, WM_CLOSE, 0, 0, SMTO_NORMAL | SMTO_ABORTIFHUNG, 5000, &dwResult)) 

in b.cpp wollen.

Auch WM_CLOSE kann nicht gesendet werden - es kann only be posted. Senden WM_CLOSE Querfaden endet oft mit einem RPC_E_CANTCALLOUT_ININPUTSYNCCALL Fehler.

+0

Vielen Dank für Ihre Antwort, aber ich kann nicht sehen, wo der verlinkte Beitrag sagt, dass 'WM_CLOSE' * nicht * gesendet werden kann, nur ein Kommentar, wo Herr Chen sagt, dass es" normalerweise gepostet "ist? Ich fand sogar diesen, zugegebenermaßen alten [KB-Artikel] (https://support.microsoft.com/en-us/kb/178893), der die Verwendung von SendMessageTimeout behandelt, um eine 'WM_CLOSE'-Nachricht an eine andere Anwendung zu senden. Auch das Hinzufügen von SMTO_ABORTIFHUNG ändert nichts (zumindest auf meiner Maschine), was wie erwartet ist, da Prozess A nicht aufgehängt wird. – user786653

+0

Es ist * Weg * unten in den Kommentaren ([Link hier] (https://blogs.msdn.microsoft.com/oldnewthing/20050222-00/?p=36393#comment-257363)). –

+0

Das ist der Kommentar, auf den ich mich beziehe, aber soweit ich das beurteilen kann, gilt das nur für Anwendungen, die [COM] verwenden (https://support.microsoft.com/en-us/kb/198996), was nicht das ist Fall hier. Wenn der Aufruf von SendMessageTimeout von Prozess B fehlgeschlagen wäre, wäre das in Ordnung, aber das Problem ist, dass es für immer hängt (?). – user786653

Verwandte Themen