VC真是个非常笨非常不友好工具还是这样说VC(MFC)和现在流行.net framework java比起来就想石器时代跟工业时代相比样!
接触MFC也有几年了为了它有过加班、有过熬夜、甚至通宵代码没有十万行也应该有几万行了但是MFC就是这么牛它牛得不但令新手忘而却步而且常常令有经验软件Software工程师也栽跟斗最近由于个小小环境设置设置问题花了很多时间这跟用惯了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集而我给CStringFormat是“多集”(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];
mem(buf,0,20);
WideCharToMultiByte( //转换Unicode到Ansi
CP_ACP,
WC_COMPOSITECHECK | WC_DEFAULTCHAR,
strWideChar,
strWideChar.GetLength,
(char *)buf, //转换到缓冲区中
20, //最多个字节
0,
0
);
同样你接收到串想要在界面正常显示还必须把它转换成宽字节表示(烦吧?):
char chBytes[8];
memcpy(chBytes,”aaaaaaa\0”,8);
WCHAR wch[9];
n = MultiByteToWideChar( //转换Unicode到Ansi
CP_ACP,
0,
chBytes,
8,
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”就是多字节集
第 2次中招god花了我好长时间才找到问题:
我在CodeProject上找了个很厚道老外写个继承了CDialog窗体类CResizableDialog源码这个类作用是使MFC窗体放大缩小时窗体上Control控件可以定位(Auchor)不要小看这个小小每天都要用到功能用MFC实现真很麻烦很佩服那个老外写了那么多代码(当然跟他们条件有关资本主义国家工人随便找个工作就可以衣食无忧病了政府照顾我们做“挨踢”活得像民工样当然没有那个闲情去写那么好代码免费给别人使用这是题外话)
我拿了那个现成工程直接在我工程里引用他工程Everything works perfect直到我把项目发布成Release双击运行后没有任何反应Very weird!后来我用MessageBox打印消息发现运行到DoModal里面就没有出来直接退出了!使用trycatch都得不到!我窗体是继承老外写窗体类来原先继承CDialog是好好问题肯定在他工程里面可是他给举例没有任何问题啊MFC出错时候是很要命它不会给你任何提示它就是不干了!
我又拿个前测试让它从CResizableDialog继承也没有任何问题
简直头大了、无语了不知道哪里出现了问题Release又不能像Debug那样调试打了堆MessageBox后还是不知道问题出现在哪里凭着经验可以知道中可能出现了内存越界访问什么致命才会导致“声不吭”地退出但是究竟哪里出了问题呢?
就在束手无策时候我发现CResizableDialog成员EnableSaveRestore会引发链接:“未定义外部符号”不引用它不会出错测试引用它没有任何通常这个造成是引用在.h文件里声明了但是在.cpp里面没有定义或者.cpp文件里定义和.h上参数对不上但是此时不可能是这个测试没有啊直觉告诉我这是解决“Release后直接退出关键”说不定这个问题解决了Release问题也解决了
MFC真是很强大它强大得不但“像迷宫样里面有怪兽进去不小心就永远出不来”而且它让你当遇到怪兽时候总是给你点点星光只要你不放弃奇迹就会出现你就会练成绝世神功这跟武侠小说是相通主人公每次到了生死关头就会出现奇迹成为天下无敌高手看看我如何找到解决思路方法Very tricky:
既然EnableSaveRestore出现了不该出现那么就从这个开始找这个是这样:
.h文件声明
void EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly = FALSE);
.cpp文件定义
void CResizableDialog::EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly/* = FALSE */)
{
m_sSection = pszSection;
m_bEnableSaveRestore = TRUE;
m_bRectOnly = bRectOnly;
// restore immediately
LoadWindowRect(pszSection, bRectOnly);
}
上面代码没有任何既然没有就要用使用以下思路方法来找:
1.重新为CResizableDialog写个它没有参数它发现没有看来参数有问题
2.既然没有参数没有就把出问题参数去掉吧竟然也没有!那问题就肯定是出在参数上
3.去掉其中个参数测试发现是LPCTSTR pszSection问题而不是BOOL bRectOnly问题
4.既然这样那就换种表示吧把LPCTSTR pszSection换成WCHAR* pszSection运行它竟然不出错了!翻开MFC宏定义就会发现其实LPCTSTR和WCHAR*是样MFC真是freak!
5.但是这个功能还是不正常断点进入那个里面发现传进去串只有个了这种情况就是宽当成短时第 2个字节\0当成了串截止了也就是说这个里采用是短(多集Multi Byte)处理
6.我工程采用是宽集(Unicode Char)检查设置原来那个老外是用VC6编默认是使用多集(Multi Byte)VC真是笨啊两个Project在个Solution里面完全区别设置竟然没有任何提示简直把我弄死了!
7.把引用工程也改成使用Unicode集并且把EnableSaveRestore WCHAR* pszSection恢复原样搞定!果然不出我所料Release也没有问题了!我用以前那个测试来使刚好以前把它设成Multi Byte所以也没有Damn!
仅仅是个设置啊如果VC出错提示稍微好至少集不匹配不要说成“未定义外部符号”也好用点啊难怪现在用VC人越来越少了!
注:通常说VC不是指使用.net frameworkVC那个很简单内存都不用管通常是指非托管VC
最新评论