使用 CreateProcess 执行程序

来源:互联网 发布:devc建立c语言项目 编辑:程序博客网 时间:2024/05/19 17:06

使用 CreateProcess 执行程序

CreateProcess 创建新进程和它的主进程,新进程运行指定可执行文件。
函数原型

BOOL WINAPI CreateProcess(  _In_opt_    LPCTSTR               lpApplicationName,  _Inout_opt_ LPTSTR                lpCommandLine,  _In_opt_    LPSECURITY_ATTRIBUTES lpProcessAttributes,  _In_opt_    LPSECURITY_ATTRIBUTES lpThreadAttributes,  _In_        BOOL                  bInheritHandles,  _In_        DWORD                 dwCreationFlags,  _In_opt_    LPVOID                lpEnvironment,  _In_opt_    LPCTSTR               lpCurrentDirectory,  _In_        LPSTARTUPINFO         lpStartupInfo,  _Out_       LPPROCESS_INFORMATION lpProcessInformation);

参数

  • lpApplicationName 可执行程序路径,可以是绝对路径或相对路径,如果设置为 NULL,则可执行文件名在 lpCommandLine 最前边并且用空格分开。
  • lpCommandLine 传递给可执行程序的命令行参数,可以为空。当 lpApplicationName 为空时, lpCommandLine 第一个空格前的字符串被认为是可执行程序名,如果未指定后缀,则默认为 exe,如果指定文件名未包含路径,则会在应用程序当前路径、父进程路径、windows 路径和 PATH 中的目录中搜索
  • lpProcessAttributes 指向 SECURITY_ATTRIBUTES 结构,该结构决定句柄是否可以被子进程继承,如果为 NULL 则不可继承。
  • lpThreadAttributes 与 lpProcessAttributes 参数一致,决定句柄是否被子线程继承,如果为 NULL 则不可继承。
  • bInheritHandles 指示新进程是否从调用进程处继承了句柄,如果为真,调用进程中的每一个可继承的打开句柄都将被子进程继承,被继承的句柄与原进程拥有完全相同的值和访问权限。
  • dwCreationFlags 控制进程优先级和创建进程的标志
     CREATE_DEFAULT_ERROR_MODE 新的进程不继承调用进程的错误模式。CreateProcess 函数赋予新进程当前的默认错误模式作为替代。应用程序可以调用 SetErrorMode 函数设置当前的默认错误模式。对于 CreateProcess 函数,默认的行为是为新进程继承调用者的错误模式。设置这个标志以改变默认的处理方式。
     CREATE_NEW_CONSOLE 新的进程将使用一个新的控制台,而不是继承父进程的控制台。这个标志不能与 DETACHED_PROCESS 标志一起使用。
     CREATE_NEW_PROCESS_GROUP 新进程将使一个进程树的根进程。进程树中的全部进程都是根进程的子进程。新进程树的用户标识符与这个进程的标识符是相同的,由lpProcessInformation参数返回。进程树经常使用GenerateConsoleCtrlEvent函数允许发送CTRL+C或CTRL+BREAK信号到一组控制台进程。
     CREATE_SEPARATE_WOW_VDM 如果被设置,新进程将会在一个私有的虚拟 DOS 机 (VDM) 中运行。
     CREATE_SHARED_WOW_VDM 如果 WIN.INI 中的 Windows 段的DefaultSeparateVDM 选项被设置为真,这个标识使得 CreateProcess 函数越过这个选项并在共享的虚拟 DOS 机中运行新进程。
     CREATE_SUSPENDED 新进程的主线程会以暂停的状态被创建,直到调用 ResumeThread 函数被调用时才运行。
     CREATE_UNICODE_ENVIRONMENT 如果被设置,由 lpEnvironment 参数指定的环境块使用 Unicode 字符,如果为空,环境块使用 ANSI 字符。
     DEBUG_PROCESS 如果这个标志被设置,调用进程将被当做一个调试程序,并且新进程会被当做被调试的进程。系统把被调试程序发生的所有调试事件通知给调试器。如果你使用这个标志创建进程,只有调用进程(调用 CreateProcess 函数的进程)可以调用 WaitForDebugEvent 函数。
     DEBUG_ONLY_THIS_PROCESS 如果此标志没有被设置且调用进程正在被调试,新进程将成为调试调用进程的调试器的另一个调试对象。如果调用进程没有被调试,有关调试的行为就不会产生。
     DETACHED_PROCESS 对于控制台进程,新进程没有访问父进程控制台的权限。新进程可以通过 AllocConsole 函数自己创建一个新的控制台。这个标志不可以与 CREATE_NEW_CONSOLE 标志一起使用。
     CREATE_NO_WINDOW 系统不为新进程创建CUI窗口,使用该标志可以创建不含窗口的CUI程序。
    dwCreationFlags 参数还用来控制新进程的优先类,优先类用来决定此进程的线程调度的优先级。默认的优先类是NORMAL_PRIORITY_CLASS,除非被创建的进程是IDLE_PRIORITY_CLASS。在这种情况下子进程的默认优先类是IDLE_PRIORITY_CLASS。
    可以为:
     HIGH_PRIORITY_CLASS 指示这个进程将执行时间临界的任务,所以它必须被立即运行以保证正确。这个优先级的程序优先于正常优先级或空闲优先级的程序。一个例子是 Windows 任务列表,为了保证当用户调用时可以立刻响应,放弃了对系统负荷的考虑。确保在使用高优先级时应该足够谨慎,因为一个高优先级的 CPU 关联应用程序可以占用几乎全部的 CPU 可用时间。
     IDLE_PRIORITY_CLASS 指示这个进程的线程只有在系统空闲时才会运行并且可以被任何高优先级的任务打断。例如屏幕保护程序。空闲优先级会被子进程继承。
     NORMAL_PRIORITY_CLASS 指示这个进程没有特殊的任务调度要求。
     REALTIME_PRIORITY_CLASS 指示这个进程拥有可用的最高优先级。一个拥有实时优先级的进程的线程可以打断所有其他进程线程的执行,包括正在执行重要任务的系统进程。例如,一个执行时间稍长一点的实时进程可能导致磁盘缓存不足或鼠标反映迟钝。
  • lpEnvironment 指向新进程的环境块,如果为 NULL 则使用调用进程的环境。
  • lpCurrentDirectory 指定子进程工作路径
  • lpStartupInfo 指向决定新进程主窗口如何显示的 STARTUPINFO 或 STARTUPINFOEX 结构,如果需要指定新进程创建之后的显示状态,则设置此结构。
  • lpProcessInformation 指向 PROCESS_INFORMATION 结构,接收函数调用后新进程的信息,当不在使用时需要使用 CloseHandle 关闭其中的句柄。
    PROCESS_INFORMATION 结构:
