COM互操作程序集加载顺序

时间:2008-12-03 17:53:39

标签: .net interop outlook gac assembly-loading

我的Outlook插件遇到了非常奇怪的程序集引用问题和加载问题。这是细节(长篇大论:) :):

我有一个旧的Outlook插件,使用.Net 1.1编写和构建。在其自己的应用程序域中使用非托管填充程序加载插件。即使用户的计算机上没有1.1,也可以使用.Net 2.0。

addin使用由VS 2003针对Outlook 2000创建的自定义Outlook互操作程序集,并在重建之后进行强名称(就像我的插件一样)。

在addin项目中,我只引用了这个自定义互操作程序集,没有引用官方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,版本= 9.0.0.0,   文化=中性,   公钥= 4cfbdc5349cf59d8

这正是我所期望的。

问题是,当时 OnConnection(对象应用程序,Extensibility.ext_ConnectMode connectMode,对象addInInst,ref System.Array自定义) 调用,我在日志中看到(我有一个当前域的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,文化=中立,   公钥= 71e9bce111e9429c

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

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

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

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

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

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

1 个答案:

答案 0 :(得分:6)

我想我在微软的Primary Interop Assemblies引子中找到了问题的答案。在Visual Studio中处理PIA的方式不同:

  

当用户尝试添加对具有已注册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。我不明白这个的确切原因,但我认为这可能与编组优化和具有唯一类型定义有关。