7.2 通过API创建新进程

2023-09-22 08:56:39

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

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

该函数的原型为:

UINT WinExec(
  LPCSTR lpCmdLine,
  UINT   uCmdShow
);

其参数说明如下:

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

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

#include <iostream>
#include <Windows.h>

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;
}

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

该函函数原型如下:

HINSTANCE ShellExecute(
  HWND    hwnd,
  LPCTSTR lpOperation,
  LPCTSTR lpFile,
  LPCTSTR lpParameters,
  LPCTSTR lpDirectory,
  INT     nShowCmd
);

参数说明:

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

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

#include <iostream>
#include <Windows.h>

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;
}

最后一个创建进程的函数是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 结构的指针
);

参数说明:

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

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

#include <iostream>
#include <Windows.h>

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;
}

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/89068d1f.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

更多推荐

IP归属地在金融行业的应用场景

IP归属地查询在各大行业当中的利用率可以说非常的高了,提供了各种的保障,比如安全保障、数据保障、性能保障等等。今天我就来详细说一说IP归属地在金融行业的应用场景有哪些?用途一:通过解析用户IP地址所处的区县位置与表单填写位置或者GPS位置进行交叉验证,判断位置是否一致;用途二:识别来自高危地区的IP地址,如缅甸、老挝;

【面试题】—— 笔试题(4题)

文章目录1.分割集合第一种方式:自己实现分割方法第二种方式:使用第三方依赖2.链表计算3.字符串计算4.找到相加为0的数字1.分割集合题目:编写一个Java函数,实现批量获取数据的功能(BService.get(Listids))。具体要求如下:1)提供一个函数BService.get(Listids),支持最多传入1

使用Jmeter+ant进行接口自动化测试(数据驱动)

最近在做接口测试,因为公司有使用jmeter做接口测试的相关培训资料,所以还是先选择使用jmeter来批量管理接口,进行自动化测试。话不多说,进入正题:1.使用csv文件保存接口测试用例,方便后期对接口进行维护(先新建txt文件,然后文件扩展名改为.csv,不要新建xls再改为csv,不然会出现读取不到文件的情况)注意

【C语言学习笔记---指针进阶02】

C语言程序设计笔记---017C语言进阶之回调函数1、函数指针数组2、回调函数3、回调函数的应用---qsort库函数4、模拟qsort函数5、结语C语言进阶之回调函数前言:通过C语言进阶前篇的指针进阶01的知识,继续学习。这篇引用一个简易计算器的程序进行深入学习指针进阶的知识。/知识点汇总/1、函数指针数组比如:指针

认识Redis

文章目录为什么需要使用缓存中间件提高读取性能降低数据库负载提高可伸缩性降低外部依赖提高用户体验缓存数据一致性应对突发流量缓存的类型本地缓存分布式缓存内存缓存磁盘缓存缓存代理什么是RedisRedis和Memcached对比数据结构支持持久化支持数据查询和操作数据复制和分布式内存管理:生态系统和支持库应用场景总结为什么用

【大数据】Doris 构建实时数仓落地方案详解(二):Doris 核心功能解读

本系列包含:Doris构建实时数仓落地方案详解(一):实时数据仓库概述Doris构建实时数仓落地方案详解(二):Doris核心功能解读Doris构建实时数仓落地方案详解(三):Doris实时数仓设计Doris构建实时数仓落地方案详解(二):Doris核心功能解读1.Doris发展历程2.Doris三大模型3.Doris

Wireshark TS | MQ 传输缓慢问题

问题背景应用传输慢是一种比较常见的问题,慢在哪,为什么慢,有时候光从网络数据包分析方面很难回答的一清二楚,毕竟不同的技术方向专业性太强,全栈大佬只能仰望,而我们能做到的是在专注于自身的专业方向之外,尽量扩展知识面,学会找出问题的规律,并提出可能的解决建议。就像本次MQ案例一样,说实话我对MQ一无所知,但并不会让我们在拿

haproxy工具,负载均衡配置,反向代理配置,动静分离,高可用等等

文章目录haproxyhaproxy概述haproxy配置文件解析haproxy实战haproxy配置过程haproxy负载均衡和反向代理haproxy查看状态信息Haproxy健康检查功能基于tcp端口的健康检查基于URL的健康检查haproxy的高可用--不需要keepalived获取真实ip地址haproxy动静

CSS 实现祥云纹理背景

🪴背景最近掘金出来一个中秋创意活动,我准备参加一下。作品方向选择用纯css做一个中秋贺卡,其中有一些中秋的元素和一些简单的动画,而贺卡背景的实现就是本文要讲的内容。中秋贺卡成果图(生成gif有点失真😵‍💫)如下:有兴趣的可以看我的另一篇文章:中秋贺卡传送门贺卡背景是我用css,仿照从网上搜到的祥云纹理背景图实现的

CSS中去掉li前面的圆点方法

1.引言在网页开发中,我们经常会使用无序列表(<ul>)来展示一系列的项目。默认情况下,每个列表项(<li>)前面都会有一个圆点作为标记。然而,在某些情况下,我们可能希望去掉这些圆点,以满足设计需求或者个性化要求。本文将介绍几种常见的方法来去掉<li>前面的圆点。2.使用CSS属性我们可以使用CSS的list-styl

CSS中的定位

position的属性与含义CSS中的position属性用于控制元素在页面中的定位方式,有四个主要的取值,每个取值都会影响元素的布局方式,它们是:static(默认值):这是所有元素的初始定位方式。在静态定位下,元素会按照它们在文档流中的顺序依次排列,不受top、right、bottom、left等属性的影响。静态定

热文推荐