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中初始化一个对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Delphi 中调试从 Java 调用的 DLL?

如何使用 Delphi 代码调试 VC++ 中构建的 DLL 文件?

Delphi简单调用DLL

如何在Delphi中使用用C#创建的DLL

易语言这个DLL代码怎么用delphi写?

Delphi 软件包安装错误:动态链接库 (DLL) 初始化例程失败