SkinMagic提供的静态库不支持Unicode,将该库链接到支持Unicode编码的工程中会出现错误LNK2001,原因
很简单:静态库中的代码是硬编码了,无法改变,而SkinMagicLib.h中定义的函数参数(字符串)在Unicode
工程中被重新解析了,所以原先的函数声明和函数定义中的参数不一致,当然会出错了。本文介绍了对原本不
支持Unicode的静态库,如何能链接到Unicode编码的工程中。
如果你有静态库的源代码,问题就好办了,直接在静态库所在的VC工程中Project Setting/ C/C++ 的
Preprocessor definations加入 _UNICODE,编译后生成的静态库就可以用到支持Unicode编码的应用程
序所在的工程中了。
skinmagic的作者没有提供Unicode 版的静态库,所以只好另外想办法了。以"破解静态库"那篇文章中
附件MDIDemo为例,该工程包含的静态库是SkinMagicLibMD6.lib, 其它静态库的处理方法完全相同,不
再赘述。将该库拷贝一份出来,重命名为SkinMagicLibUMD6.lib,下面的方法可将SkinMagicLibUMD6.lib
改成支持Unicode的静态库。步骤如下:
1. 修改MDIDemo工程的编译选项
在Project Setting/Link中加入: /entry:"wWinMainCRTStartup"
2. 欺骗编译环境
造成函数声明和函数定义中的参数不一致的元凶是SkinMagicLib.h文件中所有参数为"LPCTSTR"的函数,
比如:
int __stdcall LoadSkinFile( LPCTSTR lpSkinFile );
按照__stdcall的调用约定,产生形如: LoadSkinFile@@YGHPBD@Z 的东东.
其中"PBD"很关键,只要把它换成"PBG"就可以骗过编译器了 :)
如果只是让工程MDIDemo编译通过,那么只要改以下函数即可:
InitSkinMagicLib
SetWindowSkin
LoadSkinFile
SetDialogSkin
SetControlTooltip
彻底的改法是把SkinMagicLib.h文件中所有参数为"LPCTSTR"的函数都做上述修改,我们以修改LoadSkinFile
为例,说一下修改方法:
用UltraEdit打开SkinMagicLibUMD6.lib文件,查找(ASCII)"LoadSkinFile", 比如找到:
?LoadSkinFile@@YGHPBD@Z
改成
?LoadSkinFile@@YGHPBG@Z
这里会找到3处,分别修改就行了,其它的函数按照同样方法修改。
注意LoadSkinFile函数比较特殊,它在内部调用了LoadSkinFromFile,参数也是"LPCTSTR"型的,所以需要
针对LoadSkinFromFile做同样的处理。
3. 修改调用方法
这样修改后编译是通过了,但还没有完,注意到MDIDemo工程中对skinmagic中参数为"LPCTSTR"的函数的调用
VERIFY( 1 == LoadSkinFile( _T("corona.smf") ) );
这个"_T"会把const型的字符转换成wchar,造成参数误读。根本解决办法是修改LoadSkinFile的内部实现,
将Unicode参数再转换回原来的Multi-Byte型,实现有些复杂,所以这里绕了个弯,改成如下调用方式:VERIFY( 1 == LoadSkinFile( (LPCTSTR)"corona.smf" ) );
也就是说,只要你调用了skinmagic库中参数是LPCTSTR的函数,一定注意将_T改成(LPCTSTR).
4. ExitSkinMagicLib
按照上述修改后,编译运行即可弹出带皮肤的界面,但是对Debug版来说(Release版没这个问题),当程序退出
后会出现断言错误,调试时发现是CMainFrame::DestroyWindow中CMDIFrameWnd::DestroyWindow调用出错,于是
只好把:CMDIDemoApp::ExitInstance() 中的ExitSkinMagicLib调用放到CMDIFrameWnd::DestroyWindow之前,
问题解决。附件是修改过静态库后的工程文件:
附件[MDIDemoUnicode.rar]:
http://blog.blogchina.com/upload/2004-12-11/20041211231750628890.rar