IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【C/C++】Windows控制台API基本使用 -> 正文阅读

[C++知识库]【C/C++】Windows控制台API基本使用

前言

??本文章所使用的一些API为旧版API,建议使用其它方案代替它们。
??本文章多有些纰漏,若发现错误请在评论区指正。
??注: 文章内所有代码均在VS2019下编译通过。

一、控制台缓冲区大小

一、获取缓冲区大小

??GetConsoleScreenBufferInfo 可以获取到控制台窗口的一些信息。

BOOL WINAPI GetConsoleScreenBufferInfo(
  _In_  HANDLE                      hConsoleOutput,           // 输出句柄
  _Out_ PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo // 缓冲区信息结构体
);

??PCONSOLE_SCREEN_BUFFER_INFO 实际上是一个指针,可以使用_CONSOLE_SCREEN_BUFFER_INFO 或 CONSOLE_SCREEN_BUFFER_INFO 替代它。此结构体的原型为:

typedef struct _CONSOLE_SCREEN_BUFFER_INFO {
  COORD      dwSize;              // 缓冲区大小
  COORD      dwCursorPosition;    // 控制台屏幕缓冲区中光标的列和行坐标
  WORD       wAttributes;
  SMALL_RECT srWindow;            // 显示窗口左上角和右下角的控制台屏幕缓冲区的坐标(即窗口大小)
  COORD      dwMaximumWindowSize; // 在给定当前屏幕缓冲区大小和字体和屏幕大小的情况下,它包含控制台窗口的最大大小(字符列和行)
} CONSOLE_SCREEN_BUFFER_INFO;

??此结构体同样包含缓冲区光标位置的信息,在获取光标位置时可以使用此结构体。
??下方代码将会输出缓冲区大小。

#include <stdio.h>
#include <Windows.h>

int main(int argc, char* argv[]) {
	// 获取输出句柄
	HANDLE outputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_SCREEN_BUFFER_INFO info;

	GetConsoleScreenBufferInfo(outputHandle, &info);

	printf("缓冲区大小: x=%hd, y=%hd\n", info.dwSize.X, info.dwSize.Y);

	return 0;
}

Windows10中
Win7下

二、设置缓冲区大小

??(旧版API)SetConsoleScreenBufferSize 可以修改控制台的缓冲区大小。

WINBASEAPI
BOOL
WINAPI
SetConsoleScreenBufferSize(
    _In_ HANDLE hConsoleOutput, // 输出句柄
    _In_ COORD dwSize           // 新缓冲区大小
    );

??此函数接受一个 COORD 结构体 作为参数,其原型为:

typedef struct _COORD {
    SHORT X;
    SHORT Y;
} COORD, *PCOORD;

??下方代码将会设置缓冲区大小为115×40个字符。

#include <stdio.h>
#include <Windows.h>

int main(int argc, char* argv[]) {
	// 获取输出句柄
	HANDLE outputHandle = GetStdHandle(STD_OUTPUT_HANDLE);

	// 定义大小
	COORD size = { 115, 40 };

	// 应用
	SetConsoleScreenBufferSize(outputHandle, size);
	SetConsoleScreenBufferSize(outputHandle, size);

	return 0;
}

效果
??不建议使用此API。

三、更详细的结构体

??CONSOLE_SCREEN_BUFFER_INFOEX 结构体能够记录更多的控制台信息,并且也有与之匹配的获取(GetConsoleScreenBufferInfoEx)和设置(SetConsoleScreenBufferInfoEx)函数。多数情况下,笔者更推荐使用 CONSOLE_SCREEN_BUFFER_INFOEX,因为 CONSOLE_SCREEN_BUFFER_INFOEX 拥有与之匹配的函数,而 _CONSOLE_SCREEN_BUFFER_INFO 和 CONSOLE_SCREEN_BUFFER_INFO 仅有一个获取函数(GetConsoleScreenBufferInfo),所以,能用就用吧。
??下面的代码演示了如何使用 CONSOLE_SCREEN_BUFFER_INFOEX

#include <stdio.h>
#include <Windows.h>

