在Win下通过代码调用CMD执行批处理不是什么新技术了,主要是有一下三种方式,这里粗略提下.我实现过C版 C++版,汇编版,AS版的调用执行批处理命令.下面是C++版本的做法:
直接调用函数system
最简单的方式可如下调用system函数执行命令
system("echo Hello CMD");
缺点:会显示CMG控制台窗口,无回显数据,优点:简单直接
使用ShellExecuteEx
其次简单的方式是使用ShellExecuteEx函数
SHELLEXECUTEINFO sei; memset(&sei, 0, sizeof(SHELLEXECUTEINFO)); sei.cbSize = sizeof(SHELLEXECUTEINFO); sei.fMask = SEE_MASK_NOCLOSEPROCESS; sei.lpVerb = _T("open"); sei.lpFile = _T(strToolName); sei.lpParameters = "echo Hello CMD"; // SW_HIDE SW_SHOWNORMAL 参数决定是否显示控制台 sei.nShow = SW_HIDE;//; SW_SHOWNORMAL ShellExecuteEx(&sei); // 等待进程结束再往下执行 WaitForSingleObject(sei.hProcess, INFINITE); CloseHandle(sei.hProcess);
缺点:无回显数据,优点:可隐藏控制台
通过创建进程与管道调用
这种方式被我用得最多.启动函数如下
SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; // 创建管道用于读取回显数据 if(!CreatePipe(&pThis->m_hRead,&pThis->m_hWrite,&sa,0)) { ShowMsgBox("CreatePipe Failed"); return true; } STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si,sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); GetStartupInfo(&si); si.hStdError = pThis->m_hWrite; si.hStdOutput = pThis->m_hWrite; si.wShowWindow = SW_HIDE; si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; CString tmp; tmp.Format(_T("Cmd.exe /C %s"),"echo Hello CMD"); char cmdline[2000]; memset(cmdline,0,2000); sprintf(cmdline,"%s",tmp); // DEBUG_PROCESS CREATE_NEW_CONSOLE // 创建进程用于启动CMD if(!CreateProcess(NULL,cmdline,NULL,NULL,TRUE,CREATE_NO_WINDOW,NULL,NULL,&si,&pi)) { ShowMsgBox("CreateProcess failed!"); return true; } // 等待执行结束 WaitForSingleObject(pi.hProcess,INFINITE); CloseHandle(pThis->m_hWrite);
读取执行命令后的返回数据也很简单
char buffer[4096] = {0}; CString strOutput; DWORD bytesRead; while(TRUE) { Sleep(1000); memset(buffer,0,4096); if(NULL == ReadFile(pThis->m_hRead,buffer,4095,&bytesRead,NULL)) { break; } printf(buffer); }
优点:有数据回显,缺点:略复杂.
存在的问题
在我最近一次使用代码调用批处理的时候发现几个问题,至今无法找到原因,有几个老外也发现了同样的问题,但是都没找到原因,只有替代的解决方案.我把问题记录在这里.
- 创建进程的方式,无法使用xcopy
使用创建进程的方式启动CMD,无法执行与xcopy有关的所有命令.我最后是用ShellExecute去执行的xcopy,但是为什么创建进程就无法执行呢??诡异啊~
- ShellExecute与创建进程的方式 都无法使用for
例如for /r Rect %a in (*.cpp) do (del %a)\r\n
,删除Rect文件夹下的所有.cpp文件,这个命令只有system函数能执行,其他两种方式都不能的,为什么呢??