Partager via


Dual-STA requête et configuration

Note

Pour développer les fonctionnalités décrites dans cette rubrique, le Kit de développement logiciel (SDK) Windows 11 (10.0.22000.194) et ultérieur est nécessaire.

Il existe deux types d’interfaces associées aux adaptateurs qui prennent en charge les connexions à double station (dual-STA) : les interfaces STA principales et les interfaces STA secondaires. Tous les adaptateurs exposent une interface STA principale, mais seuls les adaptateurs prenant en charge la fonctionnalité STA double exposent les interfaces STA secondaires.

Par défaut, Windows se connecte uniquement sur l’interface STA principale. Windows se connecte sur l’interface STA secondaire uniquement si toutes les conditions suivantes sont remplies :

  1. Le pilote indique la prise en charge des interfaces STA secondaires dans ses fonctionnalités.
  2. Il n’existe aucune stratégie empêchant la connectivité STA secondaire.
  3. Il existe au moins une application qui a appelé leWlanSetInterfaceavec le wlan_intf_opcode_secondary_sta_synchronized_connections opcode avec le paramètre défini sur TRUE.

Interrogation d’interfaces DUAL-STA

Pour déterminer si un adaptateur est configuré pour dual-STA et pour obtenir la liste de l’interface STA secondaire GUIDs, votre application doit appeler WlanQueryInterface (wlanapi.h) avec le wlan_intf_opcode_secondary_sta_interfaces opcode.

Cet opcode prend comme paramètre l'GUID de l’interface de station principale (STA) (qui peut être obtenue par un appel à WlanEnumInterfaces), et retourne une liste d’interfaces STA secondaires associées à cette interface STA primaire.

Voici un exemple d’obtention de la liste des interfaces STA secondaires.

#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;
}

Interrogation de l’état des connexions synchronisées double STA

Pour déterminer si un adaptateur se connecte automatiquement via l’interface STA secondaire après une connexion sur l’interface STA principale, votre application peut interroger l’état actuel en appelant WlanQueryInterface avec le wlan_intf_opcode_secondary_sta_synchronized_connections opcode.

Ce code opcode retourne une valeur BOOL indiquant si les connexions STA primaires et secondaires sont synchronisées.

Voici un exemple d’interrogation de cet état.

#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;
}

Activation des connexions sur l’interface STA secondaire

Windows ne se connecte pas sur les interfaces STA secondaires, sauf si une application utilise la connexion STA secondaire. Pour contrôler si Windows se connecte sur l’interface STA secondaire, votre application doit appeler WlanSetInterface avec le wlan_intf_opcode_secondary_sta_synchronized_connections opcode, avec un paramètre BOOL spécifiant s’il faut activer ou désactiver les connexions sur l’interface STA secondaire. Une valeur de TRUE indique que vous souhaitez activer la connectivité STA secondaire, tandis qu’une valeur de FALSE indique que vous n’avez plus besoin de connectivité STA secondaire.

L’appel de l’API avec la même valeur (TRUE ou FALSE) plusieurs fois est redondant, et seule la première instance d’une nouvelle valeur entraîne la modification des fonctionnalités. Une fois que votre application active la connectivité STA secondaire, vous devez conserver le handle au service ouvert pendant la durée pendant laquelle vous prévoyez d’utiliser la connexion STA secondaire. Une fois que votre application désactive explicitement la connectivité STA secondaire (en appelant WlanSetInterface avec l'wlan_intf_opcode_secondary_sta_synchronized_connections opcode et la valeur de paramètre de FALSE, ou en appelant WlanCloseHandle), ou implicitement (en sortant), Windows désactive la connectivité via l’interface STA secondaire à un moment donné.

La connectivité STA secondaire reste activée tant qu’au moins une fois l’application la demande.

Voici un exemple montrant comment activer ou désactiver la connectivité STA secondaire.

#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;
}