2

注意:代码示例已被简化,但整体结构保持不变。

我正在开发一个主界面是系统托盘图标的 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。中间没有我自己的窗口过程。

使属性表无模式似乎没有帮助。另外,我宁愿不这样做,因为它会使代码更复杂。

只要我的对话过程足够快地返回,这应该不是问题。但是看起来很奇怪,对话过程中更长的操作不仅会锁定对话本身,还会锁定整个外壳。我可以想象只有消息的窗口过程有能力导致这种行为,因为它与托盘图标更密切相关......但是这个函数没有显示在调用堆栈上。

我在做一些根本错误的事情吗?任何人都可以对这个问题有所了解吗?

4

1 回答 1

1

实际上,这是相当明显的,混乱一定是由于缺乏咖啡。

任务栏可能用于SendMessage将消息发送到我的应用程序,这会导致它阻塞,直到消息被处理。SendMessageTimeout显然没有使用。

我仍然认为调用堆栈上没有显示我自己的函数很奇怪。当然,这样的消息必须通过我的消息循环才能被处理?那么,“此行下方的堆栈帧可能不完整或丢失”的警告可能实际上是正确的。

于 2009-10-02T07:00:14.843 回答