博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++ 调用cmd的几种方法
阅读量:2242 次
发布时间:2019-05-09

本文共 5537 字,大约阅读时间需要 18 分钟。

文章目录

调用cmd来执行响应的命令,windows实际上也给了一些接口,但是有些在执行某些命令的时候,却不能够执行,比如 winsat。

system

这个命令使用 VS 的同学一定不陌生

当我们想要执行某个命令或打开某个程序时

system("calc");

注:该函数是阻塞的

WinExec

WinExec("ipconfig", SW_SHOWNORMAL); //第二个参数表示显示cmd命令框

注:该函数是非阻塞的,也就是说,当输入的命令需要长时间来执行时,程序并不会等待执行结果,而是直接往下运行

ShellExecute

上述两种执行cmd的方法比较少用。

先看这个这个函数原型,共有六个参数

HINSTANCE ShellExecuteA(  HWND   hwnd,          //指定父窗口,一般为NULL  LPCSTR lpOperation,   //打开方式  LPCSTR lpFile,        //要打开的文件,要执行的程序  LPCSTR lpParameters,  //参数  LPCSTR lpDirectory,   //缺省目录,一般为NULL  INT    nShowCmd       //命令框打开方式);

各个参数含义:

HWND hwnd 指定父窗口句柄(通常为NULL)
LPCSTR lpOperation 指定动作,表示打开Filename的方式:
     open     正常打开
     runas    以管理员身份打开
     print     打印Filename指定的文件
     explore   表示浏览由FileName参数指定的文件夹
     find      从lpDirectory指定的目录开始搜索
     edit      启动编辑器并打开文档进行编辑
LPCSTR lpFile, 表示要打开的文件,比如cmd.exe,calc(计算器)
LPCSTR lpParameters, 打开程序所执行的参数
LPCSTR lpDirectory, 缺省目录,一般为NULL
INT nShowCmd 命令框打开方式
    SW_HIDE(0)隐藏窗口并激活另一个窗口。
    SW_MAXIMIZE(3)最大化指定的窗口。
    SW_MINIMIZE(6)最小化指定的窗口并激活z顺序中的下一个顶级窗口。
    SW_RESTORE(9)激活并显示窗口。如果窗口最小化或最大化,Windows会将其恢复到原始大小和位置。应用程序应在还原最小化窗口时指定此标志。
    SW_SHOW(5)激活窗口并以当前大小和位置显示它。
    SW_SHOWDEFAULT(10)根据启动应用程序的程序传递给CreateProcess函数的STARTUPINFO结构中指定的SW_标志设置show状态。应用程序应该使用此标志调用ShowWindow来设置其主窗口的初始显示状态。
    SW_SHOWMAXIMIZED(3)激活窗口并将其显示为最大化窗口。
    SW_SHOWMINIMIZED(2)激活窗口并将其显示为最小化窗口。
    SW_SHOWMINNOACTIVE(7)将窗口显示为最小化窗口。活动窗口保持活动状态。
    SW_SHOWNA(8)以当前状态显示窗口。活动窗口保持活动状态。
    SW_SHOWNOACTIVATE(4)显示最近大小和位置的窗口。活动窗口保持活动状态。
    SW_SHOWNORMAL(1)激活并显示一个窗口。如果窗口最小化或最大化,Windows会将其恢复到原始大小和位置。应用程序应在首次显示窗口时指定此标志。

最常用的几个:SW_SHOWNORMAL(正常显示)、SW_HIDE(隐藏)

例子:

ShellExecute(NULL, "runas", "cmd", "/c ipconfig >> D:\\disk.txt", NULL, SW_SHOWNORMAL);

含义:以管理员身份运行cmd,执行ipconfg命令,将输出重定向到C:\disk.txt中,命令框正常显示

注:和WinExec一样,该函数也是非阻塞的

阻塞式调用ShellExecute

SHELLEXECUTEINFO ShExecInfo = {
0 }; ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; ShExecInfo.hwnd = NULL; ShExecInfo.lpVerb = "runas"; ShExecInfo.lpFile = "cmd"; ShExecInfo.lpParameters = "/c winsat disk >> D:\\disk.txt"; ShExecInfo.lpDirectory = NULL; ShExecInfo.nShow = SW_HIDE; ShExecInfo.hInstApp = NULL; ShellExecuteEx(&ShExecInfo); WaitForSingleObject(ShExecInfo.hProcess, INFINITE);

每个参数的含义和ShellExecute都一样。其中上述命令参数中 /c:

  • /c 是执行完命令后关闭命令窗口。
  • /k 是执行完命令后不关闭命令窗口。

但上述方法却不是万能的,有些命令在cmd中可以执行,但如果按照上述方法打开cmd就不能执行,比如 winsat,会出现winsat不是内部命令或可执行文件 的错误。那是因为应用程序发生了重定向

使用CreatProcess(最好使用这个)

bool RunCmdAndOutPutRedirect(const std::string &outPutFile, const std::string &cmd, bool wait = false){
cout<< "outPutFile:" << outPutFile << " cmd:" << cmd << " wait:" << wait; STARTUPINFOA si; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; HANDLE handle = CreateFileA(outPutFile.c_str(), FILE_APPEND_DATA, FILE_SHARE_WRITE | FILE_SHARE_READ, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (!handle) {
cout << "CreateFile failed:" << GetLastError(); return false; } memset(&si, 0, sizeof(STARTUPINFO)); memset(&pi, 0, sizeof(PROCESS_INFORMATION)); si.cb = sizeof(STARTUPINFO); si.dwFlags |= STARTF_USESTDHANDLES; si.wShowWindow = SW_HIDE; si.hStdInput = NULL; si.hStdError = NULL; si.hStdOutput = handle; if (!CreateProcessA(NULL, (LPSTR)cmd.c_str(), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
cout << "CreateProcess failed:" << GetLastError(); return false; } if (wait) {
WaitForSingleObject(pi.hProcess, INFINITE); } cout << "WaitForSingleObject finish return:" << GetLastError(); CloseHandle(handle); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); return true;}void Task(){
PVOID oldValue = NULL; if (Wow64DisableWow64FsRedirection(&oldValue)) {
string filePath = "D:\\diak.txt"; string cmd = "winsat disk"; RunCmdAndOutPutRedirect(filePath, cmd, true); //true表示阻塞调用 } else {
LOG_WARN << "重定向失败:" << GetLastError(); } if (Wow64RevertWow64FsRedirection(oldValue) == FALSE) {
return; }}

如何调用winsat(解决应用程序重定向问题)

需要调用windows的两个函数:Wow64DisableWow64FsRedirection() Wow64RevertWow64FsRedirection()

PVOID oldValue = NULL;    if (Wow64DisableWow64FsRedirection(&oldValue))    {
//ShellExecute(NULL, "runas", "cmd", "/c winsat disk >> D:\\disk.txt", NULL, SW_SHOWNORMAL); //执行cmd命令 SHELLEXECUTEINFO ShExecInfo = {
0 }; ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; ShExecInfo.hwnd = NULL; ShExecInfo.lpVerb = "runas"; ShExecInfo.lpFile = "cmd"; ShExecInfo.lpParameters = "/k winsat disk >> D:\\disk.txt"; ShExecInfo.lpDirectory = NULL; ShExecInfo.nShow = SW_HIDE; ShExecInfo.hInstApp = NULL; ShellExecuteEx(&ShExecInfo); WaitForSingleObject(ShExecInfo.hProcess, INFINITE); } if (Wow64RevertWow64FsRedirection(oldValue) == FALSE) {
return; }

就很好的解决了重定向的问题。

Wow64DisableWow64FsRedirection() 主要是为了关闭重定向
Wow64RevertWow64FsRedirection() 主要是为了恢复重定向
这两个函数一定要成对出现,关闭完成任务后一定要记得恢复。要不然会对其他的产生一定的影响。

任务计划程序

实际上,调用cmd还有另外一种方法,就是使用任务计划程序。这种方法也可以解决上面重定向的问题,但使用起来会比较麻烦一些。

转载地址:http://pcwdb.baihongyu.com/

你可能感兴趣的文章
为什么需要 Mini-batch 梯度下降,及 TensorFlow 应用举例
查看>>
为什么在优化算法中使用指数加权平均
查看>>
初探Java设计模式5:一文了解Spring涉及到的9种设计模式
查看>>
Java集合详解1:一文读懂ArrayList,Vector与Stack使用方法和实现原理
查看>>
Java集合详解2:一文读懂Queue和LinkedList
查看>>
Java集合详解3:一文读懂Iterator,fail-fast机制与比较器
查看>>
Java集合详解4:一文读懂HashMap和HashTable的区别以及常见面试题
查看>>
Java集合详解5:深入理解LinkedHashMap和LRU缓存
查看>>
Java集合详解6:这次,从头到尾带你解读Java中的红黑树
查看>>
Java集合详解8:Java集合类细节精讲,细节决定成败
查看>>
Java并发指南2:深入理解Java内存模型JMM
查看>>
Java并发指南5:JMM中的final关键字解析
查看>>
Java并发指南6:Java内存模型JMM总结
查看>>
Java并发指南7:JUC的核心类AQS详解
查看>>
Java并发指南8:AQS中的公平锁与非公平锁,Condtion
查看>>
Java网络编程和NIO详解6:Linux epoll实现原理详解
查看>>
Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理
查看>>
Java网络编程与NIO详解8:浅析mmap和Direct Buffer
查看>>
Java网络编程与NIO详解10:深度解读Tomcat中的NIO模型
查看>>
Java网络编程与NIO详解11:Tomcat中的Connector源码分析(NIO)
查看>>