Почему моя таблица свойств, отображаемая в виде значка в системном трее, может блокировать панель задач?

StackOverflow https://stackoverflow.com/questions/1498286

  •  19-09-2019
  •  | 
  •  

Вопрос

Примечание:образцы кода были упрощены, но общая структура осталась нетронутой.

Я работаю над приложением Win32, основным интерфейсом которого является значок в системном трее.Я создаю фиктивное окно, используя HWND_MESSAGE как его родительский элемент, для получения сообщений значка:

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);

Затем создается значок, относящийся к этому окну, предназначенному только для сообщений:

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

При двойном щелчке на значке в трее я создаю и показываю таблицу свойств (из 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);
}

Таблица свойств не имеет родительского окна.В PropertySheet функция вызывается из оконной процедуры окна только для сообщений.В PSH_MODELESS флаг не установлен;таким образом, PropertySheet возвращается только после того, как окно таблицы свойств снова будет закрыто:

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);
}

Теперь все это работает просто отлично, пока я не установлю точку останова внутри диалоговой процедуры одной из страниц таблицы свойств:

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

Когда программа останавливается на точке останова, вся панель задач блокируется!

Стек вызовов совершенно бесполезен;это показывает, что диалоговая процедура вызывается откуда-то изнутри comctl32.dll, через некоторые вызовы внутри user32.dll.Никакой моей собственной оконной процедуры между ними нет.

Сделать таблицу свойств немодальной, похоже, не помогает.Кроме того, я бы предпочел не делать этого, потому что это делает код более сложным.

Пока моя диалоговая процедура возвращается достаточно быстро, это не должно быть проблемой.Но кажется настолько странным, что более длительная операция внутри процедуры диалога привела бы к блокировке не только самого диалога, но и всей оболочки.Я могу себе представить, что процедура окна только для сообщений способна вызвать такое поведение, поскольку она более тесно связана со значком в трее...но эта функция не отображается в стеке вызовов.

Я делаю что-то в корне неправильное?Кто-нибудь может пролить некоторый свет на этот вопрос?

Это было полезно?

Решение

На самом деле, это довольно очевидно, и путаница, должно быть, произошла из-за нехватки кофе.

Панель задач, вероятно, использует SendMessage чтобы отправить сообщение в мое приложение, которое блокирует его до тех пор, пока сообщение не будет обработано. SendMessageTimeout по-видимому, не используется.

Я все еще думаю, что странно, что ни одна моя собственная функция не отображается в стеке вызовов.Конечно, такое сообщение должно проходить через мой цикл сообщений, чтобы быть обработанным?Возможно, тогда предупреждение о том, что "кадры стека ниже этой строки могут быть неполными или отсутствовать", на самом деле было правильным.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top