我们有一个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)?
答案 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();