3
votes

I have an exe developed using win32 application. When I run (double click) the exe GUI should appear and when i call exe from command prompt output should appear in command console.

My issue is how can i redirect output to command window using printf? I am able to print in command window using AllocConsole(), but new command window is created and output is redirected to new window. I want to print output in same command window where exe is called using Win32 application. Any help appreciated.

4
Are you asking how to act like a command line program when run from a command prompt, and run with a GUI when double clicked? - crashmstr
Not exactly a duplicate, but very closely related to stackoverflow.com/questions/24171017/… - Adrian McCarthy
There's no good way to do this. Build two executables, one GUI and one for the command line. - Harry Johnston

4 Answers

5
votes

To build on what wilx said (sorry I don't have enough reputation to just comment on his answer) you can use AttachConsole(...); So to attach to a console if an only if there is already one available you could use something like:

bool bAttachToConsole()
{
    if (!AttachConsole(ATTACH_PARENT_PROCESS))
    {
        if (GetLastError() != ERROR_ACCESS_DENIED) //already has a console
        {
            if (!AttachConsole(GetCurrentProcessId()))
            {
                DWORD dwLastError = GetLastError();
                if (dwLastError != ERROR_ACCESS_DENIED) //already has a console
                {
                    return false;
                }
            }
        }
    }

    return true;
}

Then in your WinMain you can do this:

if (bAttachToConsole())
{
    //do your io with STDIN/STDOUT
    // ....
}
else
{
    //Create your window and do IO via your window
    // ....
}

Additionally you will have to "fix" the c standard IO handles to use your new console see the following write up for a great example of how to do this.

1
votes

This almost does what you want:

// Win32Project1.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include <stdio.h>  // printf, _dup2
#include <io.h>     // _open_osfhandle

void SetupConsole()
{
    AttachConsole(ATTACH_PARENT_PROCESS);
    HANDLE hConIn = GetStdHandle(STD_INPUT_HANDLE);
    int fd0 = _open_osfhandle((intptr_t)hConIn, 0);
    _dup2(fd0, 0);
    HANDLE hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
    int fd1 = _open_osfhandle((intptr_t)hConOut, 0);
    _dup2(fd1, 1);
    HANDLE hConErr = GetStdHandle(STD_ERROR_HANDLE);
    int fd2 = _open_osfhandle((intptr_t)hConErr, 0);
    _dup2(fd2, 2);
}

WNDPROC g_pOldProc;

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    if (uMsg == WM_CLOSE)
    {
        PostQuitMessage(0);
        return 0;
    }

    return CallWindowProc(g_pOldProc, hwnd, uMsg, wParam, lParam);
}

void GUI(HINSTANCE hInstance)
{
    HWND hWnd = CreateWindow(
                        _T("EDIT"),
                        _T("GUI"),
                        WS_OVERLAPPEDWINDOW|WS_VISIBLE,
                        100, 100, 200,200,
                        NULL,
                        NULL,
                        hInstance,
                        NULL
                        );
    g_pOldProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)&WindowProc);

    SetWindowText(hWnd, _T("Hello world."));

    MSG m;
    while (GetMessage(&m, NULL, 0, 0))
    {
        DispatchMessage(&m);
    }

    DestroyWindow(hWnd);
}

void Console()
{
    SetupConsole();
    printf("Hello world.");
}

int APIENTRY _tWinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPTSTR    lpCmdLine,
                       int       nCmdShow)
{
    HANDLE hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
    if (!hConOut)
        GUI(hInstance);
    else
        Console();

    return 0;
}
0
votes

Try using AttachConsole(ATTACH_PARENT_PROCESS) (or use PID) to attach to the existing console.


While I have posted my answer already, TBH, I am not sure I do understand your problem exactly. I have some code that has a comment that says (above AllocConsole():

We ignore the return value here. If we already have a console, it will fail.

Are you sure that you cannot just use AllocConsole() unconditionally like I do?

0
votes

Try this:

// Win32Project1.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include <stdio.h>  // printf
#include <io.h>     // _open_osfhandle, _dup2

void SetupConsole()
{
    BOOL bCreated = AllocConsole();
    if (!bCreated)
        return; // We already have a console.

    HANDLE hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
    int fd = _open_osfhandle((intptr_t)hConOut, 0);
    _dup2(fd, 1);

}

int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPTSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    SetupConsole();
    printf("Hello world!");
    Sleep(10000);

    return 0;
}