int main(int argc, char* argv[]) {
	// 获取输出句柄
	HANDLE outputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_SCREEN_BUFFER_INFOEX info;
	info.cbSize = sizeof(info);        // 不要忘记指定结构体大小

	GetConsoleScreenBufferInfoEx(outputHandle, &info);
	printf(
		"缓冲区大小: x=%hd, y=%hd\n"
		"窗口大小: x=%hd, y=%hd\n"
		"光标坐标: x=%hd, y=%hd\n"
		, info.dwSize.X, info.dwSize.Y, info.srWindow.Right + 1, info.srWindow.Bottom + 1, info.dwCursorPosition.X, info.dwCursorPosition.Y);

	return 0;
}

二、窗口大小

一、获取窗口大小

??对于这种需求,CONSOLE_SCREEN_BUFFER_INFOEX 可以解决一切问题。但现在这里将依然使用 GetConsoleScreenBufferInfo 函数获取窗口大小。下面代码将会演示此功能。

#include <stdio.h>
#include <Windows.h>

int main(int argc, char* argv[]) {
	// 获取输出句柄
	HANDLE outputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_SCREEN_BUFFER_INFO info;

	GetConsoleScreenBufferInfo(outputHandle, &info);

	printf("窗口大小: x=%hd, y=%hd\n", info.srWindow.Right + 1, info.srWindow.Bottom + 1);

	return 0;
}

Win7+Win10
??注: srWindow会把0也算进窗口大小内,所以需要将结果加1得到正确的数字。
??使用 CONSOLE_SCREEN_BUFFER_INFOEX 的样例在第一节的第三小节。

二、设置窗口大小

??(旧版API)SetConsoleWindowInfo 可以做到这一点。
??查阅 Microsoft Docs 了解此函数的参数。
??下面的代码可以实现此功能。

#include <stdio.h>
#include <Windows.h>

int main(int argc, char* argv[]) {
	// 获取输出句柄
	HANDLE outputHandle = GetStdHandle(STD_OUTPUT_HANDLE);

	SMALL_RECT winSize = {0, 0};

	winSize.Right = 20 - 1;
	winSize.Bottom = 10 - 1;

	SetConsoleWindowInfo(outputHandle, 1, &winSize);
	SetConsoleWindowInfo(outputHandle, 1, &winSize);

	printf("窗口大小被改变。\n");

	return 0;
}

三、光标位置

一、获取光标位置

??第一节的第三小节的示例代码演示了如何获取光标位置。而 _CONSOLE_SCREEN_BUFFER_INFO 和 CONSOLE_SCREEN_BUFFER_INFO 也可以获取光标位置。
??_CONSOLE_SCREEN_BUFFER_INFO 和 CONSOLE_SCREEN_BUFFER_INFO 的 dwCursorPosition 成员规定了光标的坐标。 CONSOLE_SCREEN_BUFFER_INFOEX 也有该成员。下面代码演示了如何使用 _CONSOLE_SCREEN_BUFFER_INFO 和 CONSOLE_SCREEN_BUFFER_INFO 的 dwCursorPosition 成员获取光标信息。

#include <stdio.h>
#include <Windows.h>

int main(int argc, char* argv[]) {
	// 获取输出句柄
	HANDLE outputHandle = GetStdHandle(STD_OUTPUT_HANDLE);

	CONSOLE_SCREEN_BUFFER_INFO info;
	GetConsoleScreenBufferInfo(outputHandle, &info);

	printf("光标位置: (%hd,%hd)\n", info.dwCursorPosition.X, info.dwCursorPosition.Y);

	return 0;
}

二、设置光标位置

??Windows 10 支持特殊 ANSI 序列,可以直接输出 ANSI 转义序列移动光标。

#include <stdio.h>

int main(int argc, char* argv[]) {

	//    光标即将前往的坐标
	short x = 5, y = 5;
	printf("\x1b[%hd;%hdH", y + 1, x);
	printf("Hello world!\n");

	return 0;
}


??使用 (旧版API)SetConsoleCursorPosition 函数可以在新旧版控制台中工作。如果程序需要跨平台,最好不使用此 API。

四、设置光标是否显示

一、旧版API

??(旧版API)GetConsoleCursorInfo(旧版API)SetConsoleCursorInfo(旧版结构)CONSOLE_CURSOR_INFO 搭配可以设置光标信息。下方代码演示了这项工作。

