Dual-STA zapytań i konfiguracji
Nuta
Do opracowania funkcji opisanych w tym temacie potrzebny jest zestaw Windows 11 SDK (10.0.22000.194) i nowsze.
Istnieją dwa typy interfejsów skojarzonych z adapterami obsługującymi połączenia podwójnej stacji (dual-STA) — podstawowe interfejsy STA i pomocnicze interfejsy STA. Wszystkie karty uwidacznia podstawowy interfejs STA, ale tylko karty obsługujące funkcję podwójnego sta uwidacznia pomocnicze interfejsy STA.
Domyślnie system Windows łączy się tylko z podstawowym interfejsem STA. System Windows połączy się z pomocniczym interfejsem STA tylko wtedy, gdy zostaną spełnione wszystkie następujące warunki:
- Sterownik wskazuje obsługę pomocniczych interfejsów STA w swoich możliwościach.
- Nie ma żadnych zasad uniemożliwiających pomocniczą łączność STA.
- Istnieje co najmniej jedna aplikacja o nazwie WlanSetInterface z kodem opcode wlan_intf_opcode_secondary_sta_synchronized_connections z parametrem ustawionym na
TRUE
.
Wykonywanie zapytań dotyczących dwóch interfejsów STA
Aby określić, czy karta jest skonfigurowana dla funkcji dual-STA, oraz aby uzyskać listę pomocniczych interfejsów STA identyfikatorów GUIDs, aplikacja musi wywołać WlanQueryInterface (wlanapi.h) przy użyciu wlan_intf_opcode_secondary_sta_interfaces opcode.
Ten kod opcode przyjmuje jako parametr guiD interfejsu stacji podstawowej (STA) (który można uzyskać przez wywołanie WlanEnumInterfaces), i zwraca listę pomocniczych interfejsów STA skojarzonych z tym podstawowym interfejsem STA.
Oto przykład pobierania listy pomocniczych interfejsów STA.
#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;
}
Wykonywanie zapytań o stan połączeń synchronizowanych z dwoma stami
Aby określić, czy karta będzie automatycznie łączyć się za pośrednictwem pomocniczego interfejsu STA po połączeniu za pośrednictwem podstawowego interfejsu STA, aplikacja może wysyłać zapytania o bieżący stan, wywołując WlanQueryInterface za pomocą wlan_intf_opcode_secondary_sta_synchronized_connections opcode.
Ten kod opcode zwraca wartość BOOL wskazującą, czy podstawowe i pomocnicze połączenia STA są synchronizowane.
Oto przykład wykonywania zapytań dotyczących tego stanu.
#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;
}
Włączanie połączeń w pomocniczym interfejsie STA
System Windows nie będzie łączyć się z pomocniczymi interfejsami STA, chyba że istnieje aplikacja, która będzie używać pomocniczego połączenia STA. Aby kontrolować, czy system Windows łączy się z pomocniczym interfejsem STA, aplikacja musi wywołać WlanSetInterface za pomocą wlan_intf_opcode_secondary_sta_synchronized_connections opcode, z parametrem BOOL określającym, czy włączyć lub wyłączyć połączenia w pomocniczym interfejsie STA. Wartość TRUE
wskazuje, że chcesz włączyć dodatkową łączność STA, a wartość FALSE
wskazuje, że nie potrzebujesz już dodatkowej łączności STA.
Wywoływanie interfejsu API przy użyciu tej samej wartości (TRUE
lub FALSE
) jest nadmiarowe i tylko pierwsze wystąpienie nowej wartości powoduje zmianę funkcjonalności.
Po włączeniu dodatkowej łączności STA aplikacja musi zachować dojście do usługi otwarte przez czas trwania oczekiwanego użycia pomocniczego połączenia STA. Gdy aplikacja jawnie wyłączy dodatkową łączność STA (wywołując WlanSetInterface z wlan_intf_opcode_secondary_sta_synchronized_connections opcode i wartości parametru FALSE
lub wywołując WlanCloseHandle) lub niejawnie (po zakończeniu), system Windows wyłączy łączność przez pomocniczy interfejs STA w pewnym momencie w późniejszym czasie.
Dodatkowa łączność STA pozostanie włączona tak długo, jak co najmniej raz aplikacja żąda jej.
Oto przykład pokazujący sposób włączania lub wyłączania pomocniczej łączności STA.
#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;
}