Come utilizzare le funzioni API di Windows "Native WiFi API" con Delphi
Domanda
Sto cercando di utilizzare una funzione di Windows API su Delphi, funzioni per Windows wlanapi.dll (API WiFi nativo)
DWORD WINAPI WlanOpenHandle(
__in DWORD dwClientVersion,
__reserved PVOID pReserved,
__out PDWORD pdwNegotiatedVersion,
__out PHANDLE phClientHandle
);
WlanhostednetworkQueryProperty
DWORD WINAPI WlanHostedNetworkQueryProperty(
__in HANDLE hClientHandle,
__in WLAN_HOSTED_NETWORK_OPCODE OpCode,
__out PDWORD pdwDataSize,
__out PVOID *ppvData,
__out PWLAN_OPCODE_VALUE_TYPE *pWlanOpcodeValueType,
__reserved PVOID pvReserved
);
Sto cercando di usare queste funzioni e altre per ore, leggendo i riferimenti MSDN e altri siti, ma non riesco proprio a farlo funzionare.
Il mio tentativo
type
TWlanOpenHandle = function( dwClientVersion:DWORD;
pReserved:Pointer;
pdwNegotiatedVersion:PDWORD;
phClientHandle:PHANDLE
):DWORD; stdcall;
function apiWlanOpenHandle( dwClientVersion:DWORD;
pReserved:Pointer;
pdwNegotiatedVersion:PDWORD;
phClientHandle:PHANDLE
):DWORD;
implementation
function apiWlanOpenHandle ( dwClientVersion:DWORD; pReserved:Pointer; pdwNegotiatedVersion:PDWORD; phClientHandle:PHANDLE ):DWORD;
var
WlanOpenHandle: TWlanOpenHandle;
DLL: Cardinal;
begin
DLL:=LoadLibrary('Wlanapi.dll');
WlanOpenHandle := GetProcAddress(DLL, 'WlanOpenHandle');
if Assigned(WlanOpenHandle) then
begin
WlanOpenHandle(dwClientVersion, pReserved, pdwNegotiatedVersion, phClientHandle);
end
else begin
ShowMessage('Function not found');
end;
end;
Sto cercando di tradurre questa API, sembra un sacco di lavoro e sono solo un principiante a Delphi, ho letto un sacco di cose sul web, come faccio a gestire questo OpCode
Parametro, sembra una struttura C con costanti e pwlan_opcode_value_type?
http://msdn.microsoft.com/en-us/library/windows/desktop/dd439502(v=vs.85).aspx
Soluzione
In realtà non hai mostrato come hai chiamato apiWlanOpenHandle
Il che, credo, spiegherebbe qual è il problema. Tuttavia, c'è un errore molto comune che è molto probabilmente ciò che ti sta confondendo.
Considera la dichiarazione C dell'API:
DWORD WINAPI WlanOpenHandle(
__in DWORD dwClientVersion,
__reserved PVOID pReserved,
__out PDWORD pdwNegotiatedVersion,
__out PHANDLE phClientHandle
);
I parametri che sospetto ti stiano causando problemi sono gli ultimi due. Lasciaci considerare pdwNegotiatedVersion
. Questo è un puntatore a un DWORD
. Poiché questo è un parametro Out, è necessario fornire un puntatore alla memoria valida. Sospetto che tu stia solo dichiarando una variabile di tipo PDWORD
e passando quello.
var
NegotiatedVersionPtr: PDWORD;
begin
WlanOpenHandle(...., NegotiatedVersionPtr, ...);
La funzione WlanOpenHandle
Quindi differenze quel puntatore e cerca di scrivere alla memoria. Se non hai dato un puntatore valido, questo fallirà.
La soluzione ingenua è cambiare il codice chiamante per assomigliare a questo:
var
NegotiatedVersion: DWORD;
NegotiatedVersionPtr: PDWORD;
begin
NegotiatedVersionPtr := @NegotiatedVersion;
WlanOpenHandle(...., NegotiatedVersionPtr, ...);
Funzionerà ma c'è un modo molto più pulito. Dichiarare l'importazione dell'API in questo modo:
function WlanOpenHandle(
dwClientVersion: DWORD;
pReserved: Pointer;
out NegotiatedVersion: DWORD;
out ClientHandle: THandle
): DWORD; stdcall; external 'Wlanapi.dll';
Un out
parametro di tipo DWORD
è effettivamente passato come puntatore al DWORD
che fornisci come argomento alla chiamata della funzione. Puoi quindi modificare il tuo codice di chiamata per assomigliare a questo:
var
ReturnValue: DWORD;
NegotiatedVersion: DWORD;
ClientHandle: THandle;
begin
ReturnValue := WlanOpenHandle(2, nil, NegotiatedVersion, ClientHandle);
if ReturnValue<>ERROR_SUCCESS then
//respond to error
Nota che ho anche aggiunto un controllo degli errori che dovresti davvero fare.
Il motivo per cui la funzione API di Windows viene dichiarata usando i puntatori è che la lingua C supporta solo i parametri che passano per valore. Semplicemente non ha pass per riferimento, cioè out
o var
In termini di Delphi. Le lingue che supportano il passaggio pass-by-reference dovrebbero farne uso quando possono.
Alcune funzioni API di Windows hanno parametri opzionali dichiarati come puntatori. Quando questo è il caso che passa NULL
Poiché il puntatore è il modo per segnalare che non si desidera passare un parametro. Tradurre quelle API in Delphi è più complesso. È necessario implementare una versione utilizzando i puntatori per consentire ai chiamanti di rinunciare alla fornitura del parametro. Ma può essere utile fornire una versione sovraccarica che utilizza out
o var
per comodità al chiamante. Il Delphi Windows
L'unità contiene molti di questi esempi.
Quanto a WlanHostedNetworkQueryProperty
, Lo dichiarerei così:
const
// WLAN_HOSTED_NETWORK_OPCODE constants
wlan_hosted_network_opcode_connection_settings = 0;
wlan_hosted_network_opcode_security_settings = 1;
wlan_hosted_network_opcode_station_profile = 2;
wlan_hosted_network_opcode_enable = 3;
// WLAN_OPCODE_VALUE_TYPE constants
wlan_opcode_value_type_query_only = 0;
wlan_opcode_value_type_set_by_group_policy = 1;
wlan_opcode_value_type_set_by_user = 2;
wlan_opcode_value_type_invalid = 3;
function WlanHostedNetworkQueryProperty(
hClientHandle: THandle;
OpCode: Integer;
out DataSize: DWORD;
out Data: Pointer;
out WlanOpcodeValueType: Integer;
Reserved: Pointer
): DWORD; external 'Wlanapi.dll' delayed;
Ho usato il delayed
struttura perché si tratta di un'API di Windows 7 e UP. Presumibilmente vorrai che il tuo programma venga eseguito sulle versioni precedenti di Windows e quindi è necessario il caricamento del ritardo. Per ulteriori informazioni sul caricamento del ritardo in Delphi, vedere questa risposta, e in particolare i collegamenti successivi.
Si noti che la documentazione nell'argomento MSDN a cui si collega non è corretta. Il pWlanOpcodeValueType
Il parametro è dichiarato erroneamente nell'argomento MSDN. La definizione corretta, quella che si trova in wlanpi.h
è questo:
__out PWLAN_OPCODE_VALUE_TYPE pWlanOpcodeValueType,