Please visit our SourceForge product page.
The purpose of this article is to show how to run CMD commands from any application regardless of its type (MFC, Win32, Console), wait for the results and view them using your own user interface.
As part of our daily work at Secured Globe, Inc., we run pre-made programs. All they do is execute a series of CMD commands programmatically while responding to the result. That brought up the idea to build a generic tool for that purpose.
The "How To"
First, we define 3 global variables to store the state of the command's asynchronized processing.
Command - the command you would have typed in CMD
CommandResult - the result you would have seen on screen when execution is completed
IsRunning - indicates whether the command is still being processed. To test a command that takes longer to process, try typing "
CString Command, CommandResult;
BOOL IsRunning = FALSE;
The DoRun() Function
The actual place where we compose the
string sent to ShellExecute() is
Good to know: you may prefer to use ShellExecuteEx() or CreateProcess().
DoRun() function first deletes any old version of result.txt and then properly sends the command.
BOOL DoRun(WCHAR *command)
BOOL Result = FALSE;
LPTSTR pTemp = NULL;
TCHAR Command[BUFSIZE] = L"";
_tcscpy_s(Command, L"/C ");
_tcscat_s(Command, L" >");
Result = (BOOL) ShellExecute(GetActiveWindow(), L"OPEN", L"cmd", Command, NULL, 0L);
retSize = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
The SetCommand Function
SetCommand function is used to initiate a new command via its own thread.
void SetCommand(CString command)
Command = command;
HANDLE hThread = (HANDLE)_beginthread(ThreadFunc, 0, NULL);
Then the thread function itself goes as follows:
void __cdecl ThreadFunc(void*)
CommandResult = L"";
IsRunning = TRUE;
IsRunning = FALSE;
CheckCommandResult() goes like that:
CommandResult = GetResultFromFile();
if (CommandResult != L"")
Getting the Results
Upon completion of the command's execution, we expect to have the results in a .txt file created and reused. The file name is "result.txt".
GetResultFromFile() function reads this file and returns a
CString with the result.
The commented part can be used for cases where the file can't be opened, however since that isn't expected to happen, I have commented that part.
CString strResult = L"";
fp = NULL;
_wfopen_s(&fp, RESULTS_FILE, L"rb");
std::fseek(fp, 0, SEEK_END);
std::fread(&contents, 1, contents.size(), fp);
CString temp1 = (CString)(CStringA)(contents.c_str());
if (temp1 == L"") temp1 = L"Unknown command";
strResult = temp1;
Thanks should be given to the author of EASY-SIZE, Marc Richarme. EASY-SIZE can be easily used to support resizing controls within a Dialog box whenever the Dialog is resized.
As a result, the dialog may originally look like this:
and then if resized, like this:
I wanted the text to be clear and large enough. I selected Courier, 140 points.
First, we define
m_font as a member variable:
Then, as part of
OnInitDialog, we call:
Then, to assign this font to a specific control (in our case, our Command and Command result, we use the following code:
To set a clear yellow on black text, we use SetTextColor() and SetBkColor(). We add the following calls to
if(ID == IDC_CMD_RESULT || ID == IDC_COMMAND)
It is always best to define constants separately, and in most cases, reuse them again without having to type their values. In this case, I defined the font name, along with the yellow and black colors in the header file.
#define FONT_NAME _T("Courier")
#define COLOR_BLACK RGB(0, 0, 0)
#define COLOR_YELLOW RGB(204, 204, 0)
To make it easy to operate, and to be consistent with the way
CMD is used, the following keyboard keys are supported:
- <ENTER> - executes a command
- <Up / Down arrow keys> - switch among previous commands given
Bug Fixed and Proofing
Thanks to evlncrn8 for finding a memory leak. and proofing... :)
- 1st August, 2019: Initial version