Link to home
Start Free TrialLog in
Avatar of paulb1989
paulb1989

asked on

Returning a Record Containing Various Data

In my app i have declared the following types:

type
  pRetData = ^TRetData;
  TRetData = record
    Data: TByteArray;
    Size: Integer;
  end;

I have a DLL with the following exported function:

function EndEdit: pRetData; stdcall;
var
  Data: TRetData;
begin
  MainForm.Hide;

  Data.Data := pByteArray(MainForm.Properties)^;
  Data.Size := Length(MainForm.Properties);

  Result := @Data;

  MainForm.Release;
end;

And In my App I load the DLL, get the address of the function and then do the following (The function is declared properly and I do load it properly):

procedure TPluginProperties.sButton1Click(Sender: TObject);
var
  PropData: String;
  Data: pRetData;
  i: Integer;
begin
  try
    if @EndEdit <> nil then
    begin
      PropData := '';

      Data := EndEdit;

      for i := 0 to Pred(Data^.Size) do
        PropData := PropData + Char(Data^.Data[i]);    // This is where it crashes

      TPlugin(Obj).Properties := PropData;
    end;
  except
  end;
end;

MainForm.Properties in the DLL is a string variable that contains various pieces of data including the Lines.Text property of a listbox.

If the listbox has only 1 item then the code works fine, but any more and it crashes the application of the indicated line. I can even read the contents of a binary file into MainForm.Properties and return it to the application successfully, so why does the contents of a listbox cause it to fail???
ASKER CERTIFIED SOLUTION
Avatar of Member_2_248744
Member_2_248744
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of paulb1989
paulb1989

ASKER

OK you have said that the TByteArray has a 32kb limit so I wrote this:

type
  pExByteArray = ^TExByteArray;
  TExByteArray = array of Byte;

and used TExByteArray instead of TByteArray. However, my app crashes int he same place as before... I tried putting the -1 in the loop aswell, but that made no difference.

I cannot use a pChar variable as the string may contain null characters... Is there any way to make my TExByteArray work of another way to do this? I need to be able to return any type of data, and more than 32kb. The typical contents of the string I want to return will be built using the Add2String method of ExeMod.pas, and can contain the contents of a binary file aswell as other data.
I do not Understand some of your comment, I can not see any reason (at least from your comments so far) why you would want to use an array of Byte (of any size) for the data transfer, If you use that method you will need to copy the bytes to the byte array and then copy the bytes out of the byte array to get your data, for me it would seem to be more efficient just to copy the bytes out of the original Data memory segment, and not have to copy them. . . .

  In my code I use a Pointer to reference the Data you want to transfer, I tried to show you how to read the data into a string if it had Null characters (#0), it was the second method -

SetLength(Str1, RetData1.Size);
StrLCopy(PChar(Str1), RetData1.pData, RetData1.Size);

 this will transfer (copy) even null charaters in a string, you failed to mention about the null chararcter in the first so I had

Str1 := PChar(RetData1.pData);

which will only copy up to the first null. . .

but where or not you use string data or any data (binary as you call it) you should be able to use a Pointer type and then typecast that into any type you may need, or type it to a  PByteArray(RetData1.pData) and read any but you like, as with -

PByteArray(RetData1.pData)[i]


any way, ,  you say you want to use more than 32 kb in a Byte array, you can type an array to any size you need (I think maybe there is a 4 Gig limit, but not sure. .  something like

type
  PBigByteArray = ^TBigByteArray;
  TBigByteArray = array(0..MAXINT) of Byte;

HOWEVER  - I would NPT use this array as you have in your record -

pRetData = ^TRetData;
  TRetData = record
    Data: TBigByteArray;
    Size: Integer;
  end;

why?  because whenever this array is used it will require 2 gig of memory, so you will get an out of memory exception (if you no got 2 gig of memory), instead  I would use

pRetData = ^TRetData;
  TRetData = record
    Data: PBigByteArray;
    Size: Integer;
  end;

so you can assign you own memory to it when used , so with this you are back to a Pointer type and you can just type cast your data to it,
I think is you use a variable array like

TExByteArray = array of Byte;

you may have to include the ShareMem unit, which is OK I guess, but I highly recommend that you do not use the ShareMem unit
OK Thankyou I'm sorry I didn't realise what you were doing in the code the first time you posted, but now I get it and my app works fine. Thankyou !