#include <stdio.h>
#include <Windows.h>

int main(int argc, char* argv[]) {
	// 获取句柄
	HANDLE outputHandle = GetStdHandle(STD_OUTPUT_HANDLE);

	// 获取光标信息
	_CONSOLE_CURSOR_INFO cursorInfomations;
	GetConsoleCursorInfo(outputHandle, &cursorInfomations);
	// 将光标设为不可见
	cursorInfomations.bVisible = 0;
	// 应用光标信息
	SetConsoleCursorInfo(outputHandle, cursorInfomations);

	printf("光标被 API 隐藏了。\n");

	return 0;
}


??此 API 建议在旧版控制台使用,最好不在新版控制台用。

二、新版控制台的 ANSI 转义序列

??下方代码将通过 ANSI 转义序列显示或隐藏光标。

#include <stdio.h>
#include <Windows.h>

void setCursorVisible(bool status) {
	// \033[?25h  显示光标
	// \033[?25l  隐藏光标
	printf("\033[?25%c", (status ? 'h' : 'l'));
}

int main(int argc, char* argv[]) {
	setCursorVisible(1); // 显示
	setCursorVisible(0); // 隐藏

	return 0;
}

三、新版控制台特性

??在 Win10 新版控制台中最好不要隐藏光标,因为不管使用 API 隐藏还是 ANSI 转义序列隐藏,用鼠标拖拽窗口改变大小都会导致光标重新显示。下方GIF演示了新版控制台的特性。

五、通过代码打开 ANSI 转义序列

??Windows 10 新版控制台可以手动开启 ANSI 转义序列,下方代码将会演示此功能,重点在于enabledANSI函数。

#include <stdio.h>
#include <Windows.h>

//   启用 ANSI
bool enabledANSI(HANDLE outputHandle) {
    if (outputHandle == INVALID_HANDLE_VALUE) { return 0; }

    DWORD dwMode_Out = 0;
    // 获取当前控制台模式
    if (!GetConsoleMode(outputHandle, &dwMode_Out)) { return 0; }

	// 启用设置
    dwMode_Out |= ENABLE_PROCESSED_OUTPUT; dwMode_Out |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
    dwMode_Out |= DISABLE_NEWLINE_AUTO_RETURN;

    // 设置
    if (!SetConsoleMode(outputHandle, dwMode_Out)) { return 0; }

    return 1;
}

int main(int argc, char* argv[]) {
    bool status = enabledANSI(GetStdHandle(STD_OUTPUT_HANDLE));

    printf("ANSI 转义序列打开....。\b\b\b\b\b\b");

    if (status) {
        printf("成功");
    } else {
        printf("失败");
    }
    printf("\n");

	return 0;
}

??此程序在笔者的系统上成功运行。

六、控制台编码

一、设置输出编码

??SetConsoleOutputCP 函数可以修改当前控制台输出的代码页,其接受一个 UINT(unsigned int) 作为参数。

BOOL WINAPI SetConsoleOutputCP(
  _In_ UINT wCodePageID       // 新代码页
);

??下面的代码将会演示此函数的功能。

#include <stdio.h>
#include <Windows.h>

int main(int argc, char* argv[]) {
	SetConsoleOutputCP(437);

	printf("English.\n");
	printf("中文。\n");
	printf("日本語。\n");

	return 0;
}


??代码页437是美国英语的代码页,其只能显示英语字符(准确来说是 ASCII 码内的字符),所以在输出其它语种时就会出现乱码,如上图所示。
??目前可用的代码页有:

代码页描述
437美国英语
850多语言
857土耳其语
866俄语
869现代希腊语
936简体中文

??定义常量以区分这些代码页。

//C
#define US           437
#define MULTILINGUAL 850
#define TURKISH      857
#define RUSSIA       866
#define MODERNGREEK  869
#define CHINESE      936
//C++
unsigned short const US           = 437,
                     MULTILINGUAL = 850,
                     TURKISH      = 857,
                     RUSSIA       = 866,
                     MODERNGREEK  = 869,
                     CHINESE      = 936;

