C# Visual Studio сборка exe с целевым anycpu, но это определяет его платформу (x86/x64) на платформе вызывающего процесса (x86/x64)
У нас есть программное обеспечение в 32 и 64 битах, которое вызывает наш exe-файл и передает ему события (например, плагин).
Дело в том, что наш исполняемый файл должен исполняться с той же разрядностью (x86/x64), что и вызывающее программное обеспечение (если программное обеспечение работает в 32-битной версии, наш исполняемый файл должен работать в 32-битной версии, если программное обеспечение работает в 64-битной версии, наш исполняемый файл). должен работать в 64 битах). Версия для Windows является 64-битной, но клиент может запустить программное обеспечение в 32-битной или 64-битной версии.
В Visual Studio(2015) опция Target AnyCPU зависит только от версии Windows (+ Prefer 32-bit checkbox), но мы должны зависеть от вызывающего программного обеспечения Process.
Есть ли какой-либо вариант или решение, которое мы можем реализовать вместо компиляции для каждой платформы (x86 и x64)?
2 ответа
Операционная система Windows не требует, чтобы два отдельных процесса имели одинаковую разрядность для связи друг с другом, поэтому я предполагаю, что у вас есть внутреннее требование, чтобы оба процесса имели одинаковую разрядность. Если вам абсолютно необходимо добиться динамического запуска одного и того же EXE-файла в 32-разрядном или 64-разрядном режиме и принять это решение во время выполнения, вы можете изменить скомпилированное приложение AnyCPU во время выполнения с помощью утилиты corflags.exe, поставляемой с Visual Studio.
Вы можете запустить corflags.exe следующим образом (используя System.Diagnostic.Process):
corflags.exe "ourapp.exe" /32BIT+
Чтобы заставить его работать 32bit, и
corflags.exe "ourapp.exe" /32BIT-
Чтобы вернуться к AnyCPU (который будет 64-битным в 64-битной ОС)
Решение состоит в том, что вы развернете копию corflags.exe в вашей среде выполнения. Затем ваше хост-приложение может обнаружить его текущую разрядность, проверив sizeof(IntPtr), чтобы увидеть, равно ли оно 8 или 4; и создайте копию corflags.exe соответствующим образом (используя System.Diagnostics.Process) перед запуском ourapp.exe.
Это очень взломанный. Быть осторожен. Очевидно, у вас будет много проблем, если вам понадобится запустить две копии файла ourapp.exe одновременно на одной машине. Было бы идеально создать уникальную копию ourapp.exe в локальную пользовательскую папку перед ее изменением и запустить ее оттуда, чтобы избежать состязаний из нескольких экземпляров и запросов UAC в зависимости от целевой среды.
Является ли абсолютным требованием, чтобы процесс отображался на вкладке " Процессы " диспетчера задач как сам по себе? Или он может работать внутри другого хост-процесса?
Если последнее, вы можете создать проект-заглушку, содержащий следующие 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://stackru.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()
метод, мы не передаем никаких параметров Main()
метод для приложений WPF, поскольку приложение 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();