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