简体   繁体   English

如何从 Delphi 中导入的 DLL 初始化 object?

[英]How to Initialize an object from an imported DLL in Delphi?

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. 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因此,代码是在http://docwiki.embarcadero.com/RADStudio/Sydney/en/Code_Generated_When_You_Import_Type_Library_Information中指定的结果 TypeLibName_TLB 单元 (Return_TLB) 中生成的

Currently, I am trying to use the function Function() written in the imported DLL that is named Function_() in the Return_TLB unit.目前,我正在尝试使用在 Return_TLB 单元中名为 Function_() 的导入 DLL 中编写的 function Function()。 When I run the program it shows a warning: Variable 'c1' might not have been initialized.当我运行该程序时,它显示一个警告:变量“c1”可能尚未初始化。 When I debug the program it throws the exception: Exception class $C0000005 with message 'access violation at 0x005ff3c3: read of address 0x00000060'.当我调试程序时,它会抛出异常:异常 class $C0000005 并带有消息“在 0x005ff3c3 处的访问冲突:读取地址 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.我一直在尝试通过使用在 Return_TLB 单元 Create(AOwner:TComponent) 中生成的 TClass1 的构造函数来初始化 c1,但我不明白应该在 AOwner 和 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.关于抛出的异常,我相信这是因为我试图使用 object 而不先初始化它。

I am new to Delphi and I would greatly appreciate your help.我是 Delphi 的新手,非常感谢您的帮助。

Here is the code that I wrote in C#:这是我在 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:这是我在 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:这是 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.```

For COM DLL, you first have to call Coinitialize(nil);对于 COM DLL,您首先必须调用Coinitialize(nil); . . Then since TClass1 is a class, you must call its constructor first to call its methods.那么由于 TClass1 是一个 class,你必须先调用它的构造函数才能调用它的方法。 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.完成 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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM