Принудительная установка x86 CLR для сборки .NET с любым процессором. - PullRequest
56 голосов
/ 02 октября 2009

В .NET опция компилятора Platform Target: Any CPU позволяет сборке .NET работать как на 64-битной машине и 32-битной на машине x86. Также возможно заставить сборку работать как x86 на машине x64, используя опцию компилятора Platform Target: x86.

Можно ли запустить сборку с флагом «Любой процессор», но определить, должна ли она выполняться в CLR x86 или x64? Обычно это решение принимается загрузчиком CLR / OS (как я понимаю) на основе разрядности базовой системы.

Я пытаюсь написать приложение на C # .NET, которое может взаимодействовать (читать: вводить код в) с другими запущенными процессами. Процессы x64 могут внедряться только в другие процессы x64, и то же самое с x86. В идеале я хотел бы воспользоваться преимуществами JIT-компиляции и опции Any CPU , чтобы позволить одному приложению использоваться для внедрения в процессы x64 или x86 (на компьютере x64).

Идея состоит в том, что приложение будет скомпилировано как Любой ЦП . На машине x64 он будет работать как x64. Если целевой процесс - x86, он должен перезапустить себя, заставляя CLR запускать его как x86. Это возможно?

Ответы [ 4 ]

60 голосов
/ 02 октября 2009

Вы можете узнать, как приложение будет работать, и изменить его статически, используя приложение CorFlags . Чтобы узнать, как будет работать приложение, используйте:

corflags <PathToExe>

Чтобы изменить способ запуска приложения, используйте:

corflags /32bit+  <PathToExe>

Это заставит EXE-файл работать как 32-битный процесс. Информация о том, как должна выполняться сборка, хранится в PE-заголовке. См. Вопрос переполнения стека Как узнать, скомпилирован ли собственный файл DLL как x64 или x86? .

Если вы хотите внедрить код во время выполнения, вам нужно написать .NET профилировщик в C ++ / COM. См. .NET Internals: Profiling API и Profiling (Справочник по неуправляемому API) для получения дополнительной информации.

Вам нужно будет реализовать обратный вызов JitCompilationStarted и выполнять свою работу там. Если вы в этом направлении, вам придется создать DLL-файл для инъекций как x86, так и x64. Собственные файлы DLL будут загружены CLR , как только будут установлены следующие переменные окружения:

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

Если он установлен правильно, то 64-разрядная версия «увидит» 64-разрядные процессы, а 32-разрядная версия «увидит» 32-разрядные процессы.

9 голосов
/ 02 октября 2009

Прошло много времени с тех пор, как я попробовал это, но я считаю, что разрядность процесса, вызывающего сборку, определяет, будет ли она JITed как x86 или x64.

Таким образом, если вы напишите небольшое консольное приложение и создадите его как x86, а другое как x64, запуск одной или другой заставит другие сборки, загруженные в процесс, работать как 32- или 64-разрядные. Это, конечно, предполагает, что вы работаете на 64-битной машине.

6 голосов
/ 15 марта 2010

Я сделал нечто подобное, создав два (на самом деле три) двоичных файла. У меня было одно определение, был ли процесс, в который я пытался внедрить, был 32 или 64-битным. Затем этот процесс запустит либо 32-битную, либо 64-битную версию вашего двоичного файла для инъекций (в отличие от перезапуска, как вы упоминали).

Звучит грязно, но вы можете легко достичь этого во время сборки с помощью события после сборки, которое делает копию вашего выходного двоичного файла и использует утилиту CorFlags , чтобы заставить копию работать как 32- немного. Таким образом, вам не нужно развертывать утилиту CorFlags вместе с вашим приложением, что, вероятно, по какой-то причине является недопустимым.

Я думаю, что это очень похоже на вашу первоначальную идею и на самом деле не требует дополнительной работы, за исключением события сборки в две строки.

6 голосов
/ 02 октября 2009

Я не уверен, смогу ли я помочь вам с этим. Но это мой опыт.

У меня есть хост-приложение A.exe (скомпилировано как x86), и у меня есть клиентское приложение B.exe (скомпилировано как ANY CPU) из хост-приложения. И я запускаю B.exe из A.exe, используя System.Diagnostic.Process class.

Теперь проблема заключается в том, что если я поместу эти два на компьютер x64, то A.exe будет работать как x86, , тогда как B.exe будет работать как x64 .

Но если A.exe вызывает сборку c (c.dll, которая компилируется как Any CPU), а B.exe также вызывает c.dll, то c.dll будет следовать приложению, которое ее вызывает. Другими словами, на 64-битном компьютере, когда A.exe вызывает его, он будет вести себя как x86 dll, тогда как когда B.exe вызывает его, он будет вести себя как x64.

...