MFC encapsule de nombreux contrôles couramment utilisés et encapsule les noms de classe sans fournir d'interface évidente. Pour écrire un programme de fenêtre à l'aide de Win API, la première étape consiste à enregistrer la classe de fenêtre.
À l'heure actuelle, le nom de la classe et le nom du titre sont enregistrés ensemble, de sorte que le titre peut être facilement défini par l'utilisateur. Malheureusement, MFC ne le fait pas. La raison peut être le nom de la fenêtre. peut être modifié en continu, mais le nom de la classe ne le peut pas. Le nom de classe de la fenêtre est déterminé par Create. Avant Create, vous devez sélectionner un nom de classe de fenêtre enregistré pour la fenêtre En tant que paramètre, la fenêtre Create sera ok. La création de CWnd ira finalement à CreateEx. chez CreateEx. Beaucoup plus clair.
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 | Afx isvalidatom ( lpszClassName )); ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName)); // autorise la modification de plusieurs paramètres de création courants CREATESTRUCT cs; style = dwStyle; cs.y = y; cs.cx = nWidth; cs.hwndParent = hWndParent; ) { 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, "Avertissement : échec de la création de la fenêtre : GetLastError renvoie 0x%8.8 Xn", GetLastError()); }#endif if (!AfxUnhookWindowCreate()) PostNcDestroy(); // nettoyage si CreateWindowEx échoue trop tôt si (hWnd == NULL) return FALSE; ASSERT(hWnd == m_hWnd); // aurait dû être défini dans send msg hook return TRUE ;}
Vous pouvez voir qu'il atteint enfin ::AfxCtxCreateWindowEx. Vous pouvez facilement savoir que CreateWindowEx est appelé ici pour créer une fenêtre.
Il y a un PreCreateWindow(cs) devant, et une fois que cs est traité par PreCreateWindow, il est remis à ::AfxCtxCreateWindowEx pour le traitement
::AfxCtxCreateWindowEx est transféré vers CreateWindowEx. cs.lpszClass est le nom de la classe, ce qui indique clairement qu'AfxCtxCreateWindowEx a de bonnes intentions.
Nous pouvons surcharger PreCreateWindow pour modifier le nom de la classe, comme suit :
// À FAIRE : ajoutez du code spécialisé ici et/ou appelez la classe de base //VERIFY(AfxDeferRegisterClass(AFX_WND_REG)); //AfxEndDeferRegisterClass(AFX_WND_REG); //cs.lpszClass = AfxRegisterWndClass(NULL); 0, sizeof(WNDCLASS)); // commence par NULL // valeurs par défaut wndcls.style = CS_DBLCLKS | CS_VREDRAW; //vous pouvez spécifier votre propre procédure de fenêtre wndcls.lpfnWndProc = ::DefWindowProc; ; wndcls.hIcon = NULL; // ou charger une autre icône wndcls.hCursor =NULL; wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); wndcls.lpszMenuName = NULL // Spécifiez votre propre nom de classe pour utiliser FindWindow plus tard; wndcls.lpszClassName = _T("MyNewClass"); // Enregistrez la nouvelle classe et quittez-la en cas d'échec if(!AfxRegisterClass(&wndcls)) { TRACE("Class Registration Failedn"); return FALSE } cs.lpszClass = wndcls.lpszClassName ; renvoie VRAI ; //retourne CWnd::PreCreateWindow(cs);
En fait, il s'agit de transmettre une chaîne de nom de classe enregistrée à CreateWindowEx. À en juger par les commentaires dans le code ci-dessus, j'ai également utilisé AfxRegisterWndClass, une méthode qui permet au système de générer un nom de classe. CWnd::PreCreateWindow ne correspond pas à mes souhaits, alors je l'ai commenté. En fait, il n'y a rien dedans, c'est juste un jugement. Dans MFC, les autres classes dérivées de CWnd ne sont pas si simples. Cependant, il suffit de modifier le nom de la classe et de surcharger cette méthode.
Oui, la plupart d’entre eux le peuvent. Malheureusement, cette méthode ne fonctionne pas pour Dialog, car elle n’utilise pas CWnd::Create, elle ne peut donc pas être contournée.
PreCreateWindow arrive. Vous pouvez surcharger cette méthode de la boîte de dialogue. Les points d'arrêt ne peuvent pas être interrompus. Étant donné que la création de CDialog peut être effectuée directement à l'aide de l'API du système et qu'il n'est pas nécessaire de déranger CWnd pour le transfert vers CReateWindowEx, vous ne pouvez donc pas utiliser la méthode ci-dessus pour modifier le nom de classe de la boîte de dialogue.
Jetez un œil à son code de création :
BOOL CDialog::Create(LPCTSTR lpszTemplateName, CWnd* pParentWnd){ ASSERT(IS_INTRESOURCE(lpszTemplateName) || AfxIsValidString(lpszTemplateName)); m_lpszTemplateName = lpszTemplateName; // utilisé pour l'aide si (IS_INTRESOURCE(m_lpszTemplateName) && m_nID Help == 0) m_nIDHelp = LOWORD((DWORD_PTR)m_lpszTemplateName);#ifdef _DEBUG if (!_AfxCheckDialogTemplate(lpszTemplateName, FALSE)) { ASSERT(FALSE); // nom de modèle de dialogue invalide PostNcDestroy(); // le nettoyage si la création échoue trop tôt renvoie FALSE ; } #endif //_DEBUG HINSTANCE hInst = AfxFindResourceHandle(lpszTemplateName, RT_DIALOG); HRSRC hResource = ::FindResource(hInst, lpszTemplateName, RT_DIALOG); ) ; FreeResource(hTemplate); retourner bResult;}
On peut voir que CDialog est créé par les ressources. Cela peut être fait de cette manière. Définissez la classe "nom de classe de dialogue" dans le script de ressource. Enregistrez ce nom de classe avant domodal ou Create dans la boîte de dialogue, puis attendez modal et. Créer. C'est tout.
Pendant cette période, j'ai été occupé avec d'autres aspects et j'ai beaucoup oublié le mécanisme d'empaquetage MFC. Je vais retracer le code comme rappel.