??GetConsoleOutputCP 可以获取当前活动代码页。下方代码将会演示此功能。

#include <stdio.h>
#include <Windows.h>

int main(int argc, char* argv[]) {
	printf("Code: %hd\n", GetConsoleOutputCP());

	return 0;
}

二、设置输入编码

??SetConsoleCP 函数可以设置输入编码。Microsoft Docs 这么描述它:

“设置与调用进程关联的控制台使用的输入代码页。 控制台使用其输入代码页将键盘输入转换为相应的字符值。”

??Microsoft Docs 明确说明了此 API 用于设置输入的字符的代码页。下方代码将会演示此功能。

// VS2019下需要定义此宏
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <Windows.h>

int main(int argc, char* argv[]) {
	// 修改输入代码页
	SetConsoleCP(437);

	printf("输入一串字符串: ");
	char getString[20] = "";
	scanf("%[^\n]", getString);

	printf("输入的内容是:\n%s\n", getString);

	return 0;
}


??虽然控制台在接受字符串时显示了中文,但是在输出该字符串时却出现了乱码,而控制台还是可以输出中文,这就是 SetConsoleCP 的作用,更改输入内容的代码页。
??与 GetConsoleOutputCP 一样,GetConsoleCP 也能获取活动的代码页,但是获取的是活动的输入代码页的代码。

七、修改控制台文本样式

一、使用API

??SetConsoleTextAttribute 函数可以更改接下来输出的文字的样式,通过下方代码您就可以了解其作用。

#include <stdio.h>
#include <Windows.h>

int main(int argc, char* argv[]) {
    HANDLE outputHandle = GetStdHandle(STD_OUTPUT_HANDLE);

    SetConsoleTextAttribute(outputHandle, 0xf0);
    printf("白底黑字\n");

    SetConsoleTextAttribute(outputHandle, 0x4e);
    printf("红底黄字\n");

    SetConsoleTextAttribute(outputHandle, 0x1a);
    printf("蓝底绿字\n");
    
    SetConsoleTextAttribute(outputHandle, 0x801a);
    printf("蓝底绿字 + 下划线\n");

    SetConsoleTextAttribute(outputHandle, 0x4e | COMMON_LVB_UNDERSCORE);
    printf("红底黄字 + 下划线\n");

    SetConsoleTextAttribute(outputHandle, 0x07);
    printf("黑底灰字\n");

	return 0;
}


??此 API 在新旧版控制台均能工作。
??Windows 还提供了其它的样式。

下方内容摘自 consoleapi2.h

//
// Attributes flags:
//

#define FOREGROUND_BLUE      0x0001 // text color contains blue.
#define FOREGROUND_GREEN     0x0002 // text color contains green.
#define FOREGROUND_RED       0x0004 // text color contains red.
#define FOREGROUND_INTENSITY 0x0008 // text color is intensified.
#define BACKGROUND_BLUE      0x0010 // background color contains blue.
#define BACKGROUND_GREEN     0x0020 // background color contains green.
#define BACKGROUND_RED       0x0040 // background color contains red.
#define BACKGROUND_INTENSITY 0x0080 // background color is intensified.
#define COMMON_LVB_LEADING_BYTE    0x0100 // Leading Byte of DBCS
#define COMMON_LVB_TRAILING_BYTE   0x0200 // Trailing Byte of DBCS
#define COMMON_LVB_GRID_HORIZONTAL 0x0400 // DBCS: Grid attribute: top horizontal.
#define COMMON_LVB_GRID_LVERTICAL  0x0800 // DBCS: Grid attribute: left vertical.
#define COMMON_LVB_GRID_RVERTICAL  0x1000 // DBCS: Grid attribute: right vertical.
#define COMMON_LVB_REVERSE_VIDEO   0x4000 // DBCS: Reverse fore/back ground attribute.
#define COMMON_LVB_UNDERSCORE      0x8000 // DBCS: Underscore.

#define COMMON_LVB_SBCSDBCS        0x0300 // SBCS or DBCS flag.

二、使用ANSI转义序列

??下方代码将会演示使用 ANSI 转义序列输出多样式文本。

#include <stdio.h>

