2017-04-18 27 views
2

我有沒有問題寫一個.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 

編輯:放入我最初省略的界面定義。

回答

0

所以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訪問它。

相關問題