如何获取线程状态(例如暂停),内存+ CPU使用率,启动时间,优先级等

时间:2014-04-08 22:50:00

标签: c++ multithreading memory process suspend

如果线程已被SuspendThread()暂停,如何获取信息。没有提供此信息的API。 toolhelp快照API非常有限。 互联网和StackOverflow上有很多误导性信息。 StackOverflow上的一些人甚至说这是不可能的。

其他人发布了需要Windows 7的解决方案。但我需要代码才能使用XP。

1 个答案:

答案 0 :(得分:10)

我自己找到了答案。 我写了一个类cProcInfo,它获取了很多关于进程和线程的信息,如:

  1. 流程和线程标识符
  2. 处理父标识符
  3. 流程名称
  4. 优先级
  5. 上下文切换
  6. 地址
  7. 国家(运行,等待,暂停等)。
  8. 进程和线程启动的日期和时间
  9. 在内核模式下花费的时间
  10. 在用户模式下花费的时间
  11. 内存使用
  12. 处理次数
  13. 页面错误
  14. 我的班级适用于Windows 2000,XP,Vista,7,8 ......

    以下代码显示了如何确定进程640中的线程1948是否被隐藏:

    Main()
    {
        cProcInfo i_Proc;
        DWORD u32_Error = i_Proc.Capture();
        if (u32_Error)
        {
            printf("Error 0x%X capturing processes.\n", u32_Error);
            return 0;
        }
    
        SYSTEM_PROCESS* pk_Proc = i_Proc.FindProcessByPid(1948);
        if (!pk_Proc)
        {
            printf("The process does not exist.\n");
            return 0;
        }
    
        SYSTEM_THREAD* pk_Thread = i_Proc.FindThreadByTid(pk_Proc, 640);
        if (!pk_Thread)
        {
            printf("The thread does not exist.\n");
            return 0;
        }
    
        BOOL b_Suspend;
        i_Proc.IsThreadSuspended(pk_Thread, &b_Suspend);
    
        if (b_Suspend) printf("The thread is suspended.\n");
        else           printf("The thread is not suspended.\n");
        return 0;
    }
    

    我的类首先使用NtQuerySystemInformation()捕获所有当前正在运行的进程和线程,然后搜索请求的线程的信息。

    您可以轻松添加按名称搜索流程的功能。 (pk_Proc->usName

    我的班级来了。它只有一个头文件:

    #pragma once
    
    #include <winternl.h>
    #include <winnt.h>
    
    typedef LONG NTSTATUS;
    
    #define STATUS_SUCCESS              ((NTSTATUS) 0x00000000)
    #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xC0000004)
    
    enum KWAIT_REASON
    {
        Executive,
        FreePage,
        PageIn,
        PoolAllocation,
        DelayExecution,
        Suspended,
        UserRequest,
        WrExecutive,
        WrFreePage,
        WrPageIn,
        WrPoolAllocation,
        WrDelayExecution,
        WrSuspended,
        WrUserRequest,
        WrEventPair,
        WrQueue,
        WrLpcReceive,
        WrLpcReply,
        WrVirtualMemory,
        WrPageOut,
        WrRendezvous,
        Spare2,
        Spare3,
        Spare4,
        Spare5,
        Spare6,
        WrKernel,
        MaximumWaitReason
    };
    
    enum THREAD_STATE
    {
        Running = 2,
        Waiting = 5,
    };
    
    #pragma pack(push,8)
    
    struct CLIENT_ID
    {
        HANDLE UniqueProcess; // Process ID
        HANDLE UniqueThread;  // Thread ID
    };
    
    // http://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/thread.htm
    // Size = 0x40 for Win32
    // Size = 0x50 for Win64
    struct SYSTEM_THREAD
    {
        LARGE_INTEGER KernelTime;
        LARGE_INTEGER UserTime;  
        LARGE_INTEGER CreateTime;
        ULONG         WaitTime;
        PVOID         StartAddress;
        CLIENT_ID     ClientID;           // process/thread ids
        LONG          Priority;
        LONG          BasePriority;
        ULONG         ContextSwitches;
        THREAD_STATE  ThreadState;
        KWAIT_REASON  WaitReason;
    };
    
    struct VM_COUNTERS // virtual memory of process
    {
        ULONG_PTR PeakVirtualSize;
        ULONG_PTR VirtualSize;
        ULONG     PageFaultCount;
        ULONG_PTR PeakWorkingSetSize;
        ULONG_PTR WorkingSetSize;
        ULONG_PTR QuotaPeakPagedPoolUsage;
        ULONG_PTR QuotaPagedPoolUsage;
        ULONG_PTR QuotaPeakNonPagedPoolUsage;
        ULONG_PTR QuotaNonPagedPoolUsage;
        ULONG_PTR PagefileUsage;
        ULONG_PTR PeakPagefileUsage;
    };
    
    // http://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/process.htm
    // See also SYSTEM_PROCESS_INROMATION in Winternl.h
    // Size = 0x00B8 for Win32
    // Size = 0x0100 for Win64
    struct SYSTEM_PROCESS
    {
        ULONG          NextEntryOffset; // relative offset
        ULONG          ThreadCount;
        LARGE_INTEGER  WorkingSetPrivateSize;
        ULONG          HardFaultCount;
        ULONG          NumberOfThreadsHighWatermark;
        ULONGLONG      CycleTime;
        LARGE_INTEGER  CreateTime;
        LARGE_INTEGER  UserTime;  
        LARGE_INTEGER  KernelTime;
        UNICODE_STRING ImageName;
        LONG           BasePriority;
        PVOID          UniqueProcessId;
        PVOID          InheritedFromUniqueProcessId;
        ULONG          HandleCount;
        ULONG          SessionId;
        ULONG_PTR      UniqueProcessKey;
        VM_COUNTERS    VmCounters;
        ULONG_PTR      PrivatePageCount;
        IO_COUNTERS    IoCounters;   // defined in winnt.h
    };
    
    #pragma pack(pop)
    
    typedef NTSTATUS (WINAPI* t_NtQueryInfo)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
    
    class cProcInfo
    {
    public:
        cProcInfo()
        {
            #ifdef WIN64
                assert(sizeof(SYSTEM_THREAD) == 0x50 && sizeof(SYSTEM_PROCESS) == 0x100);
            #else
                assert(sizeof(SYSTEM_THREAD) == 0x40 && sizeof(SYSTEM_PROCESS) == 0xB8);
            #endif
    
            mu32_DataSize  = 1000;
            mp_Data        = NULL;
            mf_NtQueryInfo = NULL;
        }
        virtual ~cProcInfo()
        {
            if (mp_Data) LocalFree(mp_Data);
        }
    
        // Capture all running processes and all their threads.
        // returns an API or NTSTATUS Error code or zero if successfull
        DWORD Capture()
        {
            if (!mf_NtQueryInfo)
            {
                mf_NtQueryInfo = (t_NtQueryInfo)GetProcAddress(GetModuleHandleA("NtDll.dll"), "NtQuerySystemInformation");
                if (!mf_NtQueryInfo)
                    return GetLastError();
            }
    
            // This must run in a loop because in the mean time a new process may have started 
            // and we need more buffer than u32_Needed !!
            while (true)
            {
                if (!mp_Data) 
                {
                    mp_Data = (BYTE*)LocalAlloc(LMEM_FIXED, mu32_DataSize);
                    if (!mp_Data)
                        return GetLastError();
                }
    
                ULONG u32_Needed = 0;
                NTSTATUS s32_Status = mf_NtQueryInfo(SystemProcessInformation, mp_Data, mu32_DataSize, &u32_Needed);
    
                if (s32_Status == STATUS_INFO_LENGTH_MISMATCH) // The buffer was too small
                {
                    mu32_DataSize = u32_Needed + 4000;
                    LocalFree(mp_Data);
                    mp_Data = NULL;
                    continue;
                }
                return s32_Status;
            }
        }
    
        // Searches a process by a given Process Identifier
        // Capture() must have been called before!
        SYSTEM_PROCESS* FindProcessByPid(DWORD u32_PID)
        {
            if (!mp_Data)
            {
                assert(mp_Data);
                return NULL;
            }
    
            SYSTEM_PROCESS* pk_Proc = (SYSTEM_PROCESS*)mp_Data;
            while (TRUE)
            {
                if ((DWORD)(DWORD_PTR)pk_Proc->UniqueProcessId == u32_PID)
                    return pk_Proc;
    
                if (!pk_Proc->NextEntryOffset)
                    return NULL;
    
                pk_Proc = (SYSTEM_PROCESS*)((BYTE*)pk_Proc + pk_Proc->NextEntryOffset);
            }
        }
    
        SYSTEM_THREAD* FindThreadByTid(SYSTEM_PROCESS* pk_Proc, DWORD u32_TID)
        {
            if (!pk_Proc)
            {
                assert(pk_Proc);
                return NULL;
            }
    
            // The first SYSTEM_THREAD structure comes immediately after the SYSTEM_PROCESS structure
            SYSTEM_THREAD* pk_Thread = (SYSTEM_THREAD*)((BYTE*)pk_Proc + sizeof(SYSTEM_PROCESS));
    
            for (DWORD i=0; i<pk_Proc->ThreadCount; i++)
            {
                if (pk_Thread->ClientID.UniqueThread == (HANDLE)(DWORD_PTR)u32_TID)
                    return pk_Thread;
    
                pk_Thread++;
            }
            return NULL;
        }
    
        DWORD IsThreadSuspended(SYSTEM_THREAD* pk_Thread, BOOL* pb_Suspended)
        {
            if (!pk_Thread)
                return ERROR_INVALID_PARAMETER;
    
            *pb_Suspended = (pk_Thread->ThreadState == Waiting &&
                             pk_Thread->WaitReason  == Suspended);
            return 0;
        }
    
    private:
        BYTE*         mp_Data;
        DWORD       mu32_DataSize;
        t_NtQueryInfo mf_NtQueryInfo;
    };
    
    // Based on the 32 bit code of Sven B. Schreiber on:
    // http://www.informit.com/articles/article.aspx?p=22442&seqNum=5