WlanAPI WlanGetNetworkBssList возвращает неверные данные

Я застрял в своих усилиях по отладке с вызовом WlanGetNetworkBssList и был бы признателен за некоторые указатели. Моя конечная цель - создать Wifi-сканер / инструмент для профилирования, чтобы помочь мне устранять проблемы с сетью на удаленных сайтах.

Я использую Windows Native Wifi API ( ссылка) и интерфейс Delphi/Pascal, который можно найти здесь, с помощью Delphi Berlin 10.1 Update 2 под Windows 10 (VCL).

Я начал с простого и грубого тестового приложения (VCL), чтобы почувствовать API, и столкнулся с проблемой, вызывающей WlanGetNetworkBssList, поэтому я создал небольшое консольное приложение, ориентированное на эту проблему. Проблема в том, что он работает в консольном приложении, запущенном в командной строке, но не в моем тестовом приложении VCL. Функции в значительной степени эквивалентны копированию и вставке, и пошаговое выполнение кода показывает, что данные идентичны, за исключением данных возврата из вызова WlanGetNetworkBssList (pWlanBssList)

Вопрос: Поскольку вызов выполняется для внешней DLL, какие шаги я могу сделать для дальнейшей отладки и понимания разницы между VCL и консольным приложением.

Примечание: WlanGetNetworkBssList имеет два режима работы, где SSID может быть предоставлен для получения BSSID (MAC точки доступа) для этого конкретного SSID. Передав NULL вместо SSID, API вернет BSSID всех AP. Передача NULL работает как в VLC, так и в консольном приложении. Что мешает, когда запрашивается конкретный SSID. После проверки структура данных SSID идентична в обоих приложениях, но возвращенный буфер данных недопустим в приложении VCL. Как это может быть?

Консольное приложение:

program CWifiScan;

{$APPTYPE CONSOLE}

uses
  Windows,
  System.SysUtils,
  nduWlanAPI,
  nduWlanTypes;
const
  WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_ADHOC_PROFILES = $00000001;
var
  hWlan: THandle;
  guid : TGUID;
  dwSupportedVersion: DWORD = 0;
  dwClientVersion: DWORD = 1;
  i,j                   : integer;
  pInterfaceInfo        : Pndu_WLAN_INTERFACE_INFO;
  pInterfaceList        : Pndu_WLAN_INTERFACE_INFO_LIST;
  pAvailableNetworkList : Pndu_WLAN_AVAILABLE_NETWORK_LIST;

procedure GetBSSIDList(clientHandle  : THandle;
                          interfaceGUID : TGUID;
                          pSSID         : Pndu_DOT11_SSID = nil;
                          SSID_Type     : Tndu_DOT11_BSS_Type = dot11_BSS_type_any;
                          SecurityEnabled : BOOL = True);
var
  //to check if interface is connected
  pData         : Pndu_WLAN_INTERFACE_STATE;
  pdwDataSize   : DWORD;
  isConnected   : Boolean;
  //to get list of BSSids from available APs
  pWlanBssList : Pndu_WLAN_BSS_LIST;
  items         : integer;
  itemIndex     : integer;
  SSID          : string;
  MAC           : string;
