Поделиться через


Запрос и конфигурация с двумя STA

Примечание

Для разработки функций, описанных в этом разделе, требуется пакет SDK для Windows 11 (10.0.22000.194) и более поздних версий.

Существует два типа интерфейсов, связанных с адаптерами, которые поддерживают подключения с двумя станциями (двойной sta): основные интерфейсы STA и вторичные интерфейсы STA. Все адаптеры предоставляют основной интерфейс STA, но только адаптеры, поддерживающие функции двойного sta, предоставляют дополнительные интерфейсы STA.

По умолчанию Windows подключается только к основному интерфейсу STA. Windows будет подключаться к дополнительному интерфейсу STA, только если выполняются все следующие условия:

  1. Драйвер указывает на поддержку дополнительных интерфейсов STA в своих возможностях.
  2. Не существует политики, запрещающей дополнительное подключение STA.
  3. Существует по крайней мере одно приложение, которое вызывает WlanSetInterface с wlan_intf_opcode_secondary_sta_synchronized_connections opcode с параметром , равным TRUE.

Запрос интерфейсов двойного STA

Чтобы определить, настроен ли адаптер для использования функции dual-STA, и получить список идентификаторов GUIDдополнительного интерфейса STA, приложение должно вызвать WlanQueryInterface (wlanapi.h) с wlan_intf_opcode_secondary_sta_interfaces кодом операции.

Этот код операции принимает в качестве параметра GUID интерфейса основной станции (STA), который можно получить путем вызова WlanEnumInterfaces), и возвращает список вторичных интерфейсов STA, связанных с этим основным интерфейсом STA.

Ниже приведен пример получения списка дополнительных интерфейсов 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;
}

Запрос состояния синхронизированных подключений с двумя sta

Чтобы определить, будет ли адаптер автоматически подключаться через дополнительный интерфейс STA после подключения через основной интерфейс STA, приложение может запросить текущее состояние, вызвав WlanQueryInterface с wlan_intf_opcode_secondary_sta_synchronized_connections кода операции.

Этот код операции возвращает значение BOOL , указывающее, синхронизированы ли первичные и вторичные подключения 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 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;
}

Включение подключений в дополнительном интерфейсе STA

Windows не будет подключаться к дополнительным интерфейсам STA, если не существует приложение, которое будет использовать дополнительное подключение STA. Чтобы управлять подключением Windows к дополнительному интерфейсу STA, приложение должно вызвать WlanSetInterface с wlan_intf_opcode_secondary_sta_synchronized_connections opcode с параметром BOOL , указывающим, следует ли включать или отключать подключения для дополнительного интерфейса STA. Значение TRUE указывает, что вы хотите включить дополнительное подключение STA, а значение FALSE указывает, что дополнительное подключение STA больше не требуется.

Вызов API с тем же значением (TRUE или FALSE) несколько раз является избыточным, и только первый экземпляр нового значения приводит к изменению функциональности. После того как приложение включит дополнительное подключение STA, необходимо держать дескриптор службы открытым в течение времени, на который вы планируете использовать дополнительное подключение STA. Когда приложение явно отключает дополнительное подключение STA (путем вызова WlanSetInterface с wlan_intf_opcode_secondary_sta_synchronized_connections кода операции и значением FALSEпараметра , или путем вызова WlanCloseHandle) или неявно (путем выхода), Windows отключит подключение через дополнительный интерфейс STA в определенный момент времени.

Дополнительное подключение STA будет оставаться включенным до тех пор, пока приложение запросит его по крайней мере один раз.

Ниже приведен пример, показывающий, как включить или отключить дополнительное подключение 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;
}