2 Stimmen

Warum kann mein Eigenschaftsblatt, das über ein Symbol in der Systemablage angezeigt wird, die Taskleiste blockieren?

Hinweis: Die Codebeispiele wurden vereinfacht, die Gesamtstruktur bleibt jedoch erhalten.

Ich arbeite an einer Win32-Anwendung, deren Hauptschnittstelle ein Symbol in der Taskleiste ist. Ich erstelle ein Dummy-Fenster, indem ich HWND_MESSAGE als übergeordnetes Element, um die Nachrichten des Symbols zu empfangen:

WNDCLASSEX wndClass;
wndClass.lpfnWndProc = &iconWindowProc;
// ...
iconWindowHandle = CreateWindow(wndClass.lpszClassName, _T(""), 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_MESSAGE, NULL, GetModuleHandle(NULL), 0);

Dann wird das Symbol erstellt, das auf dieses Fenster verweist, das nur Nachrichten enthält:

NOTIFYICONDATA iconData;
iconData.hWnd = iconWindowHandle;
iconData.uCallbackMessage = TRAYICON_MESSAGE;
// ...
Shell_NotifyIcon(NIM_ADD, &iconData)

Wenn das Tray-Symbol doppelt angeklickt wird, wird ein Eigenschaftsblatt erstellt und angezeigt (aus comctl32.dll ):

LRESULT CALLBACK iconWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  switch (uMsg) {
    case TRAYICON_MESSAGE:
      switch (lParam) { // that contains the "real" message
        case WM_LBUTTONDBLCLK:
          showPropertySheet();
          return 0;
        // ...
      }
      break;
    // ...
  }
  return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

Das Eigenschaftsblatt hat kein übergeordnetes Fenster. Das PropertySheet Funktion wird von der Fensterprozedur des reinen Nachrichtenfensters aufgerufen. Die PSH_MODELESS Flagge nicht gesetzt ist; daher, PropertySheet kehrt erst zurück, wenn das Eigenschaftsblattfenster wieder geschlossen wird:

void showPropertySheet() {
  PROPSHEETPAGE pages[NUM_PAGES];
  pages[0].pfnDlgProc = &firstPageDialogProc;
  // ...
  PROPSHEETHEADER header;
  header.hwndParent = NULL;
  header.dwFlags = PSH_PROPSHEETPAGE | PSH_USECALLBACK;
  header.ppsp = pages;
  // ...
  PropertySheet(&header);
}

All dies funktioniert gut, bis ich einen Haltepunkt in der Dialogprozedur auf einer der Seiten des Eigenschaftsblatts setze:

BOOL CALLBACK firstPageDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  return FALSE; // breakpoint here
}

Wenn das Programm an dem Haltepunkt anhält, die gesamte Taskleiste wird blockiert !

Der Aufrufstapel ist ziemlich nutzlos; er zeigt, dass die Dialogprozedur von irgendwo innerhalb von comctl32.dll über einige Aufrufe innerhalb user32.dll . Kein eigenes Fensterverfahren liegt dazwischen.

Das Eigenschaftsblatt modellfrei zu machen, scheint nicht zu helfen. Außerdem würde ich lieber nicht tun dies, weil es den Code komplexer macht.

Solange mein Dialogverfahren schnell genug zurückkehrt, sollte dies kein Problem sein. Aber es scheint so seltsam, dass eine längere Operation innerhalb der Dialogprozedur nicht nur den Dialog selbst, sondern die gesamte Shell sperren würde. Ich kann mir vorstellen, dass die Prozedur "message-only window" die Macht hat, dieses Verhalten zu verursachen, da sie enger mit dem Tray-Icon verbunden ist... aber diese Funktion wird nicht auf dem Aufrufstapel angezeigt.

Mache ich etwas grundlegend falsch? Kann jemand etwas Licht in diese Angelegenheit bringen?

1voto

Thomas Punkte 160390

Eigentlich ist es ziemlich offensichtlich, und die Verwirrung muss auf einen Mangel an Kaffee zurückzuführen sein.

Die Taskleiste verwendet wahrscheinlich SendMessage um die Nachricht an meine Anwendung zu senden, was dazu führt, dass sie blockiert, bis die Nachricht verarbeitet ist. SendMessageTimeout wird offensichtlich nicht verwendet.

Ich finde es immer noch seltsam, dass keine eigene Funktion auf dem Aufrufstapel auftaucht. Sicherlich muss eine solche Nachricht durch meine Nachrichtenschleife fließen, um verarbeitet zu werden? Vielleicht war die Warnung, dass "Stack-Frames unterhalb dieser Zeile unvollständig sein oder fehlen können", tatsächlich richtig.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X