How to Initialize an object from an imported DLL in Delphi?

2

I built a Class Library (.Net Framework) in C#, named Return that has only one method which returns 1. Then, I called the .Net DLL from a console application in Delphi by turning it COM visible and by importing it as Type Library. As such, code was generated in the resultant TypeLibName_TLB unit (Return_TLB) as specified in http://docwiki.embarcadero.com/RADStudio/Sydney/en/Code_Generated_When_You_Import_Type_Library_Information

Currently, I am trying to use the function Function() written in the imported DLL that is named Function_() in the Return_TLB unit. When I run the program it shows a warning: Variable 'c1' might not have been initialized. When I debug the program it throws the exception: Exception class $C0000005 with message 'access violation at 0x005ff3c3: read of address 0x00000060'.

I have been trying to initialize c1 by using the constructor of the TClass1 generated in the Return_TLB unit Create(AOwner:TComponent) but I donĀ“t understand what should I use in AOwner and in TComponent. Besides, I am not sure if this is the right procedure, please correct me if I'm wrong.

About the exception thrown, I believe that is due to the fact that I am trying to use an object without initializing it first.

I am new to Delphi and I would greatly appreciate your help.

Here is the code that I wrote in C#:

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Return
{
    public class Class1
    {
        public int Function()
        {
            return 1;
        }
    }
}

Here is the code that I wrote in Delphi:


