调用CMD遇到的诡异问题

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

发表评论

邮箱地址不会被公开。 必填项已用*标注