代码之家  ›  专栏  ›  技术社区  ›  Welton v3.62

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

  •  1
  • Welton v3.62  · 技术社区  · 15 年前

    我有一个用Delphi7编写的遗留应用程序。我们正在向应用程序添加新模块。这些模块用Visual Studio 2010、.NET 4、C#编写,并通过COM向应用程序公开。

    我已经成功地定义了一个类,注册了程序集,导出了类型库,将类型库导入到Delphi中,在Delphi中创建了COM客户端并执行了该模块。现在是棘手的部分:我想通过 另一个

    .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;
        }
    }
    

    使用我在.NET中声明的I接口。

    德尔菲

    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;
    

    不可否认,这是我实际问题的一个非常简单的例子,但我认为它充分说明了这个问题。

    所以我的问题是:我有没有办法强制Delphi中的接口类型与.NET中声明的接口保持一致?或者有 另一个 如何将UserInfo的实例传递给UserMaintenance?

    2 回复  |  直到 15 年前
        1
  •  2
  •   SilverKnight    15 年前

    在Delphi中,对象可能实现接口,但它们本身并不是接口对象。 要理解这种区别,您必须查看接口的原始实现 必须理解的是.NET的工作方式不同,所以 对象的.NET接口与所显示的ComVisible方面相同。

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

    您使用Delphi COM对象向导创建了一个新的COM对象。 这将实现该接口。 IMyNewInterface是在其他地方定义的辅助接口,您已经指出 对象实现。

     var
       I1: IMyObject;
       I2: IMyNewInterface;
       T: TMyObject;
     begin
       I1:=TMyObject.Create;
       I2:=TMyObject.Create;
       T:=TMyObject.Create;
     end;
    

    您可以执行这些操作,因为TMyObject实现了这些接口。也, 因为这些是引用计数,所以当 因为使用的是对象引用而不是接口引用,所以必须释放

    给定你发布的代码,如果你仔细观察,你会发现同样的情况。 在您的例子中,您的对象完全在.NET中实现,因此
    您注意到在包装器上,没有第二个方法来传递实例 ,这是因为这个对象没有实现接口,

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

    如果您已经完成了一个tusermainance.Create(nil)调用并拥有该对象的一个实例,

     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实现添加了新方法,但没有重新注册(使用COM)并重新导入新的程序集类型信息)。

    type
      IUserInfo = interface
      ['22222222-2222-2222-2222-AAAAAAAAAAAA']
      //define your methods
      end;
    
        2
  •  1
  •   martinstoeckli    15 年前

    希望我能正确理解你的问题。如果你想摆脱类型库中混乱的(和不必要的)用户信息,你不应该导出你的CoClass,只导出接口。

    [ComVisible(true)]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    [Guid("22222222-2222-2222-2222-AAAAAAAAAAAA")]
    public interface IUserInfo
    {
    }
    
    [ClassInterface(ClassInterfaceType.None)]
    [ComVisible(true)]
    [Guid("22222222-2222-2222-2222-BBBBBBBBBBBB")]
    public class UserInfo: IUserInfo
    {
    }
    

    注意CoClass的第一个属性设置为 ClassInterfaceType.无 ,这样DotNet就不会向类型库显示CoClass本身。不过,您可以像往常一样在Delphi中实例化对象:

    var
      pUserInfo: IUserInfo;
    begin
      pUserInfo := CoUserInfo.Create;
    
    推荐文章