c#visual studio build exe with target anycpu但是在调用进程平台(x86 / x64)上确定了它的平台(x86 / x64)

时间:2017-01-26 11:07:51

标签: c# visual-studio-2015 x86 target-platform anycpu

我们有一个32位和64位的软件调用我们的exe并将事件传递给它(如插件)。

问题是我们的exe必须以与调用软件相同的位(x86 / x64)执行(如果软件以32位版本运行,我们的exe必须以32位运行,如果软件以64位运行版本我们的exe必须以64位运行)。 Windows版本为64位,但客户端可以运行32位版本或64位版本的软件。

在visual studio(2015)中,Target AnyCPU选项仅取决于Windows版本(+ Prefer 32位复选框),但我们需要依赖于调用软件Process。

我们是否可以实施任何选项或解决方案而不是编译到每个平台(x86和x64)?

2 个答案:

答案 0 :(得分:4)

没有Windows操作系统要求两个独立的进程需要相同的位才能相互通信 - 所以我假设你有一些内部要求两个进程都是相同的位。如果绝对必须在32位或64位中动态运行相同的EXE并在运行时做出决定,则可以使用Visual Studio附带的corflags.exe实用程序在运行时修改AnyCPU编译的应用程序。 / p>

您可以像这样启动corflags.exe(使用System.Diagnostic.Process):

corflags.exe "ourapp.exe" /32BIT+

强制它运行32位,

corflags.exe "ourapp.exe" /32BIT-

返回AnyCPU(在64位操作系统上为64位)

解决方案是您将在运行时环境中部署corflags.exe的副本。然后,您的主机应用程序可以通过检查sizeof(IntPtr)来检测它的当前位数,以查看它是8还是4;并在启动ourapp.exe之前相应地生成corflags.exe的副本(使用System.Diagnostics.Process)。

这非常 HACKY 。小心。如果您需要在同一台计算机上同时运行两个ourapp.exe副本,显然会遇到很多麻烦。在修改ourapp.exe并将其从那里启动以避免来自多个实例和UAC提示的竞争条件(取决于您的目标环境)之前,最好将ourapp.exe的唯一副本创建到本地用户文件夹。

答案 1 :(得分:0)

绝对要求流程必须在任务管理器的 Processes 标签中显示为自身?或者它可以包含在另一个主机进程中吗?

如果是后者,您可以创建一个包含以下Main方法的存根项目,然后编译两个版本的可执行文件:一个作为32位( LaunchX86.exe )和其他64位( LaunchX64.exe )。

static int Main(string[] args)
{
    try
    {
        foreach (var t in Assembly.LoadFile(args[0]).GetTypes())
        {
            var methodInfo = t.GetMethod(
                "Main",
                BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);

            if (methodInfo != null)
            {
                int? retVal = 0;

                // See http://stackoverflow.com/questions/2378016/how-to-run-something-in-the-sta-thread#2378077
                var thread = new Thread(() =>
                {
                    try
                    {
                        // Main() methods may have zero or one parameters
                        var methodParams = methodInfo.GetParameters().Length == 0
                            ? null
                            : new object[] {args.Skip(1).ToArray()};

                        retVal = methodInfo.Invoke(t, methodParams) as int?;
                    }
                    catch (Exception e)
                    {
                        retVal = 99; // Error 99: The executable itself threw an exception
                    }
                });

                thread.SetApartmentState(ApartmentState.STA);
                thread.Start();
                thread.Join();

                return retVal ?? 0;
            }
        }

        return 98; // Error 98: unable to launch exe because no method "Main" found
    }
    catch (Exception e)
    {
        // Can identify exception type here and return appropriate result, e.g.:
        // ArgumentNullException - no EXE name provided in first param
        // BadImageFormatException - specified file was not a suitable EXE

        return 97; // Error 97: unable to load executable for analysis
    }
}

注意:为了简单起见,上面有非常粗略的异常捕获并将这些异常映射到一些固定的返回值。

另请注意,在Invoke()方法中,我们没有将任何参数传递给WPF应用程序的Main()方法,因为WPF应用程序会自动接收与启动程序相同的参数。这并不理想,但可以采用各种解决方法,例如在启动之前使用Environment.SetEnvironmentVariable()设置环境变量,使用Environment.GetEnvironmentVariable()检查目标应用程序中的变量,并使用其内容代替(如果存在)代替正常的方法。

然后,从主应用程序中启动相关的主机可执行文件,具体取决于您当前的进程的位数:

new Process
{
    StartInfo = new ProcessStartInfo(
        Environment.Is64BitProcess ? "LaunchX64.exe" : "LaunchX86.exe",
        "application_to_be_hosted.exe param1 param2 etc."
    )
}.Start();