api - Opdag 'suspenderet' Windows 8/10 proces

Indlæg af Hanne Mølgaard Plasc

Problem



UWP (eller 'Metro') apps i Windows 8/10 kan suspenderes, når de ikke er i forgrunden. Apps i denne tilstand fortsætter med at eksistere, men bruger ikke længere CPU-tid. Det ser ud til, at denne ændring blev introduceret for at forbedre ydeevnen på lav strøm/lagerenheder som tabletter og telefoner.


Hvad er den mest elegante og enkle metode til at registrere en proces i denne tilstand?


Jeg kan se 2 mulige løsninger i øjeblikket:



  1. Ring til NtQuerySystemInformation () og opregner hver proces og hver tråd. En proces er 'suspenderet', hvis alle tråde er i suspenderet tilstand. Denne tilgang vil kræve en masse kode og kritisk NtQuerySystemInformation () er kun halvdokumenteret og kunne fjernes i et fremtidigt OS. NtQueryInformationProcess () kan også tilbyde en lignende løsning med det samme problem.

  2. Ring til GetProcessTimes () og optag tællerne for hver proces. Vent lidt lang tid (minutter) og tjek igen. Hvis procestællerne ikke er blevet ændret, så antager processen er suspenderet. Jeg indrømmer, at dette er et hack, men måske kunne arbejde, hvis tidsperioden er lang nok.



Er der en mere elegant måde?

Bedste reference


for dette eksisterer PROCESS\_EXTENDED\_BASIC\_INFORMATION - betydning for flag i den beskrevet i dette svar. du er brug for IsFrozen flag. så du har brug for åben proces med PROCESS\_QUERY\_LIMITED\_INFORMATION adgang (for dette gøres for alle processer, skal du have brug for SE\_DEBUG\_PRIVILEGE aktiveret i token). og ring NtQuerySystemInformation med ProcessBasicInformation og PROCESS\_EXTENDED\_BASIC\_INFORMATION som input. for at tælle alle processer vi kan bruge NtQuerySystemInformation med SystemProcessInformation. selvfølgelig muligt og brug CreateToolhelp32Snapshot + Process32First + Process32Next men denne api er meget ikke effektiv, sammenligner direkte opkald til NtQuerySystemInformation [18] [20]


også muligt opregne alle tråde i gang, og kontroller tilstanden og hvis tilstanden venter - vent grunden. Dette er meget nemt, fordi al denne information allerede er returneret ved et enkeltopkald til NtQuerySystemInformation med SystemProcessInformation. med dette behøver vi ikke åbne processer. Normalt giver begge disse måder det samme resultat (for suspenderede/frosne) processer, men dog brug IsFrozen er den mest korrekte løsning.


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
", 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
", spi->UniqueProcessId, spi->ImageName);
                        }
                    }

                } while (NextEntryOffset = spi->NextEntryOffset);
            }
            delete [] buf;
        }
    } while (status == STATUS\_INFO\_LENGTH\_MISMATCH);
}