.NET 8 COM互操作WPF类库加载依赖程序集的UserControl时触发System.IO.FileNotFoundException异常
.NET 8 COM互操作WPF类库加载依赖程序集的UserControl时触发System.IO.FileNotFoundException异常
我完全懂你碰到的这个糟心问题——明明依赖的Wpf.Tools.CSharp程序集能被正常调用(比如实例化里面的类能弹出MessageBox),但一在WPF窗口里用它的UserControl,VB6调用COM组件时就触发找不到文件的异常,换用WPF测试程序却一切正常,这反差真的让人摸不着头脑。
先帮你梳理下核心的现象:
- 主程序集是启用了COM托管的.NET 8 WPF类库,引用了另一个WPF类库
Wpf.Tools.CSharp - 直接通过主程序集实例化依赖库的普通类,完全没问题,说明依赖集确实存在且能被加载
- 但只要主程序集的窗口XAML里引用了
ToolsUserControl,VB6调用时就会抛出System.IO.FileNotFoundException,提示找不到Wpf.Tools.CSharp - WPF测试程序调用COM组件全程正常,问题仅出在VB6的COM调用场景
问题根源:COM宿主的程序集加载上下文差异
这本质是普通WPF应用和COM宿主环境的程序集加载逻辑不一样导致的:
- 普通WPF应用启动时,会自动在应用目录、GAC等常规路径查找依赖程序集;但VB6作为COM宿主调用
comhost.dll时,.NET运行时的加载上下文更受限,它会优先从VB6进程的当前工作目录或者GAC找依赖,而不是主COM组件的输出目录。 - 当你实例化依赖库的普通类时,是通过主程序集的代码直接触发加载,这时候.NET能利用
Assembly.Load的上下文找到依赖;但WPF解析XAML中的csharp:ToolsUserControl时,XAML解析器的加载逻辑是独立的,它用默认加载上下文查找程序集,这时候如果依赖集不在VB6的工作目录或GAC里,就会找不到。
具体解决方案
下面给你三个可行的解决办法,按需选择:
方案1:把依赖程序集复制到VB6的运行目录
这是最直接的验证方法:
- 找到VB6项目的运行目录(默认是VB6的安装目录,或者你编译生成的EXE所在目录)
- 把
Wpf.Tools.CSharp.dll及其依赖文件(如果有的话)复制到这个目录 - 重新运行VB6测试程序,XAML解析器就能找到依赖集了
方案2:将依赖程序集安装到GAC
如果不想复制文件到多个目录,可以把依赖集注册到全局程序集缓存:
- 注意你的目标平台是x86,要使用x86版本的
gacutil.exe(通常在C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\x86,如果是.NET 8,找对应SDK的x86工具) - 打开x86的命令提示符,执行命令:
gacutil /i Wpf.Tools.CSharp.dll - 安装到GAC后,不管COM宿主的工作目录在哪,.NET运行时都能从GAC找到这个程序集
方案3:在主COM组件中添加程序集解析事件
这个方法不需要复制文件或安装GAC,让主组件主动告诉运行时去哪找依赖:
- 在主程序集的
SimpleComInteropClass构造函数中,注册AssemblyResolve事件,手动指定依赖集的路径:using System.Reflection; using System.IO; namespace Wpf.ComInterop { [ComVisible(true)] [Guid("C3634287-1BFA-410A-BEE7-634F080E9682")] [ClassInterface(ClassInterfaceType.None)] public class SimpleComInteropClass : ISimpleHost { public SimpleComInteropClass() { AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; } private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { // 检查是否是找不到目标依赖程序集 if (args.Name.StartsWith("Wpf.Tools.CSharp,")) { // 获取主程序集的所在目录 string mainAssemblyPath = Assembly.GetExecutingAssembly().Location; string mainDir = Path.GetDirectoryName(mainAssemblyPath); // 拼接依赖程序集的路径 string toolsAssemblyPath = Path.Combine(mainDir, "Wpf.Tools.CSharp.dll"); // 加载并返回程序集 return Assembly.LoadFrom(toolsAssemblyPath); } return null; } // 其他原有代码... } } - 这样当XAML解析器找不到依赖集时,会触发这个事件,主组件会指引运行时到自己的目录下去找依赖
额外验证提示
- 先试试方案1快速确认是不是路径问题,没问题的话再根据需求选方案2或3
- 确保主程序集和依赖程序集的平台目标一致(都是x86),避免因为平台不兼容导致的加载失败
内容来源于stack exchange
相关产品推荐
相关产品推荐

