我可以在Visual Studio 2008的C ++运行时库中使用Visual Studio 2010的C ++编译器吗?
我有一个需要在Windows 2000上运行的应用程序。我还想使用Visual Studio 2010(主要是因为auto
关键字定义的更改)。 不过,我有点困惑,因为我需要应用程序能够在较旧的操作系统上运行,即:
- Windows 2000
- Windows XP RTM
- Windows XP SP1
Visual Studio 2010的运行时库取决于Windows XP SP2中引入的EncodePointer / DecodePointer
API。
如果使用备用运行时库是可能的,这将打破依赖于VS2010添加的C ++ 0xfunction的代码,如std::regex
?
Suma的解决scheme看起来很有希望,但是它不起作用: __imp__*@4
符号需要指向函数,而不是函数本身。 不幸的是,我不知道如何使Visual C ++吐出一个这样的名称生成的指针…(好吧, __declspec(naked)
结合__stdcall
做的伎俩,但后来我不知道如何发出指针)。
如果在构build时使用汇编程序是可行的,那么解决scheme非常简单 – 使用FASM汇编以下代码并链接到生成的目标文件,并在exe中不引用EncodePointer / DecodePointer:
use32 format ms coff section ".data" data public __imp__DecodePointer@4 __imp__DecodePointer@4 dd dummy public __imp__EncodePointer@4 __imp__EncodePointer@4 dd dummy section ".text" code dummy: mov eax, [esp+4] retn 4
最简单的解决scheme是将VS2010中的工程设置中的平台工具集设置为v900,后者将使用Visual Studio 2008库和编译器。 这也意味着你失去了像C ++ 0x这样的auto
function,但说实话,用一些typedef
解决这个问题可能比构build自己的CRT或其他更复杂的解决scheme更容易。 另外,只需使用VS2008! 我不知道是否还有其他C ++ 0xfunction对您的应用程序至关重要,但是您没有提到 – 除了std::regex
,我认为它仍然在技术报告1命名空间下的v900工具集中( std::tr1::regex
)。
从我得到的印象中,我可以预测,获得VS2010库在XP SP1上运行的不便之处大于C ++ 0xfunction的便利,所以总体来说这不值得。
你不能使用2008 CRT,但你可以防止DecodePointer / EncodePointer的新function从内核链接。 用桩子replace新的function是相当容易的。
有人可能会尝试以下方法: 在main.cpp源代码中放置这样的代码:
extern "C" { void *__stdcall _imp__DecodePointer(void *x) {return x;} void *__stdcall _imp__EncodePointer(void *x) {return x;} };
以上不起作用。 虽然基本的想法是正确的,但执行需要有点不同。 如snemarch在注释和另一个答案中所述 , __imp__
不能是函数调用,只能是指向它的指针。 由于似乎不可能直接由编译器生成指针,因此需要使用MASM汇编以下代码并链接到生成的目标文件。
.model flat .data __imp__EncodePointer@4 dd dummy __imp__DecodePointer@4 dd dummy EXTERNDEF __imp__EncodePointer@4 : DWORD EXTERNDEF __imp__DecodePointer@4 : DWORD .code dummy proc mov eax, [esp+4] ret 4 dummy endp end
来自项目的符号优先考虑来自库的任何符号。 DLL库链接使用.lib部分,其中只包含__imp__
“向量”跳转到真正的function。 通过replace__imp__
“向量”,您不会触及DLL链接,您replace.lib部分。 我已经validation了解码指针/ EncodePointer没有更多的任何依赖。
背景
静态链接的库只将使用的function带入应用程序。 使用链接器详细的进度输出可以find哪些特定的CRT函数引入这些新的API:
Found __imp__EncodePointer@4 Referenced in LIBCMT.lib(crtmboxw.obj) Referenced in LIBCMT.lib(invarg.obj) Referenced in LIBCMT.lib(handler.obj) Referenced in LIBCMT.lib(onexit.obj) Referenced in LIBCMT.lib(cmiscdat.obj) Referenced in LIBCMT.lib(tidtable.obj) Referenced in LIBCMT.lib(hooks.obj) Referenced in LIBCMT.lib(winsig.obj) Referenced in LIBCMT.lib(rand_s.obj) Found __imp__DecodePointer@4 // ... same list, only order differs ...
这表明在一些CRT中使用新的API来为被认为提供频繁攻击媒介的一些function提供更多的安全性。
通过一些努力,可以使用LoadLibrary / GetProcAddress来提供操作系统提供的真实function,但是我不认为它会带来任何东西。 使用DecodePointer / EncodePointer的运行时函数并不需要它提供任何编码,他们所需要的只是通过对称编码。 你并不需要增强的安全性(VS 2008运行时也不会给你)。
我希望没有其他障碍等着你 – 我没有访问Win2k或XP SP2以前的系统,因此我无法尝试。 如果有任何exe头文件标志阻止了甚至试图在这样的系统上启动exe,它们应该很容易改变。
由于Visual Studio支持MASM(请参阅项目属性 – > Build Customizations …),以下将snemarch代码转换为MASM可能是有用的:
.model flat .data __imp__EncodePointer@4 dd dummy __imp__DecodePointer@4 dd dummy EXTERNDEF __imp__EncodePointer@4 : DWORD EXTERNDEF __imp__DecodePointer@4 : DWORD .code dummy proc mov eax, [esp+4] ret 4 dummy endp end
并记得将连接器 – >系统 – >最低要求版本设置为5.0(默认值为5.1)在Windows 2000上运行。
解决此问题的通常解决方法是构build您自己的CRT定制版本。 这里有说明。 您只需编辑代码即可忽略EncodePointer
和DecodePointer
。 (应该已经有一个#define
的。)
还有两件小事你需要做:
- 转到链接器 – >其他库目录设置并将
C:\Microsoft Visual Studio 9.0\VC\lib
为第一个要search的path。 (我假设你使用了默认安装目录,否则根据需要进行更改。) - 将PE头中的子系统版本更改为5.00(如果没有其他工具,则使用免费的CFF Explorer套件 )。
这应该允许您的程序在Windows 2000以及更高版本上运行。
选项1 – 创build2010运行时的修改版本,将问题API调用redirect到您提供的DLL。 我不知道这会是多么容易或很难 – 希望只是对符号表进行小小的调整,但这取决于文件格式 – 当然,您很可能会遇到许可证的逆向工程条款。
选项2 – 在两个不同版本的运行时库中比较导出的符号。 如果符号相同,则兼容性很好 – 尽pipe没有保证。 甚至有可能lib文件格式不同。
选项3 – 检查是否可以通过MSDN或类似方式访问运行时间源,特别是为了创build补丁版本。
选项4 – 检查您是否可以使用2010编译器,但可以使用较旧的链接器,或许在解决scheme中将其configuration为自定义构build步骤。 同样,这取决于obj和lib文件是否是相同的文件格式 – 但是您可以编写一个小的实用程序来修补简单的区别,如版本号。 旧的链接器应该没有问题链接在旧的运行时 – 假设新编译器的objs是兼容的。
选项5 – 在2010年构buildDLL,不需要自己的运行时,但是由使用旧编译器构build的应用程序加载和托pipe。 实现DLL的“无运行时”要求可能意味着很多库必须在托pipe应用程序中构build,您可能需要将自己的接口(通过主机应用程序)提供给需要工作的库函数与 – 特别是内存分配的东西。
值得检查的选项,但我相信你已经想到了他们所有 – 抱歉,我不知道他们中的任何一个将工作 – 或者他们会几乎工作,但造成间歇性的问题。
如果你被允许使用DLL,这将会容易得多。 基本上,通过使用链接器/ ENTRYPOINT函数编写一个完全不需要C运行时function的EXE。 一旦你testing了你的基本先决条件已经被满足,并且只通过在所有目标操作系统(即MessageBox)上提供的Windows提供的API向用户报告任何问题,然后调用LoadLibrary来启动包含你的逻辑的大部分的DLL 。 该DLL可以像往常一样使用VS2010运行时。 您甚至可以通过在启动时从主.EXE中包含的资源解压DLL来避免部署两个单独的文件。 (您可以在内存中完全执行此操作,而无需将.DLL写入磁盘,但是如果要利用Windows PE加载程序修复所有导入,则不能。
创build一个实现缺lessfunction的.LIB,并将其链接到KERNEL32.LIB之前。
您将需要使用链接器选项/NODEFAULTLIB:kernel32.lib,以便您可以将您的w2kcompat.lib放在kernel32.lib之前。