begin
  //check if interface is connected
  isConnected := False;
  if WlanQueryInterface(clientHandle,
                        @interfaceGUID,
                        wlan_intf_opcode_interface_state,
                        nil,
                        @pdwDataSize,
                        @pData,
                        nil) = ERROR_SUCCESS then
  begin
    isConnected := (pData^ = Tndu_WLAN_INTERFACE_STATE.wlan_interface_state_connected);
  end;

  //get the list of BSSids for the provided interface
  if isConnected then
  begin
    if WlanGetNetworkBssList(clientHandle,
                             @interfaceGUID,
                             pSSID,
                             SSID_Type,
                             SecurityEnabled,
                             nil,
                             @pWlanBssList) = ERROR_SUCCESS then
    begin
      items := pWlanBssList^.dwNumberOfItems;
      for itemIndex := 0 to items - 1 do
      begin

        SSID := String(PAnsiChar(@pWlanBssList^.wlanBssEntries[itemIndex].dot11Ssid.ucSSID));

        MAC := Format('%.2x:%.2x:%.2x:%.2x:%.2x:%.2x', [
                     pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[0],
                     pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[1],
                     pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[2],
                     pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[3],
                     pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[4],
                     pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[5]]);

        Writeln('');
        Writeln('SSID: ................ '+SSID);
        Writeln('Physical Address: .... '+MAC);
      end; {for itemIndex}
      Writeln(#10+#13+'Done.');
    end; {WlanGetNetworkBssList succeeds}

  end; {isConnected}
end;

begin
  hWlan := 0;

  if WlanOpenHandle(2, nil,@dwSupportedVersion, @hWlan)= ERROR_SUCCESS then
  begin
    if WlanEnumInterfaces(hWlan, nil, @pInterfaceList) = ERROR_SUCCESS then
    begin
      try
        for i := 0 to pInterfaceList^.dwNumberOfItems-1 do
          begin
            Writeln('Wifi Adapter - '+GUIDToString( pInterfaceList^.InterfaceInfo[i].InterfaceGuid ) );
            Writeln('Scanning: .... '+pInterfaceList^.InterfaceInfo[i].strInterfaceDescription);
            guid := pInterfaceList^.InterfaceInfo[i].InterfaceGuid;

            //Get all BSSids for this interface
            GetBSSIDList(hWlan, guid);

            if WlanGetAvailableNetworkList(hWlan,
                                           @guid,
                                           WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_ADHOC_PROFILES,
                                           nil,
                                           pAvailableNetworkList) = ERROR_SUCCESS then
            begin
              try
                for j := 0 to pAvailableNetworkList^.dwNumberOfItems - 1 do
                  begin

                    //Get BSSid for this specific SSID
                    GetBSSIDList(hWlan,
                                 guid,
                                 @pAvailableNetworkList^.Network[j].dot11Ssid,
                                 pAvailableNetworkList^.Network[j].dot11BssType,
                                 pAvailableNetworkList^.Network[j].bSecurityEnabled);

                  end;
              finally
                if pAvailableNetworkList<>nil then
                  WlanFreeMemory(pAvailableNetworkList);
              end;
            end;

          end;
      finally
        if pInterfaceList<>nil then
          WlanFreeMemory(pInterfaceList);
      end;
    end;

    WlanCloseHandle(hWlan, nil);

    readln;

  end;
end.

Соответствующие части приложения VCL:

uses
  ... nduWlanAPI, nduWlanTypes, nduWinDot11;


function TForm1.GetBSSID(clientHandle: THandle;
                         interfaceGuid: TGUID;
                         pSSID: Pndu_DOT11_SSID = nil;
                         SSID_Type : Tndu_DOT11_BSS_TYPE = dot11_BSS_type_any;
                         SecurityEnabled: boolean = true): string;
var
  //used to determin if the interface is connected
  pData       : Pndu_WLAN_INTERFACE_STATE;
  isConnected : boolean;
  //used to extract a list of BSSIDs for a given interface
  pWlanBssList : Pndu_WLAN_BSS_LIST;

  lastError     : DWORD;
  pdwDataSize   : DWORD;
  items,
  itemIndex:    Integer;
begin
  pData := nil;
  pdwDataSize := 0;
  isConnected := False;

  //check if the interface is connected
  lastError := WlanQueryInterface(clientHandle,
                                 @interfaceGuid,
                                 wlan_intf_opcode_interface_state,
                                 nil,
                                 @pdwDataSize,
                                 @pData,
                                 nil);
    if (lastError = ERROR_SUCCESS) then
    begin
     //isConnected := (Tndu_WLAN_INTERFACE_STATE(pData^.isState) = Tndu_WLAN_INTERFACE_STATE.wlan_interface_state_connected);
     isConnected := (pData^ = Tndu_WLAN_INTERFACE_STATE.wlan_interface_state_connected);
    end
    else
      DisplayError('Error in WlanQueryInterface() function', lastError);

  if isConnected then
  begin
    pWlanBssList := nil;

    lastError := WlanGetNetworkBssList(clientHandle,
                                       @interfaceGuid,
                                       pSSID,
                                       SSID_Type,
                                       SecurityEnabled,
                                       nil,
                                       @pWlanBssList);

    try

      if (lastError = ERROR_SUCCESS) then
      begin

        items := pWlanBssList^.dwNumberOfItems;
        for itemIndex := 0 to items-1 do
        begin

          Result := (Format('%.2x:%.2x:%.2x:%.2x:%.2x:%.2x', [
                   pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[0],
                   pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[1],
                   pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[2],
                   pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[3],
                   pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[4],
                   pWlanBssList^.wlanBssEntries[itemIndex].dot11Bssid[5]]));

        end;
      end
      else
        DisplayError('Error in the WlanGetNetworkBssList() function call', lastError);

    finally
      if pData<>nil then
        WlanFreeMemory(pData);

      if pWlanBssList<>nil then
        WlanFreeMemory(pWlanBssList);
    end;
  end;
end;

Что называется следующим образом:

function TForm1.ScanWifi(): THandle;
const
  WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_ADHOC_PROFILES = $00000001;
var
  hClient              : THandle;
  dwVersion            : DWORD;
  lastError            : DWORD;
  pInterface           : Pndu_WLAN_INTERFACE_INFO_LIST;
  i                    : Integer;
  j                    : Integer;
  pAvailableNetworkList: Pndu_WLAN_AVAILABLE_NETWORK_LIST;
  interfaceGuid        : TGUID;
  BSSID                : string;
begin
  lastError:=WlanOpenHandle(NDU_WLAN_API_VERSION, nil, @dwVersion, @hClient);
  if  lastError<> ERROR_SUCCESS then
  begin
     //DisplayError('Error in the WlanOpenHandle() function call', lastError);
     Result := 0;
     Exit;
  end;

  //L(Format('Requested WLAN interface version [%d], negotiated version [%d]', [NDU_WLAN_API_VERSION, dwVersion]));
  Result := hClient;

  try

      lastError:=WlanEnumInterfaces(hClient, nil, @pInterface);

      try
        if  lastError<> ERROR_SUCCESS then
        begin
           //DisplayError('Errorin the WlanEnumInterfaces() function call', lastError);
           Exit;
        end;

        for i := 0 to pInterface^.dwNumberOfItems - 1 do
        begin
          interfaceGuid:= pInterface^.InterfaceInfo[i].InterfaceGuid;

          lastError:=WlanGetAvailableNetworkList(hClient,
                                                 @interfaceGuid,
                                                 WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_ADHOC_PROFILES,
                                                 nil,
                                                 pAvailableNetworkList);

          try
            if  lastError<> ERROR_SUCCESS then
            begin
               //DisplayError('Error WlanGetAvailableNetworkList', lastError);

               Exit;
            end
            else
            begin
              for j := 0 to pAvailableNetworkList^.dwNumberOfItems - 1 do
              Begin

                 BSSID := GetBssid(hClient,
                                   interfaceGuid,
                                   @pAvailableNetworkList^.Network[j].dot11Ssid,
                                   pAvailableNetworkList^.Network[j].dot11BssType,
                                   pAvailableNetworkList^.Network[j].bSecurityEnabled
                 );

                 //FAPList.AddOrSetValue(BSSID,J);

              end;
            end;

          finally
            if pAvailableNetworkList <> nil then
              WlanFreeMemory(pAvailableNetworkList);
          end;

        end;
      finally
        if pInterface <> nil then
          WlanFreeMemory(pInterface);
      end;


  finally
    WlanCloseHandle(FhClient, nil);
  end;

end;

При сравнении данных между двумя приложениями единственное различие заключается в результате (pWlanBssList), как показано здесь (left=console, right=VCL):

1 ответ

Решение

Похоже, ошибка компилятора в логическом преобразовании, проблема заключается в следующей строке в коде VCL

SecurityEnabled: boolean = true

вам нужно изменить его на

SecurityEnabled: bool = true
Другие вопросы по тегам