(转)将VC6.0转为VS2010

[Quote=引用 14 楼 akirya 的回复:]
mfc没啥问题吧,我直接用VC5的mfc头文件,链接对应的mfc42直接就过去了。
[/Quote]

:O!!!!
看到坏编译通过,我重新有了解决它的信心,再去试!

今天发现了一个很好的链接的命令行, /verbose,可以显示查找符号时候的详细过程。

在一通折腾之后终于成功的解决了这个问题,兴奋之余,上来结贴:
工程的include的目录设置为
D:\xpoy\tools\编译器\IDE\vc6\VC98\Include;
D:\xpoy\tools\编译器\IDE\vc6\VC98\MFC\Include;
D:\xpoy\tools\编译器\IDE\vc6\VC98\ATL\Include;

那个什么#using的LIBPATH的设置为
D:\xpoy\tools\编译器\IDE\vc6\VC98\Lib;
D:\xpoy\tools\编译器\IDE\vc6\VC98\MFC\Lib;

排除目录为
D:\xpoy\tools\编译器\IDE\vc6\VC98\Lib;
D:\xpoy\tools\编译器\IDE\vc6\VC98\MFC\Lib;

src目录为
D:\xpoy\tools\编译器\IDE\vc6\VC98\CRT\SRC;
D:\xpoy\tools\编译器\IDE\vc6\VC98\MFC\SRC;

工程的其他需要设置的地方包括,
工程选项->C/C++ ->代码生成->启用c++异常== 否
                              较小类型时检查== 否
                              基本运行时检查== 默认值 (也就是无)
工程选项->C/C++ ->语言->将wchar_t视为内置类型== 否

注意如果没有特别需要的话,不要在这种情况下禁用掉默认链接的那些库,不然你需要手工根据vs编译时查找的库配置好。可以参考最后面的一些信息来这样做。

工程配置好之后,我们的工程就是可以依赖vc6的库而不是vs2010的了!

下面详细说明下其他需要注意的地方,也附上了大量以前的学习做的笔记,总结的信息是自己写的,可能有疏忽的地方,注意下!
有了/verbose选项得到详细的链接时使用的符号和符号所在库的信息。发现了三种特殊的编译器自动在生成对应功能时使用的符号,也就是说,这三种功能,在这样编译时候是不能使用的。
VC8 (or VS2005)及其以后的编译器,会自动在生成对应功能时使用的符号,也就是说,这三种功能,在强行使用旧版本的VC支持库时候是不能正常工作的。
当然,对我们而言就是不能使用下面三种功能。主要是msvcrt.lib和MFC的nafxcw.lib中的区别。
1. debug版本的话,通常会碰到__RTC_CheckEsp符号的问题,它可以通过去掉掉 Basic Runtime Check 基本运行时检查(/RTC)来禁用掉,以及关闭掉堆栈安全cookie检查 Buffer Security Checks (/GS-),这个选项是编译的选项,影响的直接是c++生成的代码中不使用这些功能,于是编译器不会添加对这些固定名称的函数的调用了。
2. __try/__except/ __leave的VC编译器支持的windows下特有的SEH方式异常处理方式。当使用它时,至少vs2010的编译器会默认添加对符号 __SEH_epilog和__SEH_prolog的使用,这是为过度到x64的PE程序而设计的功能(实现异常时回滚函数的执行的功能)。
3. try/ catch/ finally的c++异常处理方式,VS2010会自动使用__CxxFrameHandler3作为一个总的异常分发起点,在里面把try/ catch/ finally中的代码当做回调函数的形式来调用。但__CxxFrameHandler3只存在于VS2010对应版本的支持库中,之前的版本中也是不存在的。


当生成release (或debug) 版本的项目时,在 Visual c + +会默认链接的是从LIBC [D].lib、 LIBCMT [D].lib 和 MSVCRT[D].LIB)中选择的一个基本的 C 运行时库,具体链接的一个取决于您选择编译器选项 (单线程 <ML[d]>、 多线程的 <MT[d]> 或多线程的 DLL <MD[d]>, 最后d代表dll版本,没有d则会被视为静态链接)。此外可能会从std c++ lib或一个从旧的 iostream 库链接, 取决于在代码中使用头文件。
这儿有一个误区,大部分人会以为vc链接时使用的是它的运行时库msvcrt.lib,但msvcrt.lib中实际只是保持了msvcrt.dll的导出表的信息。而使用一个特别的库,用这个特别库再把msvcrt.lib链接进来,是有实际意义的。为的是解决c/ c++运行时的初始化的问题,vc通过协定一些特殊的符号,让c/c++版本的编译器能利用这些特殊符号名称和连接器使用的库文件(如libcmt)互相配合起来,实现c/ c++中的各种(功能和)初始化。

