我的Outlook插件遇到了非常奇怪的程序集引用问题和加载问题.这是细节(长篇大论:)):
我有一个旧的Outlook插件,使用.Net 1.1编写和构建.在其自己的应用程序域中使用非托管填充程序加载插件.即使用户的计算机上没有1.1,也可以使用.Net 2.0.
该插件使用由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,Version = 9.0.0.0,Culture = neutral,PublicKeyToken = 4cfbdc5349cf59d8
这正是我所期望的.
问题是,当调用OnConnection(对象应用程序,Extensibility.ext_ConnectMode connectMode,对象addInInst,ref System.Array自定义)时,我在日志中看到(我有一个当前域的AssemblyLoad事件的钩子)MS interop程序集也被加载:
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也是如此.
那么,有人知道发生了什么吗?这些问题的答案是什么:
为什么它加载Microsoft程序集?
如何在不同的程序集中定义的不相关的类/接口之间进行转换?
注意:我创建了一个新的插件,非常简单,只是加载.我可以重现这个问题,所以真的,有人知道CLR如何决定加载和从哪里加载.除了在GAC中,还有另一个地方(注册表???)COM对象和它需要的互操作之间有链接吗?
我想我在Microsoft的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.我不明白这个的确切原因,但我认为这可能与编组优化和具有唯一类型定义有关.