Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В некоторых случаях определенное имя контракта набора API может быть намеренно сопоставлено с пустым именем модуля на некоторых устройствах Windows. Причины этого зависят, но распространенный пример заключается в том, что ресурсоемкая функция с точки зрения системных ресурсов может быть удалена из ос Windows при настройке для устройства с ограниченными ресурсами. Это создает проблему для приложений для корректной обработки необязательных функций на уровне API.
Традиционный подход для тестирования доступности API Win32 — использовать LoadLibrary или GetProcAddress. Однако это не надежные средства для тестирования наборов API из-за обратной пересылки. Если обратная пересылка применяется к заданному API, LoadLibrary или GetProcAddress может разрешаться в допустимый указатель функции даже в тех случаях, когда внутренняя реализация была удалена. В этом случае указатель функции будет указывать на заглушку, которая просто возвращает ошибку.
Чтобы обнаружить этот случай, можно использовать функцию IsApiSetImplemented для запроса базовой доступности данной реализации API. Этот тест сообщает, присутствует ли набор API в схеме набора наборов API на работающем устройстве и сопоставляется ли он с модулем реализации.
Important
Успешный запрос доступности не гарантирует успешность конкретного вызова. Продолжайте обрабатывать ошибки загрузки модуля, отсутствующие экспорты и собственные результаты задокументированного сбоя API.
В следующем примере кода показано, как использовать IsApiSetImplemented , чтобы определить, доступен ли набор API, содержащий WTSEnumerateSessionsW на текущем устройстве перед вызовом.
#include <windows.h>
#include <apiquery2.h>
#include <stdio.h>
#include <wtsapi32.h>
#pragma comment(lib, "OneCore.lib")
#pragma comment(lib, "Wtsapi32.lib")
int __cdecl wmain(int /* argc */, PCWSTR /* argv */ [])
{
PWTS_SESSION_INFOW pInfo = nullptr;
DWORD count = 0;
if (!IsApiSetImplemented("ext-ms-win-session-wtsapi32-l1-1-0"))
{
wprintf(L"ext-ms-win-session-wtsapi32-l1-1-0 is not available.\n");
return 0;
}
if (WTSEnumerateSessionsW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pInfo, &count))
{
wprintf(L"SessionCount = %lu\n", count);
for (DWORD i = 0; i < count; i++)
{
PWTS_SESSION_INFOW pCurInfo = &pInfo[i];
wprintf(L" %ls: ID = %lu, state = %d\n", pCurInfo->pWinStationName,
pCurInfo->SessionId, static_cast<int>(pCurInfo->State));
}
WTSFreeMemory(pInfo);
}
else
{
wprintf(L"WTSEnumerateSessionsW failure: %lu\n", GetLastError());
}
return 0;
}
IsApiSetImplemented объявлен в apiquery2.h, а обычный путь ссылки общедоступного пакета SDK предоставляет его из OneCore.lib. Эта библиотека отличается от любой библиотеки импорта, необходимой для вызова необязательного целевого API.
Приведенный выше пример ссылается на Wtsapi32.lib для статического импорта, который сохраняет пример коротким. Рабочее приложение, которое должно запускаться, где набор API отсутствует, также должно применять рекомендации в разделе "Сохранить необязательный путь кода, доступный".
Выберите имя запроса
Передайте имя тестового набора API. Имена наборов API обычно записываются без .dll суффикса, а примеры на этой странице используют эту форму. Суффикс не является частью имени набора API.
Чтобы найти имя, которое нужно передать, см. таблицу "Требования " на справочной странице для API, который требуется вызвать. Если в этой таблице есть строка набора API , она дает имя контракта. В противном случае используйте строку DLL , но только в том случае, если имя контракта начинается с api- или ext-; физическое имя модуля, например Wtsapi32.dll не является контрактом, и запрос к нему возвращает значение FALSE.
Форма имени зависит от способа решения API.
| Поверхность API | Форма запроса | Example |
|---|---|---|
| Именованной группы | <contract>~<group> |
api-win-core-samplefeature~AdvancedOperations |
| Группа по умолчанию | Псевдоним контракта без ~Default |
api-win-core-samplefeature |
| Контракт с версиями | Полное имя контракта с версиями | ext-ms-win-core-samplefeature-l1-1-0 |
Имена samplefeature являются иллюстрированными именами для вымышленного компонента Windows. Префикс имени (api- или ext-) не играет роли в поведении доступности.
Для именованной группы успешный запрос означает, что группа существует, его контракт сопоставляется с модулем реализации, что узел доступен в текущей среде выполнения, группа не отключена, а любая системная функция, связанная с группой, включена. Запрос, использующий псевдоним контракта, применяет проверки контракта и узла.
Если общедоступный заголовок API предоставляет вспомогательный Is<APIName>Present элемент, предпочтитель этого вспомогательного элемента. Он уже содержит правильное имя набора ИЛИ группы API, который несет API.
Результатом запроса является контракт- или групповая детализация, а не детализация функции. Два вспомогательных средства, поддерживаемые одной и той же именованной группой, всегда возвращают один и тот же результат, несмотря на то, что каждый вспомогательный элемент называется для другого API.
Сохранение доступного пути к необязательному коду
Проверка доступности не может защитить запуск процесса, если необязательный API связан как статический импорт. Загрузчик разрешает статические импорты перед выполнением кода, поэтому отсутствующий модуль завершает процесс, прежде чем выполнение достигнет проверки.
Используйте один из следующих подходов:
- Настройте модуль, который содержит необязательный API для задержки загрузки. Задержка загрузки — это параметр компоновщика: укажите
/DELAYLOAD:<module>и свяжите delayimp.lib. Укажите имя модуля, которое отображается в таблице импорта двоичного файла, которое может быть классическим именем библиотеки DLL, а не именем контракта набора API. В предыдущем примере это имяWTSAPI32.dll. - Или динамически разрешайте целевой объект с помощью LoadLibrary и GetProcAddress после успешного выполнения запроса доступности.
Не используйте LoadLibrary или GetProcAddress в качестве замены запроса на доступность. Они отвечают на вопросы модуля и экспорта, они не оценивают именованное состояние группы, и они могут разрешить заглушку обратной пересылки, как описано ранее. Используйте их после запроса для обработки отдельных модулей и проверок экспорта.
Поведение в более ранних версиях Windows
Реализация, предоставляемая OneCore.lib , выбирает доступный механизм запроса во время выполнения, поэтому приложение, которое вызывает IsApiSetImplemented , по-прежнему может выполняться в системе, которая предопределяет поддержку базового запроса.
В системе, где нет механизма запросов:
- Полное имя группы, содержащее
~значение FALSE. Система, которая не может оценить именованные группы, не может сообщить о доступности группы. - Имя, которое не соответствует группе, может возвращать ЗНАЧЕНИЕ TRUE. Это сохраняет совместимость с приложениями, которые предоставили собственные библиотеки DLL пересылки в ранних версиях Windows, где контракт был на самом деле удовлетворен этим сервером пересылки.
Не используйте запрос доступности набора API в качестве проверки безопасности или авторизации.