我可以将 Visual Studio 2010 的 C++ 编译器与 Visual Studio 2008 的 C++ 运行时库一起使用吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2484511/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can I use Visual Studio 2010's C++ compiler with Visual Studio 2008's C++ Runtime Library?
提问by Billy ONeal
I have an application that needs to operate on Windows 2000. I'd also like to use Visual Studio 2010 (mainly because of the change in the definition of the auto
keyword). However, I'm in a bit of a bind because I need the app to be able to operate on older OS's, namely:
我有一个应用程序需要在Windows 2000 上运行。我也想使用Visual Studio 2010(主要是因为auto
关键字定义的变化)。但是,我有点困惑,因为我需要该应用程序能够在较旧的操作系统上运行,即:
- Windows 2000
- Windows XP RTM
- Windows XP SP1
- 视窗 2000
- Windows XP RTM
- 视窗 XP SP1
Visual Studio 2010's runtime library depends on the EncodePointer / DecodePointer
API which was introduced in Windows XP SP2.
Visual Studio 2010 的运行时库依赖EncodePointer / DecodePointer
于 Windows XP SP2 中引入的API。
If using the alternate runtime library is possible, will this break code that relies on C++0x features added in VS2010, like std::regex
?
如果可以使用备用运行时库,这个依赖于 VS2010 中添加的 C++0x 功能的代码是否会中断,例如std::regex
?
采纳答案by snemarch
Suma's solutionlooked pretty promising, but it doesn't work: the __imp__*@4
symbols need to be pointersto functions, rather than the functions themselves. Unfortunately, I don't know how to make Visual C++ spit out a pointer with that kind of name generation... (well, __declspec(naked)
combined with __stdcall
does the trick, but then I don't know how to emit a pointer).
Suma 的解决方案看起来很有前途,但它不起作用:__imp__*@4
符号需要是指向函数的指针,而不是函数本身。不幸的是,我不知道如何让 Visual C++ 吐出一个带有这种名称生成的指针......(好吧,__declspec(naked)
结合使用__stdcall
技巧,但我不知道如何发出指针)。
If using an assembler at build-time is OK, the solution is pretty trivial - assemble the following code with FASMand link against the produced object file, and presto - no EncodePointer/DecodePointer references in the exe:
如果在构建时使用汇编器没问题,那么解决方案非常简单 - 使用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
回答by AshleysBrain
The very simplest solution is just to set the Platform Toolset in project settings in VS2010 to v900, which will use the Visual Studio 2008 libraries and compiler. This also means you lose C++0x features like auto
, but to be honest, working around that with some typedef
s is probably easier than building your own version of the CRT or other more complicated solutions. Alternatively, just use VS2008! I don't know if there are other C++0x features that are critical to your application though, you didn't mention - other than std::regex
, which I think is still in the v900 toolset under the technical report 1 namespace (std::tr1::regex
).
最简单的解决方案就是将VS2010中项目设置中的Platform Toolset设置为v900,这将使用Visual Studio 2008库和编译器。这也意味着你失去了 C++0x 特性,比如auto
,但老实说,用一些typedef
s解决这个问题可能比构建你自己的 CRT 版本或其他更复杂的解决方案更容易。或者,只需使用 VS2008!我不知道是否还有其他对您的应用程序至关重要的 C++0x 功能,您没有提到 - 除了std::regex
,我认为它仍然在技术报告 1 命名空间 ( std::tr1::regex
)下的 v900 工具集中。
Just from the impression I get, I would predict the inconvenience of getting the VS2010 libraries to run on XP SP1 is greater than the convenience of C++0x features, so overall it wouldn't be worth it.
仅从我得到的印象来看,我可以预测让 VS2010 库在 XP SP1 上运行的不便性大于 C++0x 功能的便利性,因此总体而言不值得。
回答by Suma
You cannot use 2008 CRT, but you can prevent the new functions DecodePointer/EncodePointer to be linked from the kernel. It is quite easy to replace the new functions with stubs.
您不能使用 2008 CRT,但您可以阻止从内核链接新函数 DecodePointer/EncodePointer。用存根替换新函数非常容易。
One might attempt following: Place code like this in your main.cpp source:
可以尝试以下操作:将这样的代码放在 main.cpp 源中:
extern "C" {
void *__stdcall _imp__DecodePointer(void *x) {return x;}
void *__stdcall _imp__EncodePointer(void *x) {return x;}
};
extern "C" {
void *__stdcall _imp__DecodePointer(void *x) {return x;}
void *__stdcall _imp__EncodePointer(void *x) {return x;}
};
The above does not work. While the basic idea is sound, the execution needs to be a little bit different. As described by snemarch in comment and another answer, __imp__
cannot be the function call, only the pointer to it. As it seems not possible to generate the pointer directly by the compiler, you need to assemble the following code with MASM and link against the produced object file.
以上是行不通的。虽然基本想法是合理的,但执行需要有点不同。正如 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
The symbols from a project have preference against any symbols from libraries. DLL libraries are linked using .lib parts, which contain only __imp__
"vectors" jumping into the real functions. By replacing __imp__
"vectors" you do not touch the DLL linking, you replace the .lib part. I have verified there is no more any dependency of the exe on DecodePointer / EncodePointer.
项目中的符号优先于库中的任何符号。DLL 库使用 .lib 部分链接,其中仅包含__imp__
跳转到实际函数的“向量”。通过替换__imp__
“向量”,您不会触及 DLL 链接,而是替换了 .lib 部分。我已经确认 exe 不再依赖 DecodePointer/EncodePointer。
Background
背景
Statically linked library brings only used functionality into the application. It is possible to find which particular CRT function bring in those new API using linker verbose progress output:
静态链接库仅将使用过的功能带入应用程序。可以使用链接器详细进度输出找到哪些特定的 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 ...
This shows the new APIs are used in some of the CRT to provide more security for some functions which are deemed to provide frequent attack vectors.
这表明在某些 CRT 中使用了新的 API,以便为某些被认为提供频繁攻击向量的功能提供更高的安全性。
With some effort it would be possible to use LoadLibrary / GetProcAddress to provide the real functionality where OS offers is, but I do not think it would really bring anything. The runtime functions which use DecodePointer / EncodePointer do not really need it to provide any encoding, all they need is the encoding to by symmetric. You do not really need the enhanced security (VS 2008 runtime would not give it to you either).
通过一些努力,可以使用 LoadLibrary / GetProcAddress 来提供操作系统提供的真正功能,但我认为它不会真正带来任何东西。使用 DecodePointer / EncodePointer 的运行时函数并不真正需要它提供任何编码,它们所需要的只是对称编码。您并不真正需要增强的安全性(VS 2008 运行时也不会给您)。
I hope there are no other obstacles waiting for you - I do not have an access to Win2k or XP pre SP2 system, therefore I am unable to try. If there are any exe header flags preventing even attempting to launch the exe on such systems, they should be easy to change.
我希望没有其他障碍等着你——我无法访问 Win2k 或 XP pre SP2 系统,因此我无法尝试。如果有任何 exe 标头标志甚至阻止尝试在此类系统上启动 exe,则它们应该很容易更改。
回答by Tomasz Grobelny
As Visual Studio comes with support for MASM (see project properties -> Build Customizations...) the following translation of snemarch's code to MASM might be useful:
由于 Visual Studio 支持 MASM(请参阅项目属性 -> 构建自定义...),以下将 semarch 的代码转换为 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
And remember to set Linker->System->Minimum Required Version to 5.0 (default is 5.1) to run on Windows 2000.
并记住将 Linker->System->Minimum Required Version 设置为 5.0(默认为 5.1)以在 Windows 2000 上运行。
回答by Head Geek
The usual work-around for this problem is to build your own custom version of the CRT. There are instructions for it here. You'll just need to edit the code to ignore EncodePointer
and DecodePointer
. (There should already be a #define
for that.)
解决此问题的常用方法是构建您自己的 CRT 自定义版本。有关于它的说明here。您只需要编辑代码以忽略EncodePointer
和DecodePointer
。(应该已经有一个#define
。)
There are two other minor things you'll need to do:
您还需要做另外两件小事:
- Go to the Linker->Additional Library Directories setting and set
C:\Microsoft Visual Studio 9.0\VC\lib
as the first path to search. (I'm assuming you used the default install directory, otherwise change as appropriate.) - Change the subsystem version, in the PE header, to 5.00 (use the free CFF Explorer Suiteif you don't have another tool handy for it).
- 转到 Linker->Additional Library Directory 设置并设置
C:\Microsoft Visual Studio 9.0\VC\lib
为第一个搜索路径。(我假设您使用了默认安装目录,否则根据需要进行更改。) - 将 PE 标头中的子系统版本更改为 5.00(如果您手边没有其他工具,请使用免费的CFF Explorer Suite)。
That should allow your program to run on Windows 2000 as well as later versions.
这应该允许您的程序在 Windows 2000 以及更高版本上运行。
回答by Steve314
Option 1 - create a modified version of the 2010 runtime that redirects the problem API calls to a DLL that you supply. I don't know how easy or hard this would be - hopefully just a minor tweak to the symbol table, but it depends on the file format - and you're very likely to run into the reverse engineering clause of the license, of course.
选项 1 - 创建 2010 运行时的修改版本,将问题 API 调用重定向到您提供的 DLL。我不知道这有多容易或多难 - 希望只是对符号表的一个小调整,但这取决于文件格式 - 当然,你很可能会遇到许可证的逆向工程条款.
Option 2 - Compare the exported symbols in two different versions of the runtime libs. If the symbols are the same, you have good odds of compatibility - though no guarantees. Its even possible that the lib file formats are different.
选项 2 - 比较两个不同版本的运行时库中的导出符号。如果符号相同,则您有很好的兼容性 - 尽管不能保证。lib文件格式甚至可能不同。
Option 3 - Check whether you can get access to runtime sources through the MSDN or similar, specifically in order to create a patched version.
选项 3 - 检查您是否可以通过 MSDN 或类似方式访问运行时源,特别是为了创建修补版本。
Option 4 - Check whether you can use the 2010 compiler, but an older linker, perhaps configured in your solutions as a custom build step. Again, this depends on whether the obj and lib files are the same file format - but you may be able to write a small utility to patch simple differences like version numbers in a header. The older linker should have no problem linking in the older runtime - assuming the objs from the new compiler are compatible with it.
选项 4 - 检查您是否可以使用 2010 编译器,但使用较旧的链接器,可能在您的解决方案中配置为自定义构建步骤。同样,这取决于 obj 和 lib 文件是否具有相同的文件格式 - 但您可以编写一个小实用程序来修补简单的差异,例如标题中的版本号。旧的链接器在旧的运行时链接应该没有问题 - 假设来自新编译器的 objs 与其兼容。
Option 5 - build DLLs in 2010 that don't need their own runtime, but which are loaded and hosted by an application built using the older compiler. Achieving the "no runtime" requirement for your DLLs may mean a lot of your libraries must be built in the hosting application, of course, and you may need to provide your own interfaces (via the host application) to library functions you need to work with - especially memory allocation stuff.
选项 5 - 在 2010 年构建 DLL,它们不需要自己的运行时,但由使用旧编译器构建的应用程序加载和托管。为您的 DLL 实现“无运行时”要求可能意味着您的许多库必须在宿主应用程序中构建,当然,您可能需要为您需要工作的库函数提供自己的接口(通过宿主应用程序)与 - 特别是内存分配的东西。
Options worth checking, but I'm sure you already thought of them all - sorry I have no idea whether any of them will work - or whether they'll almost work but cause intermittent problems.
值得检查的选项,但我相信您已经考虑到了所有选项 - 抱歉,我不知道它们中的任何一个是否可以工作 - 或者它们是否几乎可以工作但会导致间歇性问题。
回答by Ben Voigt
This would be a lot easier if you're allowed to use a DLL. Basically, write an EXE that requires no C runtime functions at all, by using the linker /ENTRYPOINT function. Once you've tested that your basic prerequisites are met, and reported any problems to the user via only Windows-provided APIs available on all target OSes (i.e. MessageBox), then call LoadLibrary to kick off the DLL that contains the bulk of your logic. That DLL can use the VS2010 runtime as usual. You can even avoid deploying two separate files by decompressing the DLL from a resource contained within your main .EXE at startup. (You can do this entirely within memory without writing the .DLL to disk, but not if you want to take advantage of the Windows PE loader to fixup all your imports).
如果允许您使用 DLL,这会容易得多。基本上,通过使用链接器 /ENTRYPOINT 函数编写一个完全不需要 C 运行时函数的 EXE。一旦您测试了您的基本先决条件得到满足,并仅通过所有目标操作系统(即 MessageBox)上可用的 Windows 提供的 API 向用户报告任何问题,然后调用 LoadLibrary 以启动包含大部分逻辑的 DLL . 该 DLL 可以像往常一样使用 VS2010 运行时。您甚至可以通过在启动时从主 .EXE 中包含的资源解压缩 DLL 来避免部署两个单独的文件。(您可以完全在内存中执行此操作,而无需将 .DLL 写入磁盘,但如果您想利用 Windows PE 加载程序来修复所有导入,则不能这样做)。
回答by Gideon7
Create a .LIB that implements the missing functionality and link it ahead of KERNEL32.LIB.
创建一个实现缺失功能的 .LIB 并将其链接到 KERNEL32.LIB 之前。
You will need to use the linker option /NODEFAULTLIB:kernel32.lib so that you can put your w2kcompat.lib ahead of kernel32.lib.
您将需要使用链接器选项 /NODEFAULTLIB:kernel32.lib 以便您可以将 w2kcompat.lib 放在 kernel32.lib 之前。