Это фрагмент моего кода:
AttachConsole(-1);
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
freopen("CONIN$", "r", stdin); //this doesn't seem to do anything
int n = 0;
cin >> n;
cout << n + 1;
FreeConsole();
WNDCLASSA MainWindow = { 0 };
MainWindow.hbrBackground = (HBRUSH) COLOR_WINDOW;
MainWindow.hCursor = LoadCursor(NULL, IDC_ARROW);
MainWindow.hInstance = hInst;
//here the window gets created etc.
Очевидно, что использование консоли здесь является базовым, но этого должно хватить для ответа на этот вопрос. Проблема в том, что не работают такие функции, как cin
или scanf
. cout
, cerr
, clog
, printf
работают нормально, но функции ввода ничего не делают. Как я могу заставить работать stdin
(желательно с cin
)?
Почему вы не используете Unicode
@J. Добавление cin.clear()
после freopen("CONIN$", "r", stdin)
не работает.
@stackptr Мне не нужен Unicode, и я не понимаю, почему это актуально для этого вопроса
Вы можете попробовать другой метод, чем freopen()
, описанный в статье это.
Интересная идея, но визуальная студия не позволяет мне изменить значение stdin
(на самом деле это #define
d)
Вы не проверяете возвращаемые значения (большой NO-NO). Отметьте gist.github.com/Xsoda/3120099.
В статье предлагается не менять stdin
, а указывать на него.
Возможный дубликат Как получить консольный вывод на C++ с помощью программы Windows?
Вы включаете <stdio.h>
или <cstdio>
? Согласно этому: stackoverflow.com/questions/5257509/… что вы делаете должен работа. Как предложила CristiFati, проверьте возврат на freopen
. Я бы посоветовал после перенаправления stdin
сначала протестировать его с помощью (например) fgets(buf,sizeof(buf),stdin)
, чтобы убедиться, что stdin
был перенаправлен правильно. Затем вы можете перейти к тестированию с помощью cin
. Этот двухэтапный подход поможет изолировать, если freopen
не работает или требуется что-то дополнительное, чтобы заставить cin
работать (например, cin.clear()
), как предлагали другие.
@CristiFati в статье указатель на новый ФАЙЛ не разыменовывался, поэтому запутался. Он все время говорил мне, что я пытался назначить FILE * для FILE. Я все еще пытаюсь реализовать это
@Craig Estey, вот что я включил: windows.h
, io.h
, conio.h
, stdlib.h
, stdio.h
, iostream
@DarkAtom «Я все еще пытаюсь реализовать это», функция в моем ответе использует метод, описанный в статье.
Я не уверен, имеет ли это значение, но я бы использовал cstdio
, так как это способ идиоматический. cstdio
[вероятно] будет включать stdio.h
, но сделает это таким образом, чтобы cin
мог работать. Если бы вы использовали Только, используя stdin
и нет, cin
, включая stdio.h
, было бы / должно быть хорошо. Их смешивание требует особой осторожности (например, вам нужно «сообщить» cin
, что вы это делаете, чтобы он использовал буферизацию FILE
вместо своей собственной - зависит от реализации). Итак, каковы результаты теста fgets
?
@CraigEstey <cstdio>
не делал никаких забавных вещей до включения <stdio.h>
(Visual Studio).
@J. Доу заменил stdio.h
и stdlib.h
на cstdio
и cstdlib
соответственно. Никаких изменений в поведении. Я считаю, что cin не имеет ничего общего с cstdio
, но с iostream
, с той лишь разницей, что один находится в пространстве имен std
, а другой - нет.
@DarkAtom Вам следует лучше следить за тем, на кого вы ссылаетесь в своих комментариях. (Второй раз не тот человек)
Я на самом деле имел в виду CristiFati и вас
Используйте AllocConsole
, если родительский процесс с окном консоли отсутствует.
Ваша программа /SUBSYSTEM:WINDOWS
будет отсоединена от консоли сразу после ее запуска, и командный процессор cmd.exe
снова ждет ввода пользователя. Итак, stdin
уже используется, прежде чем ваша программа сможет попытаться выполнить какую-либо операцию ввода.
На самом деле,
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <iostream>
int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
AttachConsole(-1);
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
freopen("CONIN$", "r", stdin);
std::cout.clear();
std::cin.clear();
std::cout << "Hello!\n";
int i;
std::cin >> i;
std::cout << i << '\n';
std::cin.get();
std::cin.get();
}
работает должным образом при запуске из командной строки с помощью start /wait foobar.exe
. (foobar.exe
должен быть построен как x64, чтобы работать таким образом в x64 Windows. Попытка использовать исполняемый файл x86 дает забавные сообщения об ошибках.)
См. Как мне написать программу, которую можно запускать как консоль, так и приложение с графическим интерфейсом? для обсуждения темы.
он говорит, что _O_TEXT
не определен
_O_TEXT
определен в <fcntl.h>
Я вызвал это из WinMain и проверил, ложно ли возвращаемое значение. Если это так, отобразите окно сообщения Windows, в противном случае - нет. При запуске без консоли он отображает это (очевидно), но при запуске с помощью консоли он этого не отображает, но ни stdin, ни stdout не работают.
Вы проверяете возвращаемое значение вашего AttachConsole(-1);
? Что вообще за родительский процесс?
да, я проверил, он возвращает TRUE
только тогда, когда действительно есть вызывающая консоль
Вы хотите сказать, что ваш родитель - cmd.exe
?
Да, я использую Windows, поэтому я использую cmd.exe
, потому что других вариантов нет (я не думаю, что использование PowerShell что-то изменит)
Как только программа с SUBSYSTEM:WINDOWS
запускается с консоли, она отключается от нее. Командный процессор не будет ждать завершения программы, а сразу же отобразит новое приглашение и будет ждать ввода данных пользователем. Как это могло работать, если бы ваша программа могла украсть stdin консоли ??
Метод freopen()
действительно работает, если вы запускаете исполняемый файл с cmd.exe
с помощью start /wait foobar.exe
. Но на W10 x64 только с исполняемыми файлами x64. Вы получите забавные сообщения об ошибках, если попробуете с x86 exes.
Хорошо, это полезно знать, но какова тогда цель AttachConsole
? Разве нельзя повторно подключить программу к cmd?
Цель AttachConsole()
- подключиться к консоли родительского процесса, который либо имеет консоль, потому что это исполняемый файл SUBSYSTEM:CONSOLE
, либо тот, который использовал AllocConsole()
.
См. blogs.msdn.microsoft.com/oldnewthing/20090101-00 для обсуждения темы.
Хорошо, использование AllocConsole
и метода freopen
работает нормально. По какой-то причине подключение к существующим консолям является проблемой, а создание консоли - нет.
Хорошо, я нашел дальний план, но, на мой взгляд, он довольно глупый. При подключении к консоли и последующем отключении cmd.exe
, связанного с этой консолью, с помощью system("taskkill /f /im cmd.exe");
окно консоли останется открытым и будет свободно доступным для приложения. После того, как приложение завершит работу с консолью, оно может запустить cmd.exe с помощью system("start cmd.exe");
. Единственным недостатком этого является то, что он изменяет PID cmd.exe
и убивает все окна cmd (хотя я считаю, что это можно обойти, убив только процесс с родительским pid)
Я бы просто использовал консольное приложение и использовал бы консоль «легально» или FreeConsole()
в противном случае.
Вы пробовали
std::cin.clear()
послеfreopen()
потоковой передачи?