如何将运行的.NET应用程序对象暴露给COM对于VBA.GetObject? (不重复)

问题描述:

我有没有问题写一个.NET的WinForms可执行文件,其中露出一些类到COM,并在Excel中使用VBA他们经过是这样的:如何将运行的.NET应用程序对象暴露给COM对于VBA.GetObject? (不重复)

Set myVbaObj = VBA.CreateObject("MyNameSpace.MyClassName") 
myVbaObj.SayHi "I hope somebody will answer this question." 

凡我.NET类已经取得了COM正是如此可见:

using System.Runtime.InteropServices; 

namespace MyNameSpace 
{ 

    [Guid("GUID created by Visual Studio->Tools->Create GUID")] 
    public interface IMyClassName 
    { 
    void SayHi(string Msg); 
    } 

    [ComVisible(true)] 
    [Guid("Other GUID created by Visual Studio->Tools->Create GUID")] 
    [ProgId("MyNameSpace.MyClassName")] 
    [ClassInterface(ClassInterfaceType.None)] 
    public class MyClassName : IMyClassName 
    { 
    public MyClassName() 
    { 
     RegistrationServices rs; 

     try 
     { 
     // Class constructor registers itself for COM 
     rs = new RegistrationServices(); 
     if (!rs.RegisterAssembly(Assembly.GetExecutingAssembly(), 
           AssemblyRegistrationFlags.SetCodeBase)) 
     { 
      throw new Exception 
      ("Error registering MyClassName COM component."); 
     } 
     } 
     catch (Exception ex) 
     { 
     throw new Exception(string.Format(
      "Error in {0} constructor:\r\n{1}", 
      this.GetType().Name, ex.Message)); 
     } 
     // End of MyClassName constructor 
    } 

    [ComVisible(true)] 
    public void SayHi(string Msg) 
    { 
     try 
     { 
     MessageBox.Show(string.Format(
      "Hi from Excel: '{0}'.", Msg)); 
     } 
     catch (Exception ex) 
     { 
     throw new Exception(string.Format(
      "Error in {0}.SayHi:\r\n{1}", 
      this.GetType().Name, ex.Message)); 
     } 
     // End of SayHi() 
    } 
    } 
} 

不过,我想成为像Excel和暴露的.exe文件,所以我可以参考和使用运行我的.NET应用程序的实例进行交互。在Excel VBA中,出现这种情况通过“GetObject的”:

Set myVbaObj = VBA.GetObject(, "MyNameSpace.Application") 

但我难倒得到类似的东西实际上工作方式下面将在Excel VBA(立即窗口)工作:

Set xlApp = VBA.GetObject(, "Excel.Application") 
print xlApp.caption 

编辑:放入我最初省略的界面定义。

所以this guy有一个非常好的文章,回答了我的问题。虽然他更详细地介绍了,但明显的最低要求是将对象注册到运行对象表(ROT)中。我的实现如下所示。我试图从文章中实现Dispose函数时遇到错误(我想在别人浪费时间之前回答这个问题)。

添加此类的定义(直接复制/粘贴到物品 - “朋克”可能是指针未知):

using System.Runtime.InteropServices; 

public class Ole32 
{ 
    [DllImport("Ole32.Dll")] 
    public static extern int CreateBindCtx(int reserved, 
    out UCOMIBindCtx bindCtx); 
    [DllImport("oleaut32.dll")] 
    public static extern int RegisterActiveObject 
     ([MarshalAs(UnmanagedType.IUnknown)] object punk, 
      ref Guid rclsid, uint dwFlags, out int pdwRegister); 

    // End of Ole32 class definition 
} 

进行这些更改类的构造函数,并添加模块级变量:

private int _DwRegister; 

public MyClassName() 
{ 
    RegistrationServices rs; 

    try 
    { 
    // Class constructor registers itself for COM 
    rs = new RegistrationServices(); 
    if (!rs.RegisterAssembly(Assembly.GetExecutingAssembly(), 
          AssemblyRegistrationFlags.SetCodeBase)) 
    { 
     throw new Exception 
     ("Error registering MyClassName COM component."); 
    } 
    Guid guid = Marshal.GenerateGuidForType(typeof(SmartDesigner)); 
    Ole32.RegisterActiveObject(this, ref guid, 0, out _DwRegister); 
    } 
    catch (Exception ex) 
    { 
    throw new Exception(string.Format(
     "Error in {0} constructor:\r\n{1}", 
     this.GetType().Name, ex.Message)); 
    } 
    // End of MyClassName constructor 
} 

此时,一旦类以某种方式实例化(我只是在应用程序的主WinForm的'Shown'事件中创建了一个实例),您应该可以通过VBA.GetObject访问它。