平台

Windows10 + VS2015

学习内容

  • 进程的创建使用(CreateProcess方式)
  • 父子进程间匿名管道通信

相关函数及参数介绍

  • CreatePipe函数:该的原型为
CreatePipe(_Out_ PHANDLE hReadPipe,
_Out_ PHANDLE hWritePipe,
_In_opt_ LPSECURITY_ATTRIBUTES lpPipeAttributes,
_In_ DWORD nSize);

hReadPipe:返回一个可用于读管道数据的文件句柄;hWritePipe:返回一个可用于写管道数据的文件句柄;lpPipeAttributes:传入一个SECURITY_ATTRIBUTES结构的指针,该结构用于决定该函数返回的句柄是否可被子进程继承;nSize:管道的缓冲区大小,但是这仅仅只是一个理想值,系统根据这个值创建大小相近的缓冲区。如果传入0 ,那么系统将使用一个默认的缓冲区大小。需要注意读写管道数据的句柄参数位置

  • LPSECURITY_ATTRIBUTES类型:相关定义内容为
typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength;
LPVOID lpSecurityDescriptor;
BOOL bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;

nLength:结构体的大小,可用sizeof取得;lpSecurityDescriptor:安全描述符;bInheritHandle:安全描述的对象能否被新创建的进程继承。

  • CreateProcess函数:WIN32API函数CreateProcess用来创建一个新的进程和它的主线程,这个新进程运行指定的可执行文件。该函数原型有两种可能,当前环境已定义UNICODE,只参考CreateProcessW
#ifdef UNICODE
#define CreateProcess CreateProcessW
#else
#define CreateProcess CreateProcessA
#endif // !UNICODE WINBASEAPI
BOOL
WINAPI
CreateProcessW(
_In_opt_ LPCWSTR lpApplicationName,
_Inout_opt_ LPWSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCWSTR lpCurrentDirectory,
_In_ LPSTARTUPINFOW lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation
);

lpApplicationName:指向一个NULL结尾的、用来指定可执行模块的字符串,这个参数可以被设为NULL,在这种情况下,可执行模块的名字必须处于 lpCommandLine 参数最前面并由空格符与后面的字符分开;lpCommandLine:指向一个以NULL结尾的字符串,该字符串指定要执行的命令行,这个参数可以为空,那么函数将使用lpApplicationName参数指定的字符串当做要运行的程序的命令行;lpProcessAttributes:指向一个SECURITY_ATTRIBUTES结构体,这个结构体决定是否返回的句柄可以被子进程继承;lpThreadAttributes:同lpProcessAttribute,不过这个参数决定的是线程是否被继承.通常置为NULL;bInheritHandles:指示新进程是否从调用进程处继承了句柄,如果参数的值为真,调用进程中的每一个可继承的打开句柄都将被子进程继承,被继承的句柄与原进程拥有完全相同的值和访问权限;dwCreationFlags:指定附加的、用来控制优先类和进程的创建的标志;lpEnvironment:指向一个新进程的环境块,如果此参数为空,新进程使用调用进程的环境;lpCurrentDirectory:指向一个以NULL结尾的字符串,这个字符串用来指定子进程的工作路径,这个字符串必须是一个包含驱动器名的绝对路径;lpStartupInfo指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体;lpProcessInformation:指向一个用来接收新进程的识别信息的PROCESS_INFORMATION结构体。

  • dwCreationFlags参数:dwCreationFlags可选类型列表如下
参数值 描述
CREATE_DEFAULT_ERROR_MODE 新的进程不继承调用进程的错误模式
CREATE_NEW_CONSOLE 新的进程将使用一个新的控制台,而不是继承父进程的控制台。这个标志不能与DETACHED_PROCESS标志一起使用
CREATE_NEW_PROCESS_GROUP 新进程将是一个进程树的根进程
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程序
HIGH_PRIORITY_CLASS 指示这个进程将执行时间临界的任务,所以它必须被立即运行以保证正确。这个优先级的程序优先于正常优先级或空闲优先级的程序
IDLE_PRIORITY_CLASS 指示这个进程的线程只有在系统空闲时才会运行并且可以被任何高优先级的任务打断
NORMAL_PRIORITY_CLASS 指示这个进程没有特殊的任务调度要求
REALTIME_PRIORITY_CLASS 指示这个进程拥有可用的最高优先级。一个拥有实时优先级的进程的线程可以打断所有其他进程线程的执行,包括正在执行重要任务的系统进程
  • STARTUPINFO参数:该参数原型有两种可能,当前环境已定义UNICODE,只参考STARTUPINFOW
