2017-01-26 12 views
8

У нас есть программное обеспечение в 32 и 64 бит, которое вызывает наш exe и передает ему события (как плагин).C# visual studio build exe с целевой anycpu, но которая определяет его платформу (x86/x64) на платформе вызывающего процесса (x86/x64)

Дело в том, что наш exe должен выполнять в той же битте (x86/x64), что и вызывающее программное обеспечение (если программное обеспечение запущено в 32-битной версии, наш exe должен работать в 32 битах, если программное обеспечение запущено в 64-битная версия нашего EXE должна работать в 64 битах). Версия для Windows - 64 бита, но клиент может запускать программное обеспечение в 32-битной версии или 64-битной версии.

В визуальной студии (2015 г.) параметр Target AnyCPU зависит только от версии Windows (опция + 32-битный флажок), но мы должны зависеть от вызывающего программного обеспечения Process.

Есть ли какой-либо вариант или решение, которое мы можем реализовать вместо компиляции на каждую платформу (x86 и x64)?

+0

«Вызовы нашего ехе» имеет мало смысла. Плагин неизменно загружается как DLL, что файл с расширением .exe-файла не имеет значения в .NET. Любая DLL должна соответствовать битности, выбранной исполняемым файлом запуска. Хост-процесс в сценарии плагина. Очень легко сделать на C#, выбрав «AnyCPU» в качестве цели и * не * проверив флажок «Предпочтительно 32-бит». Вы действительно пробовали это? –

+0

Извините, если я объяснил это неправильно. В этом случае программное обеспечение явно запускает нашappapp.exe (это его собственный процесс не как плагин), поэтому есть два независимых процесса: software.exe и ourapp.exe Да, мы попробовали AnyCPU, прежде чем задавать вопрос и в этих случаях наш процесс основывался на его битте в окнах, которые он выполнял (логически, как задокументировано), но мы хотим, чтобы какой-то параметр основывал его битту на процессе, вызывающем наш exe (стиль начальной загрузки?) – VSP

+0

Есть ли у вас контроль над программным обеспечением .exe? Можете ли вы создать 32bitWrapper и 64BitWrapper нашегоapp.exe и позволить software.exe начинать в зависимости от того, что он хочет? –

ответ

4

Требование к операционной системе Windows не требует, чтобы два отдельных процесса должны были иметь одинаковую битту для связи друг с другом, поэтому я предполагаю, что у вас есть внутреннее требование, чтобы оба процесса были одинаковыми. Если вам абсолютно необходимо добиться динамического запуска одного и того же EXE в 32-разрядной или 64-разрядной версии и принять это решение во время выполнения, вы можете изменить свое компилируемое приложение AnyCPU во время выполнения с помощью утилиты corflags.exe, которая поставляется с Visual Studio.

Вы можете запустить 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; и создайте экземпляр corflags.exe соответственно (используя System.Diagnostics.Process), перед запуском нашего файлаappapp.exe.

Это очень HACKY. Быть осторожен. Очевидно, что у вас будет много проблем, если вам нужно одновременно запустить две копии вашего файла ourapp.exe на том же компьютере. Было бы идеально создать уникальную копию нашего файла userapp.exe в локальной папке пользователя, прежде чем изменять его и запускать там, чтобы избежать условий гонки из нескольких экземпляров и запросов UAC в зависимости от вашей целевой среды.

0

Это абсолютное требование, чтобы процесс должен отображаться как сам по себе в окне Процессы вкладки диспетчера задач? Или он может работать внутри другого хост-процесса?

В последнем случае вы можете создать проект заглушки, содержащий следующий 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() мы не передаем какие-либо параметры методу 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();