2

This is a snippet of my code:

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.

Obviously the usage of the console here is basic, but that should do for this question. The problem is that functions like cin or scanf are not working. cout, cerr, clog, printf work fine, but the input functions don't do anything. How can I make stdin work (preferrably with cin)?

Ken White
  • 123,280
  • 14
  • 225
  • 444
DarkAtom
  • 2,589
  • 1
  • 11
  • 27
  • have you tried `std::cin.clear()` after `freopen()`ing the streams? –  Oct 24 '18 at 18:50
  • Why aren't you using Unicode – lost_in_the_source Oct 24 '18 at 18:53
  • @J. Doe adding `cin.clear()` after `freopen("CONIN$", "r", stdin)` doesn't work. – DarkAtom Oct 24 '18 at 18:56
  • @stackptr I don't need Unicode and I don't see why that is relevant for this question – DarkAtom Oct 24 '18 at 18:57
  • You could try a different method than `freopen()` described in [this](https://www.codeproject.com/Articles/15836/Writing-to-and-read-from-the-console-From-a-GUI-ap) article. –  Oct 24 '18 at 19:05
  • Interesting idea, but visual studio doesn't allow me to change the value of `stdin` (actually, it is `#define`d) – DarkAtom Oct 24 '18 at 19:19
  • You don't check the return values (**big** NO-NO). Check https://gist.github.com/Xsoda/3120099. – CristiFati Oct 24 '18 at 19:30
  • The article isn't suggesting to change `stdin` but its pointee. –  Oct 24 '18 at 19:33
  • Possible duplicate of [How do I get console output in C++ with a Windows program?](https://stackoverflow.com/questions/191842/how-do-i-get-console-output-in-c-with-a-windows-program) – SoronelHaetir Oct 24 '18 at 19:34
  • Are you including `` or ``? According to this: https://stackoverflow.com/questions/5257509/freopen-equivalent-for-c-streams what you're doing _should_ work. As CristiFati suggested, check the returns on `freopen`. I'd suggest that after redirecting `stdin`, test it with (e.g.) `fgets(buf,sizeof(buf),stdin)` first to verify that `stdin` was redirected properly. Then, you can move on to testing it with `cin` This two step approach will help isolate if `freopen` is failing or if something extra is needed to get `cin` to work (e.g. `cin.clear()`) as others have suggested – Craig Estey Oct 24 '18 at 19:35
  • @CristiFati in the article the pointer to the new FILE wasn't dereferenced, that's why I got confused. It kept telling me that I was trying to assign FILE* to FILE. I am still trying to implement that – DarkAtom Oct 24 '18 at 19:41
  • @Craig Estey here is what I included: `windows.h`, `io.h`, `conio.h`, `stdlib.h`, `stdio.h`, `iostream` – DarkAtom Oct 24 '18 at 19:45
  • @DarkAtom "I am still trying to implement that" the function in my answer uses the method described in the article. –  Oct 24 '18 at 19:47
  • I'm not sure whether it makes a difference, but I'd use `cstdio` as that is the _idiomatic_ way to do it. `cstdio` will [probably] include `stdio.h` but do it in a way that allows `cin` to work. If you were _only_ using `stdin` and _not_ `cin`, including `stdio.h` would/should be fine. Intermixing them takes some special care (e.g. you need to "tell" `cin` that you're doing this so that it will use `FILE` buffering instead of doing its own--implementation dependent). So, what are the results of the `fgets` test? – Craig Estey Oct 24 '18 at 19:56
  • @CraigEstey `` doesn't do any funny things before including `` (Visual Studio). –  Oct 24 '18 at 19:59
  • @J. Doe replaced `stdio.h` and `stdlib.h` with `cstdio` and `cstdlib`, respectively. No changes in behaviour. I believe cin has nothing to do with `cstdio`, but with `iostream`, the only difference being that one is in namespace `std`, while the other one isn't. – DarkAtom Oct 24 '18 at 20:09
  • @DarkAtom You should take better care of who you refer to in your comments. (2nd time wrong person) –  Oct 24 '18 at 20:10
  • I was actually refering to CristiFati and you – DarkAtom Oct 24 '18 at 20:15
  • Use `AllocConsole` if the there is no parent process with console window – Barmak Shemirani Oct 24 '18 at 23:40

1 Answers1

3

Your /SUBSYSTEM:WINDOWS program will be detached from the console right at its launch and the command processor cmd.exe waits for user input again. So stdin is already in use before your programm can attempt any input operation.

Actually,

#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();
}

works as expected when run from the command prompt using start /wait foobar.exe. (foobar.exe must be built as x64 to work that way on x64 Windows. Trying with an x86 executable gives funny error messages.)

See How do I write a program that can be run either as a console or a GUI application? for a discussion about the topic.

  • it says `_O_TEXT` is undefined – DarkAtom Oct 24 '18 at 19:52
  • `_O_TEXT` is defined in `` –  Oct 24 '18 at 19:53
  • I called this from WinMain and checked if the return value is false. If it is, display a Windows message box, otherwise not. When launched without a console it displays that (obviously), but when launched with a console, it doesn't display that but neither stdin nor stdout are working. – DarkAtom Oct 24 '18 at 20:06
  • Do you check the return value of your `AttachConsole(-1);`? Whats the parent process anyway? –  Oct 24 '18 at 20:08
  • yes, I checked it, it only returns `TRUE` when there actually is a calling console – DarkAtom Oct 24 '18 at 20:12
  • Do you want to say your parent is `cmd.exe`? –  Oct 24 '18 at 20:14
  • Yes, I am on windows so I use `cmd.exe` because there are no other options (I don't think using powershell would change anything) – DarkAtom Oct 24 '18 at 20:16
  • Once a program with `SUBSYSTEM:WINDOWS` is started from a console, it gets detached from it. The command processor won't wait for the program to end but display a new prompt immediatly and wait for user input. How could that work if your program were able to steal the consoles stdin?? –  Oct 24 '18 at 20:42
  • The `freopen()` method actually works if you run the executable from a `cmd.exe` using `start /wait foobar.exe`. But on W10 x64 only with x64 executables. You get funny error messages if you try with x86 exes. –  Oct 24 '18 at 20:52
  • well that is good to know, but what is the purpose of `AttachConsole` then? Shouldn't it reattach the program to cmd? – DarkAtom Oct 24 '18 at 20:59
  • `AttachConsole()`s purpose is to attach to the console of a parent process that either has a console because it is a `SUBSYSTEM:CONSOLE` exe or one that used `AllocConsole()`. –  Oct 24 '18 at 21:04
  • See https://blogs.msdn.microsoft.com/oldnewthing/20090101-00/ for a discussion of the topic. –  Oct 24 '18 at 21:05
  • Ok, using `AllocConsole` and the `freopen` method works fine. For some reason attaching to existing consoles is a problem, but creating one is not – DarkAtom Oct 24 '18 at 21:06
  • Ok, I found a long shot, but it is pretty dumb in my opinion. Attaching to the console and then killing the `cmd.exe` associated with that console using `system("taskkill /f /im cmd.exe");` will leave the console window open and freely available to the application. After the application is done with the console, it can start cmd.exe using `system("start cmd.exe");`. The only downsides to this is that it changes the PID of `cmd.exe` and it kills all cmd windows (although I believe that this can be worked around by killing only the process with the parent's pid) – DarkAtom Oct 24 '18 at 21:25
  • I'd just use a console application and use the console "legally" or `FreeConsole()` it otherwise. –  Oct 24 '18 at 21:31