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