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.```
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;
User contributions licensed under CC BY-SA 3.0