typedef struct _PROCESS_INFORMATION {  HANDLE hProcess;//返回新进程句柄  HANDLE hThread;//返回主线程句柄  DWORD  dwProcessId;//返回进程 ID  DWORD  dwThreadId;//返回线程 ID} PROCESS_INFORMATION, *LPPROCESS_INFORMATION;

返回值
调用成功则返回非零值,失败时返回零,使用 GetLastError 获取错误值。该函数调用之后立即返回,不等待新进程初始化完毕,如果新进程由于动态库缺失等初始化失败,则新进程退出,可使用 GetExitCodeProcess 获取进程退出值。

使用
实际使用中,大部分参数都可以设置为默认

    WCHAR chPath[MAX_PATH] = { 0 };    ::GetCurrentDirectory(MAX_PATH, chPath);//得到当前目录    CString path = chPath;    path += _T("\\Dbgview.exe");    STARTUPINFO si;    PROCESS_INFORMATION pi;    ZeroMemory(&pi, sizeof(pi));    ZeroMemory(&si, sizeof(si));//清空    si.cb = sizeof(si);    GetStartupInfo(&si);    si.wShowWindow = SW_SHOW;    DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW;    if (CreateProcess(path, NULL, NULL, NULL, FALSE, dwCreationFlag, NULL, NULL, &si, &pi))    {   //创建成功        WaitForSingleObject(pi.hProcess, INFINITE);//等待创建的进程执行结束        CloseHandle(pi.hProcess);        CloseHandle(pi.hThread);    }    else    {        CString s;        s.Format(_T("创建失败,error code:%d"), GetLastError());        AfxMessageBox(s);    }

注意
第一个参数 lpApplicationName 可能是空,这种情况下,可执行文件的名字必须在 lpCommandLine 中, lpCommandLine 参数中可以包含空格。如果可执行文件或路径中包含空格,那么就会有执行不正确文件的风险,这是由于这个函数解析空格的方法引起的。例如:下边这个例子就很危险,因为它试图运行 Program.exe 文件,如果这个文件存在,它就会代替 MyApp.exe 文件的运行。

CreateProcess(NULL,"C:\\Program Files\\MyApp.exe",…….)

如果有恶意的用户在系统编写了一个名为 Program.exe 的文件,那么任何调用 CreateProcess 函数,且在文件路径中使用 Program Files 文件夹的参数,都有可能会运行 Program.exe 文件,而不是运行本来打算运行的文件。
要避免这个问题,可以不要将 NULL 值传递给 lpApplicationName 参数,或者在 lpCommandLine 中使用双引号(转义符)括起可执行文件的全路径名,如下所示:

CreateProcess(NULL,"\"C:\\Program Files\\MyApp.exe\" -L -S",…….)

-L和-S是MyApp.exe可执行文件的参数。
这个风险在 ShellExecuteEx 也存在

0 0
原创粉丝点击