在日常工作中,经常需要执行一些预先编写好的程序,这些程序的主要任务是程序化地执行一系列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> - 执行命令
<上/下箭头键> - 在之前给出的命令之间切换