【问题标题】:Win32 application write output to console using printfWin32 应用程序使用 printf 将输出写入控制台
【发布时间】:2015-05-07 10:20:07
【问题描述】:

我有一个使用 win32 应用程序开发的 exe。当我运行(双击)时,exe GUI 应该出现,当我从命令提示符调用 exe 时,输出应该出现在命令控制台中。

我的问题是如何使用printf 将输出重定向到命令窗口?我可以使用AllocConsole() 在命令窗口中打印,但是会创建新的命令窗口并将输出重定向到新窗口。我想在使用 Win32 应用程序调用 exe 的同一命令窗口中打印输出。任何帮助表示赞赏。

【问题讨论】:

  • 您是否在问如何在从命令提示符运行时像命令行程序一样运行,并在双击时使用 GUI 运行?
  • 不完全重复,但与stackoverflow.com/questions/24171017/…密切相关
  • 没有什么好的方法可以做到这一点。构建两个可执行文件,一个 GUI,一个用于命令行。

标签: c++ windows winapi


【解决方案1】:

要建立在 wilx 所说的基础上(抱歉,我没有足够的声誉来评论他的答案),您可以使用 AttachConsole(...); 因此,如果只有在已经有一个可用的情况下才能附加到控制台,您可以使用类似的东西:

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;
}

然后在你的 WinMain 中你可以这样做:

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

此外,您必须“修复”c 标准 IO 句柄才能使用您的新控制台,请参阅下面的 write up,了解如何执行此操作的一个很好的示例。

【讨论】:

  • 问题是命令行界面不会知道等待你的程序退出,所以你的输出会和命令行提示符混在一起。如果您需要输入,问题会更严重。
  • 好点哈利。从控制台应用程序开始并通过参数隐藏控制台可能是使用一个 exe 关闭的唯一方法。
【解决方案2】:

这几乎可以满足您的需求:

// 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;
}

【讨论】:

    【解决方案3】:

    尝试使用AttachConsole(ATTACH_PARENT_PROCESS)(或使用 PID)附加到现有控制台。


    虽然我已经发布了我的答案,TBH,但我不确定我是否完全理解您的问题。我有一些代码有一条注释,上面写着(AllocConsole():

    这里我们忽略返回值。如果我们已经有一个控制台,它将失败。

    你确定不能像我一样无条件使用AllocConsole()吗?

    【讨论】:

    • AllocConsole 仅在您想创建新控制台时才有用。 OP 想要使用现有的控制台(如果有的话)或根本没有控制台(如果没有的话)。
    • 我尝试使用 AttachConsole(ATTACH_PARENT_PROCESS),它将打开新的 cmd 窗口。我的问题陈述是我打开一个 cmd 窗口并转到我的 exe 所在的位置(C:\test.exe),然后从同一个 cmd 窗口运行 exe。包括 AttachConsole() 输出显示在新的 cmd 窗口中。
    • @user1881297:好吧,那不应该发生。 AttachConsole() 不应该创建一个新的控制台!可以给我们an MCVE吗?
    【解决方案4】:

    试试这个:

    // 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;
    }
    

    【讨论】:

    • AllocConsole 仅在您想创建新控制台时才有用。 OP 想要使用现有的控制台(如果有的话)或根本没有控制台(如果没有的话)。
    • 我尝试使用 AttachConsole(ATTACH_PARENT_PROCESS),它将打开新的 cmd 窗口。我的问题陈述是我打开一个 cmd 窗口并转到我的 exe 所在的位置(C:\test.exe),然后从同一个 cmd 窗口运行 exe。包括 AttachConsole() 输出显示在新的 cmd 窗口中。
    猜你喜欢
    • 2011-03-10
    • 1970-01-01
    • 2010-11-04
    • 1970-01-01
    • 2012-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    相关资源
    最近更新 更多