открой cmd и читай и пиши в него - PullRequest
0 голосов
/ 20 декабря 2011

Мне нужно запустить процесс, который запускает командную строку (он не должен всплывать, поэтому что-то вроде фонового процесса).

Затем мне нужно написать что-нибудь и периодически читать последнюю строку cmd.

Поскольку мои навыки C ++ не так уж велики, я не знаю, как этого добиться.

В псевдокоде я подумал примерно так:

startProcess();
writeToCmd();
readFromCmd() { // Call that every given interval (e.g. 1000 ms)
    if(returnValue >= 100) {
        stopProcess();
    }
}

Я уверен, что это будет не так просто. Было бы здорово, если бы кто-нибудь смог мне здесь помочь. Программа для Windows.

Изменить после предложений: Это то, что я сделал до сих пор (я сделал это немного по-другому.)

int errorCode;

// Variables for CreateProcess()
SECURITY_ATTRIBUTES sa;
STARTUPINFO si;
PROCESS_INFORMATION pi;
PHANDLE hInRead, hInWrite;
LPDWORD bytesWritten, bytesRead;

// The CommandLine input
TCHAR tcsCommandLine[] = _T("cmd /c format H: /fs:FAT32 /V:device");
//TCHAR tcsCommandLine[] = _T("cmd /c start D:\\foo.txt");

sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = true;

ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.wShowWindow = SW_SHOW; // SW_HIDE FOR PRODUCTION
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.hStdInput = hInRead;
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);

ZeroMemory(&pi, sizeof(pi));

errorCode = CreatePipe(hInRead, hInWrite, &sa, 0);

info = GetDriveInfo(m_wsNANDMountPoint);

if(info.m_uSizeInMB > 2048) {
    log("Wrong Mounting Point. Device has more than 2GB space.");

    return false;
}
else {
    // Start Formatting
    if(!CreateProcess(NULL, tcsCommandLine,
        NULL, NULL,
        TRUE, CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS, NULL, NULL,
        &si,
        &pi)) {

        log("CreateProcess failed. Could not format Drive");
        return false;
    }

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    WriteFile(hInWrite, "#13#10'J'#13#10", 5, bytesWritten, NULL);
    CloseHandle(hInWrite);

    // Wait until child process exits
    WaitForSingleObject(pi.hProcess, 1100);
}

return true;

После небольшой отладки я понял, что код не прерывается на ZeroMemory(), а на

errorCode = CreatePipe(hInRead, hInWrite, &sa, 0);

с ошибкой Access violation writing location. Понятия не имею, что я делаю не так. Было бы здорово, если бы вы, ребята, смогли мне помочь.

Ответы [ 3 ]

2 голосов
/ 20 декабря 2011

В этом случае вам нужно создать консоль со скрытым окном. Если вы используете CreateProcess для запуска консоли, вы сможете настроить видимость окна через структуру STARTUPINFO .

Следующим шагом будет перенаправление ввода и вывода вашей консоли. Вы можете сделать это, прикрепив 3 дескриптора консоли (вход, выход, ошибка) к каналам и считав их из родительского процесса. Эта статья MSDN описывает, как именно это сделать.

1 голос
/ 20 декабря 2011

Командная строка состоит из двух интересующих вас частей.

  1. Место для выполнения программ
  2. Буфер для всего, что написано на экране

Поскольку вам не нужно, чтобы экран был виден, вам нужны эти две вещи в вашей программе. Итак, с этого момента, забудьте о cmd.

Для выполнения программ в вашей программе у вас есть много способов. Если вы хотите, чтобы строки выполнения выглядели именно так, как вы пишете в cmd, вы можете использовать system (хотя версии Windows для fork / exec имеют больше смысла). Например:

system("my_prog.exe --option file.txt");

Который выполняет my_prog.exe с --option и file.txt в качестве аргументов.

Теперь второй, вы сказали, что хотите прочитать последнюю строку из cmd. Идея реализовать это состоит в том, чтобы выводить все в файл, а не в cmd.

Если вас интересует только последняя строка в каждом случае, вы можете перенаправить вывод ваших программ в файл, подобный следующему:

system("my_prog.exe --option file.txt > output.txt");

или, если вы хотите сохранить всю историю, вы можете добавить вместо перезаписи:

system("my_prog.exe --option file.txt >> output.txt");

Если вы также хотите перенаправить stderr, вы можете написать:

system("my_prog.exe --option file.txt &> output.txt");

Обозначение может быть linuxy, попробуйте в ваших окнах посмотреть, работает ли оно (вручную в обычном cmd) Вы также можете поискать в Google «shell redirect», и вы получите много результатов.

В любом случае, если вы хотите, чтобы последняя строка cmd включала в себя и саму команду, вы можете перезаписать / добавить командную строку для этого конкретного пользователя в программе.

0 голосов
/ 20 декабря 2011

Позвольте мне добавить это к этим превосходным ответам:

Эта замечательная ссылка демонстрирует чтение и запись консоли: http://www.adrianxw.dk/SoftwareSite/Consoles/Consoles2.html

Чтобы делать вещи периодически, используйте SetTimer(). http://msdn.microsoft.com/en-us/library/windows/desktop/ms644906(v=vs.85).aspx

Функция SetTimer выполняет функцию каждые x миллисекунд. Пример: Следующая консольная программа работает следующим образом: устанавливает таймер с помощью SetTimer затем зацикливается в цикле сообщений. Цикл сообщений получает и обрабатывает WM_TIMER сообщений и обратный вызов таймера также вызывается для каждого временного интервала. Просто поместите нужные данные в функцию TimerProc().

#define STRICT 1 
#include <windows.h>
#include <iostream.h>

VOID CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime) 
{
   //put the stuff you want done in here

  cout << "Doing stuff Time: " << dwTime << '\n';
  cout << "--------------------------------------------------\n" ;
  cout.flush();
}

int main(int argc, char *argv[], char *envp[]) 
{
    int Counter=0;
    int usage_Time_millisec=1000;
    MSG Msg;

    UINT TimerId = SetTimer(NULL, 0, usage_Time_millisec, &TimerProc); //bind TimerProc() to SetTimer() 

    cout << "TimerId: " << TimerId << '\n';

   if (!TimerId) return 16;

   while (GetMessage(&Msg, NULL, 0, 0)) 
   {
        ++Counter;
        if (Msg.message == WM_TIMER)
        cout << "Doing stuff Counter: " << Counter << "; timer message\n";
        else
        cout << "Doing stuff Counter: " << Counter << "; message: " << Msg.message << '\n';
        DispatchMessage(&Msg);
   }

   KillTimer(NULL, TimerId);

return 0;

}
...