文档章节

控制台基础概念实例

Tocy
 Tocy
发布于 2015/09/09 22:15
字数 2479
阅读 8
收藏 0

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

以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可设置控制台显示的字符属性。支持一下设置:

Attribute Meaning
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

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

© 著作权归作者所有

共有 人打赏支持
Tocy
粉丝 27
博文 50
码字总数 59635
作品 0
海淀
程序员
私信 提问
Java多线程高并发学习笔记(二)——深入理解ReentrantLock与Condition

锁的概念 从jdk发行1.5版本之后,在原来synchronize的基础上,增加了重入锁ReentrantLock。 本文就不介绍synchronize了,有兴趣的同学可以去了解一下,本文重点介绍ReentrantLock。 锁是什么...

诸葛西门
2017/09/18
0
0
捷讯分享阿里云服务器ECS如何升降配置

我们在日常用阿里云产品的时候都知道云服务器有升降配的操作,很大程度适应了大部分客户的需求。今天阿里云湖北授权服务中心的小编就跟大家简单的聊聊如何升降云服务器的配置。所谓升降配就是...

捷讯技术17
2018/08/24
0
0
使用 intellijIDEA 创建 maven 工程进行 Spring ioc 测试

使用 intellijIDEA 创建 maven 工程进行 Spring ioc 测试 ioc 概念 控制反转(Inversion of Control,缩写为IOC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其...

希希里之海
2018/08/18
0
0
OPNET网络仿真分析-目 录

版权声明:本书为作者版权所有,仅用于学习,请勿商用 OPENT网络仿真分析 (作者:栾鹏、陈玓玏) OPNET网络仿真分析-目录 OPNET网络仿真分析-电子版 目 录 第一章 OPENT基础 1.1、OPNET简介...

luanpeng825485697
2017/09/14
0
0
Payara Server 5 发布,Java EE 7 应用服务器

Payara Server 5 此版本包括几项可用性改进,使Payara Server&Payara Micro的架构更具创新性,微服务就绪,云原生并针对生产部署进行了优化。 更新内容: 1.在Payara Server 5中,域中的所有...

周其
2018/03/20
834
2

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周六乱弹 —— 我都想和他们组成一个家庭了

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @Sharon啊 :分享王菲的单曲《流年》有生之年狭路相逢终不能幸免,手心突然忽然长出纠缠的曲线。 《流年》- 王菲 手机党少年们想听歌,请使劲...

小小编辑
今天
176
6
CentOS7利用systemctl添加自定义系统服务

CentOS7的服务systemctl脚本存放在:/usr/lib/systemd/,有系统(system)和用户(user)之分,需要开机不登陆就能运行的程序,存在系统服务里,即:/usr/lib/systemd/system目录下. CentOS7的每...

linuxprobe16
今天
1
0
RabbitMQ入门

RabbitMQ是一个由erlang开发的基于AMQP(Advanced Message Queue)协议的开源实现。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面都非常的优秀。是当前最主流的消息中间...

watermelon11
今天
19
0
今天的学习

自动加载:方法一 function __autoload( $className ){在这里,完成加载B这个类文件的工作。}class A{} //这是一个类$a1 = new A(); //这里没有自动加载的发生,因为A这个类...

墨冥
今天
4
0
印刷工艺步骤

印刷厂从收到订单到交付整个流程,一般涉及到以下步骤 1.设计(经过软件如cdr,psd,ai等等设计需要印刷的名片,宣传单,画册等物料); 2.排版拼版(在电脑软件这区域完成); 3.出版、出硫...

focusone
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部