#ifdef UNICODE
typedef STARTUPINFOW STARTUPINFO;
typedef LPSTARTUPINFOW LPSTARTUPINFO;
#else
typedef STARTUPINFOA STARTUPINFO;
typedef LPSTARTUPINFOA LPSTARTUPINFO;
#endif // UNICODE typedef struct _STARTUPINFOW {
DWORD cb;
LPWSTR lpReserved;
LPWSTR lpDesktop;
LPWSTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars;
DWORD dwYCountChars;
DWORD dwFillAttribute;
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFOW, *LPSTARTUPINFOW;

结构体参数内容较多,练习使用时只用到了cb``dwFlags``wShowWindow``hStdInput``hStdOutput``hStdError,具体参数解释如下表

参数 描述
cb 包含STARTUPINFO结构中的字节数,应用程序必须将cb初始化为sizeof(STARTUPINFO)
lpReserved 保留,必须初始化为NULL
lpDesktop 用于标识启动应用程序所在的桌面的名字。如果该桌面存在,新进程便与指定的桌面相关联。如果桌面不存在,便创建一个带有默认属性的桌面,并使用为新进程指定的名字。如果lpDesktop是NULL(这是最常见的情况),那么该进程将与当前桌面相关联
lpTitle 用于设定控制台窗口的名称。如果lpTitle是NULL,则可执行文件的名字将用作窗口名
dwX 用于设定应用程序窗口在屏幕上应该放置的位置的x坐标(以像素为单位)
dwY 用于设定应用程序窗口在屏幕上应该放置的位置的y坐标(以像素为单位),只有当子进程用CW_USEDEFAULT作为CreateWindow的x参数来创建它的第一个重叠窗口时,才使用这两个坐标。若是创建控制台窗口的应用程序,这些成员用于指明控制台窗口的左上角
dwXSize 用于设定应用程序窗口的宽度(以像素为单位)当子进程将CW_USEDEFAULT用作CreateWindow的nWidth参数来创建它的第一个重叠窗口时,才使用
dwYSize 用于设定应用程序窗口的长度(以像素为单位)当子进程将CW_USEDEFAULT用作CreateWindow的nWidth参数来创建它的第一个重叠窗口时,才使用
dwXCountChars 用于设定子应用程序的控制台窗口的宽度(以字符为单位)
dwYCountChars 用于设定子应用程序的控制台窗口的高度(以字符为单位)
dwFillAttribute 用于设定子应用程序的控制台窗口使用的文本和背景颜色
dwFlags 子进程窗口标志
wShowWindow 用于设定如果子应用程序初次调用的ShowWindow将SW_SHOWDEFAULT作为nCmdShow参数传递时,该应用程序的第一个重叠窗口应该如何出现
cbReserved2 保留,必须被初始化为0
lpReserved2 保留,必须被初始化为NULL
hStdInput 用于设定供控制台输入用的缓存的句柄
hStdOutput 用于设定供控制台输出用的缓存的句柄
hStdError 用于设定供控制台输出用的缓存的句柄
  • dwFlags参数:该参数可选类型如下
参数 描述
STARTF_USESIZE 使用dwXSize和dwYSize成员
STARTF_USESHOWWINDOW 使用wShowWindow成员
STARTF_USEPOSITION 使用dwX和dwY成员
STARTF_USECOUNTCHARS 使用dwXCountChars和dwYCountChars成员
STARTF_USEFILLATTRIBUTE 使用dwFillAttribute成员
STARTF_USESTDHANDLES 使用hStdInput、hStdOutput和hStdError成员
STARTF_RUN_FULLSCREEN 强制在x86计算机上运行的控制台应用程序以全屏幕方式启动运行

