58

在 .NET 中,“平台目标:任何 CPU”编译器选项允许 .NET 程序集在 x64 机器上以 64 位运行,在 x86 机器上以 32 位运行。也可以使用“平台目标:x86”编译器选项强制程序集在 x64 机器上作为 x86 运行。

是否可以运行带有“任何 CPU”标志的程序集,但确定它应该在 x86 还是 x64 CLR 中运行?通常这个决定是由 CLR/OS 加载器(据我了解)根据底层系统的位数做出的。

我正在尝试编写一个 C# .NET 应用程序,它可以与其他正在运行的进程进行交互(读取:将代码注入)。x64 进程只能注入到其他 x64 进程中,x86 也是如此。理想情况下,我想利用 JIT 编译和Any CPU选项来允许使用单个应用程序注入 x64 或 x86 进程(在 x64 机器上)。

这个想法是应用程序将被编译为Any CPU。在 x64 机器上,它将作为 x64 运行。如果目标进程是 x86,它应该重新启动自身,强制 CLR 将其作为 x86 运行。这可能吗?

4

4 回答 4

61

您可以使用CorFlags应用程序了解应用程序的运行方式和静态更改方式。要了解应用程序将如何运行,请使用:

corflags <PathToExe>

要更改应用程序的运行方式,请使用:

corflags /32bit+  <PathToExe>

这将使 EXE 文件作为 32 位进程运行。有关程序集应如何运行的信息存储在 PE 标头中。请参阅堆栈溢出问题如何查找本机 DLL 文件是编译为 x64 还是 x86?.

如果要在运行时注入代码,则必须在C++ /COM中编写.NET分析器。有关更多详细信息,请参阅.NET 内部:Profiling APIProfiling(非托管 API 参考)

您需要实现 JitCompilationStarted 回调并在那里完成您的工作。如果朝这个方向发展,则必须将注入 DLL 文件构建为 x86 和 x64。一旦设置了以下环境变量, CLR将加载本机 DLL 文件:

Cor_Enable_Profiling=0x1
COR_PROFILER={CLSID-of-your-native-DLL-file}

如果设置正确,那么 64 位版本将“看到”64 位进程,而 32 位版本将“看到”32 位进程。

于 2009-10-02T12:52:01.657 回答
9

自从我尝试这个已经有一段时间了,但我相信调用程序集的进程的位数决定了它将被 JITed 为 x86 还是 x64。

因此,如果您编写一个小型控制台应用程序并将其构建为 x86,另一个构建为 x64,运行其中一个或另一个将导致加载到进程中的其他程序集以 32 位或 64 位运行。当然,这假设您在 64 位机器上运行。

于 2009-10-02T01:21:27.760 回答
6

我不确定我是否能帮你解决这个问题。但这是我的经验。

我有一个主机应用程序A.exe(编译为 x86),我有一个来自主机应用程序的客户端应用程序B.exe(编译为ANY CPU)。我使用System.Diagnostic.ProcessB.exe从启动。A.exe

现在的问题是,如果我将两者放在 x64 机器上,那么A.exe将作为 x86 运行,B.exe将作为 x64 运行

但是如果A.exe调用程序集 c ( c.dll,编译为Any CPU),并且B.exe还调用c.dll,则 c.dll 将跟随调用它的应用程序。换句话说,在 64 位机器中A.exe调用它时,它的行为类似于x86dll,而B.exe调用它时,它的行为类似于x64.

于 2009-10-02T03:30:14.263 回答
6

我通过创建两个(实际上是三个)二进制文件做了类似的事情。我有一个检测我试图注入的进程是 32 位还是 64 位。然后,此过程将启动 32 位或 64 位版本的注入二进制文件(而不是像您提到的那样重新启动自身)。

这听起来很混乱,但您可以在构建时通过构建后事件轻松实现这一点,该事件会复制输出二进制文件并使用CorFlags实用程序强制副本以 32 位运行。这样您就不必在您的应用程序中部署 CorFlags 实用程序,因为某种原因这可能是不合法的。

我认为这与您最初的想法非常相似,并且除了两行构建事件之外真的不需要更多工作。

于 2010-03-15T20:06:13.043 回答