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 はアプリケーションのメイン スレッドではないことに注意してください。そのため、1 回のアプリケーション実行で何度も作成および破棄できます。非常に単純化されたウィンドウ作成には注意を払わないでください。この特定のウィンドウは、画面に表示されることを意図していません。別のアプリケーションからメッセージを受信する目的でのみ作成されます。これは、CreateWindowEx 関数を呼び出すときに、hWndParent パラメーターの HWND_MESSAGE 値を使用して強調表示されます。

4

2 に答える 2

1

上記の例で何度もスレッドを作成、実行、破棄することで、メッセージループから抜けた後に2つのメソッドを呼び出す必要があることがわかりました。1 つ目はDestroyWindowで、2 つ目はUnregisterClassです。通常のアプリケーションでは、ユーザーが本当にアプリケーションを閉じることを確認した後、WM_CLOSE ハンドラでDestroyWindow関数を呼び出す必要があります。DestroyWindow関数は、WM_DESTROY および WM_NCDESTROY メッセージをウィンドウに送信します。WM_DESTROY メッセージに応答して、アプリケーションはPostQuitMessage(0)関数を呼び出す必要があります。これにより、メッセージ ループがすぐに終了します。したがって、コードのこの部分は、すべてのシナリオで必要というわけではありません。私は電話する必要がありましたWM_QUITメッセージを送信するだけでメッセージ ループを終了するため、明示的に DestroyWindow 関数を使用しますそうしないと、ウィンドウ クラスの登録を解除しようとすると、エラー 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 自体が何をアンロードし、何を自分でアンロードする必要があるかを判断してください。

たとえば、HWNDHWNDの s が破棄されると、 s も破棄されます。

最善の方法は、個人的に作成したものをすべてアンロードすることです。アンロード時に特定の関数からエラーが返された場合は、Windows または関連するリソースによってアンロードされているため、アンロードしないでください。

クラッシュの原因となる可能性があるため、不要なときに物をアンロードしないことが重要です。

たとえば、リソースから直接作成されたウィンドウで作成されたアイコンは、アンロードしないでください。ただし、HBITMAP作成して他のウィンドウに描画するものは、確実にアンロードする必要があります。

セクションの質問は、ブレークポイントを使用した簡単なテストで判断できます。私は頭の上から知りません。

于 2013-08-20T14:59:44.840 に答える