本文共 5537 字,大约阅读时间需要 18 分钟。
这个命令使用 VS 的同学一定不陌生
当我们想要执行某个命令或打开某个程序时system("calc");
注:该函数是阻塞的
WinExec("ipconfig", SW_SHOWNORMAL); //第二个参数表示显示cmd命令框
注:该函数是非阻塞的,也就是说,当输入的命令需要长时间来执行时,程序并不会等待执行结果,而是直接往下运行
上述两种执行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一样,该函数也是非阻塞的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:
但上述方法却不是万能的,有些命令在cmd中可以执行,但如果按照上述方法打开cmd就不能执行,比如 winsat,会出现winsat不是内部命令或可执行文件 的错误。那是因为应用程序发生了重定向
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; }}
需要调用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/