Im trying to use a function from Windows API on delphi, functions for Windows Wlanapi.dll (Native WIFI API)
WlanOpenHandle
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
);
I trying to use this functions and others for hours, reading the MSDN references and others sites, but I just can't get this working.
My attempt
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;
I'm trying to translate this API, seems a lot of work, and I'm just a beginner in delphi, I read a lot of stuff on the web, how do I deal with this OpCode
parameter, seems a C Struct with constants, and PWLAN_OPCODE_VALUE_TYPE?
http://msdn.microsoft.com/en-us/library/windows/desktop/dd439502(v=vs.85).aspx
You didn't actually show how you called apiWlanOpenHandle
which would, I think, explain what the problem is. However, there's one very common mistake that is most likely what is confusing you.
Consider the C declaration of the API:
DWORD WINAPI WlanOpenHandle(
__in DWORD dwClientVersion,
__reserved PVOID pReserved,
__out PDWORD pdwNegotiatedVersion,
__out PHANDLE phClientHandle
);
The parameters that I suspect are causing you problems are the final two. Let us consider pdwNegotiatedVersion
. This is a pointer to a DWORD
. Because this is an out parameter you must supply a pointer to valid memory. I suspect you are just declaring a variable of type PDWORD
and passing that.
var
NegotiatedVersionPtr: PDWORD;
begin
WlanOpenHandle(...., NegotiatedVersionPtr, ...);
The function WlanOpenHandle
then de-references that pointer and tries to write to the memory. If you have not given a valid pointer then this will fail.
The naive solution is to change the calling code to look like this:
var
NegotiatedVersion: DWORD;
NegotiatedVersionPtr: PDWORD;
begin
NegotiatedVersionPtr := @NegotiatedVersion;
WlanOpenHandle(...., NegotiatedVersionPtr, ...);
This will work but there is a much cleaner way. Declare the API import like this:
function WlanOpenHandle(
dwClientVersion: DWORD;
pReserved: Pointer;
out NegotiatedVersion: DWORD;
out ClientHandle: THandle
): DWORD; stdcall; external 'Wlanapi.dll';
An out
parameter of type DWORD
is actually passed as a pointer to the DWORD
that you supply as the argument to the function call. You can then change your calling code to look like this:
var
ReturnValue: DWORD;
NegotiatedVersion: DWORD;
ClientHandle: THandle;
begin
ReturnValue := WlanOpenHandle(2, nil, NegotiatedVersion, ClientHandle);
if ReturnValue<>ERROR_SUCCESS then
//respond to error
Note that I have also added some error checking which you really ought to be doing.
The reason that the Windows API function is declared using pointers is that the C language only supports parameter passing by value. It simply does not have pass-by-reference, i.e. out
or var
in Delphi terms. Languages that do support pass-by-reference should make use of them when they can.
Some Windows API functions have optional parameters declared as pointers. When this is the case passing NULL
as the pointer is the way to signal that you do not wish to pass a parameter. Translating those APIs to Delphi is more complex. You need to implement a version using pointers to allow callers to opt-out of supplying the parameter. But it can be helpful to supply an overloaded version that uses out
or var
for convenience to the caller. The Delphi Windows
unit contains many such examples.
As for WlanHostedNetworkQueryProperty
, I would declare it like this:
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;
I have used the delayed
facility because this is a Windows 7 and up API. You will presumably want your program to run on older versions of Windows and so delay loading is needed. For more information on delay loading in Delphi, see this answer, and particularly the onward links.
Note that the documentation in the MSDN topic to which you link is incorrect. The pWlanOpcodeValueType
parameter is declared incorrectly in the MSDN topic. The correct definition, the one to be found in wlanpi.h
is this:
__out PWLAN_OPCODE_VALUE_TYPE pWlanOpcodeValueType,