如何在 Delphi 中创建COM DLL(类库)?

f87krz0w  于 2023-06-22  发布在  其他
关注(0)|答案(3)|浏览(218)

如何在 Delphi 中创建COM DLL(类库)?
它是在非常旧的PC上使用的,在这些PC上没有也不会安装.NET,它将取代并稍微扩展VB 6 DLL,我有它的源代码。

hec6srdp

hec6srdp1#

创建新的ActiveX库。您可以在ActiveX选项卡中找到它。(文件-新建-其他- ActiveX - ActiveX库)

jv2fixgn

jv2fixgn2#

这里你有如何做到这一点:
Delphi 中的COM编程介绍那么,什么是接口呢?接口是COM技术的核心。当我使用界面这个词时,不要把它与用户交互的视觉显示混淆。它实际上是一个相当新的保留字并入 Delphi 。接口只不过是用来操作对象的一组抽象方法。
我们在上一课中确定了接口不是类;它是一个接口。因此,我们必须这样宣布。让我们来探讨一些界面特征。

  • 接口定义为类型接口
  • 你要用字母I来定义你的界面。即“IMyInterface = interface”
  • 接口继承自IUnknown
  • 不能像创建包含抽象方法的类那样创建接口的示例
  • 接口不能包含变量。(阅读:它可以包含属性,我稍后将向您展示)
  • 在接口中声明的所有函数和过程都是公共虚抽象方法。即使你不以这种方式宣布它们,它被理解为它们是什么。
  • 接口被引用计数

现在我们已经了解了接口可以做什么和不能做什么,让我们来看看声明接口是什么样子的。

IMyInterface = interface
['{676C8DA0-D8B3-11D4-BDE0-00A024BAF736}']
procedure SomeUnimplementedMethod;
end;

在GUID上,我相信你想知道那一大串疯狂的字符是什么。它被称为GUID,代表全局唯一标识符。有些人把它读为“gwid”或“Gooey ID”。下面是GUID的一些特征:

  • 您的界面将有一个不同于世界上任何其他界面的GUID
  • 所有接口和COM接口都将附加GUID
  • 您可以在 Delphi 中通过按CTRL-SHIFT-G创建GUID
  • 永远不能将GUID从一个接口复制到另一个接口

好的,但是我如何实现一个接口呢?这是个好问题。答案是:不能直接实现接口。您必须创建一个将实现您的接口的类。请参考下面的编码示例。

unit InterfaceUnit;

interface

uses
Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms, Dialogs, StdCtrls;

type
IMyInterface = interface
['{6675C5C0-D95C-11D4-BDE0-00A024BAF736}']
procedure DisplaySomething;
end;

TMyClass = class(TInterfacedObject, IMyInterface)
procedure DisplaySomething;
end;

TMyForm = class(TForm)
TestBtn: TButton;
procedure TestBtnClick(Sender: TObject);
end;

var
MyForm: TMyForm;

implementation

{$R *.DFM}
procedure TMyForm.TestBtnClick(Sender: TObject);
var
//Declare a TMyClass object
MyClass : TMyClass;
//Declare a IMyInterface Object
MyInterface : IMyInterface;
begin
//Create an interface pointing
//to a TMyClass object
MyInterface := TMyClass.Create;

//Call TMyClass'es DisplaySomething
//using our interface
MyInterface.DisplaySomething;
end;

