You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

动态加载DLL后释放DLL与PDB文件的问题求助

解决Coded UI项目编译时obj目录PDB被占用的问题

这问题我之前帮朋友排查过类似的,核心就是你的Windows主应用进程锁住了obj目录下的PDB文件——哪怕你已经释放了bin目录里的DLL和PDB,编译Coded UI项目时,编译器需要写入obj的PDB,还是会因为文件被占用报错。给你几个实用的解决方案,按优先级排序:

1. 仅加载DLL字节,避免触发符号文件加载

你已经试过用Assembly.Load加载字节数组,但可能之前的操作还是让CLR尝试加载了PDB符号。记得只加载DLL的字节流,不要附带加载PDB文件,这样CLR不会去查找任何符号文件,自然不会锁定obj目录的PDB。

示例代码:

string dllPath = @"C:\YourProject\RecordAndPlayback\bin\Debug\RecordAndPlayback.dll";
byte[] dllBytes = File.ReadAllBytes(dllPath);
// 只加载DLL字节,不加载符号
Assembly codedUIAssembly = Assembly.Load(dllBytes);
// 调用测试方法...

这样主应用完全不会接触到obj目录的PDB,编译时自然不会冲突。

2. 修改Coded UI项目的PDB输出路径

默认情况下,Coded UI项目会在obj\Debug目录生成中间PDB,同时在bin\Debug生成输出PDB。你可以把中间PDB的路径改到和输出目录一致,或者直接跳过中间PDB的生成:

  1. 右键Coded UI项目 → 属性
  2. 切换到生成标签页,点击右下角的高级按钮
  3. 在弹出的窗口里,把调试信息改成pdb-only,然后把PDB文件路径设为bin\Debug\RecordAndPlayback.pdb(和输出DLL同目录)
  4. 保存设置后重新编译

这样编译时只会在bin目录生成PDB,obj目录不再产生PDB文件,也就不存在被锁定的问题了。

3. 启用AppDomain的影子复制(Shadow Copy)

如果你需要保留调试符号的加载,那可以用AppDomain的影子复制功能——CLR会把要加载的DLL/PDB复制到临时目录,然后加载副本,原文件就会被释放,不会被锁定。之前你试过AppDomain加载卸载,可能没配置影子复制:

// 配置AppDomain的影子复制
var setup = new AppDomainSetup
{
    ShadowCopyFiles = "true", // 启用影子复制
    CachePath = Path.Combine(Path.GetTempPath(), "CodedUICache"), // 缓存副本的临时目录
    ApplicationBase = Path.GetDirectoryName(@"C:\YourProject\RecordAndPlayback\bin\Debug") // DLL所在目录
};

// 创建独立的AppDomain
var codedUIDomain = AppDomain.CreateDomain("CodedUITestDomain", null, setup);

// 在新域中加载并执行测试方法
var testInstance = codedUIDomain.CreateInstanceAndUnwrap(
    "RecordAndPlayback",
    "RecordAndPlayback.TestClass"
) as ITestInterface; // 记得定义一个共享的接口来调用方法
testInstance.RunTest();

// 卸载AppDomain,释放所有资源
AppDomain.Unload(codedUIDomain);

这个方案的好处是能保留调试功能,同时完全释放原文件,编译时不会冲突。

4. 兜底方案:强制释放文件句柄(不推荐)

如果上面的方案都不行,可以用Windows API强制关闭占用obj/PDB的句柄,但这个方法比较hack,可能导致主应用不稳定,仅作为应急手段。你需要用P/Invoke调用NtDuplicateObjectNtClose来查找并关闭对应句柄,具体代码可以参考进程句柄操作的示例,但一定要谨慎使用。


内容的提问来源于stack exchange,提问作者Islam El-gendy

火山引擎 最新活动