int main(int argc, char* argv[]) {
    printf("\x1b[31mText\x1b[0m\n");
    printf("\x1b[31;1mText\x1b[0m\n");
    printf("\x1b[31;1;47;4mText\x1b[0m\n");
    printf("\x1b[31;1;7mText(反色)\x1b[0m\n");

	return 0;
}


??这种写法在旧版控制台无效。

八、控制台窗口标题

一、获取控制台窗口标题

??GetConsoleTitle 函数可以获取窗口的标题。其原型为:

WINBASEAPI DWORD WINAPI GetConsoleTitleA(
    _Out_writes_(nSize) LPSTR lpConsoleTitle,
    _In_ DWORD nSize
    );

WINBASEAPI DWORD WINAPI GetConsoleTitleW(
    _Out_writes_(nSize) LPWSTR lpConsoleTitle,
    _In_ DWORD nSize
    );
#ifdef  UNICODE
#define GetConsoleTitle  GetConsoleTitleW
#else
#define GetConsoleTitle  GetConsoleTitleA
#endif // !UNICODE

??上方截取了 consoleapi2.h 中有关 (旧API)GetConsoleTitle 的部分。在宏 UNICODE 存在时,GetConsoleTitle 为 GetConsoleTitlteW,否则为 GetConsoleTitleA。GetConsoleTitleW 是 GetConsoleTitle宽字符版,而 GetConsoleTitleA 是摘字符版。在源文件中取消宏 UNICODE 就能使用 ANSI 版。下面的代码演示了如何正确使用 GetConsoleTitleA 和 GetConsoleTitleW。

#include <stdio.h>
#include <wchar.h>
#include <Windows.h>

int main(int argc, char* argv[]) {
	char    titleA[30]    =  "";
	wchar_t titleW[30]    = L"";

	GetConsoleTitle (titleW, 30);
	GetConsoleTitleA(titleA, 30);

	printf("titleA = %s\n"
		   "titleW = %ls\n",
		   titleA, titleW);

	return 0;
}


??Windows API 定义了不同的字符串类型,下方截取了 GetConsoleTitle 及其宽字符和窄字符版所用到的类型的定义。

// 截取自 Winnt.h
typedef _Null_terminated_ CHAR *NPSTR, *LPSTR, *PSTR;
typedef _Null_terminated_ WCHAR *NWPSTR, *LPWSTR, *PWSTR;

二、设置窗口标题

??(旧API)SetConsoleTitle 可以设置窗口标题,与 (旧API)GetConsoleTitle 一样,它也分宽字符和窄字符两种版本。下方代码演示了如何使用这些 API。

#include <stdio.h>
#include <wchar.h>
#include <Windows.h>

int main(int argc, char* argv[]) {
	char    titleA[] =  "titleA";
	wchar_t titleW[] = L"titleW";

	SetConsoleTitleA(titleA);
	printf("TitleA.\n");
	getchar();

	// 或在宏 UNICODE 存在时使用 SetConsoleTitle(titleW);
	SetConsoleTitleW(titleW);
	printf("TitleW.\n");


	return 0;
}

三、获取控制台原始标题

??(旧API)GetConsoleOriginalTitle 函数可以获取控制台的原始标题。此函数也分宽字符和窄字符两种版本,其参数与 (旧API)GetConsoleTitle 的参数一样。下面的程序将会演示其功能。

#include <iostream>
#include <Windows.h>

int main(int argc, char* argv[]) {
    using std::cout;

    HANDLE outputHandle = GetStdHandle(STD_OUTPUT_HANDLE);

    // 设置新标题
    SetConsoleTitleA("新标题");

    char originalTitle[50] = "";
    GetConsoleOriginalTitleA(originalTitle, 50);

    cout << "原始标题: " << originalTitle << std::endl;

	return 0;
}


??(旧API)GetConsoleOriginalTitle(旧API)SetConsoleTitle 后调用,但 (旧API)GetConsoleOriginalTitle 获取的标题不是现在的新标题,而是开始的标题。

九、置顶窗口

??SetWindowPos 函数可以实现此功能。其原型为:

