Configuração e consulta dual-STA
Observação
Para desenvolver para os recursos descritos neste tópico, é necessário o SDK do Windows 11 (10.0.22000.194) e posterior.
Há dois tipos de interfaces associadas a adaptadores que dão suporte a conexões de estação dupla (sta duplo) – interfaces STA primárias e interfaces STA secundárias. Todos os adaptadores expõem uma interface STA primária, mas apenas adaptadores que dão suporte à funcionalidade de STA dupla expõem interfaces STA secundárias.
Por padrão, o Windows se conecta somente na interface STA primária. O Windows se conectará na interface STA secundária somente se todas as seguintes condições forem atendidas:
- O driver indica suporte para interfaces STA secundárias em seus recursos.
- Não há nenhuma política que impeça a conectividade de STA secundária.
- Há pelo menos um aplicativo que chamou wlanSetInterface com o opcode wlan_intf_opcode_secondary_sta_synchronized_connections com o parâmetro definido como
TRUE
.
Consultando interfaces dual-STA
Para determinar se um adaptador está configurado para o DUAL STA e para obter a lista de GUIDssecundários da interface STA, seu aplicativo deve chamar WlanQueryInterface (wlanapi.h) com o wlan_intf_opcode_secondary_sta_interfaces opcode.
Esse opcode usa como parâmetro o GUID da interface sta (estação primária) (que pode ser obtida por uma chamada para WlanEnumInterfaces) e retorna uma lista de interfaces STA secundárias associadas a essa interface STA primária.
Aqui está um exemplo de como obter a lista de interfaces STA secundárias.
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <wlanapi.h>
#include <Windot11.h> // for DOT11_SSID struct
#include <objbase.h>
#include <wtypes.h>
#include <stdio.h>
#include <stdlib.h>
// Need to link with Wlanapi.lib and Ole32.lib
#pragma comment(lib, "wlanapi.lib")
#pragma comment(lib, "ole32.lib")
DWORD QueryDualStaInterfaces()
{
HANDLE hClient;
DWORD version;
DWORD dwResult = WlanOpenHandle(WLAN_API_VERSION_2_0, nullptr, &version, &hClient);
if (dwResult != ERROR_SUCCESS)
{
wprintf(L"WlanOpenHandle failed with error: %u\n", dwResult);
return dwResult;
}
PWLAN_INTERFACE_INFO_LIST pPrimaryIntfList = nullptr;
dwResult = WlanEnumInterfaces(hClient, nullptr, &pPrimaryIntfList);
if (dwResult != ERROR_SUCCESS)
{
wprintf(L"WlanEnumInterfaces FAILed, error = %u\n", dwResult);
WlanCloseHandle(hClient, NULL);
return dwResult;
}
wprintf(L"There are %u primary interfaces in the system\n", pPrimaryIntfList->dwNumberOfItems);
for (UINT i = 0; i < pPrimaryIntfList->dwNumberOfItems; i++)
{
WCHAR* strPrimaryUuid = nullptr;
if (UuidToStringW(&pPrimaryIntfList->InterfaceInfo[i].InterfaceGuid, reinterpret_cast<RPC_WSTR*>(&strPrimaryUuid)) != RPC_S_OK)
{
strPrimaryUuid = nullptr;
}
DWORD dwDataSize = 0;
PWLAN_INTERFACE_INFO_LIST pSecondaryIntfList = nullptr;
dwResult = WlanQueryInterface(
hClient,
&pPrimaryIntfList->InterfaceInfo[i].InterfaceGuid,
wlan_intf_opcode_secondary_sta_interfaces,
NULL,
&dwDataSize,
reinterpret_cast<PVOID*>(&pSecondaryIntfList),
NULL);
if (dwResult == ERROR_SUCCESS)
{
wprintf(
L"\t[%d]\tInterface %ws (State = %d) has %u Secondary interfaces\n",
i,
strPrimaryUuid ? strPrimaryUuid : L"Unknown",
pPrimaryIntfList->InterfaceInfo[i].isState,
pSecondaryIntfList->dwNumberOfItems);
for (UINT j = 0; j < pSecondaryIntfList->dwNumberOfItems; j++)
{
WCHAR* strSecondaryUuid = nullptr;
if (UuidToStringW(&pSecondaryIntfList->InterfaceInfo[j].InterfaceGuid, reinterpret_cast<RPC_WSTR*>(&strSecondaryUuid)) == RPC_S_OK)
{
wprintf(
L"\t\t[%d]\tSecondary Interface GUID: %ws, (State = %d)\n",
j,
strSecondaryUuid,
pSecondaryIntfList->InterfaceInfo[j].isState);
RpcStringFreeW(reinterpret_cast<RPC_WSTR*>(&strSecondaryUuid));
}
}
WlanFreeMemory(pSecondaryIntfList);
}
else
{
wprintf(L"\t[%d]\tInterface %ws has 0 Secondary interfaces, error = %u\n", i, strPrimaryUuid ? strPrimaryUuid : L"Unknown", dwResult);
}
if (strPrimaryUuid)
{
RpcStringFreeW(reinterpret_cast<RPC_WSTR*>(&strPrimaryUuid));
}
}
WlanFreeMemory(pPrimaryIntfList);
WlanCloseHandle(hClient, NULL);
return dwResult;
}
Consultando o estado de conexões sincronizadas de STA duplo
Para determinar se um adaptador se conectará automaticamente pela interface STA secundária após uma conexão pela interface STA primária, seu aplicativo pode consultar o estado atual chamando WlanQueryInterface com o wlan_intf_opcode_secondary_sta_synchronized_connections opcode.
Esse opcode retorna um valor BOOL que indica se as conexões STA primárias e secundárias são sincronizadas.
Aqui está um exemplo de como consultar esse estado.
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <wlanapi.h>
#include <Windot11.h> // for DOT11_SSID struct
#include <objbase.h>
#include <wtypes.h>
#include <stdio.h>
#include <stdlib.h>
// Need to link with Wlanapi.lib and Ole32.lib
#pragma comment(lib, "wlanapi.lib")
#pragma comment(lib, "ole32.lib")
DWORD QueryDualStaConnectivity()
{
HANDLE hClient;
DWORD version;
DWORD dwResult = WlanOpenHandle(WLAN_API_VERSION_2_0, nullptr, &version, &hClient);
if (dwResult != ERROR_SUCCESS)
{
wprintf(L"WlanOpenHandle failed with error: %u\n", dwResult);
return dwResult;
}
PWLAN_INTERFACE_INFO_LIST pPrimaryIntfList = nullptr;
dwResult = WlanEnumInterfaces(hClient, nullptr, &pPrimaryIntfList);
if (dwResult != ERROR_SUCCESS)
{
wprintf(L"WlanEnumInterfaces FAILed, error = %u\n", dwResult);
WlanCloseHandle(hClient, NULL);
return dwResult;
}
//
// Need to call the API only once to query/change the state.
//
if (pPrimaryIntfList->dwNumberOfItems)
{
WCHAR* strPrimaryUuid = nullptr;
if (UuidToStringW(&pPrimaryIntfList->InterfaceInfo[0].InterfaceGuid, reinterpret_cast<RPC_WSTR*>(&strPrimaryUuid)) != RPC_S_OK)
{
strPrimaryUuid = nullptr;
}
DWORD dwDataSize = 0;
PBOOL bQueriedValue = NULL;
dwResult = WlanQueryInterface(
hClient,
&pPrimaryIntfList->InterfaceInfo[0].InterfaceGuid,
wlan_intf_opcode_secondary_sta_synchronized_connections,
NULL,
&dwDataSize,
(PVOID*)&bQueriedValue,
NULL);
if (dwResult == ERROR_SUCCESS)
{
wprintf(L"Secondary Sta Synchronized connections is currently %ws\n", *bQueriedValue ? L"Enabled" : L"Disabled");
WlanFreeMemory(bQueriedValue);
}
else
{
wprintf(L"Failed to query Secondary Sta Synchronized connections - error = %u\n", dwResult);
}
if (strPrimaryUuid)
{
RpcStringFreeW(reinterpret_cast<RPC_WSTR*>(&strPrimaryUuid));
}
}
WlanFreeMemory(pPrimaryIntfList);
WlanCloseHandle(hClient, NULL);
return dwResult;
}
Habilitando conexões na interface STA secundária
O Windows não se conectará nas interfaces STA secundárias, a menos que exista um aplicativo que use a conexão STA secundária. Para controlar se o Windows se conecta na interface STA secundária, seu aplicativo deve chamar WlanSetInterface com o wlan_intf_opcode_secondary_sta_synchronized_connections opcode, com um parâmetro BOOL especificando se deseja habilitar ou desabilitar conexões na interface STA secundária. Um valor de TRUE
indica que você gostaria de habilitar a conectividade sta secundária, enquanto um valor de FALSE
indica que você não precisa mais de conectividade de STA secundária.
Chamar a API com o mesmo valor (TRUE
ou FALSE
) várias vezes é redundante e apenas a primeira instância de um novo valor faz com que a funcionalidade seja alterada.
Depois que o aplicativo habilitar a conectividade sta secundária, você deverá manter o identificador para o serviço aberto durante a duração que você espera usar a conexão STA secundária. Depois que o aplicativo desabilitar explicitamente a conectividade sta secundária (chamando WlanSetInterface com o opcode wlan_intf_opcode_secondary_sta_synchronized_connections e o valor do parâmetro de FALSE
, ou chamando WlanCloseHandle) ou implicitamente (saindo), o Windows desabilitará a conectividade pela interface STA secundária em algum momento posterior.
A conectividade sta secundária permanecerá habilitada enquanto pelo menos uma vez o aplicativo estiver solicitando.
Veja um exemplo mostrando como habilitar ou desabilitar a conectividade de STA secundária.
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <wlanapi.h>
#include <Windot11.h> // for DOT11_SSID struct
#include <objbase.h>
#include <wtypes.h>
#include <stdio.h>
#include <stdlib.h>
// Need to link with Wlanapi.lib and Ole32.lib
#pragma comment(lib, "wlanapi.lib")
#pragma comment(lib, "ole32.lib")
DWORD SetDualStaConnectivity(BOOL bEnable)
{
HANDLE hClient;
DWORD version;
DWORD dwResult = WlanOpenHandle(WLAN_API_VERSION_2_0, nullptr, &version, &hClient);
if (dwResult != ERROR_SUCCESS)
{
wprintf(L"WlanOpenHandle failed with error: %u\n", dwResult);
return dwResult;
}
PWLAN_INTERFACE_INFO_LIST pPrimaryIntfList = nullptr;
dwResult = WlanEnumInterfaces(hClient, nullptr, &pPrimaryIntfList);
if (dwResult != ERROR_SUCCESS)
{
wprintf(L"WlanEnumInterfaces FAILed, error = %u\n", dwResult);
WlanCloseHandle(hClient, NULL);
return dwResult;
}
//
// Only need to call the API once to query/change the state
//
if (pPrimaryIntfList->dwNumberOfItems)
{
WCHAR* strPrimaryUuid = nullptr;
if (UuidToStringW(&pPrimaryIntfList->InterfaceInfo[0].InterfaceGuid, reinterpret_cast<RPC_WSTR*>(&strPrimaryUuid)) != RPC_S_OK)
{
strPrimaryUuid = nullptr;
}
dwResult = WlanSetInterface(
hClient,
&pPrimaryIntfList->InterfaceInfo[0].InterfaceGuid,
wlan_intf_opcode_secondary_sta_synchronized_connections,
sizeof(bEnable),
reinterpret_cast<PBYTE>(&bEnable),
NULL);
if (dwResult == ERROR_SUCCESS)
{
wprintf(L"Successfully set Sec Sta opcode = %x on Primary Interface %ws\n", bEnable, strPrimaryUuid);
}
else
{
wprintf(L"FAILed set Sec Sta opcode = %x on Primary Interface %ws -- error = %u\n", bEnable, strPrimaryUuid, dwResult);
}
if (strPrimaryUuid)
{
RpcStringFreeW(reinterpret_cast<RPC_WSTR*>(&strPrimaryUuid));
}
}
WlanFreeMemory(pPrimaryIntfList);
// Close the handle only when the app no longer needs the dual-sta connection
//
WlanCloseHandle(hClient, NULL);
return dwResult;
}