0

I call a dll function which returns a TJSONObject. The problem is when I try to add this value to a TStringList an access violation exception is raised. Here is my code:

function GetSentMessages(AIdSender: Integer; APageNumber: Integer; AResultsCount: Integer; 
  AQuery: TFDQuery): TJSONObject; stdcall; external 'Messages.dll';
function SendMessage(AMessageJson: TJSONObject; AQuery: TFDQuery): TJSONObject;
  stdcall; external 'Messages.dll';

function Test(AQuery: TFDQuery): TJSONObject;
var
  resp, msg: TJSONObject;
  loader: TStringList;
  tmp: string;
begin
  loader := TStringList.Create;

  try
    msg := TJSONObject.Create();
    msg.AddPair(TJSONPair.Create('idsender', '10'));
    msg.AddPair(TJSONPair.Create('idreceiver', '20'));
    msg.AddPair(TJSONPair.Create('content' , 'some other content'));

    resp := SendMessage(msg, AQuery);
    tmp := resp.ToString; // '{"status":"success"}'

    resp := TJSONObject.Create();
    resp.AddPair(TJSONPair.Create('idsender', '10'));
    resp.AddPair(TJSONPair.Create('idreceiver', '20'));
    resp.AddPair(TJSONPair.Create('content', 'some content'));
    loader.Add('Test: ' + resp.ToString); 
    // loader.Text = 'Test: {"idsender":"10","idreceiver":"20","content":"some content"}'#$D#$A

    resp := GetSentMessages(475, 0, 5, AQuery); // this function I call from a dll
    // resp.ToString = '{"messages":
    // [{"idmessage":"4","idsender":"475","idreceiver":"488","content":"\"Some message\"","datesent":"2015-07-29 19:12:38","readed":"1"},
    // {"idmessage":"5","idsender":"475","idreceiver":"488","content":"Some message","datesent":"2015-07-29 19:18:45","readed":"0"},
    // {"idmessage":"6","idsender":"475","idreceiver":"488","content":"Some message","datesent":"2015-07-30 11:23:45","readed":"1"}]}'
    loader.Text := resp.ToString; // here the exception is raised
    loader.SaveToFile('output.txt');
  finally
    loader.Free;
  end;
end;

And this is the error shown: Exception class $C0000005 with message 'c0000005 ACCESS_VIOLATION'

bob_saginowski
  • 1,429
  • 2
  • 20
  • 35
  • 1
    You cannot exchange the auto-managed types between DLL and other programs. You need to use shared memory manager for that. Or stick with static types (Integer, PChar etc..). – Z.B. Aug 05 '15 at 14:21
  • This is also related: http://stackoverflow.com/questions/3178868/is-it-safe-to-pass-delphi-const-string-params-across-memory-manager-boundaries – Z.B. Aug 05 '15 at 14:22
  • Any idea why `tmp := resp.ToString;` works – bob_saginowski Aug 05 '15 at 14:42
  • 2
    It works.. but you get an AV later because "memory management" is broken when you pass String to another module. Reference counting is broken and that's why you get AV afterwards. – Z.B. Aug 05 '15 at 14:45
  • 1
    For that you need to use a shared memory manager and compile both host and dll with the same versions of compiler etc.. – Z.B. Aug 05 '15 at 14:46
  • 3
    But thats for strings... you cannot pass TObject anyway.. Either use packages (BPL) or do not use objects :) – Z.B. Aug 05 '15 at 14:48
  • In `GetSentMessages` I don't pass any strings but `SendMessage` receives a `TJSONObject` and works fine. – bob_saginowski Aug 05 '15 at 14:48
  • 2
    It doesn't work fine at all as you discover when you call a method on the object returned by `GetSentMessages`. Do yourself a favour and have the DLL return JSON text (perhaps by a `WideString` passed as an out parameter). – David Heffernan Aug 05 '15 at 15:45

0 Answers0