WlanAPI WlanGetNetworkBssList 返回无效数据

WlanAPI WlanGetNetworkBssList returning invalid data

我因调用 WlanGetNetworkBssList 而陷入调试工作,希望得到一些指示。我的目标 objective 是构建一个 Wifi scanner/profiler 工具来帮助我解决远程站点上的网络问题。

我正在使用 Windows 本机 Wifi API(link) and Delphi/Pascal interface found here 在 Windows 10 (VCL) 下使用 Delphi Berlin 10.1 Update 2。

我从一个简单粗暴的测试应用程序 (VCL) 开始,以了解 API 和 运行 在调用 WlanGetNetworkBssList 时遇到的问题,因此我创建了一个小型控制台应用程序专注于那个问题。问题是它在命令提示符下的控制台应用程序 运行 中有效,但在我的 VCL 测试应用程序中无效。这些函数几乎等同于复制粘贴,并排显示代码,除了来自 WlanGetNetworkBssList 调用 (pWlanBssList)

的 return 数据外,数据是相同的

问题:由于调用是对外部 DLL 的调用,我可以采取哪些步骤来进一步调试它并了解 VCL 和控制台应用程序之间的区别。

注意:WlanGetNetworkBssList 有两种操作模式,其中可以提供 SSID 以获取该特定 SSID 的 BSSID(接入点的MAC)。通过传递 NULL 而不是 SSID,API 将 return 所有 AP 的 BSSID。传递 NULL 适用于 VLC 和控制台应用程序。当请求特定的 SSID 时中断。经验证,SSID 数据结构在两个应用程序中是相同的,但数据缓冲区 returned 在 VCL 应用程序中无效。怎么会这样?

控制台应用程序:

program CWifiScan;

{$APPTYPE CONSOLE}

uses
  Windows,
  System.SysUtils,
  nduWlanAPI,
  nduWlanTypes;
const
  WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_ADHOC_PROFILES = [=10=]000001;
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 = [=12=]000001;
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),如下所示(左=控制台,右=VCL):

看起来像是布尔转换中的编译器错误,问题出在 VCL 代码中的以下行

SecurityEnabled: boolean = true

您需要将其更改为

SecurityEnabled: bool = true