Charles Delannois
Charles Delannois

Reputation: 11

Delphi 10.3 - Weird DLL behaviour

I have met a really weird behaviour using Delphi and DLL.

I want to learn how to create and use DLL's. To do so, I created two files: one containing the DLL, and the other one calling it.

The DLL retrieves informations from a *.ini file (the GetInfos function). When calling it in a form, I get the following error: "Access violation at address XXXXXXXX in "dlltest.dll" module. Read of address 00000000.

I wanted to try some other things, so I created a simple procedure, that just display a message.

The interesting thing is that when I call this procedure (which only purpose is to display a message), I no longer get the Access violation error.

I really do not understand how it can make my code work. I'd really like if someone could give me some explanation. I am using Delphi 10.3 Rio Version 26.0.36039.7899

Here is the code I produced :

dlltest:

library dlltest;

uses
  System.SysUtils, System.Classes, System.IniFiles, Winapi.Windows, vcl.dialogs;

var
   // Ini file var
  iniConfig: TInifile;

procedure SayHello;

var
  hello: PChar;

begin
  hello := 'Hello world!';
  ShowMessage(hello);
end;

// -----------------------------------------------------------------------------
// Retrieving .ini file
function GetIni: TInifile;
begin
  result := TInifile.Create('.\monitoring.ini');
end;

// -----------------------------------------------------------------------------
function GetInfos: ShortString;

begin
  iniConfig := GetIni;

  try
    result := iniConfig.ReadString('filename', 'start', 'start');

  finally
    iniConfig.Free;
  end; { try }
end; { function GetInfos }

exports
  SayHello, GetInfos;

begin

end.

Using dll:

unit testUtilisationDll;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils,
  System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms,
  Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Déclarations privées }
  public
    { Déclarations publiques }
  end;

var
  Form1: TForm1;

procedure SayHello; StdCall; external 'dlltest.dll';

function GetInfos: ShortString; StdCall;
  external 'dlltest.dll';

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);

begin
  SayHello;

  ShowMessage(GetInfos(self));
end;

end.

Upvotes: 0

Views: 289

Answers (1)

HeartWare
HeartWare

Reputation: 8243

When you export the functions, they are using the default calling convention (Register), whereas when you import them, you are telling the import that they're using StdCall calling convention.

The normal case for DLL exported functions is StdCall convention, so you should declare your functions to use this calling convention in your .DLL source:

function GetInfos: ShortString; stdcall;

and

procedure SayHello; stdcall;

Another problem is that when you call GetInfos:

 ShowMessage(GetInfos(self));

you are passing it a parameter (self), but your declaration of the import:

function GetInfos: ShortString; StdCall; external 'dlltest.dll';

doesn't list any parameters. You won't be able to compile the program as it is shown in your question...

Upvotes: 2

Related Questions