3

I have DLL that has functions to be performed on the TClientDataSet like set file to be loaded and loading and saving of file.

unit dll_dmunit;

interface

uses
  System.SysUtils, System.Classes, Data.DB, Datasnap.DBClient, Vcl.Dialogs,Vcl.DBGrids;

type
  TStudentModule = class(TDataModule)
    StudentSet: TClientDataSet;
    StudentSource: TDataSource;
    StudentSetNAME: TStringField;
    StudentSetID: TIntegerField;
    StudentSetAGE: TIntegerField;
    StudentSetSLNo: TAutoIncField;
    dlgOpen: TOpenDialog;
    dlgSave: TSaveDialog;
    private
    { Private declarations }
  public
  end;

  function loadfile:tdbgrid;stdcall;
  procedure setfile(fname:string);stdcall;
  procedure savefile;stdcall;

var
  StudentModule: TStudentModule;
  filename:string;
  grid:TDBgrid;

const
  path:string='C:\Users\GlobalLogic\Documents\RAD Studio\Projects\Student\test.cds';

implementation

{%CLASSGROUP 'Vcl.Controls.TControl'}

{$R *.dfm}

  procedure setfile(f_name: string);stdcall;
  begin
    filename:=f_name;
  end;

  function loadfile:tdbgrid;stdcall;
  var
    _xmldata:string;
  begin
    StudentModule := TStudentModule.Create(nil);
    grid:=TDBGrid.Create(nil);
    result:=grid;
  try
    filename:='C:\Users\GlobalLogic\Documents\RAD Studio\Projects\Student\test.cds';
    StudentModule.StudentSet.LoadFromFile(filename);
    grid.DataSource:=StudentModule.StudentSource;
    _xmldata :=StudentModule.StudentSet.XMLData;
    result:=grid;
  finally
    StudentModule.Free;
  end;
    showmessage('End of the function');
  end;

  procedure  savefile;stdcall;
  begin
    StudentModule.StudentSet.SaveToFile(filename);
  end;
end.

I am able to perform the loadfile method, but now I need to export the content of the TClientDataSet to the Delphi application. For that I am trying to get the content in a TDbgrid and then return this object to application layer, but I am unable to do so. Then I tried to read in XML format but couldn't understand how to pass and decode the XML format. I need to move the content of the loaded dataset to my application where I want to display the data. Please help me in doing so. Thank You

  • 2
    You cannot pass Delphi objects across DLL boundaries. You've already got it wrong by using string across a DLL boundary. What you appear to be looking for is runtime packages. It would make your life a lot easier if you gave up on separate modules and compiled all the code into your executable. – David Heffernan May 13 '14 at 07:10
  • @DavidHeffernan-I am new to this Language so I am not able to understand your response can you help me with some code or links which will give me better understanding of the concept that you are talking about. – Akash_Kumar May 13 '14 at 07:14
  • I don't really want to go into more detail until I know what your goals and requirements are. – David Heffernan May 13 '14 at 07:24
  • @DavidHeffernan-I have to communicate between a DLL and a delphi program.I have TClientdataset and methods defined at dll.I have to load the TclientDataset at dll end and bring the loaded data to the delphi program and display in a grid. – Akash_Kumar May 13 '14 at 08:15
  • Sounds like you've already decided on the solution to your problem. There's not really much for me to say in that case. – David Heffernan May 13 '14 at 08:18
  • @DavidHeffernan- But I am not able to do so, how can I pass the data from DLL to Delphi program.I may be wrong in my approach, if so kindly correct me and provide me a solution to my concern. – Akash_Kumar May 13 '14 at 08:25
  • 1
    There are lots and lots of ways to solve the problem, none of which involve passing objects across DLL boundaries. Why did you decide to use a DLL? Do you intend to share the code between multiple different executables? Why don't you compile all the code into a single executable? – David Heffernan May 13 '14 at 08:42
  • I have been asked to do so by my mentor. He wants me to do that way so I have to do it.Earlier I had done everything in a single executable. Thanks for your help and guidance. – Akash_Kumar May 13 '14 at 08:53
  • What does your mentor say about passing complex types (strings, objects etc.) between the executable and the DLL? Does your mentor understand the issues with doing so? – David Heffernan May 13 '14 at 08:55
  • My mentor did not asked me to pass objects between executable and the DLL he just said that he has Dataset and methods should be seprate from executable in a DLL and data should come to executable from the DLL. He just gave the problem and asked me to solve it. It was my thougt of sending through an object as I was not ware of its consequences. – Akash_Kumar May 13 '14 at 08:59
  • How do you plan to pass the data between EXE and DLL? As text? – David Heffernan May 13 '14 at 09:00
  • Yes I thought of sending it as a text in a string. – Akash_Kumar May 13 '14 at 09:01
  • I have a last small query that the code that you gave will return the content in XML format, so do I have to format it to get my actual data or it will give me the actual data. – Akash_Kumar May 13 '14 at 09:04
  • The answer of Vector is then along the right lines, but that answer currently omits a crucial detail, as I comment. One very easy way to deal with the memory allocation issues would be to use the COM BSTR, aka `WideString` in Delphi, so that the text is allocated on the shared COM heap. – David Heffernan May 13 '14 at 09:05
  • 1
    @Akash_Kumar: FWIW you can pass the entire TClientDataSet's Data (I mean its Data property, not just its "data") across DLL boundaries as an OleVariant and assign it to another TClientDataSet on the other side of the boundary. Your mentor might regard that as cheating, though ;) – MartynA May 13 '14 at 11:02
  • @MartynA- Yes my mentor had strictly said not to use TClienDataSet at the other boundary.So I had to Look for other means. :) – Akash_Kumar May 13 '14 at 11:23
  • I simplified my answer. See edit. – Vector May 13 '14 at 19:48

1 Answers1

1

Below is a simple implemetation that should do what you want without having to export objects from your dll, which tends to be a bit ackward. Instead, simply export the XML string containing your data.

The important points are the signature of your exported function, (in this case function ExportXML:pwideChar;) and the export section of your dll. Make sure to export your XML data as pwidechar.

var Xmldata:widestring;
...
 function loadfile...
...
 Xmldata :=StudentModule.StudentSet.XMLData;

 function ExportXML:pwideChar;stdcall;
 begin
    result:= pwideChar( Xmldata);
 end;

exports
  ExportXML name 'ExportXML';

In your application simply load the result of the DLL callExportXML into aTClientDataSet instance and plug it into your controls.

See Using Export Clause in Libraries for more ways to use theexportssection of your dll, which seems to be what you're missing.

As an aside, if you're going from Delphi to Delphi, you don't need the stdcall directive. See:

If you want your library to be available to applications written in other languages, it's safest to specify stdcall in the declarations of exported functions. Other languages may not support Delphi's default register calling convention.

Vector
  • 10,879
  • 12
  • 61
  • 101
  • 1
    Rather than use a global variable, it is easier to return a `WideString`. Because of [ABI differences between different compilers](http://stackoverflow.com/questions/9349530/why-can-a-widestring-not-be-used-as-a-function-return-value-for-interop), that's better done as an out parameter. I would declare the function like this: `procedure ExportXML(const Intput: WideString; out Output: WideString); stdcall;` – David Heffernan May 13 '14 at 10:34
  • @DavidHeffernan - Agreed. I didn't want to get into all that. I just threw something up there more or less fitted to the code that was used in the question, to give the core answer. Refactoring, etc - that's another story. – Vector May 13 '14 at 10:39