* Addendum to r58214.
[reactos.git] / rostests / apitests / advapi32 / QueryServiceConfig2.c
1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Test for QueryServiceConfig2A/W
5 * PROGRAMMER: Hermès BÉLUSCA - MAÏTO
6 */
7
8 #include <wine/test.h>
9 #include <winreg.h>
10 #include <winsvc.h>
11 #include <strsafe.h>
12
13 #define TESTING_SERVICEW L"Spooler"
14 #define TESTING_SERVICEA "Spooler"
15
16 /*
17 * Taken from base/system/services/config.c and adapted.
18 */
19 static DWORD
20 RegReadStringW(HKEY hKey,
21 LPWSTR lpValueName,
22 LPWSTR *lpValue)
23 {
24 DWORD dwError;
25 DWORD dwSize;
26 DWORD dwType;
27
28 *lpValue = NULL;
29
30 dwSize = 0;
31 dwError = RegQueryValueExW(hKey,
32 lpValueName,
33 0,
34 &dwType,
35 NULL,
36 &dwSize);
37 if (dwError != ERROR_SUCCESS)
38 return dwError;
39
40 *lpValue = HeapAlloc(GetProcessHeap(), 0, dwSize);
41 if (*lpValue == NULL)
42 return ERROR_NOT_ENOUGH_MEMORY;
43
44 dwError = RegQueryValueExW(hKey,
45 lpValueName,
46 0,
47 &dwType,
48 (LPBYTE)*lpValue,
49 &dwSize);
50 if (dwError != ERROR_SUCCESS)
51 {
52 HeapFree(GetProcessHeap(), 0, *lpValue);
53 *lpValue = NULL;
54 }
55
56 return dwError;
57 }
58
59 static DWORD
60 RegReadStringA(HKEY hKey,
61 LPSTR lpValueName,
62 LPSTR *lpValue)
63 {
64 DWORD dwError;
65 DWORD dwSize;
66 DWORD dwType;
67
68 *lpValue = NULL;
69
70 dwSize = 0;
71 dwError = RegQueryValueExA(hKey,
72 lpValueName,
73 0,
74 &dwType,
75 NULL,
76 &dwSize);
77 if (dwError != ERROR_SUCCESS)
78 return dwError;
79
80 *lpValue = HeapAlloc(GetProcessHeap(), 0, dwSize);
81 if (*lpValue == NULL)
82 return ERROR_NOT_ENOUGH_MEMORY;
83
84 dwError = RegQueryValueExA(hKey,
85 lpValueName,
86 0,
87 &dwType,
88 (LPBYTE)*lpValue,
89 &dwSize);
90 if (dwError != ERROR_SUCCESS)
91 {
92 HeapFree(GetProcessHeap(), 0, *lpValue);
93 *lpValue = NULL;
94 }
95
96 return dwError;
97 }
98
99
100 static int QueryConfig2W(SC_HANDLE hService, LPCWSTR serviceName, DWORD dwInfoLevel)
101 {
102 int iRet = 0;
103 LONG lRet = 0;
104 DWORD dwRet = 0;
105 BOOL bError = FALSE;
106 DWORD dwRequiredSize = 0;
107 LPBYTE lpBuffer = NULL;
108
109 WCHAR keyName[256];
110 HKEY hKey = NULL;
111 DWORD dwType = 0;
112
113 /* Get the needed size */
114 SetLastError(0xdeadbeef);
115 bError = QueryServiceConfig2W(hService,
116 dwInfoLevel,
117 NULL,
118 0,
119 &dwRequiredSize);
120 ok(bError == FALSE && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "(bError, GetLastError()) = (%u, 0x%08lx), expected (FALSE, 0x%08lx)\n", bError, GetLastError(), (DWORD)ERROR_INSUFFICIENT_BUFFER);
121 ok(dwRequiredSize != 0, "dwRequiredSize is zero, expected non-zero\n");
122 if (dwRequiredSize == 0)
123 {
124 skip("Required size is null; cannot proceed with QueryConfig2W --> %lu test\n", dwInfoLevel);
125 return 1;
126 }
127
128 /* Allocate memory */
129 lpBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize);
130 if (lpBuffer == NULL)
131 {
132 skip("Cannot allocate %lu bytes of memory\n", dwRequiredSize);
133 return 2;
134 }
135
136 /* Get the actual value */
137 SetLastError(0xdeadbeef);
138 bError = QueryServiceConfig2W(hService,
139 dwInfoLevel,
140 lpBuffer,
141 dwRequiredSize,
142 &dwRequiredSize);
143 ok(bError, "bError = %u, expected TRUE\n", bError);
144 if (bError == FALSE)
145 {
146 skip("QueryServiceConfig2W returned an error; cannot proceed with QueryConfig2W --> %lu test\n", dwInfoLevel);
147 HeapFree(GetProcessHeap(), 0, lpBuffer);
148 return 3;
149 }
150
151 /* Now we can compare the retrieved value with what it's actually stored in the registry */
152 StringCbPrintfW(keyName, sizeof(keyName), L"System\\CurrentControlSet\\Services\\%s", serviceName);
153 SetLastError(0xdeadbeef);
154 lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyName, 0, KEY_QUERY_VALUE, &hKey);
155 ok(lRet == ERROR_SUCCESS, "RegOpenKeyExW failed with 0x%08lx\n", lRet);
156 if (lRet != ERROR_SUCCESS)
157 {
158 skip("No regkey; cannot proceed with QueryConfig2W --> %lu test\n", dwInfoLevel);
159 HeapFree(GetProcessHeap(), 0, lpBuffer);
160 return 4;
161 }
162
163 switch (dwInfoLevel)
164 {
165 case SERVICE_CONFIG_DESCRIPTION:
166 {
167 LPSERVICE_DESCRIPTIONW lpDescription = (LPSERVICE_DESCRIPTIONW)lpBuffer;
168 LPWSTR lpszDescription = NULL;
169
170 /* Retrieve the description via the registry */
171 dwRet = RegReadStringW(hKey, L"Description", &lpszDescription);
172 ok(dwRet == ERROR_SUCCESS, "RegReadStringW returned 0x%08lx\n", dwRet);
173 ok(lpszDescription != NULL, "lpszDescription is null, expected non-null\n");
174
175 /* Compare it with the description retrieved via QueryServiceConfig2 */
176 if (lpszDescription)
177 iRet = wcscmp(lpDescription->lpDescription, lpszDescription);
178 else
179 iRet = 0;
180
181 ok(iRet == 0, "Retrieved descriptions are different !\n");
182
183
184 /* Memory cleanup */
185 HeapFree(GetProcessHeap(), 0, lpszDescription);
186
187 break;
188 }
189
190 case SERVICE_CONFIG_FAILURE_ACTIONS:
191 {
192 LPSERVICE_FAILURE_ACTIONSW lpFailureActions1 = (LPSERVICE_FAILURE_ACTIONSW)lpBuffer;
193 LPSERVICE_FAILURE_ACTIONSW lpFailureActions2 = NULL;
194 LPWSTR lpRebootMessage = NULL;
195 LPWSTR lpFailureCommand = NULL;
196 DWORD i = 0;
197
198 /* Retrieve the failure actions via the registry */
199 lRet = RegQueryValueExW(hKey,
200 L"FailureActions",
201 NULL,
202 &dwType,
203 NULL,
204 &dwRequiredSize);
205 ok(lRet == ERROR_SUCCESS, "RegQueryValueExW returned 0x%08lx\n", lRet);
206 ok(dwType == REG_BINARY, "dwType = %lu, expected REG_BINARY\n", dwType);
207 ok(dwRequiredSize != 0, "dwRequiredSize is zero, expected non-zero\n");
208
209 lpFailureActions2 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize);
210 if (lpFailureActions2 == NULL)
211 {
212 skip("Cannot allocate %lu bytes of memory\n", dwRequiredSize);
213 break;
214 }
215
216 lRet = RegQueryValueExW(hKey,
217 L"FailureActions",
218 NULL,
219 NULL,
220 (LPBYTE)lpFailureActions2,
221 &dwRequiredSize);
222 ok(lRet == ERROR_SUCCESS, "RegQueryValueExW returned 0x%08lx\n", lRet);
223 ok(dwRequiredSize != 0, "dwRequiredSize is zero, expected non-zero\n");
224
225 /* Get the strings */
226 RegReadStringW(hKey, L"FailureCommand", &lpFailureCommand);
227 RegReadStringW(hKey, L"RebootMessage" , &lpRebootMessage );
228
229 /* Check the values */
230 ok(lpFailureActions1->dwResetPeriod == lpFailureActions2->dwResetPeriod, "lpFailureActions1->dwResetPeriod != lpFailureActions2->dwResetPeriod\n");
231 ok(lpFailureActions1->cActions == lpFailureActions2->cActions, "lpFailureActions1->cActions != lpFailureActions2->cActions\n");
232
233 /* Compare the actions */
234 if (lpFailureActions1->cActions == lpFailureActions2->cActions)
235 {
236 lpFailureActions2->lpsaActions = (lpFailureActions2->cActions > 0 ? (LPSC_ACTION)(lpFailureActions2 + 1) : NULL);
237
238 if (lpFailureActions1->cActions > 0 &&
239 lpFailureActions1->lpsaActions != NULL)
240 {
241 for (i = 0; i < lpFailureActions1->cActions; ++i)
242 {
243 ok(lpFailureActions1->lpsaActions[i].Type == lpFailureActions2->lpsaActions[i].Type , "lpFailureActions1->lpsaActions[%lu].Type != lpFailureActions2->lpsaActions[%lu].Type\n" , i, i);
244 ok(lpFailureActions1->lpsaActions[i].Delay == lpFailureActions2->lpsaActions[i].Delay, "lpFailureActions1->lpsaActions[%lu].Delay != lpFailureActions2->lpsaActions[%lu].Delay\n", i, i);
245 }
246 }
247 }
248
249 /* TODO: retrieve the strings if they are in MUI format */
250
251 /* Compare RebootMsg */
252 if (lpFailureActions1->lpRebootMsg && lpRebootMessage)
253 iRet = wcscmp(lpFailureActions1->lpRebootMsg, lpRebootMessage);
254 else
255 iRet = 0;
256
257 ok(iRet == 0, "Retrieved reboot messages are different !\n");
258
259 /* Compare Command */
260 if (lpFailureActions1->lpCommand && lpFailureCommand)
261 iRet = wcscmp(lpFailureActions1->lpCommand, lpFailureCommand);
262 else
263 iRet = 0;
264
265 ok(iRet == 0, "Retrieved commands are different !\n");
266
267
268 /* Memory cleanup */
269 if (lpRebootMessage)
270 HeapFree(GetProcessHeap(), 0, lpRebootMessage);
271
272 if (lpFailureCommand)
273 HeapFree(GetProcessHeap(), 0, lpFailureCommand);
274
275 HeapFree(GetProcessHeap(), 0, lpFailureActions2);
276
277 break;
278 }
279
280 default:
281 skip("Unknown dwInfoLevel %lu, cannot proceed with QueryConfig2W --> %lu test\n", dwInfoLevel, dwInfoLevel);
282 break;
283 }
284
285 RegCloseKey(hKey);
286
287 HeapFree(GetProcessHeap(), 0, lpBuffer);
288
289 return 0;
290 }
291
292 static int QueryConfig2A(SC_HANDLE hService, LPCSTR serviceName, DWORD dwInfoLevel)
293 {
294 int iRet = 0;
295 LONG lRet = 0;
296 DWORD dwRet = 0;
297 BOOL bError = FALSE;
298 DWORD dwRequiredSize = 0;
299 LPBYTE lpBuffer = NULL;
300
301 CHAR keyName[256];
302 HKEY hKey = NULL;
303 DWORD dwType = 0;
304
305 /* Get the needed size */
306 SetLastError(0xdeadbeef);
307 bError = QueryServiceConfig2A(hService,
308 dwInfoLevel,
309 NULL,
310 0,
311 &dwRequiredSize);
312 ok(bError == FALSE && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "(bError, GetLastError()) = (%u, 0x%08lx), expected (FALSE, 0x%08lx)\n", bError, GetLastError(), (DWORD)ERROR_INSUFFICIENT_BUFFER);
313 ok(dwRequiredSize != 0, "dwRequiredSize is zero, expected non-zero\n");
314 if (dwRequiredSize == 0)
315 {
316 skip("Required size is null; cannot proceed with QueryConfig2A --> %lu test\n", dwInfoLevel);
317 return 1;
318 }
319
320 /* Allocate memory */
321 lpBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize);
322 if (lpBuffer == NULL)
323 {
324 skip("Cannot allocate %lu bytes of memory\n", dwRequiredSize);
325 return 2;
326 }
327
328 /* Get the actual value */
329 SetLastError(0xdeadbeef);
330 bError = QueryServiceConfig2A(hService,
331 dwInfoLevel,
332 lpBuffer,
333 dwRequiredSize,
334 &dwRequiredSize);
335 ok(bError, "bError = %u, expected TRUE\n", bError);
336 if (bError == FALSE)
337 {
338 skip("QueryServiceConfig2A returned an error; cannot proceed with QueryConfig2A --> %lu test\n", dwInfoLevel);
339 HeapFree(GetProcessHeap(), 0, lpBuffer);
340 return 3;
341 }
342
343 /* Now we can compare the retrieved value with what it's actually stored in the registry */
344 StringCbPrintfA(keyName, sizeof(keyName), "System\\CurrentControlSet\\Services\\%s", serviceName);
345 SetLastError(0xdeadbeef);
346 lRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyName, 0, KEY_QUERY_VALUE, &hKey);
347 ok(lRet == ERROR_SUCCESS, "RegOpenKeyExA failed with 0x%08lx\n", lRet);
348 if (lRet != ERROR_SUCCESS)
349 {
350 skip("No regkey; cannot proceed with QueryConfig2A --> %lu test\n", dwInfoLevel);
351 HeapFree(GetProcessHeap(), 0, lpBuffer);
352 return 4;
353 }
354
355 switch (dwInfoLevel)
356 {
357 case SERVICE_CONFIG_DESCRIPTION:
358 {
359 LPSERVICE_DESCRIPTIONA lpDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer;
360 LPSTR lpszDescription = NULL;
361
362 /* Retrieve the description via the registry */
363 dwRet = RegReadStringA(hKey, "Description", &lpszDescription);
364 ok(dwRet == ERROR_SUCCESS, "RegReadStringA returned 0x%08lx\n", dwRet);
365 ok(lpszDescription != NULL, "lpszDescription is null, expected non-null\n");
366
367 /* Compare it with the description retrieved via QueryServiceConfig2 */
368 if (lpszDescription)
369 iRet = strcmp(lpDescription->lpDescription, lpszDescription);
370 else
371 iRet = 0;
372
373 ok(iRet == 0, "Retrieved descriptions are different !\n");
374
375
376 /* Memory cleanup */
377 HeapFree(GetProcessHeap(), 0, lpszDescription);
378
379 break;
380 }
381
382 case SERVICE_CONFIG_FAILURE_ACTIONS:
383 {
384 LPSERVICE_FAILURE_ACTIONSA lpFailureActions1 = (LPSERVICE_FAILURE_ACTIONSA)lpBuffer;
385 LPSERVICE_FAILURE_ACTIONSA lpFailureActions2 = NULL;
386 LPSTR lpRebootMessage = NULL;
387 LPSTR lpFailureCommand = NULL;
388 DWORD i = 0;
389
390 /* Retrieve the failure actions via the registry */
391 lRet = RegQueryValueExA(hKey,
392 "FailureActions",
393 NULL,
394 &dwType,
395 NULL,
396 &dwRequiredSize);
397 ok(lRet == ERROR_SUCCESS, "RegQueryValueExA returned 0x%08lx\n", lRet);
398 ok(dwType == REG_BINARY, "dwType = %lu, expected REG_BINARY\n", dwType);
399 ok(dwRequiredSize != 0, "dwRequiredSize is zero, expected non-zero\n");
400
401 lpFailureActions2 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize);
402 if (lpFailureActions2 == NULL)
403 {
404 skip("Cannot allocate %lu bytes of memory\n", dwRequiredSize);
405 break;
406 }
407
408 lRet = RegQueryValueExA(hKey,
409 "FailureActions",
410 NULL,
411 NULL,
412 (LPBYTE)lpFailureActions2,
413 &dwRequiredSize);
414 ok(lRet == ERROR_SUCCESS, "RegQueryValueExA returned 0x%08lx\n", lRet);
415 ok(dwRequiredSize != 0, "dwRequiredSize is zero, expected non-zero\n");
416
417 /* Get the strings */
418 RegReadStringA(hKey, "FailureCommand", &lpFailureCommand);
419 RegReadStringA(hKey, "RebootMessage" , &lpRebootMessage );
420
421 /* Check the values */
422 ok(lpFailureActions1->dwResetPeriod == lpFailureActions2->dwResetPeriod, "lpFailureActions1->dwResetPeriod != lpFailureActions2->dwResetPeriod\n");
423 ok(lpFailureActions1->cActions == lpFailureActions2->cActions, "lpFailureActions1->cActions != lpFailureActions2->cActions\n");
424
425 /* Compare the actions */
426 if (lpFailureActions1->cActions == lpFailureActions2->cActions)
427 {
428 lpFailureActions2->lpsaActions = (lpFailureActions2->cActions > 0 ? (LPSC_ACTION)(lpFailureActions2 + 1) : NULL);
429
430 if (lpFailureActions1->cActions > 0 &&
431 lpFailureActions1->lpsaActions != NULL)
432 {
433 for (i = 0; i < lpFailureActions1->cActions; ++i)
434 {
435 ok(lpFailureActions1->lpsaActions[i].Type == lpFailureActions2->lpsaActions[i].Type , "lpFailureActions1->lpsaActions[%lu].Type != lpFailureActions2->lpsaActions[%lu].Type\n" , i, i);
436 ok(lpFailureActions1->lpsaActions[i].Delay == lpFailureActions2->lpsaActions[i].Delay, "lpFailureActions1->lpsaActions[%lu].Delay != lpFailureActions2->lpsaActions[%lu].Delay\n", i, i);
437 }
438 }
439 }
440
441 /* TODO: retrieve the strings if they are in MUI format */
442
443 /* Compare RebootMsg */
444 if (lpFailureActions1->lpRebootMsg && lpRebootMessage)
445 iRet = strcmp(lpFailureActions1->lpRebootMsg, lpRebootMessage);
446 else
447 iRet = 0;
448
449 ok(iRet == 0, "Retrieved reboot messages are different !\n");
450
451 /* Compare Command */
452 if (lpFailureActions1->lpCommand && lpFailureCommand)
453 iRet = strcmp(lpFailureActions1->lpCommand, lpFailureCommand);
454 else
455 iRet = 0;
456
457 ok(iRet == 0, "Retrieved commands are different !\n");
458
459
460 /* Memory cleanup */
461 if (lpRebootMessage)
462 HeapFree(GetProcessHeap(), 0, lpRebootMessage);
463
464 if (lpFailureCommand)
465 HeapFree(GetProcessHeap(), 0, lpFailureCommand);
466
467 HeapFree(GetProcessHeap(), 0, lpFailureActions2);
468
469 break;
470 }
471
472 default:
473 skip("Unknown dwInfoLevel %lu, cannot proceed with QueryConfig2A --> %lu test\n", dwInfoLevel, dwInfoLevel);
474 break;
475 }
476
477 RegCloseKey(hKey);
478
479 HeapFree(GetProcessHeap(), 0, lpBuffer);
480
481 return 0;
482 }
483
484
485 static void Test_QueryServiceConfig2W(void)
486 {
487 SC_HANDLE hScm = NULL;
488 SC_HANDLE hService = NULL;
489
490 SetLastError(0xdeadbeef);
491 hScm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
492 ok(hScm != NULL, "Failed to open service manager, error=0x%08lx\n", GetLastError());
493 if (!hScm)
494 {
495 skip("No service control manager; cannot proceed with QueryServiceConfig2W test\n");
496 goto cleanup;
497 }
498
499 ok_err(ERROR_SUCCESS);
500
501 SetLastError(0xdeadbeef);
502 hService = OpenServiceW(hScm, TESTING_SERVICEW, SERVICE_QUERY_CONFIG);
503 ok(hService != NULL, "Failed to open service handle, error=0x%08lx\n", GetLastError());
504 if (!hService)
505 {
506 skip("Service not found; cannot proceed with QueryServiceConfig2W test\n");
507 goto cleanup;
508 }
509
510 ok_err(ERROR_SUCCESS);
511
512 if (QueryConfig2W(hService, TESTING_SERVICEW, SERVICE_CONFIG_DESCRIPTION) != 0)
513 goto cleanup;
514
515 if (QueryConfig2W(hService, TESTING_SERVICEW, SERVICE_CONFIG_FAILURE_ACTIONS) != 0)
516 goto cleanup;
517
518 cleanup:
519 if (hService)
520 CloseServiceHandle(hService);
521
522 if (hScm)
523 CloseServiceHandle(hScm);
524 }
525
526 static void Test_QueryServiceConfig2A(void)
527 {
528 SC_HANDLE hScm = NULL;
529 SC_HANDLE hService = NULL;
530
531 SetLastError(0xdeadbeef);
532 hScm = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
533 ok(hScm != NULL, "Failed to open service manager, error=0x%08lx\n", GetLastError());
534 if (!hScm)
535 {
536 skip("No service control manager; cannot proceed with QueryServiceConfig2A test\n");
537 goto cleanup;
538 }
539
540 ok_err(ERROR_SUCCESS);
541
542 SetLastError(0xdeadbeef);
543 hService = OpenServiceA(hScm, TESTING_SERVICEA, SERVICE_QUERY_CONFIG);
544 ok(hService != NULL, "Failed to open service handle, error=0x%08lx\n", GetLastError());
545 if (!hService)
546 {
547 skip("Service not found; cannot proceed with QueryServiceConfig2A test\n");
548 goto cleanup;
549 }
550
551 ok_err(ERROR_SUCCESS);
552
553 if (QueryConfig2A(hService, TESTING_SERVICEA, SERVICE_CONFIG_DESCRIPTION) != 0)
554 goto cleanup;
555
556 if (QueryConfig2A(hService, TESTING_SERVICEA, SERVICE_CONFIG_FAILURE_ACTIONS) != 0)
557 goto cleanup;
558
559 cleanup:
560 if (hService)
561 CloseServiceHandle(hService);
562
563 if (hScm)
564 CloseServiceHandle(hScm);
565 }
566
567
568 START_TEST(QueryServiceConfig2)
569 {
570 Test_QueryServiceConfig2W();
571 Test_QueryServiceConfig2A();
572 }