GetGuiResources返回0(错误87)或无意义的值

时间:2019-07-26 14:21:31

标签: c# windows

我目前正在编码Windows服务(安装为LocalSystem),该服务监视PC /服务器上的若干事物,包括进程。对于进程,我正在监视内存使用情况,还“尝试”获得每个进程的GDI对象数(如在任务管理器中看到的那样)。

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

基本上,我有一个可执行文件名称列表,对于每个可执行文件名称,我都使用GetProcessesByName检索所有流程实例,然后对于每个唯一的流程,我都将使用该句柄并将其发送给该函数以使Gdi对象计数回来。 / p>

当我在本地计算机上以简单的控制台应用程序(通过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,在其他OS上,我得到提到的结果。 / p>

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

// 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方法获取进程句柄,但结果相同。 有人遇到过这种问题吗?

1 个答案:

答案 0 :(得分:0)

因此,由于杰里米·汤普森(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除外,而我完全可以不使用它。