1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Tests for i18n console.
5 * COPYRIGHT: Copyright 2017-2020 Katayama Hirofumi MZ
6 * Copyright 2020-2022 Hermès Bélusca-Maïto
7 */
8
9 #include "precomp.h"
10
11 #define okCURSOR(hCon, c) \
12 do { \
13 CONSOLE_SCREEN_BUFFER_INFO __sbi; \
14 BOOL expect = GetConsoleScreenBufferInfo((hCon), &__sbi) && \
15 __sbi.dwCursorPosition.X == (c).X && __sbi.dwCursorPosition.Y == (c).Y; \
16 ok(expect, "Expected cursor at (%d,%d), got (%d,%d)\n", \
17 (c).X, (c).Y, __sbi.dwCursorPosition.X, __sbi.dwCursorPosition.Y); \
18 } while (0)
19
20 #define ATTR (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
21
22 static const WCHAR u0414[] = {0x0414, 0}; /* Д */
23 static const WCHAR u9580[] = {0x9580, 0}; /* 門 */
24 static const WCHAR space[] = {L' ', 0};
25 static const WCHAR ideograph_space = (WCHAR)0x3000; /* fullwidth space */
26 static const WCHAR s_str[] = {L'A', 0x9580, 'B', 0};
27 static const LCID lcidJapanese = MAKELCID(MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT), SORT_DEFAULT);
28 static const LCID lcidRussian = MAKELCID(MAKELANGID(LANG_RUSSIAN , SUBLANG_DEFAULT), SORT_DEFAULT);
29
30 static UINT s_uOEMCP;
31 static BOOL s_bIs8Plus;
32
IsCJKCodePage(_In_ UINT CodePage)33 static BOOL IsCJKCodePage(_In_ UINT CodePage)
34 {
35 switch (CodePage)
36 {
37 case 932: // Japanese
38 case 949: // Korean
39 case 1361: // Korean (Johab)
40 case 936: // Chinese PRC
41 case 950: // Taiwan
42 return TRUE;
43 }
44 return FALSE;
45 }
46
47 static __inline
MapCJKCPToLangId(_In_ UINT CodePage)48 LANGID MapCJKCPToLangId(_In_ UINT CodePage)
49 {
50 switch (CodePage)
51 {
52 case 932: // Japanese (Shift-JIS)
53 return MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT);
54 case 949: // Korean (Hangul/Wansung)
55 // case 1361: // Korean (Johab)
56 return MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN);
57 case 936: // Chinese PRC (Chinese Simplified)
58 return MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED);
59 case 950: // Taiwan (Chinese Traditional)
60 return MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL);
61 default:
62 return MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
63 }
64 }
65
ChangeOutputCP_(_In_ const char * file,_In_ int line,_In_ UINT CodePage)66 static BOOL ChangeOutputCP_(
67 _In_ const char* file,
68 _In_ int line,
69 _In_ UINT CodePage)
70 {
71 BOOL bSuccess;
72
73 /* Validate the code page */
74 bSuccess = IsValidCodePage(CodePage);
75 if (!bSuccess)
76 {
77 skip_(file, line)("Code page %d not available\n", CodePage);
78 return FALSE;
79 }
80
81 /* Set the new code page */
82 SetLastError(0xdeadbeef);
83 bSuccess = SetConsoleOutputCP(CodePage);
84 if (!bSuccess)
85 skip_(file, line)("SetConsoleOutputCP(%d) failed with last error %lu\n", CodePage, GetLastError());
86 return bSuccess;
87 }
88
89 #define ChangeOutputCP(CodePage) \
90 ChangeOutputCP_(__FILE__, __LINE__, CodePage)
91
92
93 #define cmpThreadLangId(file, line, ExpectedLangId) \
94 do { \
95 LANGID ThreadLangId; \
96 ThreadLangId = LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale); \
97 trace_((file), (line))("Thread LangId %d, expecting %d...\n", \
98 ThreadLangId, (ExpectedLangId)); \
99 ok_((file), (line))(ThreadLangId == (ExpectedLangId), \
100 "Thread LangId %d, expected %d\n", \
101 ThreadLangId, (ExpectedLangId)); \
102 } while (0)
103
104 static BOOL
doTest_CP_ThreadLang_(_In_ const char * file,_In_ int line,_In_ UINT CodePage,_In_ LANGID ExpectedLangId)105 doTest_CP_ThreadLang_(
106 _In_ const char* file,
107 _In_ int line,
108 _In_ UINT CodePage,
109 _In_ LANGID ExpectedLangId)
110 {
111 UINT newcp;
112
113 /* Verify and set the new code page */
114 if (!ChangeOutputCP_(file, line, CodePage))
115 {
116 skip_(file, line)("Code page %d expected to be valid!\n", CodePage);
117 return FALSE;
118 }
119
120 newcp = GetConsoleOutputCP();
121 ok_(file, line)(newcp == CodePage, "Console output CP is %d, expected %d\n", newcp, CodePage);
122
123 /* Verify that the thread lang ID is the expected one */
124 cmpThreadLangId(file, line, ExpectedLangId);
125 return TRUE;
126 }
127
128 #define doTest_CP_ThreadLang(...) \
129 doTest_CP_ThreadLang_(__FILE__, __LINE__, ##__VA_ARGS__)
130
test_CP_ThreadLang(VOID)131 static VOID test_CP_ThreadLang(VOID)
132 {
133 /* Save the initial current thread locale. It is (re)initialized after
134 * attaching to a console. Don't use GetThreadLocale() as the latter
135 * can return a replacement value in case CurrentLocale is 0. */
136 LANGID ThreadLangId = LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale);
137 UINT oldcp = GetConsoleOutputCP();
138
139 if (IsCJKCodePage(s_uOEMCP))
140 {
141 /* We are on a CJK system */
142
143 /* Is the console in CJK? If so, current thread should be in CJK language */
144 if (!IsCJKCodePage(oldcp))
145 {
146 skip("CJK system but console CP not in CJK\n");
147 }
148 else
149 {
150 /* Check that the thread lang ID matches what the console set */
151 LANGID LangId = MapCJKCPToLangId(oldcp);
152 cmpThreadLangId(__FILE__, __LINE__, LangId);
153 }
154
155 /* Set the code page to OEM USA (non-CJK codepage that is supported).
156 * Verify that the thread lang ID has changed to non-CJK language. */
157 doTest_CP_ThreadLang(437, MapCJKCPToLangId(437));
158
159 /* Set the code page to the default system CJK codepage.
160 * Check that the thread lang ID matches what the console set. */
161 doTest_CP_ThreadLang(s_uOEMCP, MapCJKCPToLangId(s_uOEMCP));
162 }
163 else
164 {
165 /* We are on a non-CJK system */
166
167 /* Code pages: Japanese, Korean, Chinese Simplified/Traditional */
168 UINT CJKCodePages[] = {932, 949, 936, 950};
169 UINT newcp;
170 USHORT i;
171
172 /* Switch to a different code page (OEM USA) than the current one.
173 * In such setup, the current thread lang ID should not change. */
174 newcp = (s_uOEMCP == 437 ? 850 : 437);
175 doTest_CP_ThreadLang(newcp, ThreadLangId);
176
177 /* Try switching to a CJK codepage, if possible, but
178 * the thread lang ID should not change either... */
179
180 /* Retry as long as no valid CJK codepage has been found */
181 for (i = 0; i < ARRAYSIZE(CJKCodePages); ++i)
182 {
183 newcp = CJKCodePages[i];
184 if (IsValidCodePage(newcp))
185 break; // Found a valid one.
186 }
187 if (i >= ARRAYSIZE(CJKCodePages))
188 {
189 /* No valid CJK code pages on the system */
190 skip("CJK system but console CP not in CJK\n");
191 }
192 else
193 {
194 /* Verify that the thread lang ID remains the same */
195 doTest_CP_ThreadLang(newcp, ThreadLangId);
196 }
197 }
198
199 /* Restore code page */
200 SetConsoleOutputCP(oldcp);
201 }
202
203
204 /* Russian Code Page 855 */
205 // NOTE that CP 866 can also be used
test_cp855(HANDLE hConOut)206 static void test_cp855(HANDLE hConOut)
207 {
208 BOOL ret;
209 UINT oldcp;
210 int n;
211 DWORD len;
212 COORD c;
213 CONSOLE_SCREEN_BUFFER_INFO csbi;
214 int count;
215 WCHAR str[32];
216 WORD attrs[16];
217
218 /* Set code page */
219 oldcp = GetConsoleOutputCP();
220 if (!ChangeOutputCP(855))
221 {
222 skip("Codepage 855 not available\n");
223 return;
224 }
225
226 /* Get info */
227 ret = GetConsoleScreenBufferInfo(hConOut, &csbi);
228 ok(ret, "GetConsoleScreenBufferInfo failed\n");
229 trace("csbi.dwSize.X:%d, csbi.dwSize.Y:%d\n", csbi.dwSize.X, csbi.dwSize.Y);
230 count = 200;
231
232 /* "\u0414" */
233 {
234 /* Output u0414 "count" times at (0,0) */
235 c.X = c.Y = 0;
236 SetConsoleCursorPosition(hConOut, c);
237 okCURSOR(hConOut, c);
238 for (n = 0; n < count; ++n)
239 {
240 ret = WriteConsoleW(hConOut, u0414, lstrlenW(u0414), &len, NULL);
241 ok(ret && len == lstrlenW(u0414), "WriteConsoleW failed\n");
242 }
243
244 /* Check cursor */
245 len = count; /* u0414 is normal width in Russian */
246 c.X = (SHORT)(len % csbi.dwSize.X);
247 c.Y = (SHORT)(len / csbi.dwSize.X);
248 okCURSOR(hConOut, c);
249
250 /* Read characters at (0,0) */
251 c.X = c.Y = 0;
252 ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
253 ok(ret, "ReadConsoleOutputCharacterW failed\n");
254 ok_long(len, 6);
255 ok_int(str[0], 0x414);
256 ok_int(str[1], 0x414);
257 ok_int(str[2], 0x414);
258
259 /* Read attributes at (0,0) */
260 c.X = c.Y = 0;
261 ret = ReadConsoleOutputAttribute(hConOut, attrs, 6, c, &len);
262 ok(ret, "ReadConsoleOutputAttribute failed\n");
263 ok_long(len, 6);
264 ok_int(attrs[0], ATTR);
265
266 /* Check cursor */
267 c.X = 1;
268 c.Y = 0;
269 ret = SetConsoleCursorPosition(hConOut, c);
270 ok(ret, "SetConsoleCursorPosition failed\n");
271 okCURSOR(hConOut, c);
272
273 /* Fill by space */
274 c.X = c.Y = 0;
275 FillConsoleOutputCharacterW(hConOut, L' ', csbi.dwSize.X * csbi.dwSize.Y, c, &len);
276
277 /* Output u0414 "count" times at (1,0) */
278 c.X = 1;
279 c.Y = 0;
280 SetConsoleCursorPosition(hConOut, c);
281 okCURSOR(hConOut, c);
282 for (n = 0; n < count; ++n)
283 {
284 ret = WriteConsoleW(hConOut, u0414, lstrlenW(u0414), &len, NULL);
285 ok(ret && len == lstrlenW(u0414), "WriteConsoleW failed\n");
286 }
287
288 /* Check cursor */
289 len = 1 + count;
290 c.X = (SHORT)(len % csbi.dwSize.X);
291 c.Y = (SHORT)(len / csbi.dwSize.X);
292 okCURSOR(hConOut, c);
293
294 /* Read characters at (0,0) */
295 c.X = c.Y = 0;
296 ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
297 ok(ret, "ReadConsoleOutputCharacterW failed\n");
298 ok_long(len, 6);
299 ok_int(str[0], L' ');
300 ok_int(str[1], 0x414);
301 ok_int(str[2], 0x414);
302 }
303
304 /* "\u9580" */
305 {
306 /* Output u9580 "count" times at (0,0) */
307 c.X = c.Y = 0;
308 SetConsoleCursorPosition(hConOut, c);
309 okCURSOR(hConOut, c);
310 for (n = 0; n < count; ++n)
311 {
312 ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL);
313 ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n");
314 }
315
316 /* Check cursor */
317 len = count; /* u9580 is normal width in Russian */
318 c.X = (SHORT)(len % csbi.dwSize.X);
319 c.Y = (SHORT)(len / csbi.dwSize.X);
320 okCURSOR(hConOut, c);
321
322 /* Check cursor */
323 c.X = 1;
324 c.Y = 0;
325 ret = SetConsoleCursorPosition(hConOut, c);
326 ok(ret, "SetConsoleCursorPosition failed\n");
327 okCURSOR(hConOut, c);
328
329 /* Fill by space */
330 c.X = c.Y = 0;
331 ret = FillConsoleOutputCharacterW(hConOut, L' ', csbi.dwSize.X * csbi.dwSize.Y, c, &len);
332 ok(ret, "FillConsoleOutputCharacterW failed\n");
333 ok_long(len, csbi.dwSize.X * csbi.dwSize.Y);
334
335 /* Output u9580 "count" times at (1,0) */
336 c.X = 1;
337 c.Y = 0;
338 SetConsoleCursorPosition(hConOut, c);
339 okCURSOR(hConOut, c);
340 for (n = 0; n < count; ++n)
341 {
342 ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL);
343 ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n");
344 }
345
346 /* Check cursor */
347 len = 1 + count;
348 c.X = (SHORT)(len % csbi.dwSize.X);
349 c.Y = (SHORT)(len / csbi.dwSize.X);
350 okCURSOR(hConOut, c);
351
352 /* Fill by ideograph space */
353 c.X = c.Y = 0;
354 ret = FillConsoleOutputCharacterW(hConOut, ideograph_space, csbi.dwSize.X * csbi.dwSize.Y, c, &len);
355 ok(ret, "FillConsoleOutputCharacterW failed\n");
356 ok_long(len, csbi.dwSize.X * csbi.dwSize.Y);
357
358 /* Read characters at (0,0) */
359 c.X = c.Y = 0;
360 ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
361 ok(ret, "ReadConsoleOutputCharacterW failed\n");
362 ok_long(len, 6);
363 ok(str[0] == ideograph_space || str[0] == L'?', "str[0] was: 0x%04X\n", str[0]);
364 ok(str[1] == ideograph_space || str[1] == L'?', "str[1] was: 0x%04X\n", str[1]);
365 ok(str[2] == ideograph_space || str[2] == L'?', "str[2] was: 0x%04X\n", str[2]);
366
367 /* Read attributes at (0,0) */
368 c.X = c.Y = 0;
369 ret = ReadConsoleOutputAttribute(hConOut, attrs, 6, c, &len);
370 ok(ret, "ReadConsoleOutputAttribute failed\n");
371 ok_long(len, 6);
372 ok_int(attrs[0], ATTR);
373
374 /* Read characters at (1,0) */
375 c.X = 1;
376 c.Y = 0;
377 ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
378 ok(ret, "ReadConsoleOutputCharacterW failed\n");
379 ok_long(len, 6);
380 ok(str[0] == ideograph_space || str[0] == L'?', "str[0] was: 0x%04X\n", str[0]);
381 ok(str[1] == ideograph_space || str[1] == L'?', "str[1] was: 0x%04X\n", str[1]);
382 ok(str[2] == ideograph_space || str[2] == L'?', "str[2] was: 0x%04X\n", str[2]);
383
384 /* Output u9580 "count" once at (1,0) */
385 c.X = 1;
386 c.Y = 0;
387 SetConsoleCursorPosition(hConOut, c);
388 okCURSOR(hConOut, c);
389 ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL);
390 ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n");
391
392 /* Read attributes at (1,0) */
393 c.X = 1;
394 c.Y = 0;
395 ret = ReadConsoleOutputAttribute(hConOut, attrs, 1, c, &len);
396 ok(ret, "ReadConsoleOutputAttribute failed\n");
397 ok_long(len, 1);
398 ok_int(attrs[0], ATTR);
399
400 /* Check cursor */
401 c.X = 2;
402 c.Y = 0;
403 okCURSOR(hConOut, c);
404
405 /* Read characters at (0,0) */
406 c.X = c.Y = 0;
407 ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
408 ok(ret, "ReadConsoleOutputCharacterW failed\n");
409 ok_long(len, 6);
410 ok(str[0] == ideograph_space || str[0] == L'?', "str[0] was: 0x%04X\n", str[0]);
411 ok(str[1] == u9580[0] || str[1] == L'?', "str[1] was: 0x%04X\n", str[1]);
412 ok(str[2] == ideograph_space || str[2] == L'?', "str[2] was: 0x%04X\n", str[2]);
413 }
414
415 /* Restore code page */
416 SetConsoleOutputCP(oldcp);
417 }
418
419 /* Japanese Code Page 932 */
test_cp932(HANDLE hConOut)420 static void test_cp932(HANDLE hConOut)
421 {
422 BOOL ret;
423 UINT oldcp;
424 int n;
425 DWORD len;
426 COORD c, buffSize;
427 CONSOLE_SCREEN_BUFFER_INFO csbi;
428 int count;
429 WCHAR str[32];
430 WORD attrs[16];
431 CHAR_INFO buff[16];
432 SMALL_RECT sr;
433
434 /* Set code page */
435 oldcp = GetConsoleOutputCP();
436 if (!ChangeOutputCP(932))
437 {
438 skip("Codepage 932 not available\n");
439 return;
440 }
441
442 /* Get info */
443 ret = GetConsoleScreenBufferInfo(hConOut, &csbi);
444 ok(ret, "GetConsoleScreenBufferInfo failed\n");
445 trace("csbi.dwSize.X:%d, csbi.dwSize.Y:%d\n", csbi.dwSize.X, csbi.dwSize.Y);
446 count = 200;
447
448 /* "\u0414" */
449 {
450 /* Output u0414 "count" times at (0,0) */
451 c.X = c.Y = 0;
452 SetConsoleCursorPosition(hConOut, c);
453 okCURSOR(hConOut, c);
454 for (n = 0; n < count; ++n)
455 {
456 ret = WriteConsoleW(hConOut, u0414, lstrlenW(u0414), &len, NULL);
457 ok(ret && len == lstrlenW(u0414), "WriteConsoleW failed\n");
458 }
459
460 /* Check cursor */
461 GetConsoleScreenBufferInfo(hConOut, &csbi);
462 len = count * 2; /* u0414 is fullwidth in Japanese */
463 c.X = (SHORT)(len % csbi.dwSize.X);
464 c.Y = (SHORT)(len / csbi.dwSize.X);
465 okCURSOR(hConOut, c);
466
467 /* Read characters at (0,0) */
468 c.X = c.Y = 0;
469 ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
470 ok(ret, "ReadConsoleOutputCharacterW failed\n");
471 ok_long(len, 3);
472 ok_int(str[0], 0x414);
473 ok_int(str[1], 0x414);
474 ok_int(str[2], 0x414);
475
476 /* Read attributes at (0,0) */
477 c.X = c.Y = 0;
478 ret = ReadConsoleOutputAttribute(hConOut, attrs, 6, c, &len);
479 ok(ret, "ReadConsoleOutputAttribute failed\n");
480 ok_long(len, 6);
481 ok_int(attrs[0], ATTR | COMMON_LVB_LEADING_BYTE);
482 ok_int(attrs[1], ATTR | COMMON_LVB_TRAILING_BYTE);
483
484 /* Check cursor */
485 c.X = 1;
486 c.Y = 0;
487 ret = SetConsoleCursorPosition(hConOut, c);
488 ok(ret, "SetConsoleCursorPosition failed\n");
489 okCURSOR(hConOut, c);
490
491 /* Fill by space */
492 c.X = c.Y = 0;
493 FillConsoleOutputCharacterW(hConOut, L' ', csbi.dwSize.X * csbi.dwSize.Y, c, &len);
494
495 /* Output u0414 "count" times at (1,0) */
496 c.X = 1;
497 c.Y = 0;
498 SetConsoleCursorPosition(hConOut, c);
499 okCURSOR(hConOut, c);
500 for (n = 0; n < count; ++n)
501 {
502 ret = WriteConsoleW(hConOut, u0414, lstrlenW(u0414), &len, NULL);
503 ok(ret && len == lstrlenW(u0414), "WriteConsoleW failed\n");
504 }
505
506 /* Check cursor */
507 len = csbi.dwSize.X + (count - (csbi.dwSize.X - 1) / 2) * 2;
508 c.X = (SHORT)(len % csbi.dwSize.X);
509 c.Y = (SHORT)(len / csbi.dwSize.X);
510 okCURSOR(hConOut, c);
511
512 /* Read characters at (0,0) */
513 c.X = 0;
514 c.Y = 0;
515 ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
516 ok(ret, "ReadConsoleOutputCharacterW failed\n");
517 ok_long(len, 4);
518 ok_int(str[0], L' ');
519 ok_int(str[1], 0x414);
520 ok_int(str[2], 0x414);
521 }
522
523 /* "\u9580" */
524 {
525 /* Output u9580 "count" times at (0,0) */
526 c.X = c.Y = 0;
527 SetConsoleCursorPosition(hConOut, c);
528 okCURSOR(hConOut, c);
529 for (n = 0; n < count; ++n)
530 {
531 ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL);
532 ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n");
533 }
534
535 /* Check cursor */
536 len = count * 2; /* u9580 is fullwidth in Japanese */
537 c.X = (SHORT)(len % csbi.dwSize.X);
538 c.Y = (SHORT)(len / csbi.dwSize.X);
539 okCURSOR(hConOut, c);
540
541 /* Check cursor */
542 c.X = 1;
543 c.Y = 0;
544 ret = SetConsoleCursorPosition(hConOut, c);
545 ok(ret, "SetConsoleCursorPosition failed\n");
546 okCURSOR(hConOut, c);
547
548 /* Fill by space */
549 c.X = c.Y = 0;
550 ret = FillConsoleOutputCharacterW(hConOut, L' ', csbi.dwSize.X * csbi.dwSize.Y, c, &len);
551 ok(ret, "FillConsoleOutputCharacterW failed\n");
552 ok_long(len, csbi.dwSize.X * csbi.dwSize.Y);
553
554 /* Output u9580 "count" times at (1,0) */
555 c.X = 1;
556 c.Y = 0;
557 SetConsoleCursorPosition(hConOut, c);
558 okCURSOR(hConOut, c);
559 for (n = 0; n < count; ++n)
560 {
561 ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL);
562 ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n");
563 }
564
565 /* Check cursor */
566 len = csbi.dwSize.X + (count - (csbi.dwSize.X - 1) / 2) * 2;
567 c.X = (SHORT)(len % csbi.dwSize.X);
568 c.Y = (SHORT)(len / csbi.dwSize.X);
569 okCURSOR(hConOut, c);
570
571 /* Fill by ideograph space */
572 c.X = c.Y = 0;
573 ret = FillConsoleOutputCharacterW(hConOut, ideograph_space, csbi.dwSize.X * csbi.dwSize.Y, c, &len);
574 ok(ret, "FillConsoleOutputCharacterW failed\n");
575 if (s_bIs8Plus)
576 ok_long(len, csbi.dwSize.X * csbi.dwSize.Y / 2);
577 else
578 ok_long(len, csbi.dwSize.X * csbi.dwSize.Y);
579
580 /* Read characters at (0,0) */
581 c.X = c.Y = 0;
582 ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
583 ok(ret, "ReadConsoleOutputCharacterW failed\n");
584 ok_long(len, 3);
585 ok_int(str[0], ideograph_space);
586 ok_int(str[1], ideograph_space);
587 ok_int(str[2], ideograph_space);
588
589 /* Read attributes at (0,0) */
590 c.X = c.Y = 0;
591 ret = ReadConsoleOutputAttribute(hConOut, attrs, 6, c, &len);
592 ok(ret, "ReadConsoleOutputAttribute failed\n");
593 ok_long(len, 6);
594 ok_int(attrs[0], ATTR | COMMON_LVB_LEADING_BYTE);
595 ok_int(attrs[1], ATTR | COMMON_LVB_TRAILING_BYTE);
596 ok_int(attrs[2], ATTR | COMMON_LVB_LEADING_BYTE);
597 ok_int(attrs[3], ATTR | COMMON_LVB_TRAILING_BYTE);
598 ok_int(attrs[4], ATTR | COMMON_LVB_LEADING_BYTE);
599 ok_int(attrs[5], ATTR | COMMON_LVB_TRAILING_BYTE);
600
601 /* Output u9580 "count" once at (1,0) */
602 c.X = 1;
603 c.Y = 0;
604 SetConsoleCursorPosition(hConOut, c);
605 okCURSOR(hConOut, c);
606 ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL);
607 ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n");
608
609 /*
610 * Read attributes at (1,0) -
611 * Note that if only one attribute of a fullwidth character
612 * is retrieved, no leading/trailing byte flag is set!
613 */
614 c.X = 1;
615 c.Y = 0;
616 ret = ReadConsoleOutputAttribute(hConOut, attrs, 1, c, &len);
617 ok(ret, "ReadConsoleOutputAttribute failed\n");
618 ok_long(len, 1);
619 ok_int(attrs[0], ATTR);
620
621 /* Check that the same problem happens for the trailing byte */
622 c.X = 2;
623 c.Y = 0;
624 ret = ReadConsoleOutputAttribute(hConOut, attrs, 1, c, &len);
625 ok(ret, "ReadConsoleOutputAttribute failed\n");
626 ok_long(len, 1);
627 ok_int(attrs[0], ATTR);
628
629 /* Read attributes at (1,0) */
630 c.X = 1;
631 c.Y = 0;
632 ret = ReadConsoleOutputAttribute(hConOut, attrs, 2, c, &len);
633 ok(ret, "ReadConsoleOutputAttribute failed\n");
634 ok_long(len, 2);
635 ok_int(attrs[0], ATTR | COMMON_LVB_LEADING_BYTE);
636 ok_int(attrs[1], ATTR | COMMON_LVB_TRAILING_BYTE);
637
638 /* Read attributes at (1,0) */
639 ret = ReadConsoleOutputAttribute(hConOut, attrs, 3, c, &len);
640 ok(ret, "ReadConsoleOutputAttribute failed\n");
641 ok_long(len, 3);
642 ok_int(attrs[0], ATTR | COMMON_LVB_LEADING_BYTE);
643 ok_int(attrs[1], ATTR | COMMON_LVB_TRAILING_BYTE);
644 if (s_bIs8Plus)
645 ok_int(attrs[2], ATTR | COMMON_LVB_TRAILING_BYTE);
646 else
647 ok_int(attrs[2], ATTR);
648
649 /* Read attributes at (0,0) */
650 c.X = c.Y = 0;
651 ret = ReadConsoleOutputAttribute(hConOut, attrs, 4, c, &len);
652 ok(ret, "ReadConsoleOutputAttribute failed\n");
653 ok_long(len, 4);
654 if (s_bIs8Plus)
655 ok_int(attrs[0], ATTR | COMMON_LVB_LEADING_BYTE);
656 else
657 ok_int(attrs[0], ATTR);
658 ok_int(attrs[1], ATTR | COMMON_LVB_LEADING_BYTE);
659 ok_int(attrs[2], ATTR | COMMON_LVB_TRAILING_BYTE);
660 if (s_bIs8Plus)
661 ok_int(attrs[3], ATTR | COMMON_LVB_TRAILING_BYTE);
662 else
663 ok_int(attrs[3], ATTR);
664
665 /* Check cursor */
666 c.X = 3;
667 c.Y = 0;
668 okCURSOR(hConOut, c);
669
670 /* Read characters */
671 c.X = c.Y = 0;
672 ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len);
673 ok(ret, "ReadConsoleOutputCharacterW failed\n");
674 if (s_bIs8Plus)
675 {
676 ok_long(len, 3);
677 ok_int(str[0], ideograph_space);
678 ok_int(str[1], u9580[0]);
679 ok_int(str[2], ideograph_space);
680 }
681 else
682 {
683 ok_long(len, 4);
684 ok_int(str[0], L' ');
685 ok_int(str[1], u9580[0]);
686 ok_int(str[2], L' ');
687 }
688 }
689
690 /* COMMON_LVB_LEADING_BYTE and COMMON_LVB_TRAILING_BYTE for u0414 */
691 {
692 /* set cursor */
693 c.X = c.Y = 0;
694 SetConsoleCursorPosition(hConOut, c);
695 okCURSOR(hConOut, c);
696
697 /* fill by 'A' */
698 ret = FillConsoleOutputCharacterW(hConOut, L'A', csbi.dwSize.X * 2, c, &len);
699 ok_int(ret, 1);
700 ok_long(len, csbi.dwSize.X * 2);
701
702 /* reset buff */
703 buffSize.X = ARRAYSIZE(buff);
704 buffSize.Y = 1;
705 memset(buff, 0x7F, sizeof(buff));
706
707 /* read output */
708 c.X = c.Y = 0;
709 ZeroMemory(&sr, sizeof(sr));
710 sr.Right = buffSize.X - 1;
711 ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
712 ok_int(ret, 1);
713 ok_int(sr.Left, 0);
714 ok_int(sr.Top, 0);
715 ok_int(sr.Right, buffSize.X - 1);
716 ok_int(sr.Bottom, 0);
717
718 /* check buff */
719 ok_int(buff[0].Char.UnicodeChar, L'A');
720 ok_int(buff[0].Attributes, ATTR);
721
722 /* read attr */
723 ret = ReadConsoleOutputAttribute(hConOut, attrs, 1, c, &len);
724 ok_int(ret, 1);
725 ok_long(len, 1);
726 ok_int(attrs[0], ATTR);
727
728 /* read char */
729 c.X = c.Y = 0;
730 memset(str, 0x7F, sizeof(str));
731 ret = ReadConsoleOutputCharacterW(hConOut, str, 4, c, &len);
732 ok_int(ret, 1);
733 ok_long(len, 4);
734 ok_int(str[0], L'A');
735 ok_int(str[1], L'A');
736 ok_int(str[2], L'A');
737 ok_int(str[3], L'A');
738
739 /* set cursor */
740 c.X = c.Y = 0;
741 SetConsoleCursorPosition(hConOut, c);
742 okCURSOR(hConOut, c);
743
744 /* write u0414 */
745 ret = WriteConsoleW(hConOut, u0414, 1, &len, NULL);
746 ok_int(ret, 1);
747 ok_long(len, 1);
748
749 /* reset buff */
750 buffSize.X = ARRAYSIZE(buff);
751 buffSize.Y = 1;
752 memset(buff, 0x7F, sizeof(buff));
753
754 /* read output */
755 c.X = c.Y = 0;
756 ZeroMemory(&sr, sizeof(sr));
757 sr.Right = buffSize.X - 1;
758 ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
759 ok_int(ret, 1);
760 ok_int(sr.Left, 0);
761 ok_int(sr.Top, 0);
762 ok_int(sr.Right, buffSize.X - 1);
763 ok_int(sr.Bottom, 0);
764
765 /* check buff */
766 if (s_bIs8Plus)
767 {
768 ok_int(buff[0].Char.UnicodeChar, 0x0414);
769 ok_int(buff[0].Attributes, ATTR | COMMON_LVB_LEADING_BYTE);
770 ok_int(buff[1].Char.UnicodeChar, 0x0414);
771 ok_int(buff[1].Attributes, ATTR | COMMON_LVB_TRAILING_BYTE);
772 }
773 else
774 {
775 ok_int(buff[0].Char.UnicodeChar, 0x0414);
776 ok_int(buff[0].Attributes, ATTR);
777 ok_int(buff[1].Char.UnicodeChar, L'A');
778 ok_int(buff[1].Attributes, ATTR);
779 }
780 ok_int(buff[2].Char.UnicodeChar, L'A');
781 ok_int(buff[2].Attributes, ATTR);
782 ok_int(buff[3].Char.UnicodeChar, L'A');
783 ok_int(buff[3].Attributes, ATTR);
784
785 /* read attr */
786 ret = ReadConsoleOutputAttribute(hConOut, attrs, ARRAYSIZE(attrs), c, &len);
787 ok_int(ret, 1);
788 ok_long(len, ARRAYSIZE(attrs));
789 ok_int(attrs[0], ATTR | COMMON_LVB_LEADING_BYTE);
790 ok_int(attrs[1], ATTR | COMMON_LVB_TRAILING_BYTE);
791 ok_int(attrs[2], ATTR);
792 ok_int(attrs[3], ATTR);
793
794 /* read char */
795 c.X = c.Y = 0;
796 memset(str, 0x7F, sizeof(str));
797 ret = ReadConsoleOutputCharacterW(hConOut, str, 4, c, &len);
798 ok_int(ret, 1);
799 ok_long(len, 3);
800 ok_int(str[0], 0x0414);
801 ok_int(str[1], L'A');
802 ok_int(str[2], L'A');
803 if (s_bIs8Plus)
804 ok_int(str[3], 0);
805 else
806 ok_int(str[3], 0x7F7F);
807
808 /* set cursor */
809 c.X = 1;
810 c.Y = 0;
811 SetConsoleCursorPosition(hConOut, c);
812 okCURSOR(hConOut, c);
813
814 /* write u0414 */
815 ret = WriteConsoleW(hConOut, u0414, 1, &len, NULL);
816 ok_int(ret, 1);
817 ok_long(len, 1);
818
819 /* read output */
820 c.X = c.Y = 0;
821 ZeroMemory(&sr, sizeof(sr));
822 sr.Right = buffSize.X - 1;
823 ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
824 ok_int(ret, 1);
825 ok_int(sr.Left, 0);
826 ok_int(sr.Top, 0);
827 ok_int(sr.Right, buffSize.X - 1);
828 ok_int(sr.Bottom, 0);
829
830 /* check buff */
831 if (s_bIs8Plus)
832 {
833 ok_int(buff[0].Char.UnicodeChar, 0x0414);
834 ok_int(buff[0].Attributes, ATTR | COMMON_LVB_LEADING_BYTE);
835 ok_int(buff[1].Char.UnicodeChar, 0x0414);
836 ok_int(buff[1].Attributes, ATTR | COMMON_LVB_LEADING_BYTE);
837 ok_int(buff[2].Char.UnicodeChar, 0x0414);
838 ok_int(buff[2].Attributes, ATTR | COMMON_LVB_TRAILING_BYTE);
839 }
840 else
841 {
842 ok_int(buff[0].Char.UnicodeChar, L' ');
843 ok_int(buff[0].Attributes, ATTR);
844 ok_int(buff[1].Char.UnicodeChar, 0x0414);
845 ok_int(buff[1].Attributes, ATTR);
846 ok_int(buff[2].Char.UnicodeChar, L'A');
847 ok_int(buff[2].Attributes, ATTR);
848 }
849 ok_int(buff[3].Char.UnicodeChar, L'A');
850 ok_int(buff[3].Attributes, ATTR);
851
852 /* read attr */
853 c.X = c.Y = 0;
854 ret = ReadConsoleOutputAttribute(hConOut, attrs, ARRAYSIZE(attrs), c, &len);
855 ok_int(ret, 1);
856 ok_long(len, ARRAYSIZE(attrs));
857 if (s_bIs8Plus)
858 ok_int(attrs[0], ATTR | COMMON_LVB_LEADING_BYTE);
859 else
860 ok_int(attrs[0], ATTR);
861 ok_int(attrs[1], ATTR | COMMON_LVB_LEADING_BYTE);
862 ok_int(attrs[2], ATTR | COMMON_LVB_TRAILING_BYTE);
863 ok_int(attrs[3], ATTR);
864
865 /* read char */
866 c.X = c.Y = 0;
867 memset(str, 0x7F, sizeof(str));
868 ret = ReadConsoleOutputCharacterW(hConOut, str, 4, c, &len);
869 ok_int(ret, 1);
870 ok_long(len, 3);
871 if (s_bIs8Plus)
872 {
873 ok_int(str[0], 0x0414);
874 ok_int(str[1], 0x0414);
875 ok_int(str[2], L'A');
876 ok_int(str[3], 0);
877 }
878 else
879 {
880 ok_int(str[0], L' ');
881 ok_int(str[1], 0x0414);
882 ok_int(str[2], L'A');
883 ok_int(str[3], 0x7F7F);
884 }
885
886 /* set cursor */
887 c.X = csbi.dwSize.X - 1;
888 c.Y = 0;
889 SetConsoleCursorPosition(hConOut, c);
890 okCURSOR(hConOut, c);
891
892 /* write u0414 */
893 WriteConsoleW(hConOut, u0414, 1, &len, NULL);
894 ok_int(ret, 1);
895 ok_long(len, 1);
896
897 /* reset buff */
898 buffSize.X = ARRAYSIZE(buff);
899 buffSize.Y = 1;
900 memset(buff, 0x7F, sizeof(buff));
901
902 /* read output */
903 c.X = c.Y = 0;
904 sr.Left = csbi.dwSize.X - 2;
905 sr.Top = 0;
906 sr.Right = csbi.dwSize.X - 1;
907 sr.Bottom = 0;
908 ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
909 ok_int(ret, 1);
910 ok_int(sr.Left, csbi.dwSize.X - 2);
911 ok_int(sr.Top, 0);
912 ok_int(sr.Right, csbi.dwSize.X - 1);
913 ok_int(sr.Bottom, 0);
914
915 /* check buff */
916 ok_int(buff[0].Char.UnicodeChar, L'A');
917 ok_int(buff[0].Attributes, ATTR);
918 ok_int(buff[1].Char.UnicodeChar, L'A');
919 ok_int(buff[1].Attributes, ATTR);
920
921 /* read attrs */
922 c.X = csbi.dwSize.X - 2;
923 c.Y = 0;
924 ret = ReadConsoleOutputAttribute(hConOut, attrs, ARRAYSIZE(attrs), c, &len);
925 ok_int(ret, 1);
926 ok_long(len, ARRAYSIZE(attrs));
927 ok_int(attrs[0], ATTR);
928 ok_int(attrs[1], ATTR);
929
930 /* read char */
931 ret = ReadConsoleOutputCharacterW(hConOut, str, 2, c, &len);
932 ok_int(ret, 1);
933 ok_long(len, 2);
934 ok_int(str[0], L'A');
935 ok_int(str[1], L'A');
936
937 /* fill by 'A' */
938 c.X = c.Y = 0;
939 ret = FillConsoleOutputCharacterW(hConOut, L'A', 10, c, &len);
940 ok_int(ret, 1);
941 ok_long(len, 10);
942
943 /* fill by u0414 */
944 c.X = 1;
945 c.Y = 0;
946 ret = FillConsoleOutputCharacterW(hConOut, 0x0414, 1, c, &len);
947 c.X = c.Y = 0;
948 ok_int(ret, 1);
949 ok_long(len, 1);
950
951 /* reset buff */
952 buffSize.X = ARRAYSIZE(buff);
953 buffSize.Y = 1;
954 memset(buff, 0x7F, sizeof(buff));
955
956 /* read output */
957 c.X = c.Y = 0;
958 sr.Left = 0;
959 sr.Top = 0;
960 sr.Right = 4;
961 sr.Bottom = 0;
962 ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
963 ok_int(ret, 1);
964 ok_int(sr.Left, 0);
965 ok_int(sr.Top, 0);
966 ok_int(sr.Right, 4);
967 ok_int(sr.Bottom, 0);
968
969 /* check buff */
970 ok_int(buff[0].Char.UnicodeChar, L'A');
971 ok_int(buff[0].Attributes, ATTR);
972 if (s_bIs8Plus)
973 {
974 ok_int(buff[1].Char.UnicodeChar, 0x0414);
975 ok_int(buff[1].Attributes, ATTR | COMMON_LVB_LEADING_BYTE);
976 ok_int(buff[2].Char.UnicodeChar, 0x0414);
977 ok_int(buff[2].Attributes, ATTR | COMMON_LVB_TRAILING_BYTE);
978 }
979 else
980 {
981 ok_int(buff[1].Char.UnicodeChar, L' ');
982 ok_int(buff[1].Attributes, ATTR);
983 ok_int(buff[2].Char.UnicodeChar, L'A');
984 ok_int(buff[2].Attributes, ATTR);
985 }
986 ok_int(buff[3].Char.UnicodeChar, L'A');
987 ok_int(buff[3].Attributes, ATTR);
988 ok_int(buff[4].Char.UnicodeChar, L'A');
989 ok_int(buff[4].Attributes, ATTR);
990
991 /* read attrs */
992 c.X = 0;
993 c.Y = 0;
994 ret = ReadConsoleOutputAttribute(hConOut, attrs, 4, c, &len);
995 ok_int(ret, 1);
996 ok_long(len, 4);
997 ok_int(attrs[0], ATTR);
998 if (s_bIs8Plus)
999 {
1000 ok_int(attrs[1], ATTR | COMMON_LVB_LEADING_BYTE);
1001 ok_int(attrs[2], ATTR | COMMON_LVB_TRAILING_BYTE);
1002 }
1003 else
1004 {
1005 ok_int(attrs[1], ATTR);
1006 ok_int(attrs[2], ATTR);
1007 }
1008 ok_int(attrs[3], ATTR);
1009 }
1010
1011 /* COMMON_LVB_LEADING_BYTE and COMMON_LVB_TRAILING_BYTE for u9580 */
1012 {
1013 /* set cursor */
1014 c.X = c.Y = 0;
1015 SetConsoleCursorPosition(hConOut, c);
1016 okCURSOR(hConOut, c);
1017
1018 /* fill by 'A' */
1019 ret = FillConsoleOutputCharacterW(hConOut, L'A', csbi.dwSize.X * 2, c, &len);
1020 ok_int(ret, 1);
1021 ok_long(len, csbi.dwSize.X * 2);
1022
1023 /* reset buff */
1024 buffSize.X = ARRAYSIZE(buff);
1025 buffSize.Y = 1;
1026 memset(buff, 0x7F, sizeof(buff));
1027
1028 /* read output */
1029 c.X = c.Y = 0;
1030 ZeroMemory(&sr, sizeof(sr));
1031 sr.Right = buffSize.X - 1;
1032 ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
1033 ok_int(ret, 1);
1034 ok_int(sr.Left, 0);
1035 ok_int(sr.Top, 0);
1036 ok_int(sr.Right, buffSize.X - 1);
1037 ok_int(sr.Bottom, 0);
1038
1039 /* check buff */
1040 ok_int(buff[0].Char.UnicodeChar, L'A');
1041 ok_int(buff[0].Attributes, ATTR);
1042
1043 /* read attr */
1044 ret = ReadConsoleOutputAttribute(hConOut, attrs, 1, c, &len);
1045 ok_int(ret, 1);
1046 ok_long(len, 1);
1047 ok_int(attrs[0], ATTR);
1048
1049 /* read char */
1050 memset(str, 0x7F, sizeof(str));
1051 ret = ReadConsoleOutputCharacterW(hConOut, str, 2, c, &len);
1052 ok_int(ret, 1);
1053 ok_long(len, 2);
1054 ok_int(str[0], L'A');
1055 ok_int(str[1], L'A');
1056
1057 /* set cursor */
1058 c.X = 0;
1059 c.Y = 0;
1060 SetConsoleCursorPosition(hConOut, c);
1061 okCURSOR(hConOut, c);
1062
1063 /* write u9580 */
1064 ret = WriteConsoleW(hConOut, u9580, 1, &len, NULL);
1065 ok_int(ret, 1);
1066 ok_long(len, 1);
1067
1068 /* reset buff */
1069 buffSize.X = ARRAYSIZE(buff);
1070 buffSize.Y = 1;
1071 memset(buff, 0x7F, sizeof(buff));
1072
1073 /* read output */
1074 c.X = c.Y = 0;
1075 ZeroMemory(&sr, sizeof(sr));
1076 sr.Right = buffSize.X - 1;
1077 ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
1078 ok_int(ret, 1);
1079 ok_int(sr.Left, 0);
1080 ok_int(sr.Top, 0);
1081 ok_int(sr.Right, buffSize.X - 1);
1082 ok_int(sr.Bottom, 0);
1083
1084 /* check buff */
1085 if (s_bIs8Plus)
1086 {
1087 ok_int(buff[0].Char.UnicodeChar, u9580[0]);
1088 ok_int(buff[0].Attributes, ATTR | COMMON_LVB_LEADING_BYTE);
1089 ok_int(buff[1].Char.UnicodeChar, u9580[0]);
1090 ok_int(buff[1].Attributes, ATTR | COMMON_LVB_TRAILING_BYTE);
1091 }
1092 else
1093 {
1094 ok_int(buff[0].Char.UnicodeChar, u9580[0]);
1095 ok_int(buff[0].Attributes, ATTR);
1096 ok_int(buff[1].Char.UnicodeChar, L'A');
1097 ok_int(buff[1].Attributes, ATTR);
1098 }
1099 ok_int(buff[2].Char.UnicodeChar, L'A');
1100 ok_int(buff[2].Attributes, ATTR);
1101 ok_int(buff[3].Char.UnicodeChar, L'A');
1102 ok_int(buff[3].Attributes, ATTR);
1103
1104 /* read attr */
1105 ret = ReadConsoleOutputAttribute(hConOut, attrs, ARRAYSIZE(attrs), c, &len);
1106 ok_int(ret, 1);
1107 ok_long(len, ARRAYSIZE(attrs));
1108
1109 ok_int(attrs[0], ATTR | COMMON_LVB_LEADING_BYTE);
1110 ok_int(attrs[1], ATTR | COMMON_LVB_TRAILING_BYTE);
1111 ok_int(attrs[2], ATTR);
1112 ok_int(attrs[3], ATTR);
1113
1114 /* read char */
1115 c.X = c.Y = 0;
1116 memset(str, 0x7F, sizeof(str));
1117 ret = ReadConsoleOutputCharacterW(hConOut, str, 4, c, &len);
1118 ok_int(ret, 1);
1119 ok_long(len, 3);
1120 ok_int(str[0], u9580[0]);
1121 ok_int(str[1], L'A');
1122 ok_int(str[2], L'A');
1123 if (s_bIs8Plus)
1124 ok_int(str[3], 0);
1125 else
1126 ok_int(str[3], 0x7F7F);
1127
1128 /* set cursor */
1129 c.X = 1;
1130 c.Y = 0;
1131 SetConsoleCursorPosition(hConOut, c);
1132 okCURSOR(hConOut, c);
1133
1134 /* write u9580 */
1135 ret = WriteConsoleW(hConOut, u9580, 1, &len, NULL);
1136 ok_int(ret, 1);
1137 ok_long(len, 1);
1138
1139 /* read output */
1140 c.X = c.Y = 0;
1141 ZeroMemory(&sr, sizeof(sr));
1142 sr.Right = buffSize.X - 1;
1143 ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
1144 ok_int(ret, 1);
1145 ok_int(sr.Left, 0);
1146 ok_int(sr.Top, 0);
1147 ok_int(sr.Right, buffSize.X - 1);
1148 ok_int(sr.Bottom, 0);
1149
1150 /* check buff */
1151 if (s_bIs8Plus)
1152 {
1153 ok_int(buff[0].Char.UnicodeChar, u9580[0]);
1154 ok_int(buff[0].Attributes, ATTR | COMMON_LVB_LEADING_BYTE);
1155 ok_int(buff[1].Char.UnicodeChar, u9580[0]);
1156 ok_int(buff[1].Attributes, ATTR | COMMON_LVB_LEADING_BYTE);
1157 ok_int(buff[2].Char.UnicodeChar, u9580[0]);
1158 ok_int(buff[2].Attributes, ATTR | COMMON_LVB_TRAILING_BYTE);
1159 }
1160 else
1161 {
1162 ok_int(buff[0].Char.UnicodeChar, L' ');
1163 ok_int(buff[0].Attributes, ATTR);
1164 ok_int(buff[1].Char.UnicodeChar, u9580[0]);
1165 ok_int(buff[1].Attributes, ATTR);
1166 ok_int(buff[2].Char.UnicodeChar, L'A');
1167 ok_int(buff[2].Attributes, ATTR);
1168 }
1169 ok_int(buff[3].Char.UnicodeChar, L'A');
1170 ok_int(buff[3].Attributes, ATTR);
1171
1172 /* read attr */
1173 c.X = c.Y = 0;
1174 ret = ReadConsoleOutputAttribute(hConOut, attrs, ARRAYSIZE(attrs), c, &len);
1175 ok_int(ret, 1);
1176 ok_long(len, ARRAYSIZE(attrs));
1177
1178 if (s_bIs8Plus)
1179 {
1180 ok_int(attrs[0], ATTR | COMMON_LVB_LEADING_BYTE);
1181 }
1182 else
1183 {
1184 ok_int(attrs[0], ATTR);
1185 }
1186 ok_int(attrs[1], ATTR | COMMON_LVB_LEADING_BYTE);
1187 ok_int(attrs[2], ATTR | COMMON_LVB_TRAILING_BYTE);
1188 ok_int(attrs[3], ATTR);
1189
1190 /* set cursor */
1191 c.X = csbi.dwSize.X - 1;
1192 c.Y = 0;
1193 SetConsoleCursorPosition(hConOut, c);
1194 okCURSOR(hConOut, c);
1195
1196 /* write u9580 */
1197 WriteConsoleW(hConOut, u9580, 1, &len, NULL);
1198 ok_int(ret, 1);
1199 ok_long(len, 1);
1200
1201 /* reset buff */
1202 buffSize.X = ARRAYSIZE(buff);
1203 buffSize.Y = 1;
1204 memset(buff, 0x7F, sizeof(buff));
1205
1206 /* read output */
1207 c.X = c.Y = 0;
1208 sr.Left = csbi.dwSize.X - 2;
1209 sr.Top = 0;
1210 sr.Right = csbi.dwSize.X - 1;
1211 sr.Bottom = 0;
1212 ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
1213 ok_int(ret, 1);
1214 ok_int(sr.Left, csbi.dwSize.X - 2);
1215 ok_int(sr.Top, 0);
1216 ok_int(sr.Right, csbi.dwSize.X - 1);
1217 ok_int(sr.Bottom, 0);
1218
1219 /* check buff */
1220 ok_int(buff[0].Char.UnicodeChar, L'A');
1221 ok_int(buff[0].Attributes, ATTR);
1222 ok_int(buff[1].Char.UnicodeChar, L'A');
1223 ok_int(buff[1].Attributes, ATTR);
1224
1225 /* read attr */
1226 c.X = csbi.dwSize.X - 2;
1227 c.Y = 0;
1228 ret = ReadConsoleOutputAttribute(hConOut, attrs, ARRAYSIZE(attrs), c, &len);
1229 ok_int(ret, 1);
1230 ok_long(len, ARRAYSIZE(attrs));
1231 ok_int(attrs[0], ATTR);
1232 ok_int(attrs[1], ATTR);
1233
1234 /* read char */
1235 memset(str, 0x7F, sizeof(str));
1236 ret = ReadConsoleOutputCharacterW(hConOut, str, 2, c, &len);
1237 ok_int(ret, 1);
1238 ok_long(len, 2);
1239 ok_int(str[0], L'A');
1240 ok_int(str[1], L'A');
1241
1242 /* fill by 'A' */
1243 c.X = c.Y = 0;
1244 ret = FillConsoleOutputCharacterW(hConOut, L'A', 10, c, &len);
1245 ok_int(ret, 1);
1246 ok_long(len, 10);
1247
1248 /* fill by u9580 */
1249 c.X = 1;
1250 c.Y = 0;
1251 ret = FillConsoleOutputCharacterW(hConOut, u9580[0], 1, c, &len);
1252 c.X = c.Y = 0;
1253 ok_int(ret, 1);
1254 ok_long(len, 1);
1255
1256 /* reset buff */
1257 buffSize.X = ARRAYSIZE(buff);
1258 buffSize.Y = 1;
1259 memset(buff, 0x7F, sizeof(buff));
1260
1261 /* read output */
1262 c.X = c.Y = 0;
1263 sr.Left = 0;
1264 sr.Top = 0;
1265 sr.Right = 4;
1266 sr.Bottom = 0;
1267 ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
1268 ok_int(ret, 1);
1269 ok_int(sr.Left, 0);
1270 ok_int(sr.Top, 0);
1271 ok_int(sr.Right, 4);
1272 ok_int(sr.Bottom, 0);
1273
1274 /* check buff */
1275 ok_int(buff[0].Char.UnicodeChar, L'A');
1276 ok_int(buff[0].Attributes, ATTR);
1277 if (s_bIs8Plus)
1278 {
1279 ok_int(buff[1].Char.UnicodeChar, u9580[0]);
1280 ok_int(buff[1].Attributes, ATTR | COMMON_LVB_LEADING_BYTE);
1281 ok_int(buff[2].Char.UnicodeChar, u9580[0]);
1282 ok_int(buff[2].Attributes, ATTR | COMMON_LVB_TRAILING_BYTE);
1283 }
1284 else
1285 {
1286 ok_int(buff[1].Char.UnicodeChar, L' ');
1287 ok_int(buff[1].Attributes, ATTR);
1288 ok_int(buff[2].Char.UnicodeChar, L'A');
1289 ok_int(buff[2].Attributes, ATTR);
1290 }
1291 ok_int(buff[3].Char.UnicodeChar, L'A');
1292 ok_int(buff[3].Attributes, ATTR);
1293 ok_int(buff[4].Char.UnicodeChar, L'A');
1294 ok_int(buff[4].Attributes, ATTR);
1295
1296 /* read attrs */
1297 c.X = 0;
1298 c.Y = 0;
1299 ret = ReadConsoleOutputAttribute(hConOut, attrs, 4, c, &len);
1300 ok_int(ret, 1);
1301 ok_long(len, 4);
1302 ok_int(attrs[0], ATTR);
1303 if (s_bIs8Plus)
1304 {
1305 ok_int(attrs[1], ATTR | COMMON_LVB_LEADING_BYTE);
1306 ok_int(attrs[2], ATTR | COMMON_LVB_TRAILING_BYTE);
1307 }
1308 else
1309 {
1310 ok_int(attrs[1], ATTR);
1311 ok_int(attrs[2], ATTR);
1312 }
1313 ok_int(attrs[3], ATTR);
1314 }
1315
1316 /* FillConsoleOutputAttribute and WriteConsoleOutput */
1317 {
1318 c.X = c.Y = 0;
1319 SetConsoleCursorPosition(hConOut, c);
1320 okCURSOR(hConOut, c);
1321 for (n = 0; n < count; ++n)
1322 {
1323 ret = WriteConsoleW(hConOut, space, lstrlenW(space), &len, NULL);
1324 ok_int(ret, 1);
1325 ok_long(len, 1);
1326 }
1327
1328 /* fill attrs */
1329 c.X = c.Y = 0;
1330 SetConsoleCursorPosition(hConOut, c);
1331 okCURSOR(hConOut, c);
1332 ret = FillConsoleOutputAttribute(hConOut, 0xFFFF, 2, c, &len);
1333 ok_int(ret, 1);
1334 ok_long(len, 2);
1335
1336 /* read attrs */
1337 memset(attrs, 0x7F, sizeof(attrs));
1338 ret = ReadConsoleOutputAttribute(hConOut, attrs, 3, c, &len);
1339 ok_int(ret, 1);
1340 ok_long(len, 3);
1341 if (s_bIs8Plus)
1342 {
1343 ok_int(attrs[0], 0xDCFF);
1344 ok_int(attrs[1], 0xDCFF);
1345 }
1346 else
1347 {
1348 ok_int(attrs[0], 0xFCFF);
1349 ok_int(attrs[1], 0xFCFF);
1350 }
1351 ok_int(attrs[2], ATTR);
1352
1353 /* fill attrs */
1354 c.X = c.Y = 0;
1355 SetConsoleCursorPosition(hConOut, c);
1356 okCURSOR(hConOut, c);
1357 ret = FillConsoleOutputAttribute(hConOut, ATTR, 4, c, &len);
1358 ok_int(ret, 1);
1359 ok_long(len, 4);
1360
1361 /* write */
1362 c.X = c.Y = 0;
1363 sr.Left = 0;
1364 sr.Top = 0;
1365 sr.Right = 4;
1366 sr.Bottom = 0;
1367 // Check how Read/WriteConsoleOutput() handle inconsistent DBCS flags.
1368 buff[0].Char.UnicodeChar = u9580[0];
1369 buff[0].Attributes = ATTR | COMMON_LVB_LEADING_BYTE;
1370 buff[1].Char.UnicodeChar = u9580[0];
1371 buff[1].Attributes = ATTR | COMMON_LVB_LEADING_BYTE;
1372 buff[2].Char.UnicodeChar = u9580[0];
1373 buff[2].Attributes = ATTR | COMMON_LVB_TRAILING_BYTE;
1374 buff[3].Char.UnicodeChar = L'A';
1375 buff[3].Attributes = ATTR;
1376 buff[4].Char.UnicodeChar = L' ';
1377 buff[4].Attributes = 0xFFFF;
1378 buffSize.X = 4;
1379 buffSize.Y = 1;
1380 ret = WriteConsoleOutputW(hConOut, buff, buffSize, c, &sr);
1381 ok_int(ret, 1);
1382 ok_int(sr.Left, 0);
1383 ok_int(sr.Top, 0);
1384 ok_int(sr.Right, 3);
1385 ok_int(sr.Bottom, 0);
1386
1387 /* read output */
1388 sr.Left = 0;
1389 sr.Top = 0;
1390 sr.Right = 4;
1391 sr.Bottom = 0;
1392 memset(buff, 0x7F, sizeof(buff));
1393 ret = ReadConsoleOutputW(hConOut, buff, buffSize, c, &sr);
1394 ok_int(ret, 1);
1395 ok_int(sr.Left, 0);
1396 ok_int(sr.Top, 0);
1397 ok_int(sr.Right, 3);
1398 ok_int(sr.Bottom, 0);
1399
1400 /* check buff */
1401 if (s_bIs8Plus)
1402 {
1403 ok_int(buff[0].Char.UnicodeChar, u9580[0]);
1404 ok_int(buff[0].Attributes, ATTR | COMMON_LVB_LEADING_BYTE);
1405 ok_int(buff[1].Char.UnicodeChar, u9580[0]);
1406 ok_int(buff[1].Attributes, ATTR | COMMON_LVB_LEADING_BYTE);
1407 ok_int(buff[2].Char.UnicodeChar, u9580[0]);
1408 ok_int(buff[2].Attributes, ATTR | COMMON_LVB_TRAILING_BYTE);
1409 ok_int(buff[3].Char.UnicodeChar, L'A');
1410 ok_int(buff[3].Attributes, ATTR);
1411 ok_int(buff[4].Char.UnicodeChar, 0x7F7F);
1412 ok_int(buff[4].Attributes, 0x7F7F);
1413 }
1414 else
1415 {
1416 ok_int(buff[0].Char.UnicodeChar, u9580[0]);
1417 ok_int(buff[0].Attributes, ATTR);
1418 ok_int(buff[1].Char.UnicodeChar, u9580[0]);
1419 ok_int(buff[1].Attributes, ATTR);
1420 ok_int(buff[2].Char.UnicodeChar, 0);
1421 ok_int(buff[2].Attributes, 0);
1422 ok_int(buff[3].Char.UnicodeChar, 0);
1423 ok_int(buff[3].Attributes, 0);
1424 ok_int(buff[4].Char.UnicodeChar, 0x7F7F);
1425 ok_int(buff[4].Attributes, 0x7F7F);
1426 }
1427
1428 /* read attrs */
1429 c.X = c.Y = 0;
1430 memset(attrs, 0x7F, sizeof(attrs));
1431 ret = ReadConsoleOutputAttribute(hConOut, attrs, 6, c, &len);
1432 ok_int(ret, 1);
1433 ok_long(len, 6);
1434 ok_int(attrs[0], ATTR | COMMON_LVB_LEADING_BYTE);
1435 if (s_bIs8Plus)
1436 {
1437 ok_int(attrs[1], ATTR | COMMON_LVB_LEADING_BYTE);
1438 ok_int(attrs[2], ATTR | COMMON_LVB_TRAILING_BYTE);
1439 ok_int(attrs[3], ATTR);
1440 }
1441 else
1442 {
1443 ok_int(attrs[1], ATTR | COMMON_LVB_TRAILING_BYTE);
1444 ok_int(attrs[2], ATTR | COMMON_LVB_LEADING_BYTE);
1445 ok_int(attrs[3], ATTR | COMMON_LVB_TRAILING_BYTE);
1446 }
1447 ok_int(attrs[4], ATTR);
1448 ok_int(attrs[5], ATTR);
1449 }
1450
1451 /* WriteConsoleOutputCharacterW and WriteConsoleOutputAttribute */
1452 {
1453 c.X = c.Y = 0;
1454 SetConsoleCursorPosition(hConOut, c);
1455 okCURSOR(hConOut, c);
1456 for (n = 0; n < count; ++n)
1457 {
1458 ret = WriteConsoleW(hConOut, space, lstrlenW(space), &len, NULL);
1459 ok_int(ret, 1);
1460 ok_long(len, 1);
1461 }
1462
1463 /* write attrs */
1464 attrs[0] = ATTR;
1465 attrs[1] = 0xFFFF;
1466 attrs[2] = ATTR;
1467 attrs[3] = 0;
1468 ret = WriteConsoleOutputAttribute(hConOut, attrs, 4, c, &len);
1469 ok_int(ret, 1);
1470 ok_long(len, 4);
1471
1472 /* read attrs */
1473 memset(attrs, 0x7F, sizeof(attrs));
1474 ret = ReadConsoleOutputAttribute(hConOut, attrs, 4, c, &len);
1475 ok_int(ret, 1);
1476 ok_long(len, 4);
1477 ok_int(attrs[0], ATTR);
1478 if (s_bIs8Plus)
1479 ok_int(attrs[1], 0xDCFF);
1480 else
1481 ok_int(attrs[1], 0xFCFF);
1482 ok_int(attrs[2], ATTR);
1483 ok_int(attrs[3], 0);
1484
1485 /* fill attr */
1486 ret = FillConsoleOutputAttribute(hConOut, ATTR, 4, c, &len);
1487 ok_int(ret, 1);
1488 ok_long(len, 4);
1489
1490 /* write char */
1491 ret = WriteConsoleOutputCharacterW(hConOut, s_str, 4, c, &len);
1492 ok_int(ret, 1);
1493 ok_long(len, 4);
1494
1495 /* read attrs */
1496 memset(attrs, 0x7F, sizeof(attrs));
1497 ret = ReadConsoleOutputAttribute(hConOut, attrs, 4, c, &len);
1498 ok_int(ret, 1);
1499 ok_long(len, 4);
1500 ok_int(attrs[0], ATTR);
1501 ok_int(attrs[1], ATTR | COMMON_LVB_LEADING_BYTE);
1502 ok_int(attrs[2], ATTR | COMMON_LVB_TRAILING_BYTE);
1503 ok_int(attrs[3], ATTR);
1504 }
1505
1506 /* Restore code page */
1507 SetConsoleOutputCP(oldcp);
1508 }
1509
1510
START_TEST(ConsoleCP)1511 START_TEST(ConsoleCP)
1512 {
1513 HANDLE hConIn, hConOut;
1514 OSVERSIONINFOA osver = { sizeof(osver) };
1515
1516 // https://github.com/reactos/reactos/pull/2131#issuecomment-563189380
1517 GetVersionExA(&osver);
1518 s_bIs8Plus = (osver.dwMajorVersion > 6) ||
1519 (osver.dwMajorVersion == 6 && osver.dwMinorVersion >= 2);
1520
1521 FreeConsole();
1522 ok(AllocConsole(), "Couldn't alloc console\n");
1523
1524 hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1525 hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1526 ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n");
1527 ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n");
1528
1529 /* Retrieve the system OEM code page */
1530 s_uOEMCP = GetOEMCP();
1531 trace("Running on %s system (codepage %d)\n",
1532 IsCJKCodePage(s_uOEMCP) ? "CJK" : "Non-CJK",
1533 s_uOEMCP);
1534
1535 /* Test thread lang ID syncing with console code page */
1536 test_CP_ThreadLang();
1537
1538 if (IsValidLocale(lcidRussian, LCID_INSTALLED))
1539 {
1540 if (!IsCJKCodePage(s_uOEMCP))
1541 test_cp855(hConOut);
1542 else
1543 skip("Russian testcase is skipped because of CJK\n");
1544 }
1545 else
1546 {
1547 skip("Russian locale is not installed\n");
1548 }
1549
1550 if (IsValidLocale(lcidJapanese, LCID_INSTALLED))
1551 {
1552 if (IsCJKCodePage(s_uOEMCP))
1553 test_cp932(hConOut);
1554 else
1555 skip("Japanese testcase is skipped because of not CJK\n");
1556 }
1557 else
1558 {
1559 skip("Japanese locale is not installed\n");
1560 }
1561
1562 CloseHandle(hConIn);
1563 CloseHandle(hConOut);
1564 FreeConsole();
1565 ok(AllocConsole(), "Couldn't alloc console\n");
1566 }
1567