父进程代码

1 .父进程的功能是创建管道和创建进程

2 .创建成功后等待控制台输入信息并通过管道发送给子进程

3 .等待一段时间后从管道读取数据

4 .将管道数据输出到控制台

#include <iostream>
#include <windows.h>
using namespace std; char rxbuff[100] = { 0 };
char txbuff[100] = { 0 };
DWORD txcount = 0, rxcount = 0; void main(void)
{
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE; //管道创建
HANDLE hwrite, hread;
if (CreatePipe(&hread,&hwrite,&sa,0)==NULL)
{
cout << "pPipe Create error!" << endl;
return;
} //进程创建
STARTUPINFO si;
ZeroMemory(&si,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
si.hStdOutput = hwrite;
si.hStdInput = hread; PROCESS_INFORMATION pi;
TCHAR exe[] = TEXT("E:\\Soft_Pro\\VC_work\\MD5_Check\\Debug\\MD5_Check.exe");
//创建子进程
if (CreateProcess(NULL,
exe,
NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)==NULL)
{
cout << "进程创建错误" << endl;
CloseHandle(hread);
CloseHandle(hwrite);
hread = NULL;
hwrite = NULL;
return;
}
else
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
} cin >> txbuff;
//父进程往管道写数据
if (!WriteFile(hwrite, txbuff, sizeof(txbuff), &txcount, NULL))
{
cout << "父进程写数据失败!" << endl;
return;
}
else
{
cout << "父进程写数据成功!" << endl;
} Sleep(300); //父进程从管道读取数据
if (!ReadFile(hread,rxbuff,100,&rxcount,NULL))
{
cout << "父进程读取失败!" << endl;
return;
}
else
{
cout << "父进程管道读取数据:" << rxbuff << endl;
} system("pause");
}

子进程代码

1 .子进程获取管道数据的文件句柄

2 .子进程从输入端读取管道数据

3 .子进程将读取的数据从输出端发送至管道

#include <iostream>
#include <windows.h>
using namespace std; char rxbuff[100] = {0};
char txbuff[100] = {0};
DWORD txcount = 0, rxcount = 0;
HANDLE hRead, hWrite; int main(void)
{
hRead = GetStdHandle(STD_INPUT_HANDLE);
hWrite = GetStdHandle(STD_OUTPUT_HANDLE); //读管道数据
if (!ReadFile(hRead,rxbuff,100,&rxcount,NULL))
{
cout << "子进程读管道失败" << endl;
return 0;
}
sprintf_s(txbuff, "子进程应答:%s\n", rxbuff); Sleep(200); //写管道数据
if (!WriteFile(hWrite,txbuff,sizeof(txbuff),&txcount,NULL))
{
cout << "子进程写失败!" << endl;
return 0;
} return 0;
}

父进程运行结果

额外说明

  • CreateProcess的lpCommandLine参数使用TEXT("path")方式创建进程时总是报错,后来在一篇博客里看到了解决方案
  • 初次学习还有部分问题,后续继续补充

