行程
Windows进程

操作系统使用进程ID来唯一标识每个进程。在一个进程内部，使用进程句柄来标识关注的每个进程。使用Windows API从进程ID获取进程句柄：
OpenProcess(PROCESS_ALL_ACCESS, TRUE, procId); //或者PROCESS_QUERY_INFORMATION
使用API函数：GetModuleFileNameEx或GetProcessImageFileName或QueryFullProcessImageName查询进程的exe文件名
使用API函数GetCurrentProcess可以获取本进程的伪句柄（值为-1），只能用于本进程的API函数调用；不能被其他进程继承或复制。可用API函数DuplicateHandle获得进程的真句柄。
使用API函数CreateProcess创建进程，WaitForSingleObject可等待子进程的结束。例如：
#include <windows.h>
#include <stdio.h>
#include <tchar.h>

void main() {
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));
    // Start the child process.
    if (!CreateProcess(NULL,    // No module name (use command line)
                       "demo.exe arg1", // Command line
                       NULL,    // Process handle not inheritable
                       NULL,    // Thread handle not inheritable
                       FALSE,   // Set handle inheritance to FALSE
                       0,       // No creation flags
                       NULL,    // Use parent's environment block
                       NULL,    // Use parent's starting directory
                       &si,     // Pointer to STARTUPINFO structure
                       &pi)     // Pointer to PROCESS_INFORMATION structure,用于给出子进程主窗口的属性
       ) {
        printf("CreateProcess failed (%d).\n", GetLastError());
        return;
    }
    // Wait until child process exits.
    WaitForSingleObject(pi.hProcess, INFINITE);
    // Close process and thread handles.
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}
创建的子进程可以继承父进程的：
CreateFile返回的打开句柄，包括文件、控制台输入缓冲区、控制台屏幕缓冲区, 命名管道, 串口通信设备, 邮槽.
打开的句柄，包括：进程、线程、互斥锁、事件对象、信号量、命名管道、匿名管道、文件映射对象。
环境变量
当前目录
控制台，除非进程脱离（detach）或创建了新的控制台。
错误模式，使用API函数SetErrorMode设置
进程亲和掩码（affinity mask），用以指示期望使用CPU的哪些核
在哪个作业中。
子进程不能继承：
优先级类别Priority class.
句柄，由LocalAlloc, GlobalAlloc, HeapCreate, HeapAlloc返回
伪句柄，由GetCurrentProcess或GetCurrentThread返回
DLL模块句柄，由LoadLibrary返回
GDI对象句柄或USER对象句柄，如HBITMAP或HMENU.
为继承句柄，父进程在创建（或者代开、复制）各种可继承对象句柄时，在SECURITY_ATTRIBUTES结构的bInheritHandle成员为TRUE。在CreateProcess的bInheritHandles参数为TRUE；如果要继承标准输入、标准输出、标准错误的句柄，STARTUPINFO结构的dwFlags成员包含STARTF_USESTDHANDLES标志位.
下述API的函数用于获取进程相关信息：
GetCommandLine：当前进程的命令行字符串
GetStartupInfo：当前进程被创建时的STARTUPINFO结构
GetProcessVersion：获取可执行头的版本信息
GetModuleFileName：获取包含了进程代码的可执行文件的全路径与文件名
GetGuiResources：获取使用中的GUI对象的句柄数量
IsDebuggerPresent：确定进程是否被调试
GetProcessIoCounters：获取进程执行的所有I/O操作的薄记信息。
GetProcessMemoryInfo：获取进程的工作集内存的信息
GetProcessWorkingSetSize：获取进程的工作集内存被允许的下限与上限
SetProcessWorkingSetSize：设置进程的工作集内存的下限与上限
进程终止时，所有打开的句柄被关闭，进程对象被触发（signaled）。进程的退出码（exit code）或者在ExitProcess、TerminateProcess函数中指出，或者是main、WinMain函数返回值。如果进程由于一个致命异常（fatal exception）而终止，退出码是这个异常值，同时进程的所有执行中的线程的退出码也是这个异常值。
优雅地关闭其他进程的方法是用RegisterWindowMessage登记私有消息，用BroadcastSystemMessage播放消息，收到消息的进程用ExitProcess关闭。
如果想要获取特定名字的进程的ID，需要枚举所有进程。传统办法是CreateToolhelp32Snapshot、Process32First、Process32Next函数；也可以使用EnumProcesses、EnumProcessModules函数来获取所有的进程ID，一个进程的所有模块的句柄。示例如下：
PROCESSENTRY32 pe32;
HANDLE hSnaphot;
HANDLE hApp;
DWORD dProcess;
hSnaphot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); // 获取进程快照
Process32First(hSnaphot, &pe32); // 枚举第一个进程
do {
    if (lstrcmpi(pe32.szExeFile, _T("NotePad.exe")) == 0) { // 查找进程名称为 NotePad.exe
        dProcess = pe32.th32ProcessID;
        break;
    }
} while (Process32Next(hSnaphot, &pe32)); // 不断循环直到枚举不到进程
hApp = OpenProcess(PROCESS_VM_OPERATION | SYNCHRONIZE, FALSE, dProcess); // 根据进程 ID 获取程序的句柄
if (!WaitForSingleObject(hApp, INFINITE)) // 等待进程关闭
    AfxMessageBox(" 记事本已经关闭！");

// 另一种方法
DWORD aProcId[1024], dwProcCnt, dwModCnt;
HMODULE hMod[1000];
TCHAR szPath[MAX_PATH];

// 枚举出所有进程ID
if (!EnumProcesses(aProcId, sizeof(aProcId), &dwProcCnt)) {
    //cout << "EnumProcesses error: " << GetLastError() << endl;
    return 0;
}

// 遍例所有进程
for (DWORD i = 0; i < dwProcCnt; ++i) {
    // 打开进程，如果没有权限打开则跳过
    HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, aProcId[i]);
    if (NULL != hProc) {
        // 打开进程的第1个Module，并检查其名称是否与目标相符
        if (EnumProcessModules(hProc, &hMod, 1000, &dwModCnt)) {
            GetModuleBaseName(hProc, hMod, szPath, MAX_PATH);
            if (0 == lstrcmpi(szPath, lpName)) {
                CloseHandle(hProc);
                return aProcId[i];
            }
        }
        CloseHandle(hProc);
    }
}
return 0;