【问题标题】:Why does this code works inside a button, and not inside a single procedure?为什么此代码在按钮内工作,而不是在单个过程内工作?
【发布时间】:2012-03-03 03:50:10
【问题描述】:

我正在将 Native WiFi API 的 WinAPI 转换为 delphi,并在按钮内编写了一个 rotine 进行测试,它工作正常。但不是在程序中工作,我不知道为什么,因为我只是复制和粘贴。

这段代码可以正常工作

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'; 它可以工作!而且我仍然不知道为什么,可能与指针和内存溢出有关。**

【问题讨论】:

  • 请显示调用setSSID()的代码。你要传递什么给text
  • @RemyLebeau-TeamB 编辑了我的问题,但我基本上从同一个按钮调用,我只是 CTRL+X 代码和 CTRL+V 在外部函数上并从该按钮调用。神秘地不起作用。
  • 该 API 函数的 MSDN 文档不正确。请参阅文档底部的我的评论。这可能是问题所在。您能否将您的 WlanHostedNetworkQueryProperty 声明添加到问题中,然后我们将能够解决问题。哦,类型定义也会有所帮助。
  • 你还有兴趣解决这个问题吗?
  • 其实,我刚刚回头看了你之前的问题,发现了这个:stackoverflow.com/questions/9344980/… 难怪这个问题似曾相识。我不明白您为什么按照您的方式翻译 API 函数。我敦促您重新阅读我对您之前问题的回答并遵循该建议。

标签: delphi winapi pointers stack-overflow access-violation


【解决方案1】:

WlanHostedNetworkQueryProperty 函数的文档指出,当您调用它时,pData 指针必须设置为 nil。您根本没有初始化它,所以它可能是也可能不是,这取决于堆栈的状态。您需要添加以下行:

pData := nil;

在通话之前。

您可能想要初始化所有参数。

(抱歉格式错误,在手机上尝试这样做很难!)

【讨论】:

  • 尝试了 niling 一切,但我总是遇到访问冲突,但如果我不使用参数中的 name:=text;,请使用静态字符串,而不是像 name:='test';,工作就像一个魅力。并且没有错误
  • 这只是告诉我你有堆栈损坏。我坚信 API 调用正在覆盖堆栈。 David 认为函数定义不正确的建议似乎最有可能。
【解决方案2】:

在另一个问题的帮助下,我实际上解决了这个问题。

访问冲突是由delphi的正常行为引起的。

Delphi 字符串的内存管理有点不寻常。在你之后 调用 myFunc(text),并分配 textcopy := mytext,所有三个变量 (text, mytext 和 textcopy) 将指向同一个地址,即 的原始字符串。

但是,只要您使用其中一个变量来更改 字符串,Delphi 在幕后克隆字符串,以及您的更改 应用于副本。其他两个变量仍然指向 原始的,所以它们保持不变。所以在上下文 2 中所做的任何更改 不会在上下文 1 中看到 - 这种“写时复制”机制 有效地为您提供按值传递的语义。所有这些字符串 被引用计数,并且将被自动释放一次 引用超出范围。

但是,有一个例外如果您使用 指针,而不是字符串操作,您将绕过复制 步骤,您的更改将影响原始文件。您还将绕过 引用计数逻辑,并且可能以指向 已释放的内存块。这可能是您访问的原因 违规,但我不能说没有更多细节/更多代码。

如果您想要引用传递,请将您的函数声明为 myFunc(var mytext:字符串)。如果你想强制 Delphi 复制字符串, 而不是等到它被修改,你可以使用 System.UniqueString。

原答案https://stackoverflow.com/a/9543812/938822

【讨论】:

  • 这与问题无关。
猜你喜欢
  • 2011-03-01
  • 1970-01-01
  • 2022-10-02
  • 2021-11-01
  • 2011-09-01
  • 2021-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多