Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

812 lines
23 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. ConfTest.c
  5. Abstract:
  6. This file contains tests of the Service Controller's config APIs:
  7. ChangeServiceConfig
  8. CreateService
  9. DeleteService
  10. QueryServiceConfig
  11. TestChangeConfig2
  12. CompareFailureActions
  13. TestQueryConfig2
  14. TestConfig2APIs
  15. Author:
  16. John Rogers (JohnRo) 22-Apr-1992
  17. Environment:
  18. User Mode - Win32
  19. Revision History:
  20. 22-Apr-1992 JohnRo
  21. Created.
  22. 17-Oct-1996 AnirudhS
  23. Added Config2 API tests.
  24. --*/
  25. //
  26. // INCLUDES
  27. //
  28. // #define UNICODE
  29. #include <windows.h>
  30. #include <assert.h> // assert().
  31. #include <tchar.h> // _tcscmp
  32. #include <debugfmt.h> // FORMAT_ equates.
  33. #include <winsvc.h>
  34. #include <scdebug.h> // STATIC.
  35. #include <sctest.h> // TRACE_MSG macros, UNEXPECTED_MSG(), etc.
  36. #include <stdio.h> // printf()
  37. #define BUF_SIZE 1024 // arbitrary
  38. //#define NEW_SERVICE_NAME TEXT("FLARP")
  39. #define NEW_SERVICE_NAME TEXT("Simple")
  40. #define TEST_SERVICE_DESCR TEXT("A servile service")
  41. #define LENGTH(array) (sizeof(array)/sizeof((array)[0]))
  42. #define OPTIONAL_LPTSTR(optStr) \
  43. ( ( (optStr) != NULL ) ? (optStr) : TEXT("(NONE)") )
  44. VOID
  45. DumpServiceConfig(
  46. IN LPQUERY_SERVICE_CONFIG Config
  47. )
  48. {
  49. (VOID) printf( "Service config:\n" );
  50. (VOID) printf( " Service type: " FORMAT_HEX_DWORD "\n",
  51. Config->dwServiceType );
  52. (VOID) printf( " Start type: " FORMAT_DWORD "\n",
  53. Config->dwStartType );
  54. (VOID) printf( " Error control: " FORMAT_DWORD "\n",
  55. Config->dwErrorControl );
  56. (VOID) printf( " Binary path: " FORMAT_LPTSTR "\n",
  57. Config->lpBinaryPathName );
  58. (VOID) printf( " Load order group: " FORMAT_LPTSTR "\n",
  59. OPTIONAL_LPTSTR( Config->lpBinaryPathName ) );
  60. (VOID) printf( " Dependencies: " FORMAT_LPTSTR "\n",
  61. OPTIONAL_LPTSTR( Config->lpBinaryPathName ) );
  62. (VOID) printf( " Service start name: " FORMAT_LPTSTR "\n",
  63. Config->lpBinaryPathName );
  64. } // DumpServiceConfig
  65. SC_HANDLE
  66. TestCreateService(
  67. IN SC_HANDLE hScManager,
  68. IN LPTSTR ServiceName,
  69. IN DWORD ExpectedStatus
  70. )
  71. {
  72. DWORD ApiStatus;
  73. SC_HANDLE hService;
  74. hService = CreateService(
  75. hScManager, // SC manager handle
  76. ServiceName, // service name
  77. NULL, // display name
  78. GENERIC_ALL, // desired access
  79. SERVICE_WIN32_OWN_PROCESS, // service type
  80. SERVICE_DISABLED, // start type
  81. SERVICE_ERROR_NORMAL, // error control
  82. TEXT("simple.exe"), // binary load path name
  83. // TEXT("\\nt\\system32\\bogus.exe"),// binary load path name
  84. NULL, // no load order group
  85. NULL, // no tag
  86. NULL, // no dependencies
  87. NULL, // start name (domain\username)
  88. // TEXT(".\\JohnRoDaemon"), // start name (domain\username)
  89. NULL); // no password.
  90. if (hService == NULL) {
  91. ApiStatus = GetLastError();
  92. } else {
  93. ApiStatus = NO_ERROR;
  94. }
  95. TRACE_MSG2( "TestCreateService: back from CreateService, "
  96. "API status is " FORMAT_DWORD ", expecting " FORMAT_DWORD "\n",
  97. ApiStatus, ExpectedStatus );
  98. assert( ApiStatus == ExpectedStatus );
  99. return (hService);
  100. }
  101. VOID
  102. TestDeleteService(
  103. IN SC_HANDLE hScManager,
  104. IN LPTSTR ServiceName,
  105. IN DWORD DesiredAccess,
  106. IN DWORD OpenExpectedStatus,
  107. IN DWORD DeleteExpectedStatus
  108. )
  109. {
  110. DWORD ApiStatus = NO_ERROR;
  111. SC_HANDLE hService;
  112. //////////////////////////////////////////////////////////////////////
  113. hService = OpenService(
  114. hScManager,
  115. ServiceName,
  116. DesiredAccess );
  117. if (hService == NULL) {
  118. ApiStatus = GetLastError();
  119. }
  120. TRACE_MSG2( "TestDeleteService: back from OpenService, "
  121. "API status is " FORMAT_DWORD ", expecting " FORMAT_DWORD "\n",
  122. ApiStatus, OpenExpectedStatus );
  123. assert( ApiStatus == OpenExpectedStatus );
  124. if (ApiStatus != NO_ERROR) {
  125. return;
  126. }
  127. //////////////////////////////////////////////////////////////////////
  128. if ( !DeleteService( hService ) ) {
  129. ApiStatus = GetLastError();
  130. }
  131. TRACE_MSG2( "TestDeleteService: back from DeleteService, "
  132. "API status is " FORMAT_DWORD ", expecting " FORMAT_DWORD "\n",
  133. ApiStatus, DeleteExpectedStatus );
  134. assert( ApiStatus == DeleteExpectedStatus );
  135. //////////////////////////////////////////////////////////////////////
  136. if ( !CloseServiceHandle( hService ) ) {
  137. ApiStatus = GetLastError();
  138. }
  139. TRACE_MSG2( "TestDeleteService: back from CloseService, "
  140. "API status is " FORMAT_DWORD ", expecting " FORMAT_DWORD "\n",
  141. ApiStatus, NO_ERROR );
  142. assert( ApiStatus == NO_ERROR );
  143. }
  144. VOID
  145. TestQueryConfig(
  146. IN SC_HANDLE hService,
  147. IN DWORD ExpectedStatus
  148. )
  149. {
  150. DWORD ApiStatus;
  151. BYTE buffer[BUF_SIZE];
  152. DWORD sizeNeeded;
  153. TRACE_MSG0( "TestQueryConfig: calling QueryServiceConfig...\n" );
  154. if ( !QueryServiceConfig(
  155. hService,
  156. (LPVOID) buffer,
  157. BUF_SIZE,
  158. & sizeNeeded ) ) {
  159. ApiStatus = GetLastError();
  160. } else {
  161. ApiStatus = NO_ERROR;
  162. }
  163. TRACE_MSG1( "TestQueryConfig: back from QueryServiceConfig, "
  164. "API status is " FORMAT_DWORD "\n", ApiStatus );
  165. assert( ApiStatus == ExpectedStatus );
  166. if (ApiStatus == NO_ERROR) {
  167. DumpServiceConfig( (LPVOID) buffer );
  168. }
  169. } // TestQueryConfig
  170. VOID
  171. TestConfigAPIs(
  172. VOID
  173. )
  174. {
  175. SC_HANDLE hScManager = NULL;
  176. SC_HANDLE hService = NULL;
  177. TRACE_MSG1( "handle (before anything) is " FORMAT_HEX_DWORD ".\n",
  178. (DWORD) hScManager );
  179. ///////////////////////////////////////////////////////////////////
  180. TRACE_MSG0( "calling OpenSCManager (default)...\n" );
  181. hScManager = OpenSCManager(
  182. NULL, // local machine.
  183. NULL, // no database name.
  184. GENERIC_ALL ); // desired access.
  185. TRACE_MSG1( "back from OpenSCManager, handle is " FORMAT_HEX_DWORD ".\n",
  186. (DWORD) hScManager );
  187. if (hScManager == NULL) {
  188. UNEXPECTED_MSG( "from OpenSCManager (default)", GetLastError() );
  189. goto Cleanup;
  190. }
  191. ///////////////////////////////////////////////////////////////////
  192. #ifdef TEST_BINDING_HANDLES
  193. TestQueryConfig( NULL, ERROR_INVALID_HANDLE );
  194. #endif
  195. ///////////////////////////////////////////////////////////////////
  196. TestDeleteService(
  197. hScManager,
  198. NEW_SERVICE_NAME,
  199. DELETE, // desired access
  200. ERROR_SERVICE_DOES_NOT_EXIST,
  201. NO_ERROR );
  202. ///////////////////////////////////////////////////////////////////
  203. #ifdef TEST_BINDING_HANDLES
  204. hService = TestCreateService(
  205. NULL, NEW_SERVICE_NAME, ERROR_INVALID_HANDLE );
  206. #endif
  207. ///////////////////////////////////////////////////////////////////
  208. hService = TestCreateService( hScManager, NULL, ERROR_INVALID_NAME );
  209. ///////////////////////////////////////////////////////////////////
  210. hService = TestCreateService( hScManager, NEW_SERVICE_NAME, NO_ERROR );
  211. assert( hService != NULL );
  212. ///////////////////////////////////////////////////////////////////
  213. TestQueryConfig( hService, NO_ERROR );
  214. ///////////////////////////////////////////////////////////////////
  215. (VOID) TestCreateService( hScManager, NEW_SERVICE_NAME,
  216. ERROR_SERVICE_EXISTS );
  217. ///////////////////////////////////////////////////////////////////
  218. TestDeleteService(
  219. NULL,
  220. NEW_SERVICE_NAME,
  221. DELETE, // desired access
  222. ERROR_INVALID_HANDLE,
  223. NO_ERROR );
  224. ///////////////////////////////////////////////////////////////////
  225. TestDeleteService(
  226. hScManager,
  227. NULL,
  228. DELETE, // desired access
  229. NO_ERROR,
  230. ERROR_INVALID_NAME );
  231. ///////////////////////////////////////////////////////////////////
  232. TestDeleteService(
  233. hScManager,
  234. NEW_SERVICE_NAME,
  235. GENERIC_READ, // desired access
  236. NO_ERROR,
  237. ERROR_ACCESS_DENIED );
  238. ///////////////////////////////////////////////////////////////////
  239. TestDeleteService(
  240. hScManager,
  241. NEW_SERVICE_NAME,
  242. DELETE, // desired access
  243. NO_ERROR,
  244. NO_ERROR );
  245. ///////////////////////////////////////////////////////////////////
  246. TestQueryConfig( hService, NO_ERROR );
  247. ///////////////////////////////////////////////////////////////////
  248. TestDeleteService(
  249. hScManager,
  250. NEW_SERVICE_NAME,
  251. DELETE, // desired access
  252. ERROR_SERVICE_DOES_NOT_EXIST,
  253. NO_ERROR );
  254. Cleanup:
  255. if (hService != NULL) {
  256. TRACE_MSG0( "calling CloseServiceHandle(hService)...\n" );
  257. if ( !CloseServiceHandle( hService ) ) {
  258. UNEXPECTED_MSG( "from CloseServiceHandle", GetLastError() );
  259. }
  260. }
  261. if (hScManager != NULL) {
  262. TRACE_MSG0( "calling CloseServiceHandle(hScManager)...\n" );
  263. if ( !CloseServiceHandle( hScManager ) ) {
  264. UNEXPECTED_MSG( "from CloseServiceHandle", GetLastError() );
  265. }
  266. }
  267. } // TestConfigAPIs
  268. VOID
  269. TestChangeConfig2(
  270. IN SC_HANDLE hService,
  271. IN DWORD dwInfoLevel,
  272. IN LPVOID lpInfo,
  273. IN DWORD ExpectedStatus
  274. )
  275. {
  276. DWORD ApiStatus;
  277. TRACE_MSG0( "TestChangeConfig2: Calling ChangeServiceConfig2...\n" );
  278. if ( !ChangeServiceConfig2( hService, dwInfoLevel, lpInfo ) ) {
  279. ApiStatus = GetLastError();
  280. } else {
  281. ApiStatus = NO_ERROR;
  282. }
  283. TRACE_MSG2( "TestChangeConfig2: back from ChangeServiceConfig2, "
  284. "API status %lu, expecting %lu\n", ApiStatus, ExpectedStatus );
  285. assert( ApiStatus == ExpectedStatus );
  286. /*
  287. if (ApiStatus == NO_ERROR) {
  288. DumpServiceConfig( (LPVOID) buffer );
  289. }
  290. */
  291. } // TestChangeConfig2
  292. VOID
  293. CompareFailureActions(
  294. IN LPSERVICE_FAILURE_ACTIONS psfa1, // Expected result buffer
  295. IN LPSERVICE_FAILURE_ACTIONS psfa2 // Actual result buffer
  296. )
  297. {
  298. if (psfa1 == NULL)
  299. {
  300. return;
  301. }
  302. assert(psfa2 != NULL);
  303. assert(psfa1->dwResetPeriod == psfa2->dwResetPeriod);
  304. if (psfa1->lpRebootMsg)
  305. {
  306. assert(_tcscmp(psfa1->lpRebootMsg, psfa2->lpRebootMsg) == 0);
  307. }
  308. else
  309. {
  310. assert(psfa2->lpRebootMsg == NULL);
  311. }
  312. if (psfa1->lpCommand)
  313. {
  314. assert(_tcscmp(psfa1->lpCommand, psfa2->lpCommand) == 0);
  315. }
  316. else
  317. {
  318. assert(psfa2->lpCommand == NULL);
  319. }
  320. assert(psfa1->cActions == psfa2->cActions);
  321. if (psfa1->cActions)
  322. {
  323. DWORD i;
  324. assert(psfa2->lpsaActions != NULL);
  325. for (i = 0; i < psfa1->cActions; i++)
  326. {
  327. assert(psfa1->lpsaActions[i].Type == psfa2->lpsaActions[i].Type);
  328. assert(psfa1->lpsaActions[i].Delay == psfa2->lpsaActions[i].Delay);
  329. }
  330. }
  331. else
  332. {
  333. assert(psfa2->lpsaActions == NULL);
  334. }
  335. }
  336. VOID
  337. TestQueryConfig2(
  338. IN SC_HANDLE hService,
  339. IN DWORD dwInfoLevel, // which configuration data is requested
  340. OUT LPBYTE lpBuffer, // pointer to service configuration buffer
  341. IN DWORD cbBufSize, // size of service configuration buffer
  342. OUT LPDWORD pcbBytesNeeded, // address of variable for bytes needed
  343. IN DWORD ExpectedStatus,
  344. IN LPVOID ExpectedBuffer
  345. )
  346. {
  347. DWORD ApiStatus;
  348. TRACE_MSG0( "TestQueryConfig2: calling QueryServiceConfig2...\n" );
  349. if ( !QueryServiceConfig2(
  350. hService,
  351. dwInfoLevel,
  352. lpBuffer,
  353. cbBufSize,
  354. pcbBytesNeeded ) ) {
  355. ApiStatus = GetLastError();
  356. } else {
  357. ApiStatus = NO_ERROR;
  358. }
  359. TRACE_MSG2( "TestQueryConfig2: back from QueryServiceConfig2, "
  360. "API status %lu, expecting %lu\n", ApiStatus, ExpectedStatus );
  361. assert( ApiStatus == ExpectedStatus );
  362. if (ApiStatus == NO_ERROR)
  363. {
  364. switch (dwInfoLevel)
  365. {
  366. case SERVICE_CONFIG_DESCRIPTION:
  367. {
  368. LPSERVICE_DESCRIPTION psd = (LPSERVICE_DESCRIPTION) lpBuffer;
  369. if (ExpectedBuffer == NULL)
  370. {
  371. assert(psd->lpDescription == NULL);
  372. }
  373. else
  374. {
  375. assert(psd->lpDescription != NULL);
  376. assert(_tcscmp(psd->lpDescription, (LPTSTR)ExpectedBuffer) == 0);
  377. }
  378. }
  379. break;
  380. case SERVICE_CONFIG_FAILURE_ACTIONS:
  381. CompareFailureActions((LPSERVICE_FAILURE_ACTIONS)ExpectedBuffer,
  382. (LPSERVICE_FAILURE_ACTIONS)lpBuffer);
  383. break;
  384. default:
  385. break;
  386. }
  387. }
  388. /*
  389. if (ApiStatus == NO_ERROR) {
  390. DumpServiceConfig( (LPVOID) buffer );
  391. }
  392. */
  393. } // TestQueryConfig2
  394. VOID
  395. TestConfig2APIs(
  396. VOID
  397. )
  398. {
  399. SC_HANDLE hScManager = NULL;
  400. SC_HANDLE hService = NULL;
  401. SC_ACTION saActions[] =
  402. {
  403. { SC_ACTION_RESTART, 10000 },
  404. { SC_ACTION_NONE, 42 },
  405. { SC_ACTION_REBOOT, 500 }
  406. };
  407. SERVICE_FAILURE_ACTIONS sfa =
  408. {
  409. 501, // reset period
  410. TEXT("Put your shoes back on!"), // reboot message
  411. TEXT("Do badly."), // failure command
  412. LENGTH(saActions), // number of actions
  413. saActions // action array
  414. };
  415. BYTE Buffer[200];
  416. DWORD cbBytesNeeded;
  417. TRACE_MSG1( "handle (before anything) is " FORMAT_HEX_DWORD ".\n",
  418. (DWORD) hScManager );
  419. ///////////////////////////////////////////////////////////////////
  420. TRACE_MSG0( "calling OpenSCManagerW (default)...\n" );
  421. hScManager = OpenSCManager(
  422. NULL, // local machine.
  423. NULL, // no database name.
  424. GENERIC_ALL ); // desired access.
  425. TRACE_MSG1( "back from OpenSCManagerW, handle is " FORMAT_HEX_DWORD ".\n",
  426. (DWORD) hScManager );
  427. if (hScManager == NULL) {
  428. UNEXPECTED_MSG( "from OpenSCManagerW (default)", GetLastError() );
  429. goto Cleanup;
  430. }
  431. ///////////////////////////////////////////////////////////////////
  432. TestDeleteService(
  433. hScManager,
  434. NEW_SERVICE_NAME,
  435. DELETE, // desired access
  436. ERROR_SERVICE_DOES_NOT_EXIST,
  437. NO_ERROR );
  438. ///////////////////////////////////////////////////////////////////
  439. hService = TestCreateService( hScManager, NEW_SERVICE_NAME, NO_ERROR );
  440. assert( hService != NULL );
  441. memset(Buffer, -1, sizeof(Buffer));
  442. TestQueryConfig2(
  443. hService,
  444. SERVICE_CONFIG_DESCRIPTION,
  445. Buffer,
  446. sizeof(Buffer),
  447. &cbBytesNeeded,
  448. NO_ERROR,
  449. NULL );
  450. ///////////////////////////////////////////////////////////////////
  451. printf("Setting service description\n");
  452. {
  453. SERVICE_DESCRIPTION sd = { TEST_SERVICE_DESCR };
  454. TestChangeConfig2(
  455. hService,
  456. SERVICE_CONFIG_DESCRIPTION,
  457. &sd,
  458. NO_ERROR );
  459. }
  460. TestQueryConfig2(
  461. hService,
  462. SERVICE_CONFIG_DESCRIPTION,
  463. Buffer,
  464. sizeof(Buffer),
  465. &cbBytesNeeded,
  466. NO_ERROR,
  467. TEST_SERVICE_DESCR );
  468. // For consistency with QueryServiceConfig, the API should set
  469. // cbBytesNeeded even on a success return, even though this is not
  470. // documented
  471. #ifdef UNICODE
  472. assert(cbBytesNeeded == sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR));
  473. #else
  474. assert(cbBytesNeeded >= sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR) &&
  475. cbBytesNeeded <= sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR)*2);
  476. #endif
  477. ///////////////////////////////////////////////////////////////////
  478. printf("Setting service failure actions\n");
  479. TestChangeConfig2(
  480. hService,
  481. SERVICE_CONFIG_FAILURE_ACTIONS,
  482. &sfa,
  483. NO_ERROR );
  484. TestQueryConfig2(
  485. hService,
  486. SERVICE_CONFIG_FAILURE_ACTIONS,
  487. Buffer,
  488. sizeof(Buffer),
  489. &cbBytesNeeded,
  490. NO_ERROR,
  491. &sfa );
  492. ///////////////////////////////////////////////////////////////////
  493. printf("Testing count 3 and NULL pointer to array\n");
  494. sfa.lpsaActions = NULL;
  495. TestChangeConfig2(
  496. hService,
  497. SERVICE_CONFIG_FAILURE_ACTIONS,
  498. &sfa,
  499. NO_ERROR );
  500. // Resulting config should not have changed
  501. sfa.lpsaActions = saActions;
  502. TestQueryConfig2(
  503. hService,
  504. SERVICE_CONFIG_FAILURE_ACTIONS,
  505. Buffer,
  506. sizeof(Buffer),
  507. &cbBytesNeeded,
  508. NO_ERROR,
  509. &sfa );
  510. ///////////////////////////////////////////////////////////////////
  511. printf("Testing count 0 and NULL pointer to array\n");
  512. sfa.cActions = 0;
  513. sfa.lpsaActions = NULL;
  514. TestChangeConfig2(
  515. hService,
  516. SERVICE_CONFIG_FAILURE_ACTIONS,
  517. &sfa,
  518. NO_ERROR );
  519. // Resulting config should not have changed
  520. sfa.cActions = LENGTH(saActions);
  521. sfa.lpsaActions = saActions;
  522. TestQueryConfig2(
  523. hService,
  524. SERVICE_CONFIG_FAILURE_ACTIONS,
  525. Buffer,
  526. sizeof(Buffer),
  527. &cbBytesNeeded,
  528. NO_ERROR,
  529. &sfa );
  530. ///////////////////////////////////////////////////////////////////
  531. printf("Testing count 0 and non-NULL pointer to array\n");
  532. sfa.cActions = 0;
  533. sfa.lpsaActions = (LPSC_ACTION) 0xfefefefe; // a bad pointer
  534. TestChangeConfig2(
  535. hService,
  536. SERVICE_CONFIG_FAILURE_ACTIONS,
  537. &sfa,
  538. NO_ERROR );
  539. // Resulting config should have no actions at all
  540. // However, it should still have a failure command and a reboot message
  541. sfa.dwResetPeriod = 0;
  542. sfa.lpsaActions = NULL;
  543. TestQueryConfig2(
  544. hService,
  545. SERVICE_CONFIG_FAILURE_ACTIONS,
  546. Buffer,
  547. sizeof(Buffer),
  548. &cbBytesNeeded,
  549. NO_ERROR,
  550. &sfa );
  551. ///////////////////////////////////////////////////////////////////
  552. printf("Testing empty failure command and unchanged reboot message\n");
  553. sfa.lpCommand = TEXT("");
  554. sfa.lpRebootMsg = NULL;
  555. TestChangeConfig2(
  556. hService,
  557. SERVICE_CONFIG_FAILURE_ACTIONS,
  558. &sfa,
  559. NO_ERROR );
  560. // Resulting config should have an empty failure command
  561. // However, it should still have a reboot message
  562. sfa.lpCommand = NULL;
  563. sfa.lpRebootMsg = TEXT("Put your shoes back on!");
  564. TestQueryConfig2(
  565. hService,
  566. SERVICE_CONFIG_FAILURE_ACTIONS,
  567. Buffer,
  568. sizeof(Buffer),
  569. &cbBytesNeeded,
  570. NO_ERROR,
  571. &sfa );
  572. ///////////////////////////////////////////////////////////////////
  573. printf("Testing invalid level\n");
  574. TestChangeConfig2(
  575. hService,
  576. 101,
  577. &sfa,
  578. ERROR_INVALID_LEVEL );
  579. ///////////////////////////////////////////////////////////////////
  580. memset(Buffer, -1, sizeof(Buffer));
  581. TestQueryConfig2(
  582. hService,
  583. SERVICE_CONFIG_DESCRIPTION,
  584. Buffer,
  585. sizeof(Buffer), // plenty big buffer
  586. &cbBytesNeeded,
  587. NO_ERROR,
  588. TEST_SERVICE_DESCR );
  589. ///////////////////////////////////////////////////////////////////
  590. memset(Buffer, -1, sizeof(Buffer));
  591. TestQueryConfig2(
  592. hService,
  593. SERVICE_CONFIG_DESCRIPTION,
  594. Buffer,
  595. sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR),
  596. // just big enough
  597. &cbBytesNeeded,
  598. NO_ERROR,
  599. TEST_SERVICE_DESCR );
  600. ///////////////////////////////////////////////////////////////////
  601. memset(Buffer, -1, sizeof(Buffer));
  602. cbBytesNeeded = 0;
  603. TestQueryConfig2(
  604. hService,
  605. SERVICE_CONFIG_DESCRIPTION,
  606. Buffer,
  607. sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR) - 1,
  608. // 1 byte too small
  609. &cbBytesNeeded,
  610. ERROR_INSUFFICIENT_BUFFER,
  611. NULL );
  612. #ifdef UNICODE
  613. assert(cbBytesNeeded == sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR));
  614. #else
  615. assert(cbBytesNeeded >= sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR) &&
  616. cbBytesNeeded <= sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR)*2);
  617. #endif
  618. ///////////////////////////////////////////////////////////////////
  619. memset(Buffer, -1, sizeof(Buffer));
  620. cbBytesNeeded = 0;
  621. TestQueryConfig2(
  622. hService,
  623. SERVICE_CONFIG_DESCRIPTION,
  624. Buffer,
  625. 0, // zero size
  626. &cbBytesNeeded,
  627. ERROR_INSUFFICIENT_BUFFER,
  628. NULL );
  629. #ifdef UNICODE
  630. assert(cbBytesNeeded == sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR));
  631. #else
  632. assert(cbBytesNeeded >= sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR) &&
  633. cbBytesNeeded <= sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR)*2);
  634. #endif
  635. ///////////////////////////////////////////////////////////////////
  636. TestDeleteService(
  637. hScManager,
  638. NEW_SERVICE_NAME,
  639. DELETE, // desired access
  640. NO_ERROR,
  641. NO_ERROR );
  642. Cleanup:
  643. if (hService != NULL) {
  644. TRACE_MSG0( "calling CloseServiceHandle(hService)...\n" );
  645. if ( !CloseServiceHandle( hService ) ) {
  646. UNEXPECTED_MSG( "from CloseServiceHandle", GetLastError() );
  647. }
  648. }
  649. if (hScManager != NULL) {
  650. TRACE_MSG0( "calling CloseServiceHandle(hScManager)...\n" );
  651. if ( !CloseServiceHandle( hScManager ) ) {
  652. UNEXPECTED_MSG( "from CloseServiceHandle", GetLastError() );
  653. }
  654. }
  655. } // TestConfig2APIs