总结《二》MFC中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
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);
}
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;
}
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;
}
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。
LRESULT CALLBACK
AfxWndProc(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);
}
总结《二》MFC中WinMain和CALLBACK的更多相关文章
- 多线程编程之二 ---MFC中的多线程开发
下载源代码 五.MFC对多线程编程的支持 MFC中有两类线程,分别称之为工作者线程和用户界面线程.二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环. 工作者线程没有消 ...
- MFC中获取各个窗口之间的句柄或者指针对象的方法
MFC在非常多的对话框操作中,我们常常要用到在一个对话框中调用还有一个对话框的函数或变量.能够用例如以下方法来解决. HWND hWnd=::FindWindow(NULL,_T("S ...
- VC++ MFC中如何将应用程序的配置信息保存到注册表中(二)
在上一篇中介绍了几个写入注册表数据和读取注册表数据的接口,并介绍了使用方法. 这一片教你如何使得你的应用程序在下次打开时保持上一次关闭前的状态. 在上一篇添加的代码的基础上,要添加WM_CLOSE消息 ...
- <MFC_1>深入剖析MFC的WinMain和消息机制
一.开篇引论 熟悉Win32开发的朋友,应该非常了解它的基本组成和流程 1. WinMain:书写窗口类(WNDCLASS) -> 注册窗口类 -> 创建窗口 -> 显示窗口和更新窗 ...
- MFC中的乱起八糟----字符编码:LPTSTR,LPCTSTR, TCHAR等
注意,编写有 Unicode 意识的代码总是一件好事,比如: CString graycat = CString(_T("Gray")) + _T("Cat") ...
- MFC中存在的不属于任何类的全局函数,它们统统在函数名称开头加上Afx
MFC中存在的不属于任何类的全局函数,它们统统在函数名称开头加上Afx. 函数名称 说明 AfxWinInit 被WinMain(MFC提供)调用的一个函数,用做MFC GUI程序初始化的一部分,如果 ...
- C运行时库(C Run-time Library)详解(提供的另一个最重要的功能是为应用程序添加启动函数。Visual C++对控制台程序默认使用单线程的静态链接库,而MFC中的CFile类已暗藏了多线程)
一.什么是C运行时库 1)C运行时库就是 C run-time library,是 C 而非 C++ 语言世界的概念:取这个名字就是因为你的 C 程序运行时需要这些库中的函数. 2)C 语言是所谓的“ ...
- MFC中使用FLASH
一.准备工作 第一步:下载并安装Adobe Flash Player. 从官方网站(http://get.adobe.com/cn/flashplayer/)上下载最新的Flash Player(大约 ...
- MFC中对话框类(Dialog)的应用
转载http://hi.baidu.com/jackywdx/item/feee8041d2c2e12310ee1e85 Windows应用程序通常是通过对话框接收用户输入.向用户输出信息,本节介绍应 ...
随机推荐
- Nginx之让用户通过用户名密码认证访问web站点
有时我们会有这么一种需求,就是你的网站并不想提供一个公共的访问或者某些页面不希望公开,我们希望的是某些特定的客户端可以访问. 那么我们可以在访问时要求进行身份认证,就如给你自己的家门加一把锁,以拒绝那 ...
- no such file to load -- bundler/setup
bundle install rake routesrake aborted!no such file to load -- bundler/setup 解决 gem install bundler
- Node.js 文件系统fs模块
Node.js 文件系统封装在 fs 模块是中,它提供了文件的读取.写入.更名.删除.遍历目录.链接等POSIX 文件系统操作. 与其他模块不同的是,fs 模块中所有的操作都提供了异步的和 同步的两个 ...
- Spark2 Dataset分析函数--排名函数row_number,rank,dense_rank,percent_rank
select gender, age, row_number() over(partition by gender order by age) as rowNumber, ...
- vue之修饰符
修饰符 .lazy 在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 .你可以添加 lazy 修饰符,从而转变为使用 change 事件进行同步: <!-- ...
- 9.8Django书单列表3.0
2018-9-8 19:03:17 我暂且叫书单商城吧 更加优化了一下 这个网站有好多的样式前端的福利 https://v3.bootcss.com/ 3.0版本 放在了github :htt ...
- [ZT] matlab中plot画图参数的设置
一.Matlab绘图中用到的直线属性包括: (1)LineStyle:线形 (2)LineWidth:线宽 (3)Color:颜色 (4)MarkerType:标记点的形状 (5)MarkerSize ...
- 【巷子】---json-server---基本使用
一.前后端并行开发的痛点 前端需要等待后端开发完接口以后 再根据接口来完成前端的业务逻辑 二.解决方法 在本地模拟后端接口用来测试前端效果 这种做法称之为构建前端Mock 三.json-serve ...
- ASP.NET Web配置指南
利用ASP.NET,可以指定影响服务器上所有的Web应用程序.仅影响单个的应用程序.影响个别页面.或影响Web应用程序中的个别文件夹的配置设置.可以对编译器选项.调试.用户身份验证.错误消息显示.连接 ...
- MySQL命令:创建数据库、插入数据
简介: 学习mysql环境为ubantu,下面记录一些基本的创建数据库和插入数据的口令 打开MySQL 服务并使用 root 登录: --打开 MySQL 服务 sudo service mysql ...