?
MSDN里面有一些文档可以看看,方法是利用CreateProcess的 LPSTARTUPINFO 参数,
设置dwFlags为STARTF_USESTDHANDLES:
然后自定义:
HANDLE  hStdInput;
HANDLE  hStdOutput;
HANDLE  hStdError;
三个流句柄。
这些句柄可以用CreatePipe创建的匿名管道句柄代替:
BOOL CreatePipe(
PHANDLE hReadPipe,                       // read handle
PHANDLE hWritePipe,                      // write handle
LPSECURITY_ATTRIBUTES lpPipeAttributes,  // security attributes
DWORD nSize                              // pipe size
);
其中hStdOutput,hStdError传给hWritePipe,hStdInput传给hReadPipe,然后把管道的另一端的句柄保存起来。就可以用ReadFile/WriteFile从这些句柄读取/写入控制台程序的输出/输入。
要注意的是这些句柄的继承性,调用CreateProcess时注意设置BOOL bInheritHandles = TRUE,使它可以继承主进程的句柄。调用CreatePipe要设置LPSECURITY_ATTRIBUTES lpPipeAttributes参数使Pipe的句柄能够被继承。
此外,这样使CreatePipe创建的两个句柄都可以被继承了,所以要调用DuplicateHandle把不需要传入子进程的句柄设置为不可继承。不然子进程拥有了另一个句柄但是不会调用Closehandle减少引用记数,会导致Pipe不能被在使用完毕后被撤消。
此外注意关闭所有使用过的内核对象句柄。
以下是MSDN的一个例子:
  1. INHERIT.C
  2. /*******************************************************************************       This is a part of the Microsoft Source Code Samples.
  3. *       Copyright (C) 1992-1996 Microsoft Corporation.
  4. *       All rights reserved.
  5. *       This source code is only intended as a supplement to
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the
  8. *       Microsoft samples programs.
  9. /******************************************************************************/
  10. /********************************************************************
  11. * This program is to demonstrate the use of anonymous pipes used as *
  12. * stdout and stderr replacements. One of two techniques can be      *
  13. * chose to do this: the SetStdHandle technique or the               *
  14. * STARTF_USESTDHANDLES technique. The SetStdHandle technique sets   *
  15. * the standard output handles to the pipe that we will read from,   *
  16. * which the child will inherit. The STARTF_USESTDHANDLES technique  *
  17. * passes the pipe handles to the child as standard handles via the  *
  18. * STARTUPINFO structure. The STARTF_USESTDHANDLES technique *must*  *
  19. * be used for "console-less" processes such as GUI applications or  *
  20. * detached processes.                                               *
  21. *                                                                   *
  22. * This program demonstrates the use of the following Win32 APIs:    *
  23. *   CreatePipe, CreateProcess.                                      *
  24. *                                                                   *
  25. * This program also uses the following Win32 APIs:                  *
  26. *   GetLastError, CreateFile, CloseHandle, CreateProcess, ReadFile, *
  27. *   WriteFile.                                                      *
  28. *                                                                   *
  29. *                                                                   *
  30. * Execution instructions:                                           *
  31. *                                                                   *
  32. *   inherit <trace file> <command to execute>                       *
  33. *   trace file is the name of the file where the stdout             *
  34. *     and stderr of command will be redirected                      *
  35. *                                                                   *
  36. *   command to execute can be either an external executable or an   *
  37. *     internal cmd.exe command.                                     *
  38. *                                                                   *
  39. *   Examples:                                                       *
  40. *                                                                   *
  41. *   inherit chkdsk.dat chkdsk d:                                    *
  42. *   inherit nmake.txt nmake /f foo.mak                              *
  43. *                                                                   * ********************************************************************/
  44. #include <windows.h>
  45. #include <stdio.h>
  46. #include <stdlib.h>
  47. #include <string.h>
  48. /* define USESTDHANDLES to use the new technique of passing the
  49. standard handles to the child process via the STARTUPINFO structure.
  50. This technique must be used for "console-less" parents such as GUI
  51. applications or detached applications. */
  52. #define USESTDHANDLES
  53. /* Standard error macro for reporting API errors */
  54. //#define PERR(bSuccess, api) {if (!(bSuccess)) printf("%s: Error %d from %s
  55. //    on line %d/n", __FILE__, GetLastError(), api, __LINE__);}  void PERR(BOOL bSuccess, char * api);
  56. int main(int argc, char *argv[])
  57. {
  58. char chReadBuffer[64];  /* pipe read buffer */
  59. BOOL bSuccess;  /* BOOL return code for APIs */
  60. int j;
  61. HANDLE hOutFile;  /* handle to log file */
  62. /* handles to the anonymous pipe */
  63. HANDLE hReadPipe, hWritePipe, hWritePipe2;
  64. char szArgs[256];  /* child process argument buffer */
  65. char *p;  /* temporary pointer into szArgs */
  66. DWORD cchReadBuffer;  /* number of bytes read or to be written */
  67. STARTUPINFO si;  /* for CreateProcess call */
  68. PROCESS_INFORMATION pi;  /* for CreateProcess call */
  69. SECURITY_ATTRIBUTES saPipe;  /* security for anonymous pipe */
  70. OSVERSIONINFO os; /* operating system specs */
  71. os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); // required assignment
  72. // check if running on Windows NT, if not, display notice and terminate
  73. if ( GetVersionEx(&os) )
  74. {
  75. if( os.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS &
  76. os.dwPlatformId != VER_PLATFORM_WIN32_NT)
  77. {
  78. MessageBox( NULL,
  79. "This sample application can only run on Windows NT and Windows 95./n
  80. This application will now terminate.",
  81. "Inherit",
  82. MB_OK | MB_ICONSTOP | MB_SETFOREGROUND );
  83. return( 1 );
  84. }
  85. }
  86. else
  87. {
  88. MessageBox( NULL,
  89. "Unable to test for OS version.",
  90. "Inherit Error",
  91. MB_OK | MB_ICONSTOP | MB_SETFOREGROUND );
  92. return( 1 );
  93. }
  94. if (argc < 3)
  95. {
  96. puts("format: inherit <trace file> <command to execute>");
  97. puts("trace file is the name of the file where the stdout");
  98. puts("and stderr of command will be redirected/n");
  99. puts("command to execute is command line of the function");
  100. puts("you wish to perform./n");
  101. puts("Examples:/n");
  102. puts("  inherit trace.txt chkdsk d:");
  103. puts("  inherit trace.txt nmake /f foo.mak");
  104. return(1);
  105. }
  106. /* create the log file where we will save all output from child */
  107. hOutFile = CreateFile(argv[1],  /* file to open */
  108. GENERIC_WRITE,  /* access mode */
  109. FILE_SHARE_READ,  /* share mode */
  110. NULL,  /* security attributes */
  111. CREATE_ALWAYS,  /* creation flags - trash existing file */
  112. FILE_ATTRIBUTE_NORMAL,  /* file attributes */
  113. NULL);
  114. PERR(hOutFile != INVALID_HANDLE_VALUE, "CreateFile");
  115. /* set up the security attributes for the anonymous pipe */
  116. saPipe.nLength = sizeof(SECURITY_ATTRIBUTES);
  117. saPipe.lpSecurityDescriptor = NULL;
  118. /* In order for the child to be able to write to the pipe, the handle */
  119. /* must be marked as inheritable by setting this flag: */
  120. saPipe.bInheritHandle = TRUE;
  121. /* create the anonymous pipe */
  122. bSuccess = CreatePipe(&hReadPipe,  /* read handle */
  123. &hWritePipe,  /* write handle, used as stdout by child */
  124. &saPipe,  /* security descriptor */
  125. 0);  /* pipe buffer size */
  126. PERR(bSuccess, "CreatePipe");
  127. /* Now we need to change the inheritable property for the readable
  128. end of the pipe so that the child will not inherit that handle as
  129. a "garbage" handle. This will keep us from having extra,
  130. unclosable handles to the pipe. Alternatively, we could have
  131. opened the pipe with saPipe.bInheritHandle = FALSE and changed the
  132. inherit property on the *write* handle of the pipe to TRUE. */
  133. bSuccess = DuplicateHandle(GetCurrentProcess(), /* source process */
  134. hReadPipe, /* handle to duplicate */
  135. GetCurrentProcess(), /* destination process */
  136. NULL, /* new handle - don't want one, change original handle */
  137. 0, /* new access flags - ignored since DUPLICATE_SAME_ACCESS */
  138. FALSE, /* make it *not* inheritable */
  139. DUPLICATE_SAME_ACCESS);
  140. PERR(bSuccess, "DuplicateHandle");
  141. /* I most cases you can get away with using the same anonymous
  142. pipe write handle for both the child's standard output and
  143. standard error, but this may cause problems if the child app
  144. explicitly closes one of its standard output or error handles. If
  145. that happens, the anonymous pipe will close, since the child's
  146. standard output and error handles are really the same handle. The
  147. child won't be able to write to the other write handle since the
  148. pipe is now gone, and parent reads from the pipe will return
  149. ERROR_BROKEN_PIPE and child output will be lost. To solve this
  150. problem, simply duplicate the write end of the pipe to create
  151. another distinct, separate handle to the write end of the pipe.
  152. One pipe write handle will serve as standard out, the other as
  153. standard error. Now *both* write handles must be closed before the
  154. write end of the pipe actually closes. */
  155. bSuccess = DuplicateHandle(GetCurrentProcess(), /* source process */
  156. hWritePipe, /* handle to duplicate */
  157. GetCurrentProcess(), /* destination process */
  158. &hWritePipe2, /* new handle, used as stderr by child */
  159. 0, /* new access flags - ignored since DUPLICATE_SAME_ACCESS */
  160. TRUE, /* it's inheritable */
  161. DUPLICATE_SAME_ACCESS);
  162. PERR(bSuccess, "DuplicateHandle");
  163. /* Set up the STARTUPINFO structure for the CreateProcess() call */
  164. memset(&si, 0, sizeof(si));
  165. si.cb = sizeof(si);
  166. /* Set up the command-line buffer for the child for CreateProcess() */
  167. memset(szArgs, 0, sizeof(szArgs));
  168. strcpy(szArgs, argv[2]);
  169. if (strchr(szArgs, '.') == NULL)  /* does it have a '.'? */
  170. strcat(szArgs, ".exe");  /* if not, assume it's an .exe */
  171. strcat(szArgs, " ");
  172. p = strchr(szArgs, 0);  /* point to the terminating null */
  173. for (j = 3; j < argc; j++)
  174. {
  175. strcat(p, argv[j]);
  176. /* the program and parameters are delimited by spaces */
  177. strcat(p, " ");
  178. }
  179. #ifdef USESTDHANDLES
  180. /* If using the STARTUPINFO STARTF_USESTDHANDLES flag, be sure to
  181. set the CreateProcess fInheritHandles parameter too TRUE so that
  182. the file handles specified in the STARTUPINFO structure will be
  183. inheritied by the child. Note that we don't specify a standard
  184. input handle; the child will not inherit a valid input handle, so
  185. if it reads from stdin, it will encounter errors. */
  186. si.hStdInput = hWritePipe2; /* hStdInput needs a valid handle in case it is checked by the child */
  187. si.hStdOutput = hWritePipe; /* write end of the pipe */
  188. si.hStdError = hWritePipe2; /* duplicate of write end of the pipe */
  189. si.dwFlags = STARTF_USESTDHANDLES;
  190. #else
  191. /* If we're not using the STARTF_USESTDHANDLES flag, set the
  192. standard output and error handles to the end of the pipe we want
  193. the child to inherit with SetStdHandle(). For this program, we
  194. don't want standard input inherited so we'll also change the
  195. handle inheritance property of standard input so that it is not
  196. inherited */
  197. bSuccess = SetStdHandle(STD_INPUT_HANDLE, hWritePipe2);
  198. PERR(bSuccess, "SetStdHandle");
  199. bSuccess = SetStdHandle(STD_OUTPUT_HANDLE, hWritePipe);
  200. PERR(bSuccess, "SetStdHandle");
  201. bSuccess = SetStdHandle(STD_ERROR_HANDLE, hWritePipe2);
  202. PERR(bSuccess, "SetStdHandle");
  203. bSuccess = DuplicateHandle(GetCurrentProcess(), /* source process */
  204. GetStdHandle(STD_INPUT_HANDLE), /* handle to duplicate */
  205. GetCurrentProcess(), /* destination process */
  206. NULL, /* new handle - don't want one, change original handle */
  207. 0, /* new access flags - ignored since DUPLICATE_SAME_ACCESS */
  208. FALSE, /* it's *not* inheritable */
  209. DUPLICATE_SAME_ACCESS);
  210. PERR(bSuccess, "DuplicateHandle");
  211. #endif
  212. /* Now create the child process, inheriting handles */
  213. bSuccess = CreateProcess(NULL,  /* filename */
  214. szArgs,  /* full command line for child */
  215. NULL,  /* process security descriptor */
  216. NULL,  /* thread security descriptor */
  217. TRUE,  /* inherit handles? Also use if STARTF_USESTDHANDLES */
  218. 0,  /* creation flags */
  219. NULL,  /* inherited environment address */
  220. NULL,  /* startup dir; NULL = start in current */
  221. &si,  /* pointer to startup info (input) */
  222. π);  /* pointer to process info (output) */
  223. PERR(bSuccess, "CreateProcess");
  224. /* We can close the returned child process handle and thread
  225. handle as we won't be needing them; you could, however, wait on
  226. the process handle to wait until the child process terminates. */
  227. CloseHandle(pi.hThread);
  228. CloseHandle(pi.hProcess);
  229. /* We need to close our instances of the inheritable pipe write
  230. handle now that it's been inherited so that all open handles to
  231. the pipe are closed when the child process ends and closes its
  232. handles to the pipe. */
  233. bSuccess = CloseHandle(hWritePipe);
  234. PERR(bSuccess, "CloseHandle");
  235. bSuccess = CloseHandle(hWritePipe2);
  236. PERR(bSuccess, "CloseHandle");
  237. /* read from the pipe until we get an ERROR_BROKEN_PIPE */
  238. for (;;)
  239. {
  240. bSuccess = ReadFile(hReadPipe,  /* read handle */
  241. chReadBuffer,  /* buffer for incoming data */
  242. sizeof(chReadBuffer),  /* number of bytes to read */
  243. &cchReadBuffer,  /* number of bytes actually read */
  244. NULL);  /* no overlapped reading */
  245. if (!bSuccess && (GetLastError() == ERROR_BROKEN_PIPE))
  246. break;  /* child has died */
  247. PERR(bSuccess, "ReadFile");
  248. if (bSuccess && cchReadBuffer)
  249. {
  250. /* write the data from the child to the file */
  251. bSuccess = WriteFile(hOutFile,  /* write handle */
  252. chReadBuffer,  /* buffer to write */
  253. cchReadBuffer,  /* number of bytes to write */
  254. &cchReadBuffer,  /* number of bytes actually written */
  255. NULL);  /* no overlapped writing */
  256. PERR(bSuccess, "WriteFile");
  257. /* write buffer (of specified length) to console */
  258. printf("%.*s", cchReadBuffer, chReadBuffer);
  259. }
  260. }
  261. /* close the trace file, pipe handles */
  262. CloseHandle(hOutFile);
  263. CloseHandle(hReadPipe);
  264. return(0);
  265. }
  266. void PERR(BOOL bSuccess, char * api)
  267. {
  268. DWORD       dwError;
  269. TCHAR       szMsgBuf[500];
  270. if (!(bSuccess))
  271. {
  272. dwError = GetLastError();
  273. printf("/nFile:%s/nError occured in %s on line %d/n", __FILE__, api, __LINE__);
  274. FormatMessage(
  275. FORMAT_MESSAGE_FROM_SYSTEM,
  276. NULL,                               // ignored
  277. dwError,                     // message id
  278. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),   // message language
  279. szMsgBuf,                   // address of buffer pointer
  280. 500,                                  // minimum buffer size
  281. NULL );                              // no other arguments
  282. printf("/nError:(%ld)%s ", dwError, szMsgBuf);
  283. }
  284. }

