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 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 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 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 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 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 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 */ 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 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