C++ 进程和匿名管道使用学习的更多相关文章

  1. linux的IPC进程通信方式-匿名管道(一)

    linux的IPC进程通信-匿名管道 什么是管道 如果你使用过Linux的命令,那么对于管道这个名词你一定不会感觉到陌生,因为我们通常通过符号"|"来使用管道,但是管道的真正定义是 ...

  2. Linux进程通信----匿名管道

    Linux进程通信中最为简单的方式是匿名管道 匿名管道的创建需要用到pipe函数,pipe函数参数为一个数组表示的文件描述字.这个数组有两个文件描 述字,第一个是用于读数据的文件描述符第二个是用于写数 ...

  3. Linux学习笔记(12)-进程间通信|匿名管道

    Linux的进程间通信有几种方式,包括,管道,信号,信号灯,共享内存,消息队列和套接字等-- 现在一个个的开始学习! ----------------------------------------- ...

  4. Linux学习笔记(13)-进程通信|命名管道

    匿名管道只能在具有亲属关系的进程间通信,那么如果想要在不具有亲戚关系,想在陌生人之间通信,那又该怎么办呢? 别慌,Linux身为世界上*强大的操作系统,当然提供了这种机制,那便是命名管道-- 所谓命名 ...

  5. linux进程通信之使用匿名管道进行父子进程通信

    管道:是指用于连接一个读进程和一个写进程,以实现它们之间通信的共享文件,又称pipe文件. 管道是单向的.先进先出的.无结构的.固定大小的字节流,它把一个进程的标准输出和另一个进程的标准输入连接在一起 ...

  6. 操作系统-进程通信(信号量、匿名管道、命名管道、Socket)

    进程通信(信号量.匿名管道.命名管道.Socket) 具体的概念就没必要说了,参考以下链接. 信号量 匿名管道 命名管道 Socket Source Code: 1. 信号量(生产者消费者问题) #i ...

  7. 邮槽 匿名管道 命名管道 剪贴板 进程通讯 转自http://www.cnblogs.com/kzloser/archive/2012/11/04/2753367.html#

    邮槽 通信流程: 服务器 客户端 注意: 邮槽是基于广播通信体系设计出来的,它采用无连接的不可靠的数据传输 邮槽可以实现一对多的单向通信,我们可以利用这个特点编写一个网络会议通知系统,而且实现这一的系 ...

  8. Windows进程通信之一看就懂的匿名管道通信

    目录 进程通信之一看就懂的匿名管道通信 一丶匿名管道 1.1何为匿名管道 1.2创建匿名管道需要注意的事项 1.3 创建匿名管道需要的步骤 1.4代码例子 1.5代码运行截图 进程通信之一看就懂的匿名 ...

  9. 进程通信类型 管道是Linux支持的最初Unix IPC形式之一 命名管道 匿名管道

    管道 Linux环境进程间通信(一) https://www.ibm.com/developerworks/cn/linux/l-ipc/part1/index.html 管道及有名管道 郑彦兴200 ...

随机推荐

  1. 执行 composer update 命令的时候报 Your requirements could not be resolved to an installable set of packages. 错误

    Your requirements could not be resolved to an installable set of packages. 以上原因:不匹配composer.json要求的版 ...

  2. c++ auto_ptr笔记

    1.auto_ptr 不可以使用指针惯用的赋值初始化方式,只能直接初始化. 示例:  char *p = 'A';//error  auto_ptr<char>ptr = new char ...

  3. js运用sort对json 数组进行排序

    Array.sort()方法是用来对数组项进行排序的 ,默认情况下是进行升序排列.sort() 方法可以接受一个 方法为参数. sort()排序时每次比较两个数组项都回执行这个参数,并把两个比较的数组 ...

  4. 一本通1166 求f(x,n)

    [题目描述] 已知 计算x=4.2,n=1以及x=2.5,n=15时f的值. [输入] 输入x和n. [输出] 函数值,保留两位小数. [输入样例] 4.2 10 [输出样例] 3.68 1.看见这种 ...

  5. CentOS7.7安装python3.8.2与pip20

    1.安装第三方库 # yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-deve ...

  6. springboot-jar

    预览 1.pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns=&quo ...

  7. oracle(8)视图和查询数据库对象方法

    视图 view 视图是数据库的对象之一. 视图也叫做虚表,既虚拟表,本质是对应一条select 语句, select语句的结果集赋予一个名字就是视图的名字. 作用: 1.可以简化复杂的查询 2.可以限 ...

  8. VMware Workstation 12 PRo密钥

    注意:手动输入(起初复制输入,一个都没成功,不要偷懒哦) VMware Workstation 12序列号: 5A02H-AU243-TZJ49-GTC7K-3C61N

  9. Vue-router(4)之路由跳转

    路由传参 案例:现在需要展示一个电影列表页,点击每一部电影,会跳转到该部电影详情页(跳转时携带type和id) 代码实现(未携带type): index.js import Vue from 'vue ...

  10. 第32&35章 数据库的安装&存储实力的管理

    第32章 数据库的安装IO取决于磁盘的个数和接口带宽 版本安装顺序是从低到高存储架构师 第35章 存储实例的管理ASM配置说白了就是ORACLE自己的,不通过操作系统对磁盘进行管理.fdisk -l查 ...