Как заставить LoadLibrary отображать диалоговое окно с ошибкой при отсутствии зависимостей

Допустим, у нас есть две динамические библиотекиlibfoo.dll а такжеlibbar.dll , учитывая, чтоlibbar.dll зависит отlibfoo.dll . Далее компилируем исполняемый файлtest.exe это загружает нашиlibbar.dll с использованием функции WinAPILoadLibrary() .

Если мы бежимtext.exe в Windows XP с отсутствующимlibfoo.dll ,LoadLibrary() показывает предупреждение диалогового окна, чемlibfoo.dll фактически отсутствует и устанавливаетLastError кERROR_MOD_NOT_FOUND (126).

Если мы запустим то же самоеtext.exe в тех же условиях на Windows 10,LoadLibrary() наборыLastError кERROR_MOD_NOT_FOUND только диалоговое окно не появляется.

В обоих случаяхErrorMode равно 0. Есть ли возможность отловить имя отсутствующей зависимости вLoadLibrary() процесс вызова, или хотя бы как сделатьLoadLibrary() показать диалог ошибки в Windows 10?

Вот пример кода (с использованием MinGW):

foo.c

int foo(int a, int b)
{
    return a + b;
}

Скомпилировать с помощью:gcc foo.c -o libfoo.dll -fPIC -shared

bar.c

int foo(int a, int b);

int bar(int a, int b)
{
    return foo(a, b);
}

Скомпилировать с помощью:gcc bar.c -o libbar.dll -fPIC -shared -L. -lfoo

test.c

#include <windows.h>
#include <stdio.h>

typedef int (*pfn)(int a, int b);

int main()
{
    SetErrorMode(0);

    HMODULE hmod = LoadLibrary("libbar.dll");

    if(!hmod)
    {
        fprintf(stderr, "error loading library %d\n", GetLastError());
        return 1;
    }

    pfn bar = (pfn)GetProcAddress(hmod, "bar");
    if(bar)
    {
        fprintf(stdout, "bar(3, 1) = %d\n", bar(3, 1));
    }
    else
    {
        fprintf(stderr, "can't load bar foonction\n");
    }

    FreeLibrary(hmod);
    return 0;
}

Скомпилировать с помощью:gcc test.c -o test

# dll windows-10 winapi loadlibrary
Источник
  • 3
    Возможно, это как-то связано с режимом SetErrorMode по умолчанию.
  • 0
    Цитата из документа функции LoadLibary: Чтобы включить или отключить сообщения об ошибках, отображаемые загрузчиком во время загрузки DLL, используйте функцию SetErrorMode.
  • 0
    Как я уже упоминал выше, для моего ErrorMode установлено значение 0 (SetErrorMode (0) в образце test.c), что означает (согласно документу msdn) он должен отображать все диалоги.
  • 0
    Зачем вам это нужно?
  • 1
    xp вызывает NtRaiseHardError если зависимая dll не загружается. в результате вы и можете просматривать диалоговое окно с ошибкой, и SetErrorMode имеет эффект. но win10 больше не вызывает NtRaiseHardError . в результате диалоговое окно с ошибкой и режим ошибки здесь не играют роли
  • 0
    Дэвиду Хеффернану: ну, у нас есть куча устаревшего кода (скомпилированного в MSVS 2003 для winXP), который показывает такие диалоги, и мы хотим сохранить это поведение в Win10, нам важно точно знать, какая библиотека отсутствует. To RbMm: спасибо за это объяснение. Но есть ли варианты?
  • 0
    Что-то не так, если вы полагаетесь на это старое устаревшее поведение. Вы также не должны были использовать его на XP. Найдите лучшее решение проблемы.
  • 0
    @DavidHeffernan, я полностью согласен с тем, что мне не следует полагаться на это, и можно использовать другое решение.
  • 0
    Как вариант, я мог явно проверить зависимости libbar.dll (с помощью LoadLibrary ()). В моем случае я знаю, какие библиотеки следует проверять. Но, может быть, есть способ получить в коде зависимости .dll?
  • 0
    Зачем нужно что-то проверять? Просто установите правильные библиотеки DLL.
  • 0
    @DavidHeffernan, недавний случай: клиент испортил дистрибутив, который мы предоставляем, и некоторые библиотеки были потеряны - те, от которых зависят другие. В этом случае и для клиента, и для разработчика кажется, что есть проблема с LoadLibrary() поскольку она выдает ошибку 126. Поэтому было бы неплохо определить, что на самом деле проблема заключается в отсутствии зависимостей.
  • 0
    Вам нужна лучшая программа установки. Это настоящая проблема. ERROR_MOD_NOT_FOUND - правильный код ошибки. Обращайтесь с этим правильно.
  • 0
    Я полагаю, вы могли бы включить DLL с отложенной загрузкой для libbar.dll. Таким образом, вы будете получать обратные вызовы для каждого модуля, который он пытается загрузить. Вам не нужно вручную проверять список зависимостей, который со временем может измениться. Однако я не уверен, что эта опция доступна в Visual Studio 2003.
  • 0
    Вы можете включить служебную программу для запуска пользователем, которая печатает отладочные строки из вашего приложения в простом цикле, который в основном вызывает WaitForDebugEventEx , ReadProcessMemory , ContinueDebugEvent . При включении привязок загрузчика (0x2) в параметре GlobalFlag исполняемого файла «Параметры выполнения файла образа» загрузчик очень болтлив. Просто найдите строку вроде LdrpProcessWork - ERROR: Unable to load DLL: "foo.dll", Parent Module: "C:\Temp\bar.dll", Status: 0xc0000135 . Это собственный код состояния STATUS_DLL_NOT_FOUND .
  • 0
    Спасибо за ответы, попробую эти варианты.
Codelisting
за 1 против
Лучший ответ

На данный момент кажется, что нет элегантного решения поставленного вопроса.

Как отметил @DavidHeffernan в комментариях к исходному посту, проблема должна решаться на принципиально другом уровне. В качествеLoadLibrary() ведет себя так же, как и должно, главное - это правильная установка и обработка ошибок.

Однако, если нужно явно отловить недостающие зависимости динамически загружаемых библиотек, можно применить методы, предоставляемые @IInspectable и @eryksun:

  • включение DLL с отложенной загрузкой для библиотек, которые будут загружаться динамически. Такой подход предоставляет вспомогательные обратные вызовы для каждого зависимого модуля, поэтому недостающие зависимости могут быть обработаны на месте. Основным недостатком этого подхода является то, что целевая библиотека должна быть перекомпилирована с соответствующими флагами компоновщика;
  • можно написать вспомогательную утилиту, которая выгружает отладочные строки из приложения (подробности см. в комментарии @eryksun к исходному сообщению). Недостатки: помимо необходимости написания дополнительного модуля, он также включает некоторые манипуляции с реестром.
Codelisting
Популярные категории
На заметку программисту