检测“挂起"消息. Windows 8/10进程 [英] Detect "suspended" Windows 8/10 process

查看:306
本文介绍了检测“挂起"消息. Windows 8/10进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

UWP(或地铁")应用程序不在前台时可以挂起.处于此状态的应用程序继续存在,但不再消耗CPU时间.似乎引入了此更改是为了提高低功耗/存储设备(如平板电脑和手机)的性能.

UWP (or "Metro") apps in Windows 8/10 can be suspended when they are not in the foreground. Apps in this state continue to exist but no longer consume CPU time. It looks like this change was introduced to improve performance on low-power/storage devices like tablets and phones.

在这种状态下检测进程的最优雅,最简单的方法是什么?

What is the most elegant and simple method to detect a process in this state?

我现在可以看到2种可能的解决方案:

I can see 2 possible solutions at the moment:

  1. 调用NtQuerySystemInformation()并枚举每个进程和每个线程.如果所有线程都处于挂起状态,则该进程将被挂起".这种方法将需要大量代码,并且至关重要的是NtQuerySystemInformation()仅是半文档化的,可以在以后的OS中删除. NtQueryInformationProcess()也可能提供具有相同问题的类似解决方案.

  1. Call NtQuerySystemInformation() and the enumerate each process and each thread. A process is "suspended" if all threads are in the suspended state. This approach will require a lot of code and critically NtQuerySystemInformation() is only semi-documented and could be removed in a future OS. NtQueryInformationProcess() may also offer a similar solution with the same problem.

调用GetProcessTimes()并记录每个进程的计数器.等待较长时间(分钟),然后再次检查.如果进程计数器未更改,则假定进程已暂停.我承认这是一个hack,但如果时间足够长,也许可以工作.

Call GetProcessTimes() and record the counters for each process. Wait some longish time (minutes) and check again. If the process counters haven't changed then assume the process is suspended. I admit this is a hack but maybe could work if the time period is long enough.

还有更优雅的方式吗?

推荐答案

为此存在 answer中描述的标志含义.您需要IsFrozen标志.因此,您需要具有PROCESS_QUERY_LIMITED_INFORMATION访问权限的开放进程(为此,对于所有进程都需要在令牌中启用SE_DEBUG_PRIVILEGE).并使用ProcessBasicInformation

for this exist PROCESS_EXTENDED_BASIC_INFORMATION - meaning of flags in it described in this answer. you are need IsFrozen flag. so you need open process with PROCESS_QUERY_LIMITED_INFORMATION access (for do this for all processes, you will be need have SE_DEBUG_PRIVILEGE enabled in token). and call NtQuerySystemInformation with ProcessBasicInformation and PROCESS_EXTENDED_BASIC_INFORMATION as input. for enumerate all processes we can use NtQuerySystemInformation with SystemProcessInformation. of course possible and use CreateToolhelp32Snapshot + Process32First + Process32Next but this api very not efficient, compare direct call to NtQuerySystemInformation

也可能枚举正在处理的所有线程,并检查其状态以及状态是否为wait-等待原因.这非常容易,因为使用SystemProcessInformation一次调用NtQuerySystemInformation已经返回了所有这些信息.这样,我们就不需要开放流程了.通常,这两种方法都会给出相同的结果(对于挂起/冻结),但是使用IsFrozen是最正确的解决方案.

also possible enumerate all threads in process and check it state and if state wait - wait reason. this is very easy, because all this information already returned by single call to NtQuerySystemInformation with SystemProcessInformation. with this we not need open processes. usually both this ways give the same result (for suspended/frozen) processes, but however use IsFrozen is most correct solution.

void PrintSuspended()
{
    BOOLEAN b;
    RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &b);

    ULONG cb = 0x1000;
    NTSTATUS status;
    do 
    {
        status = STATUS_INSUFFICIENT_RESOURCES;

        if (PBYTE buf = new BYTE[cb])
        {
            if (0 <= (status = NtQuerySystemInformation(SystemProcessInformation, buf, cb, &cb)))
            {
                union {
                    PBYTE pb;
                    SYSTEM_PROCESS_INFORMATION* spi;
                };

                pb = buf;

                ULONG NextEntryOffset = 0;
                do 
                {
                    pb += NextEntryOffset;

                    if (!spi->UniqueProcessId)
                    {
                        continue;
                    }

                    if (HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, 
                        (ULONG)(ULONG_PTR)spi->UniqueProcessId))
                    {
                        PROCESS_EXTENDED_BASIC_INFORMATION pebi;
                        if (0 <= NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pebi, sizeof(pebi), 0) &&
                            pebi.Size >= sizeof(pebi))
                        {
                            if (pebi.IsFrozen)
                            {
                                DbgPrint("f:%x %wZ\n", spi->UniqueProcessId, spi->ImageName);
                            }
                        }
                        CloseHandle(hProcess);
                    }

                    if (ULONG NumberOfThreads = spi->NumberOfThreads)
                    {
                        SYSTEM_THREAD_INFORMATION* TH = spi->TH;
                        do 
                        {
                            if (TH->ThreadState != StateWait || TH->WaitReason != Suspended)
                            {
                                break;
                            }
                        } while (TH++, --NumberOfThreads);

                        if (!NumberOfThreads)
                        {
                            DbgPrint("s:%x %wZ\n", spi->UniqueProcessId, spi->ImageName);
                        }
                    }

                } while (NextEntryOffset = spi->NextEntryOffset);
            }
            delete [] buf;
        }
    } while (status == STATUS_INFO_LENGTH_MISMATCH);
}

这篇关于检测“挂起"消息. Windows 8/10进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