gpt4 book ai didi

delphi - 如何将 .NET COM 对象的实例从 Delphi 传递到另一个 .NET COM 对象?

转载 作者:行者123 更新时间:2023-12-03 19:44:53 25 4
gpt4 key购买 nike

我有一个用 Delphi 7 编写的旧版应用程序。我们正在向该应用程序添加新模块。这些模块是用 Visual Studio 2010、.NET 4、C# 编写的,并通过 COM 公开给应用程序。

我已经成功定义了一个类,注册了程序集,导出了类型库,将类型库导入Delphi,在Delphi中创建了COM客户端并执行了模块。现在到了棘手的部分:我想将另一个对象(如上所述已定义-注册-导出-blah-blah-blah)作为参数传递给第一个模块上的方法。

.NET

[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("11111111-1111-1111-1111-AAAAAAAAAAAA")]
public interface IUserMaintenance
{
bool AssignUser(IUserInfo);
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
[Guid("11111111-1111-1111-1111-BBBBBBBBBBBB")]
public class UserMaintenance: IUserMaintenance
{
private IUserInfo _UserInfo;

public bool AssignUser(IUserInfo userInfo)
{
_UserInfo = userInfo;
LoadUser();
}

private void LoadUser()
{
//load user data from database using _UserInfo.UserName
}
}

[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("22222222-2222-2222-2222-AAAAAAAAAAAA")]
public interface IUserInfo
{
void Initialize(string userName);
string UserName { get; }
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
[Guid("22222222-2222-2222-2222-BBBBBBBBBBBB")]
public class UserInfo: IUserInfo
{
public string UserName { get; private set };

public void Initialize(string userName)
{
UserName = userName;
}
}

假设我有实现每个接口(interface)的单独类,并且包含这些类的程序集成功编译和注册,我将类型库导入 Delphi,创建 UserMaintenance_TLB.pas 和 UserInfo_TLB.pas。然而,我看到了一些意想不到的东西:虽然我在 .NET 中定义的接口(interface)存在(以“I”开头的接口(interface)),但 Delphi 生成了另一组接口(interface)(以“_”开头的接口(interface))。 Delphi 根本不使用我在 .NET 中声明的 I 接口(interface)。

德尔福
UserMaintenance_TLB.pas

// *********************************************************************//
// Forward declaration of types defined in TypeLibrary
// *********************************************************************//
IUserMaintenance = interface;
IUserMaintenanceDisp = dispinterface;
_UserMaintenance = interface;
_UserMaintenanceDisp = dispinterface;

UserInfo_TLB.pas

// *********************************************************************//
// Forward declaration of types defined in TypeLibrary
// *********************************************************************//
IUserInfo = interface;
IUserInfoDisp = dispinterface;
_UserInfo = interface;
_UserInfoDisp = dispinterface;

Delphi 还创建了相应的 Delphi 类型:
// *********************************************************************//
// OLE Server Proxy class declaration
// Server Object : TUserMaintenance
// Help String :
// Default Interface: _UserMaintenance
// Def. Intf. DISP? : No
// Event Interface:
// TypeFlags : (2) CanCreate
// *********************************************************************//

TUserMaintenance = class(TOleServer)
private
FIntf: _UserMaintenance;
function GetDefaultInterface: _UserMaintenance;
protected
procedure InitServerData; override;
function Get_ToString: WideString;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Connect; override;
procedure ConnectTo(svrIntf: _UserMaintenance);
procedure Disconnect; override;
function Equals(obj: OleVariant): WordBool;
function GetHashCode: Integer;
function GetType: _Type;
WordBool AssignUser(IUserInfo userInfo);
property DefaultInterface: _UserMaintenance read GetDefaultInterface;
property ToString: WideString read Get_ToString;
published
end;

我想做的是创建一个 TUserMaintenance 实例,然后将一个 TUserInfo 实例传递给它。然而,有两件事是显而易见的:Delphi 类 TUserInfo 没有实现 IUserInfo,DefaultInterface 是 Delphi 生成的新接口(interface) _UserInfo。我不能将我的 UserInfo 变量声明为 IUserInfo 类型,因为 TUserInfo 没有实现该接口(interface)。我也不能将其声明为 _UserInfo 类型,因为 UserMaintenance.LoadUser 需要一个 IUserInfo 实例。

诚然,这是我实际问题的一个非常简化的示例,但我认为它充分说明了问题。

所以我的问题是:有什么方法可以强制 Delphi 中的接口(interface)类型与 .NET 中声明的接口(interface)保持一致?还是有另一种方法可以将 UserInfo 的实例传递给 UserMaintenance?

最佳答案

Delphi 中的部分问题是,对象可以实现接口(interface),但它们本身并不是接口(interface)对象。
要理解这种区别,您必须查看接口(interface)的原始实现
在 Delphi 对象上,并了解 COM 使用的引用计数机制。另一件事
必须理解的是 .NET 的工作方式不同,所以看起来
.NET 中对象的接口(interface)与所呈现的 ComVisible 方面相同。

TYPE
TMyObject = class(TInterfacedObject, IMyObject, IMyNewInterface)
end;

鉴于上述情况,可以对这个对象说以下事情。
您使用 Delphi COM 对象向导创建了一个新的 COM 对象。
Interface IMyObject 被定义为默认接口(interface),而 TMyObject 是具体类
这将实现该接口(interface)。
IMyNewInterface 是在其他地方定义的辅助接口(interface),您已表明您的
对象实现。

您可以使用此对象执行以下操作
 var
I1: IMyObject;
I2: IMyNewInterface;
T: TMyObject;
begin
I1:=TMyObject.Create;
I2:=TMyObject.Create;
T:=TMyObject.Create;
end;

您可以做这些事情,因为 TMyObject 实现了这些接口(interface)。还,
因为这些是引用计数的,所以你不必从内存中释放它们,当
方法范围结束,对象的生命周期也结束 - 除了最后一个
因为您使用的是 OBJECT REFERENCE 而不是 INTERFACE REFERENCE,所以您必须释放
您创建的对象。

鉴于您发布的代码,如果您仔细观察,您实际上会发现相同的情况。
在您的情况下,您的对象完全在 .NET 中实现,所以您正在尝试
use 是一个 Delphi 代码包装器——它是一个 OBJECT,而不是一个 INTERFACE。
您在包装器上注意到,没有第二种方法可以传递实例
的 IUserInfo 对象,那是因为这个 OBJECT 没有实现 INTERFACE,
(您的 .NET 对象是为此而创建的) - 您在 Delphi 中需要做的是“选择该接口(interface)”

您将通过执行以下操作来完成该任务:

如果您已经完成了 TUserMaintenance.Create(nil) 调用并拥有该对象的实例,
获取默认接口(interface),然后将其“强制转换”为适当的实现接口(interface)
 var
UMDelphiWrapper: TUserMaintenance;
UIDelphiWrapper: TUserInfo;
UI: IUserInfo;
UM: IUserMaintenance;


begin
//this part creates a Delphi OBJECT reference to the Implementation class -
//this is NOT Reference counted, because it doesn't implement an interface.
UIDelphiWrapper:=TUserInfo.Create(nil);
try
//this is the part where you acquire the interface of the object that actually
//implementes this interface - e.g. your .NET class
//not that this is the INTERFACE reference - which WILL be reference counted
UI:=UIDelphiWrapper.DefaultInterface as IUserInfo;

//UI.<Set some properties of your IUserInfo object>

try
//this part creates a Delphi OBJECT reference to the Implementation class -
//this is NOT Reference counted, because it doesn't implement an interface.
UMDelhpiWrapper:=TUserMaintenance.Create(nil);
try
//this is the part where you acquire the interface of the object that actually
//implementes this interface - e.g. your .NET class
//not that this is the INTERFACE reference - which WILL be reference counted
UM:=UMdelphiWrapper.DefaultInterface as IUserMaintenance;
try
//Here, you have an interface type implemented by your .NET class that you are
//sending to the implementation of your management object (Also a .NET class)
UM.SendUser(UI);

//do whatever else you need to do with your interface and user/management .NET object(s)
finally
//this IS a reference counted COM object - no "free" necessary
//this would naturally happen when the reference goes out of scope in the method
//but for clairity sake is set to NIL to explicitly release your reference
UM:=nil;
end;

finally
//This is a delphi object that is NOT reference counted and must be released
FreeAndNil(UMDelphiWrapper);
end;

finally
//this IS a reference counted COM object - no "free" necessary
//this would naturally happen when the reference goes out of scope in the method
//but for clairity sake is set to NIL to explicitly release your reference
UI:=nil;
end;
Finally
//This is a delphi object that is NOT reference counted and must be released
FreeAndNIl(UIDelphiWrapper);
end;

除了实际使用 Delphi 提供的包装器之外,只要您知道正确的信息,您还可以直接创建对 .NET 对象的引用。
var
UI: IUserInfo;
UM: IUserManager;

begin
UI:=CreateOleObject('YourAssembly.YourImplementationClass') as IUserInfo;
UI.SomeProperty:=SomeValue;
UM:=CreateOleObject('YourAssembly.YourImplementationClass') as IUserManger;
UM.SomeMetohd(UI);
end;

这段代码更简洁 - 但是,您仍然必须拥有 IUserInfo 和 IUserMaintenance 的准确定义,并且知道对象的类友好名称,因为它们已在 COM 中注册。

您可以自己通过键入代码来执行此操作 - 当您从程序集中导入 COM 公开的 DLL 时,类型导入函数应该为您执行此操作。我没有在您提供的代码中看到实际的实现,但您仍然应该在头文件中找到此信息。 -- 如果你不这样做,那么你没有导入正确的程序集,或者 Delphi 7 导入没有正确运行 - 或者它需要刷新(例如,你在 .NET 实现中添加了新方法,但没有t 重新注册(使用 COM)并重新导入新的程序集类型信息)。
type
IUserInfo = interface
['22222222-2222-2222-2222-AAAAAAAAAAAA']
//define your methods
end;

关于delphi - 如何将 .NET COM 对象的实例从 Delphi 传递到另一个 .NET COM 对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3962096/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com