windows 主进程创建子进程并运行Ping 命令(CMD)
windows 主进程创建子进程并运行Ping 命令(CMD)
/*
主进程创建子进程并运行Ping 命令
*/
#include <Windows.h>
#include <tchar.h>
#include <strsafe.h>
#define GRS_USEPRINTF() TCHAR pBuf[1024] = {}
#define GRS_PRINTF(...) \
StringCchPrintf(pBuf,1024,__VA_ARGS__);\
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),pBuf,lstrlen(pBuf),NULL,NULL);
#define GRS_USEPRINTFA() CHAR pBufA[1024] = {}
#define GRS_PRINTFA(...) \
StringCchPrintfA(pBufA,1024,__VA_ARGS__);\
WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE),pBufA,lstrlenA(pBufA),NULL,NULL);
#define GRS_ALLOC(sz) HeapAlloc(GetProcessHeap(),0,sz)
#define GRS_CALLOC(sz) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz)
#define GRS_SAFEFREE(sz) if(NULL != p){HeapFree(GetProcessHeap(),0,p);p=NULL;}
//获取应用程序所在的路径
void GetAppPath(PTSTR pszPath)
{
DWORD dwLen = 0;
//获取当前进程已加载模块的文件的完整路径
dwLen = GetModuleFileName(NULL, pszPath, MAX_PATH);//NULL表示获取当前exe全路径
if (dwLen == 0) return;
for (DWORD i = dwLen; i > 0; i--)
{
if ('\\' == pszPath[i])
{
pszPath[i + 1] = '\0';
break;
}
}
}
//这几个是用于测试的
#define text0 0
#define test1 0
#define test2 0
#define text3 0
#define text4 0
int _tmain()
{
GRS_USEPRINTF();
TCHAR pszAppPath[MAX_PATH + 1] = {};
TCHAR pszExe[MAX_PATH + 1] = {};
GetAppPath(pszAppPath);//获取当前exe文件所在的目录
STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi = {};
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES) };
sa.bInheritHandle = FALSE;//该子进程不可继承
#if text0
//启用窗口应用程序
si.dwFlags = STARTF_USESIZE | STARTF_USESHOWWINDOW | STARTF_USEPOSITION;
si.wShowWindow = SW_SHOWNORMAL;
si.dwXSize = 800;
si.dwYSize = 300;
si.dwX = 312;
si.dwY = 234;
StringCchPrintf(pszExe, MAX_PATH, _T("%s%s"), pszAppPath, _T("SubGUI.exe"));
CreateProcess(pszExe, pszExe, NULL, NULL, TRUE, 0, NULL, pszAppPath, &si, &pi);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
#endif // text0
printf("这是父进程的控制台窗口!\r\n");
#if test1
//启动控制台窗口
//1,附加到本进程输入输出,默认特性
si.dwFlags = 0;
StringCchPrintf(pszExe, MAX_PATH, _T("%s%s"), pszAppPath, _T("SubConsole.exe"));
CreateProcess(pszExe, pszExe, NULL, NULL, TRUE, 0, NULL, pszAppPath, &si, &pi);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
#endif // test1
#if test2
//2,独立输入,输出
si.dwFlags = 0;
StringCchPrintf(pszExe, MAX_PATH, _T("%s%s"), pszAppPath, _T("SubConsole.exe"));
CreateProcess(pszExe, pszExe, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, pszAppPath, &si, &pi);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
#endif // test2
#if test3
//3,分离进程(注意子进程内部需要调用一下AllocConsole,但本例中没这么做,所以会不正常
si.dwFlags = 0;
StringCchPrintf(pszExe, MAX_PATH, _T("%s%s"), pszAppPath, _T("SubConsole.exe"));
CreateProcess(pszExe, pszExe, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, pszAppPath, &si, &pi);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
#endif // test3
#if test4
//4,重定向输入,输出到文件
sa.bInheritHandle = TRUE;//设置子进程句柄可继承
si.dwFlags = STARTF_USESTDHANDLES;
StringCchPrintf(pszExe, MAX_PATH, _T("%s%s"), pszAppPath, _T("Output.txt"));
HANDLE hOutput = CreateFile(pszExe, GENERIC_WRITE, 0, &sa, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
//Input.txt文件要提前创建
StringCchPrintf(pszExe, MAX_PATH, _T("%s%s"), pszAppPath, _T("Input.txt"));
HANDLE hInput = CreateFile(pszExe, GENERIC_READ, 0, &sa, OPEN_EXISTING, 0, NULL);
si.hStdOutPut = hOutput;
si.hStdInput = hInput;
//子进程创建后,会讲Input.txt的作为输入设备,将Output.txt作为商人处设备
//有因子进程代码中要读入数据(从Input.txt中),并输出(从定向到Output.txt)
StringCchPrintf(pszExe, MAX_PATH, _T("%s%s"), pszAppPath, _T("SubConsole.exe"));
CreateProcess(pszExe, pszExe, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, pszAppPath, &si, &pi);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(hOutput);
CloseHandle(hInput);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
#endif // test4
#if 1
//重定向到管道,接受ping命令的输出
GRS_USEPRINTFA();
StringCchPrintf(pszExe, MAX_PATH, _T("PING www.baidu.com"));
BYTE pBuffer[1024] = {};//缓存
DWORD dwLen = 0;
HANDLE hRead1, hWrite1;//管道读写句柄
BOOL bRet;
sa.bInheritHandle = TRUE;
//创建匿名管道,管道句柄是可被继承的
bRet = CreatePipe(&hRead1, &hWrite1, &sa, 1024);
if (!bRet)
{
GRS_PRINTF(_T("管道创建失败,Error Code:%d\n"), GetLastError());
_tsystem(_T("PAUSE"));
return 0;
}
/**/
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;//隐藏子进程窗口
si.hStdOutput = hWrite1;//将子进程的输出输入通道
//创建子进程,ping命令,子进程是可继承的
CreateProcess(NULL, pszExe, NULL, NULL, TRUE,
DETACHED_PROCESS, NULL, pszAppPath, &si, &pi);
//管道句柄已被继承,本地则可关闭,否则管道内核对象没有释放,
// 之后的读管道操作人会一直等待管道吸入数据
// HANDLE pHandle = GetCurrentProcess();//0xfffffff
// HANDLE tHandle = GetCurrentThread();//0xfffffffe
//党ping指向完毕,已经没有数据写入,就会因ReadFile读不到数据,而进程阻塞
CloseHandle(hWrite1);
printf("执行子进程:运行ping命令!\r\n");
//读管道知道管道关闭
dwLen = 1000;
DWORD dwRead = 0;
while (ReadFile(hRead1,pBuffer,dwLen,&dwRead,NULL))
{
if (0 == dwRead)
{
break;
}
GRS_PRINTFA("%s\n", pBuffer);
ZeroMemory(pBuffer, 1024);
}
GRS_PRINTF(_T("Read Completion!\n\n"));
CloseHandle(hRead1);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
#endif // 0
_tsystem(_T("PAUSE"));
return 0;
}