From: Hermès Bélusca-Maïto Date: Tue, 9 Oct 2012 20:56:11 +0000 (+0000) Subject: [MSVCRT:APITEST] X-Git-Tag: backups/ros-csrss@57560~34 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=6dacc020db15a6dc9cebf7a968101a73c68e1c00;hp=bc8c82214e6f3a0d003dfb4f20605f5a013b04c1 [MSVCRT:APITEST] - Add a test which allows testing the command line argument lpCmdLine in WinMain function (GUI programs). svn path=/trunk/; revision=57524 --- diff --git a/rostests/apitests/msvcrt/CMakeLists.txt b/rostests/apitests/msvcrt/CMakeLists.txt index 59c6772b378..07022be9e40 100644 --- a/rostests/apitests/msvcrt/CMakeLists.txt +++ b/rostests/apitests/msvcrt/CMakeLists.txt @@ -1,7 +1,10 @@ +add_subdirectory(cmdline_util) + add_definitions(-D_DLL -D__USE_CRTIMP) list(APPEND SOURCE + CommandLine.c ieee.c splitpath.c testlist.c) diff --git a/rostests/apitests/msvcrt/CommandLine.c b/rostests/apitests/msvcrt/CommandLine.c new file mode 100644 index 00000000000..e6b6c999c81 --- /dev/null +++ b/rostests/apitests/msvcrt/CommandLine.c @@ -0,0 +1,280 @@ +/* + * PROJECT: ReactOS API Tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Test for CRT command-line handling. + * PROGRAMMER: Hermès BÉLUSCA - MAÏTO + */ + +#define WIN32_NO_STATUS +#define UNICODE +#include +#include +#include + +#define COUNT_OF(x) (sizeof((x))/sizeof((x)[0])) + +/* + * The path to the data file is hardcoded in cmdline_util.c + * Please synchronize it whenever you do a change. + */ +#define DATAFILE L"C:\\cmdline.dat" + +/** + * Extracts the command tail from the command line + * (deletes the program's name and keep the rest). + **/ +#define SPACECHAR L' ' +#define DQUOTECHAR L'\"' + +LPWSTR ExtractCmdLine(IN LPWSTR lpszCommandLine) +{ + BOOL inDoubleQuote = FALSE; + + /* + * Skip the program's name (the first token in the command line). + * Handle quoted program's name. + */ + if (lpszCommandLine) + { + while ( (*lpszCommandLine > SPACECHAR) || + (*lpszCommandLine && inDoubleQuote) ) + { + if (*lpszCommandLine == DQUOTECHAR) + inDoubleQuote = !inDoubleQuote; + + ++lpszCommandLine; + } + + /* Skip all white spaces preceeding the second token. */ + while (*lpszCommandLine && (*lpszCommandLine <= SPACECHAR)) + ++lpszCommandLine; + } + + return lpszCommandLine; +} + +VOID ExtractCmdLine_U(IN OUT PUNICODE_STRING pCommandLine_U) +{ + BOOL inDoubleQuote = FALSE; + PWSTR lpszCommandLine; + + /* + * Skip the program's name (the first token in the command line). + * Handle quoted program's name. + */ + if (pCommandLine_U && pCommandLine_U->Buffer && (pCommandLine_U->Length != 0)) + { + lpszCommandLine = pCommandLine_U->Buffer; + + while ( (pCommandLine_U->Length > 0) && + ( (*lpszCommandLine > SPACECHAR) || + (*lpszCommandLine && inDoubleQuote) ) ) + { + if (*lpszCommandLine == DQUOTECHAR) + inDoubleQuote = !inDoubleQuote; + + ++lpszCommandLine; + pCommandLine_U->Length -= sizeof(WCHAR); + } + + /* Skip all white spaces preceeding the second token. */ + while ((pCommandLine_U->Length > 0) && *lpszCommandLine && (*lpszCommandLine <= SPACECHAR)) + { + ++lpszCommandLine; + pCommandLine_U->Length -= sizeof(WCHAR); + } + + pCommandLine_U->Buffer = lpszCommandLine; + } + + return; +} + + +typedef struct _TEST_CASE +{ + LPWSTR CmdLine; +} TEST_CASE, *PTEST_CASE; + +static TEST_CASE TestCases[] = +{ + {L"cmdline_util.exe"}, + {L"cmdline_util.exe foo bar"}, + {L"cmdline_util.exe \"foo bar\""}, + {L"cmdline_util.exe foo \"bar John\" Doe"}, + + {L"\"cmdline_util.exe\""}, + {L"\"cmdline_util.exe\" foo bar"}, + {L"\"cmdline_util.exe\" \"foo bar\""}, + {L"\"cmdline_util.exe\" foo \"bar John\" Doe"}, + + {L"\"cmdline_util.exe\""}, + {L"\"cmdline_util.exe \"foo bar\"\""}, +}; + +static void Test_CommandLine(IN ULONG TestNumber, + IN PTEST_CASE TestCase) +{ + BOOL bRet; + + WCHAR CmdLine[MAX_PATH]; + STARTUPINFOW si; + PROCESS_INFORMATION pi; + + ZeroMemory(&si, sizeof(si)); + ZeroMemory(&pi, sizeof(pi)); + si.cb = sizeof(si); + + wcscpy(CmdLine, TestCase->CmdLine); + + /* + * Launch the utility program and wait till it's terminated. + */ + bRet = CreateProcessW(NULL, + CmdLine, + NULL, NULL, + FALSE, + CREATE_UNICODE_ENVIRONMENT, + NULL, NULL, + &si, &pi); + ok(bRet, "Test %lu - Failed to launch ' %S ', error = %lu.\n", TestNumber, TestCase->CmdLine, GetLastError()); + + if (bRet) + { + /* Wait until child process exits. */ + WaitForSingleObject(pi.hProcess, INFINITE); + + /* Close process and thread handles. */ + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + } + + /* + * Analyses the result. + */ + { + /* Open the data file. */ + HANDLE hFile = CreateFileW(DATAFILE, + GENERIC_READ, + 0, NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + ok(hFile != INVALID_HANDLE_VALUE, "Test %lu - Failed to open the data file 'C:\\cmdline.dat', error = %lu.\n", TestNumber, GetLastError()); + + if (hFile != INVALID_HANDLE_VALUE) + { + WCHAR BuffWinMain[MAX_PATH]; LPWSTR WinMainCmdLine = BuffWinMain; + WCHAR BuffWin32[MAX_PATH] ; LPWSTR Win32CmdLine = BuffWin32 ; + WCHAR BuffNT[0xffff /* Maximum USHORT size */]; + UNICODE_STRING NTCmdLine; + + DWORD dwSize, dwStringSize; + + /* + * Format of the data file : + * + * [size_of_string 4 bytes][null_terminated_C_string] + * [size_of_string 4 bytes][null_terminated_C_string] + * [UNICODE_STRING_structure][string_buffer_of_UNICODE_STRING] + */ + + /* 1- Read the WinMain's command line. */ + dwStringSize = 0; + + ReadFile(hFile, + &dwStringSize, + sizeof(dwStringSize), + &dwSize, + NULL); + + dwStringSize = min(dwStringSize, sizeof(BuffWinMain)); + ReadFile(hFile, + WinMainCmdLine, + dwStringSize, + &dwSize, + NULL); + *(LPWSTR)((ULONG_PTR)WinMainCmdLine + dwStringSize) = 0; + + /* 2- Read the Win32 mode command line. */ + dwStringSize = 0; + + ReadFile(hFile, + &dwStringSize, + sizeof(dwStringSize), + &dwSize, + NULL); + + dwStringSize = min(dwStringSize, sizeof(BuffWin32)); + ReadFile(hFile, + Win32CmdLine, + dwStringSize, + &dwSize, + NULL); + *(LPWSTR)((ULONG_PTR)Win32CmdLine + dwStringSize) = 0; + + /* 3- Finally, read the UNICODE_STRING command line. */ + ReadFile(hFile, + &NTCmdLine, + sizeof(NTCmdLine), + &dwSize, + NULL); + + NTCmdLine.Buffer = BuffNT; + ReadFile(hFile, + NTCmdLine.Buffer, + NTCmdLine.Length, + &dwSize, + NULL); + + /* Now close the file. */ + CloseHandle(hFile); + + /* + * Remove the program's name in the Win32 and NT command lines. + */ + Win32CmdLine = ExtractCmdLine(Win32CmdLine); + ExtractCmdLine_U(&NTCmdLine); + + /* Print the results */ + *(LPWSTR)((ULONG_PTR)NTCmdLine.Buffer + NTCmdLine.Length) = 0; + printf("WinMain cmdline = '%S'\n" + "Win32 cmdline = '%S'\n" + "NT cmdline = '%S'\n" + "NT length = %u\n", + WinMainCmdLine, + Win32CmdLine, + NTCmdLine.Buffer, NTCmdLine.Length); + + /* + * Now check the results. + */ + dwStringSize = min(wcslen(WinMainCmdLine), wcslen(Win32CmdLine)); + ok(wcslen(WinMainCmdLine) == wcslen(Win32CmdLine), "Test %lu - WinMain and Win32 command lines do not have the same length !\n", TestNumber); + ok(wcsncmp(WinMainCmdLine, Win32CmdLine, dwStringSize) == 0, "Test %lu - WinMain and Win32 command lines are different !\n", TestNumber); + + dwStringSize = min(wcslen(WinMainCmdLine), NTCmdLine.Length / sizeof(WCHAR)); + ok(wcsncmp(WinMainCmdLine, NTCmdLine.Buffer, dwStringSize) == 0, "Test %lu - WinMain and NT command lines are different !\n", TestNumber); + + dwStringSize = min(wcslen(Win32CmdLine), NTCmdLine.Length / sizeof(WCHAR)); + ok(wcsncmp(Win32CmdLine, NTCmdLine.Buffer, dwStringSize) == 0, "Test %lu - Win32 and NT command lines are different !\n", TestNumber); + } + } + + /* + * Always delete the data file. + */ + DeleteFileW(DATAFILE); +} + +START_TEST(CommandLine) +{ + ULONG i; + + for (i = 0 ; i < COUNT_OF(TestCases) ; ++i) + { + Test_CommandLine(i, &TestCases[i]); + } +} + +/* EOF */ diff --git a/rostests/apitests/msvcrt/cmdline_util/CMakeLists.txt b/rostests/apitests/msvcrt/cmdline_util/CMakeLists.txt new file mode 100644 index 00000000000..ce0cf5bae93 --- /dev/null +++ b/rostests/apitests/msvcrt/cmdline_util/CMakeLists.txt @@ -0,0 +1,10 @@ + +add_definitions(-D_DLL -D__USE_CRTIMP) + +list(APPEND SOURCE + cmdline_util.c) + +add_executable(cmdline_util ${SOURCE}) +set_module_type(cmdline_util win32gui UNICODE) +add_importlibs(cmdline_util msvcrt kernel32 ntdll) +add_cd_file(TARGET cmdline_util DESTINATION reactos/bin FOR all) diff --git a/rostests/apitests/msvcrt/cmdline_util/cmdline_util.c b/rostests/apitests/msvcrt/cmdline_util/cmdline_util.c new file mode 100644 index 00000000000..007e7f088e1 --- /dev/null +++ b/rostests/apitests/msvcrt/cmdline_util/cmdline_util.c @@ -0,0 +1,94 @@ +/* + * PROJECT: ReactOS API Tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Test for CRT command-line handling - Utility GUI program. + * PROGRAMMER: Hermès BÉLUSCA - MAÏTO + */ + +#define WIN32_NO_STATUS +#include +#include +#include + +int APIENTRY wWinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPWSTR lpCmdLine, + int nCmdShow) +{ + /* + * Get the unparsed command line as seen in Win32 mode, + * and the NT-native mode one. + */ + LPWSTR CmdLine = GetCommandLineW(); + UNICODE_STRING CmdLine_U = NtCurrentPeb()->ProcessParameters->CommandLine; + + /* Write the results into a file. */ + HANDLE hFile = CreateFileW(L"C:\\cmdline.dat", + GENERIC_WRITE, + 0, NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + DWORD dwSize, dwStringSize; + + /* + * Format of the data file : + * + * [size_of_string 4 bytes][null_terminated_C_string] + * [size_of_string 4 bytes][null_terminated_C_string] + * [UNICODE_STRING_structure][string_buffer_of_UNICODE_STRING] + */ + + /* 1- Write the WinMain's command line. */ + dwStringSize = (wcslen(lpCmdLine) + 1) * sizeof(WCHAR); + + WriteFile(hFile, + &dwStringSize, + sizeof(dwStringSize), + &dwSize, + NULL); + + WriteFile(hFile, + lpCmdLine, + dwStringSize, + &dwSize, + NULL); + + /* 2- Write the Win32 mode command line. */ + dwStringSize = (wcslen(CmdLine) + 1) * sizeof(WCHAR); + + WriteFile(hFile, + &dwStringSize, + sizeof(dwStringSize), + &dwSize, + NULL); + + WriteFile(hFile, + CmdLine, + dwStringSize, + &dwSize, + NULL); + + /* 3- Finally, write the UNICODE_STRING command line. */ + WriteFile(hFile, + &CmdLine_U, + sizeof(CmdLine_U), + &dwSize, + NULL); + + WriteFile(hFile, + CmdLine_U.Buffer, + CmdLine_U.Length, + &dwSize, + NULL); + + /* Now close the file. */ + CloseHandle(hFile); + } + + return 0; +} + +/* EOF */ diff --git a/rostests/apitests/msvcrt/testlist.c b/rostests/apitests/msvcrt/testlist.c index 0e57890b48f..e55fbdaadb1 100644 --- a/rostests/apitests/msvcrt/testlist.c +++ b/rostests/apitests/msvcrt/testlist.c @@ -5,14 +5,15 @@ #define STANDALONE #include "wine/test.h" +extern void func_CommandLine(void); extern void func_ieee(void); extern void func_splitpath(void); const struct test winetest_testlist[] = { + { "CommandLine", func_CommandLine }, { "ieee", func_ieee }, { "splitpath", func_splitpath }, { 0, 0 } }; -