拓冰建站拓冰建站
首页 / 资讯中心 / 正文

VS2019+MFC开发销售管理系统:环境搭建、常见坑与打包部署完整实践

简介基于VS2019与MFC的销售管理系统完整工程源码包面向需要学习Windows桌面应用开发、MFC框架及C项目实践的开发者。系统围绕商品进货、出货、库存、报表统计、用户权限和数据导入导出等核心业务模块展开适合作为课程设计、毕业设计或企业级C桌面应用入门案例。压缩包共111个文件包含15个h头文件、12个cpp源文件、.rc界面资源、.sln/.vcxproj工程配置、.exe可执行程序以及调试生成的obj、pdb、tlog等中间文件整体约96.43MB目录结构可完整还原VS2019开发环境便于直接打开和编译运行。当前已有1327人学习下载。从内容预览可知工程包含销售管理系统.cpp、销售管理系统Doc.cpp、销售管理系统View.cpp、CAddDlg.cpp、CSellDlg.cpp、CUserDlg.cpp、CSelectView.cpp、InfoFile.cpp等关键源码清晰展示了MFC文档/视图架构、对话框交互、数据库记录集查询和界面布局实现配合MainFrm.cpp、.rc资源文件、.ico图标及sln/vcxproj配置可以对照学习从界面设计到业务逻辑落地的完整过程并在此基础上继续扩展商品分类、客户关系、促销管理等新功能。 接手这个项目之前我其实犹豫过一阵子。2024年还用VS2019配MFC去做销售管理系统听起来像在考古。但真正落到企业现场会发现这类需求比想象中多得多——老旧的Windows收银机、门店管理端、进销存后台很多都跑在十年前甚至二十年前的技术栈上而MFC在VS2019里依然被完整支持维护老系统、做内部工具、写轻量级桌面客户端它反而比动不动上百MB的.NET应用或者Electron套壳方案更顺手。这篇文章就是我基于自己的实际项目经验把从环境搭建、数据库设计到界面实现、打包发布的完整链路走一遍重点放在那些搜索页里出现频率极高的坑上中文注释报错、控件自适应屏幕、静态文本重叠、安装包制作……每个都会给出根因分析和可复制的解决方案。1. 为什么销售管理系统还在用MFC选型逻辑先想清楚先说个大实话如果是从零开始做全新项目我不太会主动选MFC毕竟现代UI框架在界面美观度和开发效率上确实有代差。但销售管理系统这类业务软件有个共同特点——它不靠花哨界面吃饭核心诉求是窗口要稳定、数据别丢、操作够快而MFC恰好擅长这个。尤其当你面对的是以下场景客户的运行环境是Windows 7甚至更早的系统.NET Framework版本混乱安装运行时可能被各种策略拦下来软件要走远程桌面或瘦客户机部署客户端体积要小一个exe加几个配置文件就能跑团队里沉淀了大量C业务代码迁移到新框架的成本远高于在MFC里继续迭代。VS2019对MFC的支持力度其实超出很多人预期官方文档仍将MFC列为受支持的桌面开发框架v142工具集对C14/17标准支持良好MFC本身也持续在修bug。搭配销售管理系统的典型架构——对话框主界面 数据列表 数据库访问层MFC的项目结构恰好能快速搭起来。你要做商品维护、订单录入、客户管理、销售统计这些模块本质上就是表单 列表 SQL的增删改查组合这套东西在MFC里已经被无数项目验证过稳就是最大的优势。当然也要把丑话说在前面。MFC的UI绘制机制老旧控件换肤需要自绘动画效果基本别想字符串处理还是得牢记CString与std::string的转换编译出来的程序一旦崩溃排查难度比托管代码高不少。但对应到销售管理系统的实际需求这些劣势都可以接受。我的建议是不是所有项目都适合用MFC重构但在维护和定制化需求频繁的中小企业管理软件领域用VS2019 MFC做一套扎实可用的系统性价比仍然很高。2. VS2019环境与工程创建第一个坑就卡在组件和编码上2.1 装了VS2019却找不到MFC项目模板很多人上来就栽在这一步。VS2019默认安装路径里根本没有MFC模板因为VS安装器默认不勾选MFC组件。打开Visual Studio Installer找到已安装的VS2019点击修改确保勾选了使用C的桌面开发工作负载然后在右侧的安装详细信息列表里展开C桌面开发节点找到**适用于v142生成工具的C MFC(x86和x64)**。注意这个选项有两个子项一个针对x86一个针对x64建议都勾上。如果你还需要ATL顺手把适用于v142生成工具的C ATL也勾了MFC项目向导在某些配置下会依赖它。这一步做完新建项目时才能看到MFC应用模板。2.2 项目类型选择对话框应用就够了MFC项目向导里提供多种类型单个文档、多个文档、基于对话框。销售管理系统通常不需要文档/视图架构那一套复杂的序列化机制主界面就是一个带菜单栏、工具栏和状态栏的大对话框所以选**基于对话框**最省事。如果后续觉得对话框窗口管理不过来也可以改成FormView 单文档框架但我的经验是——对话框的定位、缩放、子控件布局自己写起来更可控销售管理系统这种窗口内嵌各种分区的界面对话框反而是最自然的选择。向导中其他设置按默认即可字符集我会直接选使用Unicode字符集一旦日后要对接外部系统或者导出ExcelUnicode能让你少掉很多乱码头发的机会。2.3 中文注释和中文输出就报错根子是编码页冲突这是搜索词里霸榜的问题也是我可想而知会出现的状况。VS2019默认情况下MSVC编译器按系统的ANSI代码页中文系统通常是GBK/936来解读源文件。如果你用VS的默认设置新建一个.cpp文件它保存的格式是UTF-8无BOM当你往这个文件里写入中文字符串或注释时编译器按GBK去解码UTF-8字节流就会把中文字节误解码成乱码轻则出现C4819警告该文件包含不能在当前代码页中表示的字符重则直接报C2001等编译错误尤其是字符串文本里的中文字符会造成字面量意外终结。解决的思路有三条我按推荐程度排序给源文件加BOM头。用VS打开文件后文件 - 另存为 - 右上角保存按钮的倒三角 - 编码保存 - 选择Unicode(UTF-8带签名)-代码页65001。这样编译器能正确识别UTF-8中文字符串和注释都再无问题。缺点是团队协作时要么所有人都用带BOM的格式要么git会在BOM上产生差异需要统一配置。在cpp文件首行加编译指示#pragma execution_character_set(utf-8)这条指令告诉编译器把字符串字面量按UTF-8编码写入生成的可执行文件程序运行时字符串就会以UTF-8形式存在。但注意它不影响编译器解读源文件的方式如果源文件本身就是无BOM的UTF-8编译器读取文件时还是会按GBK解出乱码照样报错。所以这个方案必须配合文件本身是UTF-8无BOM才有意义有点鸡生蛋的问题——实际上最省心的是方案3。把VS的保存文档时使用Unicode编码设为UTF-8带签名并统一团队规则。Tools - Options - Environment - Documents - 勾选Save documents in Unicode when cannot be saved in code page同时给编辑器装上Force UTF-8 (with BOM)之类扩展存在争议我实测下来最保险的还是方案1最机械但最可靠。还要特别提醒一个坑不要在cpp文件里混用注释里的全角引号和代码中的字符串引号。我在项目里遇到过中文注释导致括号匹配错乱的假象本质上是编码解读出乱码后注释符//之后的乱码字节恰好包含了换行符的牺牲品编译器行为变得奇怪。这类问题扫一眼文件编码再扫一眼保存格式基本就有定论。2.4 编译闪退多半不是代码的锅有相当一部分编译闪退其实发生在VS2019运行时的环境问题。如果你点击本地Windows调试器后窗口弹一下立刻消失先检查项目是否配置了正确的入口点——MFC应用必须包含CWinApp派生类且项目向导生成的theApp要存在。另外如果是Debug下正常、Release下闪退优先怀疑未初始化的成员变量。销售管理系统里数据访问对象、数据库连接指针这类成员如果构造函数里忘了置NULLRelease下用的可能就是野指针一运行就崩。建议所有成员变量要么在声明处初始化要么在构造函数初始化列表里赋值这条规矩对MFC项目尤其重要。3. 销售管理系统的数据底座表结构设计与ADO数据库封装3.1 核心表设计销售管理系统的数据模型不复杂但表之间的关联要清晰。我这里给出通常项目最快能用的一组表结构以SQL Server为例MySQL/Oracle只需做少量语法调整Product商品表ProductID自增主键、ProductCode商品编码SKU、ProductName商品名称、Category分类、Spec规格、Unit单位、SalePrice销售价、CostPrice成本价、StockQty库存数量、SaleCount累计销量、CreateTime。Customer客户表CustomerID、CustomerCode、CustomerName、Contact、Phone、Address、CreditLimit授信额度做账期销售时需要。Users员工/操作员表UserID、UserName、LoginName、PasswordHash、Role角色收银员/管理员密码绝不能存明文。SaleOrder销售订单主表OrderID建议用自定义单号如SO20240412001、UserID操作员、CustomerID、OrderDate、TotalAmount含税总金额、DiscountAmount优惠金额、PayMethod支付方式、StatusCode状态待支付/已支付/已退款。SaleOrderDetail订单明细分表DetailID、OrderID、ProductID、Quantity数量、Price当时成交单价注意快照价格、Amount行合计、Remark。主表和明细表为什么要分开因为一张订单可能包含多个商品而统计报表经常按订单分组查总金额也经常按商品查销量分表后用JOIN关联两边查询都干净。销售统计里的核心指标——月销售总额、热销商品排行、客户贡献度都可以通过一个GROUP BY SUM ORDER BY搞定。比如热销商品排行SELECT TOP 20 p.ProductName, SUM(d.Quantity) AS TotalQty, SUM(d.Amount) AS TotalAmount FROM SaleOrderDetail d INNER JOIN SaleOrder o ON d.OrderID o.OrderID INNER JOIN Product p ON d.ProductID p.ProductID WHERE o.OrderDate 2024-01-01 AND o.OrderDate 2024-04-01 GROUP BY p.ProductName ORDER BY TotalQty DESC3.2 MFC访问数据库的方案选型MFC程序连数据库老牌选择有三个ODBC API、DAO、ADO。我的建议是直接上ADOActiveX Data Objects理由很实在ADO基于COM几乎支持所有主流数据库SQL Server、MySQL、Oracle、Access代码写起来比ODBC舒服而且MFC项目对ADO封装的资料最多遇到问题几乎都能搜到现成答案。ADO连接SQL Server用ProviderSQLOLEDB连接MySQL需要先装MySQL的ODBC驱动然后走ProviderMSDASQLDriver{MySQL ODBC 8.0 Unicode Driver}。封装一个数据库访问层是比较好的做法CAdoDatabase类负责连接、执行SQL、取数据集。下面是个可以开箱即用的最小封装#import C:\Program Files\Common Files\System\ado\msado15.dll no_namespace rename(EOF,adoEOF) class CAdoDatabase { public: _ConnectionPtr m_pConn; _RecordsetPtr m_pRs; bool Connect(const CString strConn) { HRESULT hr m_pConn.CreateInstance(__uuidof(Connection)); if (FAILED(hr)) return false; hr m_pConn-Open(_bstr_t(strConn), _bstr_t(L), _bstr_t(L), adConnectUnspecified); return SUCCEEDED(hr); } bool ExecuteSQL(const CString strSQL) { try { m_pConn-Execute(_bstr_t(strSQL), NULL, adCmdText); return true; } catch (_com_error e) { AfxMessageBox(e.ErrorMessage()); return false; } } _RecordsetPtr Query(const CString strSQL) { try { m_pRs.CreateInstance(__uuidof(Recordset)); m_pRs-Open(_bstr_t(strSQL), m_pConn.GetInterfacePtr(), adOpenStatic, adLockOptimistic, adCmdText); return m_pRs; } catch (_com_error e) { AfxMessageBox(e.ErrorMessage()); return NULL; } } };注意#import的路径要按实际系统调整64位系统里如果编译出来报找不到msado15.tlh就把路径换成C:\Program Files (x86)\Common Files\System\ado\msado15.dll映射一下。实际调试中还有一个高发问题_ConnectionPtr指针在对话框销毁时不会自动释放极可能导致进程退出时崩溃。所以一定要在CDialogEx的OnDestroy里主动调用m_pConn.Release();和m_pRs.Release();或者用智能指针封装。3.3 业务层与界面层解耦销售管理系统虽然不大但代码如果全部堆在按钮的OnBnClicked事件里用不了两个月就成了一团浆糊。我沿用C经典的分层思路对话框类只负责取用户输入并显示结果中间加一个原子业务函数层比如CSaleService::CreateOrder(CSaleOrder order, vectorCSaleOrderDetail details)这类函数内部完成多表事务再往下一层才是CAdoDatabase的数据访问。这样当你从SQL Server换到MySQL或者从对话窗口改成网页API只要改数据访问层上层业务完全不受影响。事务处理上MFC里操作数据库事务直接调用连接对象的BeginTrans()/CommitTrans()/RollbackTrans()下单时先插主表拿到OrderID再循环插入明细分表任何一个失败就回滚避免出现订单头存在、明细丢失的脏数据。4. 界面控件的实战经验列表、自绘按钮与自适应布局4.1 商品列表用CListCtrl报表视图销售管理系统的中心区域几乎永远是数据列表。CListCtrl切换到报表模式LVS_REPORT配合CListCtrl::InsertColumn设置列头用InsertItem逐行填充。做商品管理时商品数量通常几百到几千直接全部加载问题不大但如果是订单明细长期运营后可能是几万到几十万条此时再用InsertItem一条条塞进去界面会卡到怀疑人生。解决方案两个分页加载按时间或订单号范围分段查询比如每次只加载一个月的数据配合顶部搜索条件。虚拟列表给列表控件设置LVS_OWNERDATA风格自己处理LVN_GETDISPINFO通知消息数据存内存数组列表只显示可视区域的行。虚拟列表的代码量稍大但对大数据的滚动流畅度提升非常明显。销售统计报表的结果集不会太大分页基本就够了什么时候用虚拟列表当你在订单管理里想一次性展示全年上万条订单且要求随便滚动时虚拟列表是更优解。4.2 自定义按钮和静态文本覆盖问题MFC默认按钮样式是比较古旧的想让它好看些常规做法是CButton派生一个自绘类重写DrawItem。下一步必须在按钮属性中设置Owner Draw为True否则DrawItem根本不会被调用。自绘按钮核心在两点根据按钮状态正常/悬停/按下/禁用选不同的背景色和文字色文字居中绘制用DrawText(..., DT_CENTER | DT_VCENTER | DT_SINGLELINE)。给按钮加个细节——鼠标悬停变色需要重写OnMouseMove和OnMouseLeave设置TRACKMOUSEEVENT让系统在鼠标离开时通知你。再聊热搜词里另一个高频问题MFC静态文本 覆盖。很多人在对话框上加控件时发现静态文本Static Text被其他控件挡住了或者运行时文字不刷新。这个问题的本质是**控件的Z序Tab顺序**问题。对话框的每个控件都有一个Tab顺序最后创建的控件默认Z序在最上面。静态文本和Group Box在Tab顺序里如果排在多个控件之后就会遮住别的控件。解决方式按键盘CtrlD对话框上会显示Tab顺序标号按你期望的顺序依次点击控件来调整。静态文本的样式里有Notify、Sunken等设置会造成自绘不下发纯粹的标签文本把Client Edge和Static Edge取消掉避免渐变背景误以为其他控件画在它上面。如果是在代码里动态创建控件注意创建顺序后创建的窗口默认会显示在前面OnSize里要置顶。静态文本不刷新还有一个原因控件默认背景是对话框背景刷子如果你在OnCtlColor里不返回背景刷子而静态文本区域又恰好被覆盖就会显示残留。解决方案是在OnCtlColor中匹配静态文本控件ID并用SetBkMode(TRANSPARENT)设为透明再把DC的文字颜色设置好。这样静态文本背景就随对话框背景走了各种重叠、脏背景问题都能缓解。4.3 控件自适应屏幕分辨率销售管理系统的客户机千奇百怪从1024x768的工控屏到2K高分屏都可能出现。控件自适应有两条路线路线一经典比例缩放。在对话框第一次显示时保存每个控件相对于客户区的位置和尺寸比例在OnSize里按比例移动和拉伸。操作步骤是OnInitDialog里遍历所有子窗口把每个控件的Rect记录到数组同时记录客户区基准宽高在OnSize里分别用新的宽高除以基准宽高得到x和y方向的缩放比例对控件的Left/Top乘以x方向比例、Right/Bottom乘以y方向比例然后用SetWindowPos重新定位。缺点很明显控件太多时列表拉宽了按钮也被拉扁了效果有时会有点诡异。路线二PerMonitorV2高DPI支持推荐。VS2019生成的MFC项目默认支持系统DPI缩放但如果你想做到真正的每显示器高DPI感知需要在app.manifest里添加application xmlnshttp://schemas.microsoft.com/SMI/2016/WindowsSettings dpiAwarenessPerMonitorV2/dpiAwareness /application并设置项目属性 - 清单工具 - 输入和输出 - DPI感知 - 每个监视器高DPI支持。MFC框架在VS2019中已经对PerMonitorV2做了适配对话框在DPI变化时会整体缩放比老代码里手写OnSize比例缩放稳得多。但要提醒一句如果你使用了自绘控件、自绘按钮必须自己处理DPI缩放逻辑包括字体大小、图片位图的缩放否则会出现按钮文字溢出、图片模糊的问题。两条路线我的实际建议是新项目优先走PerMonitorV2路线代码干净省去一堆原生适配琐事老项目改造如果只想局部修正比如窗口太大一屏装不下可以在OnInitDialog里根据屏幕分辨率动态调整窗口初始大小再配合OnSize比例缩放也能撑住绝大多数使用场景。4.4 列表框与常用控件的几个小经验热搜词里出现MFC列表框控件的使用这里简单补充。CListBox在销售系统里常用于下拉选择客户、商品分类、仓库等场景。AddString添加项后用GetCurSel获取当前选中索引GetLBText取得对应文本。注意点如果列表框内容会根据数据库变化刷新先调用ResetContent清空再添加新项最后SetCurSel(0)让第一项默认选中避免空选框传回空值导致SQL语句出BUG——这类隐藏的空值问题实际上非常常见所以做数据校验时不要把下拉框当成可空输入。文本方面的另一个高频需求是把数字转成金额格式CString的Format(L%.2f, price)只能得到1234.50要想千分位显示1,234.50Windows APIGetNumberFormat可以搞定但MFC项目里更轻量的做法是直接拼接。注意金额计算一律用double比较时别用判断相等而是做精度容差比如fabs(d1 - d2) 0.001f销售系统里这个细节能避免很多奇葩的钱对不上问题。5. 核心业务模块的编码节奏从下单到统计怎么落地5.1 商品上下架与库存变更商品管理模块就是典型的列表 编辑对话框。左边搜索区按编码、名称模糊查询用LIKE拼接SQL中间CListCtrl展示结果底部新增/修改/删除按钮。实现时有个边界条件要特别注意商品被订单明细引用后不能物理删除只能做停用标记。所以Product表里最好有一个Enabled字段删除按钮弹出确认后执行UPDATE Product SET Enabled0 WHERE ProductID?。这样销售历史中的商品名称、价格快照依然能在报表里查询到而不是变成一堆NULL或者关联失败。库存扣减不必做成复杂的仓储事务。最简单的可靠实现是在订单提交成功后执行一条UPDATE Product SET StockQty StockQty - ? WHERE ProductID ? AND StockQty ?通过受影响行数判断库存是否充足。受影响的记录数为0说明库存不足立刻回滚订单事务。这个写法避免了先SELECT再UPDATE中间可能产生的超卖问题。5.2 订单录入界面主列表和明细列表的联动订单录入是销售系统的重灾区建议把一个订单拆成两个列表上方主表区域显示已有订单OrderID、客户、日期、总额、状态下方明细区域显示当前选中订单的明细记录。两个列表用订单选中事件联动实现起来基本就是在主列表的LVN_ITEMCHANGED消息里重新查询一次明细表并刷新生成列表。性能上明细不必一次载入每次切换订单查询一次即可SQLite和SQL Server这种量级都毫秒级响应。录入新订单时弹出一个模态对话框上半部选客户、填操作员、支付方式和日期下半部是个可增删行的CListCtrl没行输入商品编码后自动带出名称和价格输数量后自动算行金额底部显示订单总额。这些联动逻辑用CListCtrl虽然写起来比C# DataGrid麻烦但自由度高完全按业务诉求定制比如该客户授信额度不足时在对话框上直接标红提示并禁止保存。做到这个深度系统的实用性会比普通demo高出一大截。5.3 销售统计与多条件筛选统计报表不需要界面上重复造轮子把查询条件起始日期、结束日期、商品分类、客户、操作员做成对话框顶部的条件区下方用CListCtrl展示聚合结果即可。SQL的GROUP BY SUM在数据库端把数据算好MFC只负责把数据集一行行塞进列表。数据量较大时可以加一个Excel导出功能用ODBC或CSV导出是两条可选路径导出CSV最简单用CStdioFile按UTF-8 BOM编码逐行写然后提示用户用Excel打开如果需要xlsx格式再引入第三方库。我的经验是先做CSV导出就能覆盖客户的绝大多数导出到Excel需求没必要一上来就引入庞大依赖。统计SQL里还有个小技巧按月汇总可以用CONVERT(VARCHAR(7), OrderDate, 120)拿到2024-04这种格式做分组键按季度则用DATEPART(QUARTER, OrderDate)结合YEAR。这些聚合查询是销售管理系统里最有含金量的地方设计表结构时考虑到这些查询业务功能做起来会顺很多。5.4 文件保存与对话框记忆功能实际使用中客户会反复要求下次打开的时候记住我的查询条件。这个在MFC里很简单把当前窗口位置、列宽、最近查询日期范围这些配置写到应用目录下的config.ini或注册表里。我推荐用INI文件——用WritePrivateProfileString和GetPrivateProfileString读写简单直观而且客户备份配置时复制一个文件就够了。只注意一个问题程序安装在Program Files目录下时普通用户可能没有写入权限所以INIFile的存储路径应该用GetAppDataPath或程序目录下的一级子目录不要硬编码到C盘系统目录。6. 发布部署把Release装到客户机器上的那些坎6.1 编译Release版本的正确姿势交付给客户之前务必在Release模式下重新编译一次。Debug版跑得正常的程序Release版可能因为变量初始化、编译器优化导致行为异常销售管理系统虽不至于触发太底层的问题但Release下订单总额计算和Debug不一致这种bug我真实遇到过——原因是浮点优化把运算顺序改了精度差异被累计放大。所以对金额计算一个稳妥的方法是所有金额都用整数分存储数据库里存分成单位界面显示时除以100彻底绕过浮点误差。这是老财务系统的最佳实践放到MFC项目里同样适用。再检查一下项目属性 - C/C - 代码生成 - 运行库。默认是多线程(/MT)这种方式把C/C运行库静态链接到了exe里客户机器上无需安装VC Redistributable如果选多线程DLL(/MD)运行时会依赖MSVCP140.dll等文件就必须捆绑vcredist。销售管理系统部署到门店和收银机时环境不可控因素很多我的建议是直接用/MT静态链接简单省事换来的代价是exe体积略大一点大概多个一两MB完全可以接受。6.2 打包安装程序的思路VS2019本身不带安装项目模板需要先在VS Installer里安装Microsoft Visual Studio Installer Projects扩展装完后新建项目里会出现Setup Project。但说实话这个内置安装项目能力非常古老对于MFC应用的打包我更推荐用Inno Setup——免费、脚本化、生成体积小对中文界面支持也好。Inno Setup的脚本虽然要写但常见模板就几行复制修改即可。下面是个最小可用的打包脚本框架[Setup] AppName销售管理系统 AppVersion1.0.0 DefaultDirName{autopf}\SaleManager DefaultGroupName销售管理系统 UninstallDisplayIcon{app}\SaleManager.exe Compressionlzma2 SolidCompressionyes OutputBaseFilenameSaleManagerSetup PrivilegesRequiredadmin [Files] Source: D:\build\Release\SaleManager.exe; DestDir: {app} Source: D:\build\Release\config.ini; DestDir: {app} Source: D:\build\Release\data.db; DestDir: {app} [Icons] Name: {group}\销售管理系统; Filename: {app}\SaleManager.exe Name: {group}\卸载销售管理系统; Filename: {uninstallexe}如果你的业务要求客户机器上保留数据库文件在安装目录之外的位置Data目录要单独用InitializeSetup或者安装后的配置文件引导程序去生成。我习惯在exe启动时读取config.ini如果数据库文件不存在则自动创建并初始化表结构这样客户拿到安装包装完就能直接用不需要手动建库建表部署体验好很多。6.3 客户机上双击没反应的排查顺序交付后如果真的出现客户环境跑不起来的状况按下面顺序排查90%的问题五到十分钟内解决确认exe已经在客户机上而不是快捷方式路径不对确认Visual C运行库有没有问题——如果你按上面的建议用了/MT这一条直接跳过确认杀毒软件有没有把exe或者INI文件隔离了国内不少企业电脑装了安全软件MFC程序第一次联网写入配置时有被拦的概率手动到exe所在目录双击运行看是否有错误弹窗对话框程序的崩溃信息有时候会被系统拦截连日志都不留建议在入口点写全局的SetUnhandledExceptionFilter把崩溃栈记录到文本文件里排查起来会省力很多。这条崩溃日志的思路很多人不屑但当你出差到客户现场、远离自己调试环境的时候一个小日志文件能救你于水火。在CWinApp的InitInstance里加几行代码把未处理异常转向自己的处理函数用MiniDumpWriteDump生成dump文件回来用VS2019打开dump定位崩溃位置——这套流程学会之后打包部署的信心会完全不一样。最后再分享一个实际项目里的小细节MFC应用第一次启动时把程序版本号和数据库版本号写入config.ini后续每次启动时做一次检测如果发现版本不一致就自动执行升级SQL脚本。销售管理系统的生命周期往往长达五到十年上线之后每半年加个字段、改个报表是常态有了这个机制后续发版升级就不用每次跑到门店去手动更新数据库了。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门