Index: rostests/apitests/kernel32/CMakeLists.txt =================================================================== --- rostests/apitests/kernel32/CMakeLists.txt (revision 74316) +++ rostests/apitests/kernel32/CMakeLists.txt (working copy) @@ -2,6 +2,7 @@ add_subdirectory(redirptest) list(APPEND SOURCE + Console.c DefaultActCtx.c DeviceIoControl.c dosdev.c Index: rostests/apitests/kernel32/Console.c =================================================================== --- rostests/apitests/kernel32/Console.c (nonexistent) +++ rostests/apitests/kernel32/Console.c (working copy) @@ -0,0 +1,474 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Test for i18n console test + * PROGRAMMERS: Katayama Hirofumi MZ + */ + +#include +#include +#include + +#define okCURSOR(hCon, c) do { \ + CONSOLE_SCREEN_BUFFER_INFO __sbi; \ + BOOL expect = GetConsoleScreenBufferInfo((hCon), &__sbi) && \ + __sbi.dwCursorPosition.X == (c).X && __sbi.dwCursorPosition.Y == (c).Y; \ + ok(expect, "Expected cursor at (%d,%d), got (%d,%d)\n", \ + (c).X, (c).Y, __sbi.dwCursorPosition.X, __sbi.dwCursorPosition.Y); \ +} while (0) + +#define ATTR \ + (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED) + +static const WCHAR u0414[] = { 0x0414, 0 }; /* Д */ +static const WCHAR u9580[] = { 0x9580, 0 }; /* 門 */ +static const WCHAR ideograph_space = (WCHAR)0x3000; /* fullwidth space */ +LCID lcidJapanese = MAKELCID(MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT), SORT_DEFAULT); +LCID lcidRussian = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT), SORT_DEFAULT); + +/* Russian Code Page 855 */ +static void test_cp855(HANDLE hConOut) +{ + BOOL ret; + DWORD oldcp; + int n; + DWORD len; + COORD c; + CONSOLE_SCREEN_BUFFER_INFO csbi; + int count; + WCHAR str[32]; + WORD attr; + + if (!IsValidCodePage(855)) + { + skip("Codepage 855 not available\n"); + return; + } + + /* set code page */ + oldcp = GetConsoleOutputCP(); + SetLastError(0xdeadbeef); + ret = SetConsoleOutputCP(855); + if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("SetConsoleOutputCP is not implemented\n"); + return; + } + + /* get info */ + ret = GetConsoleScreenBufferInfo(hConOut, &csbi); + ok(ret, "GetConsoleScreenBufferInfo failed\n"); + trace("csbi.dwSize.X:%d, csbi.dwSize.Y:%d\n", csbi.dwSize.X, csbi.dwSize.Y); + count = csbi.dwSize.X * 3 / 2; + trace("count: %d\n", count); + + /* "\u0414" */ + { + /* output u0414 "count" times at (0,0) */ + c.X = c.Y = 0; + SetConsoleCursorPosition(hConOut, c); + okCURSOR(hConOut, c); + for (n = 0; n < count; ++n) + { + ret = WriteConsoleW(hConOut, u0414, lstrlenW(u0414), &len, NULL); + ok(ret && len == lstrlenW(u0414), "WriteConsoleW failed\n"); + } + + /* check cursor */ + len = count; /* u0414 is normal width in Russian */ + c.X = len % csbi.dwSize.X; + c.Y = len / csbi.dwSize.X; + okCURSOR(hConOut, c); + + /* read characters at (0,0) */ + c.X = c.Y = 0; + ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len); + ok(ret, "ReadConsoleOutputCharacterW failed\n"); + ok(len == 6, "len was: %ld\n", len); + ok(str[0] == 0x414, "str[0] was: 0x%04X\n", str[0]); + ok(str[1] == 0x414, "str[1] was: 0x%04X\n", str[1]); + ok(str[2] == 0x414, "str[2] was: 0x%04X\n", str[2]); + + /* check cursor */ + c.X = 1; + c.Y = 0; + ret = SetConsoleCursorPosition(hConOut, c); + ok(ret, "SetConsoleCursorPosition failed\n"); + okCURSOR(hConOut, c); + + /* fill by space */ + c.X = c.Y = 0; + FillConsoleOutputCharacterW(hConOut, L' ', csbi.dwSize.X * csbi.dwSize.Y, c, &len); + + /* output u0414 "count" times at (1,0) */ + c.X = 1; + c.Y = 0; + SetConsoleCursorPosition(hConOut, c); + okCURSOR(hConOut, c); + for (n = 0; n < count; ++n) + { + ret = WriteConsoleW(hConOut, u0414, lstrlenW(u0414), &len, NULL); + ok(ret && len == lstrlenW(u0414), "WriteConsoleW failed\n"); + } + + /* check cursor */ + len = 1 + count; + c.X = len % csbi.dwSize.X; + c.Y = len / csbi.dwSize.X; + okCURSOR(hConOut, c); + + /* read characters at (0,0) */ + c.X = c.Y = 0; + ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len); + ok(ret, "ReadConsoleOutputCharacterW failed\n"); + ok(len == 6, "len was: %ld\n", len); + ok(str[0] == L' ', "str[0] was: 0x%04X\n", str[0]); + ok(str[1] == 0x414, "str[1] was: 0x%04X\n", str[1]); + ok(str[2] == 0x414, "str[2] was: 0x%04X\n", str[2]); + } + + /* "\u9580" */ + { + /* output u9580 "count" times at (0,0) */ + c.X = c.Y = 0; + SetConsoleCursorPosition(hConOut, c); + okCURSOR(hConOut, c); + for (n = 0; n < count; ++n) + { + ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL); + ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n"); + } + + /* check cursor */ + len = count; /* u9580 is normal width in Russian */ + c.X = len % csbi.dwSize.X; + c.Y = len / csbi.dwSize.X; + okCURSOR(hConOut, c); + + /* check cursor */ + c.X = 1; + c.Y = 0; + ret = SetConsoleCursorPosition(hConOut, c); + ok(ret, "SetConsoleCursorPosition failed\n"); + okCURSOR(hConOut, c); + + /* fill by space */ + c.X = c.Y = 0; + ret = FillConsoleOutputCharacterW(hConOut, L' ', csbi.dwSize.X * csbi.dwSize.Y, c, &len); + ok(ret, "FillConsoleOutputCharacterW failed\n"); + ok(len == csbi.dwSize.X * csbi.dwSize.Y, "len was: %ld\n", len); + + /* output u9580 "count" times at (1,0) */ + c.X = 1; + c.Y = 0; + SetConsoleCursorPosition(hConOut, c); + okCURSOR(hConOut, c); + for (n = 0; n < count; ++n) + { + ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL); + ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n"); + } + + /* check cursor */ + len = 1 + count; + c.X = len % csbi.dwSize.X; + c.Y = len / csbi.dwSize.X; + okCURSOR(hConOut, c); + + /* fill by ideograph space */ + c.X = c.Y = 0; + ret = FillConsoleOutputCharacterW(hConOut, ideograph_space, csbi.dwSize.X * csbi.dwSize.Y, c, &len); + ok(ret, "FillConsoleOutputCharacterW failed\n"); + ok(len == csbi.dwSize.X * csbi.dwSize.Y, "len was: %ld\n", len); + + /* read characters at (0,0) */ + c.X = c.Y = 0; + ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len); + ok(ret, "ReadConsoleOutputCharacterW failed\n"); + ok(len == 6, "len was: %ld\n", len); + ok(str[0] == ideograph_space || str[0] == L'?', "str[0] was: 0x%04X\n", str[0]); + ok(str[1] == ideograph_space || str[1] == L'?', "str[1] was: 0x%04X\n", str[1]); + ok(str[2] == ideograph_space || str[2] == L'?', "str[2] was: 0x%04X\n", str[2]); + + /* read attr at (0,0) */ + c.X = 0; + c.Y = 0; + ret = ReadConsoleOutputAttribute(hConOut, &attr, 1, c, &len); + ok(ret, "ReadConsoleOutputAttribute failed\n"); + ok(attr == ATTR, "attr was: %d\n", attr); + ok(len == 1, "len was %ld\n", len); + + /* read characters at (1,0) */ + c.X = 1; + c.Y = 0; + ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len); + ok(ret, "ReadConsoleOutputCharacterW failed\n"); + ok(len == 6, "len was: %ld\n", len); + ok(str[0] == ideograph_space || str[0] == L'?', "str[0] was: 0x%04X\n", str[0]); + ok(str[1] == ideograph_space || str[1] == L'?', "str[1] was: 0x%04X\n", str[1]); + ok(str[2] == ideograph_space || str[2] == L'?', "str[2] was: 0x%04X\n", str[2]); + + /* output u9580 "count" once at (1,0) */ + c.X = 1; + c.Y = 0; + SetConsoleCursorPosition(hConOut, c); + okCURSOR(hConOut, c); + ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL); + ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n"); + + /* read attr (1,0) */ + c.X = 1; + c.Y = 0; + ret = ReadConsoleOutputAttribute(hConOut, &attr, 1, c, &len); + ok(ret, "ReadConsoleOutputAttribute failed\n"); + ok(attr == ATTR, "attr was: %d\n", attr); + ok(len == 1, "len was %ld\n", len); + /* check cursor */ + c.X = 2; + c.Y = 0; + okCURSOR(hConOut, c); + + /* read characters at (0,0) */ + c.X = c.Y = 0; + ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len); + ok(ret, "ReadConsoleOutputCharacterW failed\n"); + ok(len == 6, "len was: %ld\n", len); + ok(str[0] == ideograph_space || str[0] == L'?', "str[0] was: 0x%04X\n", str[0]); + ok(str[1] == 0x9580 || str[1] == L'?', "str[1] was: 0x%04X\n", str[1]); + ok(str[2] == ideograph_space || str[2] == L'?', "str[2] was: 0x%04X\n", str[2]); + } + + /* restore code page */ + SetConsoleOutputCP(oldcp); +} + +/* Japanese Code Page 932 */ +static void test_cp932(HANDLE hConOut) +{ + BOOL ret; + DWORD oldcp; + int n; + DWORD len; + COORD c; + CONSOLE_SCREEN_BUFFER_INFO csbi; + int count; + WCHAR str[32]; + WORD attr; + + if (!IsValidCodePage(932)) + { + skip("Codepage 932 not available\n"); + return; + } + + /* set code page */ + oldcp = GetConsoleOutputCP(); + SetLastError(0xdeadbeef); + ret = SetConsoleOutputCP(932); + if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("SetConsoleOutputCP is not implemented\n"); + return; + } + + /* get info */ + ret = GetConsoleScreenBufferInfo(hConOut, &csbi); + ok(ret, "GetConsoleScreenBufferInfo failed\n"); + trace("csbi.dwSize.X:%d, csbi.dwSize.Y:%d\n", csbi.dwSize.X, csbi.dwSize.Y); + count = csbi.dwSize.X * 3 / 2; + trace("count: %d\n", count); + + /* "\u0414" */ + { + /* output u0414 "count" times at (0,0) */ + c.X = c.Y = 0; + SetConsoleCursorPosition(hConOut, c); + okCURSOR(hConOut, c); + for (n = 0; n < count; ++n) + { + ret = WriteConsoleW(hConOut, u0414, lstrlenW(u0414), &len, NULL); + ok(ret && len == lstrlenW(u0414), "WriteConsoleW failed\n"); + } + + /* check cursor */ + GetConsoleScreenBufferInfo(hConOut, &csbi); + len = count * 2; /* u0414 is fullwidth in Japanese */ + c.X = len % csbi.dwSize.X; + c.Y = len / csbi.dwSize.X; + okCURSOR(hConOut, c); + + /* read characters at (0,0) */ + c.X = c.Y = 0; + ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len); + ok(ret, "ReadConsoleOutputCharacterW failed\n"); + ok(len == 3, "len was: %ld\n", len); + ok(str[0] == 0x414, "str[0] was: 0x%04X\n", str[0]); + ok(str[1] == 0x414, "str[1] was: 0x%04X\n", str[1]); + ok(str[2] == 0x414, "str[2] was: 0x%04X\n", str[2]); + + /* check cursor */ + c.X = 1; + c.Y = 0; + ret = SetConsoleCursorPosition(hConOut, c); + ok(ret, "SetConsoleCursorPosition failed\n"); + okCURSOR(hConOut, c); + + /* fill by space */ + c.X = c.Y = 0; + FillConsoleOutputCharacterW(hConOut, L' ', csbi.dwSize.X * csbi.dwSize.Y, c, &len); + + /* output u0414 "count" times at (1,0) */ + c.X = 1; + c.Y = 0; + SetConsoleCursorPosition(hConOut, c); + okCURSOR(hConOut, c); + for (n = 0; n < count; ++n) + { + ret = WriteConsoleW(hConOut, u0414, lstrlenW(u0414), &len, NULL); + ok(ret && len == lstrlenW(u0414), "WriteConsoleW failed\n"); + } + + /* check cursor */ + len = csbi.dwSize.X + (count - (csbi.dwSize.X - 1) / 2) * 2; + c.X = len % csbi.dwSize.X; + c.Y = len / csbi.dwSize.X; + okCURSOR(hConOut, c); + + /* read characters at (0,0) */ + c.X = 0; + c.Y = 0; + ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len); + ok(ret, "ReadConsoleOutputCharacterW failed\n"); + ok(len == 4, "len was: %ld\n", len); + ok(str[0] == L' ', "str[0] was: 0x%04X\n", str[0]); + ok(str[1] == 0x414, "str[1] was: 0x%04X\n", str[1]); + ok(str[2] == 0x414, "str[2] was: 0x%04X\n", str[2]); + } + + /* "\u9580" */ + { + /* output u9580 "count" times at (0,0) */ + c.X = c.Y = 0; + SetConsoleCursorPosition(hConOut, c); + okCURSOR(hConOut, c); + for (n = 0; n < count; ++n) + { + ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL); + ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n"); + } + + /* check cursor */ + len = count * 2; /* u9580 is fullwidth in Japanese */ + c.X = len % csbi.dwSize.X; + c.Y = len / csbi.dwSize.X; + okCURSOR(hConOut, c); + + /* check cursor */ + c.X = 1; + c.Y = 0; + ret = SetConsoleCursorPosition(hConOut, c); + ok(ret, "SetConsoleCursorPosition failed\n"); + okCURSOR(hConOut, c); + + /* fill by space */ + c.X = c.Y = 0; + ret = FillConsoleOutputCharacterW(hConOut, L' ', csbi.dwSize.X * csbi.dwSize.Y, c, &len); + ok(ret, "FillConsoleOutputCharacterW failed\n"); + ok(len == csbi.dwSize.X * csbi.dwSize.Y, "len was: %ld\n", len); + + /* output u9580 "count" times at (1,0) */ + c.X = 1; + c.Y = 0; + SetConsoleCursorPosition(hConOut, c); + okCURSOR(hConOut, c); + for (n = 0; n < count; ++n) + { + ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL); + ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n"); + } + + /* check cursor */ + len = csbi.dwSize.X + (count - (csbi.dwSize.X - 1) / 2) * 2; + c.X = len % csbi.dwSize.X; + c.Y = len / csbi.dwSize.X; + okCURSOR(hConOut, c); + + /* fill by ideograph space */ + c.X = c.Y = 0; + ret = FillConsoleOutputCharacterW(hConOut, ideograph_space, csbi.dwSize.X * csbi.dwSize.Y, c, &len); + ok(ret, "FillConsoleOutputCharacterW failed\n"); + ok(len == csbi.dwSize.X * csbi.dwSize.Y, "len was: %ld\n", len); + + /* read characters */ + c.X = 0; + c.Y = 0; + ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len); + ok(ret, "ReadConsoleOutputCharacterW failed\n"); + ok(len == 3, "len was: %ld\n", len); + ok(str[0] == ideograph_space, "str[0] was: 0x%04X\n", str[0]); + ok(str[1] == ideograph_space, "str[1] was: 0x%04X\n", str[1]); + ok(str[2] == ideograph_space, "str[2] was: 0x%04X\n", str[2]); + /* read attr */ + ret = ReadConsoleOutputAttribute(hConOut, &attr, 1, c, &len); + ok(ret, "ReadConsoleOutputAttribute failed\n"); + ok(attr == ATTR, "attr was: %d\n", attr); + ok(len == 1, "len was %ld\n", len); + + /* output u9580 "count" once at (1,0) */ + c.X = 1; + c.Y = 0; + SetConsoleCursorPosition(hConOut, c); + okCURSOR(hConOut, c); + ret = WriteConsoleW(hConOut, u9580, lstrlenW(u9580), &len, NULL); + ok(ret && len == lstrlenW(u9580), "WriteConsoleW failed\n"); + /* read attr */ + ret = ReadConsoleOutputAttribute(hConOut, &attr, 1, c, &len); + ok(ret, "ReadConsoleOutputAttribute failed\n"); + ok(attr == ATTR, "attr was: %d\n", attr); + ok(len == 1, "len was %ld\n", len); + /* check cursor */ + c.X = 3; + c.Y = 0; + okCURSOR(hConOut, c); + + /* read characters */ + c.X = 0; + c.Y = 0; + ret = ReadConsoleOutputCharacterW(hConOut, str, 3 * sizeof(WCHAR), c, &len); + ok(ret, "ReadConsoleOutputCharacterW failed\n"); + ok(len == 4, "len was: %ld\n", len); + ok(str[0] == L' ', "str[0] was: 0x%04X\n", str[0]); + ok(str[1] == 0x9580, "str[1] was: 0x%04X\n", str[1]); + ok(str[2] == L' ', "str[2] was: 0x%04X\n", str[2]); + } + + /* restore code page */ + SetConsoleOutputCP(oldcp); +} + +START_TEST(Console) +{ + HANDLE hConIn, hConOut; + FreeConsole(); + ok(AllocConsole(), "Couldn't alloc console\n"); + + hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n"); + ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n"); + + if (IsValidLocale(lcidRussian, LCID_INSTALLED)) + test_cp855(hConOut); + else + skip("Russian is not installed locale\n"); + + if (IsValidLocale(lcidJapanese, LCID_INSTALLED)) + test_cp932(hConOut); + else + skip("Japanese is not installed locale\n"); + + CloseHandle(hConIn); + CloseHandle(hConOut); + FreeConsole(); + ok(AllocConsole(), "Couldn't alloc console\n"); +} Index: rostests/apitests/kernel32/testlist.c =================================================================== --- rostests/apitests/kernel32/testlist.c (revision 74316) +++ rostests/apitests/kernel32/testlist.c (working copy) @@ -3,6 +3,7 @@ #define STANDALONE #include +extern void func_Console(void); extern void func_DefaultActCtx(void); extern void func_DeviceIoControl(void); extern void func_dosdev(void); @@ -28,6 +29,7 @@ const struct test winetest_testlist[] = { + { "Console", func_Console }, { "DefaultActCtx", func_DefaultActCtx }, { "DeviceIoControl", func_DeviceIoControl }, { "dosdev", func_dosdev },