我的共享加载项构造函数有什么问题?

时间:2009-08-05 04:06:12

标签: c# excel com add-in constructor

早上好,研究员们:

我目前正在尝试修复从以前的开发人员继承的Excel共享加载项的几个性能问题,基本上我正在尝试查找加载项内部如何在Excel内部工作,这意味着我已经搜索了网络我的理解是:

  1. 在注册表中,LoadBehaviour应设置为3
  2. 打开事件期间的Excel工作簿应预先加载VBA项目中引用的所有加载项
  3. 文档打开后,我的加载项应可供VBA代码使用。
  4. 现在我将Log4Net添加到加载项中,奇怪的是我已经看到了以下行为

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

    Public myAddin As Object
    
    Set myAddin = New TradingAddin.TradingAddin
    

    因此调用C#类的Contructor。

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

    我认为一旦Excel加载外接程序,它应该可用于VBE代码,我可以编写类似

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

    但它返回Nothing并且调用Class的Constructor两次销毁在Excel工作簿的生命周期内应该在内存中可用的C#Object内保存的任何状态。

    更新:

    平台是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更改为3,从第一次正确触发所有可扩展性事件OnConnection,OnDisconecction和Object Class构造函数时加载外接程序,现在我需要从VBA中找到一种调用VBA的方法。加载项,意味着如何将加载项实例连接到VBA中的引用,并从那里调用通过COM对象的接口公开的所有方法????

    我还使用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传递的,而是我的类的实例,所以 尝试分配给Object属性是不正确的,因为它在该类

    中不存在

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

    有什么想法吗?

1 个答案:

答案 0 :(得分:2)

  

我怎么能知道有多少   COM对象的实例是   装?或换句话说   可能有一个单一的   COM对象的实例?

你的意思是COM插件吗?您不能多次将相同的COM加载项加载到Excel中。

  

现在我需要找到一种方法   来自VBA的调用部分   加载项,意思是如何连接   加载项实例到VBA中的引用   那里召唤所有的方法   通过接口暴露出来   COM对象????

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

  

我认为一旦Excel加载了   加载项应该可用于   VBE代码,我可以写点东西   像

     

设置myAddin =   Application.COMAddins.Item( “交易”)。对象

因此,如果我理解正确,您不仅希望拥有C#托管COM加载项调用VBA代码(如上所述),而且现在您还希望VBA代码能够调用我们的C#托管COM加入?我认为这很复杂,可能需要重新思考......但是可以做到。

从C#完成将您的托管COM加载项通过ComAddin.Object属性暴露给COM调用者很棘手,但是可行。请参阅以下讨论:

Calling Managed Add-In method from Automation client

我希望这有助于你前进......

麦克

编辑:对Pedro的回复的回复

佩德罗,

  

你会注意到这看起来很小   不同于你发布了一段时间   前...

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

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

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加载项的外部调用者使用。这不是应该从 加载项本身使用的代码。

  

因为addInInst没有作为传递   Office.COMAddin但是我的一个实例   类,所以试图分配给   对象属性不正确,因为它   该类中不存在

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

如果你想尝试超越标准方法的花哨的东西,那没关系,但我会先得到一个简单的例子。尝试复制我在示例Calling Managed Add-In method from Automation client中显示的代码。一旦你有了这个工作,你可以尝试进行更复杂的操作。但是一旦你有简单的版本工作,我想你会发现这就是你所需要的。

我希望这有助于佩德罗,

麦克