1

我将在我的程序中使用一些 CMD 命令,这些命令可能会引发一些异常。如您所知,当出现异常时,CMD 会在屏幕上写入自己的错误消息。但是,我想写我自己的错误信息。

我的问题是:有没有办法阻止 CMD 消息并只写我自己的错误消息?

PS 这不是一个复杂的程序。它使用 System() 执行 CMD 命令。

例子:

假设用户可以重命名和复制程序中的任何文件。如您所知,如果用户没有正确输入文件路径,屏幕上会显示一条错误消息。我希望这个错误消息永远不会出现在屏幕上。只显示我自己的错误消息。

谢谢!

4

5 回答 5

3

这取决于您的平台和您要使用的命令。顺便说一句,大多数人强烈不鼓励使用system()for 调用控制台命令(对于大多数目的来说,这太重了)。
我建议您使用CreateProcess()CREATE_NO_WINDOW 标志并等待进程退出并调用WaitForSingleObject()and 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;
}

如果您想检索命令的输出,您还可以hStdOutputhStdError结构STARTUPINFO和集合中提供STARTF_USESTDHANDLESSTARTUPINFO.dwFlags. 您甚至可以在执行命令时在自己的程序中执行其他操作(尤其是在您提到文件复制时)。这是通过 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;
}
于 2012-11-16T22:56:42.713 回答
1

重新表述已经说过的话:

问:你能以某种方式拦截你通过“system()”调用的命令引发的错误吗?

答:没有。有很多原因。

但是您可以重定向由命令行程序编写的文本错误消息:

  • 重定向“stderr”相对容易。“GetStdHandle(STD_ERROR_HANDLE)”是一种方法。重定向到 "> :err" 是另一个。

  • 不幸的是,并非所有程序都可以很好地将错误消息写入“stderr”。

    许多人将所有内容都写入“stdout”。

在后一种情况下,您必须弄清楚 1) 实际发生了错误,以及 2) 弄清楚如何将文本输入的“标准输出”部分与“错误文本”部分分开.

PS:

“system()”的替代 API 是“popen()”。

于 2012-11-16T23:48:35.073 回答
0

除了你的内容之外,我想指出异常不会跨越进程边界。所以你在这里处理的是输出(两者stderrstdout)加上它的退出代码(如果这提供了任何有用的信息)。这主要是为了让您了解这实际上与您的标题所暗示的异常处理无关。

That means you can set hStdOutput and hStdError when using CreateProcess/CreateProcessEx to use pipes that you control and where you "catch" the output and then replace it with your own before outputting it to the console. In case you want to only replace stderr you can also do that.

于 2012-11-16T23:42:59.057 回答
0

一种蛮力的方法是通过管道将 CMD 的输出即yourCommand > file.txt传输到文件,然后读取文件内容以确定是否存在异常。

于 2012-11-16T22:40:41.327 回答
-1

您可以使用

#include "Exception.h"

class MyClass
{
public:
    class Error : public Exception { };
    MyClass();
    ~MyClass();
    void myFunction() throw(Error);
}

...

catch (MyClass::Error & error)
{
    cout << error.full_message << endl;

    return;
}

class Exception
{
public:
    std::string message;
    std::string full_message;

    virtual char * info() { return ""; };

    void setMessage(std::string msg)
    {
        message = msg;
        if (*info() == 0) { full_message = msg; }
        else { full_message = MakeString() << info() << " " << msg; }
    }
};

// template function ///////////////////////////////////////////

template <class errType>
void Throw(const std::string msg=std::string(""))
{
errType err;
err.setMessage(msg);

throw(err);
}
于 2012-11-16T22:47:51.163 回答