在应用程序中运行CMD命令并获取结果

在日常工作中,经常需要执行一些预先编写好的程序,这些程序的主要任务是程序化地执行一系列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> - 执行命令

<上/下箭头键> - 在之前给出的命令之间切换

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485