MiTec/MSICS/MSI_WiFi.pas
2024-07-06 22:30:25 +02:00

471 lines
15 KiB
ObjectPascal

{*******************************************************}
{ MiTeC System Information Component Suite }
{ WI-FI Detection Part }
{ version 14.0.0 }
{ }
{ Copyright (c) 1997-2021 Michal Mutl }
{ }
{*******************************************************}
{$INCLUDE Compilers.inc}
unit MSI_WIFI;
interface
uses {$IFDEF RAD9PLUS}
WinAPI.Windows, System.SysUtils, System.Classes,
WinAPI.ActiveX, System.Win.ComObj, MiTeC_SS,
{$ELSE}
Windows, SysUtils, Classes, ActiveX, ComObj, MiTeC_SS,
{$ENDIF}
MiTeC_WLANAPI,
MSI_Common, MSI_Defs;
const
StorageFolderName = 'WiFi';
type
TWiFiInterface = record
Name: string;
GUID: string;
end;
TWiFiNetwork = record
ID: Int64;
Intf: TWiFiInterface;
Profile,
SSID: string;
SignalQuality: Cardinal;
AuthAlgorithm: TDOT11_AUTH_ALGORITHM;
CipherAlgorithm: TDOT11_CIPHER_ALGORITHM;
PHYType: TDOT11_PHY_TYPE;
BSSType: TDOT11_BSS_TYPE;
SecurityEnabled,
Connectable,
Connected: Boolean;
MACAddress: string;
MaxSpeed, //Mbps
ChannelFreq: Cardinal; //kHz
RSSI: Integer; //dBm
end;
TWiFi = array of TWiFiNetwork;
{$IFDEF RAD9PLUS} [ComponentPlatformsAttribute(pidWin32 or pidWin64)] {$ENDIF}
TMiTeC_WiFi = class(TMiTeC_Component)
private
FData: TWiFi;
FCached: Boolean;
function GetCount: Integer;
function GetRecord(AIndex: Integer): TWifiNetwork;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Clear; override;
procedure RefreshData(AScanObjects: TScanObjects = soAll); override;
procedure SaveToStorage(const AFilename: string; var AWriteHeader: Boolean; AFormat: integer = 0; const AComment: string=''; ACodeStream: TCodeStreamProcedure = nil); override;
function LoadFromStorage(const AFilename: string; var AReadHeader: boolean; ACodeStream: TCodeStreamProcedure = nil): boolean; override;
function GetConnectedNetwork: Integer;
function GetConnectedNetworkName(AIncludeFreq: Boolean = False): string;
property Networks[AIndex: Integer]: TWifiNetwork read GetRecord;
published
property NetworkCount: Integer read GetCount;
property Cached: Boolean read FCached write FCached default False;
end;
function AuthToStr(Value :TDOT11_AUTH_ALGORITHM): string;
function CipherToStr(Value :TDOT11_CIPHER_ALGORITHM): string;
function PHYToStr(Value :TDOT11_PHY_TYPE): string;
function BSSToStr(Value :TDOT11_BSS_TYPE): string;
function GetChannelNumber(AChannelFreq: Cardinal): Cardinal;
implementation
uses MiTeC_CommonDefs, MiTeC_CRC;
function AuthToStr(Value :TDOT11_AUTH_ALGORITHM): string;
begin
Result:='';
case Value of
DOT11_AUTH_ALGO_80211_OPEN : Result:='80211 Open';
DOT11_AUTH_ALGO_80211_SHARED_KEY : Result:='80211 Shared Key';
DOT11_AUTH_ALGO_WPA : Result:='WPA';
DOT11_AUTH_ALGO_WPA_PSK : Result:='WPA-PSK';
DOT11_AUTH_ALGO_WPA_NONE : Result:='WPA-NONE';
DOT11_AUTH_ALGO_RSNA : Result:='RSNA';
DOT11_AUTH_ALGO_RSNA_PSK : Result:='RSNA-PSK';
DOT11_AUTH_ALGO_IHV_START : Result:='IHV-START';
DOT11_AUTH_ALGO_IHV_END : Result:='IHV-END';
end;
end;
function CipherToStr(Value :TDOT11_CIPHER_ALGORITHM): string;
begin
Result:='';
case Value of
DOT11_CIPHER_ALGO_NONE : Result:='None';
DOT11_CIPHER_ALGO_WEP40 : Result:='WEP40';
DOT11_CIPHER_ALGO_TKIP : Result:='TKIP';
DOT11_CIPHER_ALGO_CCMP : Result:='CCMP';
DOT11_CIPHER_ALGO_WEP104 : Result:='WEP104';
DOT11_CIPHER_ALGO_WPA_USE_GROUP : Result:='WPA Use Group Key / RSN Use Group Key';
DOT11_CIPHER_ALGO_WEP : Result:='WEP';
DOT11_CIPHER_ALGO_IHV_START : Result:='IHV-START';
DOT11_CIPHER_ALGO_IHV_END : Result:='IHV-END';
end;
end;
function PHYToStr(Value :TDOT11_PHY_TYPE): string;
begin
Result:='';
case Value of
dot11_phy_type_unknown : Result:='Unknown';
dot11_phy_type_fhss : Result:='FHSS';
dot11_phy_type_dsss : Result:='DSSS';
dot11_phy_type_irbaseband : Result:='IR';
dot11_phy_type_ofdm : Result:='802.11a';
dot11_phy_type_hrdsss : Result:='High-rate DSSS';
dot11_phy_type_erp : Result:='IEEE 802.11g';
dot11_phy_type_ht : Result:='IEEE 802.11n';
dot11_phy_type_vht : Result:='IEEE 802.11ac';
dot11_phy_type_IHV_start : Result:='IHV-START';
dot11_phy_type_IHV_end : Result:='IHV-END';
end;
end;
function BSSToStr(Value :TDOT11_BSS_TYPE): string;
begin
Result:='';
case Value of
dot11_BSS_type_infrastructure : Result:='Infrastructure';
dot11_BSS_type_independent : Result:='Independent';
dot11_BSS_type_any : Result:='Any';
end;
end;
function GetChannelNumber;
const
cf: array[1..14] of Cardinal = (2412,2417,2422,2427,2432,2437,2442,2447,2452,2457,2462,2467,2472,2484);
var
i: Integer;
begin
Result:=0;
AChannelFreq:=Round(AChannelFreq/1000);
for i:=14 downto 1 do
if AChannelFreq>=cf[i] then begin
Result:=i;
Break;
end;
end;
{ TMiTeC_WiFi }
procedure TMiTeC_WiFi.Clear;
begin
Finalize(FData);
end;
constructor TMiTeC_WiFi.Create(AOwner: TComponent);
begin
FCached:=False;
inherited;
end;
destructor TMiTeC_WiFi.Destroy;
begin
inherited;
end;
function TMiTeC_WiFi.GetConnectedNetwork: Integer;
var
i: Integer;
begin
Result:=-1;
for i:=0 to High(FData) do
if FData[i].Connected then begin
Result:=i;
Break;
end;
end;
function TMiTeC_WiFi.GetConnectedNetworkName(AIncludeFreq: Boolean = False): string;
var
idx: integer;
begin
Result:='';
idx:=GetConnectedNetwork;
if idx>-1 then begin
Result:=FData[idx].SSID;
if AIncludeFreq then
Result:=Result+Format(' - %1.2f GHz',[FData[idx].ChannelFreq/1000000]);
end;
end;
function TMiTeC_WiFi.GetCount: Integer;
begin
Result:=Length(FData);
end;
function TMiTeC_WiFi.GetRecord(AIndex: Integer): TWifiNetwork;
begin
Result:=FData[AIndex];
end;
function TMiTeC_WiFi.LoadFromStorage(const AFilename: string; var AReadHeader: boolean; ACodeStream: TCodeStreamProcedure): boolean;
var
stg: IStorage;
SS: TStructuredStorage;
Sub: TStructuredStorage;
function ReadFromStream(AIndex: integer): boolean;
var
strm: TStorageStream;
sl: TStringList;
begin
Result:=False;
try strm:=Sub.OpenStream(Format(strm_Item,[AIndex]),STG_READ_INSTORAGE,False) except strm:=nil end;
if strm<>nil then
try
sl:=TStringList.Create;
try
LoadFromEncodedStream(strm,sl,ACodeStream);
SetLength(FData,Length(FData)+1);
with FData[High(FData)] do begin
Intf.Name:=ReadStrProperty(sl,'Interface');
Intf.GUID:=ReadStrProperty(sl,'GUID');
Profile:=ReadStrProperty(sl,'Profile');
SSID:=ReadStrProperty(sl,'SSID');
SignalQuality:=ReadIntProperty(sl,'SignalQuality');
AuthAlgorithm:=TDOT11_AUTH_ALGORITHM(ReadIntProperty(sl,'Authentication'));
CipherAlgorithm:=TDOT11_CIPHER_ALGORITHM(ReadIntProperty(sl,'Security'));
PHYType:=TDOT11_PHY_TYPE(ReadIntProperty(sl,'PHYType'));
BSSType:=TDOT11_BSS_TYPE(ReadIntProperty(sl,'BSSType'));
SecurityEnabled:=ReadIntProperty(sl,'SecurityEnabled')=1;
Connectable:=ReadIntProperty(sl,'Connectable')=1;
Connected:=ReadIntProperty(sl,'Connected')=1;
MACAddress:=ReadStrProperty(sl,'MACAddress');
RSSI:=ReadIntProperty(sl,'RSSI');
MaxSpeed:=ReadIntProperty(sl,'MaxSpeed');
ChannelFreq:=ReadIntProperty(sl,'ChannelFreq');
end;
Result:=True;
SetDataAvail(True);
finally
sl.Free;
end;
finally
strm.Free;
end;
end;
var
i: integer;
begin
Clear;
Result:=inherited LoadFromStorage(AFilename,AReadHeader,ACodeStream);
if StgIsStorageFile(PWideChar(WideString(AFileName)))<>S_OK then
Exit;
OleCheck(StgOpenStorage(PWideChar(WideString(AFileName)),nil,STG_READ_INSTORAGE,nil,LongInt(nil),stg));
SS:=TStructuredStorage.Create(nil,stg);
try
Result:=False;
try
Sub:=SS.OpenSubStorage(StorageFolderName,STG_READ_INSTORAGE,False);
except
Sub:=nil;
end;
if Assigned(Sub) then begin
i:=0;
while ReadFromStream(i) do
Inc(i);
Result:=Result or (i>0);
SetDataAvail(Result);
end;
finally
if Sub<>nil then
Sub.Free;
SS.Free;
end;
end;
procedure TMiTeC_WiFi.RefreshData(AScanObjects: TScanObjects);
var
h: THandle;
v,res,ms: Cardinal;
r: TWiFiNetwork;
iil: PWLAN_INTERFACE_INFO_LIST;
i,j,k: Integer;
anl: PWLAN_AVAILABLE_NETWORK_LIST;
IntfGuid: PGUID;
bssl: PWLAN_BSS_LIST;
s: string;
idx,n: Integer;
begin
inherited;
if not FCached then
Clear;
{$R-}
res:=WlanOpenHandle(1,nil,@v,@h);
try
if res<>ERROR_SUCCESS then
Exit;
res:=WlanEnumInterfaces(h,nil,@iil);
if (res<>ERROR_SUCCESS) or (iil^.dwNumberOfItems=0) then
Exit;
try
for i:=0 to iil^.dwNumberOfItems-1 do begin
IntfGuid:=@iil^.InterfaceInfo[iil^.dwIndex].InterfaceGuid;
WlanScan(h,IntfGUID,nil,nil,nil);
res:=WlanGetAvailableNetworkList(h,IntfGUID,WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_MANUAL_HIDDEN_PROFILES or WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_ADHOC_PROFILES,nil,anl);
if res=ERROR_SUCCESS then begin
try
for j:=0 to anl^.dwNumberOfItems-1 do begin
ResetMemory(r,SizeOf(r));
r.Intf.Name:=iil^.InterfaceInfo[i].strInterfaceDescription;
r.Intf.GUID:=GUIDToString(iil^.InterfaceInfo[i].InterfaceGuid);
r.Profile:={$IFNDEF UNICODE}WideCharToString{$ENDIF}(anl^.Network[j].strProfileName);
r.SSID:=string(PAnsiChar(@anl^.Network[j].dot11Ssid.ucSSID));
r.SignalQuality:=anl^.Network[j].wlanSignalQuality;
r.AuthAlgorithm:=anl^.Network[j].dot11DefaultAuthAlgorithm;
r.CipherAlgorithm:=anl^.Network[j].dot11DefaultCipherAlgorithm;
r.PHYType:=anl^.Network[j].dot11PhyTypes[0];
r.BSSType:=anl^.Network[j].dot11BssType;
r.SecurityEnabled:=anl^.Network[j].bSecurityEnabled;
r.Connectable:=anl^.Network[j].bNetworkConnectable;
r.Connected:=anl^.Network[j].dwFlags and WLAN_AVAILABLE_NETWORK_CONNECTED = WLAN_AVAILABLE_NETWORK_CONNECTED;
res:=WlanGetNetworkBssList(h,IntfGUID,
@anl^.Network[j].dot11Ssid,
anl^.Network[j].dot11BssType,
anl^.Network[j].bSecurityEnabled,
nil,bssl);
if res=ERROR_SUCCESS then
try
r.MACAddress:='';
for k:=0 to SizeOf(bssl^.wlanBssEntries[0].dot11Bssid)-1 do
r.MACAddress:=r.MACAddress+Format('%2.2x-',[bssl^.wlanBssEntries[0].dot11Bssid[k]]);
SetLength(r.MACAddress,Length(r.MACAddress)-1);
r.MaxSpeed:=0;
n:=bssl^.wlanBssEntries[0].wlanRateSet.uRateSetLength;
if n>DOT11_RATE_SET_MAX_LENGTH then
n:=DOT11_RATE_SET_MAX_LENGTH;
for k:=0 to n-1 do begin
ms:=Round((bssl^.wlanBssEntries[0].wlanRateSet.usRateSet[k] and $7FFF)*0.5);
if ms>r.MaxSpeed then
r.MaxSpeed:=ms;
end;
r.ChannelFreq:=bssl^.wlanBssEntries[0].ulChCenterFrequency;
r.RSSI:=bssl^.wlanBssEntries[0].lRssi;
//r.ID:=bssl^.wlanBssEntries[0].uPhyId;
finally
WlanFreeMemory(bssl);
end;
s:=r.SSID+'_'+r.MACAddress;
r.ID:=CRC64(s);
//if r.ChannelFreq<3000000 then begin
idx:=-1;
if FCached then begin
for k:=0 to High(FData) do begin
if (r.ID=FData[i].ID) and (idx=-1) then
idx:=i;
FData[i].SignalQuality:=0;
end;
end;
if idx=-1 then begin
SetLength(FData,Length(FData)+1);
idx:=High(FData);
end;
FData[idx]:=r;
//end;
end;
finally
WlanFreeMemory(anl);
end;
end;
end;
finally
WlanFreeMemory(iil);
end;
{$R+}
finally
WlanCloseHandle(h,nil);
end;
SetDataAvail(True);
end;
procedure TMiTeC_WiFi.SaveToStorage(const AFilename: string; var AWriteHeader: Boolean; AFormat: integer = 0; const AComment: string=''; ACodeStream: TCodeStreamProcedure = nil);
var
stg: IStorage;
SS: TStructuredStorage;
Sub: TStructuredStorage;
procedure WriteToStream(AIndex: Integer);
var
strm: TStorageStream;
sl: TStringList;
begin
sl:=TStringList.Create;
try
WriteStrProperty(sl,'Interface',Self.Networks[AIndex].Intf.Name);
WriteStrProperty(sl,'GUID',Self.Networks[AIndex].Intf.GUID);
WriteStrProperty(sl,'Profile',Self.Networks[AIndex].Profile);
WriteStrProperty(sl,'SSID',Self.Networks[AIndex].SSID);
WriteIntProperty(sl,'SignalQuality',Self.Networks[AIndex].SignalQuality);
WriteIntProperty(sl,'Authentication',Integer(Self.Networks[AIndex].AuthAlgorithm));
WriteIntProperty(sl,'Security',Integer(Self.Networks[AIndex].CipherAlgorithm));
WriteIntProperty(sl,'PHYType',Integer(Self.Networks[AIndex].PHYType));
WriteIntProperty(sl,'BSSType',Integer(Self.Networks[AIndex].BSSType));
WriteIntProperty(sl,'SecurityEnabled',Integer(Self.Networks[AIndex].SecurityEnabled));
WriteIntProperty(sl,'Connectable',Integer(Self.Networks[AIndex].Connectable));
WriteIntProperty(sl,'Connected',Integer(Self.Networks[AIndex].Connected));
WriteStrProperty(sl,'MACAddress',Self.Networks[AIndex].MACAddress);
WriteIntProperty(sl,'MaxSpeed',Self.Networks[AIndex].MaxSpeed);
WriteIntProperty(sl,'ChannelFreq',Self.Networks[AIndex].ChannelFreq);
WriteIntProperty(sl,'RSSI',Self.Networks[AIndex].RSSI);
strm:=Sub.OpenStream(Format(strm_Item,[AIndex]),STG_OPEN,True);
try
SaveToEncodedStream(sl,strm,ACodeStream);
finally
strm.Free;
end;
finally
sl.Free;
end;
end;
var
i: Integer;
begin
inherited SaveToStorage(AFilename,AWriteHeader,AFormat,AComment,ACodeStream);
if StgIsStorageFile(PWideChar(WideString(AFileName)))<>S_OK then
OleCheck(StgCreateDocFile(PWideChar(WideString(AFileName)),STG_CREATE_OPEN,0,stg))
else
OleCheck(StgOpenStorage(PWideChar(WideString(AFileName)),nil,STG_OPEN,nil,LongInt(nil),stg));
SS:=TStructuredStorage.Create(nil,stg);
try
SS.DeleteElement(StorageFolderName);
Sub:=SS.OpenSubStorage(StorageFolderName,STG_OPEN,True);
try
for i:=0 to Self.NetworkCount-1 do
WriteToStream(i);
finally
Sub.Free;
end;
finally
SS.Free;
end;
end;
end.