Что не так с моим конструктором общей надстройки?

Доброе утро, товарищи разработчики:

В настоящее время я пытаюсь исправить несколько проблем с производительностью общей надстройки 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

Но он ничего не возвращает и дважды вызывая конструктор класса, уничтожает любое состояние, сохраненное внутри объекта 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 в реестре на 3 из 2 загружает надстройку в первый раз, правильно запускает все события расширяемости OnConnection, OnDisconecction и конструктор класса объектов, теперь мне нужно найти способ для части вызова из VBA Add- in, что означает, как подключить экземпляр надстройки к ссылке в VBA и оттуда вызвать все методы, представленные через интерфейс COM-объекта ????

Также я дважды проверил с помощью ProcMon, что надстройка была найдена и загружена Excel по этой ссылке (очень полезно) http://blogs.msdn.com/dvespa/archive/2008/10/15/устранениенеполадок-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 ()? ?

Любые идеи?


person Community    schedule 05.08.2009    source источник
comment
с какой проблемой вы столкнулись? какой вопрос вы задаете?   -  person shahkalpeshp    schedule 05.08.2009


Ответы (1)


Как мне узнать, сколько экземпляров COM-объекта загружено? или другими словами можно было бы иметь единственный экземпляр COM-объекта?

Вы имеете в виду надстройку COM? Вы не можете загрузить одну и ту же надстройку COM в Excel более одного раза.

Теперь мне нужно найти способ для части вызова из VBA надстройки, то есть, как подключить экземпляр надстройки к ссылке в VBA и оттуда вызвать все методы, представленные через интерфейс COM-объекта ?? ??

VBA имеет позднюю привязку, он не компилируется предварительно в DLL, как VB6 DLL или сборка .NET. Следовательно, все ваши вызовы VBA также должны иметь позднюю привязку. Самый простой - вызвать Excel.Appliction.Run("NameOfYourVbaMacro") для вызова любого макроса, хранящегося в стандартном модуле вашей книги. (Вы можете получить доступ к своей книге по имени с помощью Excel.Application.Workbooks["NameOfYourAddin.xla"]. Вам не нужно рассматривать ее как надстройку отдельно, кроме случаев, когда вы вызываете ее принудительную загрузку.) Вы также можете использовать код отражения для доступа к книге и членам рабочего листа, если у вас есть код либо за модулем класса ThisWorkbook, либо за любым из модулей класса Worksheet.

Я подумал, что как только Excel загрузит надстройку, она станет доступной для кода VBE, и я мог бы написать что-то вроде

Установите myAddin = Application.COMAddins.Item («Торговля»). Object.

Итак, если я правильно понимаю, вы хотите, чтобы ваша надстройка COM, управляемая C #, вызывала код VBA (как обсуждалось выше), но теперь вы также хотите иметь код VBA, чтобы иметь возможность вызывать нашу надстройку COM, управляемую C #. ? Я думаю, что это тонна сложности, которую, вероятно, нужно переосмыслить ... но это можно сделать.

Предоставление вашей управляемой надстройки COM вызывающей стороне COM через свойство ComAddin.Object сложно, если это делается с C #, но выполнимо. См. Следующее обсуждение:

Вызов метода управляемой надстройки из клиента автоматизации.

Надеюсь, это поможет вам начать ...

Майк

Изменить: ответ на ответ Педро

Педро,

Вы заметите, что это выглядит немного иначе, чем вы опубликовали некоторое время назад ...

Да, у вас другой код и поэтому он не работает!

Как минимум, ваша последняя строка выглядит некорректно:

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);

Эта строка выглядит так, как будто она должна вызвать исключение. Я очень удивлен, что это не так. Но код, похожий на этот - где вы передаете progId для надстройки COM, к которой хотите получить доступ, - обычно используется внешним вызывающим абонентом, который хочет получить доступ к вашей надстройке COM через свойство .Object. Это не код, который следует использовать внутри самой надстройки.

Поскольку addInInst не передается как Office.COMAddin, а является экземпляром моего класса, поэтому попытка присвоения свойству объекта неверна, поскольку его нет в этом классе

Я не понимаю, что вы здесь пытаетесь сделать. Я не знаю, можно ли передать какой-либо другой объект, кроме экземпляра класса, реализующего IDTExtensibility2. Как минимум, любой класс, который вы передаете обратно, должен быть видимым классом COM с использованием правильных атрибутов класса и интерфейса. Но я думаю, что гораздо проще придерживаться стандартной практики передачи класса, реализующего IDTExtensibility2, из метода OnConnection. То есть передать ссылку на объект this.

Если вы хотите попробовать необычные вещи, выходящие за рамки стандартного подхода, это нормально, но сначала я бы получил простой рабочий пример. Попробуйте воспроизвести код, который я показываю в примере Вызов метода управляемой надстройки из клиента автоматизации. Как только у вас это получится, вы можете попытаться перейти к более сложным операциям. Но как только у вас заработает простая версия, я думаю, вы обнаружите, что это все, что вам нужно.

Надеюсь, это поможет Педро,

Майк

person Mike Rosenblum    schedule 07.08.2009
comment
Майк, твой пришел с небес. Одной из проблем, с которыми я столкнулся, была проблема позднего связывания в моем методе OnConnection, потому что для меня было безумием, замеченным на стороне VBA, была связка Set managedObject = new K2Trading.K2Trading, которые создавали несколько вызовов CTOR Add- в инициализации переменных несколько раз, что создает большую проблему, но не обнаруживается. Когда моему боссу было поручено исправить и найти проблемы, а также провести оптимизацию, мой код не работал через ComAddin.Object из-за позднего связывания. Я попробую ваше блюдо в понедельник, но я уверен, что это решение. - person ; 08.08.2009