从Rust调用C# DLL时start_monitor函数依赖缺失问题
解决Rust调用C# DLL时NAudio依赖缺失的问题
问题原因
当从非.NET进程(如Rust)加载.NET Framework DLL时,.NET的程序集加载器会优先在Rust可执行文件的目录而非C# DLL所在目录搜索依赖。这就是为什么C#控制台调用正常(工作目录是C# DLL目录),但Rust调用失败的核心原因。
可行解决方案
1. 复制依赖到Rust输出目录
直接把NAudio.Wasapi.dll、NAudio.dll等所有NAudio相关依赖文件,复制到Rust项目的target/debug(调试模式)或target/release(发布模式)目录下,和Rust生成的可执行文件放在一起。
2. 切换Rust程序的工作目录
在加载C# DLL前,将Rust程序的工作目录切换到C# DLL所在目录,让.NET加载器能在该目录找到依赖。修改Rust代码:
extern crate libloading; use libloading::{Library, Symbol}; use std::env; type SayHelloFunc = unsafe extern "C" fn(); fn main() { // 切换到C# DLL所在目录 env::set_current_dir("C:\\path\\to\\MicMonitorDllNetFramework") .expect("Failed to switch working directory"); let lib_path = "MicMonitorDllNetFramework.dll"; let lib = unsafe { Library::new(lib_path).expect("Could not load the library") }; unsafe { let myname: Symbol<SayHelloFunc> = lib.get(b"my_name\0").expect("Could not load function my_name"); let mics: Symbol<SayHelloFunc> = lib.get(b"start_monitor\0").expect("Could not load function start_monitor"); myname(); mics(); } }
3. 在C# DLL中添加程序集解析逻辑
在C# DLL的类中添加静态构造函数,注册程序集解析事件,强制从C# DLL所在目录加载依赖。修改C#代码:
using NAudio.CoreAudioApi; using NAudio.CoreAudioApi.Interfaces; using RGiesecke.DllExport; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.InteropServices; namespace MicMonitorDllNetFramework { public class MicMonitor { // 静态构造函数,注册程序集解析事件 static MicMonitor() { AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { // 获取当前DLL所在目录 string currentDllDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); // 拼接依赖DLL的路径 string dllName = new AssemblyName(args.Name).Name + ".dll"; string dllPath = Path.Combine(currentDllDir, dllName); if (File.Exists(dllPath)) { return Assembly.LoadFrom(dllPath); } return null; }; } [DllExport("start_monitor", CallingConvention = CallingConvention.Cdecl)] public static void GetActiveApplications() { // 原有代码不变... } [DllExport("my_name", CallingConvention = CallingConvention.Cdecl)] public static void MyName() { Console.WriteLine("Hello world!"); } }}
重新编译C# DLL后,无论Rust程序在哪运行,都会自动从C# DLL所在目录加载依赖。
4. 将C# DLL和依赖打包成单文件
使用Costura.Fody工具将NAudio依赖嵌入到C# DLL中,生成一个包含所有依赖的单文件DLL,无需单独携带依赖文件:
- 在C#项目中安装
Costura.FodyNuGet包 - 重新编译C# DLL,生成的DLL会包含所有NAudio依赖
- 直接在Rust中调用这个单文件DLL即可
内容的提问来源于stack exchange,提问作者sid patra
相关产品推荐
相关产品推荐

