【问题标题】:Highlighting text in console makes window unresponsive [duplicate]在控制台中突出显示文本使窗口无响应[重复]
【发布时间】:2016-06-03 22:11:31
【问题描述】:

对于我的一个应用程序,我一直在使用 Windows API,即为窗口功能创建一个非常小的包装器。因为我也喜欢控制台输出,所以我通过AllocConsole() 创建了一个控制台。然后我注意到在此控制台中突出显示文本(例如,如果您想复制某些内容)“冻结”打开的窗口,即。不会处理任何消息,它不可点击或关闭。消息循环和 wndProc 都是标准的。

两个问题:这是预期/记录的行为(我找不到任何关于它的信息),如果是,有没有办法禁用它?这有点烦人。

提前致谢

编辑:根据要求,控制台创建代码:

FILE *conOut = NULL;
FILE *conIn = NULL;

if (::AllocConsole())
{
    ::freopen_s(&conIn, "CONOUT$", "r", stdin);
    ::freopen_s(&conOut, "CONOUT$", "w", stdout);

    // ...

    if (conOut != NULL)
        ::fclose(conOut);
    if (conIn != NULL)
        ::fclose(conIn);

    ::FreeConsole();
}

【问题讨论】:

  • 在我看来,在控制台窗口中突出显示文本会导致 Windows 消息泵停止。我会尝试分离一个新线程,然后创建控制台,这样您的主线程就不会被控制台中的任何活动阻塞。这是控制台msdn.microsoft.com/en-us/library/windows/desktop/… 上的Windows MSDN 主页,其中包含一系列指向更具体主题的链接。另请参阅stackoverflow.com/questions/192294/…,其中包含指向代码项目示例的链接。
  • 我还建议您在问题中添加一个代码示例,展示您如何创建控制台。这篇文章也可能会有所帮助dslweb.nwnexus.com/~ast/dload/guicon.htm
  • 您希望用户如何突出显示滚动控制台窗口中的任何内容?这不是暂停输出的唯一方法,一个简单的 Ctrl+S 也可以完成工作。杀手锏。这很像苏联的老笑话,使用 1970 年代的用户界面隐含的是用户界面控制着你。如果你想控制用户界面,那么你可以使用 winapi 创建你自己的窗口。你让剪贴板工作。这是更多的工作。
  • 是的,这是标准的预期行为。进入选择模式会导致控制台滚动/刷新暂停。很惊讶你以前没有注意到这一点。

标签: c++ winapi


【解决方案1】:

我用一个基本的 Win32 项目创建了一个测试 Win32 应用程序。我添加了一个简单的类来处理控制台创建并测试了两个场景。我发现控制台窗口输出将停止,就好像在 Edit->Mark 完成时生成输出的线程被挂起,直到通过 Copy 完成 Mark 或取消。

使用 Win32 应用程序测试的两个场景是:(1) 在单独的线程中打印到控制台窗口,以及 (2) 在主窗口消息处理逻辑中打印到控制台窗口。

测试程序的细节和测试的两个场景的细节如下。

控制台.h

#pragma once

#include <stdio.h>

class CConsole
{
public:
    CConsole(void);
    ~CConsole(void);

    int Create(void);

public:
    FILE *m_conOut;
    FILE *m_conIn;
};

控制台.cpp

#include "StdAfx.h"
#include "Console.h"

CConsole::CConsole(void)
{
}

CConsole::~CConsole(void)
{
}

int CConsole::Create(void)
{
    if (::AllocConsole())
    {
        ::freopen_s(&m_conIn, "CONIN$", "r", stdin);
        ::freopen_s(&m_conOut, "CONOUT$", "w", stdout);
    }

    return 0;
}

在顶部附近的主文件中,Win32 项目向导放置了一些全局变量,我为我的控制台添加了一个额外的全局变量CConsole myConsole;,然后我在下面添加了一个简单的函数,它是_beginthreadex()。函数如下:

unsigned __stdcall myThread( void *x )
{
    HWND  hWnd = (HWND)x;

    // allow for two different test scenarios depending on whether the
    // SendMessage() is commented out or the fprintf() is commented out.
    // if SendMessage() is live then the main window will write to the console window
    // if fprintf() is live then this thread will write to the console window.
    for (int i = 0; i < 50; i++) {
//      SendMessage (hWnd, WM_USER, i, 0);    // send a message to main window to request print
        fprintf (myConsole.m_conOut, "This is line %d\n", i);  // print from this thread
        Sleep (1000);
    }
    return 0;
}

return 语句之前的InitInstance(HINSTANCE hInstance, int nCmdShow) 中,我添加了以下两行代码:

myConsole.Create();
_beginthreadex (NULL, 0, myThread, hWnd, 0, NULL);

最后在处理主窗口消息的主消息循环中,我添加了一个额外的消息目标:

case WM_USER:
    fprintf (myConsole.m_conOut, "This is line %d\n", wParam);
    break;

然后我尝试了两个不同的实验,将函数中的两行之一注释掉,这是_beginthreadex() 的目标。

一个是在该线程中使用fprintf() 打印到控制台窗口。第二个测试用例是向主窗口发送WM_USER的消息,并要求它使用fprintf()打印到控制台窗口。

我发现,打印是由线程完成的,然后当我使用 Edit->Mark 开始标记要复制的文本的过程时,我观察到以下行为:

  • 主窗口响应菜单选择

  • 控制台窗口输出停止

  • 当我清除标记或复制文本时,控制台窗口输出恢复

这种行为就像写入控制台窗口的线程被挂起,直到标记和复制过程完成。

当处理WM_USER 消息时由主窗口的消息循环完成打印时,当我使用编辑->标记开始标记要复制的文本的过程时,我观察到以下行为:

  • 主窗口对菜单选项无响应

  • 控制台窗口输出停止

  • 当我清除标记或复制文本时,主窗口响应与控制台输出一样返回

有关控制台窗口子系统的更多信息,请参阅Consoles。有关该技术的一些信息,请参阅WinEventProc Callback Function 以及在某种程度上描述此功能的SetWinEventHook,以及What Are WinEvents?In-Context Hook Function Precautions

有关控制台窗口子系统的简要概述,另请参阅 Windows Internals 一书中的Console Window Host

有关架构更改的介绍,请参阅 Windows 7 / Windows Server 2008 R2: Console Host

最后,来自《Inside Windows Debugging》一书的The Console Host Process in Windows 7 展示了如何“发现 printf 序列中涉及的各个层”。

可以使用较低级别的控制台功能直接与控制台窗口子系统交互,以防止正在对控制台窗口进行 I/O 的线程冻结。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-03
    • 2014-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多