MFC는 일반적으로 사용되는 많은 컨트롤을 캡슐화하고 명확한 인터페이스를 제공하지 않고 클래스 이름을 캡슐화합니다. win api를 사용하여 창 프로그램을 작성하려면 첫 번째 단계는 창 클래스를 등록하는 것입니다.
이때 클래스 이름과 타이틀 이름이 함께 등록되므로 사용자가 쉽게 타이틀을 설정할 수 있습니다. 클래스 이름도 매우 간단해야 하는데 아쉽게도 MFC에서는 이를 수행하지 않습니다. 계속 변경할 수 있지만 클래스 이름은 변경할 수 없습니다. 창의 클래스 이름은 Create에 의해 결정됩니다. Create 전에 창에 등록된 창 클래스 이름을 선택해야 합니다. 매개변수로 CWnd의 Create는 결국 CreateEx로 이동합니다. CreateEx에서 훨씬 더 명확합니다.
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& ret, CWnd* pParentWnd, UINT nID, LPVOID lpParam /* = NULL */){ return CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle , ret.left, ret.top, ret.right - ret.left, ret.bottom - ret.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 IsVal idAtom( lpszClassName )); ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName)); // 여러 공통 생성 매개변수 수정 허용 CREATESTRUCT cs; cs.lpszClass = lpszClassName; 스타일 = dwStyle; cs.y = y; cs.hwndParent = hWndParent; if (!PreCreateWindow(cs) ) { PostNcDestroy(); return FALSE; 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); // send msg 후크에 설정되어 있어야 합니다. return TRUE;}
드디어::AfxCtxCreateWindowEx에 도달한 것을 볼 수 있습니다. 여기에서 CreateWindowEx를 호출하여 윈도우를 생성하는 것을 쉽게 알 수 있습니다.
앞에 PreCreateWindow(cs)가 있고 PreCreateWindow에 의해 cs가 처리된 후 ::AfxCtxCreateWindowEx로 넘겨져 처리됩니다.
::AfxCtxCreateWindowEx는 CreateWindowEx로 전송됩니다. cs.lpszClass는 클래스 이름이므로 AfxCtxCreateWindowEx에 좋은 의도가 있음이 분명해집니다.
PreCreateWindow를 오버로드하여 다음과 같이 클래스 이름을 수정할 수 있습니다.
// TODO: 여기에 특수 코드를 추가하거나 기본 클래스를 호출합니다. //VERIFY(AfxDeferRegisterClass(AFX_WND_REG)) //cs.lpszClass = AfxRegisterWndClass(NULL); 0, sizeof(WNDCLASS)); // NULL로 시작 // 기본값 wndcls.style = CS_HREDRAW | CS_VREDRAW; //자신만의 창 프로시저를 지정할 수 있습니다 wndcls.lpfnWndProc = ::DefWindowProc = AfxGetInstanceHandle; ; wndcls.hIcon = NULL; // 또는 다른 아이콘 로드 wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1) // 나중에 FindWindow를 사용하기 위해 자신만의 클래스 이름을 지정합니다. wndcls.lpszClassName = _T("MyNewClass"); // 새 클래스를 등록하고 실패하면 종료합니다. if(!AfxRegisterClass(&wndcls)) { TRACE("클래스 등록 실패n") } cs.lpszClass = wndcls.lpszClassName; return TRUE; //return CWnd::PreCreateWindow(cs);
실제로는 등록된 클래스 이름 문자열을 CreateWindowEx에 전달하는 것입니다. 위 코드의 주석을 보면 시스템에서 className을 생성할 수 있는 메서드인 AfxRegisterWndClass도 사용했습니다. CWnd::PreCreateWindow는 내 바람에 맞지 않아서 주석 처리했습니다. 실제로는 아무것도 없고 단지 판단일 뿐입니다. MFC에서 CWnd의 다른 파생 클래스는 그렇게 간단하지 않습니다. 그러나 단순히 클래스 이름을 수정하고 이 메서드를 오버로드하는 것은 대부분 괜찮습니다.
예, 대부분 가능합니다. 불행하게도 이 방법은 CWnd::Create를 사용하지 않으므로 우회할 수 없기 때문에 Dialog에서는 작동하지 않습니다.
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 Help == 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); HRSRC hResource = ::FindResource(hInst, lpszTemplateName, RT_DIALOG) HGLOBAL hTemplate = LoadResource(hInst, hResource); ) ; FreeResource(hTemplate); 반환 bResult;}
이렇게 하면 CDialog가 리소스에 의해 생성되는 것을 볼 수 있습니다. 리소스 스크립트에서 클래스 "dialog class name"을 정의하고 대화 상자에서 domodal 또는 Create 전에 이 클래스 이름을 등록한 후 모달을 기다립니다. 창조하세요.
이 기간 동안 나는 다른 측면으로 바빠서 MFC 패키징 메커니즘에 대해 많이 잊어버렸습니다.