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