Есть два дьявола, заставляющие код вести себя неправильно.
Первый дьявол: предупреждающее сообщение было первым признаком того, что экспортированные инициализаторы не будут запущены до того, как MANAGED CODE будет впервые выполнен (угадайте, что при компиляции управляемого ничего не инициализируется, когда DLLзагружен).Пример предупреждения, когда я тестировал порядок загрузки смешанного кода:
1>CBla.cpp(8): warning C4835: '_bla1_' : the initializer for exported data will not be run until managed code is first executed in the host assembly.
, который я игнорировал, так как все работало.
Второй дьявол: некоторые из стандартных кодов c / c ++ могут 'быть скомпилировано в управляемый.Хотя у меня сложилось впечатление, что это не должно быть скомпилировано как управляемое.Но я начал получать предупреждающие сообщения в функциях, использующих переменные аргументы, и начал использовать везде прагмы нативного кода для компиляции нативного кода в нативный !!!
#pragma managed(push, off)
// native code
#pragma managed(pop)
Теперь это скомпилировано нормально, но в этом случае все "нативные"классы фактически жили только как нативные, никаких вызовов к управляемому коду не было - управляемый VFTABLE никогда не создавался.Управляемые функции имеют разные VFTABLE, пока они не будут загружены, каждая функция переписывается для загрузки CLR перед выполнением фактической управляемой функции.О чем вы можете узнать только с помощью IDA disasembler или аналогичных утилит ... но также кратко объясните внизу следующей страницы: https://msdn.microsoft.com/en-us/library/ms173266.aspx?f=255&MSPPError=-2147217396 "Инициализация смешанных сборок".Там никогда не вызывали инициализатор для внешних нативных классов, которые статически хранились в LIB / DLL, которые хранились в памяти (пустая оболочка).Таким образом, чистое нативное приложение, вызывающее смешанный код LIB / DLL, который никогда не использует / запускает код CLR, никогда не вызовет Constructor / Destructor в нативных скомпилированных классах.
РЕШЕНИЕ: Единственный способ преодолеть это ограничение -поместите некоторую управляемую функцию во все это, чтобы заставить CLR загружаться, и в этом случае вы заметите одно исключение во время процесса отладки:
First-chance exception at 0x7620c41f in ManagedNativeNatTest.exe: 0x04242420: CLRDBG_NOTIFICATION_EXCEPTION_CODE.
Это актуальный момент, когда код CLR получает уведомление об инициализации и начинает загрузкуэкспортированные собственные классы для LIB / DLL.Я смог вызвать это, поместив пустую функцию, принадлежащую нативному классу, в управляемый код:
...
#pragma managed(push, off)
...
#pragma managed(pop)
void CBla1::ManagedCall()
{ }
#pragma managed(push, off)
...
И вызов этой функции привел к выполнению загрузчика CLR в ответ на инициализацию моих внешних переменных.
Почемуэто сделано так, я не уверен, может быть, потому что CLR никогда ничего не загружает, пока не будет использован.Интересно, будет ли это в том же случае, если я скомпилирую CLR в нативный код с использованием NGen, но это может быть еще одно приключение.
На этом мой ответ завершается, почему extern vars не получают вызовы Constructor / Destructor в смешанных LIB / DLL.