UNPKG

7.77 kBtext/x-cView Raw
1#include <windows.h>
2#include <stdio.h>
3#include <stdarg.h>
4#include <wchar.h>
5
6#include "../src/shared/OsModule.h"
7#include "../src/shared/StringUtil.h"
8
9#include "TestUtil.cc"
10#include "../src/shared/StringUtil.cc"
11
12#define COUNT_OF(x) (sizeof(x) / sizeof((x)[0]))
13
14// Some of these types and functions are missing from the MinGW headers.
15// Others are undocumented.
16
17struct AGENT_CONSOLE_FONT_INFO {
18 DWORD nFont;
19 COORD dwFontSize;
20};
21
22struct AGENT_CONSOLE_FONT_INFOEX {
23 ULONG cbSize;
24 DWORD nFont;
25 COORD dwFontSize;
26 UINT FontFamily;
27 UINT FontWeight;
28 WCHAR FaceName[LF_FACESIZE];
29};
30
31// undocumented XP API
32typedef BOOL WINAPI SetConsoleFont_t(
33 HANDLE hOutput,
34 DWORD dwFontIndex);
35
36// undocumented XP API
37typedef DWORD WINAPI GetNumberOfConsoleFonts_t();
38
39// XP and up
40typedef BOOL WINAPI GetCurrentConsoleFont_t(
41 HANDLE hOutput,
42 BOOL bMaximumWindow,
43 AGENT_CONSOLE_FONT_INFO *lpConsoleCurrentFont);
44
45// XP and up
46typedef COORD WINAPI GetConsoleFontSize_t(
47 HANDLE hConsoleOutput,
48 DWORD nFont);
49
50// Vista and up
51typedef BOOL WINAPI GetCurrentConsoleFontEx_t(
52 HANDLE hConsoleOutput,
53 BOOL bMaximumWindow,
54 AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx);
55
56// Vista and up
57typedef BOOL WINAPI SetCurrentConsoleFontEx_t(
58 HANDLE hConsoleOutput,
59 BOOL bMaximumWindow,
60 AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx);
61
62#define GET_MODULE_PROC(mod, funcName) \
63 m_##funcName = reinterpret_cast<funcName##_t*>((mod).proc(#funcName)); \
64
65#define DEFINE_ACCESSOR(funcName) \
66 funcName##_t &funcName() const { \
67 ASSERT(valid()); \
68 return *m_##funcName; \
69 }
70
71class XPFontAPI {
72public:
73 XPFontAPI() : m_kernel32(L"kernel32.dll") {
74 GET_MODULE_PROC(m_kernel32, GetCurrentConsoleFont);
75 GET_MODULE_PROC(m_kernel32, GetConsoleFontSize);
76 }
77
78 bool valid() const {
79 return m_GetCurrentConsoleFont != NULL &&
80 m_GetConsoleFontSize != NULL;
81 }
82
83 DEFINE_ACCESSOR(GetCurrentConsoleFont)
84 DEFINE_ACCESSOR(GetConsoleFontSize)
85
86private:
87 OsModule m_kernel32;
88 GetCurrentConsoleFont_t *m_GetCurrentConsoleFont;
89 GetConsoleFontSize_t *m_GetConsoleFontSize;
90};
91
92class UndocumentedXPFontAPI : public XPFontAPI {
93public:
94 UndocumentedXPFontAPI() : m_kernel32(L"kernel32.dll") {
95 GET_MODULE_PROC(m_kernel32, SetConsoleFont);
96 GET_MODULE_PROC(m_kernel32, GetNumberOfConsoleFonts);
97 }
98
99 bool valid() const {
100 return this->XPFontAPI::valid() &&
101 m_SetConsoleFont != NULL &&
102 m_GetNumberOfConsoleFonts != NULL;
103 }
104
105 DEFINE_ACCESSOR(SetConsoleFont)
106 DEFINE_ACCESSOR(GetNumberOfConsoleFonts)
107
108private:
109 OsModule m_kernel32;
110 SetConsoleFont_t *m_SetConsoleFont;
111 GetNumberOfConsoleFonts_t *m_GetNumberOfConsoleFonts;
112};
113
114class VistaFontAPI : public XPFontAPI {
115public:
116 VistaFontAPI() : m_kernel32(L"kernel32.dll") {
117 GET_MODULE_PROC(m_kernel32, GetCurrentConsoleFontEx);
118 GET_MODULE_PROC(m_kernel32, SetCurrentConsoleFontEx);
119 }
120
121 bool valid() const {
122 return this->XPFontAPI::valid() &&
123 m_GetCurrentConsoleFontEx != NULL &&
124 m_SetCurrentConsoleFontEx != NULL;
125 }
126
127 DEFINE_ACCESSOR(GetCurrentConsoleFontEx)
128 DEFINE_ACCESSOR(SetCurrentConsoleFontEx)
129
130private:
131 OsModule m_kernel32;
132 GetCurrentConsoleFontEx_t *m_GetCurrentConsoleFontEx;
133 SetCurrentConsoleFontEx_t *m_SetCurrentConsoleFontEx;
134};
135
136static std::vector<std::pair<DWORD, COORD> > readFontTable(
137 XPFontAPI &api, HANDLE conout, DWORD maxCount) {
138 std::vector<std::pair<DWORD, COORD> > ret;
139 for (DWORD i = 0; i < maxCount; ++i) {
140 COORD size = api.GetConsoleFontSize()(conout, i);
141 if (size.X == 0 && size.Y == 0) {
142 break;
143 }
144 ret.push_back(std::make_pair(i, size));
145 }
146 return ret;
147}
148
149static void dumpFontTable(HANDLE conout) {
150 const int kMaxCount = 1000;
151 XPFontAPI api;
152 if (!api.valid()) {
153 printf("dumpFontTable: cannot dump font table -- missing APIs\n");
154 return;
155 }
156 std::vector<std::pair<DWORD, COORD> > table =
157 readFontTable(api, conout, kMaxCount);
158 std::string line;
159 char tmp[128];
160 size_t first = 0;
161 while (first < table.size()) {
162 size_t last = std::min(table.size() - 1, first + 10 - 1);
163 winpty_snprintf(tmp, "%02u-%02u:",
164 static_cast<unsigned>(first), static_cast<unsigned>(last));
165 line = tmp;
166 for (size_t i = first; i <= last; ++i) {
167 if (i % 10 == 5) {
168 line += " - ";
169 }
170 winpty_snprintf(tmp, " %2dx%-2d",
171 table[i].second.X, table[i].second.Y);
172 line += tmp;
173 }
174 printf("%s\n", line.c_str());
175 first = last + 1;
176 }
177 if (table.size() == kMaxCount) {
178 printf("... stopped reading at %d fonts ...\n", kMaxCount);
179 }
180}
181
182static std::string stringToCodePoints(const std::wstring &str) {
183 std::string ret = "(";
184 for (size_t i = 0; i < str.size(); ++i) {
185 char tmp[32];
186 winpty_snprintf(tmp, "%X", str[i]);
187 if (ret.size() > 1) {
188 ret.push_back(' ');
189 }
190 ret += tmp;
191 }
192 ret.push_back(')');
193 return ret;
194}
195
196static void dumpFontInfoEx(
197 const AGENT_CONSOLE_FONT_INFOEX &infoex) {
198 std::wstring faceName(infoex.FaceName,
199 winpty_wcsnlen(infoex.FaceName, COUNT_OF(infoex.FaceName)));
200 cprintf(L"nFont=%u dwFontSize=(%d,%d) "
201 "FontFamily=0x%x FontWeight=%u FaceName=%ls %hs\n",
202 static_cast<unsigned>(infoex.nFont),
203 infoex.dwFontSize.X, infoex.dwFontSize.Y,
204 infoex.FontFamily, infoex.FontWeight, faceName.c_str(),
205 stringToCodePoints(faceName).c_str());
206}
207
208static void dumpVistaFont(VistaFontAPI &api, HANDLE conout, BOOL maxWindow) {
209 AGENT_CONSOLE_FONT_INFOEX infoex = {0};
210 infoex.cbSize = sizeof(infoex);
211 if (!api.GetCurrentConsoleFontEx()(conout, maxWindow, &infoex)) {
212 printf("GetCurrentConsoleFontEx call failed\n");
213 return;
214 }
215 dumpFontInfoEx(infoex);
216}
217
218static void dumpXPFont(XPFontAPI &api, HANDLE conout, BOOL maxWindow) {
219 AGENT_CONSOLE_FONT_INFO info = {0};
220 if (!api.GetCurrentConsoleFont()(conout, maxWindow, &info)) {
221 printf("GetCurrentConsoleFont call failed\n");
222 return;
223 }
224 printf("nFont=%u dwFontSize=(%d,%d)\n",
225 static_cast<unsigned>(info.nFont),
226 info.dwFontSize.X, info.dwFontSize.Y);
227}
228
229static void dumpFontAndTable(HANDLE conout) {
230 VistaFontAPI vista;
231 if (vista.valid()) {
232 printf("maxWnd=0: "); dumpVistaFont(vista, conout, FALSE);
233 printf("maxWnd=1: "); dumpVistaFont(vista, conout, TRUE);
234 dumpFontTable(conout);
235 return;
236 }
237 UndocumentedXPFontAPI xp;
238 if (xp.valid()) {
239 printf("maxWnd=0: "); dumpXPFont(xp, conout, FALSE);
240 printf("maxWnd=1: "); dumpXPFont(xp, conout, TRUE);
241 dumpFontTable(conout);
242 return;
243 }
244 printf("setSmallFont: neither Vista nor XP APIs detected -- giving up\n");
245 dumpFontTable(conout);
246}
247
248int main() {
249 const HANDLE conout = openConout();
250 const COORD largest = GetLargestConsoleWindowSize(conout);
251 printf("largestConsoleWindowSize=(%d,%d)\n", largest.X, largest.Y);
252 dumpFontAndTable(conout);
253 UndocumentedXPFontAPI xp;
254 if (xp.valid()) {
255 printf("GetNumberOfConsoleFonts returned %u\n", xp.GetNumberOfConsoleFonts()());
256 } else {
257 printf("The GetNumberOfConsoleFonts API was missing\n");
258 }
259 printf("CP=%u OutputCP=%u\n", GetConsoleCP(), GetConsoleOutputCP());
260 return 0;
261}