Reputation: 735
I will use some CMD commands in my program and these commands might throw some exceptions. And as you know, when an exception accours, CMD writes its own error message the screen. But, I want to write my own error message.
My question is this: Is there a way to block CMD messages and write only my own error messages?
P.S. This is not a complex program. It executes CMD commands using System().
Example:
Let's say, the user can rename and copy any files in the program. As you know, if the user does not enter file's path properly, an error message is showed on the screen. And I want that this error message never appears on the screen. Only my own error message is showed.
Thank you!
Upvotes: 1
Views: 2089
Reputation: 3478
It depends on your platform and the commands you are going to use. The usage of system()
for calling console commands is by the way strongly discouraged by most people (it's way to heavy for most purposes).
I would suggest to you using CreateProcess()
with the CREATE_NO_WINDOW flag and waiting for the process to exit with a call to WaitForSingleObject()
and GetExitCodeProcess()
.
This approach utilizes the fact, that most CMD command are executables, located somewhere in 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;
}
If you want to retrieve the output of the command you could also provide hStdOutput
, hStdError
in the STARTUPINFO
structure and set STARTF_USESTDHANDLES
in STARTUPINFO.dwFlags
.
You can even do other things in your own program while the command is executing (especially as you mentioned file copy). This one is done the C++ way:
/*
* 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;
}
Upvotes: 3
Reputation: 121881
To rephrase what's already been said:
Q: Can you somehow intercept an error thrown by a command you've invoked via "system()"?
A: No. For many reasons.
But you can redirect the textual error message that's written by the command line program:
Redirecting "stderr" is relatively easy. "GetStdHandle(STD_ERROR_HANDLE)" is one way. Redirecting to "> :err" is another.
Unfortunately, not all programs are nice enough to write error messages to "stderr".
Many write everything to "stdout".
In the latter case, you'd have to figure out 1) that an error actually occurred, and 2) figure out how to separate the parts of the text input that are "standard output", vs those parts that are "error text".
PS:
An alternative API to "system()" is "popen()".
Upvotes: 1
Reputation: 21369
Adding to what yourmt wrote, I'd like to point out that exceptions won't bleed through across process boundaries. So what you are tackling here is the output (both stderr
and stdout
) of the executed program (and shell) plus its exit code (in case this provides any useful information). This is mostly so you understand that this is literally not about exception handling as your title implies.
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.
Upvotes: 0
Reputation: 563
You can use
#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;
}
and
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);
}
Upvotes: -1
Reputation: 8206
One brute force way to do it would be to pipe the output of the CMD i.e. yourCommand > file.txt
to a file and then read the file contents to determine if there was an exception.
Upvotes: 0