总结《二》MFC中WinMain和CALLBACK
发布日期:2021-06-30 12:12:22 浏览次数:3 分类:技术文章

本文共 8252 字,大约阅读时间需要 27 分钟。

MFC中WinMain和回调函数CALLBACK
一,路线
       1.一般普通窗口或控件建立调用的CWnd :: CreateEx函数
       2.经过资源对话框创建的即不调用的CWnd :: CreateEx函数
二,在WIN32SDK下编程我们总是从入口函数WINMAIN和给予窗口类指定窗口回调函数(CALLBACK),如下:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd ){	WNDCLASSEX wc = { 0 };	wc.cbSize = sizeof(WNDCLASSEX);	wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);	wc.hCursor = LoadCursor(nullptr, IDC_ARROW);	wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION);	wc.hInstance = hInstance;	wc.lpfnWndProc = WndProc;//CALLBACK
那么MFC隐藏了这些细节,我们具体来解剖下。
三,WINMAIN
     
在MFC中由appmodul.cpp中声明
extern int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,	_In_ LPTSTR lpCmdLine, int nCmdShow);extern "C" int WINAPI_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,	_In_ LPTSTR lpCmdLine, int nCmdShow)#pragma warning(suppress: 4985){	// call shared/exported WinMain	return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);}
winmain.cpp定义
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,	_In_ LPTSTR lpCmdLine, int nCmdShow){	ASSERT(hPrevInstance == NULL);	int nReturnCode = -1;	CWinThread* pThread = AfxGetThread();	CWinApp* pApp = AfxGetApp();	// AFX internal initialization	if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))		goto InitFailure;	// App global initializations (rare)	if (pApp != NULL && !pApp->InitApplication())		goto InitFailure;	// Perform specific initializations	if (!pThread->InitInstance())	{		if (pThread->m_pMainWnd != NULL)		{			TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd\n");			pThread->m_pMainWnd->DestroyWindow();		}		nReturnCode = pThread->ExitInstance();		goto InitFailure;	}	nReturnCode = pThread->Run();InitFailure:	AfxWinTerm();	return nReturnCode;}
三,CALLBACK
分析上述1,先看源码,一切源码说话
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) || 		AfxIsValidAtom(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;	cs.hInstance = AfxGetInstanceHandle();	cs.lpCreateParams = lpParam;	if (!PreCreateWindow(cs))	{		PostNcDestroy();		return FALSE;	}	AfxHookWindowCreate(this);	HWND hWnd = CreateWindowEx(cs.dwExStyle, cs.lpszClass,			cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,			cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);	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;}
在正式创建窗口前加入一个的PreCreateWindow的虚函数,这样派生类就有机会重新定义它,当我们想改变窗口类里的属性时可以从派生类覆写此虚函数,也可以我们自己注册窗口类,自己注册后直接返回TRUE即可。
BOOL CWnd::PreCreateWindow(CREATESTRUCT& cs){	if (cs.lpszClass == NULL)	{		// make sure the default window class is registered		VERIFY(AfxDeferRegisterClass(AFX_WND_REG));		// no WNDCLASS provided - use child window default		ASSERT(cs.style & WS_CHILD);		cs.lpszClass = _afxWnd;	}	if ((cs.hMenu == NULL) && (cs.style & WS_CHILD))	{		cs.hMenu = (HMENU)(UINT_PTR)this;	}	return TRUE;}
在CreateWindowEx创建窗口之前调用了AfxHookWindowCreate函数,函数源码:
void AFXAPI AfxHookWindowCreate(CWnd* pWnd){	_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();	if (pThreadState->m_pWndInit == pWnd)		return;	if (pThreadState->m_hHookOldCbtFilter == NULL)	{		pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT,			_AfxCbtFilterHook, NULL, ::GetCurrentThreadId());		if (pThreadState->m_hHookOldCbtFilter == NULL)			AfxThrowMemoryException();	}	ASSERT(pThreadState->m_hHookOldCbtFilter != NULL);	ASSERT(pWnd != NULL);	ASSERT(pWnd->m_hWnd == NULL);   // only do once	ASSERT(pThreadState->m_pWndInit == NULL);   // hook not already in progress	pThreadState->m_pWndInit = pWnd;}
内部调用了SetWindowHookEx函数下了钩子,钩子类型为:WH_CBT,即在激活、创建、破坏、最小化、最大化、移动或调整窗口大小之前,系统会先调用我们下的钩子函数,即_AfxCbtFilterHook,该函数源码:
LRESULT CALLBACK_AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam){	_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();	if (code != HCBT_CREATEWND)	{		// wait for HCBT_CREATEWND just pass others on...		return CallNextHookEx(pThreadState->m_hHookOldCbtFilter, code,			wParam, lParam);	}	LPCREATESTRUCT lpcs = ((LPCBT_CREATEWND)lParam)->lpcs;	CWnd* pWndInit = pThreadState->m_pWndInit;	BOOL bContextIsDLL = afxContextIsDLL;	if (pWndInit != NULL || (!(lpcs->style & WS_CHILD) && !bContextIsDLL))	{		// Note: special check to avoid subclassing the IME window		if (_afxDBCS)		{			// check for cheap CS_IME style first...			if (GetClassLong((HWND)wParam, GCL_STYLE) & CS_IME)				goto lCallNextHook;			// get class name of the window that is being created			LPCTSTR pszClassName;			TCHAR szClassName[_countof("ime")+1];			if (DWORD_PTR(lpcs->lpszClass) > 0xffff)			{				pszClassName = lpcs->lpszClass;			}			else			{				szClassName[0] = '\0';#pragma warning(push)#pragma warning(disable: 4302) // 'type cast' : truncation from 'LPCSTR' to 'ATOM'				GlobalGetAtomName((ATOM)lpcs->lpszClass, szClassName, _countof(szClassName));#pragma warning(pop)				pszClassName = szClassName;			}			// a little more expensive to test this way, but necessary...			if (::AfxInvariantStrICmp(pszClassName, _T("ime")) == 0)				goto lCallNextHook;		}		ASSERT(wParam != NULL); // should be non-NULL HWND		HWND hWnd = (HWND)wParam;		WNDPROC oldWndProc;		if (pWndInit != NULL)		{			AFX_MANAGE_STATE(pWndInit->m_pModuleState);			// connect the HWND to pWndInit...			pWndInit->Attach(hWnd);			// allow other subclassing to occur first			pWndInit->PreSubclassWindow();			WNDPROC *pOldWndProc = pWndInit->GetSuperWndProcAddr();			ASSERT(pOldWndProc != NULL);			// subclass the window with standard AfxWndProc			WNDPROC afxWndProc = AfxGetAfxWndProc();			oldWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC,				(DWORD_PTR)afxWndProc);			ASSERT(oldWndProc != NULL);			if (oldWndProc != afxWndProc)				*pOldWndProc = oldWndProc;			pThreadState->m_pWndInit = NULL;		}		else		{			static ATOM s_atomMenu = 0;			bool bSubclass = true;						if (s_atomMenu == 0)			{				WNDCLASSEX wc;				memset(&wc, 0, sizeof(WNDCLASSEX));				wc.cbSize = sizeof(WNDCLASSEX);				s_atomMenu = (ATOM)GetClassInfoEx(NULL, _T("#32768"), &wc);			}			// Do not subclass menus.			if (s_atomMenu != 0)			{				ATOM atomWnd = (ATOM)::GetClassLongPtr(hWnd, GCW_ATOM);				if (atomWnd == s_atomMenu)						bSubclass = false;			}			else			{							TCHAR szClassName[256];				if (::GetClassName(hWnd, szClassName, 256))				{					szClassName[255] = NULL;					if (_tcscmp(szClassName, _T("#32768")) == 0)						bSubclass = false;				}			}						if (bSubclass)			{				// subclass the window with the proc which does gray backgrounds				oldWndProc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC);				if (oldWndProc != NULL && GetProp(hWnd, _afxOldWndProc) == NULL)				{					SetProp(hWnd, _afxOldWndProc, oldWndProc);					if ((WNDPROC)GetProp(hWnd, _afxOldWndProc) == oldWndProc)					{						GlobalAddAtom(_afxOldWndProc);						SetWindowLongPtr(hWnd, GWLP_WNDPROC, (DWORD_PTR)_AfxActivationWndProc);						ASSERT(oldWndProc != NULL);					}				}			}		}	}lCallNextHook:	LRESULT lResult = CallNextHookEx(pThreadState->m_hHookOldCbtFilter, code,		wParam, lParam);	return lResult;}
该函数把code不是HCBT_CREATEWND过滤,保留了HCBT_CREATEWND。
该code为一个窗口即将被创建时在向窗口发送WM_CREATE或者WM_NCCREATE消息,所以在这个时候进行了子类化操作,就是把所有的窗口回调函数设为AfxWndProc
LRESULT CALLBACKAfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam){	// special message which identifies the window as using AfxWndProc	if (nMsg == WM_QUERYAFXWNDPROC)		return 1;	// all other messages route through message map	CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);	ASSERT(pWnd != NULL);						ASSERT(pWnd==NULL || pWnd->m_hWnd == hWnd);	if (pWnd == NULL || pWnd->m_hWnd != hWnd)		return ::DefWindowProc(hWnd, nMsg, wParam, lParam);	return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);}

转载地址:https://jadeshu.blog.csdn.net/article/details/71512547 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:内核对象
下一篇:复习总结《一》MFC消息映射

发表评论

最新留言

不错!
[***.144.177.141]2024年04月22日 15时57分20秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章