C++调用外部应用程序
很多时候,我们的程序需要调用DOS命令,通过Dos命令调用其他程序从而完成所需要完成的功能。比如,调用Dos程序PKZIP完成ZIP包的解压缩,调用SVN完成文件的更新或者上传。但是在程序运行时又要求没有DOS控制台的窗口出现,而且一切本应该在DOS下显示的信息都应该出现在我们程序提供的文本框里。
如果才能实现这种功能?需要解决两个问题:
1、调用外部应用程序。
2、不显示DOS窗口,并能将应该在DOS显示的内容,重定向到自己程序内。
C++调用外部应用程序有三个SDK:
WinExec,ShellExecute ,CreateProcess
.Net调用外部应用程序用System.Diagnostics.Process.Start(processStartInfo)
其中以WinExec最为简单,ShellExecute比WinExec灵活一些,CreateProcess最为复杂。
(1)WinExec 两个参数,前一个指定路径,后一个指定显示方式。
(2)ShellExecute 可以指定工作目录,并且还可以寻找文件的关联直接打开不用加载与文件关联的应用程序,ShellExecute还可以打开网页,启动相应的邮件关联发送邮件等等。
(3)CreateProcess 一共有十个参数,不过大部分都可以用NULL代替,它可以指定进程的安全属性,继承信息,类的优先级等等。如果我们要得到足够多的关于新的进程的信息,控制新的进程的细节属性,若要达到这些目的,我们就需要使用CreateProcess函数了。
要实现[将应该在DOS显示的内容,重定向到自己程序内],本程序选了CreateProcess。
调用外部应用程序的SDK确定了之后,还需要考虑用什么方法重定向DOS的显示信息,此时,可以用[匿名管道] 技术实现这个功能。
管道
管道技术由来已久,相信不少人对DOS命令里的管道技术最为熟悉。当我们type一个文件的时候如果想让他分页现实可以输入
C:\>type autoexec.bat|more
这里“|”就是管道操作符。他以type输出的信息为读取端,以more的输入端为写入端建立的管道。
管道是针对两个进程之间的通信而设计的,管道建立后,实际获得两个文件描述符:一个用于读取而另外一个用于写入。任何从管道写入端写入的数据,可以从管道读取端读出。特点:管道是半双工的,数据只能向一个方向流动,需要双方通信时,需要建立起两个管道。
匿名管道
匿名管道,就是没有名字的管道,还有一种管道,叫做命名管道。命名管道的功能很强大,匿名管道在命名管道面前,功能那是简陋的不行的。匿名管道正因为提供的功能很单一,所以它所需要的系统的开销也就比命名管道小很多,在本地机器上可以使用匿名管道来实现父进程和子进程之间的通信,这里需要注意两点,第一就是在本地机器上,这是因为匿名管道不支持跨网络之间的两个进程之间的通信,第二就是实现的是父进程和子进程之间的通信,而不是任意的两个进程。然后得话还顺便介绍匿名管道的另外一种功能,其通过匿名管道可以实现子进程输出的重定向。下面介绍一下匿名管道的使用:
(1)匿名管道主要用于本地父进程和子进程之间的通信,
(2)在父进程中的话,首先是要创建一个匿名管道,
(3)在创建匿名管道成功后,可以获取到对这个匿名管道的读写句柄,
(4)然后父进程就可以向这个匿名管道中写入数据和读取数据了,
(5)但是如果要实现的是父子进程通信的话,那么还必须在父进程中创建一个子进程,
(6)同时,这个子进程必须能够继承和使用父进程的一些公开的句柄,
(7)为什么呢?
(8)因为在子进程中必须要使用父进程创建的匿名管道的读写句柄,
(9)通过这个匿名管道才能实现父子进程的通信,所以必须继承父进程的公开句柄。
(10)同时在创建子进程的时候,
(11)必须将子进程的标准输入句柄设置为父进程中创建匿名管道时得到的读管道句柄,
(12)将子进程的标准输出句柄设置为父进程中创建匿名管道时得到的写管道句柄。
(13)然后在子进程就可以读写匿名管道了。
借用Linux下的匿名管道实现机制如下:
要实现全双工通信,就需要再创建一个管道,并且Windows是子进程是将标准输入输出重置为管道读写端的。
调用外部程序步骤
1、创建管道
函数原型:
BOOL WINAPI CreatePipe(
_Out_PHANDLE hReadPipe,
_Out_PHANDLE hWritePipe,
_In_opt_LPSECURITY_ATTRIBUTES lpPipeAttributes,
_In_DWORD nSize);
实际调用形式:
CreatePipe(&read, &write, &sa, );
其中read是读句柄,write是写句柄,sa是管道安全属性,0代表管道缓冲设置为系统默认值。
由上函数可知在创建管道之前,需要先设置管道安全属性。
设置管道安全属性
对象原型:
typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength; //结构体的大小,可用SIZEOF取得
LPVOID lpSecurityDescriptor; //安全描述符
BOOL bInheritHandle ;//安全描述的对象能否被新创建的进程继承
} SECURITY_ATTRIBUTES,* PSECURITY_ATTRIBUTES;
在程序中仅需如下设置即可:(网上有很多使用方法,此处略过)
sa.bInheritHandle = TRUE; // TRUE为管道可以被子进程所继承
sa.lpSecurityDescriptor = NULL; // 默认为NULL
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
创建好管道后,可以考虑创建子进程,使其继承父进程的管道句柄。
创建子进程
1、createprocess的参数
TCHAR szCmdline[] = TEXT("../../child/Debug/child.exe"); // 设置子进程路径
BOOL bSuccess = FALSE;
PROCESS_INFORMATION pi; // 用来接收新进程的识别信息
STARTUPINFO si; // 用于决定新进程的主窗体如何显示
// 设置PROCESS_INFORMATION
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); // 用0填充内存区域
// 设置STARTUPINFO
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO); // 结构大小 HANDLE read1, write1,read2,write2;
//*************** 句柄继承设置******************
// 创建了两个管道
// 管道1由父进程读,子进程写
// 管道2由父进程写,子进程读
si.hStdError = write1; // 错误输出句柄(在写句柄中写回父进程)
si.hStdOutput = write1; // 子进程继承管道1写句柄
si.hStdInput = read2; // 子进程继承管道2读句柄
//*************** 句柄继承设置******************
si.dwFlags |= STARTF_USESTDHANDLES; // 使用hStdInput 、hStdOutput 和hStdError 成员
// 创建子进程
// 摘自msdn:
// If lpApplicationName is NULL,
// the first white space–delimited token of the command line specifies the module name.
bSuccess = CreateProcess(
NULL, // lpApplicationName
szCmdline, // command line
// 以上两个字段都可以创建目标子进程
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // bInheritHandles:指示新进程是否从调用进程处继承了句柄
, // creation flags:指定附加的、用来控制优先类和进程的创建的标志。
// 设置为 CREATE_NEW_CONSOLE 可显示子窗口
NULL, // use parent's environment
NULL, // use parent's current directory
&si, // STARTUPINFO :指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体
&pi // PROCESS_INFORMATION :指向一个用来接收新进程的识别信息的PROCESS_INFORMATION结构体
);
// If an error occurs, exit the application.
if (!bSuccess)
cout << "创建子程序失败" << endl;
else
{
// 关闭一些子进程用的句柄
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(write1);
CloseHandle(read2);
}
首先设置子进程所在路径,子进程为一个exe可执行程序。然后会用到两个类型STARTUPINFO和PROCESS_INFORMATION,有兴趣的朋友可自行百度,查看两种类中的参数。
这里也不贴CreateProcess的函数原型了,代码块中有较好的注释。
其实对于管道创建和子进程创建都是一个模版框架。
读写函数请见github源代码
步骤总结:
1、创建管道
2、创建子进程
3、父进程从管道内读取数据
4、子进程内,从管道内读取数据,并且向另一个管道内写入数据,供父进程读取。(子进程调用一般就是DOS,然后是外部程序的命令以及参数等)
C++调用外部应用程序的更多相关文章
- windows下调用外部exe程序 SHELLEXECUTEINFO
本文主要介绍两种在windows下调用外部exe程序的方法: 1.使用SHELLEXECUTEINFO 和 ShellExecuteEx SHELLEXECUTEINFO 结构体的定义如下: type ...
- c# 调用外部exe程序
c#调用外部exe程序,首先要 using System.Diagnostics; 然后开启一个新process System.Diagnostics.ProcessStartInfo p=null; ...
- [转]VC中调用外部exe程序方式
本文转自:http://blog.sina.com.cn/s/blog_486285690100ljwu.html 目前知道三种方式:WinExec,ShellExecute ,CreateProce ...
- C++调用外部应用程序的方法的整理总结(常用)
一.三个SDK函数: WinExec,ShellExecute ,CreateProcess可以实现调用其他程序的要求,其中以WinExec最为简单,ShellExecute比WinExec灵活一些 ...
- as3调用外部应用程序 as调用外部exe文件as3调用bat文件 未测试
private function callTest(event: Event): void{callExe("d:/a.exe");callBat("d:/a.bat&q ...
- Delphi xe5调用外部扫描程序——谷歌 zxing
unit uZXing; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Va ...
- python模拟鼠标键盘操作 GhostMouse tinytask 调用外部脚本或程序 autopy右键另存为
0.关键实现:程序窗口前置 python 通过js控制滚动条拉取全文 通过psutil获取pid窗口句柄,通过win32gui使程序窗口前置 通过pyauto实现右键菜单和另存为操作 1.参考 aut ...
- System.Diagnostics.Process 启动进程资源或调用外部的命令的使用
经常看到一些程序在保存为一个txt,或者excel的文件的时候,保存完毕立即打开, 启动程序或打开文件的代码 System.Diagnostics.Process.Start(System.IO.Pa ...
- 关于js调用外部部署的web api
没想到多年之后我还得继续写这些东西.... 瀑布汗~ 最近不得不开始研究用web api MVC的项目中,在js文件里,实现点击一个按钮调用外部发布好的api,再从api把值回传给js页面,跳转. 经 ...
随机推荐
- Sharc FLAGS I/O Register(flag0~3)
Core FLAG Pins Multiplexing This module also includes the multiplexers of the FLAG0-3 pins shown ...
- CPU个数、CPU核心数、CPU线程数
CPU个数.CPU核心数.CPU线程数 我们在选购电脑的时候,CPU是一个需要考虑到核心因素,因为它决定了电脑的性能等级.CPU从早期的单核,发展到现在的双核,多核.CPU除了核心数之外,还有线程数之 ...
- socket.io的用户认证
一直专心于写代码,遇到问题便看别人的博客来解决问题,突然感觉自己也应该写点东西帮助别人来解决问题.废话不多说了,直接切入正题~ 最近在写一个聊天室来学习node和socket相关知识.遇到的问题描述: ...
- [洛谷P2258][NOIP2014PJ]子矩阵(dfs)(dp)
NOIP 2014普及组 T4(话说一道PJ组的题就把我卡了一个多小时诶) 这道题在我看第一次的时候是没有意识到这是一道DP题的,然后就摁着DFS敲了好长时间,结果敲了一个TLE 这是DP!!! 下面 ...
- CF868 F. Yet Another Minimization Problem 决策单调优化 分治
目录 题目链接 题解 代码 题目链接 CF868F. Yet Another Minimization Problem 题解 \(f_{i,j}=\min\limits_{k=1}^{i}\{f_{k ...
- POJ.2728.Desert King(最优比率生成树 Prim 01分数规划 二分/Dinkelbach迭代)
题目链接 \(Description\) 将n个村庄连成一棵树,村之间的距离为两村的欧几里得距离,村之间的花费为海拔z的差,求花费和与长度和的最小比值 \(Solution\) 二分,假设mid为可行 ...
- 洛谷.3391.[模板]文艺平衡树(Splay)
题目链接 //注意建树 #include<cstdio> #include<algorithm> const int N=1e5+5; //using std::swap; i ...
- C++ map<key , value> key值为指针
STL中map的key能否用char *呢?当然可以! 在程序中需要用到一个map,本来是这样写的, map<string, int> mapStr; 为了追求效率,把string改成了c ...
- 初识zookeeper(1)之zookeeper的安装及配置
初识zookeeper(一)之zookeeper的安装及配置 1.简要介绍 zookeeper是一个分布式的应用程序协调服务,是Hadoop和Hbase的重要组件,是一个树型的目录服务,支持变更推送. ...
- What’s Brewing for .NET Developers
Microsoft hosted its premier fall developer event – Connect(); // 2016 in New York on November 16-17 ...