• 控制台基础概念实例


    上一篇文章 控制台基础概念 介绍了控制的基本构成,以及一些操作处理。这一部分以实际代码为主,给出控制台使用的几个例子。

    以main函数作为入口函数的程序都是控制台程序,最简单的控制台程序就是Hello World的程序。这里不给出了。

    GUI程序可以使用以下几种方式使用控制台:

    • 在调用CreateProcess时使用CREATE_NEW_CONSOLE标志。(默认情况下,待启动进程为控制台程序时不推荐使用该参数,因为无法确定用户输入是有哪个控制台处理的)
    • 通过 AttachConsole函数附加到一个已经存在的控制台。
    • 未附加到控制台的程序可通过AllocConsole函数创建控制台。(GUI进程默认不会和控制台关联。若使用DETACHED_PROCESS参数调用CreateProcess启动一个控制台进程,则会创建一个无控制台的控制台进程。)

    GUI程序可使用FreeConsole函数来释放控制台。一个控制台程序可以通过GetConsoleProcessList函数获取所有与其关联的进程列表。

    控制台程序提供以下函数,用于改变控制台属性:

    GetConsoleScreenBufferInfo 获得窗口大小、屏幕缓冲大小和颜色属性
    SetConsoleWindowInfo 设置控制台窗口大小
    SetConsoleScreenBufferSize 设置控制台屏幕缓冲大小
    SetConsoleTextAttribute 设置控制台字符属性
    SetConsoleTitle 设置控制台标题
    GetConsoleTitle 获取控制台标题

    实例a 控制台参数获取及设置

    本实例说明如何获取和设置控制台相关参数,例如设置和获取标题栏、设置和获取控制台显示窗口位置等。

    代码如下: 

    // 显示及设置控制台相关参数
    // 1. 设置及获取控制台标题栏
    // 2. 获取屏幕输出缓冲的参数
    // 3. 设置控制台窗口大小
    // 4. 设置控制台屏幕缓冲大小
    // 建议使用visual studio 2005以上版本编译,使用unicode编码
    
    #include <windows.h>
    #include <iostream>
    using std::wcout;
    using std::endl;
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        std::wcout.imbue(std::locale("chs"));
    
        // 获取和设置控制台标题栏
        DWORD title_need_size = 1024; // 64k
        TCHAR * console_title = new TCHAR[title_need_size+1];
        memset(console_title, 0, (title_need_size+1)*sizeof(TCHAR));
        DWORD title_size = GetConsoleTitle(console_title, title_need_size);
        if (0 == title_size)
        {
            wcout << "调用GetConsoleTitle异常,错误码"<< GetLastError() << endl;
            delete [] console_title;
            return 0;
        }
        wcout << _T("控制台标题栏") << console_title << endl;
        SetConsoleTitle(_T("ShowConsoleInfo"));
        wcout << endl << endl;
    
        HANDLE stdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
        if (INVALID_HANDLE_VALUE == stdOutHandle)
        {
            wcout << "调用GetStdHandle失败,错误码" << GetLastError() << endl;
            return 0;
        }
    
        // 获取屏幕缓冲信息
        CONSOLE_SCREEN_BUFFER_INFO console_screen_buff_info;
        memset(&console_screen_buff_info, 0, sizeof(CONSOLE_SCREEN_BUFFER_INFO));
        if (GetConsoleScreenBufferInfo(stdOutHandle, &console_screen_buff_info))
        {
            wcout << _T("屏幕缓冲大小:列数x行数") << console_screen_buff_info.dwSize.X
                << _T("x") << console_screen_buff_info.dwSize.Y << endl;
            wcout << _T("控制台光标位置(x,y):(") << console_screen_buff_info.dwCursorPosition.X
                << _T(",") << console_screen_buff_info.dwCursorPosition.Y << _T(")") << endl;
            wcout << _T("屏幕缓冲字符属性: ") << std::hex << console_screen_buff_info.wAttributes << endl;
            wcout << _T("屏幕缓冲显示窗口位置left:") << console_screen_buff_info.srWindow.Left 
                << _T(" Right:") << console_screen_buff_info.srWindow.Right 
                << _T(" Top:") << console_screen_buff_info.srWindow.Top
                << _T(" Bottom:") << console_screen_buff_info.srWindow.Bottom <<endl;
            wcout << _T("最大显示窗口大小:") << console_screen_buff_info.dwMaximumWindowSize.X
                << _T("x") << console_screen_buff_info.dwMaximumWindowSize.Y << endl;
        }
    
        // 下面设置需要将控制台屏幕缓冲窗口下移三行,用于移除关于设置控制台标题提示
        SMALL_RECT sRect;
        sRect.Left = 0;
        sRect.Right = 0;
        sRect.Top = 3;
        sRect.Bottom = 3;
        if (!SetConsoleWindowInfo(stdOutHandle, FALSE, &sRect))
        {
            wcout << "调用SetConsoleWindowInfo失败,错误码" << GetLastError() << endl;
            return 0;
        }
        // 以上代码是控制台滚屏的一种实现方式,可考虑扩展下
        // msdn上的例子
        // http://msdn.microsoft.com/en-us/library/windows/desktop/ms685118(v=vs.85).aspx
    
        // 可使用SetConsoleScreenBufferSize来设置屏幕缓冲大小
    
        return 0;
    }
    View Code

    实例b GUI程序创建控制台及销毁

    可以使用本实例的方法,在GUI程序中使用控制台调试跟踪相关问题。

    最终运行效果如下图,GUI程序界面+后台的Console界面

    代码如下:

    // GUI程序创建控制台示例代码,1_bGuiAllocConsole
    // GUI程序可以使用AttachConsole函数与某个已经存在的控制台关联,需要预先知道该进程pid
    // 本demo展示了如何使用Alloc创建控制台,主要代码位于WM_CREATE、WM_DESTORY消息处理中
    // 编译建议使用visual studio 2010 类型win32,使用unicode编码
    
    #include <iostream>
    
    // 全局变量:
    HINSTANCE hInst;                                // 当前实例
    TCHAR szTitle[] = _T("win32Test");// 标题栏文本
    TCHAR szWindowClass[]= _T("WIN32TEST");// 主窗口类名
    
    // 此代码模块中包含的函数的前向声明:
    ATOM                MyRegisterClass(HINSTANCE hInstance);
    BOOL                InitInstance(HINSTANCE, int);
    LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
    
    int APIENTRY _tWinMain(HINSTANCE hInstance,
                         HINSTANCE hPrevInstance,
                         LPTSTR    lpCmdLine,
                         int       nCmdShow)
    {
        UNREFERENCED_PARAMETER(hPrevInstance);
        UNREFERENCED_PARAMETER(lpCmdLine);
        std::wcout.imbue(std::locale("chs"));
    
        MyRegisterClass(hInstance);
    
        // 执行应用程序初始化:
        if (!InitInstance (hInstance, nCmdShow))
        {
            return FALSE;
        }
    
        MSG msg;
        // 主消息循环:
        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        return (int) msg.wParam;
    }
    
    
    
    //
    //  函数: MyRegisterClass()
    //
    //  目的: 注册窗口类。
    //
    //  注释:
    //
    //    仅当希望
    //    此代码与添加到 Windows 95 中的“RegisterClassEx”
    //    函数之前的 Win32 系统兼容时,才需要此函数及其用法。调用此函数十分重要,
    //    这样应用程序就可以获得关联的
    //    “格式正确的”小图标。
    //
    ATOM MyRegisterClass(HINSTANCE hInstance)
    {
        WNDCLASSEX wcex;
    
        wcex.cbSize = sizeof(WNDCLASSEX);
    
        wcex.style            = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc    = WndProc;
        wcex.cbClsExtra        = 0;
        wcex.cbWndExtra        = 0;
        wcex.hInstance        = hInstance;
        wcex.hIcon            = NULL;
        wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground    = (HBRUSH)(COLOR_WINDOW+1);
        wcex.lpszMenuName    = NULL;
        wcex.lpszClassName    = szWindowClass;
        wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
    
        return RegisterClassEx(&wcex);
    }
    
    //
    //   函数: InitInstance(HINSTANCE, int)
    //
    //   目的: 保存实例句柄并创建主窗口
    //
    //   注释:
    //
    //        在此函数中,我们在全局变量中保存实例句柄并
    //        创建和显示主程序窗口。
    //
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
       HWND hWnd;
    
       hInst = hInstance; // 将实例句柄存储在全局变量中
    
       hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
    
       if (!hWnd)
       {
          return FALSE;
       }
    
       ShowWindow(hWnd, nCmdShow);
       UpdateWindow(hWnd);
    
       return TRUE;
    }
    
    //
    //  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
    //
    //  目的: 处理主窗口的消息。
    //
    //  WM_COMMAND    - 处理应用程序菜单
    //  WM_PAINT    - 绘制主窗口
    //  WM_DESTROY    - 发送退出消息并返回
    //
    //
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        PAINTSTRUCT ps;
        HDC hdc;
        static RECT rcText = {10,10,300,100};
    
        switch (message)
        {
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps);
            // TODO: 在此添加任意绘图代码...
            DrawText(hdc, _T("这是一个Win32测试程序!"), -1, &rcText, DT_CENTER);
            EndPaint(hWnd, &ps);
            break;
        case WM_CREATE:
            if (!AllocConsole())
            {
                MessageBox(hWnd, _T("创建控制台失败"), _T("初始化错误"), MB_OK);
            }
            SetConsoleTitle(_T("win32AllocConsoleTest"));
            // 这里重定向标准输出到控制台上
            // 如果不做重定向就需要使用WriteConsole或者_cprintf函数
            freopen( "CONOUT$", "w+t", stdout );// 申请写
            //freopen( "CONIN$", "r+t", stdin ); // 申请读
    
            std::wcout << _T("创建控制台并成功初始化") << std::endl;
            break;
        case WM_DESTROY:
            FreeConsole();
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }
    View Code

      实例c 控制台字符属性详细用法介绍

     函数SetConsoleTextAttribute可设置控制台显示的字符属性。支持一下设置:

    AttributeMeaning
    FOREGROUND_BLUE 前景色,包含蓝色
    FOREGROUND_GREEN 前景色,包含绿色
    FOREGROUND_RED 前景色,包含红色
    FOREGROUND_INTENSITY 前景色,加亮
    BACKGROUND_BLUE 背景色,包含蓝色
    BACKGROUND_GREEN 背景色,包含绿色
    BACKGROUND_RED 背景色,包含红色
    BACKGROUND_INTENSITY 背景色,加亮
    COMMON_LVB_LEADING_BYTE 多字节码的Leading byte.
    COMMON_LVB_TRAILING_BYTE 多字节码的Trailing byte.
    COMMON_LVB_GRID_HORIZONTAL 顶部水平网格(上划线)
    COMMON_LVB_GRID_LVERTICAL 左竖直网格
    COMMON_LVB_GRID_RVERTICAL 右竖直网格
    COMMON_LVB_REVERSE_VIDEO 前景色背景色反转
    COMMON_LVB_UNDERSCORE 下划线

    示例代码如下: 

    // 控制台字体属性设置示例 ChangeTextAttrDemo
    // 设置前景色、背景色、unicode下划线、删除线等
    // 建议使用vs2005以上版本编译,unicode编码
    
    #include <windows.h>
    #include <iostream>
    using std::wcout;
    using std::endl;
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        // 输出中文
        std::wcout.imbue(std::locale("chs"));
    
        // 设置控制台标题栏
        SetConsoleTitle(_T("ChangeTextAttrDemo"));
    
        HANDLE stdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
        if (INVALID_HANDLE_VALUE == stdOutHandle)
        {
            wcout << L"调用GetStdHandle失败,错误码" << GetLastError() << endl;
            return 0;
        }
    
        // 默认背景色黑色,前景色白色
        wcout << _T("默认背景色,ABCabc123*&@!") << endl << endl;
    
        // 红色前景色,绿色背景色
        SetConsoleTextAttribute(stdOutHandle, FOREGROUND_RED|BACKGROUND_GREEN);
        wcout << _T("设置红色前景色,绿色背景色") << endl;
        wcout << _T("测试字符串,ABCabc123*&@!") << endl << endl;
    
        // 前景色加亮对比
        SetConsoleTextAttribute(stdOutHandle, 
            FOREGROUND_RED|BACKGROUND_GREEN|FOREGROUND_INTENSITY);
        wcout << _T("设置红色前景色,绿色背景色,前景色加亮对比") << endl;
        wcout << _T("测试字符串,ABCabc123*&@!") << endl << endl;
    
        // 设置为默认字体属性+上划线
        SetConsoleTextAttribute(stdOutHandle, 
            FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN|COMMON_LVB_GRID_HORIZONTAL);
        wcout << _T("设置为默认字体属性+顶部水平网格") << endl;
        wcout << _T("测试字符串,ABCabc123*&@!") << endl << endl;
    
        // 设置为蓝色前景+下划线
        SetConsoleTextAttribute(stdOutHandle, 
            FOREGROUND_BLUE|COMMON_LVB_UNDERSCORE);
        wcout << _T("设置为蓝色前景+下划线") << endl;
        wcout << _T("测试字符串,ABCabc123*&@!") << endl << endl;
    
        // 设置为绿色前景+左划线
        SetConsoleTextAttribute(stdOutHandle, 
            FOREGROUND_GREEN|COMMON_LVB_GRID_LVERTICAL);
        wcout << _T("设置为绿色前景+左竖网格") << endl;
        wcout << _T("  测试字符串,ABCabc123*&@!") << endl << endl;
    
        // 设置为绿色背景+右划线
        SetConsoleTextAttribute(stdOutHandle, 
            BACKGROUND_GREEN|COMMON_LVB_GRID_RVERTICAL);
        wcout << _T("设置为绿色背景+右竖网格") << endl;
        wcout << _T("  测试字符串,ABCabc123*&@!") << endl << endl;
    
        SetConsoleTextAttribute(stdOutHandle, 
            FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN);
        return 0;
    }
    View Code

    如果需要彩色的控制台,建议关注下代码中的各种效果。上述宏可组合使用,支持8种前景色和背景色,输出效果如下图:

     

    实例d 控制台光标位置、样式及位置

    本实例介绍控制台下光标的样式获取及设置,光标位置的设置等。

    代码如下。(具体效果需要自己编译代码查看) 

    // 控制台光标样式获取、设置,CursorAttrDemo
    // 1. 光标属性获取及设置
    // 2. 光标位置获取及设置
    // 建议使用vs2005以上版本编译,unicode编码
    
    #include <windows.h>
    #include <iostream>
    using std::wcout;
    using std::endl;
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        // 输出中文
        std::wcout.imbue(std::locale("chs"));
    
        // 设置控制台标题栏
        SetConsoleTitle(_T("CursorAttrDemo"));
    
        HANDLE stdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
        if (INVALID_HANDLE_VALUE == stdOutHandle)
        {
            wcout << L"调用GetStdHandle失败,错误码" << GetLastError() << endl;
            return 0;
        }
    
        CONSOLE_CURSOR_INFO cursor_info;
        memset(&cursor_info, 0, sizeof(cursor_info));
        if (GetConsoleCursorInfo(stdOutHandle, &cursor_info))
        {
            wcout << _T("光标可见:") << (cursor_info.bVisible ? _T("") : _T("")) << endl;
            wcout << _T("光标占位比例 :") << cursor_info.dwSize << _T("%") << endl;
    
            cursor_info.bVisible = TRUE;
            cursor_info.dwSize = 100;
            SetConsoleCursorInfo(stdOutHandle, &cursor_info);
            wcout << _T("设置100%光标占比") << endl;
            int x;
            std::cin >> x;
    
            cursor_info.dwSize = 50;
            SetConsoleCursorInfo(stdOutHandle, &cursor_info);
            wcout << _T("设置50%光标占比") << endl;
        }
    
        // 获取光标位置使用GetConsoleScreenBufferInfo函数
        // 直接输出定位到第二行
        COORD cursor_pos = {0, 8};
        SetConsoleCursorPosition(stdOutHandle, cursor_pos);
        
        return 0;
    }
    View Code

    注:本文涉及所有代码可使用Git直接下载:https://git.oschina.net/Tocy/SampleCode.git。实际代码位于Console目录下,以1_开头的cpp文件。

    本文作者:Tocy

    版权所有,请勿用于商业用途,转载请注明原文地址。本人保留所有权利。

  • 相关阅读:
    Framework 7 日历插件改成Picker 模式
    DataTables 表格固定栏使用方法
    DIV内滚动条滚动到指定位置
    js类型转换 之 转字符串及布尔类型
    js类型转换 之 转数字类型
    UrlRewriter.dll伪静态实现二级域名泛解析
    sql server2005内存过高释放方法
    HttpContext.Current.RewritePath方法重写URL
    sql2005数据库转换成sql2000
    asp.net获取当前页面源码并生成静态页面
  • 原文地址:https://www.cnblogs.com/tocy/p/console_intro_sample.html
Copyright © 2020-2023  润新知