Вызов среды выполнения c ++ из DllMain или глобальных инициализаторов - PullRequest
3 голосов
/ 25 февраля 2011

Вопрос вдохновлен этой дискуссией .
Похоже, что опасения, связанные с вызовами C ++ во время выполнения из DllMain (или из глобальных переменных ctor's), несколько устарели. Я часто использую глобальные инициализаторы в dll без каких-либо сбоев, и теперь я запускаю специальную тестовую программу (скомпилированную с VC2010 Express без SP), содержащую exe-модуль со статической связью во время выполнения и dll с динамической. Dll загружается вручную из exe с помощью LoadLibrary ().
Dll создает и заполняет объект карты во время глобальной инициализации (и поэтому использует библиотеку времени выполнения, по крайней мере, функции выделения памяти). Код Dll:

#include <map>
using namespace std;

struct A{
  char* p;
  static const int num=1000;
  map<int,string> m;
  A(){ 
    for(int i=0; i<num; ++i){m[i]= *new string("some text");}
  }
};

A a;

extern "C"{
_declspec(dllexport) const char* getText(int i){ return a.m[i].data(); }
}


Exe-код (для конфигурации выпуска; измените имя библиотеки времени выполнения на MSVCR100D.DLL для отладки):

#include <windows.h>
typedef const char* (*pfunc_t)(int idx);

int main(int argc, TCHAR* argv[])
{
  HMODULE h_crt= GetModuleHandle("MSVCR100.DLL");
  // ensure that runtime library is NOT loaded yet:
  MessageBox(NULL,(NULL==h_crt)? "CRT NOT loaded by .exe module": "CRT Loaded by .exe module"  ,"before LoadLibrary",MB_OK);

  HMODULE hlib=LoadLibrary("dll_example.dll");
  h_crt= GetModuleHandle("MSVCR100.DLL");
  MessageBox(NULL,(NULL==h_crt)? "CRT NOT loaded": "CRT Loaded"  ,"after LoadLibrary",MB_OK);

  pfunc_t pfunc= (pfunc_t)(void*)GetProcAddress(hlib,"getText");
  MessageBox(NULL,pfunc(99),"map[99]",MB_OK);

    return 0;
}

Выходная информация соответствует ожидаемой:

before LoadLibrary: CRT NOT loaded by .exe module
after LoadLibrary: CRT Loaded
map[99]: some text

Нет сбоев, нулевых указателей, ошибок страниц и т. Д.

Профилирование с помощью DependencyWalker также подтверждает, что библиотека времени выполнения (MSVCR100.DLL) загружается только после вызова LoadLibrary (и не предварительно загружается и инициализируется exe).

Кажется, что динамическая библиотека времени выполнения загружается и правильно инициализируется во время процесса загрузки dll_example.dll перед фазой глобальной инициализации.

есть мысли?

PS. Я не рекомендую переводить какой-либо тяжелый код инициализации на глобальную фазу инициализации; но я полагаю, что простой код выделения памяти достаточно безопасен (?).

Ответы [ 2 ]

4 голосов
/ 25 февраля 2011

Все зависит от того, что вы делаете внутри DLLMain.Поскольку в документации отказывается указывать, что можно и нельзя делать, а ЭЛТ не дает никаких обещаний, это всегда кажется рискованной областью.

Лично я перенесу всю свою глобальную инициализацию в одну процедурукоторый экспортируется из DLL и требует, чтобы все клиенты вызывали его перед вызовом любой другой функции.

3 голосов
/ 25 февраля 2011

Инициализация CRT при загрузке DLL - это очень распространенный сценарий, например, для любого COM-сервера.Таким образом, вы можете положиться на CRT, явно поддерживающий сценарий, если вам не требуется инициализация переменных с помощью кода, который, в свою очередь, зависит от опасных вызовов API.Инициализация управляемых объектов - это известный режим отказа, CLR не может быть инициализирован, пока удерживается блокировка загрузчика.Тупик очень неприятен для диагностики, но очень легко обнаружить.Что в целом верно, у вас нет проблем с обнаружением, что у вас есть проблема.Только найти обходной путь для этого.

Тем не менее, можно заплатить немало денег, если основная программа и одна или несколько DLL-библиотек используют разные экземпляры CRT.Что и происходит в вашей тестовой программе.Вы должны очень тщательно создать экспортированные функции DLL, чтобы не возвращать указатели или объекты C ++.Вы вернётесь с возвратом const char *, вызывающий не должен владеть этим указателем.Предположительно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...