C# 如何为VBA.GetObject向COM公开正在运行的.NET应用程序对象?(不重复)
我在编写.NET WinForms可执行文件、向COM公开其中的一些类以及通过以下方式在Excel VBA中使用它们方面没有问题:C# 如何为VBA.GetObject向COM公开正在运行的.NET应用程序对象?(不重复),c#,.net,excel,winforms,winforms-interop,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; namespa
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(即时窗口)中实际工作:
编辑:输入我最初省略的接口定义。因此有一篇非常好的文章回答了我的问题。尽管他更详细地阐述了这一点,但最明显的最低要求是在Running Objects表(ROT)中注册对象。我的实现如下所示。我在尝试实现本文中的Dispose函数时出错(我想在其他人浪费时间之前回答这个问题)
添加此类定义(直接复制/粘贴文章-‘朋克’可能是未知的):
对类构造函数进行以下更改并添加模块级变量:
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的“Showed”事件中创建了一个实例),您应该能够通过VBA.GetObject访问它
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
}