代码之家  ›  专栏  ›  技术社区  ›  Sunny Milenov

COM互操作程序集加载顺序

  •  7
  • Sunny Milenov  · 技术社区  · 17 年前

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

    我有一个旧的Outlook插件,使用编写和构建。净值1.1。该加载项在其自己的应用程序域中使用非托管填充程序加载。它工作正常,与。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,版本=9.0.0.0, 文化=中立, 公钥令牌=4cfbdc5349cf59d8

    这正是我所期望的。

    问题是,当 OnConnection(对象应用程序、可扩展性.ext_ConnectMode连接模式、对象addInInst、引用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);
    }
    

    输出:

    会议 微软。办公室。互操作。见解, 版本=12.0.0.0,文化=中性, 公钥令牌=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应用程序对象已满 类型为: 微软。办公室。互操作。见解。应用类, 微软。办公室。互操作。见解, 版本=12.0.0.0,文化=中性, 公钥令牌=71e9bce111e9429c

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

    我已经与Reflector进行了检查,我的程序集没有以任何方式引用Microsoft的互操作程序集。我的Interop也是如此。Outlook.dll。

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

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

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

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

    1 回复  |  直到 17 年前
        1
  •  6
  •   Dirk Vollmar    17 年前

    我想我在微软的 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"
    

    据我所知,使用重新注册工具注销PIA应该会删除密钥,重新添加对自己IA的引用应该会得到预期的结果。

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

    推荐文章