{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  Return_TLB in 'Return_TLB.pas';

  var
    i:Integer;
    c1:TClass1;

begin

    //c1.Create(TObject: TClass1);   Trying to initialize c1
    i:= c1.Function_();

    WriteLn(i);

    ReadLn;

end.

Here is the code of the Return_TLB unit:


// ************************************************************************ //
// WARNING                                                                    
// -------                                                                    
// The types declared in this file were generated from data read from a       
// Type Library. If this type library is explicitly or indirectly (via        
// another type library referring to this type library) re-imported, or the   
// 'Refresh' command of the Type Library Editor activated while editing the   
// Type Library, the contents of this file will be regenerated and all        
// manual modifications will be lost.                                         
// ************************************************************************ //

// $Rev: 52393 $
// File generated on 07/12/2020 21:52:26 from Type Library described below.

// ************************************************************************  //
// Type Lib: C:\Users\jsreb\Documents\MIEB\C-mo\DLL_antigo\Return\Return\bin\Debug\Return.tlb (1)
// LIBID: {02B4AEEB-B3B5-40B5-AFB0-BF7A4420E4FF}
// LCID: 0
// Helpfile: 
// HelpString: 
// DepndLst: 
//   (1) v2.0 stdole, (C:\Windows\SysWOW64\stdole2.tlb)
//   (2) v2.4 mscorlib, (C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.tlb)
// SYS_KIND: SYS_WIN32
// Errors:
//   Hint: Member 'Function' of '_Class1' changed to 'Function_'
//   Error creating palette bitmap of (TClass1) : Server mscoree.dll contains no icons
// ************************************************************************ //
{$TYPEDADDRESS OFF} // Unit must be compiled without type-checked pointers. 
{$WARN SYMBOL_PLATFORM OFF}
{$WRITEABLECONST ON}
{$VARPROPSETTER ON}
{$ALIGN 4}

interface

uses Winapi.Windows, mscorlib_TLB, System.Classes, System.Variants, System.Win.StdVCL, Vcl.Graphics, Vcl.OleServer, Winapi.ActiveX;
  


// *********************************************************************//
// GUIDS declared in the TypeLibrary. Following prefixes are used:        
//   Type Libraries     : LIBID_xxxx                                      
//   CoClasses          : CLASS_xxxx                                      
//   DISPInterfaces     : DIID_xxxx                                       
//   Non-DISP interfaces: IID_xxxx                                        
// *********************************************************************//
const
  // TypeLibrary Major and minor versions
  ReturnMajorVersion = 1;
  ReturnMinorVersion = 0;

  LIBID_Return: TGUID = '{02B4AEEB-B3B5-40B5-AFB0-BF7A4420E4FF}';

  IID__Class1: TGUID = '{9F546242-F23E-3352-8B36-330792602E41}';
  CLASS_Class1: TGUID = '{B24AB9E7-6C6C-3FB6-8948-732135D01A14}';
type

// *********************************************************************//
// Forward declaration of types defined in TypeLibrary                    
// *********************************************************************//
  _Class1 = interface;
  _Class1Disp = dispinterface;

// *********************************************************************//
// Declaration of CoClasses defined in Type Library                       
// (NOTE: Here we map each CoClass to its Default Interface)              
// *********************************************************************//
  Class1 = _Class1;


// *********************************************************************//
// Interface: _Class1
// Flags:     (4560) Hidden Dual NonExtensible OleAutomation Dispatchable
// GUID:      {9F546242-F23E-3352-8B36-330792602E41}
// *********************************************************************//
  _Class1 = interface(IDispatch)
    ['{9F546242-F23E-3352-8B36-330792602E41}']
    function Get_ToString: WideString; safecall;
    function Equals(obj: OleVariant): WordBool; safecall;
    function GetHashCode: Integer; safecall;
    function GetType: _Type; safecall;
    function Function_: Integer; safecall;
    property ToString: WideString read Get_ToString;
  end;

// *********************************************************************//
// DispIntf:  _Class1Disp
// Flags:     (4560) Hidden Dual NonExtensible OleAutomation Dispatchable
// GUID:      {9F546242-F23E-3352-8B36-330792602E41}
// *********************************************************************//
  _Class1Disp = dispinterface
    ['{9F546242-F23E-3352-8B36-330792602E41}']
    property ToString: WideString readonly dispid 0;
    function Equals(obj: OleVariant): WordBool; dispid 1610743809;
    function GetHashCode: Integer; dispid 1610743810;
    function GetType: _Type; dispid 1610743811;
    function Function_: Integer; dispid 1610743812;
  end;

// *********************************************************************//
// The Class CoClass1 provides a Create and CreateRemote method to          
// create instances of the default interface _Class1 exposed by              
// the CoClass Class1. The functions are intended to be used by             
// clients wishing to automate the CoClass objects exposed by the         
// server of this typelibrary.                                            
// *********************************************************************//
  CoClass1 = class
    class function Create: _Class1;
    class function CreateRemote(const MachineName: string): _Class1;
  end;


// *********************************************************************//
// OLE Server Proxy class declaration
// Server Object    : TClass1
// Help String      : 
// Default Interface: _Class1
// Def. Intf. DISP? : No
// Event   Interface: 
// TypeFlags        : (2) CanCreate
// *********************************************************************//
  TClass1 = class(TOleServer)
  private
    FIntf: _Class1;
    function GetDefaultInterface: _Class1;
  protected
    procedure InitServerData; override;
    function Get_ToString: WideString;
  public
    constructor Create(AOwner: TComponent); override;
    destructor  Destroy; override;
    procedure Connect; override;
    procedure ConnectTo(svrIntf: _Class1);
    procedure Disconnect; override;
    function Equals(obj: OleVariant): WordBool;
    function GetHashCode: Integer;
    function GetType: _Type;
    function Function_: Integer;
    property DefaultInterface: _Class1 read GetDefaultInterface;
    property ToString: WideString read Get_ToString;
  published
  end;

procedure Register;

resourcestring
  dtlServerPage = 'ActiveX';

  dtlOcxPage = 'ActiveX';

implementation

uses System.Win.ComObj;

class function CoClass1.Create: _Class1;
begin
  Result := CreateComObject(CLASS_Class1) as _Class1;
end;

class function CoClass1.CreateRemote(const MachineName: string): _Class1;
begin
  Result := CreateRemoteComObject(MachineName, CLASS_Class1) as _Class1;
end;

procedure TClass1.InitServerData;
const
  CServerData: TServerData = (
    ClassID:   '{B24AB9E7-6C6C-3FB6-8948-732135D01A14}';
    IntfIID:   '{9F546242-F23E-3352-8B36-330792602E41}';
    EventIID:  '';
    LicenseKey: nil;
    Version: 500);
begin
  ServerData := @CServerData;
end;

procedure TClass1.Connect;
var
  punk: IUnknown;
begin
  if FIntf = nil then
  begin
    punk := GetServer;
    Fintf:= punk as _Class1;
  end;
end;

procedure TClass1.ConnectTo(svrIntf: _Class1);
begin
  Disconnect;
  FIntf := svrIntf;
end;

procedure TClass1.DisConnect;
begin
  if Fintf <> nil then
  begin
    FIntf := nil;
  end;
end;

function TClass1.GetDefaultInterface: _Class1;
begin
  if FIntf = nil then
    Connect;
  Assert(FIntf <> nil, 'DefaultInterface is NULL. Component is not connected to Server. You must call "Connect" or "ConnectTo" before this operation');
  Result := FIntf;
end;

constructor TClass1.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
end;

destructor TClass1.Destroy;
begin
  inherited Destroy;
end;

function TClass1.Get_ToString: WideString;
begin
  Result := DefaultInterface.ToString;
end;

function TClass1.Equals(obj: OleVariant): WordBool;
begin
  Result := DefaultInterface.Equals(obj);
end;

function TClass1.GetHashCode: Integer;
begin
  Result := DefaultInterface.GetHashCode;
end;

function TClass1.GetType: _Type;
begin
  Result := DefaultInterface.GetType;
end;

function TClass1.Function_: Integer;
begin
  Result := DefaultInterface.Function_;
end;

procedure Register;
begin
  RegisterComponents(dtlServerPage, [TClass1]);
end;

end.```
c#
delphi
dll
com
asked on Stack Overflow Dec 8, 2020 by Joana

1 Answer

1

For COM DLL, you first have to call Coinitialize(nil);. Then since TClass1 is a class, you must call its constructor first to call its methods. And when you are done, you must free the instance you created. When you are done with COM, you must call CoUninitialize(), typically at the end of program.

var
    c1 : TClass1;
    i  : Integer;
begin
    CoInitialize(nil);
    c1 := TClass1.Create(nil);
    try
        i := c1.Function_();
        WriteLn(i);
    finally
        c1.Free;
    end;
    CoUninitialize();
end;
answered on Stack Overflow Dec 8, 2020 by fpiette • edited Dec 9, 2020 by fpiette

User contributions licensed under CC BY-SA 3.0