Shell扩展中Microsoft.Xaml.Behaviors.dll同目录无法加载,需添加至GAC的原因及免GAC方案咨询
Shell扩展中Microsoft.Xaml.Behaviors.dll同目录无法加载,需添加至GAC的原因及免GAC方案咨询
嗨,这个问题其实和Shell扩展的运行环境——也就是explorer.exe进程的程序集加载机制密切相关,我来给你拆解一下:
一、为什么同目录下只有Microsoft.Xaml.Behaviors.dll找不到?
普通桌面应用启动时,CLR会优先从程序的启动目录搜索依赖DLL,但Shell扩展是直接注入到explorer.exe这个系统进程里运行的,它的加载规则和普通应用完全不同:
explorer.exe的默认DLL搜索路径是系统目录(比如System32),而不是你的Shell扩展所在的文件夹;- 你的其他依赖DLL能被找到,大概率是这两种情况:要么这些DLL是强命名且已经存在于GAC中,要么是你的代码通过显式引用触发了CLR的"私有路径探测"(CLR会关联主程序集所在的目录去搜索);
- 而
Microsoft.Xaml.Behaviors.dll是被WPF XAML解析器动态加载的——XAML加载器的上下文和代码里显式引用的程序集加载上下文不一样,它不会自动去你的Shell扩展目录搜索依赖,只会走系统默认路径,所以哪怕DLL在同目录也找不到,必须放进GAC才能被系统路径搜索到。
二、跳过GAC的可行方案
既然你是通过NuGet引用的Behaviors包,有几个方法可以绕过GAC部署:
1. 配置私有探测路径
给你的Shell扩展程序集添加同名的配置文件(比如你的主DLL叫MyShellExtension.dll,就创建MyShellExtension.dll.config),放在和DLL同一目录,内容如下:
<configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <!-- 指定当前目录作为私有探测路径,让CLR优先在这里找依赖 --> <probing privatePath="." /> </assemblyBinding> </runtime> </configuration>
这样可以告诉CLR,加载你的扩展的依赖时,先去扩展所在的目录搜索,不用只看系统路径。
2. 合并程序集
用工具把Microsoft.Xaml.Behaviors.dll合并到你的主Shell扩展DLL里,这样就不需要单独加载这个依赖了。常用的工具比如:
- ILMerge:传统的程序集合并工具,需要注意WPF相关DLL的合并细节,可能需要调整参数;
- Fody/Costura:通过NuGet包集成的合并工具,配置简单,自动把依赖嵌入主程序集,适合快速实现。
3. 手动提前加载DLL
在你的Shell扩展初始化的最开始阶段(比如构造函数或者初始化方法里),手动加载Microsoft.Xaml.Behaviors.dll,这样后续XAML解析时就会直接使用已经加载好的程序集,不会再去搜索:
using System.IO; using System.Reflection; // 获取当前扩展DLL所在的目录 var extensionDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); // 拼接Behaviors DLL的完整路径 var behaviorsPath = Path.Combine(extensionDir, "Microsoft.Xaml.Behaviors.dll"); // 手动加载程序集 Assembly.LoadFrom(behaviorsPath);
备注:内容来源于stack exchange,提问作者LechExt
相关产品推荐
相关产品推荐

