正确的破坏窗口资源的方法

时间:2013-08-20 13:41:40

标签: windows winapi resources

这是我基于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返回没有错误)?

  3. 请注意,TMyThread不是应用程序的主线程。因此,它可以在一次应用程序运行中多次创建和销毁。请不要注意非常简化的窗口创建。此特定窗口并不意味着在屏幕上可见。它的创建仅用于接收来自其他应用程序的消息。调用CreateWindowEx函数时,使用hWndParent参数的HWND_MESSAGE值突出显示。

2 个答案:

答案 0 :(得分:1)

通过在上面的例子中反复创建,运行和销毁线程,我发现从消息循环中退出后需要调用两个方法。首先是 DestroyWindow ,其次是 UnregisterClass 。在用户确认他确实要关闭应用程序之后,在WM_CLOSE处理程序中的常规应用程序 DestroyWindow 函数should be called中。 DestroyWindow 函数然后将WM_DESTROY和WM_NCDESTROY消息发送到窗口。响应WM_DESTROY消息,应用程序应调用 PostQuitMessage(0)函数,该函数会立即退出消息循环。所以这部分代码在所有场景中都不是必需的。我需要显式调用 DestroyWindow 函数,因为我只是通过发送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);
}

答案 1 :(得分:0)

您必须非常小心Win32中的资​​源。确保您仔细查看了文档,以确定Windows本身将为您卸载的内容以及您必须自行卸载的内容。

例如,当HWND被破坏时,HWND将被销毁。

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

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

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

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