Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En algunos casos, un nombre de contrato de conjunto de API determinado podría asignarse intencionadamente a un nombre de módulo vacío en algunos dispositivos Windows. Las razones de esto varían, pero un ejemplo común es que una característica costosa en términos de recursos del sistema podría quitarse del sistema operativo Windows cuando se configura para un dispositivo restringido a recursos. Esto supone un desafío para que las aplicaciones controlen correctamente las características opcionales en el nivel de API.
El enfoque tradicional para probar si hay disponible una API de Win32 es usar LoadLibrary o GetProcAddress. Sin embargo, no son un medio confiable para probar conjuntos de API, debido al reenvío inverso. Cuando se aplica el reenvío inverso a una API determinada, LoadLibrary o GetProcAddress pueden resolverse en un puntero de función válido incluso en los casos en los que se ha quitado la implementación interna. En este caso, el puntero de función apuntará a una función de código auxiliar que simplemente devuelve un error.
Para detectar este caso, puede usar la función IsApiSetImplemented para consultar la disponibilidad subyacente de una implementación de API determinada. Esta prueba informa de si el conjunto de API está presente en el esquema del conjunto de API compuesto en el dispositivo en ejecución y si está asignado a un módulo de implementación.
Importante
Una consulta de disponibilidad correcta no garantiza que una llamada determinada se realice correctamente. Continúe controlando los errores de carga de módulos, las exportaciones que faltan y los propios resultados de errores documentados de la API.
En el ejemplo de código siguiente se muestra cómo usar IsApiSetImplemented para determinar si el conjunto de API que contiene WTSEnumerateSessionsW está disponible en el dispositivo actual antes de llamarlo.
#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 se declara en apiquery2.h y la ruta de acceso del vínculo del SDK público normal la proporciona desde OneCore.lib. Esa biblioteca es independiente de cualquier biblioteca de importación necesaria para llamar a la PROPIA API de destino opcional.
En el ejemplo anterior se vincula Wtsapi32.lib para una importación estática, que mantiene el ejemplo corto. Una aplicación de producción que debe ejecutarse donde el conjunto de API no esté presente también debe aplicar las instrucciones de Mantener accesible la ruta de acceso de código opcional.
Elija el nombre de la consulta.
Pase el nombre del conjunto de API que está probando. Los nombres de conjuntos de API se escriben convencionalmente sin un .dll sufijo y los ejemplos de esta página usan ese formulario. El sufijo no forma parte del nombre del conjunto de API.
Para buscar el nombre que se va a pasar, consulte la tabla Requirements (Requisitos ) en la página de referencia de la API a la que desea llamar. Si esa tabla tiene una fila de conjunto de API , proporciona el nombre del contrato. De lo contrario, use la fila DLL , pero solo cuando el nombre hay un nombre de contrato a partir api- de o ext-; un nombre de módulo físico como Wtsapi32.dll no es un contrato y la consulta devuelve FALSE.
El formato del nombre depende de cómo se aborda la API.
| Superficie de la API | Formulario de consulta | Example |
|---|---|---|
| Grupo con nombre | <contract>~<group> |
api-win-core-samplefeature~AdvancedOperations |
| Grupo predeterminado | Alias de contrato, sin ~Default |
api-win-core-samplefeature |
| Contrato con versiones | Nombre completo del contrato con versiones | ext-ms-win-core-samplefeature-l1-1-0 |
Los samplefeature nombres son nombres ilustrativos para un componente de Windows ficticio. El prefijo de nombre (api- o ext-) no desempeña un papel en el comportamiento de disponibilidad.
Para un grupo con nombre, una consulta correcta significa que el grupo existe, su contrato se asigna a un módulo de implementación, que el host se puede usar en el entorno de ejecución actual, el grupo no está deshabilitado y cualquier característica del sistema asociada al grupo está habilitada. Una consulta que usa un alias de contrato aplica las comprobaciones de contrato y host.
Si el encabezado público de la API proporciona un Is<APIName>Present asistente, prefiera ese asistente. Ya contiene el nombre correcto para el conjunto o grupo de API que contiene la API.
El resultado de una consulta es contract-or group-granular, not function-granular. Dos asistentes respaldados por el mismo grupo con nombre siempre devuelven el mismo resultado, aunque cada asistente tenga el nombre de una API diferente.
Mantener accesible la ruta de acceso de código opcional
Una comprobación de disponibilidad no puede proteger el inicio del proceso si la API opcional está vinculada como una importación estática. El cargador resuelve las importaciones estáticas antes de que se ejecute el código, por lo que un módulo que falta produce un error en el proceso antes de que la ejecución alcance la comprobación.
Use uno de estos enfoques:
- Configure el módulo que lleva la API opcional para retrasar la carga. La carga retrasada es una configuración del enlazador: especifique
/DELAYLOAD:<module>y vincule delayimp.lib. Especifique el nombre del módulo que aparece en la tabla de importación del archivo binario, que podría ser el nombre del archivo DLL clásico en lugar del nombre del contrato del conjunto de API. En el ejemplo anterior, ese nombre es WTSAPI32.dll. - O resuelva el destino dinámicamente con LoadLibrary y GetProcAddress después de que la consulta de disponibilidad se realice correctamente.
No use LoadLibrary ni GetProcAddress como sustituto de la consulta de disponibilidad. Responden a preguntas de módulo y exportación, no evalúan el estado del grupo con nombre y pueden resolverse en un código auxiliar de reenvío inverso, como se describió anteriormente. Úselos después de la consulta para controlar el módulo independiente y las comprobaciones de exportación.
Comportamiento en versiones anteriores de Windows
La implementación proporcionada por OneCore.lib selecciona un mecanismo de consulta disponible en tiempo de ejecución, por lo que una aplicación que llama a IsApiSetImplemented puede seguir ejecutándose en un sistema que predecite la compatibilidad con la consulta subyacente.
En un sistema en el que no haya ningún mecanismo de consulta disponible:
- Un nombre calificado por grupo que contiene
~devuelve FALSE. Un sistema que no puede evaluar grupos con nombre no puede informar de que un grupo está disponible. - Un nombre que no sea calificado por grupos puede devolver TRUE. Esto conserva la compatibilidad con las aplicaciones que proporcionaron sus propios archivos DLL de reenviador en versiones anteriores de Windows, donde el contrato estaba satisfecho por ese reenviador.
No use una consulta de disponibilidad del conjunto de API como comprobación de seguridad o autorización.