[ADVAPI32_APITEST][NTDLL_APITEST][WINDOWSCODECS] Comment out some unused functions...
[reactos.git] / modules / rostests / apitests / advapi32 / ServiceArgs.c
1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
4 * PURPOSE: Test for service arguments
5 * PROGRAMMER: Jacek Caban for CodeWeavers
6 * Thomas Faber <thomas.faber@reactos.org>
7 */
8
9 #include <apitest.h>
10 #include <winnls.h>
11 #include <winsvc.h>
12 #include <strsafe.h>
13
14 static char **argv;
15 static int argc;
16
17 static HANDLE pipe_handle = INVALID_HANDLE_VALUE;
18 static char service_nameA[100];
19 static WCHAR service_nameW[100];
20 static WCHAR named_pipe_name[100];
21
22 /* Test process global variables */
23 static SC_HANDLE scm_handle;
24 static SERVICE_STATUS_HANDLE service_handle;
25
26 static void send_msg(const char *type, const char *msg)
27 {
28 DWORD written = 0;
29 char buf[512];
30
31 StringCbPrintfA(buf, sizeof(buf), "%s:%s", type, msg);
32 WriteFile(pipe_handle, buf, strlen(buf)+1, &written, NULL);
33 }
34
35 #if 0
36 static inline void service_trace(const char *msg, ...)
37 {
38 va_list valist;
39 char buf[512];
40
41 va_start(valist, msg);
42 StringCbVPrintfA(buf, sizeof(buf), msg, valist);
43 va_end(valist);
44
45 send_msg("TRACE", buf);
46 }
47 #endif
48
49 static void service_ok(int cnd, const char *msg, ...)
50 {
51 va_list valist;
52 char buf[512];
53
54 va_start(valist, msg);
55 StringCbVPrintfA(buf, sizeof(buf), msg, valist);
56 va_end(valist);
57
58 send_msg(cnd ? "OK" : "FAIL", buf);
59 }
60
61 static VOID WINAPI service_handler(DWORD ctrl)
62 {
63 SERVICE_STATUS status;
64
65 status.dwServiceType = SERVICE_WIN32;
66 status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
67 status.dwWin32ExitCode = 0;
68 status.dwServiceSpecificExitCode = 0;
69 status.dwCheckPoint = 0;
70 status.dwWaitHint = 0;
71
72 switch(ctrl)
73 {
74 case SERVICE_CONTROL_STOP:
75 status.dwCurrentState = SERVICE_STOP_PENDING;
76 status.dwControlsAccepted = 0;
77 SetServiceStatus(service_handle, &status);
78 default:
79 status.dwCurrentState = SERVICE_RUNNING;
80 SetServiceStatus(service_handle, &status);
81 }
82 }
83
84 static void service_main_common(void)
85 {
86 SERVICE_STATUS status;
87 BOOL res;
88
89 service_handle = RegisterServiceCtrlHandlerW(service_nameW, service_handler);
90 service_ok(service_handle != NULL, "RegisterServiceCtrlHandler failed: %lu\n", GetLastError());
91 if (!service_handle)
92 return;
93
94 status.dwServiceType = SERVICE_WIN32;
95 status.dwCurrentState = SERVICE_RUNNING;
96 status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
97 status.dwWin32ExitCode = 0;
98 status.dwServiceSpecificExitCode = 0;
99 status.dwCheckPoint = 0;
100 status.dwWaitHint = 10000;
101 res = SetServiceStatus(service_handle, &status);
102 service_ok(res, "SetServiceStatus(SERVICE_RUNNING) failed: %lu", GetLastError());
103
104 Sleep(100);
105
106 status.dwCurrentState = SERVICE_STOPPED;
107 status.dwControlsAccepted = 0;
108 res = SetServiceStatus(service_handle, &status);
109 service_ok(res, "SetServiceStatus(SERVICE_STOPPED) failed: %lu", GetLastError());
110 }
111
112 /*
113 * A/W argument layout XP/2003:
114 * [argv array of pointers][parameter 1][parameter 2]...[service name]
115 *
116 * A/W argument layout Vista:
117 * [argv array of pointers][align to 8 bytes][parameter 1][parameter 2]...[service name]
118 *
119 * A/W argument layout Win7/8:
120 * [argv array of pointers][service name]
121 * [parameter 1][align to 4 bytes][parameter 2][align to 4 bytes]...
122 *
123 * Space for parameters and service name is always enough to store
124 * the WCHAR version including null terminator.
125 */
126
127 static void WINAPI service_mainA(DWORD service_argc, char **service_argv)
128 {
129 int i;
130 char *next_arg;
131 char *next_arg_aligned;
132
133 service_ok(service_argc == argc - 3, "service_argc = %d, expected %d", service_argc, argc - 3);
134 if (service_argc == argc - 3)
135 {
136 service_ok(!strcmp(service_argv[0], service_nameA), "service_argv[0] = %s, expected %s", service_argv[0], service_nameA);
137 service_ok(service_argv[0] == (char *)&service_argv[service_argc] ||
138 service_argv[1] == (char *)&service_argv[service_argc] ||
139 service_argv[1] == (char *)(((ULONG_PTR)&service_argv[service_argc] + 7) & ~7), "service_argv[0] = %p, [1] = %p, expected one of them to be %p", service_argv[0], service_argv[1], &service_argv[service_argc]);
140 //service_trace("service_argv[0] = %p", service_argv[0]);
141 next_arg_aligned = next_arg = NULL;
142 for (i = 1; i < service_argc; i++)
143 {
144 //service_trace("service_argv[%d] = %p", i, service_argv[i]);
145 service_ok(!strcmp(service_argv[i], argv[i + 3]), "service_argv[%d] = %s, expected %s", i, service_argv[i], argv[i + 3]);
146 service_ok(next_arg == NULL ||
147 service_argv[i] == next_arg ||
148 service_argv[i] == next_arg_aligned, "service_argv[%d] = %p, expected %p or %p", i, service_argv[i], next_arg, next_arg_aligned);
149 next_arg = service_argv[i];
150 next_arg += 2 * (strlen(next_arg) + 1);
151 next_arg_aligned = (char *)(((ULONG_PTR)next_arg + 3) & ~3);
152 }
153 }
154
155 service_main_common();
156 }
157
158 static void WINAPI service_mainW(DWORD service_argc, WCHAR **service_argv)
159 {
160 int i;
161 WCHAR argW[32];
162 WCHAR *next_arg;
163 WCHAR *next_arg_aligned;
164
165 service_ok(service_argc == argc - 3, "service_argc = %d, expected %d", service_argc, argc - 3);
166 if (service_argc == argc - 3)
167 {
168 service_ok(!wcscmp(service_argv[0], service_nameW), "service_argv[0] = %ls, expected %ls", service_argv[0], service_nameW);
169 service_ok(service_argv[0] == (WCHAR *)&service_argv[service_argc] ||
170 service_argv[1] == (WCHAR *)&service_argv[service_argc] ||
171 service_argv[1] == (WCHAR *)(((ULONG_PTR)&service_argv[service_argc] + 7) & ~7), "service_argv[0] = %p, [1] = %p, expected one of them to be %p", service_argv[0], service_argv[1], &service_argv[service_argc]);
172 //service_trace("service_argv[0] = %p", service_argv[0]);
173 next_arg_aligned = next_arg = NULL;
174 for (i = 1; i < service_argc; i++)
175 {
176 //service_trace("service_argv[%d] = %p", i, service_argv[i]);
177 MultiByteToWideChar(CP_ACP, 0, argv[i + 3], -1, argW, _countof(argW));
178 service_ok(!wcscmp(service_argv[i], argW), "service_argv[%d] = %ls, expected %ls", i, service_argv[i], argW);
179 service_ok(next_arg == NULL ||
180 service_argv[i] == next_arg ||
181 service_argv[i] == next_arg_aligned, "service_argv[%d] = %p, expected %p or %p", i, service_argv[i], next_arg, next_arg_aligned);
182 next_arg = service_argv[i];
183 next_arg += wcslen(next_arg) + 1;
184 next_arg_aligned = (WCHAR *)(((ULONG_PTR)next_arg + 3) & ~3);
185 }
186 }
187
188 service_main_common();
189 }
190
191 static void service_process(BOOLEAN unicode)
192 {
193 BOOL res;
194
195 SERVICE_TABLE_ENTRYA servtblA[] =
196 {
197 { service_nameA, service_mainA },
198 { NULL, NULL }
199 };
200 SERVICE_TABLE_ENTRYW servtblW[] =
201 {
202 { service_nameW, service_mainW },
203 { NULL, NULL }
204 };
205
206 res = WaitNamedPipeW(named_pipe_name, NMPWAIT_USE_DEFAULT_WAIT);
207 if (!res)
208 return;
209
210 pipe_handle = CreateFileW(named_pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
211 if (pipe_handle == INVALID_HANDLE_VALUE)
212 return;
213
214 //service_trace("Starting...");
215 if (unicode)
216 {
217 res = StartServiceCtrlDispatcherW(servtblW);
218 service_ok(res, "StartServiceCtrlDispatcherW failed: %lu\n", GetLastError());
219 }
220 else
221 {
222 res = StartServiceCtrlDispatcherA(servtblA);
223 service_ok(res, "StartServiceCtrlDispatcherA failed: %lu\n", GetLastError());
224 }
225
226 CloseHandle(pipe_handle);
227 }
228
229 static SC_HANDLE register_service(PCWSTR extra_args)
230 {
231 WCHAR service_cmd[MAX_PATH+150];
232 SC_HANDLE service;
233
234 GetModuleFileNameW(NULL, service_cmd, MAX_PATH);
235
236 StringCbCatW(service_cmd, sizeof(service_cmd), L" ServiceArgs ");
237 StringCbCatW(service_cmd, sizeof(service_cmd), service_nameW);
238 StringCbCatW(service_cmd, sizeof(service_cmd), extra_args);
239
240 trace("service_cmd \"%ls\"\n", service_cmd);
241
242 service = CreateServiceW(scm_handle, service_nameW, service_nameW, GENERIC_ALL,
243 SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE,
244 service_cmd, NULL, NULL, NULL, NULL, NULL);
245 if (!service && GetLastError() == ERROR_ACCESS_DENIED)
246 {
247 skip("Not enough access right to create service\n");
248 return NULL;
249 }
250
251 ok(service != NULL, "CreateService failed: %lu\n", GetLastError());
252 return service;
253 }
254
255 static DWORD WINAPI pipe_thread(void *arg)
256 {
257 char buf[512];
258 DWORD read;
259 BOOL res;
260
261 res = ConnectNamedPipe(pipe_handle, NULL);
262 ok(res || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe failed: %lu\n", GetLastError());
263
264 while (1)
265 {
266 res = ReadFile(pipe_handle, buf, sizeof(buf), &read, NULL);
267 if (!res)
268 {
269 ok(GetLastError() == ERROR_BROKEN_PIPE || GetLastError() == ERROR_INVALID_HANDLE,
270 "ReadFile failed: %lu\n", GetLastError());
271 break;
272 }
273
274 if (!strncmp(buf, "TRACE:", 6))
275 {
276 trace("service trace: %s\n", buf+6);
277 }
278 else if (!strncmp(buf, "OK:", 3))
279 {
280 ok(1, "service: %s\n", buf+3);
281 }
282 else if (!strncmp(buf, "FAIL:", 5))
283 {
284 ok(0, "service: %s\n", buf+5);
285 }
286 else
287 {
288 ok(0, "malformed service message: %s\n", buf);
289 }
290 }
291
292 DisconnectNamedPipe(pipe_handle);
293 //trace("pipe disconnected\n");
294 return 0;
295 }
296
297 static void test_startA(SC_HANDLE service_handle, int service_argc, const char **service_argv)
298 {
299 SERVICE_STATUS status;
300 BOOL res;
301
302 res = StartServiceA(service_handle, service_argc, service_argv);
303 ok(res, "StartService failed: %lu\n", GetLastError());
304 if (!res)
305 return;
306
307 do
308 {
309 Sleep(100);
310 ZeroMemory(&status, sizeof(status));
311 res = QueryServiceStatus(service_handle, &status);
312 } while (res && status.dwCurrentState != SERVICE_STOPPED);
313 ok(res, "QueryServiceStatus failed: %lu\n", GetLastError());
314 ok(status.dwCurrentState == SERVICE_STOPPED, "status.dwCurrentState = %lx\n", status.dwCurrentState);
315 }
316
317 static void test_startW(SC_HANDLE service_handle, int service_argc, const WCHAR **service_argv)
318 {
319 SERVICE_STATUS status;
320 BOOL res;
321
322 res = StartServiceW(service_handle, service_argc, service_argv);
323 ok(res, "StartService failed: %lu\n", GetLastError());
324 if (!res)
325 return;
326
327 do
328 {
329 Sleep(100);
330 ZeroMemory(&status, sizeof(status));
331 res = QueryServiceStatus(service_handle, &status);
332 } while (res && status.dwCurrentState != SERVICE_STOPPED);
333 ok(res, "QueryServiceStatus failed: %lu\n", GetLastError());
334 ok(status.dwCurrentState == SERVICE_STOPPED, "status.dwCurrentState = %lx\n", status.dwCurrentState);
335 }
336
337 static void test_runner(BOOLEAN unicode, PCWSTR extra_args, int service_argc, void *service_argv)
338 {
339 HANDLE thread;
340 SC_HANDLE service_handle;
341 BOOL res;
342
343 StringCbPrintfW(service_nameW, sizeof(service_nameW), L"WineTestService%lu", GetTickCount());
344 WideCharToMultiByte(CP_ACP, 0, service_nameW, -1, service_nameA, _countof(service_nameA), NULL, NULL);
345 //trace("service_name: %ls\n", service_nameW);
346 StringCbPrintfW(named_pipe_name, sizeof(named_pipe_name), L"\\\\.\\pipe\\%ls_pipe", service_nameW);
347
348 pipe_handle = CreateNamedPipeW(named_pipe_name, PIPE_ACCESS_INBOUND,
349 PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_WAIT, 10, 2048, 2048, 10000, NULL);
350 ok(pipe_handle != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %lu\n", GetLastError());
351 if (pipe_handle == INVALID_HANDLE_VALUE)
352 return;
353
354 thread = CreateThread(NULL, 0, pipe_thread, NULL, 0, NULL);
355 ok(thread != NULL, "CreateThread failed: %lu\n", GetLastError());
356 if (!thread)
357 return;
358
359 service_handle = register_service(extra_args);
360 if (!service_handle)
361 return;
362
363 //trace("starting...\n");
364
365 if (unicode)
366 test_startW(service_handle, service_argc, service_argv);
367 else
368 test_startA(service_handle, service_argc, service_argv);
369
370 res = DeleteService(service_handle);
371 ok(res, "DeleteService failed: %lu\n", GetLastError());
372
373 CloseServiceHandle(service_handle);
374
375 ok(WaitForSingleObject(thread, 10000) == WAIT_OBJECT_0, "Timeout waiting for thread\n");
376 CloseHandle(thread);
377 CloseHandle(pipe_handle);
378 }
379
380 START_TEST(ServiceArgs)
381 {
382 argc = winetest_get_mainargs(&argv);
383
384 scm_handle = OpenSCManagerW(NULL, NULL, GENERIC_ALL);
385 ok(scm_handle != NULL, "OpenSCManager failed: %lu\n", GetLastError());
386 if (!scm_handle)
387 {
388 skip("Failed to open service control manager. Skipping test\n");
389 return;
390 }
391
392 if (argc < 3)
393 {
394 char *service_argvA[10];
395 WCHAR *service_argvW[10];
396
397 test_runner(FALSE, L" A", 0, NULL);
398 test_runner(FALSE, L" W", 0, NULL);
399 test_runner(TRUE, L" A", 0, NULL);
400 test_runner(TRUE, L" W", 0, NULL);
401
402 service_argvA[0] = "x";
403 service_argvW[0] = L"x";
404 test_runner(FALSE, L" A x", 1, service_argvA);
405 test_runner(FALSE, L" W x", 1, service_argvA);
406 test_runner(TRUE, L" A x", 1, service_argvW);
407 test_runner(TRUE, L" W x", 1, service_argvW);
408
409 service_argvA[1] = "y";
410 service_argvW[1] = L"y";
411 test_runner(FALSE, L" A x y", 2, service_argvA);
412 test_runner(FALSE, L" W x y", 2, service_argvA);
413 test_runner(TRUE, L" A x y", 2, service_argvW);
414 test_runner(TRUE, L" W x y", 2, service_argvW);
415
416 service_argvA[0] = "ab";
417 service_argvW[0] = L"ab";
418 test_runner(FALSE, L" A ab y", 2, service_argvA);
419 test_runner(FALSE, L" W ab y", 2, service_argvA);
420 test_runner(TRUE, L" A ab y", 2, service_argvW);
421 test_runner(TRUE, L" W ab y", 2, service_argvW);
422
423 service_argvA[0] = "abc";
424 service_argvW[0] = L"abc";
425 test_runner(FALSE, L" A abc y", 2, service_argvA);
426 test_runner(FALSE, L" W abc y", 2, service_argvA);
427 test_runner(TRUE, L" A abc y", 2, service_argvW);
428 test_runner(TRUE, L" W abc y", 2, service_argvW);
429
430 service_argvA[0] = "abcd";
431 service_argvW[0] = L"abcd";
432 test_runner(FALSE, L" A abcd y", 2, service_argvA);
433 test_runner(FALSE, L" W abcd y", 2, service_argvA);
434 test_runner(TRUE, L" A abcd y", 2, service_argvW);
435 test_runner(TRUE, L" W abcd y", 2, service_argvW);
436
437 service_argvA[0] = "abcde";
438 service_argvW[0] = L"abcde";
439 test_runner(FALSE, L" A abcde y", 2, service_argvA);
440 test_runner(FALSE, L" W abcde y", 2, service_argvA);
441 test_runner(TRUE, L" A abcde y", 2, service_argvW);
442 test_runner(TRUE, L" W abcde y", 2, service_argvW);
443
444 service_argvA[0] = "abcdef";
445 service_argvW[0] = L"abcdef";
446 test_runner(FALSE, L" A abcdef y", 2, service_argvA);
447 test_runner(FALSE, L" W abcdef y", 2, service_argvA);
448 test_runner(TRUE, L" A abcdef y", 2, service_argvW);
449 test_runner(TRUE, L" W abcdef y", 2, service_argvW);
450
451 service_argvA[0] = "abcdefg";
452 service_argvW[0] = L"abcdefg";
453 test_runner(FALSE, L" A abcdefg y", 2, service_argvA);
454 test_runner(FALSE, L" W abcdefg y", 2, service_argvA);
455 test_runner(TRUE, L" A abcdefg y", 2, service_argvW);
456 test_runner(TRUE, L" W abcdefg y", 2, service_argvW);
457
458 service_argvA[0] = "";
459 service_argvW[0] = L"";
460 test_runner(FALSE, L" A \"\" y", 2, service_argvA);
461 test_runner(FALSE, L" W \"\" y", 2, service_argvA);
462 test_runner(TRUE, L" A \"\" y", 2, service_argvW);
463 test_runner(TRUE, L" W \"\" y", 2, service_argvW);
464 }
465 else
466 {
467 strcpy(service_nameA, argv[2]);
468 MultiByteToWideChar(CP_ACP, 0, service_nameA, -1, service_nameW, _countof(service_nameW));
469 StringCbPrintfW(named_pipe_name, sizeof(named_pipe_name), L"\\\\.\\pipe\\%ls_pipe", service_nameW);
470 if (!strcmp(argv[3], "A"))
471 service_process(FALSE);
472 else
473 service_process(TRUE);
474 }
475
476 CloseServiceHandle(scm_handle);
477 }