在日常工作中,经常需要执行一些预先编写好的程序,这些程序的主要任务是程序化地执行一系列CMD命令,并根据结果进行响应。这启发了构建一个通用工具来实现这一目的。
在Secured Globe, Inc.的日常工作中,经常需要执行一些预先编写好的程序。这些程序的主要任务是程序化地执行一系列CMD命令,并根据结果进行响应。这启发了构建一个通用工具来实现这一目的。
首先,定义了三个全局变量来存储命令的异步处理状态。
命令 - 在CMD中输入的命令
命令结果 - 执行完成后在屏幕上看到的结果
正在运行 - 表示命令是否仍在处理中。要测试一个需要更长时间处理的命令,可以尝试输入"netstat
"。
C++代码示例:
CString Command, CommandResult;
BOOL IsRunning = FALSE;
DoRun()函数是实际发送命令的地方。
值得注意的是,可能会更喜欢使用ShellExecuteEx()或CreateProcess()。
DoRun()函数首先删除任何旧版本的result.txt,然后正确地发送命令。
C++代码示例:
BOOL DoRun(WCHAR *command) {
BOOL Result = FALSE;
DWORD retSize;
LPTSTR pTemp = NULL;
TCHAR Command[BUFSIZE] = L"";
if (!(DeleteFile(RESULTS_FILE))) {
//return L"Can't delete previous results";
}
_tcscpy_s(Command, L"/C ");
_tcscat_s(Command, command);
_tcscat_s(Command, L">");
_tcscat_s(Command, RESULTS_FILE);
wprintf(L"Calling:\n%s\n", Command);
Result = (BOOL) ShellExecute(GetActiveWindow(), L"OPEN", L"cmd", Command, NULL, 0L);
if (!Result) {
retSize = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, GetLastError(), LANG_NEUTRAL, (LPTSTR)&pTemp, 0, NULL);
MessageBox(NULL, pTemp, L"Error", MB_OK);
}
return Result;
}
SetCommand函数用于通过自己的线程启动新命令。
C++代码示例:
void SetCommand(CString command) {
Command = command;
HANDLE hThread = (HANDLE)_beginthread(ThreadFunc, 0, NULL);
}
然后线程函数本身如下:
void __cdecl ThreadFunc(void *) {
CommandResult = L"";
if (DoRun(Command.GetBuffer())) {
IsRunning = TRUE;
while (IsRunning) {
if (CheckCommandExecutionStatus()) {
break;
}
}
}
IsRunning = FALSE;
_endthreadex(0);
}
CheckCommandResult()如下:
bool CheckCommandExecutionStatus() {
CommandResult = GetResultFromFile();
if (CommandResult != L"") return true;
else return false;
}
命令执行完成后,期望在创建并重用的.txt文件中获得结果。文件名为"result.txt"。
GetResultFromFile()函数读取此文件并返回一个包含结果的CString。
C++代码示例:
CString GetResultFromFile() {
CString strResult = L"";
std::FILE *fp;
fp = NULL;
_wfopen_s(&fp, RESULTS_FILE, L"rb");
if (fp) {
std::string contents;
std::fseek(fp, 0, SEEK_END);
contents.resize(std::ftell(fp));
std::rewind(fp);
std::fread(&contents[0], 1, contents.size(), fp);
std::fclose(fp);
CString temp1 = (CString)(CStringA)(contents.c_str());
wprintf(L"Result:\n%s\n", temp1.GetBuffer());
if (temp1 == L"") temp1 = L"Unknown command";
strResult = temp1;
}
/*
else {
DWORD lastError = GetLastError();
if (lastError == 32) {
// File is locked since it is being prepared
return strResult;
}
strResult.Format(L"Can't open file %s. Error %d", RESULTS_FILE, lastError);
return strResult;
}*/
return strResult;
}
感谢EASY-SIZE的作者Marc Richarme。EASY-SIZE可以轻松用于支持在对话框调整大小时调整对话框内的控件大小。
结果,对话框可能最初看起来像这样:
然后如果调整大小,看起来像这样:
希望文本清晰且足够大。选择了Courier字体,140点。
首先,定义m_font作为成员变量:
CFont m_Font;
然后,在OnInitDialog中,调用:
m_Font.CreatePointFont(140, _T("Courier"));
然后,要将此字体分配给特定控件(在情况下,是命令和命令结果),使用以下代码:
CommandTyped.SetFont(&m_Font);
要设置清晰的黄色背景黑色文本,使用SetTextColor()和SetBkColor()。在OnCtrColor()中添加了以下调用:
case CTLCOLOR_EDIT:
if (ID == IDC_CMD_RESULT || ID == IDC_COMMAND) {
pDC->SetTextColor(COLOR_YELLOW);
pDC->SetBkColor(COLOR_BLACK);
return (HBRUSH)(m_brush->GetSafeHandle());
}
break;
最好单独定义常量,并在大多数情况下重用它们,而不必输入它们的值。在这种情况下,在头文件中定义了字体名称,黄色和黑色颜色。
#define FONT_NAME _T("Courier")
#define COLOR_BLACK RGB(0, 0, 0)
#define COLOR_YELLOW RGB(204, 204, 0)
为了便于操作,并与CMD的使用方式保持一致,支持以下键盘键:
<ENTER> - 执行命令
<上/下箭头键> - 在之前给出的命令之间切换