Как использовать функции Windows API "Native Wifi API" в Delphi
Я пытаюсь использовать функцию из Windows API на Delphi, функции для Windows Wlanapi.dll (собственный WIFI API)
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 ответ
Вы на самом деле не показали, как вы звонили 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
для удобства звонящего. Дельфы 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,