kueri dan konfigurasi Dual-STA
Nota
Untuk mengembangkan fitur yang dijelaskan dalam topik ini, Windows 11 SDK (10.0.22000.194), dan yang lebih baru, diperlukan.
Ada dua jenis antarmuka yang terkait dengan adaptor yang mendukung koneksi stasiun ganda (dual-STA) — antarmuka STA utama, dan antarmuka STA sekunder. Semua adaptor mengekspos antarmuka STA utama, tetapi hanya adaptor yang mendukung fungsionalitas DUAL-STA yang mengekspos antarmuka STA sekunder.
Secara default, Windows hanya tersambung pada antarmuka STA utama. Windows akan tersambung pada antarmuka STA sekunder hanya jika semua kondisi berikut terpenuhi:
- Driver menunjukkan dukungan untuk antarmuka STA sekunder dalam kemampuannya.
- Tidak ada kebijakan yang mencegah konektivitas STA sekunder.
- Setidaknya ada satu aplikasi yang telah memanggilWlanSetInterface dengan opcode wlan_intf_opcode_secondary_sta_synchronized_connections dengan parameter yang diatur ke
TRUE
.
Mengkueri antarmuka dual-STA
Untuk menentukan apakah adaptor dikonfigurasi untuk dual-STA, dan untuk mendapatkan daftar antarmuka STA sekunder GUID, aplikasi Anda harus memanggil WlanQueryInterface (wlanapi.h) dengan opcode wlan_intf_opcode_secondary_sta_interfaces.
Opcode tersebut mengambil sebagai parameter GUID antarmuka stasiun utama (STA) (yang dapat diperoleh dengan panggilan ke WlanEnumInterfaces), dan mengembalikan daftar antarmuka STA sekunder yang terkait dengan antarmuka STA utama tersebut.
Berikut adalah contoh cara mendapatkan daftar antarmuka STA sekunder.
#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;
}
Mengkueri status koneksi yang disinkronkan dual-STA
Untuk menentukan apakah adaptor akan secara otomatis terhubung melalui antarmuka STA sekunder setelah koneksi melalui antarmuka STA utama, aplikasi Anda dapat meminta status saat ini dengan memanggil WlanQueryInterface dengan opcode wlan_intf_opcode_secondary_sta_synchronized_connections.
Opcode tersebut mengembalikan nilai BOOL yang menunjukkan apakah koneksi STA primer dan sekunder disinkronkan.
Berikut adalah contoh cara mengkueri status ini.
#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;
}
Mengaktifkan koneksi pada antarmuka STA sekunder
Windows tidak akan tersambung pada antarmuka STA sekunder kecuali ada aplikasi yang akan menggunakan koneksi STA sekunder. Untuk mengontrol apakah Windows terhubung pada antarmuka STA sekunder, aplikasi Anda harus memanggil WlanSetInterface dengan opcode wlan_intf_opcode_secondary_sta_synchronized_connections, dengan parameter BOOL yang menentukan apakah akan mengaktifkan atau menonaktifkan koneksi pada antarmuka STA sekunder. Nilai TRUE
menunjukkan bahwa Anda ingin mengaktifkan konektivitas STA sekunder, sementara nilai FALSE
menunjukkan bahwa Anda tidak lagi memerlukan konektivitas STA sekunder.
Memanggil API dengan nilai yang sama (TRUE
atau FALSE
) beberapa kali berlebihan, dan hanya instans pertama dari nilai baru yang menyebabkan fungsionalitas berubah.
Setelah aplikasi Anda mengaktifkan konektivitas STA sekunder, Anda harus menjaga handel ke layanan terbuka selama durasi yang Anda harapkan untuk menggunakan koneksi STA sekunder. Setelah aplikasi Anda menonaktifkan konektivitas STA sekunder secara eksplisit (baik dengan memanggil WlanSetInterface dengan wlan_intf_opcode_secondary_sta_synchronized_connections opcode dan nilai parameter FALSE
, atau dengan memanggil WlanCloseHandle), atau secara implisit (dengan keluar), Windows akan menonaktifkan konektivitas melalui antarmuka STA sekunder pada beberapa titik waktu setelahnya.
Konektivitas STA sekunder akan tetap diaktifkan selama setidaknya setelah aplikasi memintanya.
Berikut adalah contoh yang menunjukkan cara mengaktifkan atau menonaktifkan konektivitas STA sekunder.
#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;
}