如何将运行的.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访问它。