zoukankan      html  css  js  c++  java
  • Windows程序设计(1)——Win32运行原理(三)

    4 进程控制

    4.1 获得系统进程

    使用toolhelp模块可以实现获取系统中当前运行当中的进程列表。

    思路如下,使用CreateToolhelp32Snapshot函数给当前系统内执行的进程拍快照(Snapshot),也就是获得了进程列表,这个列表记录着进程的ID、进程对应的可执行文件的名称和创建该进程的进程ID等数据。然后使用Process32First函数和Process32Next函数遍历快照中记录的列表。

    #include <windows.h>
    #include <TlHelp32.h> // for snapshot
    #include <stdio.h>
    
    int main(int argc, char* argv[])
    {
        PROCESSENTRY32 pe32;
        int iProcessCount;
    
        // initial its size
        pe32.dwSize = sizeof(pe32);
        iProcessCount = 0;
    
        // create snapshot for all processes
        HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if (hProcessSnap == INVALID_HANDLE_VALUE)
        {
            printf("CreateToolhelp32Snapshot failure!
    ");
            exit(1);
        }
    
        // traversal snapshot
        BOOL bMore = ::Process32First(hProcessSnap, &pe32);
        while (bMore) 
        {
            printf("%-20.20s%6u%4u%6u%6u%6u%3ld
    ", pe32.szExeFile, 
                pe32.th32ProcessID, pe32.cntUsage, pe32.th32DefaultHeapID, 
                pe32.th32ModuleID, pe32.th32ParentProcessID, pe32.pcPriClassBase);
            bMore = ::Process32Next(hProcessSnap, &pe32);
            iProcessCount ++;
        }
    
        // clear snapshot
        ::CloseHandle(hProcessSnap);
    
        printf("Processes count: %d
    
    ", iProcessCount);
    
        getchar();
        return 0;
    }

    结果很容易理解。

    CreateToolhelp32Snapshot

    CreateToolhelp32Snapshot用于获取系统内指定进程的快照,也可以获取这些进程使用的堆、模块、线程的快照。如:

    HANDLE WINAPI CreateToolhelp32Snapshot( 
        DWORD dwFlags,      // 指定快照内容
        DWORD th32ProcessID // 指定进程ID
    );

    dwFlags参数可以是如下值:

    • TH32CS_SNAPHEAPLIST枚举`th32ProcessID参数指定进程中的堆。
    • TH32CS_SNAPMODULE枚举`th32ProcessID参数指定进程中的模块。
    • TH32CS_SNAPPROCESS,此时`th32ProcessID参数被忽略。
    • TH32CS_SNAPTHREAD,此时`th32ProcessID参数被忽略。
    • TH32CS_SNAPALL,相当于以上4个值的并集。

    根据获取快照的不同,使用下面几组函数来获取快照信息:

    • Heap32ListFirst Heap32ListNext
    • Module32First Module32Next
    • Process32First Process32Next
    • Thread32First Thread32Next
    • Heap32First Heap32Next

    以上函数的第二个参数是指向如下之一结构的指针:

    • HEAPLIST32
    • HEAPENTRY32
    • MODULEENTRY32
    • THREADENTRY32
    • PROCESSENTRY32
    typedef struct tagHEAPLIST32 { 
        DWORD dwSize; 
        DWORD th32ProcessID; 
        DWORD th32HeapID; 
        DWORD dwFlags; 
    } HEAPLIST32; 
    
    typedef struct tagHEAPENTRY32 
    { 
        DWORD dwSize; 
        HANDLE hHandle; 
        DWORD dwAddress; 
        DWORD dwBlockSize; 
        DWORD dwFlags; 
        DWORD dwLockCount; 
        DWORD dwResvd; 
        DWORD th32ProcessID; 
        DWORD th32HeapID; 
    } HEAPENTRY32;
    
    typedef struct tagMODULEENTRY32 { 
        DWORD dwSize; 
        DWORD th32ModuleID; 
        DWORD th32ProcessID; 
        DWORD GlblcntUsage; 
        DWORD ProccntUsage; 
        BYTE *modBaseAddr; 
        DWORD modBaseSize; 
        HMODULE hModule;
        TCHAR szModule[MAX_MODULE_NAME32 + 1]; 
        TCHAR szExePath[MAX_PATH]; 
        DWORD dwFlags
    } MODULEENTRY32;
    
    typedef struct tagTHREADENTRY32{ 
        DWORD dwSize; 
        DWORD cntUsage; 
        DWORD th32ThreadID; 
        DWORD th32OwnerProcessID; 
        LONG tpBasePri; 
        LONG tpDeltaPri; 
        DWORD dwFlags;
        DWORD th32AccessKey;
        DWORD th32CurrentProcessID;
    } THREADENTRY32; 
    
    typedef struct tagPROCESSENTRY32 { 
        DWORD dwSize; 
        DWORD cntUsage; 
        DWORD th32ProcessID; 
        DWORD th32DefaultHeapID; 
        DWORD th32ModuleID; 
        DWORD cntThreads; 
        DWORD th32ParentProcessID; 
        LONG pcPriClassBase; 
        DWORD dwFlags; 
        TCHAR szExeFile[MAX_PATH]; 
        DWORD th32MemoryBase;
        DWORD th32AccessKey;
    } PROCESSENTRY32; 
    

    4.2 终止当前进程

    终止一个进程有如下4种方式:

    1. 主线程的入口函数返回。
    2. 进程中一个线程调用了ExitProcess函数。
    3. 此进程中的所有线程都结束了。
    4. 其他进程中的一个线程调用了TerminateProcess函数。

    最常用的方式是让主线程的入口函数返回。当入口函数返回时,启动函数会调用C/C++运行期退出函数exit,并将用户的返回值传递给它。exit函数会销毁所有的全局的或者静态的C++对象,然后调用系统函数ExitProcess使操作系统终止应用程序。ExitProcess是一个API函数,它会结束当前应用程序的执行,并设置它的退出代码。

    VOID ExitProcess(  
        UINT uExitCode   // 所有线程的退出代码
    );

    在程序的任何地方都可以调用ExitProcess,强制当前程序的执行立即结束。这对操作系统来说,是正常的。但对C/C++应用程序应该避免直接调用这个函数。因为这会使C/C++运行期库得不到通知,而没有机会去调用全局的或者静态的C++对象的析构函数。

    4.3 终止其他进程

    ExitProcess函数只能用来结束当前进程,不能用于结束其他进程。如果要终止其他进程,可以使用TerminateProcess函数。

    BOOL TerminateProcess(
        HANDLE hProcess, // 目标进程句柄
        UINT uExitCode   // 目标进程的退出代码
    );

    前面介绍过,使用CreateProcess函数创建新的进程,会得到新进程的句柄。对于不是自己创建的进程,可以使用OpenProcess函数来取得这进程的访问权限,函数如下:

    HANDLE OpenProcess(
        DWORD dwDesiredAccess,  // 访问权限
        BOOL bInheritHandle,    // 返回的句柄是否可被继承
        DWORD dwProcessId       // 要打开的进程的ID
    );

    参数dwDesiredAccess指定的对进程的访问权限,可以是如下值:

    说明
    PROCESS_ALL_ACCESS 所有可进行的权限
    PROCESS_CREATE_PROCESS 创建一个进程
    PROCESS_CREATE_THREAD 创建一个线程
    PROCESS_DUP_HANDLE 做为DuplicateHandle参数
    PROCESS_QUERY_INFORMATION 查看进程信息的权限,如优先级类等
    PROCESS_QUERY_LIMITED_INFORMATION 需要返回特定信息
    PROCESS_SET_INFORMATION 设置进程的优先级
    PROCESS_SET_QUOTA 设置内存限制
    PROCESS_SUSPEND_RESUME 睡眠和唤醒
    PROCESS_TERMINATE 关闭进程
    PROCESS_VM_OPERATION 修改进程的地址空间
    PROCESS_VM_READ 读进程内存
    PROCESS_VM_WRITE 写进程内存
    SYNCHRONIZE 等待进程结束

    在进程结束后,调用GetExitCodeProcess函数可以取得其退出代码,如果调用时,目标进程还没有结束,此函数会返回STILL_ACTIVE,表示进程还在运行。通过该函数可以检测进程是否结束了。

    BOOL GetExitCodeProcess(
        HANDLE hProcess,     // 目标进程句柄
        LPDWORD lpExitCode   // 目标进程的退出句柄
    );

    如果进程已经结束,其退出代码是通过下面几种方式设置的:

    1. ExitProcess或者TerminateProcess函数中指定。
    2. main或者WinMain的返回值。
    3. 由于未处理的异常导致的结束,返回相应的异常值。

    一旦进程终止,就会如下事件发生:

    1. 所有被这个进程创建的或撕开的对象句柄就会关闭。
    2. 此进程内的所有线程将终止执行。
    3. 进程内核对象变成受信状态,所有等待在此对象上的线程开始运行,即WaitForSingleObject函数返回。
    4. 系统将进程对象中退出代码值由STILL_ACTIVE设置为指定的退出代码。
  • 相关阅读:
    初认识AngularJS
    (imcomplete) UVa 10127 Ones
    UVa 10061 How many zero's and how many digits?
    UVa 11728 Alternate Task
    UVa 11490 Just Another Problem
    UVa 10673 Play with Floor and Ceil
    JSON对象和字符串的收发(JS客户端用typeof()进行判断非常重要)
    HTML.ActionLink 和 Url.Action 的区别
    EASYUI TREE得到当前节点数据的GETDATA方法
    jqueery easyui tree把已选中的节点数据拼成json或者数组(非常重要)
  • 原文地址:https://www.cnblogs.com/furzoom/p/7710237.html
Copyright © 2011-2022 走看看