检测“暂停"Windows 8/10 进程 [英] Detect "suspended" Windows 8/10 process

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

问题描述

Windows 8/10 中的 UWP(或Metro")应用程序不在前台时可以暂停.此状态下的应用程序继续存在,但不再消耗 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() 只是半文档化的,可以在未来的操作系统中删除.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() 并记录每个进程的计数器.等待较长时间(分钟)并再次检查.如果进程计数器没有改变,则假定进程已挂起.我承认这是一个黑客,但如果时间段足够长,也许可以工作.

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.

有没有更优雅的方式?

推荐答案

为此存在 PROCESS_EXTENDED_BASIC_INFORMATION - 此 答案.你需要 IsFrozen 标志.因此,您需要具有 PROCESS_QUERY_LIMITED_INFORMATION 访问权限的开放进程(要对所有进程执行此操作,您需要在令牌中启用 SE_DEBUG_PRIVILEGE).并使用 ProcessBasicInformationPROCESS_EXTENDED_BASIC_INFORMATION 作为输入.为了枚举所有进程,我们可以使用 NtQuerySystemInformationSystemProcessInformation.当然可以使用CreateToolhelp32Snapshot + Process32First + Process32Next 但是这个api效率很低,比较直接调用NtQuerySystemInformation

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

也可以枚举进程中的所有线程并检查它的状态,如果状态等待 - 等待原因.这很容易,因为所有这些信息已经通过使用 SystemProcessInformationNtQuerySystemInformation 的单次调用返回.有了这个,我们不需要开放流程.通常这两种方式都会给出相同的结果(对于暂停/冻结)进程,但是使用 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天全站免登陆