前言
??本文章所使用的一些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;
}
二、设置缓冲区大小
??(旧版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;
}
??注: 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) {
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>
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 | 简体中文 |
??定义常量以区分这些代码页。
#define US 437
#define MULTILINGUAL 850
#define TURKISH 857
#define RUSSIA 866
#define MODERNGREEK 869
#define CHINESE 936
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 用于设置输入的字符的代码页。下方代码将会演示此功能。
#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
#define FOREGROUND_BLUE 0x0001
#define FOREGROUND_GREEN 0x0002
#define FOREGROUND_RED 0x0004
#define FOREGROUND_INTENSITY 0x0008
#define BACKGROUND_BLUE 0x0010
#define BACKGROUND_GREEN 0x0020
#define BACKGROUND_RED 0x0040
#define BACKGROUND_INTENSITY 0x0080
#define COMMON_LVB_LEADING_BYTE 0x0100
#define COMMON_LVB_TRAILING_BYTE 0x0200
#define COMMON_LVB_GRID_HORIZONTAL 0x0400
#define COMMON_LVB_GRID_LVERTICAL 0x0800
#define COMMON_LVB_GRID_RVERTICAL 0x1000
#define COMMON_LVB_REVERSE_VIDEO 0x4000
#define COMMON_LVB_UNDERSCORE 0x8000
#define COMMON_LVB_SBCSDBCS 0x0300
二、使用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
??上方截取了 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 及其宽字符和窄字符版所用到的类型的定义。
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();
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 函数可以实现此功能。其原型为:
WINUSERAPI BOOL WINAPI SetWindowPos(
_In_ HWND hWnd,
_In_opt_ HWND hWndInsertAfter,
_In_ int X,
_In_ int 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);
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) {
printf("X:");
scanf("%ud", &getPos[0]);
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 函数可以移动控制台指定区域的文本到制定区域,其原型为:
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;
if (!GetConsoleScreenBufferInfo(hConsole, &csbi))
{
return;
}
scrollRect.Left = 0;
scrollRect.Top = 0;
scrollRect.Right = csbi.dwSize.X;
scrollRect.Bottom = csbi.dwSize.Y;
scrollTarget.X = 0;
scrollTarget.Y = (SHORT)(0 - csbi.dwSize.Y);
fill.Char.UnicodeChar = TEXT(' ');
fill.Attributes = csbi.wAttributes;
ScrollConsoleScreenBuffer(hConsole, &scrollRect, NULL, scrollTarget, &fill);
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,
_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;
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 结构体使用。下方的程序将会演示此功能。
#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;
}
|