我目前正在编码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方法获取进程句柄,但结果相同。 有人遇到过这种问题吗?
答案 0 :(得分:0)
因此,由于杰里米·汤普森(Jeremy Thompson)的评论使我获得了关于课程0的信息,并且通过进一步的研究,我得以解决了我的问题。
参考文献:
Application Loader to launch process in another session
Wait for process exit (ProcessWaitHandle)
我所做的是修改第一个参考中的示例代码,以提供一个进程ID(我希望GDI对象计数的那个)并启动我的小控制台应用程序(它也使用相同的进程ID,并返回GDI)通过复制提供的进程的令牌并调用 CreateProcessAsUser 在同一会话中作为退出代码)。 通过在同一会话中启动控制台应用程序,我能够在以前测试过的每个操作系统上检索有关GDI对象的正确信息,但Win Server 2003除外,而我完全可以不使用它。