我的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也一样。
那么,有人知道发生了什么事吗?这些问题的答案是什么:
为什么要加载Microsoft程序集?
如何在不同的程序集/接口之间进行转换,在不同的程序集中定义?
注意:我创建了一个新的插件,非常简单,只是加载。我可以重现这个问题,所以真的,有人知道CLR如何决定加载和从哪里加载。除了在GAC中,还有另一个地方(注册表???)COM对象和它需要的互操作之间有链接吗?
答案 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。我不明白这个的确切原因,但我认为这可能与编组优化和具有唯一类型定义有关。