使用 istream (std cin):防止在 Windows 上"[input] is not recognized as ..."

Using istream (std cin): prevent "[input] is not recognized as ..." on Windows

本文关键字:input is as recognized not Windows std istream cin 使用      更新时间:2024-04-27

我有一个具有命令行功能的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();
}

当输入"Yes"、"No"、"YesAll"或"NoAll"(不区分大小写(时,程序会按预期继续,但当用户输入其他内容时,cmd会抛出以下内容:

'[input]'未被识别为内部或外部命令[…]

然后再次显示"C:\path\to\exe>",用户可以继续输入,直到键入正确的值之一。一旦输入了有效的字符串,它就会按预期再次继续。

我试过这个答案和std::getline()一样,但没有区别。

那么,如何防止出现错误并继续显示cout呢?

AttachConsole只是连接到父进程的控制台,它不会阻止父进程也从中读取。因此,控制台输入在父进程(cmd.exe(和您的应用程序之间交错,管理起来可能会有问题(有些人建议杀死父进程,这显然不是一个好主意(。

您可以做的是始终创建一个新的控制台(请参阅AllocConsole(。

或者,如果您想重复使用相同的控制台,可以将控制台子系统作为目标(链接器选项/SUBSYSTEM:CONSOLE(,并使用常规的main()函数而不是WinMain(是的,您可以在main()内创建Win32窗口来处理控制台I/O(。

您甚至可以拥有一个多子系统源,该源可以链接为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. . .