接触MFC也有几年了,为了它有过加班、有过熬夜、甚至通宵,代码没有十万行也应该有几万行了.但是MFC就是这么牛,它牛得不但令新手忘而却步,而且常常令有经验的软件工程师也栽跟斗.最近由于一个小小的环境设置设置问题花了很多时间,这跟用惯了VC6突然转到VC2005有关,但关键还是VC实在太笨了,它让我在一周内连续两中招次!
第一次中招是这样的,很简单:
我不知道VC.net2005默认工程默认设置是采用"Unicode字符集"(Unicode Character Set)的,以前用VC6工程的时候默认是"多字符集"(Multi-Byte Character Set)的.以前也没有用过VC.net2005啊,我一直认为.net是用来在framework上面编程的,在MFC上编程没有必要打开庞大的.net2005,把机器弄得像牛拉车一样.
我声明了一个CString,按计划给它赋值,就像下面:
CString s;
s.Format("count = %d",count);
按经验这肯定不会有错误的,但是不好意思,编译错误,因为这是我的环境采用的Unicode字符集的,而我给CString的Format函数是"多字符集"(Multi-Byte)所以编译不通过,要知道在这种设置下使用MessageBox("ddd");编译是不会通过的,因为系统调用的是MessageBoxW,即Unicode宽字符集的那个函数.
还好我根据编译器的提示把s.Format("count = %d",count);改成s.Format(_T("count = %d",count);就搞定了,_T代表一个宏,宏的意思就是把字符串转成宽字符表示.同样的,MessageBox("ddd");可以为MessageBox(_T("ddd"));
但是还有个问题就是,所有窗体显示的东西都是宽字符的,例如a在内存里就是a\0两个字节,前面一个字节a后面是\0,当从窗体取下数据(例如用户输入)要跟其他平台交互时,例如网络传输到远端机器.如果那边使用的不是Unicode字符集,就会出问题,为了使界面和后台传输一致,只好使用把宽字符转换成多字符集表示:
CString strWideChar;
strWideChar.Format(_T("这是宽字节哦"));
char buf[20];
memset(buf,0,20);
WideCharToMultiByte( //转换Unicode到Ansi
CP_ACP,
WC_COMPOSITECHECK | WC_DEFAULTCHAR,
strWideChar,
strWideChar.GetLength(),
(char *)buf, //转换到缓冲区中
20, //最多个字节
同样的,你接收到的字符串想要在界面正常显示,还必须把它转换成宽字节表示(烦吧?):
char chBytes[8];
memcpy(chBytes,"aaaaaaa\0",8);
WCHAR wch[9];
n = MultiByteToWideChar( //转换Unicode到Ansi
CP_ACP,
chBytes,
wch, //转换到缓冲区中
8 //最多个字节
wch[n] = '\0';
这样每次从界面取数据和把数据显示到界面上都要先做处理,但是也可以把编译环境设置成"多字符集"(Multi-Byte Character Set),就可以避免这样转换来转换去(可惜我发现的时候代码已经差不多写完了).就是在"Project->Configuration Properties->General->Character Set,选择"Use Unicode Character Set"就是使用Uncode字符集,选择" Use Multi-Byte Character Set"就是多字节字符集.
第二次中招,god,花了我好长时间才找到问题:
我在CodeProject上找了一个很厚道的老外写的一个继承了CDialog窗体类CResizableDialog的源码,这个类的作用是使MFC的窗体放大缩小时,窗体上的控件可以定位(Auchor),不要小看这个小小的每天都要用到的功能,用MFC实现真的很麻烦.很佩服那个老外写了那么多代码(当然跟他们的条件有关,资本主义国家的工人随便找个工作就可以衣食无忧,病了政府照顾,我们做"挨踢"的活得像民工一样,当然没有那个闲情去写那么好的代码免费给别人使用,这是题外话).
我拿了那个现成的工程,直接在我的工程里引用他的工程.Everything works perfect.直到我把项目发布成Release的,双击运行后没有任何反应,Very weird!后来我用MessageBox打印消息,发现运行到DoModal函数里面就没有出来,程序直接退出了!使用try,catch都得不到错误!因为我的窗体是继承老外写的窗体类来的,原先继承CDialog是好好的,问题肯定在他的工程里面,可是他给的示例程序没有任何问题啊.MFC出错的时候是很要命的,它不会给你任何提示,它就是不干了!
我又拿一个前的测试程序,让它从CResizableDialog继承,也没有任何问题.
简直头大了、无语了,不知道哪里出现了问题,Release又不能像Debug那样调试,打了一堆MessageBox后还是不知道问题出现在哪里.凭着经验,可以知道程序中可能出现了内存的越界访问什么的致命错误,才会导致程序"一声不吭"地退出,但是究竟哪里出了问题呢?
就在束手无策的时候,我发现调用CResizableDialog的成员函数EnableSaveRestore会引发链接错误:"未定义的外部符号",不引用它不会出错,测试程序引用它没有任何错误.通常这个错误造成是因为引用函数在.h文件里声明了,但是在.cpp里面没有定义,或者.cpp文件里的定义和.h上的参数对不上.但是此时不可能是这个错误,因为测试程序没有错误啊.直觉告诉我这是解决"Release后程序直接退出的关键",说不定这个函数调用的问题解决了Release的问题也解决了.
MFC真是很强大,它强大得不但"像迷宫一样,里面有怪兽,进去一不小心就永远出不来",而且它让你当遇到怪兽的时候总是给你一点点星光,只要你不放弃,奇迹就会出现,你就会练成绝世神功.这跟武侠小说是相通的,主人公每次到了生死关头就会出现奇迹,成为天下无敌的高手.看看我怎么找到解决方法的
该文转自网络:http://wenda.tianya.cn/wenda/thread?tid=5ef059fd09536957
分享到:
相关推荐
然而,将旧的VC 6.0工程转换到新的VS平台并不总是一帆风顺,会遇到一些挑战,主要包括编译指令的冲突、变量作用域问题以及OpenGL等SDK的兼容问题。下面我们将详细探讨这些内容。 首先,编译指令的冲突问题主要源于...
标题和描述中提到的"vs2005工程转换成vc6.0工程的小工具(vcproj->dsw包含源代码)"正是为了解决这种问题而设计的。 这个小工具的主要功能是将VS2005的项目文件(.vcproj)转换为VC6.0的项目工作区文件(.dsw),使得...
本文将围绕"VC.NET转换成VC6.0的程序源码"这一主题,深入探讨如何进行这种转换,并分享相关的知识点。 首先,理解两个版本的主要差异是至关重要的。VC.NET引入了.NET Framework,这是一个用于构建和运行.NET应用...
3. **代码兼容性**:VC7.0支持C++标准库的新功能,如STL改进,这可能需要在转换时检查和修改源代码,以适应VC6.0的旧版库。 4. **编译器选项**:编译设置如警告级别、优化选项等可能有所不同,需要在VC6.0中重新...
本文将深入探讨“图像颜色空间转换VC6.0源代码”所涉及的知识点,包括颜色空间的基本概念、RGB与HSV颜色空间的区别以及如何在Visual C++ 6.0(简称VC6.0)环境下实现这种转换。 首先,我们了解颜色空间的概念。颜色...
《飞机飞行源代码(VC6.0)》 在计算机编程领域,开发一款模拟飞机飞行的程序是一项富有挑战性的任务,它涉及到多个复杂的系统和算法。这个“飞机飞行源代码(VC6.0)”正是这样一款应用的源代码,它是使用微软的...
在本文中,我们将深入探讨如何在Visual C++ 6.0(简称VC 6.0)环境下编译和调试FFmpeg源代码。 ### 1. 安装与配置VC 6.0 首先,确保你已经安装了Visual C++ 6.0,这是一个经典的开发环境,虽然较旧但仍然可以用于...
标题 "VC.NET_To_VC6.0.rar_VC.NET VC6.0_vc6.0" 暗示了这个压缩包包含了一个工具或者一组转换过程,旨在帮助用户将基于Visual C++.NET(VC.NET)的项目或代码转换为适用于Visual C++ 6.0(VC6.0)的格式。...
5. **编译和链接器**:VC6.0的编译器和链接器能快速将源代码转换成可执行文件,支持多种优化选项以提高程序性能。 【安装与运行】 "vc6_cn_full.exe"是VC6.0的简体中文完整版安装程序,双击运行后按照向导步骤进行...
连接器是编译过程中的一个重要环节,它的主要任务是在编译器将源代码转换为一个个独立的对象文件后,将这些文件合并成一个可执行程序。在这个过程中,连接器会处理符号引用、合并代码和数据、以及处理库文件等。 在...
5. **编译器和链接器**:将源代码转换为可执行文件的关键组件。 虽然VC6.0免安装版方便实用,但需要注意的是,由于其发布时间较早,不支持现代的C++标准和特性,也不包含对64位系统的原生支持。同时,可能存在与新...
以下将详细讲解如何在VC6.0中实现NTP时间服务器同步的代码逻辑、涉及的关键技术和相关知识点。 1. **NTP协议理解**: - NTP是一种基于UDP的应用层协议,使用端口号123。 - 它通过发送时间请求包到NTP服务器,然后...
《VC6.0 编写的简易计算器:编程入门与实践指南》 在计算机科学的世界里,编程是一项基础而重要的技能,对于初学者来说,通过实际项目来学习编程语言是最佳的方式之一。本篇文章将深入探讨如何使用Visual C++ 6.0...
通过深入研究这个“VC6.0计算器源代码”,我们可以了解到MFC应用程序的基本架构,以及如何处理用户输入和控制GUI元素。这不仅有助于理解Windows程序的工作原理,也为后续更复杂的项目打下坚实基础。在实践中,不断...
在“数字时钟源代码VC6.0”项目中,我们通常会创建一个派生自`CDialog`的类,比如`CDigitalClock`,这个类将负责实现数字时钟的功能。 创建对话框应用程序的第一步是设计对话框资源。在VC6.0的Resource Editor中,...
WndTabs是一款针对Microsoft Visual C++ 6.0(简称VC6.0)开发环境的高效增强插件,它显著提升了代码编辑器的多文档界面(MDI)管理能力。这款插件在原有VC6.0的基础上增加了标签式界面,使得用户在处理多个源代码...
3. **编译器和链接器**:这个精简版包含MSVC++ 6.0的编译器,可以将源代码转换为可执行文件。同时,链接器将编译产生的.obj文件合并成一个可执行程序。 4. **调试器**:VC6.0内置的调试器允许开发者设置断点、查看...
2. **编译器和链接器**:编译器将源代码转换为机器可执行的二进制代码,而链接器则将编译后的对象文件合并成一个可执行文件,处理库的引用和符号解析。 3. **调试器**:VC6.0的调试器提供强大的断点设置、单步执行...
通过这些源代码,初学者可以学习到图像处理的基本流程和编程技巧,同时了解VC6.0环境下如何组织和调用函数,以及如何利用面向对象的特性设计图像处理类。 需要注意的是,虽然VC6.0是一个经典且功能强大的IDE,但它...
在“推箱子vc6.0源代码”中,我们讨论的是使用Microsoft Visual C++ 6.0(简称VC6.0)开发的推箱子游戏的原始编程代码。VC6.0是微软发布的一款古老的但仍然被许多开发者用来学习C++编程的集成开发环境。尽管它已经...