Delphi中如何从导入的DLL中初始化一个对象?
Posted
技术标签:
【中文标题】Delphi中如何从导入的DLL中初始化一个对象?【英文标题】:How to Initialize an object from an imported DLL in Delphi? 【发布时间】:2021-03-19 08:06:20 【问题描述】:我在 C# 中构建了一个名为 Return 的类库 (.Net Framework),它只有一个返回 1 的方法。然后,我从 Delphi 中的控制台应用程序调用 .Net DLL,方法是使其 COM 可见并导入它作为类型库。因此,代码是在 http://docwiki.embarcadero.com/RADStudio/Sydney/en/Code_Generated_When_You_Import_Type_Library_Information 中指定的结果 TypeLibName_TLB 单元 (Return_TLB) 中生成的 目前,我正在尝试使用在 Return_TLB 单元中名为 Function_() 的导入 DLL 中编写的函数 Function()。当我运行该程序时,它会显示一个警告:变量“c1”可能尚未初始化。当我调试程序时,它会引发异常:异常类 $C0000005 带有消息“在 0x005ff3c3 处的访问冲突:读取地址 0x00000060”。 我一直在尝试通过使用在 Return_TLB 单元 Create(AOwner:TComponent) 中生成的 TClass1 的构造函数来初始化 c1,但我不明白应该在 AOwner 和 TComponent 中使用什么。此外,我不确定这是否是正确的程序,如果我错了,请纠正我。 关于抛出的异常,我相信这是因为我试图使用一个对象而不先初始化它。 我是 Delphi 新手,非常感谢您的帮助。
这是我用 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;
这是我在 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.
这是Return_TLB单元的代码:
// ************************************************************************ //
// 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.```
【问题讨论】:
【参考方案1】:对于 COM DLL,您首先必须调用 Coinitialize(nil);
。那么由于 TClass1 是一个类,你必须先调用它的构造函数才能调用它的方法。完成后,您必须释放您创建的实例。完成 COM 后,您必须调用 CoUninitialize()
,通常在程序结束时。
var
c1 : TClass1;
i : Integer;
begin
CoInitialize(nil);
c1 := TClass1.Create(nil);
try
i := c1.Function_();
WriteLn(i);
finally
c1.Free;
end;
CoUninitialize();
end;
【讨论】:
@joana 如果我的答案符合您的需要,请将其标记为已接受(答案左侧的复选标记)。谢谢。 非常感谢您的帮助。当我运行代码时,出现以下错误:E2035 没有足够的实际参数,参考 c1 的初始化行,因为在 Return_TLB 单元中,TClass1 的构造函数被定义为 Create(AOwner:TComponent)。但是我不明白我应该在 AOwner 和 TComponent 中使用什么。当我尝试将 c1 初始化为 c1:=TClass1.Create(TClass1: TClass1) 时出现以下错误:E2010 不兼容的类型:'TComponent' 和 'class of TClass1'。非常感谢您对此提供的帮助。 您可以使用“nil”作为参数:c1 := TClass1.Create(nil); 我按照建议使用了 nil,并在 WriteLn(i) 之后添加了 ReadLn,效果非常好。非常感谢您的帮助。以上是关于Delphi中如何从导入的DLL中初始化一个对象?的主要内容,如果未能解决你的问题,请参考以下文章