EnumProcessModules因内部进程中的ERROR_INVALID_HANDLE而失败

时间:2016-03-14 13:43:01

标签: winapi pinvoke

我想枚举我自己进程中的所有模块 - 本机和托管。所以我用以下P / Invoke声明包装了EnumProcessModules:

[DllImport("psapi.dll", SetLastError = true)]
private static extern bool EnumProcessModules(
        IntPtr hProcess,
        [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.SysInt)]
        [In][Out] IntPtr[] lphModule,
        uint cb,
        [MarshalAs(UnmanagedType.U4)]
        out uint lpcbNeeded);

我使用

从我自己的进程(接近其开始时间)调用它
var processHandle = Process.GetCurrentProcess().Handle;
uint needed;
EnumProcessModules(processHandle, new IntPtr[0], 0, out needed);
var modules = new IntPtr[needed * 2];
bool enumResult = EnumProcessModules(processHandle, modules, (uint)(needed * IntPtr.Size), out needed);

在生产环境中,大部分时间都有效,但有时第二次调用失败,最后一个错误代码为6,即ERROR_INVALID_HANDLE。我知道从在线阅读和查看reference .NET implementation,如果OS加载程序触及模块信息,有时此函数会失败,但我认为错误应该是ERROR_PARTIAL_COPY。我无法理解从自己的流程运行时如何获得ERROR_INVALID_HANDLE

我试图在一个测试中通过在循环中运行代码来重新创建它(希望在一些随机迭代中它会失败)但问题并没有重现。关于这一点的有趣(和奇怪)的事情是我设法以下列方式重新创建它:

  • 在代码中的某处添加断点
  • 调试测试
  • 点击断点
  • 删除断点
  • 继续调试(F5)
  • 然后发生错误

这些复制步骤连续多次工作。每次继续调试后都会发生错误。我还在参考代码中看到EnumProcessModules在循环中被调用,以防它失败。我试图做同样的事情,但它没有帮助。一旦发生错误,它至少会发生50次......

代码是在x64计算机上运行的x86。

1 个答案:

答案 0 :(得分:0)

好的,问题是从Process返回的Handle不安全使用并被收集。这是我写的一个小副本

var handle = new IntPtr(-1); // works
var handle = Process.GetCurrentProcess().Handle; // doesn't work

GC.Collect();

uint needed;
var modules = new IntPtr[1024];

var enumResult = ModulesCheck.EnumProcessModules(handle, modules, (uint)modules.Length, out needed);
Console.WriteLine(enumResult);

所以我想我应该使用-1或者获得SafeWaitHandle并保持活着直到我完成枚举。

P.S。要让repro工作 - 必须在发布模式下运行它!