C++ CMD异常处理C/C++;
我将在程序中使用一些CMD命令,这些命令可能会引发一些异常。正如您所知,当出现异常时,CMD会在屏幕上写入自己的错误消息。但是,我想写我自己的错误消息 我的问题是:有没有办法阻止CMD消息并只写我自己的错误消息 另外,这不是一个复杂的程序。它使用System()执行CMD命令 例如: 比方说,用户可以重命名和复制程序中的任何文件。如您所知,如果用户没有正确输入文件的路径,屏幕上将显示一条错误消息。我希望这个错误消息永远不会出现在屏幕上。只显示我自己的错误消息C++ CMD异常处理C/C++;,c++,c,exception-handling,cmd,C++,C,Exception Handling,Cmd,我将在程序中使用一些CMD命令,这些命令可能会引发一些异常。正如您所知,当出现异常时,CMD会在屏幕上写入自己的错误消息。但是,我想写我自己的错误消息 我的问题是:有没有办法阻止CMD消息并只写我自己的错误消息 另外,这不是一个复杂的程序。它使用System()执行CMD命令 例如: 比方说,用户可以重命名和复制程序中的任何文件。如您所知,如果用户没有正确输入文件的路径,屏幕上将显示一条错误消息。我希望这个错误消息永远不会出现在屏幕上。只显示我自己的错误消息 谢谢大家! 一种蛮力方法是通过管道将
谢谢大家! 一种蛮力方法是通过管道将CMD的输出,即
yourCommand>file.txt
传输到一个文件,然后读取文件内容以确定是否存在异常。您可以使用
#include "Exception.h"
class MyClass
{
public:
class Error : public Exception { };
MyClass();
~MyClass();
void myFunction() throw(Error);
}
catch(MyClass::Error&Error)
{
cout这取决于您的平台和您将要使用的命令。顺便说一句,大多数人强烈反对使用for调用控制台命令(对于大多数目的来说,这是一种沉重的方式)。
我建议您使用带有CREATE\u NO\u窗口标志的CreateProcess()
,并通过调用WaitForSingleObject()
和GetExitCodeProcess()
等待进程退出
这种方法利用了一个事实,即大多数CMD命令都是可执行的,位于C:/Windows/…
中的某个位置
/*
* Executes a program and returns it's exit code.
*
* TODO: Error checking should be added for
* CreateProcess()
* WaitForSingleObject()
* GetExitCodeProcess()
*/
DWORD ExecCmdLine(TCHAR const* cmdline)
{
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
memset(&pi, 0, sizeof(pi));
::CreateProcess(NULL, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
::CloseHandle(pi.Thread);
::WaitForSingleObject(pi.hProcess, INFINITE);
DWORD exitcode;
::GetExitCodeProcess(pi.hProcess, &exitcode);
::CloseHandle(pi.hProcess);
return exitcode;
}
如果要检索命令的输出,还可以在STARTUPINFO
结构中提供hStdOutput
,hStdError
,并在STARTUPINFO.dwFlags
中设置STARTF\u USESTDHANDLES
。
在命令执行时,你甚至可以在自己的程序中做其他事情(特别是你提到的文件拷贝)。这一个是用C++方式完成的:
/*
* TODO: Error checking should be added for
* CreateProcess()
* WaitForSingleObject()
* GetExitCodeProcess()
*/
class AsyncCmd
{
public:
AsyncCmd(std::string const& cmdline)
: cmdline(cmdline),
processHandle(NULL)
{
}
~AsyncCmd()
{
if (this->processHandle != NULL)
::CloseHandle(this->processHandle);
}
// Starts the execution of the commandline.
void Start(HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE), HANDLE hErr = GetStdHandle(STD_ERROR_HANDLE))
{
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si.hStdOutput = hOut;
si.hStdError = hErr;
PROCESS_INFORMATION pi;
memset(&pi, 0, sizeof(pi));
::CreateProcess(NULL, this->cmdline.c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
::CloseHandle(pi.hThread);
this->processHandle = pi.hProcess;
}
// Blocks until execution is finished and returns the exit code.
DWORD ExitCode()
{
::WaitForSingleObject(this->processHandle, INFINITE);
DWORD exitcode;
::GetExitCodeProcess(this->processHandle, &exitcode);
return exitcode;
}
private:
AsyncCmd(AsyncCmd const&);
AsyncCmd& operator=(AsyncCmd const&);
std::string cmdline;
HANDLE processHandle;
}
除了编写的内容之外,我想指出,异常不会跨越进程边界。因此,这里要处理的是已执行程序(和shell)的输出(包括stderr
和stdout
)及其退出代码(如果这提供了任何有用的信息)。这主要是为了让您理解,这并不是您的标题所暗示的异常处理
这意味着您可以在使用CreateProcess
/CreateProcessEx
时设置hStdOutput
和hStdError
以使用您控制的管道以及“捕获”的位置在将输出输出到控制台之前,将其替换为您自己的输出。如果您只想替换stderr,也可以这样做。要重新表述已经说过的内容:
问:您是否能够以某种方式拦截通过“system()”调用的命令引发的错误
答:没有,原因很多
但是您可以重定向由命令行程序编写的文本错误消息:
- 重定向“stderr”相对容易。“GetStdHandle(STD_ERROR_HANDLE)”是一种方法。重定向到“>:err”是另一种方法
- 不幸的是,并不是所有的程序都能将错误消息写入“stderr”
许多人把所有的东西都写在“标准输出”上
在后一种情况下,您必须找出1)实际发生了错误,2)找出如何将文本输入中的“标准输出”部分与“错误文本”部分分开
附言:
“system()”的另一个API是“popen()”你能说得更具体一点吗?我假设你正在编写一个控制台应用程序?通过CMD你指的是Windows命令行?错误通常写入到stderr/cerr,用你自己的流替换该流(如何替换取决于你使用的操作系统)或将所有内容重定向到一个文件(你将解析)。这与处理从cmd.exe打印到stdout的错误消息无关。我认为应该补充一点,管道是hStdOutput
和hStdError
的良好“死胡同”,因为s(he)想抑制执行程序的输出。哇!这很酷,但是对我来说有点先进…所以,我想知道你能建议一个教程还是一个C++主题,这是必须学习的,这使得代码对我来说是可以理解的?我真的很想提高我的C++技能和能力。但是,对于C++,我通常都喜欢,特别是面向对象编程部分。我有C++的一般知识,没有问题。但是,我不能理解你写的代码行……我想,只有了解它们的方法才能学习Windows API,对吗?真的不必“学习”它,但您可以检查MSDN中您不知道的API调用:,实际上,只有当且仅当命令行中显式使用cmd.exe
作为shell时,这才有效,因为您尝试在此处使用shell重定向。此外,2>
还可以用于重定向stderr
,而不仅仅是stdout
和NUL
可以类似于unixoid系统上的/dev/null
来抑制输出。为了完整性,您可以通过在命令前面加上%COMSPEC%/c
和cmd.exe
来强制使用cmd.exe
支持,而不仅仅是stdin
、stdout
和stderr
。我将把这一点保留下来,只是为了历史记录,但是@yourmt的答案显然是最好的。用他的。
/*
* Executes a program and returns it's exit code.
*
* TODO: Error checking should be added for
* CreateProcess()
* WaitForSingleObject()
* GetExitCodeProcess()
*/
DWORD ExecCmdLine(TCHAR const* cmdline)
{
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
memset(&pi, 0, sizeof(pi));
::CreateProcess(NULL, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
::CloseHandle(pi.Thread);
::WaitForSingleObject(pi.hProcess, INFINITE);
DWORD exitcode;
::GetExitCodeProcess(pi.hProcess, &exitcode);
::CloseHandle(pi.hProcess);
return exitcode;
}
/*
* TODO: Error checking should be added for
* CreateProcess()
* WaitForSingleObject()
* GetExitCodeProcess()
*/
class AsyncCmd
{
public:
AsyncCmd(std::string const& cmdline)
: cmdline(cmdline),
processHandle(NULL)
{
}
~AsyncCmd()
{
if (this->processHandle != NULL)
::CloseHandle(this->processHandle);
}
// Starts the execution of the commandline.
void Start(HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE), HANDLE hErr = GetStdHandle(STD_ERROR_HANDLE))
{
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si.hStdOutput = hOut;
si.hStdError = hErr;
PROCESS_INFORMATION pi;
memset(&pi, 0, sizeof(pi));
::CreateProcess(NULL, this->cmdline.c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
::CloseHandle(pi.hThread);
this->processHandle = pi.hProcess;
}
// Blocks until execution is finished and returns the exit code.
DWORD ExitCode()
{
::WaitForSingleObject(this->processHandle, INFINITE);
DWORD exitcode;
::GetExitCodeProcess(this->processHandle, &exitcode);
return exitcode;
}
private:
AsyncCmd(AsyncCmd const&);
AsyncCmd& operator=(AsyncCmd const&);
std::string cmdline;
HANDLE processHandle;
}