Использование новых функций Windows с резервным - PullRequest
4 голосов
/ 10 декабря 2010

Я уже довольно давно использую динамические библиотеки и прочее GetProcAddress, но это всегда кажется утомительным, интеллигентным, враждебным и уродливым способом.

Кто-нибудь знает чистый способ импортировать новые функции, оставаясь совместимым со старыми ОС.

Скажем, я хочу использовать библиотеку XML, которая является частью Vista. Я вызываю LoadLibraryW и затем могу использовать функции, если HANDLE не равен нулю.

Но я действительно не хочу идти #typedef (void*)(PFNFOOOBAR)(int, int, int) и PFNFOOOBAR foo = reinterpret_cast<PFNFOOOBAR>(GetProcAddress(GetModuleHandle(), "somecoolfunction"));, все это время 50, в путь.

Есть ли нехакское решение, с помощью которого я мог бы избежать этого беспорядка?

Я думал о добавлении coolxml.lib в настройках проекта, затем включении coolxml.dll в список dll delayload и, возможно, копировании нескольких сигнатур функций, которые я буду использовать в нужном файле. Затем проверка возврата LoadLibraryW с ненулевым значением, а если он не нулевой, то переход к ветви Vista, как в обычном потоке программы.

Но я не уверен, могут ли LoadLibrary и задержка загрузки работать вместе, и не предсказывает ли ветвление в некоторых случаях.

Кроме того, не уверен, что этот подход будет работать, и не вызовет ли он проблем после обновления до следующего SDK.

Ответы [ 3 ]

4 голосов
/ 10 декабря 2010

IMO, LoadLibrary и GetProcAddress - лучший способ сделать это.

(Создайте несколько объектов-обёрток, которые позаботятся об этом для вас, чтобы вы не загрязняли ваш основной код этой логикой и уродством.)

  1. DelayLoad приносит проблемы с безопасностью ( см. Этот пост OldNewThing ) (редактируйте: хотя нет, если вы уверены, что никогда не вызываете эти API в старых версиях Windows).

    DelayLoad также упрощает случайную зависимость от API, который не будет доступен для всех целей. Да, вы можете использовать инструменты для проверки того, какие API вы вызываете во время выполнения, но лучше иметь дело с этими вещами во время компиляции, IMO, и эти инструменты могут проверять только тот код, который вы фактически используете при работе под ними.

  2. Кроме того, избегайте компиляции некоторых частей вашего кода с различными версиями заголовков Windows, если только вы не будете очень осторожны при разделении кода и объектов, которые передаются в / из него.

    Это не совсем неправильно - и это совершенно нормально для таких вещей, как подключаемые библиотеки DLL, где две совершенно разные команды, вероятно, работали над двумя модулями, не зная, на какую версию SDK нацелены друг друга - но это может привести к трудным проблемам, если вы не осторожны, поэтому лучше избегать их вообще.

    Если вы смешиваете версии заголовков, вы можете получить очень странные ошибки. Например, у нас был статический объект, который содержал структуру ОС, которая меняла размер в Vista. Большая часть нашего проекта была скомпилирована для XP, но мы добавили новый файл .cpp, имя которого начиналось с буквы A и было настроено на использование заголовков Vista. Тогда этот новый файл (произвольно) стал тем, который вызвал статический объект, который должен быть размещен, используя размеры структуры Vista, но фактический код для этого объекта был построен с использованием структур XP. Конструктор думал, что члены объекта находятся в разных местах кода, который выделил объект. Странные вещи привели!

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

Очень утомительно писать все вещи typedef и GetProcAddress, а также копировать структуры и определения из заголовков (что кажется неправильным, но они являются двоичным интерфейсом, поэтому не собираются менять) (не забудьте проверить для #pragma pack тоже :(), но IMO это лучший способ, если вы хотите получить лучшее уведомление о проблемах во время компиляции.

Я уверен, что другие не согласятся!

PS: Где-то у меня есть маленький шаблон, который я сделал, чтобы сделать материал GetProcAddress немного менее утомительным ... Пытаюсь найти его; обновлю это, когда / если я это сделаю. Нашел, но на самом деле это было не так полезно. На самом деле, ни один из моего кода даже не использовал его. :)

2 голосов
/ 10 декабря 2010

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

1 голос
/ 02 апреля 2011

Задержка загрузки - лучший способ избежать непосредственного использования LoadLibrary() и GetProcAddress().Что касается упомянутых проблем безопасности, то единственное, что вы можете с этим поделать, - это использовать ловушки с задержкой загрузки , чтобы убедиться (и при необходимости принудительно), что требуемая DLL загружается во время уведомления dliNotePreLoadLibrary, используясистемный путь, а не относительно вашей папки приложения.Использование обратных вызовов также позволит вам заменить свои собственные резервные реализации в уведомлениях dliFailLoadLib / dliFailGetProc, когда нужные функции API недоступны.Таким образом, остальная часть вашего кода не должна беспокоиться о различиях платформ (или очень мало).

...