【问题标题】:AllocConsole() not displaying coutAllocConsole() 不显示 cout
【发布时间】:2013-03-21 09:24:27
【问题描述】:

我有一个 DLL,我在其中使用 AllocConsole() 和 cout 来显示数据以进行调试。
它曾经可以正常工作,但由于我将编译器 (Visual Studio 2012) 更新到最新版本,因此 dll 仅显示控制台,但不显示打印/输出。
我不知道为什么会这样。
有什么想法吗?

我的部分代码

__declspec(dllexport) INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)
{
    switch(Reason)
    {
    case DLL_PROCESS_ATTACH:    
        AllocConsole();

        DisableThreadLibraryCalls(hDLL);

        //
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourAttach(&(PVOID&)pSend, MySend);
        if(DetourTransactionCommit() == NO_ERROR)
             cout << "[" << MySend << "] successfully detoured." << endl;

但什么都没有显示。

【问题讨论】:

    标签: c++ dll


    【解决方案1】:

    我隐约记得您可能需要将标准输出重定向到控制台。不过我可能是错的(因为你的代码之前工作过):

    AllocConsole();
    freopen("CONOUT$", "w", stdout);
    std::cout << "This works" << std::endl;
    

    【讨论】:

    • freopen("CONIN$", "r", stdin); 也可以正常工作。
    • 由于freopen 已被弃用(出于安全问题),您应该使用freopen_s(&amp;new_stdout, "CONOUT$", "w", stdout);,其中new_stdoutFILE 指针。
    • freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
    【解决方案2】:

    通过AllocConsole()分配新的控制台后,您需要重新打开标准流(stdoutstderrstdin)才能使用它们。

    您可以使用freopen 来执行此操作(在较新版本的 Visual Studio 中,您需要使用 freopen_s) 示例:

    FILE *fDummy;
    freopen_s(&fDummy, "CONIN$", "r", stdin);
    freopen_s(&fDummy, "CONOUT$", "w", stderr);
    freopen_s(&fDummy, "CONOUT$", "w", stdout);
    

    如果您想使用已弃用的freopen,您可以通过#defineing _CRT_SECURE_NO_WARNINGSdisable the warning

    如果您还想使用宽字符流(std::wcoutstd::wcerr 等...),则需要调用 SetStdHandle() 为您的进程设置新的输出句柄。您可以通过使用CONOUT$ / CONIN$ 作为文件名调用CreateFile() 来获取所需的文件句柄:

    HANDLE hConOut = CreateFile(_T("CONOUT$"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    SetStdHandle(STD_OUTPUT_HANDLE, hConOut);
    

    此外,如果您在重新打开它们之前尝试使用其中一个流,它们将具有 std::ios_base::badbitstd::ios_base::failbit 在他们的iostate 中设置,因此后续的写入/读取将被忽略。
    您可以使用.clear() 重置流状态,之后您可以再次读取/写入流:

    std::cout.clear();
    std::cin.clear();
    

    这是在AllocConsole() 之后重新打开所有流的完整示例:

    void CreateConsole()
    {
        if (!AllocConsole()) {
            // Add some error handling here.
            // You can call GetLastError() to get more info about the error.
            return;
        }
    
        // std::cout, std::clog, std::cerr, std::cin
        FILE* fDummy;
        freopen_s(&fDummy, "CONOUT$", "w", stdout);
        freopen_s(&fDummy, "CONOUT$", "w", stderr);
        freopen_s(&fDummy, "CONIN$", "r", stdin);
        std::cout.clear();
        std::clog.clear();
        std::cerr.clear();
        std::cin.clear();
    
        // std::wcout, std::wclog, std::wcerr, std::wcin
        HANDLE hConOut = CreateFile(_T("CONOUT$"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        HANDLE hConIn = CreateFile(_T("CONIN$"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        SetStdHandle(STD_OUTPUT_HANDLE, hConOut);
        SetStdHandle(STD_ERROR_HANDLE, hConOut);
        SetStdHandle(STD_INPUT_HANDLE, hConIn);
        std::wcout.clear();
        std::wclog.clear();
        std::wcerr.clear();
        std::wcin.clear();
    }
    

    【讨论】:

    • 有没有办法打开两个控制台并向每个控制台写入不同的内容?
    • @JerryJeremiah 一个进程可以与only one console 相关联,但您当然可以创建一个子进程,然后它可以拥有自己的控制台(使用管道或其他形式的 ipc 从父进程到子控制台)。或者,您可以使用AttachConsole() 并在不同的控制台之间切换,但是您仍然需要子进程来为您创建这些控制台,因为每个进程只能创建一个控制台。
    【解决方案3】:

    这适用于带有std::cout.clear()行的vs2015

    if (!AllocConsole())
        MessageBox(NULL, L"The console window was not created", NULL, MB_ICONEXCLAMATION);
    
    FILE* fp;
    
    freopen_s(&fp, "CONOUT$", "w", stdout);
    
    printf("Hello console on\n");
    
    std::cout.clear();
    
    std::cout << "Cout line one." << std::endl;
    
    cout << "Cout line two." << std::endl;
    
    MessageBox(NULL, (L"Pause to see console output."), (L"Pause Here"), MB_OK | MB_SYSTEMMODAL | MB_ICONEXCLAMATION);
    
    fclose(fp);
    
    if (!FreeConsole())
        MessageBox(NULL, L"Failed to free the console!", NULL, MB_ICONEXCLAMATION);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-24
      • 2012-02-16
      • 2014-12-31
      • 2016-07-13
      • 1970-01-01
      • 1970-01-01
      • 2017-05-28
      • 2013-09-03
      相关资源
      最近更新 更多