我是靠谱客的博主 傻傻钢笔,最近开发中收集的这篇文章主要介绍C++ 调用cmd的几种方法,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

    • system
    • WinExec
    • ShellExecute
    • 阻塞式调用ShellExecute
    • 使用CreatProcess(最好使用这个)
    • 如何调用winsat(解决应用程序重定向问题)
    • 任务计划程序

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

最后

以上就是傻傻钢笔为你收集整理的C++ 调用cmd的几种方法的全部内容,希望文章能够帮你解决C++ 调用cmd的几种方法所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(56)

评论列表共有 0 条评论

立即
投稿
返回
顶部