Последовательность загрузки сборки COM-взаимодействия - PullRequest
6 голосов
/ 03 декабря 2008

Существует очень странная проблема со ссылками на сборки и проблема с загрузкой, с которыми я сталкиваюсь с надстройкой Outlook. Вот деталь (долгая история :)):

У меня есть старый плагин для Outlook, написанный и собранный с использованием .Net 1.1. Надстройка загружается с использованием неуправляемой прокладки в собственном домене приложения. Он работает нормально, с .Net 2.0, даже если 1.1 не присутствует на компьютере пользователя.

Надстройка использует настраиваемую сборку взаимодействия Outlook, созданную VS 2003 для Outlook 2000, и после этого перестраивается под строгим именем (как и мое дополнение).

В проекте надстройки я ссылаюсь только на эту пользовательскую сборку взаимодействия, но не на официальную сборку взаимодействия MS.

Когда этот плагин используется в среде с Outlook 2007 и .Net 2.0, где в GAC установлены официальные сборки взаимодействия MS, по какой-то причине я вижу, что плагин загружает и использует их.

В коде класса Connect у меня есть директива using:

using Outlook;

- это пространство имен моей пользовательской сборки взаимодействия.

В Connect ctor у меня есть следующие строки кода (добавлены в целях тестирования):

Assembly.LoadFrom(PATHTOMYASSEMBLY + "Interop.Outlook.dll");
Type type = typeof(Outlook.ApplicationClass);
logger.Debug("Outlook.Application full type is: {0}", type.AssemblyQualifiedName);

Это выводит:

Outlook.Application полный тип: Outlook.ApplicationClass, Interop.Outlook, версия = 9.0.0.0, Culture = нейтрально, PublicKeyToken = 4cfbdc5349cf59d8

Это именно то, чего я ожидал.

Проблема в том, что когда OnConnection (объект приложения, Extensibility.ext_ConnectMode connectMode, объект addInInst, ссылка System.Array custom) называется, я вижу в журнале (у меня есть перехват к событию AssemblyLoad текущего домена), что сборка взаимодействия MS также загружается:

private void app_domain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
{
    Assembly loadedAssembly = args.LoadedAssembly;
    logger.Debug("Assembly {0} is loaded from: {1}", loadedAssembly.FullName, loadedAssembly.GlobalAssemblyCache ? "GAC" : loadedAssembly.Location);
}

Выход:

Ассамблея Microsoft.Office.Interop.Outlook, Версия = 12.0.0.0, Культура = нейтральная, PublicKeyToken = 71e9bce111e9429c является загружен из: GAC

Мой метод OnConnection запускается так:

public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom)
{
    Type type = application.GetType();
    logger.Debug("OnConnection application object's full type is: {0}", type.AssemblyQualifiedName);

    Outlook.Application applicationObject = (Outlook.Application)application;

Это выводит:

Объект приложения OnConnection заполнен тип является: Microsoft.Office.Interop.Outlook.ApplicationClass, Microsoft.Office.Interop.Outlook, Версия = 12.0.0.0, Культура = нейтральная, PublicKeyToken = 71e9bce111e9429c

Это действительно странно, так как вы можете видеть, что на следующей строке я могу без проблем привести к Outlook.Application.

Я проверил с помощью Reflector, и моя сборка никоим образом не ссылается на сборки взаимодействия Microsoft. То же самое для моего Interop.Outlook.dll.

Так, кто-то знает, что происходит? Каков ответ на эти вопросы:

  1. Почему он вообще загружает сборки Microsoft?

  2. Как можно привести между несвязанными классами / интерфейсами, определенными в разных сборках?

ПРИМЕЧАНИЕ. Я создал новый очень простой плагин, который ничего не делает, просто загружает. Я мог бы воспроизвести проблему, так что, действительно, кто-нибудь знает, как CLR решает, какое взаимодействие загрузить и откуда. Помимо GAC, есть ли другое место (реестр ???), где есть связь между COM-объектом и взаимодействием, которое для этого требуется?

1 Ответ

6 голосов
/ 29 января 2009

Я думаю, что нашел ответ на вашу проблему в учебнике Microsoft Primary Interop Assembly . PIA обрабатываются по-разному в Visual Studio:

Когда пользователь пытается добавить ссылку на библиотеку типов с зарегистрированной PIA, Visual Studio автоматически использует зарегистрированную PIA вместо того, чтобы импортировать библиотеку типов с помощью Tlbimp. Это гарантирует, что PIA используется по возможности.

Это означает, что когда вы добавляете ссылку на свой собственный IA в проект, Visual Studio проверит, есть ли PIA, зарегистрированная для этого COM-объекта. PIA Outlook регистрируются под следующим ключом:

HKEY_CLASSES_ROOT\CLSID\{0006F023-0000-0000-C000-000000000046}\InprocServer32\12.0.0.0
    Assembly="Microsoft.Office.Interop.Outlook, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71E9BCE111E9429C"

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

Однако Microsoft не рекомендует использовать пользовательские IA, если есть доступная PIA. Я не понимаю точной причины этого, но я предполагаю, что это может быть связано с оптимизацией маршалинга и наличием уникальных определений типов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...