需要ANSI字符和字符串的GUI应用程序       WinMainCRTStartup
需要Unicode字符和字符串的GUI应用程序      wWinMainCRTStartup
需要ANSI字符和字符串的CUI应用程序       mainmainCRTStartup
需要Unicode字符和字符串的CUI应用程序      wmainwmainCRTStartup
C运行时库所连接的lib和编译时的设置对应关系(without iostream or standard C++ library):
C run-time library  Characteristics        Option  预处理产生的宏
LIBC.LIB  Single-threaded, static link      /ML 
LIBCMT.LIB  Multithreaded, static link      /MT  _MT
MSVCRT.LIB  Multithreaded, dynamic link (MSVCR71.DLL).     /MD  _MT, _DLL
   注意,如果你使用了标准c++的库,你的程序就需要MSVCP71才能运行了。 
LIBCD.LIB  Single-threaded, static link (debug)     /MLd  _DEBUG
LIBCMTD.LIB  Multithreaded, static link (debug)     /MTd  _DEBUG, _MT
MSVCRTD.LIB  Multithreaded, dynamic link (MSVCR71D.DLL) (debug)   /MDd  _DEBUG


当生成release (或debug) 版本的项目时,在 Visual c + +会默认链接的是从LIBC [D].lib、 LIBCMT [D].lib 和 MSVCRT[D].LIB)中选择的一个基本的 C 运行时库,具体链接的一个取决于您选择编译器选项 (单线程 <ML[d]>、 多线程的 <MT[d]> 或多线程的 DLL <MD[d]>, 最后d代表dll版本,没有d则会被视为静态链接)。此外可能会从std c++ lib或一个从旧的 iostream 库链接, 取决于在代码中使用头文件。
C run-time library  Characteristics          Option  预处理产生的宏
LIBC.LIB  Single-threaded, static link      /ML 
LIBCMT.LIB  Multithreaded, static link      /MT  _MT
MSVCRT.LIB  Multithreaded, dynamic link (MSVCR71.DLL).     /MD  _MT, _DLL
   注意,如果你使用了标准c++的库,你的程序就需要MSVCP71才能运行了。 
LIBCD.LIB  Single-threaded, static link (debug)     /MLd  _DEBUG
LIBCMTD.LIB  Multithreaded, static link (debug)     /MTd  _DEBUG, _MT
MSVCRTD.LIB  Multithreaded, dynamic link (MSVCR71D.DLL) (debug)   /MDd  _DEBUG

c++运行时库所链接的lib和编译时的设置对应关系:
Standard C++ Library Characteristics     Option  预处理产生的宏
LIBCP.LIB  Single-threaded, static link   /ML 
LIBCPMT.LIB  Multithreaded, static link   /MT  _MT
MSVCPRT.LIB  Multithreaded, dynamic link (MSVCP71.dll) /MD  _MT, _DLL
LIBCPD.LIB  Single-threaded, static link   /MLd  _DEBUG
LIBCPMTD.LIB  Multithreaded, static link   /MTd  _DEBUG, _MT
MSVCPRTD.LIB  Multithreaded, dynamic link (MSVCP71D.DLL) /MDd  _DEBUG, _MT,


这儿有一个误区,大部分人会以为vc链接时使用的是它的运行时库msvcrt.lib,但msvcrt.lib中实际只是保存了和当前VC的版本所对应的msvcrt.dll(或者msvcr100.dll)的导出表的信息,因而链接msvcrt.lib会自动选择对应的DLL。而使用一个特别的库,用这个特别库再把msvcrt.lib链接进来,是有实际意义的。为的是解决c/c++运行时的初始化的问题,vc通过协定一些特殊的符号,让c/c++版本的编译器能利用这些特殊符号名称和连接器使用的库文件(如libcmt)互相配合起来,实现c/ c++中的各种(功能和)初始化。这些编译器使用的特殊符号其含义其应用范围如下,
vc的lib常见的subsystem下使用的实际PE入口点分别是:
需要ANSI字符和字符串的GUI应用程序       WinMainCRTStartup
需要Unicode字符和字符串的GUI应用程序      wWinMainCRTStartup
需要ANSI字符和字符串的CUI应用程序       mainmainCRTStartup
需要Unicode字符和字符串的CUI应用程序      wmainwmainCRTStartup


下面的是静态链接MFC时使用的库文件,
库文件  对应的字符集版本 debug版本或者release版本的库
NAFXCW.LIB  ASCII   release
UAFXCW.LIB UNICODE   release
NAFXCWD.LIB ASCII   debug
UAFXCWD.LIB UNICODE   debug

下面的是动态链接MFC时使用的库文件,
库文件    对应的字符集版本 debug版本或者release版本的库
mfc42.lib+ mfcs42.lib    ASCII   release
MFC42D.LIB+ MFCS42D.LIB  ASCII   debug
mfc42u.lib+ mfcs42u.lib  UNICODE   release
MFC42UD.LIB+ MFCS42UD.LIB UNICODE   debug
另有几个lib,储存的是MFC中一些不常用功能的lib,命名格式是一样的,结尾的D表示debug版本。U则是UNICODE版本

 

