• 7.2 通过API创建新进程


    创建新的进程是Windows程序开发的重要部分,它可以用于实现许多功能,例如进程间通信、并行处理等。其中,常用的三种创建进程的方式分别是WinExec()ShellExecute()CreateProcessA(),这三种创建进程的方式各有特点。如果需要创建简单进程或从其他程序启动新进程,可以使用WinExec()ShellExecute()函数。如果需要对新进程进行更精细的配置,例如控制进程参数、指定安全级别、传递特定的命令和参数等,可以使用CreateProcessA()函数。

    首先介绍WinExec函数,该函数是创建进程的一种方式,它使用较为简单,但缺乏对进程参数和安全性等方面的控制。使用WinExec()函数,可以传递一个字符串类型的参数,该参数中指定了要启动的进程名和参数等信息。但是,由于WinExec()函数没有提供区分进程启动成功和失败的返回值,且无法从函数返回的进程句柄获得与进程相关的信息,因此使用较为有限。

    该函数的原型为:

    UINT WinExec(
      LPCSTR lpCmdLine,
      UINT   uCmdShow
    );
    
    • 1
    • 2
    • 3
    • 4

    其参数说明如下:

    • lpCmdLine:需要执行的命令行字符串
    • uCmdShow:指定程序窗口最初显示方式,如SW_SHOW,即窗口正常大小和位置显示

    WinExec 函数的返回值是一个无符号整数,它表示进程是否成功启动。若成功启动,则返回值为任务句柄。否则,返回值为0。但是该函数也存在一些问题,例如ANSI编码、不支持进程标识符等,建议在实际开发中使用更为灵活的CreateProcess()ShellExecute()函数。

    #include 
    #include 
    
    BOOL WinExec(char *pszExePath, UINT uiCmdShow)
    {
      UINT uiRet = 0;
      uiRet = WinExec(pszExePath, uiCmdShow);
      if (31 < uiRet)
      {
        return TRUE;
      }
      return FALSE;
    }
    
    int main(int argc, char * argv[])
    {
      int ret = 0;
      ret = WinExec("c:\\windows\\system32\\notepad.exe",TRUE);
      printf("执行状态: %d \n", ret);
    
      system("pause");
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    创建进程的第二个函数是ShellExecute,该函数提供了很多功能,例如可以启动进程、打开文件、运行脚本等等。ShellExecute()函数的优点是可以控制进程的启动方式、传递命令参数,并对返回值进行判断,通过传递参数来控制启动进程的方式,比如最大化或最小化窗口,或者在后台启动进程。

    该函函数原型如下:

    HINSTANCE ShellExecute(
      HWND    hwnd,
      LPCTSTR lpOperation,
      LPCTSTR lpFile,
      LPCTSTR lpParameters,
      LPCTSTR lpDirectory,
      INT     nShowCmd
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    参数说明:

    • hwnd:执行的窗口的句柄。可以为NULL,如果为NULL则表示没有窗口。
    • lpOperation:操作类型,可以是open或print。如果为NULL,则此函数将尝试打开文件。
    • lpFile:需要执行的目标文件、应用程序或者URL地址。
    • lpParameters:命令行参数。
    • lpDirectory:指定被启动程序的执行路径,如果为NULL,则使用当前程序路径。
    • nShowCmd:指定被启动程序的窗口状态。

    该函数返回HINSTANCE类型的值,如果没有执行或则执行失败,它将返回一个值为ERROR_FILE_NOT_FOUNDERROR_BAD_FORMAT的值。

    #include 
    #include 
    
    BOOL MyShellExecute(char *pszExePath, UINT uiCmdShow)
    {
      HINSTANCE hInstance = 0;
      hInstance = ShellExecute(NULL, NULL, pszExePath, NULL, NULL, uiCmdShow);
      if (32 < (DWORD)hInstance)
      {
        return TRUE;
      }
      return FALSE;
    }
    
    int main(int argc, char * argv[])
    {
      int ret = 0;
      ret = MyShellExecute("c:\\windows\\system32\\notepad.exe", TRUE);
      printf("执行状态: %d \n", ret);
    
      system("pause");
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    最后一个创建进程的函数是CreateProcess()该函数提供了比较灵活的进程控制,相比于其他API函数,例如WinExec()ShellExecute() ,它可以更详细地控制进程的执行,如进程窗口的大小和位置,输出、输入和错误信息的控制等,并且能够获取到新进程的标识符以及进程句柄。同时CreateProcess()也具有更高的系统安全性。因此,在实际开发中,开发人员往往使用 CreateProcess()函数进行进程控制、管理和处理。

    其函数原型如下:

    BOOL CreateProcess(
      LPCSTR                lpApplicationName,   // 可执行文件名或命令行调用
      LPSTR                 lpCommandLine,       // 字符串形式的命令行参数
      LPSECURITY_ATTRIBUTES lpProcessAttributes,// 进程的安全属性
      LPSECURITY_ATTRIBUTES lpThreadAttributes, // 线程的安全属性
      BOOL                  bInheritHandles,     // 建立进程时是否继承父句柄
      DWORD                 dwCreationFlags,     // 进程标记
      LPVOID                lpEnvironment,       // 进程环境空间块的指针
      LPCSTR                lpCurrentDirectory,  // 当前工作目录的指针
      LPSTARTUPINFOA        lpStartupInfo,       // 指向 StartupInfo 结构的指针
      LPPROCESS_INFORMATION lpProcessInformation // 指向 ProcessInformation 结构的指针
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    参数说明:

    • lpApplicationName:需要执行的可执行文件名或命令行调用。如果为NULL,则将使用lpCommandLine参数中的文件名
    • lpCommandLine:命令行参数,可以传递参数给可执行文件
    • lpProcessAttributes:进程的安全属性。一般为NULL
    • lpThreadAttributes:线程的安全属性。一般为NULL
    • bInheritHandles:指定新进程是否继承父进程的句柄
    • dwCreationFlags:指定进程的标记。常用的标记有NORMAL_PRIORITY_CLASS,表示新进程在普通优先级类中运行
    • lpEnvironment:进程环境空间块的指针,用于设置新进程的环境变量
    • lpCurrentDirectory:指定新进程的初始工作目录,如果为NULL,则使用与调用进程相同的当前目录
    • lpStartupInfo:指向STARTUPINFO结构体的指针
    • lpProcessInformation:进程信息结构,包括新进程的句柄和进程ID

    如果仅仅只是需要将一个进程拉起来,那么只需要传递三个参数即可,其余参数可以全部使用0进行填充,如下所示;

    #include 
    #include 
    
    BOOL ExecRun(LPCSTR exe_file)
    {
      PROCESS_INFORMATION pi = { 0 };
      STARTUPINFO si = { 0 };
      si.cb = sizeof(STARTUPINFO);
    
      BOOL bRet = CreateProcessA(exe_file, 0, 0, 0, 0, 0, 0, 0, &si, &pi);
    
      if (bRet != FALSE)
        CloseHandle(pi.hProcess);
      return TRUE;
      return FALSE;
    }
    
    int main(int argc, char * argv[])
    {
      int ret = 0;
      ret = ExecRun("c:\\windows\\system32\\notepad.exe");
      printf("执行状态: %d \n", ret);
    
      system("pause");
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
  • 相关阅读:
    【BA无标度网络(无限规模)的传播阈值推导过程】
    Elasticsearch 8.9 Bulk批量给索引增加数据源码
    【毕业设计】深度学习实现行人重识别 - python opencv yolo Reid
    深入浅出 C++ 11 右值引用
    分布式系统 中间件
    什么蓝牙耳机实惠又好用?高性价比蓝牙耳机推荐
    Golang gorm manytomany 多对多 更新、删除、替换
    jmeter==docker安装nginx , jmeter压力测试并发20个请求在1秒内发出
    MyBatis-----10、MyBatis逆向工程
    You have an error in your SQL syntax; check the manual that corresponds to...
  • 原文地址:https://blog.csdn.net/lyshark_csdn/article/details/133156995