Использование istream (std cin): запретить "[input] не распознается как ..." на Windows - PullRequest
1 голос
/ 01 мая 2020

У меня есть приложение Qt gui с функцией командной строки. Чтобы сделать эту работу, я добавил это в начало функции main():

#ifdef _WIN32
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
    freopen("CONOUT$", "w", stdout);
    freopen("CONIN$", "r", stdin);
    freopen("CONOUT$", "w", stderr);
}
#endif

Затем создается экземпляр моего основного класса. В конструкторе QCommandLineParser определяет, есть ли какие-либо аргументы, и создает экземпляр класса синтаксического анализа cmdline или класса приложения gui.

В классе синтаксического анализа cmdline я прошу пользователя: введите определенные значения:

QString qanswer;

// `answerToInt` is an std::unordered_map
while (answerToInt.find(qanswer) == answerToInt.end()) {
    std::cout << std::endl << "File will be overwritten:" << std::endl
              << path.toStdString() << std::endl
              << "Are you sure? " << (multiple ? "(Yes/YesAll/No/NoAll)" : "(Yes/No)") << std::endl;

    std::string answer;
    std::cin >> answer;
    qanswer = QString::fromStdString(answer).toLower();
    std::cin.clear();
}

Когда вводится «Да», «Нет», «ДаАлл» или «Нет данных» (без учета регистра), программа продолжает работу, как и ожидалось, но когда пользователь вводит что-то иное, чем это , cmd выдает это:

'[input]' не распознается как внутренняя или внешняя команда [...]

А затем "C: \ path \ to \ exe> "отображается снова, где пользователь может продолжать ввод, пока не будет набрано одно из правильных значений. После ввода правильной строки она снова продолжается, как и ожидалось.

Я пытался этот ответ , а также std::getline(), но это не имеет значения.

Так как предотвратить появление ошибки и продолжить отображение cout?

1 Ответ

1 голос
/ 01 мая 2020

AttachConsole просто подключается к консоли родительского процесса, это не мешает родительскому процессу также читать из него. Таким образом, консольный ввод чередуется между родительским процессом (cmd.exe) и вашим приложением, что может быть проблематичным c для управления (некоторые люди советуют убить родительский процесс, который, очевидно, не является хорошая идея).

Вместо этого вы всегда можете создать новую консоль (см. AllocConsole).

Или, если вы Если вы хотите повторно использовать консоль , такую ​​же , может оказаться целесообразным использовать вместо нее подсистему консоли (опция компоновщика /SUBSYSTEM:CONSOLE) и использовать обычную функцию main() вместо WinMain (да, вы можете создать Win32 windows и обрабатывать консольный ввод / вывод все в main()).

Вы можете даже иметь многосистемный источник, который может быть связан как Windows, а также Консольная подсистема с подобной шиммой (nCmdShow и аргументы командной строки еще не реализованы):

HWND hwnd;

int main() {
    std::thread t([] {
        // let GUI run in its own thread ...
        WinMain(GetModuleHandle(NULL), NULL, "", SW_SHOWDEFAULT);
        exit(0);
    });
    // meanwhile in this thread we handle console I/O ...
    std::string s;
    std::cout << "Press Enter to exit" << std::endl;
    while (std::getline(std::cin, s)) {
        if (s == "")
            break;
        std::cout << "Hello " << s << std::endl;
    }
    PostMessageA(hwnd, WM_CLOSE, 0, 0);
    t.join();
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
     // Your normal WinMain.
     // CreateWindow, GetMessage loop etc. . .
...