
1. MFC的过去从图形界面荒漠到Windows开发者的共同记忆聊MFC之前得先承认一件事如果你今天才入行大概率不理解为什么还有人在为一个1992年诞生的类库写长篇大论。但只要你在Windows平台上写过几年CMFC这个名字就像老家的旧房子——你早就搬走了可每次路过还是会多看两眼。MFC全称Microsoft Foundation Classes也就是微软基础类库。它的诞生背景特别直白90年代初Windows 3.x开始普及但那时候写Windows程序用的是纯C API一个简单的窗口要写上百行代码消息处理全靠switch-case硬怼。我记得刚入行那会儿翻老代码一个WndProc函数里几十个case分支看一会儿头就大了。MFC做的事情本质上就是把Win32 API里那些“重复又繁琐”的部分包了一层C外衣窗口类、消息映射、控件封装、文档视图架构全部变成可在类层次中继承和重写的东西。那个年代的C开发者生态MFC几乎是唯一的主流选择。Borland C Builder还没成气候Qt还在挪威的小公司里憋大招MFC借着Visual C的东风稳稳霸占了Windows桌面开发的C位。学MFC就等于学Windows开发这几乎是当时的共识。大家研究CWnd的继承关系、琢磨消息映射宏的展开结果、折腾DDX/DDV数据交换那是一整代C程序员的集体记忆。现在回头看MFC的设计思路里有几个点很值得说。首先是消息映射机制。MFC没有用C的虚函数来分发消息而是搞了一套宏驱动的映射表BEGIN_MESSAGE_MAP、ON_WM_PAINT、END_MESSAGE_MAP。这背后其实是C编译器限制下的聪明妥协——如果每个消息都是一个虚函数那CWnd的虚函数表会膨胀到不可收拾而且新消息类型无法方便地扩展。宏展开后生成的消息映射表和基类链路查询本质上是用空间和代码生成换灵活性和兼容性。其次是文档视图架构。MFC的Document/View把数据和界面分离Doc管数据View管显示Frame管窗口框架。这在当时是相当先进的设计理念哪怕放到今天数据层和界面层解耦的思路也不过时。MFC应用向导能一键生成单文档、多文档程序程序员只需要往Doc里塞数据、往View里画输出一个像模像样的编辑器就出来了。这也是为什么MFC当年在教育领域特别受欢迎——学完MFC你对Windows GUI程序的组织方式就有了整体认知。还有一点是MFC和Visual C工具链的一体化。ClassWizard、资源编辑器、调试器深度集成在那个IDE还是稀缺物种的时代这套开发体验的完成度非常高。你拖一个按钮到对话框上双击就跳转到点击事件处理器这种感觉在当年是非常震撼的。VC 6.0配MFC是多少中国程序员第一次写出“带窗口的软件”的工具包。当然MFC的黄金时代也伴随着不少骂声。它的类层次设计复杂CView、CScrollView、CFormView、CEditView一堆视图类新手上手有坡度它的宏和消息映射虽然有巧思但也让代码变得很难静态分析IDE跳转总是各种阵发性失灵它的内存管理沿用了很多C时代的习惯new和delete散落各处稍不注意就泄漏。更别提后来微软自己搞出个.NET和WinForms等于亲手给MFC的棺材板钉了一颗钉子。但那些年MFC确实养活了大量的Windows桌面软件也养活了一大批C程序员。工厂里的上位机、银行柜台的业务终端、通信设备的网管系统、医院里的影像工作站到处都有MFC程序的影子。现在你去工控论坛看还有人在维护二十年前用MFC 6.0写的设备控制程序那个软件里沉淀的是整个产线的工艺逻辑。所以谈MFC的过去不能简单说它是“过时的老东西”。它是一个时代Windows桌面开发的代表是C封装Win32的经典范例也是一代开发者思维方式的底色。技术会老但它塑造的那些设计思想比如消息驱动、界面与数据分离、资源与代码分离今天依然活在无数软件里。2. MFC的现在存量庞大、需求真实、争议常在MFC现在到底什么状态说实话我逢人就讲MFC还活着而且活得比很多人想象中安稳。微软官方并没有宣布MFC停止维护。Visual Studio 2022里依然包含MFC库仍然提供MFC应用向导仍然会修复安全问题。只是微软的注意力早就转移到WinUI、MAUI这些新框架上MFC的新功能更新基本停滞——它进入了“维护模式”类似一栋老房子有人定期检查电路和水管但不会再重新装修了。但“没新功能”不等于“没人用”。MFC的存量代码量非常庞大保守估计全球范围内Windows商业软件里仍有数十万级别、甚至更多的MFC程序在跑。很多制造业工厂的产线控制系统、实验室仪器的数据采集软件、电力行业的监控后台、医疗设备的上位机界面长得还是二十年前的样子但每天都在真实运作。为什么企业不迁移答案很现实成本和风险。一套产线控制软件写业务逻辑的人早就退休了原来的开发文档也残缺不全你现在找一队人用Qt重写光是复现旧系统的边界行为就要几个月的回归测试。停产一天损失多少钱没人愿意背这个锅。于是MFC程序就这么一代一代传下来成了某种意义上的“传家宝”。MFC现在的主要使用人群我觉得可以粗略分成三类。第一类是存量系统的维护者。他们可能在国企信息中心、设备厂商、研究所日常工作是给十几年前的MFC程序加功能、修Bug、适配新Windows版本。这台软件的技能栈基本固定在VS2010、VS2008甚至VC6最头疼的是高分屏适配和Unicode迁移。第二类是工业软件和硬件配套软件的开发者。工控机、嵌入式设备的上位机图的就是MFC启动快、依赖少、和Win32底层很贴近——直接操作串口、网口、USBMFC和C搭起来非常顺手。对硬件交互的细腻控制这类需求MFC依然能打。第三类是C的学院派和底层玩家。他们不追求界面多花哨但喜欢MFC把Win32 API封装的清晰脉络学MFC等于同时理解Windows消息机制。这类人数量不算多但一直没断代过。热搜词里那些问题恰好能说明现在MFC开发者的真实处境。比如有人搜“此项目需要MFC库”这说明还有人第一次打开一个老工程被依赖项卡住有人搜“让控制台程序支持MFC”说明还有人要在脚本工具里用上MFC的封装类有人搜“MFC GridCtrl单元格能否配置颜色选择控件”说明还有人在维护老旧的表格控件并做定制化改造。需求很具体、很零碎但从来不是零。还有个很典型的信号“VS2010 MFC List控件第一行设置LVCFMT_LEFT无效果”。这类问题只能发生在老版本开发工具的真实项目里搜索引擎一搜全是论坛帖子回复的人还是那批老工程师。你会发现一个很有意思的现象MFC的技术讨论社区至今活跃虽然发帖频率比不上当年但提问回答的质量依然很扎实因为问的都是在生产环境里被逼出来的实际问题。我心里对MFC“现在”的判断是它是一个典型的存量技术新项目里很少有人主动选它但存量项目里它无处不在。它不是朝阳也不是夕阳而是入夜后依然亮着的路灯。3. 现代MFC开发者的日常热搜词背后的真实项目细节既然现在还有这么多人在用MFC那大家每天到底在解决什么问题这一节我结合热搜词把几个最具代表性的场景展开讲讲。3.1 “此项目需要MFC库”到底是什么意思当你打开一个visual studio解决方案编译报错提示“此项目需要MFC库”先别慌这不是代码问题是环境问题。MFC类库不是C标准库一部分它由Visual Studio安装程序作为可选组件提供。在VS安装器里勾选“使用C的桌面开发”工作负载时默认不会装MFC组件你需要额外在“单个组件”里找到“适用于最新v143生成工具的C MFCx86和x64”并勾选安装。有个小坑MFC还区分动态链接版和静态链接版。老项目为了部署简单经常用静态链接最后生成的exe很大但不需要带一堆DLL新项目则倾向于动态链接程序依赖安装目录里的mfc140u.dll。如果你拿到的工程配置是“在静态库中使用MFC”但开发机上只装了动态库运行库一样会编译不过。实际运维中我建议给这类计算机准备一个清单VS版本、MFC组件是否安装、Windows SDK版本、目标平台是x86还是x64。MFC老代码很多是x86编译的在64位系统上跑是因为WOW64兼容层但如果拿x64工具链去编老的MFC工程偶尔会遇到第三方库没有64位版本的问题那会儿就只能保持x86。3.2 让控制台程序支持MFC有人觉得这样很奇怪但真实场景里很常见你想在命令行工具里用CString、CFile、CMap这些MFC封装类而不是自己造轮子。做法有两个路线。一个是在控制台工程里把项目属性调整为“使用MFC”。在VS中新建的是Win32控制台应用然后在项目属性-常规-使用MFC里选择“在共享DLL中使用MFC”代码里包含afxwin.h或afx.h然后把main改成类似下面这种。#include afxwin.h #include afx.h int main() { CString strMsg _T(Hello MFC in Console); _tprintf(_T(%s\n), (LPCTSTR)strMsg); return 0; }另一个是反过来MFC程序里开控制台窗口。用AllocConsole和freopen把stdout重定向到控制台方便调试时打印日志。这两种做法我都用过前者适合工具类程序后者适合界面程序调试期看输出。需要注意MFC初始化需要一个CWinApp对象来管理实例状态。控制台程序里即使不创建窗口最好也构造一个CWinApp的子类对象来保证MFC内部机制正常不然某些类首次使用时可能拿到未初始化的模块状态。3.3 MFC里画一个彩色正方形热搜里有“基于MFC绘制一个彩色正方形”这算是MFC绘图入门必练项目。核心是把绘图代码放在视图类的OnDraw函数里用GDI对象绘制图形。例如在CView子类里void CMyView::OnDraw(CDC* pDC) { CBrush brush(RGB(255, 0, 0)); CBrush* pOldBrush pDC-SelectObject(brush); pDC-Rectangle(100, 100, 300, 300); pDC-SelectObject(pOldBrush); }如果想让正方形变成渐变色可以用GDI的CreateSolidBrush配合多次叠色绘制条纹实现渐变效果也可以用GDIMFC项目和GDI配合得也很好几行代码就能画出更丰富的图形。C GDI 绘制渐变的正方形 这里涉及的一个核心概念叫“设备上下文”DCMFC里就是CDC类。所有Windows上的绘制最终都要通过DC来操作MFC帮我们把GetDC、DeleteDC这类API调用封装好了但原理没变。初学者搞懂DC和GDI对象的选择与恢复MFC的绘图基本就通了一大半。 我记得有个容易踩的坑在非OnDraw的地方绘图需要用CClientDC主动获取客户区DC绘制完成后DC析构会自动释放资源但如果你自己用GetDC取的DC一定要记得ReleaseDC否则就是经典的GDI对象泄漏——现象就是程序跑几天后界面变花最后画不出东西。 ### 3.4 MFC里显示二维码zxing-cpp的集成方案 看到“MFC zxing-cpp”和“VC MFC工程读取图片中的二维码”这个需求非常典型。MFC工程里要识别二维码最靠谱的方案就是集成zxing-cpp这个C库。 zxing-cpp是ZXing的C移植版支持从图片文件中解析二维码和条形码。在MFC里集成的步骤比较典型 第一下载zxing-cpp源码用CMake编译成静态库或动态库。编译时注意运行时库配置要和MFC工程保持一致MFC通常使用多线程Debug DLL或Release DLL运行时。 第二把头文件和lib文件配置到项目中在stdafx.h里包含相关头文件。 第三加载图片并调用解码接口。MFC中CImage可以很方便地读取BMP、JPG、PNG等图片然后把像素数据传给zxing-cpp的ImageView。 cpp CImage img; if (FAILED(img.Load(strFilePath))) return -1; BITMAP bmpInfo; CBitmap* pBitmap CBitmap::FromHandle(img); pBitmap-GetBitmap(bmpInfo); std::vectoruint8_t pixels; int width bmpInfo.bmWidth; int height bmpInfo.bmHeight; // 转为灰度或保留灰度像素传给 zxing::ImageView auto view zxing::ImageView(pixels.data(), width, height, zxing::ImageFormat::Lum); auto result zxing::ReadBarcode(view); if (result.format() ! zxing::BarcodeFormat::None) { CString strText result.text().c_str(); }这个方案我落地过效果很稳。需要注意zxing-cpp对图片清晰度和对比度比较敏感工业现场拍摄的图片经常有反光、倾斜、畸变建议在送入识别前做预处理转灰度、增强对比度、高斯去噪、甚至透视校正。这些预处理用MFC自带的GDI操作很麻烦我的做法是配合OpenCV做图像预处理识别再交给zxing-cpp两者互补很舒服。3.5 MFC里的线程AfxBeginThread与CWinThread搜“MFC winthread”的朋友应该是刚接触MFC多线程。MFC封装了一个CWinThread类而创建线程最方便的是AfxBeginThread全局函数。UINT MyThreadProc(LPVOID pParam) { // 线程逻辑 ::PostMessage(hwndMain, WM_USER_THREAD_DONE, 0, 0); return 0; } // 创建线程 CWinThread* pThread AfxBeginThread(MyThreadProc, this);MFC线程有个重要特点线程里有局部MFC对象使用一般是安全的但不能跨线程传递MFC对象指针。比如不能在一个线程里操作另一个线程创建的CWnd子类对象因为MFC对象的句柄映射是线程局部存储的。正确做法是在线程里PostMessage给目标窗口让窗口在自己的消息循环里处理UI更新。另一个与其相关的函数是_beginthreadex它和CreateThread相比会正确初始化C运行时库的堆和errno等状态。在MFC程序里我建议优先用AfxBeginThread如果要纯Win32风格就_beginthreadex而不是直接用CreateThread。线程间同步在MFC里可以选用CCriticalSection、CEvent、CMutex等封装好的同步类和Win32的临界区、事件、互斥量一一对应。用这些类的好处是析构函数自动释放句柄比手动CloseHandle少很多麻烦。3.6 MFC表格控件GridCtrl和单元格定制“MFC GridCtrl单元格能否配置颜色选择控件并显示选定配色线条状图形”这个问题是老MFCer的日常了。MFC自带的CListCtrl能做的事有限所以社区里流行的MFC GridCtrl比如CGridCtrl被广泛使用。CGridCtrl允许你给每个单元格设置背景色、字体、文本内容还能通过设置单元格类型来嵌入下拉框、按钮等。如果我们想实现“在单元格里点一下弹出一个颜色选择对话框选择后把颜色以线条状图形显示在单元格里”做法分两步。第一步是派生一个网格控件重写OnClick或编辑框控制逻辑在用户点击单元格时打开CColorDialog。void CMyGridCtrl::OnClickCell(int nRow, int nCol) { if (nCol COLOR_COLUMN) { CColorDialog dlg(m_clrCurrent, CC_FULLOPEN, this); if (dlg.DoModal() IDOK) { m_clrCurrent dlg.GetColor(); SetItemColor(nRow, nCol, m_clrCurrent); // 触发重绘绘制线条图形 RedrawCell(nRow, nCol); } } CGridCtrl::OnClickCell(nRow, nCol); }第二步是重写单元格绘制函数OnDrawCell在单元格里用选中的颜色画一条粗线或图形。BOOL CMyGridCtrl::OnDrawCell(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBkgnd) { if (nCol COLOR_COLUMN m_mapColor.count(nRow)) { CBrush br(m_mapColor[nRow]); pDC-FillRect(rect, br); CPen pen(PS_SOLID, 4, m_mapColor[nRow]); pDC-SelectObject(pen); pDC-MoveTo(rect.left 5, rect.CenterPoint().y); pDC-LineTo(rect.right - 5, rect.CenterPoint().y); return TRUE; } return CGridCtrl::OnDrawCell(pDC, nRow, nCol, rect, bEraseBkgnd); }这个过程的关键在于理解“绘制是由视图或控件自己负责而不是容器程序主动画上去再交还”的模型。MFC控件刷新时会回调OnDrawCell你只需要在这个回调里根据数据状态自定义绘制。这在MFC里算高阶玩法但一旦掌握表格的可视化能力会提升一个档次。3.7 MFC调试常见问List控件第一行LVCFMT_LEFT没效果这个热搜词像极了那些“明明照着文档做了就是不生效”的夜晚。VS2010里用CListCtrl插入列设置了LVCFMT_LEFT却发现第一行数据不对齐。问题根源在于你对LVCOLUMN结构体的使用漏了字段。LVCOLUMN的mask必须包含LVCF_FMTfmt字段才生效。如果只写了LVCF_TEXT或LVCF_WIDTHfmt值会被忽略。很多人写代码时只给mask赋值了LVCF_TEXT | LVCF_WIDTH后缀的LVCFMT_LEFT自然毫无反应。LVCOLUMN lvCol {0}; lvCol.mask LVCF_TEXT | LVCF_WIDTH | LVCF_FMT; lvCol.fmt LVCFMT_LEFT; lvCol.cx 120; lvCol.pszText _T(列名); m_ListCtrl.InsertColumn(0, lvCol);另一个常见坑是“第一行”看起来没有左对齐是因为整列都居中了但后续行左对齐第一行由于被选中状态高亮涂抹看不出差异。这种时候去检查LVITEM对每行插入时有没有显式设置LVIF_TEXT和pszText就行行数据和列头数据是两回事。3.8 MFC流量计拆解“MFC流量计拆解”这个词有点跨界。流量计是工业仪表但它名字里的MFC是Mass Flow Controller质量流量控制器不是微软类库。不过这件事反而提醒我MFC这个词在工程领域有歧义搜MFC的人不一定在搜MFC开发。但如果我们把“MFC流量计拆解”理解为“拆解一个用MFC写的流量计上位机”那可就太常见了。工业仪器厂商很喜欢用MFC写上位机采集流量数据、曲线显示、参数配置、串口通信、历史数据存储这套组合拳MFC都能接得住。这类软件我拆过典型结构是一个基于对话框或单文档的界面后台开一个串口线程持续读取设备数据数据用定时器或消息触发展示到自定义绘图控件上参数配置界面和通信协议强耦合。代码里的难点一般不是界面而是协议解析和丢包处理。MFC只是壳真正的价值在业务逻辑里这也是很多MFC老程序“不能动”的根本原因——业务逻辑太复杂重写的风险太高。3.9 还能用什么工具编译MFCvscode与老工程的现代工作流“如何使用vscode编译MFC”这个问题我一开始觉得有点反直觉——MFC是Visual Studio的亲儿子干嘛非要用VSCode编译后来想明白了很多人是习惯了VSCode的编辑体验只是希望MFC项目不要被绑定在笨重的VS里。那这个需求是能走通的但路子比较野。核心思路是MFC代码最终是用cl.exe编译的VSCode只是编辑器。你要做的是在VSCode里配置好cl.exe的编译命令、include路径、库路径然后用Tasks或CMake工具去驱动MSBuild编译。但是这里有个现实问题MFC工程没有CMakeLists.txt或Makefile它是.vcxproj工程文件。最省事的做法是保留MSBuild作为编译后端在VSCode里添加一个任务来调用MSBuild。{ version: 2.0.0, tasks: [ { label: build-mfc, type: shell, command: devenv.com, args: [MyProject.sln, /Build, Release|x86], group: {kind: build, isDefault: true}, problemMatcher: [$msCompile] } ] }用devenv.com调用起来也和MSBuild等价但注意devenv.com是Visual Studio自带的命令行入口一定要把VS安装目录加入PATH不然任务找不到命令。VSCode里面写代码、看文件、做git管理编译交给VS命令行查询错误靠problemMatcher突出一个取长补短。界面调试还是得回到VSMFC的调试信息在VSCode里配置起来太麻烦划不来。4. MFC的技术价值评估它是不是过时了聊完MFC现在每天面临的鸡毛蒜皮我们退一步看一个更大的问题MFC到底过时没有对于这个问题我的回答是作为“新技术”它早就过时了但作为“技术资产”它远没过时而且它的设计思想并没有被彻底淘汰。先说它不如谁。MFC的UI能力在今天看起来确实“素”没有CSS那种丰富的样式机制没有Qt的QSS更没有WinUI的流畅设计语言。MFC默认控件就那副老样子想做圆角、动画、亚克力效果得大量自绘成本高得离谱。相比之下WPF的矢量渲染、数据绑定、模板化开发效率简直天壤之别。如果让我从零开始做一个现代界面的Windows应用我大概率选WinUI或Qt不会开一个MFC工程。但MFC强在“离系统近”。它封装的是Win32本身没有引入一套全新的渲染引擎。这意味着MFC程序的启动速度快、内存占用相对可控、对老硬件兼容性好也意味着你可以随时在MFC代码里直接调用Win32 API而不用跳出一层抽象去够底层能力。对工业、医疗、军工这类不追求美观但要求可靠、稳定的领域MFC的“土”恰恰是它的“稳”。我还想为MFC辩护一下它的学习价值。MFC的类设计虽然老派但它非常“窗口消息驱动”你在MFC里搞懂了WM_PAINT、WM_SIZE、WM_COMMAND这些消息的流动以后看Win32程序、Qt的事件机制、甚至前端的DOM事件思维方式是相通的。而且MFC的文档视图架构、视图/文档分离思想在当年是相当先进的软件工程实践。今天你学Qt的Model/View隐隐约约都有一点MFC的旧影。再说一个常被忽略的点MFC和C标准的兼容性其实比很多人想象中好。现代MFC代码里你可以用C11/14/17特性unique_ptr管理GDI对象、auto替代冗长迭代器、lambda配合std::sort处理容器数据MFC完全扛得住。它不是那个只能写老式C的框架只是很多老代码停留在老式写法而已。总结过时与否这件事我的观点很明确如果你问“MFC能不能优雅地开发现代桌面应用”答案是不能但如果你问“MFC值不值得继续维护和投入”答案是非常值得——只要你的业务跑在存量系统上MFC就是你最可靠的基座。5. MFC的未来不会死但也不会重回舞台中央MFC的未来我预判过很多次也在博客、论坛里跟人争论过。我的结论一直是那两句不会死也不会重回舞台中央。微软对MFC的态度很微妙。一方面Windows 10/11上MFC程序仍然能正常跑Visual Studio每次发布新版本都还兼容MFC组件另一方面微软在大力推WinUI 3和MAUI连WPF都进入了维护模式MFC的新功能开发基本冻结。微软没有“处死”MFC因为它知道有庞大的存量业务不能断但它也不会再在MFC上投入多少新资源。这种“不死不火”的状态恰恰是MFC未来五到十年的主旋律。它的生存逻辑不是靠吸引新人而是靠存量项目的时间惯性。一批老工程师用MFC维护着产线系统他们离退休还有十几年这几年内没有人会提议重写系统等到他们真正退休接手的新人大概率会拿新技术栈重构。MFC的消亡路径不会是“轰然倒塌”而是在一代人的职业生涯里慢慢淡出。从生态角度看MFC的社区生命力依然来自“问题驱动”。只要有MFC存量代码在跑就会有新的VS版本兼容问题、新的Windows版本适配问题、新的二维码识别需求、新的控制硬件需求浮出来。这些需求会持续产生讨论和解决方案形成一种小但稳定的内容循环。我甚至观察到近几年由于AI辅助编程工具的兴起用Copilot或ChatGPT改MFC代码的效率大幅提升——很多以前要翻MSDN半天的消息映射问题现在AI能直接给出示例这门老技术反而有了新工具的红利。那MFC用户未来该怎么办我觉得有三条路可以走。第一条路是维护型深耕。守着存量系统把MFC技术练到炉火纯青做一个不可替代的“老系统守护者”。这条路适合那些已经在行业里扎根多年、熟悉业务逻辑的工程师。MFC只是表面真正的护城河是那些写在你脑子里关于产线、工艺、通信协议的知识。第二条路是渐进迁移。在维持MFC主程序正常运转的同时把新模块用其他技术栈实现。比如用Qt写一个新的配置界面通过进程间通信或API调用来集成到老系统里或者用C/CLI桥接MFC和WPF逐步替换界面层。这类迁移的节奏要非常克制务必保证业务不中断。第三条路是重写重构。如果系统体量可控、业务逻辑理顺了就从零开始用现代框架重写。这种情况在我接触的项目里相对少见但一旦启动MFC的历史使命就结束了。QML技术栈、C#的WPF、甚至Python配PySide都是可选项。就我个人的建议如果你是刚入行看到MFC工作岗位的年轻人学习MFC可以有但不要把它当唯一技能。把C基础、Windows消息机制、面向对象设计这些底子打扎实MFC只是一个可以随时切入的具体框架。这样今天可以靠MFC吃饭明天也可以平滑转向别的技术栈。6. 我的看法写了这么多最后说几句心里话。MFC在我职业生涯里占的位置很特殊。我刚工作那年做的就是MFC的活帮一家设备厂商改上位机软件界面丑得不行但客户用了很多年从没出过大问题。后来我做过C#、做过Web、也研究过Qt但对Windows桌面程序的理解根基还是当年啃MFC的时候打下的。我常跟人说技术就像工具没有绝对的好坏只有合不合手。MFC这把锤子是老了锤头有点钝但握把是你用了十年的形状打钉子还是很准。真正重要的不是你手里拿的是什么锤子而是你知道在什么场合用多大的力敲在哪个位置。如果你现在正在维护一个MFC项目别焦虑别被“技术过时”的言论吓到。这个软件承载着实际的业务价值而你有能力维护它这就是你的本事。如果你有机会选择新项目也请理性评估用更现代的框架当然好但一定要想清楚迁移成本、运行环境和团队能力。MFC的过去是一代人的青春和积累MFC的现在是一堆业务的真实依赖MFC的未来——我赌它还能再陪我们很多年。就像Windows命令提示符谁都说它该进博物馆了但每天照样有那么多人开着黑窗口起着服务、跑着脚本。有些东西活着就是因为它还在解决实实在在的问题。