{ TMyClass }
procedure TMyClass.DisplaySomething;
begin
ShowMessage('MyInterface was created and
will now fall out of scope!');
end;

end.

上面列出的代码示例非常简单,同时仍然具有某种类型的视觉功能。让我们仔细看看过程TextBtnClick。是不是少了什么?如果你有?我没有注意到,我们没有显式地释放接口。这看起来是内存泄漏,但表象是骗人的。一旦接口超出范围, Delphi 实际上会自动为您释放接口!当过程或函数结束时,在过程或函数中声明的接口自然会超出范围。当对象被释放或程序结束时,在类中声明或全局声明的接口自然会超出范围。
现在我们需要讨论引用计数。每次检索对象的接口时,例如MyClass:= MyClass; Delphi 将使用IUnknown的_AddRef函数自动增加其引用计数。当接口福尔斯作用域时, Delphi 会自动调用IUnknown的._Release函数。如果你还没有弄明白,IUnkown也是一个接口,既然我们已经知道接口不能实现它定义的方法,那么你可能想知道AddRef和Release是从哪里来的。答案是TInterfacedObject!什么是TInterfacedObject?TInterfacedObject和IUnknown在system.pas中定义。在我详细说明这一点之前,我们至少需要看看代码:
TInterfacedObject的IUnkown声明及其实现

IUnknown = interface
['{00000000-0000-0000-C000-000000000046}']
function QueryInterface
(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
end;

TInterfacedObject = class(TObject, IUnknown)
protected
FRefCount: Integer;
function QueryInterface
(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
public
procedure BeforeDestruction; override;
property RefCount: Integer read FRefCount;
end;

procedure TInterfacedObject.BeforeDestruction;
begin
if RefCount <> 0 then Error(reInvalidPtr);
end;

function TInterfacedObject.QueryInterface
(const IID: TGUID; out Obj): HResult;
const
E_NOINTERFACE = $80004002;
begin
if GetInterface(IID, Obj) then
Result := 0 else Result := E_NOINTERFACE;
end;

function TInterfacedObject._AddRef: Integer;
begin
Result := InterlockedIncrement(FRefCount);
end;

function TInterfacedObject._Release: Integer;
begin
Result := InterlockedDecrement(FRefCount);
if Result = 0 then Destroy;
end;

代码可能看起来有点吓人,但我们将逐步完成,因为理解引用计数对于有效地在COM中编程至关重要。从上面的代码中可以明显看出,TInterfacedObject实现了IUnkown中定义的方法。当你创建一个使用TInterfacedObject的类时,你实际上是在告诉这个类,如果一个接口被分配给它,它将被引用计数。
让我们看一段简单的代码,这样我就可以描述发生的过程。

TMyInterfaceClass = class(TInterfacedObject, IMyInterface)
{blah blah blah}
{blah blah blah}
procedure DoThis;
var
MyClass : TMyInterfaceClass;
MyInterface : IMyInterface;
begin
MyClass := TMyInterfaceClass.Create;
MyInterface := MyClass
end;

当您使用直接赋值将MyInterface赋值给MyClass时, Delphi 会自动调用_AddRef方法。这对MyClass说,“嘿,一个接口正在引用你!我们将增加您的引用计数。”如果您要将上述代码更改为以下内容:

TMyInterfaceClass = class(TInterfacedObject, IMyInterface)
{blah blah blah}
{blah blah blah}
procedure DoThis;
var
MyClass : TMyInterfaceClass;
MyInterface : IMyInterface;
MyInterface2: IMyInterface;
begin
MyClass := TMyInterfaceClass.Create;
MyInterface := MyClass;
MyInterface2 := MyClass
end;

请注意,我添加了一个名为MyInterface 2的新变量。既然我们现在设置两个不同的接口等于MyClass,猜猜MyClass会发生什么?的引用计数?它变成了2,因为我们现在有两个接口分配给它!

您可能想知道TInterfaceedObject实现的_Release方法。对于分配给超出范围的类的每个接口,都会自动调用_Release方法。很明显,在DoThis过程的末尾,程序执行将返回它来自哪里,因此,你的局部类和接口声明会落在声明它们的作用域之外。由于我们定义了两个接口,_Release将被调用多少次?答案是亮闪闪的“2”!一旦我们的引用计数为零,那么MyClass就会被 Delphi 自动释放。多么漂亮和干净!
source of the answer

mftmpeh8

mftmpeh83#

通过this site,这是在 Delphi 中开发COM的良好起点。它有关于 Delphi 中COM技术的教程、文章和代码。可能对你有帮助

相关问题