MFC encapsula muchos controles de uso común y encapsula los nombres de las clases sin proporcionar una interfaz obvia. Para escribir un programa de ventana usando win api, el primer paso es registrar la clase de ventana.
En este momento, el nombre de la clase y el nombre del título se registran juntos, por lo que el usuario puede configurar fácilmente el título. Desafortunadamente, MFC no hace esto. Se puede cambiar continuamente. Cambiar, pero el nombre de la clase no. El nombre de clase de la ventana está determinado por Create. Antes de Create, debe seleccionar un nombre de clase de ventana registrado para la ventana. Como parámetro, la ventana Create estará bien. La creación de CWnd eventualmente irá a CreateEx. en CreateEx. Mucho más claro.
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 Tom( lpszClassName )); ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName)); // permite la modificación de varios parámetros de creación comunes CREATESTRUCT cs; estilo = dwStyle; cs.x = x; cs.y = y; cs.cx = nIDorHMenu; 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, "Advertencia: Error al crear la ventana: GetLastError devuelve 0x%8.8 Xn", GetLastError()); }#endif if (!AfxUnhookWindowCreate()) PostNcDestroy(); // limpieza si CreateWindowEx falla demasiado pronto if (hWnd == NULL) return FALSE; ASSERT(hWnd == m_hWnd); // debería haberse configurado en el gancho de envío de mensaje return TRUE;}
Puede ver que finalmente llega a::AfxCtxCreateWindowEx. Puede saber fácilmente que aquí se llama a CreateWindowEx para crear una ventana.
Hay un PreCreateWindow (cs) al frente, y después de que PreCreateWindow procesa cs, se entrega a :: AfxCtxCreateWindowEx para su procesamiento.
::AfxCtxCreateWindowEx se transfiere a CreateWindowEx. cs.lpszClass es el nombre de la clase, lo que deja claro que AfxCtxCreateWindowEx tiene buenas intenciones.
Podemos sobrecargar PreCreateWindow para modificar el nombre de la clase, de la siguiente manera:
// TODO: agregue código especializado aquí y/o llame a la clase base //VERIFY(AfxDeferRegisterClass(AFX_WND_REG)); //AfxEndDeferRegisterClass(AFX_WND_REG); //cs.lpszClass = AfxRegisterWndClass(NULL); 0, sizeof(WNDCLASS)); // comienza con NULL // valores predeterminados wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; //puedes especificar tu propio procedimiento de ventana wndcls.lpfnWndProc = ::DefWindowProc; wndcls.hInstance = AfxGetInstanceHandle() ; wndcls.hIcon = NULL; // o cargar un icono diferente wndcls.hCursor =NULL; wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); wndcls.lpszMenuName = NULL; wndcls.lpszClassName = _T("MyNewClass"); // Registra la nueva clase y sale si falla if(!AfxRegisterClass(&wndcls)) { TRACE("Error en el registro de clasen"); wndcls.lpszClassName; return TRUE; //return CWnd::PreCreateWindow(cs);
De hecho, es para pasar una cadena de nombre de clase registrada a CreateWindowEx. A juzgar por los comentarios en el código anterior, también utilicé AfxRegisterWndClass, un método que permite al sistema generar className. CWnd::PreCreateWindow no se ajusta a mis deseos, así que lo comenté. De hecho, no contiene nada, es solo un juicio. En MFC, otras clases derivadas de CWnd no son tan simples. Sin embargo, simplemente modificar el nombre de la clase y sobrecargar este método estará bien.
Sí, la mayoría de ellos pueden Desafortunadamente, este método no funciona para Dialog porque no usa CWnd::Create, por lo que no se puede eludir.
Se acerca PreCreateWindow. Puede sobrecargar este método del cuadro de diálogo. Los puntos de interrupción no se pueden romper. Debido a que la creación de CDialog se puede realizar directamente usando la API del sistema y no hay necesidad de molestar a CWnd para transferirlo a CReateWindowEx, no puede usar el método anterior para cambiar el nombre de clase del cuadro de diálogo.
Eche un vistazo a su código de creación:
BOOL CDialog::Create(LPCTSTR lpszTemplateName, CWnd* pParentWnd){ ASSERT(IS_INTRESOURCE(lpszTemplateName) || AfxIsValidString(lpszTemplateName)); m_lpszTemplateName = lpszTemplateName // usado como ayuda if (IS_INTRESOURCE(m_lpszTemplateName) && m_nID Help == 0) m_nIDHelp = LOWORD((DWORD_PTR)m_lpszTemplateName);#ifdef _DEBUG if (!_AfxCheckDialogTemplate(lpszTemplateName, FALSE)) { ASSERT(FALSE); // nombre de plantilla de diálogo no válido PostNcDestroy() // limpieza si la creación falla demasiado pronto return FALSE; } #endif //_DEBUG HINSTANCE hInst = AfxFindResourceHandle(lpszTemplateName, RT_DIALOG); HRSRC hResource = ::FindResource(hInst, lpszTemplateName, RT_DIALOG); ) ; FreeResource(hTemplate); devolver bResultado;}
Se puede ver que CDialog es creado por recursos. Se puede hacer de esta manera. Defina la clase "nombre de clase de diálogo" en el script de recursos. Registre este nombre de clase antes de domodal o Crear en el cuadro de diálogo. Crear. Eso es todo.
Durante este período de tiempo, he estado ocupado con otros aspectos y me he olvidado mucho sobre el mecanismo de empaquetado de MFC. Rastrearé el código como repaso.