在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函数能执行,其他两种方式都不能的,为什么呢??