怎样在windows环境中启动某控制台程序并改变它的stdin、stdout和stderr? http://book.77169.org/ask18/how106297.htm相关推荐

  1. Microsoft Windows 环境中NLS_LANG的正确设置 (文档 ID 1577370.1)

    Microsoft Windows 环境中NLS_LANG的正确设置 (文档 ID 1577370.1) 适用于: Oracle Database - Enterprise Edition - 版本 ...

  2. windows环境rocketMq启动mqbroker.cmd无反应

    问题现象 windows环境rocketMq启动mqbroker.cmd无反应. 问题排查 这时我们找到rocketmq的日志,打开看一下日志C:\Users\admin\logs\rocketmql ...

  3. 离线安装python第三方库的实用方法:解决公司内网,服务器/电脑不能上网却需要安装python三方库问题(上:Windows环境中)

    离线安装python第三方库的实用方法:解决公司内网,服务器/电脑不能上网却需要安装python三方库问题(上:Windows环境中) 参考文章: (1)离线安装python第三方库的实用方法:解决公 ...

  4. windows环境中,pm2不是内部或外部命令的解决方案

    windows环境中,pm2下载成功后却显示不是内部或外部命令解决方法 一开始遇见这种情况很是头疼,百度了很多pm2下载成功却显示不是内部命令的原因,结果都不尽人意,没有解决:于是我就在想安装成功后不 ...

  5. Windows环境中运行.dll文件

    Windows环境中运行.dll文件 安装dotnet-sdk 1.官网下载自己所需要的sdk版本https://dotnet.microsoft.com/zh-cn/download/dotnet ...

  6. windows环境下Eclipse开发MapReduce程序遇到的四个问题及解决办法

    按此文章<Hadoop集群(第7期)_Eclipse开发环境设置>进行MapReduce开发环境搭建的过程中遇到一些问题,饶了一些弯路,解决办法记录在此: 文档目的: 记录windows环 ...

  7. Windows系统中防止病毒木马程序的几种方式

    Windows系统中防止病毒木马程序的几种方法 1. BIOS防病毒入侵 在开机时,按F2或F8键进入BIOS,Advanced BIOS Features–>Virus Warning–> ...

  8. Neo4j 第一篇:在Windows环境中安装Neo4j

    图形数据库(Graph Database)是NoSQL数据库家族中特殊的存在,用于存储丰富的关系数据,Neo4j 是目前最流行的图形数据库,支持完整的事务,在属性图中,图是由顶点(Vertex),边( ...

  9. 同一台Windows机器中启动多个Memcached服务

    我使用的Visual-AMP的PHP集成环境中,已经存在一个memcached,如果我打开这个服务,那么windows上的memcached 进程就会被这个占用,端口为它的默认端口号11211. 如果 ...

最新文章

  1. 解决Caused by: java.lang.NoSuchMethodException: com.mchange.v2.c3p0.cfg.C3P0Config.init()的总结...
  2. 【原理+实战+视频+源码】手撸SpringBoot缓存系统
  3. Kubernetes对象中的PersistentVolume、PersistentVolumeClaim和StorageClass的概念关系
  4. android gradle + junit + jacoco 集成jenkins,sonar系统
  5. 为什么Kubernetes要引入pod的概念,而不直接操作Docker容器
  6. Spring系列:父子容器详解
  7. 将误删的Downloads文件夹快速恢复教程
  8. Servlet的文件上传
  9. 1016.外网资源下载神器
  10. java 二叉树的各种遍历
  11. 常见的系统store procedure
  12. 操作系统课设 Nachos 实验三:利用信号量实现线程同步
  13. 基于php技术的Web的电子病历管理系统
  14. 万年历Java有界面_java万年历界面版
  15. 优秀的WMS仓库管理系统应该具备哪些条件
  16. flutter BoxDecoration设置背景 image 报错:type ‘Image‘ is not a subtype of type ‘ImageProvider<Object> 解决方法
  17. 解压压缩包的时候要求输入密码
  18. Word文档进行XXE攻击
  19. Python处理CSV文件(一)
  20. 企业邮箱支持通过手机号登录邮箱

热门文章

  1. 驭势主张 | 创业路上,勿失童心
  2. Tracker:元数据搜刮工具
  3. mysql csv格式导入
  4. 红客团队html引导,HTML语言--百度红客吧系列专题课程--23
  5. 百度媒体云播放器用法
  6. B站微服务框架Kratos详细教程(1)- 安装搭建
  7. go kratos 微服务框架(笔记一)
  8. 腾讯视频进入台湾地区:付费会员每月42元
  9. oracle ip地址 计算,【翻译自mos文章】怎么正确的计算一个ip地址的subnet id?
  10. 教育知识与能力-第二章 中学课程