2
votes

Using Delphi XE.

When trying to access a Delphi interface object from a DLL, it fails if I try to do it dynamically versus statically.

The interface unit in the dll implements a function to return an instance of the interface. When linked statically, the result is nil when entering the function and everything works. When loading dynamically, the result is non-nil, so when the assignment to result is being done, the IntFCopy code sees it as non-nil and so tries to free it before the assignment, which raises an exception.

Any insight would be appreciated.

The DLL includes testinterfaceload_u and exports testInt:

library testinterfaceload;

uses
  SimpleShareMem,
  SysUtils,
  Classes,
  testinterfaceload_u in 'testinterfaceload_u.pas';

{$R *.res}
exports testInt;

begin
end.

testinterfaceload_u is the unit that defines the interface and simple class implementation:

unit testinterfaceload_u;

interface

type ITestInt = interface
 procedure Test;
end;

{this function returns an instance of the interface}
function testInt : ITestInt; stdcall; export;

type

TTestInt = class(TInterfacedObject,ITestInt)
 procedure Test;
end;



implementation

function testInt : ITestInt;
begin
//debugger shows result as non-nil ITestInt even before this assignment, when dynamic
  result := TTestInt.Create;  
end;

procedure TTestInt.Test;
var
  i : integer;
begin
  i := 0;
end;



end.

Here's a console app that loads the dll and calls the testInt function to return the interface:

program testload_console;

{$APPTYPE CONSOLE}

uses

SysUtils,
  Windows,
  testinterfaceload_u in 'testinterfaceload_u.pas';

type
  TTestInt = function() : ITestInt;

var
   TestInt: TTestInt;
   NewTestInt : ITestInt;
   DLLHandle: THandle;
begin
  DLLHandle := LoadLibrary('testinterfaceload.dll');
  if (DLLHandle < HINSTANCE_ERROR) then
       raise Exception.Create('testinterfaceload.dll can not be loaded or not found. ' +     SysErrorMessage(GetLastError));
  @TestInt := GetProcAddress(DLLHandle, 'testInt');
  try
    if Assigned(TestInt) then
      NewTestInt := TestInt;
  except on e:Exception do
    WriteLn(Output,e.Message);
  end;
end.
4
Why use explicit LoadLibrary rather than implicit linking? - David Heffernan
I'm having a problem in InstallAware trying to run one of my dll's that calls another of my dll's. InstallAware seems to choke when trying to unload the libraries if the second dll is loaded, so I was trying to handle its lifespan in the first dll. - Dan Hacker
if (DLLHandle < HINSTANCE_ERROR) then is incorrect. LoadLibrary returns 0 (i.e. NULL) in case of error. Also, export is not needed and just serves to confuse. Remove it. - David Heffernan

4 Answers

5
votes

TTestInt needs to be declared as stdcall in the code that imports the DLL.

5
votes

Your interface definition should contain a GUID and each function needs the "stdcall" declaration. Without it you might run into problems..

type ITestInt = interface
  ['{AA286610-E3E1-4E6F-B631-F54BC6B31150}']
  procedure Test; stdcall
end;
3
votes

Taking a stab at things: Try adding a calling method (stdcall, pascal, etc.) to the declaration of the dll's testInt function and the TTestInt fnction type in the console app.

1
votes

necroposting mode on

function testInt : ITestInt;
begin
//debugger shows result as non-nil ITestInt even before this assignment, when dynamic
  result := TTestInt.Create;  
end;

should be a procedure like this

procedure testInt(out intf: ITestInt); stdcall;
begin
 intf := TTestInt.Create;  
end;