Почему этот код работает внутри кнопки, а не внутри одной процедуры? - PullRequest
0 голосов
/ 03 марта 2012

Я перевожу WinAPI Native WiFi API в delphi, и я написал ротин для показа внутри кнопки, и это сработало. Но не работает внутри процедуры, и я не могу понять ПОЧЕМУ, потому что я только что скопировал и вставил.

Это точно код РАБОТАЕТ

procedure TForm1.Button1Click(Sender: TObject);
var
nVersion:DWORD;
clientHandle:HWND;
return:DWORD;
size:DWORD;
pdata:pWLAN_HOSTED_NETWORK_CONNECTION_SETTINGS;
vtype:pWLAN_OPCODE_VALUE_TYPE;
pfail:PWLAN_HOSTED_NETWORK_REASON;
ssid:array[0..DOT11_SSID_MAX_LENGTH] of UCHAR;
name:String;
begin
    return:=WlanOpenHandle(2,nil,@nVersion,@clientHandle);
    return:=WlanHostedNetworkQueryProperty(clientHandle,wlan_hosted_network_opcode_connection_settings,@size,@pdata,@vtype,nil);
    if return<>ERROR_SUCCESS then ShowMessage('Returned ERROR '+ IntToStr(return));

  name:=Edit1.Text;
    StrCopy(@pdata.hostedNetworkSSID.ucSSID, @name[1]);
    pdata.hostedNetworkSSID.uSSIDLength:=Length(name);

    return:=WlanOpenHandle(2,nil,@nVersion,@clientHandle);
    return:=WlanHostedNetworkSetProperty(clientHandle,wlan_hosted_network_opcode_connection_settings,size,pdata,@pfail,nil);
    if return<>ERROR_SUCCESS then ShowMessage('Returned ERROR '+ IntToStr(return));
end;

но если поместить этот код в другую процедуру, чтобы очистить код и вызвать функцию внутри кнопки, это НЕ РАБОТАЕТ!

procedure setSSID(text:String);
var
nVersion:DWORD;
clientHandle:HWND;
return:DWORD;
size:DWORD;
pdata:pWLAN_HOSTED_NETWORK_CONNECTION_SETTINGS;
vtype:pWLAN_OPCODE_VALUE_TYPE;
pfail:PWLAN_HOSTED_NETWORK_REASON;
ssid:array[0..DOT11_SSID_MAX_LENGTH] of UCHAR;
name:String;
begin
    return:=WlanOpenHandle(2,nil,@nVersion,@clientHandle);
    return:=WlanHostedNetworkQueryProperty(clientHandle,wlan_hosted_network_opcode_connection_settings,@size,@pdata,@vtype,nil);
    if return<>ERROR_SUCCESS then ShowMessage('Returned ERROR' + IntToStr(return)); <<<<<< RETURNING ERROR 1734

  name:=text;
    StrCopy(@pdata.hostedNetworkSSID.ucSSID, @name[1]);
    pdata.hostedNetworkSSID.uSSIDLength:=Length(name);

    return:=WlanOpenHandle(2,nil,@nVersion,@clientHandle);
    return:=WlanHostedNetworkSetProperty(clientHandle,wlan_hosted_network_opcode_connection_settings,size,pdata,@pfail,nil);
    if return<>ERROR_SUCCESS then ShowMessage('Returned ERROR '+ IntToStr(return));
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
    setSSID('test');
end;

Я получаю ошибку 1734 в выделенной строке и после того, как получаю Access violation at address 004084D0 in module Project1.exe. Write of address 000000000.

Я просто не могу найти никаких проблем, потому что это точно такой же код!

function WlanHostedNetworkQueryProperty(
  hClientHandle:HANDLE;
  OpCode:WLAN_HOSTED_NETWORK_OPCODE;
  pdwDataSize:PDWORD;
  ppvData:PPVOID;
  pWlanOpcodeValueType:PWLAN_OPCODE_VALUE_TYPE;
  pvReserved:PVOID
):DWORD; stdcall; external 'Wlanapi.dll';


function WlanHostedNetworkSetProperty(
  hClientHandle:HANDLE;
  OpCode:WLAN_HOSTED_NETWORK_OPCODE;
  dwDataSize:DWORD;
  pvData:PVOID;
  pFailReason:PWLAN_HOSTED_NETWORK_REASON;
  pvReserved:PVOID
):DWORD; stdcall; external 'Wlanapi.dll';

** OBS: если я изменю строку name:=text; на name:='hello';, это сработает! И я до сих пор не знаю, почему, возможно, что-то связано с указателями и переполнением памяти. **

Ответы [ 2 ]

6 голосов
/ 03 марта 2012

В документации для функции WlanHostedNetworkQueryProperty говорится, что указатель pData должен быть установлен равным нулю при вызове.Вы вообще его не инициализируете, поэтому может быть или не быть , в зависимости от состояния стека.Вам необходимо добавить строку:

pData: = nil;

перед вызовом.

Возможно, вы захотите инициализировать все ваши параметры.

(Извините за плохое форматирование, попытаться сделать это на телефоне сложно!)

0 голосов
/ 04 марта 2012

Я действительно решил вопрос с помощью другого вопроса.

Нарушение прав доступа было вызвано нормальным поведением delphi.

Управление памятью для строк Delphi немного необычно. После Вас вызовите myFunc (текст) и назначьте textcopy: = mytext, все три переменные (текст, mytext и textcopy) будет указывать на тот же адрес, что исходной строки.

Но как только вы используете одну из этих переменных, чтобы внести изменения в строка, Delphi клонирует строку за кулисами и ваши изменения применяются к копии. Две другие переменные по-прежнему указывают на оригинал, поэтому они остаются неизменными. Так что любые изменения, сделанные в контексте 2 не будет рассматриваться в контексте 1 - этот механизм копирования при записи эффективно дает вам семантику передачи по значению. Все эти строки считаются ссылками и будут автоматически освобождены после того, как все ссылки выходят за рамки.

Однако, есть исключение . Если вы получаете доступ к строке, используя указатели , а не строковые операции, вы будете обходить копирование шаг и ваши изменения повлияют на оригинал. Вы также обойдете логика подсчета ссылок, и потенциально заканчивается указателем на освобожденный блок памяти . Это может быть причиной вашего доступа нарушение, но я не могу сказать без более подробной информации / больше кода.

Если вы хотите передать ссылку, объявите вашу функцию как myFunc (var mytext: String). Если вы хотите заставить Delphi скопировать строку, вместо того, чтобы ждать, пока он не будет изменен, вы можете использовать System.UniqueString.

Оригинальный ответ https://stackoverflow.com/a/9543812/938822

...