c# - 如何为 VBA.GetObject 向 COM 公开正在运行的 .NET 应用程序对象? (不重复)

标签 c# .net excel winforms winforms-interop

我在编写 .NET WinForms 可执行文件、将其中的一些类暴露给 COM 并通过类似以下方式在 Excel VBA 中使用它们时没有问题:

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

编辑:放入我最初省略的接口(interface)定义。

最佳答案

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

添加此类定义(直接从文章复制/粘贴 - 'punk' 可能是指针未知):

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 的“显示”事件中创建了一个实例),您应该能够通过 VBA.GetObject 访问它。

关于c# - 如何为 VBA.GetObject 向 COM 公开正在运行的 .NET 应用程序对象? (不重复),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43477413/

相关文章:

c# - 如何识别文本中的模式并对其进行分类

c# - Expression.Reduce() 是做什么的?

c# - 枚举值的算术运算

excel - V 或 XLOOKUP 12 位数字范围的最后 4 个字符中的 4 位数字

c# - Azure AD 上传服务主体 key 凭据证书

c# - 将一些html导出到excel文件时如何防止css丢失?

C# 尝试/捕捉/最后

c# - 如何在我的应用程序中加密用户设置(例如密码)?

sql - 如何将值从 VBA 传递到 SQL Server 2008 中的表变量?

vba - 当应用程序的路径错误时处理 wsshellobj.Run() 中的错误