Как использовать функции Windows API "Native Wifi API" в Delphi - PullRequest
4 голосов
/ 19 февраля 2012

Я пытаюсь использовать функцию из Windows API на delphi, функции для Windows Wlanapi.dll (собственный 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
);

Я пытаюсь использовать эти и другие функции часами, читая ссылки на MSDN и другие сайты, но я просто не могу заставить это работать.

Мойпопытка

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;

Я пытаюсь перевести этот API, кажется, много работы, и я только начинающий в Delphi, я много читаю в Интернете, как мне справиться сэтот OpCode параметр, похоже, структура C с константами, и PWLAN_OPCODE_VALUE_TYPE?

http://msdn.microsoft.com/en-us/library/windows/desktop/dd439502(v=vs.85).aspx

1 Ответ

14 голосов
/ 19 февраля 2012

Вы на самом деле не показали, как звонили apiWlanOpenHandle, что, я думаю, объяснило бы, в чем проблема. Однако есть одна очень распространенная ошибка, которая скорее всего вас смущает.

Рассмотрим декларацию C API:

DWORD WINAPI WlanOpenHandle(
  __in        DWORD dwClientVersion,
  __reserved  PVOID pReserved,
  __out       PDWORD pdwNegotiatedVersion,
  __out       PHANDLE phClientHandle
);

Последние два параметра, которые, как я подозреваю, вызывают у вас проблемы. Давайте рассмотрим pdwNegotiatedVersion. Это указатель на DWORD. Поскольку это выходной параметр, вы должны указать указатель на действительную память. Я подозреваю, что вы просто объявляете переменную типа PDWORD и передаете ее.

var
  NegotiatedVersionPtr: PDWORD;
begin
  WlanOpenHandle(...., NegotiatedVersionPtr, ...);

Функция WlanOpenHandle затем отменяет ссылку на этот указатель и пытается записать в память. Если вы не указали действительный указатель, произойдет сбой.

Наивное решение состоит в том, чтобы изменить вызывающий код так:

var
  NegotiatedVersion: DWORD;
  NegotiatedVersionPtr: PDWORD;
begin
  NegotiatedVersionPtr := @NegotiatedVersion;
  WlanOpenHandle(...., NegotiatedVersionPtr, ...);

Это будет работать, но есть намного более чистый способ. Объявите импорт API следующим образом:

function WlanOpenHandle(
    dwClientVersion: DWORD;
    pReserved: Pointer;
    out NegotiatedVersion: DWORD;
    out ClientHandle: THandle
): DWORD; stdcall; external 'Wlanapi.dll';

Параметр out типа DWORD фактически передается как указатель на DWORD, который вы указываете в качестве аргумента для вызова функции. Затем вы можете изменить свой код вызова так, чтобы он выглядел следующим образом:

var
  ReturnValue: DWORD;
  NegotiatedVersion: DWORD;
  ClientHandle: THandle;
begin
  ReturnValue := WlanOpenHandle(2, nil, NegotiatedVersion, ClientHandle);
  if ReturnValue<>ERROR_SUCCESS then
    //respond to error

Обратите внимание, что я также добавил некоторые проверки ошибок, которые вы действительно должны делать.

Причина, по которой функция API Windows объявляется с помощью указателей, заключается в том, что язык C поддерживает только передачу параметров по значению. У него просто нет передачи по ссылке, то есть out или var в терминах Delphi. Языки, поддерживающие передачу по ссылке, должны использовать их, когда могут.

Некоторые функции Windows API имеют необязательные параметры, объявленные как указатели. В этом случае передача NULL в качестве указателя - это способ указать, что вы не хотите передавать параметр. Перевод этих API в Delphi более сложен. Вам нужно реализовать версию, используя указатели, чтобы позволить вызывающим абонентам отказаться от предоставления параметра. Но может быть полезно предоставить перегруженную версию, которая использует out или var для удобства звонящего. Модуль Delphi Windows содержит много таких примеров.


Что касается WlanHostedNetworkQueryProperty, я бы сказал так:

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;

Я использовал delayed, потому что это Windows 7 и выше API. Вероятно, вы захотите, чтобы ваша программа работала на более старых версиях Windows, поэтому необходима задержка загрузки. Для получения дополнительной информации о задержке загрузки в Delphi см. этот ответ и, в частности, дальнейшие ссылки.

Обратите внимание, что документация в теме MSDN, на которую вы ссылаетесь, неверна. Параметр pWlanOpcodeValueType объявлен неправильно в теме MSDN. Правильное определение, которое можно найти в wlanpi.h, таково:

__out    PWLAN_OPCODE_VALUE_TYPE     pWlanOpcodeValueType,
...