【问题标题】:OpenProcess failed to open existing process via id (Last Error code: 1008)?OpenProcess 无法通过 id 打开现有进程(上次错误代码:1008)?
【发布时间】:2015-08-31 16:00:40
【问题描述】:

我正在尝试使用 OpenProcess 通过进程 ID 打开所有现有进程。但不知何故,它只在第一次调用时起作用,而下一次调用显示它不适用于报告为 1008 的错误代码(尝试引用不存在的令牌)。

代码如下:

[DllImport("kernel32.dll", SetLastError=true)]
public static extern IntPtr OpenProcess(ProcessAccessFlags access, bool inheritHandle, int procId);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);

[Flags]
public enum ProcessAccessFlags : uint
{
    All = 0x001F0FFF,
    Terminate = 0x00000001,
    CreateThread = 0x00000002,
    VirtualMemoryOperation = 0x00000008,
    VirtualMemoryRead = 0x00000010,
    VirtualMemoryWrite = 0x00000020,
    DuplicateHandle = 0x00000040,
    CreateProcess = 0x000000080,
    SetQuota = 0x00000100,
    SetInformation = 0x00000200,
    QueryInformation = 0x00000400,
    QueryLimitedInformation = 0x00001000,
    Synchronize = 0x00100000
}

foreach (var proc in Process.GetProcesses()) {
    var procHandle = OpenProcess(ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VirtualMemoryOperation, false, proc.Id);
    var eCode = Marshal.GetLastWin32Error(); 
    //checking the last error code using Marshal.GetLastWin32Error() 
    //shows that it succeeds the first time with error code of 0
    //Then all the next calls show error code of `1008`.
    if(procHandle != IntPtr.Zero) CloseHandle(procHandle);
}

我已经尝试在谷歌上搜索错误,但不确定这里可能有什么问题。如果你能让我知道出了什么问题,那就太好了。谢谢!

更新: 正如我所说,它似乎只适用于循环中的第一个进程。但我非常怀疑即使在这种情况下它实际上也不起作用,因为从我看到的procHandleproc.Handle 保持完全不同的值,除非 OpenProcess 返回的句柄是 另一种 句柄,与 proc.Handle 不同(如果是这样,那真的很奇怪)。因此,如果我目前怀疑的是真的,那意味着OpenProcess 完全不起作用。在这种情况下它根本没用,并且仍然不确定我们可以在哪种情况下使用它。

【问题讨论】:

  • 这看起来很正常。您有两个不同的 PID。毫不奇怪,你可以用一个做事,但不能用另一个做事。 FWIW,您没有hwnd。那将是一个窗口的句柄。 OpenProcess 返回一个进程句柄。完全不同的野兽。
  • 如果您查看proc.ProcessName,它在哪个进程上失败了?如果该属性未提供任何信息,PID 是否对应于您系统上的有效进程?
  • @DavidHeffernan 我不明白你的解释。您说OpenProcess 返回一个进程句柄,我显然将hwnd 设置为返回值。那么为什么你还说hwnd 是窗口句柄呢?
  • @theB foreach 循环工作正常,我可以看到轮到不同的过程。正如我所解释的,它在第二个过程中失败了。在这种情况下,ProcessName 并不重要。
  • 进程名称并不重要,除非它可以帮助您找到错误,如果它指的是无效进程,或者您无权访问的进程,或者最近终止的进程,或者任何数量的其他东西......另外,GetLastError 仅包含一个扩展错误,如果返回的句柄是NULL(又名IntPtr.Zero)。返回的句柄是NULL吗?

标签: c# winapi process pinvoke


【解决方案1】:

您的错误检查已损坏。 OpenProcess 返回一个非零值表示成功。错误代码仅在OpenProcess 失败时才有意义,即OpenProcess 返回零。

因此,您只能在函数调用失败时询问错误代码,如其返回值所示。您检查错误代码而不检查返回值,这是一个错误。你的代码应该更像这样:

foreach (var proc in Process.GetProcesses())
{
    var procHandle = OpenProcess(ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VirtualMemoryOperation, false, proc.Id);
    if (procHandle == IntPtr.Zero)
    {
        // api call failed, can read error code
        var eCode = Marshal.GetLastWin32Error();
    }
    else
    {
        // api call succeeded, do stuff with handle
        CloseHandle(procHandle);
    }
}

【讨论】:

  • 我在手机上打字时弄错了逻辑。现在代码是准确的。
  • 现在它实际上已经接近我尝试过的了。实际上我刚刚再次尝试了这个确切的代码,OpenProcess 的返回值几乎不是 IntPtr.Zero (你可以阅读我在我的问题下发布的一些 cmets)。仅在最后 2-3 个循环中,它返回 0,但有时不会。您可以尝试代码以查看它的实际效果。顺便说一句,我当前的应用目标是 32 位。
  • 没有。这里的代码与问题中的代码非常不同。你当然可以看到。
  • 不一样,但我以前试过这个,现在我又试了一次。目前没有打印结果(我尝试打印eCode),因为procHandle 永远不是IntPtr.Zero。你应该自己试试。 OpenProcess 也可能是有问题的,因为一个人经历过这个并在第二条评论msdn.microsoft.com/en-us/library/windows/desktop/… 中发布
  • OpenProcess返回一个非零值时,它就成功了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-15
  • 2022-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多