1

这是我基于 win32 api 的代码的摘录:

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

void __fastcall TMyThread::Execute(void)
{
   WNDCLASSEX wc     = {0};
   wc.cbSize         = sizeof(WNDCLASSEX);
   wc.lpfnWndProc    = WindowProc;
   wc.hInstance      = GetModuleHandle(NULL);
   wc.lpszClassName  = class_name.c_str();

   if (!RegisterClassEx(&wc))
   {
      MessageBox(NULL, L"Window Registration Failed!", L"Error", MB_ICONEXCLAMATION | MB_OK);
      return;
   }

   hwnd = CreateWindowEx(0, class_name.c_str(), NULL, 0, 0, 0, 100, 100, HWND_MESSAGE, NULL, wc.hInstance, NULL);
   if (hwnd == NULL)
   {
      MessageBox(NULL, L"Window Creation Failed!", L"Error", MB_ICONEXCLAMATION | MB_OK);
      return;
   }

   MSG msg;
   BOOL ret;
   while ((ret = GetMessage(&msg, 0, 0, 0)) != 0)
   {
      if (ret != -1)
      {
         TranslateMessage(&msg);
         DispatchMessage(&msg);
      }
   }
}

我的问题:

  1. 退出消息循环后是否需要进行一些资源清理(例如 CloseHandle)?我经常看到没有任何此类内容的代码示例。这是对的吗?

  2. 新创建的窗口能否在第一次调用 GetMessage 函数之前将消息接收到线程队列中(我们假设窗口创建成功,即函数 CreateWindowEx 返回没有错误)?

请记住,TMyThread 不是应用程序的主线程。因此它可以在一个应用程序运行中多次创建和销毁。请不要关注相当简化的窗口创建。这个特定的窗口并不意味着在屏幕上可见。它仅是为了从另一个应用程序接收消息而创建的。这通过在调用 CreateWindowEx 函数时使用 hWndParent 参数的 HWND_MESSAGE 值突出显示。

4

2 回答 2

1

通过上面例子中线程的创建、运行和销毁一次又一次的发现,退出消息循环后需要调用两个方法。第一个是DestroyWindow,第二个是UnregisterClass。在常规应用程序中,应在用户确认他确实要关闭应用程序后,在 WM_CLOSE 处理程序中调用DestroyWindow函数。然后DestroyWindow函数将 WM_DESTROY 和 WM_NCDESTROY 消息发送到窗口。作为对 WM_DESTROY 消息的响应,应用程序应调用PostQuitMessage(0)函数,从而立即退出消息循环。所以这部分代码并不是所有场景都需要的。我需要打电话显式销毁窗口函数,因为我只需发送 WM_QUIT 消息即可退出消息循环。如果不这样做,有时我在尝试注销窗口类时收到错误 1412 (ERROR_CLASS_HAS_WINDOWS)。

if (hwnd != NULL)
{
   ret = DestroyWindow(hwnd);
   if (ret == 0)
   {
      str.printf(L"Window destroying failed (GetLastError = %d)!", GetLastError());
      ShowError(str);
   }
   hwnd = NULL;
}

ret = UnregisterClass(class_name.c_str(), wc.hInstance);
if (ret == 0)
{
   str.printf(L"Window class unregistration failed (GetLastError = %d)!", GetLastError());
   ShowError(str);
}
于 2013-08-22T11:17:09.653 回答
0

您必须非常小心 Win32 中的资源。请确保您已仔细查看文档以确定 Windows 本身将为您卸载哪些内容以及您必须自己卸载哪些内容。

例如,HWND当父HWNDs 被销毁时, s 将被销毁。

最好的技巧是尝试卸载您个人创建的所有内容。如果您在卸载时从特定函数返回错误,您可能不应该卸载它,因为它已被 Windows 或某些相关资源卸载。

重要的是不要在不需要时卸载东西,因为这可能会导致崩溃。

因此,例如,使用直接来自资源的窗口创建的图标可能不应该被卸载。但是,HBITMAP您创建的绘制到其他窗口的内容绝对应该被卸载。

您的部分问题可以通过带有断点的快速测试来确定。我不知道我的头顶。

于 2013-08-20T14:59:44.840 回答