7

我在使用 Outlook 插件时遇到了非常奇怪的程序集参考问题和加载问题。以下是详细信息(说来话长:)):

我有一个旧的 Outlook 插件,使用 .Net 1.1 编写和构建。插件是使用其自己的应用程序域中的非托管 shim 加载的。使用 .Net 2.0 可以正常工作,即使用户机器上不存在 1.1。

该插件使用由 VS 2003 针对 Outlook 2000 创建的自定义 Outlook 互操作程序集,然后重建为强命名(就像我的插件一样)。

在插件项目中,我只引用了这个自定义互操作程序集,没有引用官方的 MS 互操作程序集。

当这个插件在 Outlook 2007 和 .Net 2.0 的环境中使用时,官方的 MS 互操作程序集安装在 GAC 中,出于某种原因,我看到插件加载并使用它们。

在 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、Version=9.0.0.0、Culture=neutral、PublicKeyToken=4cfbdc5349cf59d8

这正是我所期望的。

问题是,当调用 OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom) 时,我在日志中看到 MS 互操作(我有一个当前域的 AssemblyLoad 事件的挂钩)程序集也被加载:

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,Version=12.0.0.0,Culture=neutral,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, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c

这真的很奇怪,你可以在下一行看到我可以成功地转换到 Outlook.Application 没有任何问题。

我已经检查过 Reflector,我的程序集不以任何方式引用 Microsoft 的互操作程序集。我的 Interop.Outlook.dll 也是如此。

那么,有人知道发生了什么吗?这些问题的答案是什么:

  1. 为什么它会加载 Microsoft 程序集?

  2. 如何在不同程序集中定义的不相关类/接口之间进行转换?

注意:我创建了一个新插件,非常简单,它什么都不做,只是加载。我可以重现这个问题,所以真的,有谁知道 CLR 如何决定加载什么互操作以及从哪里加载。除了在 GAC 中,还有其他地方(注册表???)在 COM 对象和它所需的互操作之间存在链接?

4

1 回答 1

7

我想我在 Microsoft 的Primary Interop Assemblies入门中找到了您问题的答案。PIA 在 Visual Studio 中的处理方式不同:

当用户尝试添加对已注册 PIA 的类型库的引用时,Visual Studio 将静默使用已注册的 PIA,而不是使用 Tlbimp 重新导入类型库。这可确保尽可能使用 PIA。

这意味着当你在项目中添加对你自己的 IA 的引用时,Visual Studio 会检查是否有为此 COM 对象注册的 PIA。Outlook PIA 在以下键下注册:

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"

据我了解,使用 regasm 工具取消注册 PIA 应该删除密钥并重新添加对您自己的 IA 的引用应该会产生预期的结果。

但是,如果有可用的 PIA,Microsoft 不建议使用自定义 IA。我不明白这个的确切原因,但我认为这可能与封送优化和具有独特的类型定义有关。

于 2009-01-29T01:00:45.473 回答