-1

I'm translating a WinAPI of Native WiFi API to delphi, and I wrote a rotine inside a button to test, and it worked. But is not working inside a procedure, and I can't figure out WHY because I just Copied and Pasted.

This exactly code is WORKING

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;

but if a put this code inside another procedure to make the code clean and call the function inside a button, it does NOT WORK!

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;

I get error 1734 on highlighted line and after I get Access violation at address 004084D0 in module Project1.exe. Write of address 000000000.

I just can't find any problem because is exactly the same code!

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: if I change the line name:=text; to name:='hello'; it works! And I still don't know why, probably something related to pointers and memory overflow.**

Vitim.us
  • 20,746
  • 15
  • 92
  • 109
  • Please show the code that is calling `setSSID()`. What are you passing to `text`? – Remy Lebeau Mar 03 '12 at 05:48
  • @RemyLebeau-TeamB edited my question, but I basically calling from the same button, I just CTRL+X the code and CTRL+V on a outside function and called from that button. Mysteriously doesn't work. – Vitim.us Mar 03 '12 at 05:56
  • 3
    The MSDN documentation for that API function is incorrect. See my comment at the bottom of the documentation. That could be the problem. Could you add your declaration of WlanHostedNetworkQueryProperty to the question and then we'll be able to solve the problem. Oh, and the type definitions would help too. – David Heffernan Mar 03 '12 at 09:10
  • Are you still interested in solving this? – David Heffernan Mar 03 '12 at 17:10
  • 2
    Actually, I've just looked back at your earlier questions and found this one: http://stackoverflow.com/questions/9344980/how-to-use-native-wifi-api-windows-api-functions-with-delphi No wonder this question seemed familiar. I can't understand why you have translated the API functions the way you have done. I urge you to re-read my answer to your earlier question and follow that advice. – David Heffernan Mar 03 '12 at 17:15
  • @DavidHeffernan I acctually solved the problem by myself, basing on this http://stackoverflow.com/questions/9543472/delphi-passing-parameters-by-reference-or-copy – Vitim.us Mar 04 '12 at 01:03

2 Answers2

6

The documentation for the WlanHostedNetworkQueryProperty function states that the pData pointer must be set to nil when you call it. You are not initialising it at all, so it may or may not be, depending on the state of the stack. You need to add the line:

pData := nil;

before the call.

You might want to initialise all of your parameters.

(Sorry for the bad formatting, trying to do this on a phone is hard!)

Nat
  • 5,414
  • 26
  • 38
  • tried niling everything but I always get access-violation, but if I not use the `name:=text;` from the parameter use static string instead like `name:='test';`, works like a charm. and no errors – Vitim.us Mar 03 '12 at 05:25
  • 1
    This just says to me that you have stack corruption. I strongly believe that the API calls are overwriting the stack. David's suggestion that that the function's definition is incorrect seems the most likely. – Nat Mar 03 '12 at 09:59
-1

I actually solved the question, with help of another question.

The Access Violation was caused by the normal behavior of delphi.

Memory management for Delphi strings is a little unusual. After you call myFunc(text), and assign textcopy := mytext, all three variables (text, mytext and textcopy) will be pointing to the same address, that of the original string.

But as soon as you use one of these variables to make changes to the string, Delphi clones the string behind the scenes, and your changes are applied to the copy. The other two variables still point to the original, so they remain unchanged. So any changes made in Context 2 will not be seen in Context 1 - this "copy-on-write" mechanic effectively gives you pass-by-value semantics. All of these strings are reference-counted, and will be freed automatically once all references go out of scope.

However, there is an exception. If you access the string using pointers, rather than string operations, you'll bypass the copying step and your changes will affect the original. You'll also bypass the reference counting logic, and potentially end up with a pointer to a deallocated block of memory. This may be the reason behind your access violation, but I couldn't say without more details / more code.

If you want reference passing, declare your function as myFunc(var mytext: String). If you want to force Delphi to copy the string, instead of waiting until it's modified, you can use System.UniqueString.

Original answer https://stackoverflow.com/a/9543812/938822

Community
  • 1
  • 1
Vitim.us
  • 20,746
  • 15
  • 92
  • 109