Как отловить ошибки DLL-импорта задержки (отсутствует DLL или символ) в MinGW (-w64)?

С помощью dlltool -y Можно создать библиотеки отложенного импорта для существующих файлов .dll или .def. Это, кажется, работает просто отлично до того момента, когда dll требуется в системах, которые не имеют соответствующей dll (как ожидается для импортированной / загруженной dll с задержкой). Однако я не смог найти никакой информации о том, как отловить ошибки (отсутствующий модуль или отсутствующая функция), сгенерированные во время отложенной загрузки.

На MSVC вы бы использовали __try {} __except (...) {} Однако обработка исключений SEH недоступна в MinGW (также я не знаю, какой механизм исключений использует dlltool).

регулярное try {} catch(...) {} тоже не работает (приложение вылетает так же, как и без обработки исключений).

Вывод GDB также не особенно полезен:

gdb: unknown target exception 0xc06d007e at 0x7fefccfaaad

Program received signal ?, Unknown signal.
0x000007fefccfaaad in RaiseException ()
from C:\Windows\system32\KernelBase.dll

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

Поэтому вопрос, кто-нибудь успешно справился с задержкой загрузки в MinGW-w64 и как?

РЕДАКТИРОВАТЬПосле нескольких экспериментов я нашел следующее решение:

extern "C" __declspec(dllexport) void foo(int);

#include <windows.h>
#include <csetjmp>
#include <stdexcept>
#include <memory>
#include <cstdio>

thread_local auto do_handler = true;
thread_local jmp_buf env;
LONG CALLBACK handler(PEXCEPTION_POINTERS e)
{
if(do_handler)
{
// this flag is necessary to prevent a recursive call to handler
do_handler = false;
longjmp(env, 1);
}
else
{
return EXCEPTION_CONTINUE_SEARCH;
}
}

struct veh_remover
{
void operator() (void * veh) const
{
RemoveVectoredExceptionHandler(veh);
do_handler = true;
}
};

int main(int, char**)
{
#define CHECKED_DELAY(fn, ...) \
do { \
auto h = std::unique_ptr<void, veh_remover>(AddVectoredExceptionHandler(1, handler)); \
if(!setjmp(env)) fn(__VA_ARGS__); \
else throw std::runtime_error(#fn " not available"); \
} while(0);

try { CHECKED_DELAY(foo, 0); }
catch(std::exception & e) { printf("%s\n", e.what()); }
}

Тем не менее, я не уверен, что поведение этого кода хорошо определено (я все-таки долго прыгаю из обработчика). Также это не кажется особенно чистым.

РЕДАКТИРОВАТЬ 2: Я попробовал другой подход, настройку __pfnDliFailureHook2:

extern "C" __declspec(dllimport) void foo(int);

#include <windows.h>
#include <csetjmp>
#include <stdexcept>
#include <memory>
#include <cstdio>
#include <cassert>

#include <delayimp.h>

FARPROC WINAPI delayHook(unsigned dliNotify, PDelayLoadInfo)
{
switch(dliNotify)
{
case dliFailLoadLib: throw std::runtime_error("module could not be loaded");
case dliFailGetProc: throw std::runtime_error("could not find procedure in module");
default: return 0;
};
}

int main(int, char**)
{
__pfnDliFailureHook2 = &delayHook;
try
{
foo(0);
}
catch(std::exception & e)
{
printf("%s\n", e.what());
}
}

Этот подход терпит неудачу, потому что исключение не распространяется должным образом и приводит к 0x20474343 SEH исключение. Кажется, есть связанная ошибка GCC что должно быть исправлено, но, по крайней мере, с помощью MinGW-w64 g ++ 4.9.2 это все равно не работает (и это самая последняя доступная версия)

4

Решение

Задача ещё не решена.

Другие решения


По вопросам рекламы [email protected]