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. Я использую Visual Studio 2010, работающую на 64-разрядной машине Windows 7.

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

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-разрядный требуется".

Таким образом, нет ничего похожего на флаг "Требуется 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, "Была предпринята попытка загрузить программу с неверным форматом".

Это отвечает на ваш вопрос, иначе не имеет ничего общего со строгим именем.

Другие вопросы по тегам