null PublicKeyToken для сборок x86

У меня проблема при компиляции управляемого проекта DLL. Решение состоит из двух проектов: первый - это .NET DLL, написанный на C #, а другой - это управляемая C ++ DLL, которая напрямую ссылается на проект C #.

Оба проекта / библиотеки DLL имеют строгое имя с файлом snk на диске. C # dll имеет целевую структуру "AnyCPU", в то время как проект Manage C ++ компилируется дважды: один для целевого объекта x86, а другой - для x64.

Моя проблема в том, что когда я компилирую проект Managed C ++ для целевой платформы x86, результирующая DLL имеет PublicKeyToken = null, как сообщает ILSpy. При компиляции для платформы x64 библиотека DLL имеет правильный PublicKeyToken. Я проверил свойства своего проекта, ссылка на файл snk правильно для обеих целей платформы в Configuration Properties -> Linker->Advanced->Key File без задержки подписи; параметр Target Machine также установлен правильно в зависимости от желаемой цели компиляции.

Вот информация, которую показывает ILSpy, когда я загружаю свою DLL.

Для x64 dll:

// MyDll.x64, Version=1.1.1000.1, Culture=neutral, PublicKeyToken=XXXXXXXXX

// Architecture: x64
// This assembly contains unmanaged code.
// Runtime: .NET 2.0

Для x86 dll:

// MyDll.x86, Version=1.1.1000.1, Culture=neutral, PublicKeyToken=null

// Architecture: AnyCPU (64-bit preferred)
// This assembly contains unmanaged code.
// Runtime: .NET 2.0

Меня беспокоит описание архитектуры сборки x86: AnyCPU (64-bit preferred)

Я не уверен, почему он использует конфигурацию AnyCPU и что именно означает предпочтительная 64-битная аннотация?

Я также хотел бы упомянуть, что мой проект построен на .NET Framwork 2.0 для проекта C #, а проект Managed C ++ построен на v90 Platform Toolset. Я использую Visual Studio 2010, работающую на 64-битной машине с Windows 7.

Может кто-нибудь сказать мне, почему это происходит и как я могу решить эту проблему?


person Zaid Amir    schedule 03.02.2014    source источник
comment
Попробуйте включить ведение журнала MSBuild, и тогда вы можете узнать.   -  person Lex Li    schedule 03.02.2014


Ответы (1)


Это просто следствие того, как заголовок COR в сборке может указывать на желаемую архитектуру процессора. Вы можете увидеть объявления в заголовочном файле CorHdr.h SDK, вы найдете его в каталоге Windows SDK на вашем компьютере. Для отображения значений можно использовать служебную программу CorFlags.exe.

Доступен только флаг: COMIMAGE_FLAGS_32BITREQUIRED. Когда он установлен, он указывает CLR, что вы хотите запустить программу в 32-битном режиме, даже в 64-битной операционной системе. В .NET 4.5 добавлен дополнительный флаг, COMIMAGE_FLAGS_32BITPREFERRED, он устраняет двусмысленность в ядрах ARM. Слишком много сборок, где 32BITREQUIRED на самом деле означает «требуется x86» вместо «32-bit required».

Таким образом, нет ничего похожего на флаг «требуется 64 бита», сборка может указывать только «32-битный» или «не имеет значения». С джиттером, обеспечивающим связующее звено "не имеет значения", он генерирует архитектурно-зависимый машинный код во время выполнения. Поскольку опция 32BITREQUIRED не включена в вашей сборке, дизассемблер не может отображать ничего, кроме AnyCPU.

Следующая деталь - это поле IMAGE_FILE_HEADER.Machine в PE-заголовке исполняемого файла, оно указывает, на какой машине может работать исполняемый файл. Это слабый сигнал для сборок .NET, поскольку они обычно не содержат исполняемого кода, только MSIL. И это легко игнорируется загрузчиком Windows, сборки .NET обычно имеют это поле, установленное на IMAGE_FILE_MACHINE_I386, чтобы указать x86. Вы по-прежнему получаете 64-битный процесс из такой сборки EXE, при загрузке такого EXE происходит довольно героическое исправление структуры загрузчика. Работа mscoree.dll, "прокладка загрузчика". Подробнее об этом читайте в этом сообщении.

Поскольку вы нацелились на x64 в своем проекте C ++ / CLI, компоновщик установил IMAGE_FILE_HEADER.Machine на IMAGE_FILE_MACHINE_AMD64. Дизассемблер увидел это, создав аннотацию «64-битная предпочтительная».

Не дайте себя обмануть словом «предпочтительный». Дизассемблер не смотрел достаточно глубоко, чтобы увидеть, действительно ли ваша сборка содержит машинный код, сгенерированный компилятором C ++ / CLI. Им это не нравится, нет никакого дизассемблера, который декомпилирует машинный код обратно в исходный код C ++ / CLI. Сборка никогда не будет работать в 32-битной операционной системе. Kaboom в 32-битной ОС, программа выдает ошибку 11, ERROR_BAD_FORMAT, «Была сделана попытка загрузить программу с неправильным форматом».

Это ответ на ваш вопрос, иначе это не имеет никакого отношения к сильному имени.

person Hans Passant    schedule 03.02.2014
comment
Спасибо за подробный ответ, однако это касается только моей озабоченности по поводу (предпочтительной для 64-битной) аннотации. Моя настоящая проблема связана с PublicKeyToken=null, поскольку я полагаюсь на него при загрузке сборки из моего клиентского приложения. - person Zaid Amir; 03.02.2014
comment
Да, я был рад, что вы на самом деле не задали этот вопрос. Конечно, я понятия не имею, вы не описали точные шаги, которые вы предприняли для подписания сборки, поэтому я не могу сказать, где это пошло не так. Знание, где не искать проблему, - это 50% битвы. Продолжай пытаться. - person Hans Passant; 03.02.2014