c# - 我的共享插件构造函数有什么问题?

标签 c# excel com add-in constructor

早上好,各位开发者:

我目前正在尝试修复从以前的开发人员那里继承的 Excel 共享加载项的几个性能问题,基本上我是在尝试查找加载项在 Excel 中的内部工作方式,这意味着我已经在网上搜索过有关信息,我的理解是:

  1. 在注册表中,LoadBehaviour 应设置为 3
  2. 打开事件期间的 Excel 工作簿应预先加载 VBA 项目中引用的所有加载项
  3. 文档打开后,我的加载项应该可供 VBA 代码使用。

现在我将 Log4Net 添加到加载项中,奇怪的是我看到了以下行为

在 Excel 工作簿中的打开事件期间有一个全局变量

Public myAddin As Object

Set myAddin = New TradingAddin.TradingAddin

从而调用了C#类的构造函数。

几秒钟后,再次调用构造函数,所有 IDTExtensibility2 方法 OnConnection、OnDisconnection 等都按预期调用。

我认为一旦 Excel 加载了加载项,VBE 代码就应该可以使用它,我可以编写类似的东西

Set myAddin = Application.COMAddins.Item("Trading").Object

但它返回 Nothing 并调用类的构造函数两次破坏保存在 C# 对象中的任何状态,这些状态在 Excel 工作簿的生命周期中应该在内存中可用。

更新:

平台是 Visual Studio 2005 Team Edition,目标应用程序是 Excel 2003,加载项是共享加载项。我没有使用 VSTO。

我试图在 VBA 中调用的实际代码是

Set addIn = Application.COMAddIns.Item("K2Trading.K2Trading").Connect

Set managedObject3 = addIn.Object <--- This value that I thought was an Instance of the Add-in is equal to Nothing (NULL)

Set addIn = Application.COMAddIns("K2Trading.K2Trading").Connect

同时将注册表中的 LoadBehaviour 从 2 更改为 3 加载加载项,第一次正确触发所有扩展性事件 OnConnection、OnDisconecction 和对象类构造函数,现在我需要从 VBA 中找到调用部分的方法加载项,意味着如何将加载项实例连接到 VBA 中的引用,并从那里调用通过 COM 对象的接口(interface)公开的所有方法????

我还使用 ProcMon 仔细检查了该加载项是根据此链接(非常有用)由 Excel 找到并加载的(非常有用)http://blogs.msdn.com/dvespa/archive/2008/10/15/troubleshooting-outlook-com-addins-using-procmon.aspx .

我们有什么想法可能指向正确的方向吗?

我怎样才能知道加载了多少个 COM 对象实例?或者换句话说,有可能拥有 COM 对象的单个实例吗?

TIA, 佩德罗

致迈克:

我尝试了您的解决方案,但在执行此代码时遇到未指定的错误(HRESULT 异常:0x80004005 (E_FAIL))

public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode,
    object addInInst, ref System.Array custom)
{
    object missing = System.Reflection.Missing.Value;

