VSTO в VBA: AddIn.Object иногда возвращает Nothing (null) - PullRequest
3 голосов
/ 10 ноября 2010

Дано:

  • Надстройка VSTO
  • override object RequestComAddInAutomationService(), который возвращает экземпляр класса, который называется Facade в моем сценарии.
  • Макрос VBA в Excel 2007, который обращается к AddIn.Object для получения Фасада и использует его.
  • Много раз, когда это прекрасно работает.
  • Пару раз, когда неожиданно это не сработало.

Обновление: выясняется, что проблема связана с конкретным пользователем. Она есть у нее все время, у других ее нет (никогда не говори «никогда»)

В эту "пару раз" я получаю

Ошибка: переменная объекта или переменная блока не установлена ​​

в строке кода, которая пытается получить доступ к свойству Facade. Короче говоря, я могу сказать вам, что код в RequestComAddInAutomationService() не содержит никакой склонной к ошибкам магии, и код VBA для доступа к надстройке был взят из Интернета и также выглядит хорошо. Более длинная версия еще впереди, для тех, кто найдет время, чтобы прочитать ее: -)

Вопрос: Кто-нибудь знает, почему это может произойти? Это проблема Excel?


Подробности как и обещали:

MyAddIn.cs:

public partial class MyAddIn
{
    public Facade Facade { get; private set; }

    protected override object RequestComAddInAutomationService()
    {
        if (this.Facade == null)
            this.Facade = new Facade(Controller.Instance);

        return this.Facade;
    }
}

Facade.cs:

[ComVisible(true)]
[Guid("1972781C-A71A-48cd-9675-AE47EACE95E8")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IFacade
{
    // some methods
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class Facade : IFacade
{
    private Controller Controller { get; set; }

    public Facade(Controller controller)
    {
        this.Controller = controller;
    }
}

Facade имеет несколько методов, но не одно поле.

Controller.cs:

public class Controller
{
    private static Controller instance = null;
    public static Controller Instance
    {
        get
        {
            if (instance == null) instance = new Controller();
            return instance;
        }
    }

    private Controller() { }
}

Controller имеет несколько закрытых полей. Поскольку назначения полей выполняются при создании, я их просмотрел. Большинство из них вообще не инициализируются или имеют значение null, поэтому конструктор практически ничего не делает.

Код VBA:

Dim addin As Office.COMAddIn
Dim automationObject As Object

Set addin = Application.COMAddIns("My AddIn")
Set automationObject = addin.Object

Dim oResult As Object
Set oResult = automationObject.SomeMethodThatReturnsAnObject()

Последняя строка, где происходит ошибка. Хотя вызываемый метод возвращает объект, я вполне уверен, что он не может быть источником ошибки: если возвращенная ссылка была null, то оператор просто оценил бы до Set oResult = Nothing, который все еще действителен. VBA скорее генерирует этот тип ошибки всякий раз, когда метод выполняется по ссылке, равной Nothing, которая в моем случае равна automationObject.

С другой стороны, если надстройки не было вообще, Application.COMAddIns(...) поднял бы индекс за пределы , я видел это раньше.

Ответы [ 3 ]

3 голосов
/ 10 ноября 2010

Работа большую часть времени и неудача иногда выглядят как состояние гонки.Эндрю Уайтчепел написал о состоянии гонки, связанном с RequestComAddInAutomationService 1 :

Состояние гонки COMAddIns

Хотя он говорит, что условия гонки не должны быть проблемой с внутрипроцессными макросами VBA, возможно, проблема может возникнуть в вашем конкретном сценарии.

Попробуйте предложенный обходной путь и выполните цикл, пока не получите Addin.Object действителен (код C #, аналогично VBA):

while (utils == null)
{
    utils = (ComServiceOleMarshal.IAddinUtilities)addin.Object;
    System.Threading.Thread.Sleep(100);
}    
utils.DoSomething();

1 В его блоге много полезной информации о том, что вы делаете, так что не стоитне пропустите соответствующие статьи.

2 голосов
/ 22 ноября 2010

Оказалось, что Excel отключил надстройку COM. Известно, что иногда это происходит тихо, и Excel не жалуется ни на что.

Итак, так как надстройка была зарегистрирована в Excel, следующая строка прошла успешно:

Set addin = Application.COMAddIns("My AddIn")

Но так как он был отключен, объект не был создан и

Set automationObject = addin.Object

привело к Nothing.

1 голос
/ 15 марта 2013

У меня была похожая проблема, часто, но не всегда, так что я не могу сказать наверняка, но вещь, которая, казалось, исправляла это, шла в Информация о Проекте / Приложении / Сборке ... и проверяя Сделать сборку COM-Видимый, затем создание объекта (в Excel VBA) с помощью:

Set automationObject = CreateObject("PlugInDllName.PlugInClass")

Никаких проблем с тех пор - скрещенные пальцы.

...