Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
In alcuni casi, un determinato nome di contratto del set di API potrebbe essere intenzionalmente mappato a un nome di modulo vuoto in alcuni dispositivi Windows. I motivi di questo problema variano, ma un esempio comune è che una funzionalità costosa in termini di risorse di sistema potrebbe essere rimossa dal sistema operativo Windows quando configurato per un dispositivo vincolato alle risorse. Ciò comporta una sfida per le applicazioni di gestire normalmente le funzionalità facoltative a livello di API.
L'approccio tradizionale per verificare se è disponibile un'API Win32 consiste nell'usare LoadLibrary o GetProcAddress. Tuttavia, questi non sono un mezzo affidabile per il test dei set di API, a causa dell'inoltro inverso. Se l'inoltro inverso viene applicato a una determinata API, LoadLibrary o GetProcAddress potrebbe risolversi in un puntatore a funzione valido anche nei casi in cui l'implementazione interna è stata rimossa. In questo caso, il puntatore alla funzione punterà a una funzione stub che restituisce semplicemente un errore.
Per rilevare questo caso, è possibile usare la funzione IsApiSetImplemented per eseguire una query sulla disponibilità sottostante di una determinata implementazione dell'API. Questo test indica se il set di API è presente nello schema del set di API composto nel dispositivo in esecuzione e se è mappato a un modulo di implementazione.
Importante
Una query di disponibilità riuscita non garantisce che una determinata chiamata abbia esito positivo. Continuare a gestire gli errori di caricamento dei moduli, le esportazioni mancanti e i risultati degli errori documentati dell'API.
L'esempio di codice seguente illustra come usare IsApiSetImplemented per determinare se il set di API che contiene WTSEnumerateSessionsW è disponibile nel dispositivo corrente prima di chiamarlo.
#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 viene dichiarato in apiquery2.h e il normale percorso di collegamento dell'SDK pubblico lo fornisce da OneCore.lib. Tale libreria è separata da qualsiasi libreria di importazione necessaria per chiamare l'API di destinazione facoltativa stessa.
L'esempio precedente collega Wtsapi32.lib per un'importazione statica, che mantiene breve l'esempio. Un'applicazione di produzione che deve essere eseguita in cui il set di API è assente deve anche applicare le indicazioni in Mantenere raggiungibile il percorso di codice facoltativo.
Scegliere il nome della query
Passare il nome del set di API di cui si esegue il test. I nomi dei set di API vengono scritti in modo convenzionale senza un .dll suffisso e gli esempi in questa pagina usano tale modulo. Il suffisso non fa parte del nome del set di API.
Per trovare il nome da passare, vedere la tabella Requisiti nella pagina di riferimento per l'API che si vuole chiamare. Se tale tabella contiene una riga del set di API , assegna il nome del contratto. In caso contrario, usare la riga DLL , ma solo quando il nome è presente un nome di contratto che inizia con api- o ext-; un nome di modulo fisico, ad esempio Wtsapi32.dll non è un contratto e l'esecuzione di query restituisce FALSE.
Il formato del nome dipende dalla modalità di gestione dell'API.
| Superficie delle API | Modulo query | Example |
|---|---|---|
| Gruppo denominato | <contract>~<group> |
api-win-core-samplefeature~AdvancedOperations |
| Gruppo predefinito | Alias del contratto, senza ~Default |
api-win-core-samplefeature |
| Contratto con controllo delle versioni | Nome del contratto con controllo delle versioni completo | ext-ms-win-core-samplefeature-l1-1-0 |
I samplefeature nomi sono nomi illustrativi per un componente Windows fittizio. Il prefisso del nome (api- o ext-) non ha un ruolo nel comportamento di disponibilità.
Per un gruppo denominato, una query con esito positivo indica che il gruppo esiste, il relativo contratto viene mappato a un modulo di implementazione, tale host è utilizzabile nell'ambiente di esecuzione corrente, il gruppo non è disabilitato e qualsiasi funzionalità di sistema associata al gruppo è abilitata. Una query che usa un alias di contratto applica i controlli del contratto e dell'host.
Se l'intestazione pubblica dell'API fornisce un Is<APIName>Present helper, preferisce tale helper. Contiene già il nome corretto per il set di API o il gruppo che contiene l'API.
Il risultato di una query è di tipo contract- o group-granular, non granulare per le funzioni. Due helper supportati dallo stesso gruppo denominato restituiscono sempre lo stesso risultato, anche se ogni helper è denominato per un'API diversa.
Mantenere raggiungibile il percorso di codice facoltativo
Un controllo di disponibilità non può proteggere l'avvio del processo se l'API facoltativa è collegata come importazione statica. Il caricatore risolve le importazioni statiche prima dell'esecuzione del codice, quindi un modulo mancante non riesce il processo prima che l'esecuzione raggiunga il controllo.
Usare uno di questi approcci:
- Configurare il modulo che contiene l'API facoltativa per il caricamento ritardato. Il caricamento ritardato è un'impostazione del linker: specificare
/DELAYLOAD:<module>e collegare delayimp.lib. Specificare il nome del modulo visualizzato nella tabella di importazione del file binario, che potrebbe essere il nome della DLL classica anziché il nome del contratto del set di API. Per l'esempio precedente, tale nome è WTSAPI32.dll. - In alternativa, risolvere la destinazione in modo dinamico con LoadLibrary e GetProcAddress dopo che la query di disponibilità ha esito positivo.
Non usare LoadLibrary o GetProcAddress come sostituto della query di disponibilità. Rispondono a domande di modulo ed esportazione, non valutano lo stato del gruppo denominato e possono risolversi in uno stub di inoltro inverso, come descritto in precedenza. Usarli dopo la query per gestire il modulo separato ed esportare i controlli.
Comportamento nelle versioni precedenti di Windows
L'implementazione fornita da OneCore.lib seleziona un meccanismo di query disponibile in fase di esecuzione, quindi un'applicazione che chiama IsApiSetImplemented può comunque essere eseguita in un sistema che precede il supporto della query sottostante.
In un sistema in cui non è disponibile alcun meccanismo di query:
- Nome completo del gruppo che contiene
~restituisce FALSE. Un sistema che non può valutare i gruppi denominati non può segnalare che un gruppo è disponibile. - Un nome non qualificato dal gruppo può restituire TRUE. Ciò consente di mantenere la compatibilità con le applicazioni che hanno fornito le proprie DLL del server d'inoltro nelle versioni precedenti di Windows, in cui il contratto è stato effettivamente soddisfatto da tale server d'inoltro.
Non usare una query di disponibilità del set di API come controllo di sicurezza o autorizzazione.