How to call and use UnregisterClass?

Using Visual Studio 2013

I have an application that can potentially use up to 20 window classes, but not all at the same time. To save space, I decided to unregister those that are no longer needed before starting a new batch of window classes, but I could not get the UnregisterClass function to work.

I called Unregister on WM_DESTROY and / or WM_NCDESTROY , but always returned error 1412, "The class still has an open window." Perhaps the call to Unregister in WM_DESTROY failed because the window has not yet been destroyed, but I did not expect the call to WM_NCDESTROY to fail because this message was sent after the window was destroyed.

The only way to make UnregisterClass work was to call PostQuitMessage at the WM_DESTROY or WM_NCDESTROY . Then, UnregisterClass will work after the message loop before the whole application is finished, but I want to start another group of classes from the application, and not start it all.

I present a test program that shows a problem. This is Win32Project7, the program provided by Visual Studio 2013 with two tiny additions - a wrapped Messagebox (mbox) and a procedure for calling unregister (tryunreg).

One extreme would be to register 20 window classes so that they would be ready when needed, the other would use one window class and multiplex on HWND. Do not get too carried away by any of them.

Questions:

  • Did I make mistakes or erroneous assumptions in this program?
  • Is there a way to make unregisterclass work without closing the program?
  • how much space does a typical window class register require? Is it probably KB or MB? Any way to experiment to find out?

Let's go this way. I did not find anything that is not yet in the documentation, for example. for example, unregister automatically when you exit the application. Stackoverflow has two posts that are similar to this, but with no responses.

The code:

I posted the code as follows:

 <pre> program fragments </pre> 

Enclosed between html pre tags but no message has been sent. An error message indicates that the text was formatted as a program, but the indent was not 4 spaces. This was initially not the case, but I changed it, but it was still not sent. I have never posted questions to this forum, so I'm doing something wrong. What?


Here is the code that I did not know how to send the original message. Better late than never.

 // Win32Project7.cpp : Defines the entry point for the application. #include "stdafx.h" #include "Win32Project7.h" #define MAX_LOADSTRING 100 // Global Variables: HINSTANCE hInst; TCHAR szTitle[MAX_LOADSTRING]; TCHAR szWindowClass[MAX_LOADSTRING]; // Forward declarations of functions included in this code module: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); static void mbox(const wchar_t * msg) // added { int errcode; const wchar_t * caption = L"Info"; int res = MessageBox(NULL, msg, caption, 0); if (res == 0) { errcode = GetLastError(); return; // was setting breakpoint, but never got here // but mbox does not give any output after postquit } } static void tryunreg(const wchar_t * where) // added { int errcode; wchar_t outmsg[100]; BOOL b = UnregisterClass(szWindowClass, hInst); if (!b) { errcode = GetLastError(); wsprintf(outmsg, L"%s: Unreg failed for classname %s errcode %d", where, szWindowClass, errcode); } else { wsprintf(outmsg, L"%s: Unreg worked", where); } mbox(outmsg); } int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // TODO: Place code here. MSG msg; HACCEL hAccelTable; // Initialize global strings LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_WIN32PROJECT7, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJECT7)); // Main message loop: while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } tryunreg(L"After message loop" ); // added this return (int) msg.wParam; } // // FUNCTION: MyRegisterClass() // // PURPOSE: Registers the window class. // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32PROJECT7)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WIN32PROJECT7); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassEx(&wcex); } // // FUNCTION: InitInstance(HINSTANCE, int) // // PURPOSE: Saves instance handle and creates main window // // COMMENTS: // // In this function, we save the instance handle in a global // variable and // create and display the main program window. // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; // Store instance handle in our global variable hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } // // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) // // PURPOSE: Processes messages for the main window. // // WM_COMMAND - process the application menu // WM_PAINT - Paint the main window // WM_DESTROY - post a quit message and return // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; BOOL b; int errcode; wchar_t msg[100]; switch (message) { case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: Add any drawing code here... EndPaint(hWnd, &ps); break; case WM_CLOSE: // added // mbox(L"@wm_close before destroywindow"); DestroyWindow(hWnd); break; case WM_DESTROY: tryunreg(L"@wm_destroy before postquit"); // added PostQuitMessage(0); // in original MS code tryunreg(L"@wm_destroy after postquit"); // added break; case WM_NCDESTROY: // added tryunreg(L"@wm_NCdestroy before postquit"); // added //PostQuitMessage(0); tryunreg(L"@wm_NCdestroy after postquit"); // added break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // Message handler for about box. INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; } 
+5
source share
1 answer

The time that UnregisterClass is required is a dynamically loaded DLL that registers the window class. Such a library should ensure that the class is not registered before it is unloaded, otherwise CreateWindow for this class will make a call to code that is no longer present.

If you decide to unregister window classes, the delay can be entered using QueueUserAPC, however this requires a change in the message loop (to one based on MsgWaitForMultipleObjectsEx and PeekMessage built-in loop). Or you can use a thread message.

I prefer APC because it allows you to untie the code that will be called from the rest of the program. For example, in MFC, using a stream message, you would need to change the message map for the stream class (in most cases, CWinApp).

+1
source

All Articles