MFC инкапсулирует многие часто используемые элементы управления и имена классов, не предоставляя очевидный интерфейс. Чтобы написать оконную программу с использованием Win API, первым шагом является регистрация класса окна.
На данный момент имя класса и имя заголовка регистрируются вместе, поэтому заголовок может быть легко установлен пользователем. Имя класса также должно быть очень простым. К сожалению, MFC не делает этого. Причина может заключаться в том, что имя окна. можно изменять постоянно. Изменить, но имя класса — нет. Имя класса окна определяется Create. Перед созданием вам необходимо выбрать зарегистрированное имя класса окна. В качестве параметра окно Create будет в порядке. Создание CWnd в конечном итоге перейдет в CreateEx. в CreateEx намного понятнее.
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, имя_доу, 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 || Имя) || lpszClassName )); ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName)); // разрешаем изменение нескольких общих параметров создания CREATESTRUCT cs; cs.dwExStyle = dwExStyle; cs.lpszClass = lpszClassName; сс. стиль = dwStyle; cs.y = y; cs.cy = nHeight; cs.hwndParent; cs.hMenu = nIDorHMenu; если (!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, "Предупреждение: не удалось создать окно: GetLastError возвращает 0x%8.8 Xn", GetLastError()); }#endif if (!AfxUnhookWindowCreate()) PostNcDestroy(); // очистка, если CreateWindowEx завершается сбоем слишком рано if (hWnd == NULL) return FALSE; ASSERT(hWnd == m_hWnd); // должен был быть установлен в ловушке отправки сообщения return TRUE;}
Вы можете видеть, что он наконец достигает::AfxCtxCreateWindowEx. Вы можете легко узнать, что CreateWindowEx вызывается здесь для создания окна.
Впереди находится PreCreateWindow(cs), и после обработки cs PreCreateWindow он передается ::AfxCtxCreateWindowEx для обработки.
::AfxCtxCreateWindowEx передается в CreateWindowEx. cs.lpszClass — это имя класса, которое дает понять, что AfxCtxCreateWindowEx имеет благие намерения.
Мы можем перегрузить PreCreateWindow, чтобы изменить имя класса, следующим образом:
// ЗАДАЧА: добавьте сюда специализированный код и/или вызовите базовый класс //VERIFY(AfxDeferRegisterClass(AFX_WND_REG)); //AfxEndDeferRegisterClass(AFX_WND_REG); //cs.lpszClass = AfxRegisterWndClass(NULL); WNDCLASS wndcls; 0, sizeof(WNDCLASS)); // начинаем с NULL // значения по умолчанию wndcls.style = CS_HREDRAW | CS_VREDRAW // вы можете указать свою собственную оконную процедуру wndcls.lpfnWndProc = ::DefWindowProc; hInstance = AfxGetInstanceHandle(); ; wndcls.hIcon = NULL; // или загрузим другой значок wndcls.hCursor =NULL; wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); wndcls.lpszMenuName = NULL; // Укажите собственное имя класса для дальнейшего использования FindWindow. wndcls.lpszClassName = _T("MyNewClass"); // Зарегистрируем новый класс и выйдем из строя в случае сбоя if(!AfxRegisterClass(&wndcls)) { TRACE("Ошибка регистрации классаn" } cs.lpszClass = wndcls.lpszClassName; return TRUE; // возвращаем CWnd::PreCreateWindow(cs);
Фактически, это передача зарегистрированной строки имени класса в CreateWindowEx. Судя по комментариям в приведенном выше коде, я также использовал AfxRegisterWndClass — метод, который позволяет системе генерировать имя класса. CWnd::PreCreateWindow не соответствует моим пожеланиям, поэтому я его закомментировал. На самом деле в нем нет ничего, это просто приговор. В MFC другие производные классы CWnd не так просты. Однако в большинстве случаев можно просто изменить имя класса и перегрузить этот метод.
Да, большинство из них могут. К сожалению, этот метод не работает для Dialog, поскольку он не использует CWnd::Create, поэтому его невозможно обойти.
PreCreateWindow появляется. Вы можете перегрузить этот метод диалогового окна. Точки останова невозможно сломать. Потому что создание CDialog можно выполнить напрямую с помощью API системы, и нет необходимости заморачивать CWnd для перехода в CReateWindowEx, поэтому вы не можете использовать приведенный выше метод для изменения имени класса диалогового окна.
Взгляните на код его создания:
BOOL CDialog::Create(LPCTSTR lpszTemplateName, CWnd* pParentWnd){ ASSERT(IS_INTRESOURCE(lpszTemplateName) || AfxIsValidString(lpszTemplateName)); m_lpszTemplateName = lpszTemplateName; // используется для справки if (IS_INTRESOURCE(m_lpszTemplateName) && m _nID Справка == 0) m_nIDHelp = LOWORD((DWORD_PTR)m_lpszTemplateName);#ifdef _DEBUG if (!_AfxCheckDialogTemplate(lpszTemplateName, FALSE)) { ASSERT(FALSE); // недопустимое имя шаблона диалога PostNcDestroy(); // очистка, если создание завершается неудачно, return FALSE; } #endif //_DEBUG HINSTANCE hInst = AfxFindResourceHandle(lpszTemplateName, RT_DIALOG hResource = ::FindResource(hInst, lpszTemplateName, RT_DIALOG); HGLOBAL hTemplate = LoadResource(hInst, hResource BOOL bResult = CreateIndirect(hTemplate, pParentWnd, hIn); ул. ) ; FreeResource(hTemplate); вернуть bResult;}
Видно, что CDialog создается ресурсами. Это можно сделать таким образом. Определите класс «имя класса диалога» в сценарии ресурса. Зарегистрируйте это имя класса перед domodal или Create в диалоговом окне, а затем дождитесь модального и. Создать. Вот и все.
В этот период времени я был занят другими аспектами и многое забыл о механизме упаковки MFC. Прослежу код для повышения квалификации.