好看点的那个表

 

 
 
回帖:发一下续集,解决c++的异常问题:


上面提到了c++的异常不能用了。
但我没发愁,因为我是有自己的解决办法的,我在以前做过的开发中实现了一个自己的win32下管理异常的类。如果没有现有的可用的话,就挺麻烦了。
这儿提一下实现方法,我是用xp后添加的VEH这种异常hanlder来处理的,也可以用SetUnhandledExceptionFilter这种很标准的方式来过滤异常。实现针对每个函数里面的异常的分发有一些麻烦,这个我是通过一个简单的宏,把处理当前函数的异常handler地址压到处理异常那个类里去。结尾类似于__except那样的也多一个宏,是用来退出函数时调用那个类的函数弹出当前函数的处理异常的代码。
具体比较有技巧,因为是专门给VC和mingw32开发的,所以利用了他们都是用一个固定的寄存器ebp保存操作局部变量和函数参数的特点,不用考虑堆栈问题,在宏里面包的处理异常代码是用c的标号表示出来的,把它作为参数传给的异常处理类。而那个自己的except的宏,其实是用来定义这个特殊标号的,在这个宏的结尾会返回到自己的异常处理类里面去,然后恢复线程环境什么的。这样功能很简单,只实现了在函数的异常处理中操作函数的局部变量的功能。具体代码是用的汇编硬编码,还有__declspec(naked)这样的让函数代码完全不包含编译器添加的代码的VC独有功能,具体的异常handler设置,也利用的是win32处理异常的结构来做的,但这是无可厚非的,毕竟自己写一个可以在源码级别编译进去的win64下的异常处理是非常非常不现实的(这个大家可以搜索一下相关的改动试试就明白 :)

但是我们是用c++的,c++是自带异常处理过程的,能支持c++原生异常处理的话就好了!
那测试下msvcrt.dll的cxxframehandler能不能欺骗了运行时库



class AppClass:CWinApp
{
        //... blabla_0

        FARPROC m_RealCxxFrameHandler;
        //..blabla_1
}


AppClass theAppClass;

BOOL AppClass::InitInstance ()
{
        HMODULE Msvcrt_HModu;
        if (NULL!=(Msvcrt_HModu= LoadLibraryA (&quot;msvcr100.dll&quot;)))
        {
                m_RealCxxFrameHandler= GetProcAddress ( Msvcrt_HModu, &quot;__CxxFrameHandler3&quot;);
        }
        else if (NULL!=(Msvcrt_HModu= LoadLibraryA (&quot;msvcrt.dll&quot;)))
        {
                m_RealCxxFrameHandler= GetProcAddress ( Msvcrt_HModu, &quot;__CxxFrameHandler&quot;);
        }
        else
        {
                AfxMessageBox ( &quot;现实是残酷的,我们还是表运行了。&quot;);
                return FALSE;
        }

        try
        {
                throw 100;
        }
        catch (...)
        {
                AfxMessageBox ( &quot;生活会越来越好。&quot;);
        }

        return TRUE;
}


void __stdcall ModifyFuncInfo_Version (DWORD * Addr_dw)
{
        DWORD OldProtect= PAGE_EXECUTE_READWRITE;
        DWORD VersionValue_Dw= *Addr_dw;
        VirtualProtect ( Addr_dw, 4, OldProtect, &OldProtect);


        if (0x19930520!=(VersionValue_Dw& 0x1FFFFFFF))
        {
                *Addr_dw= 0x19930520;
        }

        VirtualProtect ( Addr_dw, 4, OldProtect, &OldProtect);
}
extern  &quot;C&quot; __declspec(naked) void __cdecl __CxxFrameHandler3 (void)
{
        __asm push eax
        __asm push eax
        __asm call ModifyFuncInfo_Version
        __asm pop eax
        __asm JMP theApp.m_RealCxxFrameHandler
}



ModifyFuncInfo_Version 和__CxxFrameHandler3的实现只是为了让程序在win32下正常运行,里面是用了大量的win32特定的微软自己的编译器才可以用的特性,但我们的目的不就是这样吗 :)
它们二个所在的那个文件必须关闭c/c++ ->优化->全程序优化(/GL)才可以,所以最好单独放一个文件里面。

ModifyFuncInfo_Version完成的功能是修改一下只有vista之前的msvcrt才判断的一个版本位,后来的里面直接放弃这个位置里的值了,也许是为了兼容性。因为其保存在PE文件里的段里面,所以改之前要修改下内存片的访问权限,确定这个PE段可写再改。

至此包括c++异常的使用在内,一切正常。
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值