Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Dans certains cas, un nom de contrat d’ensemble d’API donné peut être mappé intentionnellement à un nom de module vide sur certains appareils Windows. Les raisons de cette variation varient, mais un exemple courant est qu’une fonctionnalité coûteuse en termes de ressources système peut être supprimée du système d’exploitation Windows lorsqu’elle est configurée pour un appareil limité par des ressources. Cela pose un défi pour les applications de gérer correctement les fonctionnalités facultatives au niveau de l’API.
L’approche traditionnelle pour tester si une API Win32 est disponible consiste à utiliser LoadLibrary ou GetProcAddress. Toutefois, il ne s’agit pas d’un moyen fiable pour tester les ensembles d’API, en raison du transfert inverse. Lorsque le transfert inverse est appliqué à une API donnée, LoadLibrary ou GetProcAddress peut être résolu en pointeur de fonction valide même dans les cas où l’implémentation interne a été supprimée. Dans ce cas, le pointeur de fonction pointe vers une fonction stub qui retourne simplement une erreur.
Pour détecter ce cas, vous pouvez utiliser la fonction IsApiSetImplemented pour interroger la disponibilité sous-jacente d’une implémentation d’API donnée. Ce test indique si le jeu d’API est présent dans le schéma de jeu d’API composé sur l’appareil en cours d’exécution et s’il est mappé à un module d’implémentation.
Important
Une requête de disponibilité réussie n’est pas une garantie qu’un appel particulier réussira. Continuez à gérer les erreurs de chargement de module, les exportations manquantes et les résultats des propres échecs documentés de l’API.
L’exemple de code suivant montre comment utiliser IsApiSetImplemented pour déterminer si l’ensemble d’API qui contient WTSEnumerateSessionsW est disponible sur l’appareil actuel avant de l’appeler.
#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 est déclaré dans apiquery2.h, et le chemin normal du lien du Kit de développement logiciel (SDK) public le fournit à partir de OneCore.lib. Cette bibliothèque est distincte de n’importe quelle bibliothèque d’importation nécessaire pour appeler l’API cible facultative elle-même.
L’exemple ci-dessus lie Wtsapi32.lib pour une importation statique, qui conserve l’exemple court. Une application de production qui doit s’exécuter là où l’ensemble d’API est absent doit également appliquer les instructions dans Conserver le chemin de code facultatif accessible.
Choisir le nom de la requête
Transmettez le nom du jeu d’API que vous testez. Les noms des ensembles d’API sont écrits de manière conventionnelle sans .dll suffixe, et les exemples de cette page utilisent ce formulaire. Le suffixe ne fait pas partie du nom du jeu d’API.
Pour trouver le nom à passer, consultez le tableau Configuration requise dans la page de référence de l’API que vous souhaitez appeler. Si cette table a une ligne d’ensemble d’API , elle donne le nom du contrat. Sinon, utilisez la ligne DLL , mais uniquement lorsque le nom contient lui-même un nom de contrat commençant api- par ou ext-; un nom de module physique tel que Wtsapi32.dll n’est pas un contrat et l’interrogation qu’il retourne FALSE.
La forme du nom dépend de la façon dont l’API est traitée.
| Surface d’API | Format de requête | Example |
|---|---|---|
| Groupe nommé | <contract>~<group> |
api-win-core-samplefeature~AdvancedOperations |
| Groupe par défaut | Alias de contrat, sans ~Default |
api-win-core-samplefeature |
| Contrat avec version | Nom complet du contrat avec version | ext-ms-win-core-samplefeature-l1-1-0 |
Les samplefeature noms sont des noms illustrant un composant de Windows fictif. Le préfixe de nom (api- ou ext-) ne joue pas de rôle dans le comportement de disponibilité.
Pour un groupe nommé, une requête réussie signifie que le groupe existe, son contrat est mappé à un module d’implémentation, que l’hôte est utilisable dans l’environnement d’exécution actuel, que le groupe n’est pas désactivé et que toute fonctionnalité système associée au groupe est activée. Une requête qui utilise un alias de contrat applique le contrat et les vérifications de l’hôte.
Si l’en-tête public de l’API fournit un Is<APIName>Present assistance, préférez cet assistance. Il contient déjà le nom correct pour l’ensemble d’API ou le groupe qui contient l’API.
Le résultat d’une requête est granulaire de contrat ou de groupe, et non granulaire de fonction. Deux assistances soutenues par le même groupe nommé retournent toujours le même résultat, même si chaque assistance est nommée pour une API différente.
Conserver le chemin de code facultatif accessible
Un contrôle de disponibilité ne peut pas protéger le démarrage du processus si l’API facultative est liée en tant qu’importation statique. Le chargeur résout les importations statiques avant l’exécution de votre code. Par conséquent, un module manquant échoue avant que l’exécution atteigne la vérification.
Utilisez l’une des approches suivantes :
- Configurez le module qui contient l’API facultative pour le chargement différé. Le chargement différé est un paramètre d’éditeur de liens : spécifier
/DELAYLOAD:<module>et lier delayimp.lib. Spécifiez le nom du module qui apparaît dans la table d’importation de votre binaire, qui peut être le nom de DLL classique plutôt que le nom du contrat du jeu d’API. Pour l’exemple précédent, ce nom est WTSAPI32.dll. - Ou résolvez la cible dynamiquement avec LoadLibrary et GetProcAddress une fois la requête de disponibilité réussie.
N’utilisez pas LoadLibrary ou GetProcAddress comme substitut de la requête de disponibilité. Ils répondent aux questions de module et d’exportation, ils n’évaluent pas l’état du groupe nommé, et peuvent résoudre un stub de transfert inverse comme décrit précédemment. Utilisez-les après la requête, pour gérer le module distinct et les vérifications d’exportation.
Comportement sur les versions antérieures de Windows
L’implémentation fournie par OneCore.lib sélectionne un mécanisme de requête disponible au moment de l’exécution. Par conséquent, une application qui appelle IsApiSetImplemented peut toujours s’exécuter sur un système qui précède la prise en charge des requêtes sous-jacentes.
Sur un système où aucun mécanisme de requête n’est disponible :
- Nom qualifié de groupe qui contient
~la valeur FALSE. Un système qui ne peut pas évaluer les groupes nommés ne peut pas signaler qu’un groupe est disponible. - Un nom qui n’est pas qualifié par un groupe peut retourner TRUE. Cela préserve la compatibilité avec les applications qui ont fourni leurs propres DLL de redirecteur sur les versions antérieures de Windows, où le contrat était en fait satisfait par ce redirecteur.
N’utilisez pas de requête de disponibilité de groupe d’API comme contrôle de sécurité ou d’autorisation.