Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use "Native Wifi API" Windows API functions with Delphi

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

like image 203
Vitim.us Avatar asked Dec 10 '22 02:12

Vitim.us


1 Answers

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,
like image 163
David Heffernan Avatar answered Mar 07 '23 10:03

David Heffernan