【问题标题】:GetGuiResources returns 0 (error 87) or nonsense valueGetGuiResources 返回 0(错误 87)或无意义的值
【发布时间】:2019-07-26 14:21:31
【问题描述】:

我目前正在编写一个 Windows 服务(作为 LocalSystem 安装),它可以监控 pc/server 上的一些东西,包括进程。对于进程,我正在观察内存使用情况,并“尝试”获取每个进程的 GDI 对象数量(可以在任务管理器中看到)。

遗憾的是,C# Process 对象没有内置 gdi 计数,因此我使用来自“user32.dll”的 GetGuiResources 方法,如下例所示: https://www.pinvoke.net/default.aspx/user32.getguiresources.

基本上我有一个可执行名称列表,对于每个可执行名称,我使用 GetProcessesByName 来检索所有进程实例,然后对于每个唯一进程,我获取句柄并将其发送到函数以获取 Gdi 对象计数。

当我在本地机器上将其作为简单的控制台应用程序(通过 Console.ReadLine 提供名称)尝试时,只要控制台应用程序以管理员身份启动,它就可以正常工作;我得到与任务管理器相同的数字。 但是,当监控服务调用此函数时,我得到 0(返回错误代码 87)或更糟:与服务绑定的进程(无 gui)在任务管理器时返回一些随机数(12、7、4 等)实际上显示 0(最后一个错误 = 0)。

所以总而言之,每个在任务管理器中显示一些 GID 对象的进程都返回 0(错误 87),每个有 0 的进程都返回一个数字(没有错误,或者监控服务本身的错误 183)。

我已经在 Windows 10、Windows Server 2012、Windows Server 2008、Windows Server 2003、Windows Server 2016 上进行了尝试。在 Windows 10(我的机器)上,我到处都是 0,在其他操作系统上,我得到了提到的结果。

这是我使用的代码的简化版本:

// Monitoring processes    exeName example: ssms, sqlbrowser
List<Process> result = Process.GetProcessesByName(exeName).ToList();
if (processes != null)
{
    for (int i = 0; i < processes.Count; i++)
    {
        int gdiCount = processes[i].GetGDIObjectsCount();  // extension method
        // logging and doing stuff with gdi count here (but i get 0s or random numbers as I told)
    }
}

// Process extension method
public static class CProcessExtensions
{
    [DllImport("User32", SetLastError = true)]
    extern private static int GetGuiResources(IntPtr hProcess, int uiFlags);

    private static int GetGDICount(IntPtr processHandle)
    {
        if (processHandle == IntPtr.Zero)
        {
            return -1;
        }

        int count = GetGuiResources(processHandle, 0);

        // Logging Marshal.GetLastWin32Error() here

        return count;
    }

    public static int GetGDIObjectsCount(this Process process)
    {
        IntPtr handle;
        process.Refresh();

        try
        {
            handle = process.Handle;
        }
        catch (Exception ex)
        {
            handle = IntPtr.Zero;
        }

        return GetGDICount(handle);
    }
}

我也尝试使用 OpenProcess dll 方法获取进程句柄,但结果相同。 以前有人遇到过这种问题吗?

【问题讨论】:

  • 这是重复的吗? stackoverflow.com/a/44272192/495455
  • 这确实似乎相关,可以解释我一直遇到的问题,不知道服务在一个孤立的会话中运行。我要进行更多测试。

标签: c# windows


【解决方案1】:

因此,感谢 Jeremy Thompson 的评论让我了解了第 0 次会议的信息,并且通过进一步研究,我能够解决我的问题。

参考资料:

Application Loader to launch process in another session

Wait for process exit (ProcessWaitHandle)

Get Exit code

我所做的是修改第一个引用中的示例代码以提供进程 ID(我想要 GDI 对象计数的那个)并启动我的小控制台应用程序(它也采用相同的进程 ID,并返回 GDI通过复制所提供进程的令牌并调用 CreateProcessAsUser 在同一会话中计为退出代码。 通过在同一个会话中启动控制台应用程序,我能够在我之前测试的每个操作系统上检索 GDI 对象的正确信息,除了 Win Server 2003,我完全可以不用它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-04
    • 2020-05-24
    • 2016-08-09
    • 2015-08-23
    相关资源
    最近更新 更多