    try
    {
        if (debug)
        {
            log.Debug("Connection Mode :" + connectMode);
        }

        this.excelApp = (Excel.Application)application;
        this.addInInstance = addInInst;

        Office.COMAddIn addIn = this.excelApp.COMAddIns.Item(ref addInInst);

        //addIn.Object = this;

        // We connect our Instance of the Add-in to the Arrya of COMAddins of Excel
        VBA.Interaction.CallByName(addIn, "Object", VBA.CallType.Let, this);

        ^
        |
        The Exception occurs here.

你会注意到这看起来和你刚才发布的有点不同

public void OnConnection(
    object application,
    Extensibility.ext_ConnectMode connectMode,
    object addInInst,
    ref System.Array custom)
{
    // Direct call fails b/c ".Object" is a late-bound call:
    //
    //    addInInst.Object = this;


    // Reflection fails I believe b/c .Object is a 'let' assigned
    // property for reference type, which is very unusual even for
    // COM (although legal) and is a foreign concept to .NET. Use
    // of the right BindingFlags here *might* work, but I'm not sure:
    //
    //    PropertyInfo propInfo;
    //    propInfo = addInInst.GetType().GetProperty("Object");
    //    propInfo.SetValue(addInInst, this, null);


    // This works!:
    VBA.Interaction.CallByName(addInInst, "Object", VBA.CallType.Let, this);
}

因为 addInInst 不是作为 Office.COMAddin 传递的,而是作为我的类的实例传递的,所以 尝试分配给对象属性是不正确的,因为它不存在于该类中

另外我很好奇 Excel 如何加载加载项,我的意思是基于我刚刚加载 Excel 时的观察,OnConnection 方法没有立即执行,但直到我点击 =AvgCost( ) 函数 ??

有什么想法吗?

最佳答案

How could I find out how many instances of the COM Object are loaded? or put into another words could be possible to have a single instance of a COM Object?

这里是指 COM 加载项吗?不能将同一个 COM 加载项多次加载到 Excel 中。

Now I need to find a way for the invocation part from VBA of the Add-in, meaning how to connect the Add-in instance to a reference in VBA and fro there call all the methods exposed throught the Interface of the COM Object????

VBA 都是后期绑定(bind)的,它不像 VB6 DLL 或 .NET 程序集那样预编译成 DLL。因此,您的所有 VBA 调用也必须进行后期绑定(bind)。最简单的方法是调用 Excel.Appliction.Run("NameOfYourVbaMacro") 来调用工作簿中标准模块中存储的任何宏。 (您可以使用 Excel.Application.Workbooks["NameOfYourAddin.xla"] 按名称访问您的工作簿。您不需要专门将其视为加载项,除非您强制执行它加载。)您还可以使用反射代码来访问工作簿和工作表成员,如果您在 ThisWorkbook 类模块或任何 Worksheet 类模块后面有代码。

I thought that once Excel loads the Add-in it should be available to the VBE Code and i could write something like

Set myAddin = Application.COMAddins.Item("Trading").Object

因此,如果我理解正确的话,您不仅希望让 C# 管理的 COM 加载项调用 VBA 代码(如上所述),而且现在您还希望使用 VBA 代码来调用我们的 C# 管理的 COM加入?我认为这是一个非常复杂的问题,可能需要重新思考……但这是可以做到的。

通过 ComAddin.Object 属性将您的托管 COM 加载项公开给 COM 调用程序在 C# 中完成时很棘手,但可行。请参阅以下讨论:

Calling Managed Add-In method from Automation client .

我希望这能帮助你前进......

迈克

编辑:对 Pedro 回复的回应

佩德罗

You will noticed this looks alittle different from you posted a while ago...

是的,您的代码不同,这就是它不起作用的原因!

至少,您的最后一行看起来不正确:

VBA.Interaction.CallByName(addIn, "Object", VBA.CallType.Let, this);

相反,您的代码应该将您的类传递给“addInInst”:

VBA.Interaction.CallByName(addInInst, "Object", VBA.CallType.Let, this);

我不确定你想通过这条线做什么:

Office.COMAddIn addIn = this.excelApp.COMAddIns.Item(ref addInInst);

该行看起来应该抛出异常。我很惊讶它没有。但是与此类似的代码——您在其中为要访问的 COM 加载项传递 progId——通常由希望通过 .Object 属性访问您的 COM 加载项的外部调用者使用。这不是应该从 加载项本身使用的代码。

Because addInInst is not pass as a Office.COMAddin but a instance of my class, so trying to assign to the Object Property is incorrect since it doesn't exists in that class

我不明白你想在这里做什么。我不知道是否可以传入除实现 IDTExtensibility2 的类的实例之外的任何其他对象。至少,通过使用正确的类和接口(interface)属性,您传回的任何类都必须是 COM 可见类。但我认为坚持从 OnConnection 方法中传入实现 IDTExtensibility2 的类的标准做法要容易得多。也就是说,传入您的“this”对象引用。

如果您想尝试超出标准方法的奇思妙想,没关系,但我会先举一个简单的示例。尝试复制我在示例中显示的代码 Calling Managed Add-In method from Automation client .完成该工作后,您可以尝试进行更复杂的操作。但是一旦您使用了简单版本,我想您会发现这就是您所需要的。

我希望这对佩德罗有帮助,

迈克

关于c# - 我的共享插件构造函数有什么问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1231140/

相关文章:

c++ - 为 HRESULT 代码生成诊断消息?

c# - 运行asp.net core api项目时如何在vscode中设置不打开新的Web浏览器选项卡

Excel 小数分数

vba - GetObject 有时会生成新的 COM+/OLE 对象,而不是获取现有的对象

c++ - 使用没有功能的 extern "C"

c++ - 调用 IWebBrowser2->get_Document 时出现错误 800706B5

c# - .NET Framework x509Certificate2 类,HasPrivateKey == true && PrivateKey == null?

c# - Unity IOC配置与json

c# - 使用依赖注入(inject)对 Azure Functions 进行单元测试

vba - 如何在 Excel 中的页眉/页脚中添加 & 符号?