// 摘自 WinUser.h
WINUSERAPI BOOL WINAPI SetWindowPos(
    _In_ HWND hWnd,                // 要操作的窗口
    _In_opt_ HWND hWndInsertAfter,
    _In_ int X,                    // 窗口新的位置的X轴
    _In_ int Y,                    // 窗口新的位置的Y轴
    _In_ int cx,                   // 窗口的新宽度
    _In_ int cy,                   // 窗口的新高度
    _In_ UINT uFlags               // 附加属性;

??uFlags将决定 X、Y、cx 和 cy 四个参数是否生效。下方代码演示了如何置顶和不置顶窗口。

#include <stdio.h>
#include <Windows.h>

int main(int argc, char* argv[]) {
	//   获取控制台窗口的句柄
	HWND window = GetConsoleWindow();

	// 置顶窗口
	SetWindowPos(window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

	// 不置顶窗口
	SetWindowPos(window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

	/*
	SetWindowPos 函数的 uFlags 参数如果包括 SWP_NOMOVE,则 X 和 Y 参数不生效,窗口就不会移动。
	如果包含 SWP_NOSIZE,则窗口大小不会被重新定义。
	*/
	return 0;
}

??上述代码中 window 是一个控制台窗口对象(或窗口句柄),GetConsoleWindow 将会返回控制台窗口的句柄。调用 SetWindowPos 时传递了控制台窗口的句柄,则接下来要操作的就是控制台窗口。
??与 GetConsoleWindow 的 API 是 GetForegroundWindow 函数,它也能返回窗口句柄,但其返回的是当前焦点所在的窗口的句柄。

??上图中正在被操作的窗口就是当前焦点所在窗口。
??下方程序演示了置顶当前焦点所在窗口。

#include <stdio.h>
#include <Windows.h>

int main(int argc, char* argv[]) {
	//   获取当前焦点所在窗口的句柄
	HWND window = GetForegroundWindow();

	// 置顶窗口
	SetWindowPos(window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

	return 0;
}

十、移动窗口

??SetWindowPos 依然能够实现此功能。刚才讲过,若 uFlags 包含 SWP_NOMOVE 则指定窗口不会移动,忽略参数 X 和 Y,如果去掉就可以实现移动窗口。下方代码演示了此功能。

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

int main(int argc, char* argv[]) {
	//   获取控制台窗口
	HWND window = GetConsoleWindow();

	// 获取到的坐标
	unsigned int getPos[2] = {0};

	while (1) {
		// 获取 X 轴
		printf("X:");
		scanf("%ud", &getPos[0]);

		// 获取 Y 轴
		printf("Y:");
		scanf("%ud", &getPos[1]);

		getchar();

		// 移动窗口
		SetWindowPos(window, NULL, getPos[0], getPos[1], 0, 0, SWP_NOSIZE);

		printf("\n");
	}

	return 0;
}

十一、(旧API)ScrollConsoleScreenBuffer

??(旧API)ScrollConsoleScreenBuffer 函数可以移动控制台指定区域的文本到制定区域,其原型为:

// 摘自 Microsoft Docs
BOOL WINAPI ScrollConsoleScreenBuffer(
  _In_           HANDLE     hConsoleOutput,
  _In_     const SMALL_RECT *lpScrollRectangle,
  _In_opt_ const SMALL_RECT *lpClipRectangle,
  _In_           COORD      dwDestinationOrigin,
  _In_     const CHAR_INFO  *lpFill
);

Microsoft Docs 这么描述:
参数
hConsoleOutput[in]
控制台屏幕缓冲区的句柄。 句柄必须具有 GENERIC_READ 访问权限。 有关详细信息,请参阅控制台缓冲区安全性和访问权限

lpScrollRectangle [in]
指向 SMALL_RECT 结构的指针,该结构的成员指定要移动的控制台屏幕缓冲区矩形的左上角和右下角坐标。

lpClipRectangle [in,可选]
指向 SMALL_RECT 结构的指针,该结构的成员指定受滚动影响的控制台屏幕缓冲区矩形的左上角和右下角坐标。 此指针可以为 NULL。

dwDestinationOrigin [in]
指定lpScrollRectangle内容的新位置的左上角的oozie.coord.application.path结构,以字符为字符。

lpFill [in]
一个指向 CHAR_INFO 结构的指针,该结构指定用于填充 lpScrollRectangle 和 lpClipRectangle 的交集中的单元格的字符和颜色属性,这些单元格在移动后留空。

十二、清空控制台

??Microsoft Docs 提供了 Cmd 中 cls 指令清除控制台的代码。

摘自 Microsoft Docs

#include <windows.h>

void cls(HANDLE hConsole)
{
   CONSOLE_SCREEN_BUFFER_INFO csbi;
   SMALL_RECT scrollRect;
   COORD scrollTarget;
   CHAR_INFO fill;

   // Get the number of character cells in the current buffer.
   if (!GetConsoleScreenBufferInfo(hConsole, &csbi))
   {
       return;
   }

   // Scroll the rectangle of the entire buffer.
   scrollRect.Left = 0;
   scrollRect.Top = 0;
   scrollRect.Right = csbi.dwSize.X;
   scrollRect.Bottom = csbi.dwSize.Y;

   // Scroll it upwards off the top of the buffer with a magnitude of the entire height.
   scrollTarget.X = 0;
   scrollTarget.Y = (SHORT)(0 - csbi.dwSize.Y);

   // Fill with empty spaces with the buffer's default text attribute.
   fill.Char.UnicodeChar = TEXT(' ');
   fill.Attributes = csbi.wAttributes;

   // Do the scroll
   ScrollConsoleScreenBuffer(hConsole, &scrollRect, NULL, scrollTarget, &fill);

   // Move the cursor to the top left corner too.
   csbi.dwCursorPosition.X = 0;
   csbi.dwCursorPosition.Y = 0;

   SetConsoleCursorPosition(hConsole, csbi.dwCursorPosition);
}

int main(void)
{
   HANDLE hStdout;

   hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

   cls(hStdout);

   return 0;
}

十三、控制台字体

一、获取控制台字体

??若要更改或获取控制台字体,应在代码中添加下方代码块:

struct CONSOLE_FONT
{
	DWORD index;
	COORD dim;
};
typedef BOOL(WINAPI* PROCSETCONSOLEFONT)(HANDLE, DWORD);
typedef BOOL(WINAPI* PROCGETCONSOLEFONTINFO)(HANDLE, BOOL, DWORD, CONSOLE_FONT*);
typedef COORD(WINAPI* PROCGETCONSOLEFONTSIZE)(HANDLE, DWORD);
typedef DWORD(WINAPI* PROCGETNUMBEROFCONSOLEFONTS)();
typedef BOOL(WINAPI* PROCGETCURRENTCONSOLEFONT)(HANDLE, BOOL, CONSOLE_FONT*);
PROCSETCONSOLEFONT SetConsoleFont;
PROCGETCONSOLEFONTINFO GetConsoleFontInfo;
PROCGETNUMBEROFCONSOLEFONTS GetNumberOfConsoleFonts;

typedef BOOL(WINAPI* PROCGETCONSOLEDISPLAYMODE)(LPDWORD);
typedef BOOL(WINAPI* PROCSETCONSOLEDISPLAYMODE)(HANDLE, DWORD, LPDWORD);

??例如:

#include <Windows.h>
#include <stdio.h>
struct CONSOLE_FONT
{
	DWORD index;
	COORD dim;
};
typedef BOOL(WINAPI* PROCSETCONSOLEFONT)(HANDLE, DWORD);
typedef BOOL(WINAPI* PROCGETCONSOLEFONTINFO)(HANDLE, BOOL, DWORD, CONSOLE_FONT*);
typedef COORD(WINAPI* PROCGETCONSOLEFONTSIZE)(HANDLE, DWORD);
typedef DWORD(WINAPI* PROCGETNUMBEROFCONSOLEFONTS)();
typedef BOOL(WINAPI* PROCGETCURRENTCONSOLEFONT)(HANDLE, BOOL, CONSOLE_FONT*);
PROCSETCONSOLEFONT SetConsoleFont;
PROCGETCONSOLEFONTINFO GetConsoleFontInfo;
PROCGETNUMBEROFCONSOLEFONTS GetNumberOfConsoleFonts;

typedef BOOL(WINAPI* PROCGETCONSOLEDISPLAYMODE)(LPDWORD);
typedef BOOL(WINAPI* PROCSETCONSOLEDISPLAYMODE)(HANDLE, DWORD, LPDWORD);

int main(int argc, char* argv[]) {
	printf("Hello world!\n");
	return 0;
}

??GetCurrentConsoleFontEx 函数可以获取字体信息,其原型为:

WINBASEAPI BOOL WINAPI GetCurrentConsoleFontEx(
    _In_ HANDLE hConsoleOutput,                        // 输出句柄。
    _In_ BOOL bMaximumWindow,                          // 如果此参数为 TRUE,则为最大窗口大小检索字体信息。 如果此参数为 FALSE,则将检索当前窗口大小的字体信息。
    _Out_ PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx  // 字体结构体
    );

??参数 lpConsoleCurrentFontEx 的类型 PCONSOLE_FONT_INFOEX 是一个指向 CONSOLE_FONT_INFOEX 的指针,CONSOLE_FONT_INFOEX 的定义为:

typedef struct _CONSOLE_FONT_INFOEX {
    ULONG cbSize;                // 结构体的大小(以字节为单位)。
    DWORD nFont;                 // 系统控制台字体表中字体的索引。
    COORD dwFontSize;            // 字体大小,规定了字体的长与宽。
    UINT FontFamily;             // 字体间距和系列。
    UINT FontWeight;             // 字体粗细。权重的范围可以是 100 到 1000,以 100 的倍数表示。
    WCHAR FaceName[LF_FACESIZE]; // 字体名称。
} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;

??在调用 GetCurrentConsoleFontEx 前必须设置 cbSize 的值,否则函数调用失败。其值可以设为 sizeof(CONSOLE_FONT_INFOEX),下方代码将会演示如何使用此函数和结构。

#include <iostream>
#include <Windows.h>

int main(int argc, char* argv[]) {
    using std::cout;
    using std::wcout;

    // 控制台字体对象
    CONSOLE_FONT_INFOEX cfi;
    cfi.cbSize = sizeof(cfi);
    // 输出句柄
    HANDLE outputHandle = GetStdHandle(STD_OUTPUT_HANDLE);

    // 获取字体信息
    GetCurrentConsoleFontEx(outputHandle, 0, &cfi);

    // 输出字体信息
    wcout << "字体: " << cfi.FaceName;
    cout << std::endl;
    cout << "大小: " << cfi.dwFontSize.X << "*" << cfi.dwFontSize.Y << std::endl
         << "权重: " << cfi.FontWeight << std::endl;

	return 0;
}


??不知道为什么,无法获取到控制台字体。

二、设置控制台字体

??(旧版API)SetCurrentConsoleFontEx 函数可以修改字体,需要搭配 (旧版结构)CONSOLE_FONT_INFOEX 结构体使用。下方的程序将会演示此功能。

/*
  此程序将会演示如何使用 SetCurrentConsoleFontEx 函数更改控制台字体为“楷体”。
  有一点需要注意,更改的字体必须是等宽字体,不是等宽字体的修改后都会变成默认字体。
*/
#include <stdio.h>
#include <Windows.h>

int main(int argc, char* argv[]) {
    // 控制台字体对象
    CONSOLE_FONT_INFOEX cfi;
    cfi.cbSize = sizeof(cfi);       // 不要忘记设置结构体的大小
    // 输出句柄
    HANDLE outputHandle = GetStdHandle(STD_OUTPUT_HANDLE);

    printf("字体会在按下回车后更改。\n");
    getchar();

    // 更改字体
    cfi.nFont        = 0;
    cfi.dwFontSize.X = 8;           // 更改字体宽度
    cfi.dwFontSize.Y = 18;          // 更改字体高度
    cfi.FontFamily   = FF_DONTCARE;
    cfi.FontWeight   = FW_NORMAL;
    wcscpy_s(cfi.FaceName, L"黑体"); // 更改字体名
    SetCurrentConsoleFontEx(outputHandle, FALSE, &cfi); // 应用更改

    printf("更改完毕。\n");

	return 0;
}

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-14 21:25:37  更:2021-11-14 21:28:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:46:32-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码