2 * PROJECT: ReactOS API Tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Test for CRT command-line handling.
5 * PROGRAMMER: Hermès BÉLUSCA - MAÏTO <hermes.belusca@sfr.fr>
10 #define WIN32_NO_STATUS
12 #include <ndk/umtypes.h>
14 #include "./CmdLineUtil/CmdLineUtil.h"
16 #define COUNT_OF(x) (sizeof((x))/sizeof((x)[0]))
19 * Extracts the command tail from the command line
20 * (deletes the program's name and keep the rest).
22 #define SPACECHAR L' '
23 #define DQUOTECHAR L'"'
25 LPWSTR
ExtractCmdLine(IN LPWSTR lpszCommandLine
)
27 BOOL inDoubleQuote
= FALSE
;
30 * Skip the program's name (the first token in the command line).
31 * Handle quoted program's name.
35 while ( (*lpszCommandLine
> SPACECHAR
) ||
36 (*lpszCommandLine
&& inDoubleQuote
) )
38 if (*lpszCommandLine
== DQUOTECHAR
)
39 inDoubleQuote
= !inDoubleQuote
;
44 /* Skip all white spaces preceeding the second token. */
45 while (*lpszCommandLine
&& (*lpszCommandLine
<= SPACECHAR
))
49 return lpszCommandLine
;
52 VOID
ExtractCmdLine_U(IN OUT PUNICODE_STRING pCommandLine_U
)
54 BOOL inDoubleQuote
= FALSE
;
55 PWSTR lpszCommandLine
;
58 * Skip the program's name (the first token in the command line).
59 * Handle quoted program's name.
61 if (pCommandLine_U
&& pCommandLine_U
->Buffer
&& (pCommandLine_U
->Length
!= 0))
63 lpszCommandLine
= pCommandLine_U
->Buffer
;
65 while ( (pCommandLine_U
->Length
> 0) &&
66 ( (*lpszCommandLine
> SPACECHAR
) ||
67 (*lpszCommandLine
&& inDoubleQuote
) ) )
69 if (*lpszCommandLine
== DQUOTECHAR
)
70 inDoubleQuote
= !inDoubleQuote
;
73 pCommandLine_U
->Length
-= sizeof(WCHAR
);
76 /* Skip all white spaces preceeding the second token. */
77 while ((pCommandLine_U
->Length
> 0) && *lpszCommandLine
&& (*lpszCommandLine
<= SPACECHAR
))
80 pCommandLine_U
->Length
-= sizeof(WCHAR
);
83 pCommandLine_U
->Buffer
= lpszCommandLine
;
89 /******************************************************************************/
91 /* The path to the utility program run by this test. */
92 static WCHAR UtilityProgramDirectory
[MAX_PATH
];
94 /* The list of tests. */
95 typedef struct _TEST_CASE
98 BOOL bEncloseProgramNameInQuotes
;
99 } TEST_CASE
, *PTEST_CASE
;
101 static TEST_CASE TestCases
[] =
105 {L
"\"foo bar\"", FALSE
},
106 {L
"foo \"bar John\" Doe", FALSE
},
110 {L
"\"foo bar\"", TRUE
},
111 {L
"foo \"bar John\" Doe", TRUE
},
114 static void Test_CommandLine(IN ULONG TestNumber
,
115 IN PTEST_CASE TestCase
)
119 BOOL bWasntInQuotes
= (UtilityProgramDirectory
[0] != L
'"');
120 WCHAR CmdLine
[MAX_PATH
] = L
"";
122 PROCESS_INFORMATION pi
;
124 ZeroMemory(&si
, sizeof(si
));
125 ZeroMemory(&pi
, sizeof(pi
));
129 /* Initialize the command line. */
130 if (TestCase
->bEncloseProgramNameInQuotes
&& bWasntInQuotes
)
131 wcscpy(CmdLine
, L
"\"");
133 wcscat(CmdLine
, UtilityProgramDirectory
);
135 if (TestCase
->bEncloseProgramNameInQuotes
&& bWasntInQuotes
)
136 wcscat(CmdLine
, L
"\"");
138 /* Add a separating space and copy the tested command line parameters. */
139 wcscat(CmdLine
, L
" ");
140 wcscat(CmdLine
, TestCase
->CmdLine
);
144 * Launch the utility program and wait till it's terminated.
146 bRet
= CreateProcessW(NULL
,
150 CREATE_UNICODE_ENVIRONMENT
,
153 ok(bRet
, "Test %lu - Failed to launch ' %S ', error = %lu.\n", TestNumber
, CmdLine
, GetLastError());
157 /* Wait until child process exits. */
158 WaitForSingleObject(pi
.hProcess
, INFINITE
);
160 /* Close process and thread handles. */
161 CloseHandle(pi
.hThread
);
162 CloseHandle(pi
.hProcess
);
166 * Analyses the result.
169 /* Open the data file. */
170 HANDLE hFile
= CreateFileW(DATAFILE
,
174 FILE_ATTRIBUTE_NORMAL
,
176 ok(hFile
!= INVALID_HANDLE_VALUE
, "Test %lu - Failed to open the data file 'C:\\cmdline.dat', error = %lu.\n", TestNumber
, GetLastError());
178 if (hFile
!= INVALID_HANDLE_VALUE
)
180 WCHAR BuffWinMain
[MAX_PATH
]; LPWSTR WinMainCmdLine
= BuffWinMain
;
181 WCHAR BuffWin32
[MAX_PATH
] ; LPWSTR Win32CmdLine
= BuffWin32
;
182 WCHAR BuffNT
[0xffff /* Maximum USHORT size */];
183 UNICODE_STRING NTCmdLine
;
185 DWORD dwSize
, dwStringSize
;
188 * Format of the data file :
190 * [size_of_string 4 bytes][null_terminated_C_string]
191 * [size_of_string 4 bytes][null_terminated_C_string]
192 * [UNICODE_STRING_structure][string_buffer_of_UNICODE_STRING]
195 /* 1- Read the WinMain's command line. */
200 sizeof(dwStringSize
),
204 dwStringSize
= min(dwStringSize
, sizeof(BuffWinMain
));
210 *(LPWSTR
)((ULONG_PTR
)WinMainCmdLine
+ dwStringSize
) = 0;
212 /* 2- Read the Win32 mode command line. */
217 sizeof(dwStringSize
),
221 dwStringSize
= min(dwStringSize
, sizeof(BuffWin32
));
227 *(LPWSTR
)((ULONG_PTR
)Win32CmdLine
+ dwStringSize
) = 0;
229 /* 3- Finally, read the UNICODE_STRING command line. */
236 NTCmdLine
.Buffer
= BuffNT
;
243 /* Now close the file. */
247 * Remove the program's name in the Win32 and NT command lines.
249 Win32CmdLine
= ExtractCmdLine(Win32CmdLine
);
250 ExtractCmdLine_U(&NTCmdLine
);
252 /* Print the results */
254 *(LPWSTR)((ULONG_PTR)NTCmdLine.Buffer + NTCmdLine.Length) = 0;
255 printf("WinMain cmdline = '%S'\n"
256 "Win32 cmdline = '%S'\n"
257 "NT cmdline = '%S'\n"
261 NTCmdLine.Buffer, NTCmdLine.Length);
265 * Now check the results.
267 dwStringSize
= min(wcslen(WinMainCmdLine
), wcslen(Win32CmdLine
));
268 ok(wcslen(WinMainCmdLine
) == wcslen(Win32CmdLine
), "Test %lu - WinMain and Win32 command lines do not have the same length !\n", TestNumber
);
269 ok(wcsncmp(WinMainCmdLine
, Win32CmdLine
, dwStringSize
) == 0, "Test %lu - WinMain and Win32 command lines are different !\n", TestNumber
);
271 dwStringSize
= min(wcslen(WinMainCmdLine
), NTCmdLine
.Length
/ sizeof(WCHAR
));
272 ok(wcsncmp(WinMainCmdLine
, NTCmdLine
.Buffer
, dwStringSize
) == 0, "Test %lu - WinMain and NT command lines are different !\n", TestNumber
);
274 dwStringSize
= min(wcslen(Win32CmdLine
), NTCmdLine
.Length
/ sizeof(WCHAR
));
275 ok(wcsncmp(Win32CmdLine
, NTCmdLine
.Buffer
, dwStringSize
) == 0, "Test %lu - Win32 and NT command lines are different !\n", TestNumber
);
280 * Always delete the data file.
282 DeleteFileW(DATAFILE
);
285 START_TEST(CommandLine
)
294 * Initialize the UtilityProgramDirectory variable.
296 dwRet
= GetModuleFileNameW(NULL
, UtilityProgramDirectory
, COUNT_OF(UtilityProgramDirectory
));
297 ok(dwRet
!= 0, "ERROR: Cannot retrieve the path to the current running process, last error %lu\n", GetLastError());
298 if (dwRet
== 0) return;
300 /* Path : executable.exe or "executable.exe" or C:\path\executable.exe or "C:\path\executable.exe" */
301 p
= wcsrchr(UtilityProgramDirectory
, L
'\\');
303 *++p
= 0; /* Null-terminate there : C:\path\ or "C:\path\ */
305 UtilityProgramDirectory
[0] = 0; /* Suppress the executable.exe name */
307 wcscat(UtilityProgramDirectory
, L
"data\\CmdLineUtil.exe");
309 /* Close the opened quote if needed. */
310 if (UtilityProgramDirectory
[0] == L
'"') wcscat(UtilityProgramDirectory
, L
"\"");
314 * Now launch the tests.
316 for (i
= 0 ; i
< COUNT_OF(TestCases
) ; ++i
)
318 Test_CommandLine(i
, &TestCases
[i
]);