MFC encapsulates many commonly used controls and encapsulates the class names without providing an obvious interface. To write a window program using win api, the first step is to register the window class.
At this time, the class name and title name are registered together, so the title can be easily set by the user. The class name should also be very simple. Unfortunately, MFC does not do this. The reason may be that the window name can be changed continuously. Change, but the class name cannot. The class name of the window is determined by Create. Before Create, you need to select a registered window class name for the window. As a parameter, the window Create will be ok. The Create of CWnd will eventually go to CreateEx. Just look at CreateEx. Much clearer
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, LPVOID lpParam /* = NULL */){ return CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle , rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pParentWnd->GetSafeHwnd(), (HMENU)(UINT_PTR)nID, lpParam);}BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam){ ASSERT(lpszClassName == NULL || AfxIsValidString(lpszClassName) || Afx IsValidAtom(lpszClassName )); ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName)); // allow modification of several common create parameters CREATESTRUCT cs; cs.dwExStyle = dwExStyle; cs.lpszClass = lpszClassName; cs.lpszName = lpszWindowName; cs.style = dwStyle; cs.x = x; cs.y = y; cs.cx = nWidth; cs.cy = nHeight; cs.hwndParent = hWndParent; cs.hMenu = nIDorHMenu; = lpParam; if (!PreCreateWindow(cs)) { PostNcDestroy(); return FALSE; } AfxHookWindowCreate(this); HWND hWnd = ::AfxCtxCreateWindowEx(cs.dwExStyle, cs.lpszClass, cs.lpszName, cs.style, cs. x, cs.y, cs.cx, cs.cy, cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);#ifdef _DEBUG if (hWnd == NULL) { TRACE(traceAppMsg, 0, "Warning : Window creation failed: GetLastError returns 0x%8.8Xn", GetLastError()); }#endif if (!AfxUnhookWindowCreate()) PostNcDestroy(); // cleanup if CreateWindowEx fails too soon if (hWnd == NULL) return FALSE; ASSERT(hWnd == m_hWnd); // should have been set in send msg hook return TRUE;}
You can see that it finally reaches::AfxCtxCreateWindowEx. You can easily know that CreateWindowEx is called here to create a window.
There is a PreCreateWindow(cs) in front, and after cs is processed by PreCreateWindow, it is handed over to ::AfxCtxCreateWindowEx for processing
::AfxCtxCreateWindowEx is transferred to CreateWindowEx. cs.lpszClass is the class name, which makes it clear that AfxCtxCreateWindowEx has good intentions.
We can overload PreCreateWindow to modify the class name, as follows:
// TODO: Add specialized code here and/or call the base class //VERIFY(AfxDeferRegisterClass(AFX_WND_REG)); //AfxEndDeferRegisterClass(AFX_WND_REG); //cs.lpszClass = AfxRegisterWndClass(NULL); WNDCLASS wndcls; memset(&wndcls, 0, sizeof(WNDCLASS)); // start with NULL // defaults wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; //you can specify your own window procedure wndcls.lpfnWndProc = ::DefWindowProc; wndcls.hInstance = AfxGetInstanceHandle() ; wndcls.hIcon = NULL; // or load a different icon wndcls.hCursor =NULL; wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); wndcls.lpszMenuName = NULL; // Specify your own class name for using FindWindow later wndcls.lpszClassName = _T("MyNewClass"); // Register the new class and exit if it fails if(!AfxRegisterClass(&wndcls)) { TRACE("Class Registration Failedn"); return FALSE; } cs.lpszClass = wndcls.lpszClassName; return TRUE; //return CWnd::PreCreateWindow(cs);
In fact, it is to pass a registered class name string to CreateWindowEx. Judging from the comments in the above code, I also used AfxRegisterWndClass, a method that allows the system to generate className. CWnd::PreCreateWindow does not suit my wishes, so I commented it out. In fact, there is nothing in it, it is just a judgment. In MFC, other derived classes of CWnd are not so simple. However, simply modifying the class name and overloading this method will mostly be ok.
Yes, most of them can. Unfortunately, this method does not work for Dialog, because it does not use CWnd::Create, so it cannot be circumvented.
PreCreateWindow is coming up. You can overload this method of the dialog box. Breakpoints cannot be broken. Because the creation of CDialog can be done directly using the system's API, and there is no need to bother CWnd to transfer to CReateWindowEx, so you cannot use the above method to change the class name of the dialog box.
Take a look at its creation code:
BOOL CDialog::Create(LPCTSTR lpszTemplateName, CWnd* pParentWnd){ ASSERT(IS_INTRESOURCE(lpszTemplateName) || AfxIsValidString(lpszTemplateName)); m_lpszTemplateName = lpszTemplateName; // used for help if (IS_INTRESOURCE(m_lpszTemplateName) && m_nID Help == 0) m_nIDHelp = LOWORD((DWORD_PTR)m_lpszTemplateName);#ifdef _DEBUG if (!_AfxCheckDialogTemplate(lpszTemplateName, FALSE)) { ASSERT(FALSE); // invalid dialog template name PostNcDestroy(); // cleanup if Create fails too soon return FALSE; } #endif //_DEBUG HINSTANCE hInst = AfxFindResourceHandle(lpszTemplateName, RT_DIALOG); HRSRC hResource = ::FindResource(hInst, lpszTemplateName, RT_DIALOG); HGLOBAL hTemplate = LoadResource(hInst, hResource); BOOL bResult = CreateIndirect(hTemplate, pParentWnd, hInst ) ; FreeResource(hTemplate); return bResult;}
It can be seen that CDialog is created by resources. It can be done in this way. Define Class "dialog class name" in the resource script. Register this class name before domodal or Create in the dialog box, and then wait for modal and Create. That's it.
During this period of time, I have been busy with other aspects, and I have forgotten a lot about the MFC packaging mechanism. I will trace the code as a refresher.