service.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. /*
  2. * Copyright 2012 Jacek Caban for CodeWeavers
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  17. */
  18. #include <stdarg.h>
  19. #include <windef.h>
  20. #include <winsvc.h>
  21. #include <stdio.h>
  22. #include <winbase.h>
  23. #include <winuser.h>
  24. #include "wine/test.h"
  25. #if !defined(__WINE_USE_MSVCRT) || defined(__MINGW32__)
  26. #define __WINE_PRINTF_ATTR(fmt,args) __attribute__((format (printf,fmt,args)))
  27. #else
  28. #define __WINE_PRINTF_ATTR(fmt,args)
  29. #endif
  30. static SERVICE_STATUS_HANDLE (WINAPI *pRegisterServiceCtrlHandlerExA)(LPCSTR,LPHANDLER_FUNCTION_EX,LPVOID);
  31. static HANDLE pipe_handle = INVALID_HANDLE_VALUE;
  32. static char service_name[100], named_pipe_name[114];
  33. static SERVICE_STATUS_HANDLE service_handle;
  34. /* Service process global variables */
  35. static HANDLE service_stop_event;
  36. static int monitor_count;
  37. static void send_msg(const char *type, const char *msg)
  38. {
  39. DWORD written = 0;
  40. char buf[512];
  41. sprintf(buf, "%s:%s", type, msg);
  42. WriteFile(pipe_handle, buf, strlen(buf)+1, &written, NULL);
  43. }
  44. static inline void service_trace(const char *msg)
  45. {
  46. send_msg("TRACE", msg);
  47. }
  48. static inline void service_event(const char *event)
  49. {
  50. send_msg("EVENT", event);
  51. }
  52. static void WINAPIV service_ok(int cnd, const char *msg, ...) __WINE_PRINTF_ATTR(2,3);
  53. static void WINAPIV service_ok(int cnd, const char *msg, ...)
  54. {
  55. va_list valist;
  56. char buf[512];
  57. va_start(valist, msg);
  58. vsprintf(buf, msg, valist);
  59. va_end(valist);
  60. send_msg(cnd ? "OK" : "FAIL", buf);
  61. }
  62. static void test_winstation(void)
  63. {
  64. HWINSTA winstation;
  65. USEROBJECTFLAGS flags;
  66. BOOL r;
  67. winstation = GetProcessWindowStation();
  68. service_ok(winstation != NULL, "winstation = NULL\n");
  69. r = GetUserObjectInformationA(winstation, UOI_FLAGS, &flags, sizeof(flags), NULL);
  70. service_ok(r, "GetUserObjectInformation(UOI_NAME) failed: %u\n", GetLastError());
  71. service_ok(!(flags.dwFlags & WSF_VISIBLE), "winstation has flags %x\n", flags.dwFlags);
  72. }
  73. /*
  74. * Test creating window in a service process. Although services run in non-interactive,
  75. * they may create windows that will never be visible.
  76. */
  77. static void test_create_window(void)
  78. {
  79. DWORD style;
  80. ATOM class;
  81. HWND hwnd;
  82. BOOL r;
  83. static WNDCLASSEXA wndclass = {
  84. sizeof(WNDCLASSEXA),
  85. 0,
  86. DefWindowProcA,
  87. 0, 0, NULL, NULL, NULL, NULL, NULL,
  88. "service_test",
  89. NULL
  90. };
  91. hwnd = GetDesktopWindow();
  92. service_ok(IsWindow(hwnd), "GetDesktopWindow returned invalid window %p\n", hwnd);
  93. class = RegisterClassExA(&wndclass);
  94. service_ok(class, "RegisterClassFailed\n");
  95. hwnd = CreateWindowA("service_test", "service_test",
  96. WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
  97. 515, 530, NULL, NULL, NULL, NULL);
  98. service_ok(hwnd != NULL, "CreateWindow failed: %u\n", GetLastError());
  99. style = GetWindowLongW(hwnd, GWL_STYLE);
  100. service_ok(!(style & WS_VISIBLE), "style = %x, expected invisible\n", style);
  101. r = ShowWindow(hwnd, SW_SHOW);
  102. service_ok(!r, "ShowWindow returned %x\n", r);
  103. style = GetWindowLongW(hwnd, GWL_STYLE);
  104. service_ok(style & WS_VISIBLE, "style = %x, expected visible\n", style);
  105. r = ShowWindow(hwnd, SW_SHOW);
  106. service_ok(r, "ShowWindow returned %x\n", r);
  107. r = DestroyWindow(hwnd);
  108. service_ok(r, "DestroyWindow failed: %08x\n", GetLastError());
  109. }
  110. static BOOL CALLBACK monitor_enum_proc(HMONITOR hmon, HDC hdc, LPRECT lprc, LPARAM lparam)
  111. {
  112. static const RECT expected_rect = {0, 0, 1024, 768};
  113. BOOL r;
  114. MONITORINFOEXA mi;
  115. service_ok(hmon != NULL, "Unexpected hmon %p\n", hmon);
  116. monitor_count++;
  117. mi.cbSize = sizeof(mi);
  118. SetLastError(0xdeadbeef);
  119. r = GetMonitorInfoA(NULL, (MONITORINFO*)&mi);
  120. service_ok(GetLastError() == ERROR_INVALID_MONITOR_HANDLE, "Unexpected GetLastError: %#x.\n", GetLastError());
  121. service_ok(!r, "GetMonitorInfo with NULL HMONITOR succeeded.\n");
  122. r = GetMonitorInfoA(hmon, (MONITORINFO*)&mi);
  123. service_ok(r, "GetMonitorInfo failed.\n");
  124. service_ok(EqualRect(lprc, &expected_rect), "Unexpected rect: %s\n", wine_dbgstr_rect(lprc));
  125. service_ok(EqualRect(&mi.rcMonitor, &expected_rect), "Unexpected rcMonitor: %s\n",
  126. wine_dbgstr_rect(&mi.rcMonitor));
  127. service_ok(EqualRect(&mi.rcWork, &expected_rect), "Unexpected rcWork: %s\n",
  128. wine_dbgstr_rect(&mi.rcWork));
  129. service_ok(!strcmp(mi.szDevice, "WinDisc"), "Unexpected szDevice received: %s\n", mi.szDevice);
  130. service_ok(mi.dwFlags == MONITORINFOF_PRIMARY, "Unexpected secondary monitor info.\n");
  131. return TRUE;
  132. }
  133. /* query monitor information, even in non-interactive services */
  134. static void test_monitors(void)
  135. {
  136. BOOL r;
  137. r = EnumDisplayMonitors(0, 0, monitor_enum_proc, 0);
  138. service_ok(r, "EnumDisplayMonitors failed.\n");
  139. service_ok(monitor_count == 1, "Callback got called less or more than once. %d\n", monitor_count);
  140. }
  141. static DWORD WINAPI service_handler(DWORD ctrl, DWORD event_type, void *event_data, void *context)
  142. {
  143. SERVICE_STATUS status;
  144. status.dwServiceType = SERVICE_WIN32;
  145. status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  146. status.dwWin32ExitCode = 0;
  147. status.dwServiceSpecificExitCode = 0;
  148. status.dwCheckPoint = 0;
  149. status.dwWaitHint = 0;
  150. switch(ctrl)
  151. {
  152. case SERVICE_CONTROL_STOP:
  153. case SERVICE_CONTROL_SHUTDOWN:
  154. service_event("STOP");
  155. status.dwCurrentState = SERVICE_STOP_PENDING;
  156. status.dwControlsAccepted = 0;
  157. SetServiceStatus(service_handle, &status);
  158. SetEvent(service_stop_event);
  159. return NO_ERROR;
  160. case 128:
  161. test_winstation();
  162. test_create_window();
  163. test_monitors();
  164. service_event("CUSTOM");
  165. return 0xdeadbeef;
  166. default:
  167. status.dwCurrentState = SERVICE_RUNNING;
  168. SetServiceStatus( service_handle, &status );
  169. return NO_ERROR;
  170. }
  171. }
  172. static void WINAPI service_main(DWORD argc, char **argv)
  173. {
  174. SERVICE_STATUS status;
  175. char buf[64];
  176. BOOL res;
  177. service_ok(argc == 3, "argc = %u, expected 3\n", argc);
  178. service_ok(!strcmp(argv[0], service_name), "argv[0] = '%s', expected '%s'\n", argv[0], service_name);
  179. service_ok(!strcmp(argv[1], "param1"), "argv[1] = '%s', expected 'param1'\n", argv[1]);
  180. service_ok(!strcmp(argv[2], "param2"), "argv[2] = '%s', expected 'param2'\n", argv[2]);
  181. buf[0] = 0;
  182. GetEnvironmentVariableA("PATHEXT", buf, sizeof(buf));
  183. service_ok(buf[0], "did not find PATHEXT environment variable\n");
  184. service_handle = pRegisterServiceCtrlHandlerExA(service_name, service_handler, NULL);
  185. service_ok(service_handle != NULL, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError());
  186. if(!service_handle)
  187. return;
  188. status.dwServiceType = SERVICE_WIN32;
  189. status.dwCurrentState = SERVICE_RUNNING;
  190. status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
  191. status.dwWin32ExitCode = 0;
  192. status.dwServiceSpecificExitCode = 0;
  193. status.dwCheckPoint = 0;
  194. status.dwWaitHint = 10000;
  195. res = SetServiceStatus(service_handle, &status);
  196. service_ok(res, "SetServiceStatus(SERVICE_RUNNING) failed: %u\n", GetLastError());
  197. service_event("RUNNING");
  198. WaitForSingleObject(service_stop_event, INFINITE);
  199. status.dwCurrentState = SERVICE_STOPPED;
  200. status.dwControlsAccepted = 0;
  201. res = SetServiceStatus(service_handle, &status);
  202. service_ok(res, "SetServiceStatus(SERVICE_STOPPED) failed: %u\n", GetLastError());
  203. }
  204. static void service_process(void (WINAPI *p_service_main)(DWORD, char **))
  205. {
  206. BOOL res;
  207. SERVICE_TABLE_ENTRYA servtbl[] = {
  208. {service_name, p_service_main},
  209. {NULL, NULL}
  210. };
  211. res = WaitNamedPipeA(named_pipe_name, NMPWAIT_USE_DEFAULT_WAIT);
  212. if(!res)
  213. return;
  214. pipe_handle = CreateFileA(named_pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  215. if(pipe_handle == INVALID_HANDLE_VALUE)
  216. return;
  217. service_trace("Starting...\n");
  218. service_stop_event = CreateEventA(NULL, TRUE, FALSE, NULL);
  219. service_ok(service_stop_event != NULL, "Could not create event: %u\n", GetLastError());
  220. if(!service_stop_event)
  221. return;
  222. res = StartServiceCtrlDispatcherA(servtbl);
  223. service_ok(res, "StartServiceCtrlDispatcher failed: %u\n", GetLastError());
  224. /* Let service thread terminate */
  225. Sleep(50);
  226. CloseHandle(service_stop_event);
  227. CloseHandle(pipe_handle);
  228. }
  229. static DWORD WINAPI no_stop_handler(DWORD ctrl, DWORD event_type, void *event_data, void *context)
  230. {
  231. SERVICE_STATUS status;
  232. status.dwServiceType = SERVICE_WIN32;
  233. status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  234. status.dwWin32ExitCode = 0;
  235. status.dwServiceSpecificExitCode = 0;
  236. status.dwCheckPoint = 0;
  237. status.dwWaitHint = 0;
  238. switch(ctrl)
  239. {
  240. case SERVICE_CONTROL_STOP:
  241. case SERVICE_CONTROL_SHUTDOWN:
  242. service_event("STOP");
  243. status.dwCurrentState = SERVICE_STOPPED;
  244. status.dwControlsAccepted = 0;
  245. SetServiceStatus(service_handle, &status);
  246. SetEvent(service_stop_event);
  247. return NO_ERROR;
  248. default:
  249. status.dwCurrentState = SERVICE_RUNNING;
  250. SetServiceStatus( service_handle, &status );
  251. return NO_ERROR;
  252. }
  253. }
  254. static void WINAPI no_stop_main(DWORD argc, char **argv)
  255. {
  256. SERVICE_STATUS status;
  257. BOOL res;
  258. service_ok(argc == 1, "argc = %u, expected 1\n", argc);
  259. service_ok(!strcmp(argv[0], service_name), "argv[0] = '%s', expected '%s'\n", argv[0], service_name);
  260. service_handle = pRegisterServiceCtrlHandlerExA(service_name, no_stop_handler, NULL);
  261. service_ok(service_handle != NULL, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError());
  262. if(!service_handle)
  263. return;
  264. status.dwServiceType = SERVICE_WIN32;
  265. status.dwCurrentState = SERVICE_RUNNING;
  266. status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
  267. status.dwWin32ExitCode = 0;
  268. status.dwServiceSpecificExitCode = 0;
  269. status.dwCheckPoint = 0;
  270. status.dwWaitHint = 10000;
  271. res = SetServiceStatus(service_handle, &status);
  272. service_ok(res, "SetServiceStatus(SERVICE_RUNNING) failed: %u\n", GetLastError());
  273. service_event("RUNNING");
  274. }
  275. /* Test process global variables */
  276. static SC_HANDLE scm_handle;
  277. static char current_event[32];
  278. static HANDLE event_handle = INVALID_HANDLE_VALUE;
  279. static CRITICAL_SECTION event_cs;
  280. static SC_HANDLE register_service(const char *test_name)
  281. {
  282. char service_cmd[MAX_PATH+150], *ptr;
  283. SC_HANDLE service;
  284. ptr = service_cmd + GetModuleFileNameA(NULL, service_cmd, MAX_PATH);
  285. /* If the file doesn't exist, assume we're using built-in exe and append .so to the path */
  286. if(GetFileAttributesA(service_cmd) == INVALID_FILE_ATTRIBUTES) {
  287. strcpy(ptr, ".so");
  288. ptr += 3;
  289. }
  290. strcpy(ptr, " service ");
  291. ptr += strlen(ptr);
  292. sprintf(ptr, "%s ", test_name);
  293. ptr += strlen(ptr);
  294. strcpy(ptr, service_name);
  295. trace("service_cmd \"%s\"\n", service_cmd);
  296. service = CreateServiceA(scm_handle, service_name, service_name, GENERIC_ALL,
  297. SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE,
  298. service_cmd, NULL, NULL, NULL, NULL, NULL);
  299. if(!service && GetLastError() == ERROR_ACCESS_DENIED) {
  300. skip("Not enough access right to create service\n");
  301. return NULL;
  302. }
  303. ok(service != NULL, "CreateService failed: %u\n", GetLastError());
  304. return service;
  305. }
  306. static void expect_event(const char *event_name)
  307. {
  308. char evt[32];
  309. DWORD res;
  310. trace("waiting for %s\n", event_name);
  311. res = WaitForSingleObject(event_handle, 30000);
  312. ok(res == WAIT_OBJECT_0, "WaitForSingleObject failed: %u\n", res);
  313. if(res != WAIT_OBJECT_0)
  314. return;
  315. EnterCriticalSection(&event_cs);
  316. strcpy(evt, current_event);
  317. *current_event = 0;
  318. LeaveCriticalSection(&event_cs);
  319. ok(!strcmp(evt, event_name), "Unexpected event: %s, expected %s\n", evt, event_name);
  320. }
  321. static DWORD WINAPI pipe_thread(void *arg)
  322. {
  323. char buf[512], *ptr;
  324. DWORD read;
  325. BOOL res;
  326. res = ConnectNamedPipe(pipe_handle, NULL);
  327. ok(res || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe failed: %u\n", GetLastError());
  328. while(1) {
  329. res = ReadFile(pipe_handle, buf, sizeof(buf), &read, NULL);
  330. if(!res) {
  331. ok(GetLastError() == ERROR_BROKEN_PIPE || GetLastError() == ERROR_INVALID_HANDLE,
  332. "ReadFile failed: %u\n", GetLastError());
  333. break;
  334. }
  335. for(ptr = buf; ptr < buf+read; ptr += strlen(ptr)+1) {
  336. if(!strncmp(ptr, "TRACE:", 6)) {
  337. trace("service trace: %s", ptr+6);
  338. }else if(!strncmp(ptr, "OK:", 3)) {
  339. ok(1, "service: %s", ptr+3);
  340. }else if(!strncmp(ptr, "FAIL:", 5)) {
  341. ok(0, "service: %s", ptr+5);
  342. }else if(!strncmp(ptr, "EVENT:", 6)) {
  343. trace("service event: %s\n", ptr+6);
  344. EnterCriticalSection(&event_cs);
  345. ok(!current_event[0], "event %s still queued\n", current_event);
  346. strcpy(current_event, ptr+6);
  347. LeaveCriticalSection(&event_cs);
  348. SetEvent(event_handle);
  349. }else {
  350. ok(0, "malformed service message: %s\n", ptr);
  351. }
  352. }
  353. }
  354. DisconnectNamedPipe(pipe_handle);
  355. trace("pipe disconnected\n");
  356. return 0;
  357. }
  358. static void test_service(void)
  359. {
  360. static const char *argv[2] = {"param1", "param2"};
  361. SC_HANDLE service_handle = register_service("simple_service");
  362. SERVICE_STATUS_PROCESS status2;
  363. SERVICE_STATUS status;
  364. DWORD bytes;
  365. BOOL res;
  366. if(!service_handle)
  367. return;
  368. trace("starting...\n");
  369. res = StartServiceA(service_handle, 2, argv);
  370. ok(res, "StartService failed: %u\n", GetLastError());
  371. if(!res) {
  372. DeleteService(service_handle);
  373. CloseServiceHandle(service_handle);
  374. return;
  375. }
  376. expect_event("RUNNING");
  377. res = QueryServiceStatus(service_handle, &status);
  378. ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
  379. ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType);
  380. ok(status.dwCurrentState == SERVICE_RUNNING, "status.dwCurrentState = %x\n", status.dwCurrentState);
  381. ok(status.dwControlsAccepted == (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN),
  382. "status.dwControlsAccepted = %x\n", status.dwControlsAccepted);
  383. ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode);
  384. ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n",
  385. status.dwServiceSpecificExitCode);
  386. ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint);
  387. todo_wine ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
  388. res = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (BYTE *)&status2, sizeof(status2), &bytes);
  389. ok(res, "QueryServiceStatusEx failed: %u\n", GetLastError());
  390. ok(status2.dwCurrentState == SERVICE_RUNNING, "status2.dwCurrentState = %x\n", status2.dwCurrentState);
  391. ok(status2.dwProcessId != 0, "status2.dwProcessId = %d\n", status2.dwProcessId);
  392. res = ControlService(service_handle, 128, &status);
  393. ok(res, "ControlService failed: %u\n", GetLastError());
  394. expect_event("CUSTOM");
  395. res = ControlService(service_handle, SERVICE_CONTROL_STOP, &status);
  396. ok(res, "ControlService failed: %u\n", GetLastError());
  397. expect_event("STOP");
  398. res = DeleteService(service_handle);
  399. ok(res, "DeleteService failed: %u\n", GetLastError());
  400. CloseServiceHandle(service_handle);
  401. }
  402. static inline void test_no_stop(void)
  403. {
  404. SC_HANDLE service_handle = register_service("no_stop");
  405. SERVICE_STATUS_PROCESS status2;
  406. SERVICE_STATUS status;
  407. DWORD bytes;
  408. BOOL res;
  409. if(!service_handle)
  410. return;
  411. trace("starting...\n");
  412. res = StartServiceA(service_handle, 0, NULL);
  413. ok(res, "StartService failed: %u\n", GetLastError());
  414. if(!res) {
  415. DeleteService(service_handle);
  416. CloseServiceHandle(service_handle);
  417. return;
  418. }
  419. expect_event("RUNNING");
  420. /* Let service thread terminate */
  421. Sleep(1000);
  422. res = QueryServiceStatus(service_handle, &status);
  423. ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
  424. ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType);
  425. ok(status.dwCurrentState == SERVICE_RUNNING, "status.dwCurrentState = %x\n", status.dwCurrentState);
  426. ok(status.dwControlsAccepted == (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN),
  427. "status.dwControlsAccepted = %x\n", status.dwControlsAccepted);
  428. ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode);
  429. ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n",
  430. status.dwServiceSpecificExitCode);
  431. ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint);
  432. todo_wine ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
  433. res = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (BYTE *)&status2, sizeof(status2), &bytes);
  434. ok(res, "QueryServiceStatusEx failed: %u\n", GetLastError());
  435. ok(status2.dwCurrentState == SERVICE_RUNNING, "status2.dwCurrentState = %x\n", status2.dwCurrentState);
  436. ok(status2.dwProcessId != 0, "status2.dwProcessId = %d\n", status2.dwProcessId);
  437. res = ControlService(service_handle, SERVICE_CONTROL_STOP, &status);
  438. ok(res, "ControlService failed: %u\n", GetLastError());
  439. expect_event("STOP");
  440. res = QueryServiceStatus(service_handle, &status);
  441. ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
  442. ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType);
  443. ok(status.dwCurrentState==SERVICE_STOPPED || status.dwCurrentState==SERVICE_STOP_PENDING,
  444. "status.dwCurrentState = %x\n", status.dwCurrentState);
  445. ok(status.dwControlsAccepted == 0, "status.dwControlsAccepted = %x\n", status.dwControlsAccepted);
  446. ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode);
  447. ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n",
  448. status.dwServiceSpecificExitCode);
  449. ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint);
  450. ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
  451. res = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (BYTE *)&status2, sizeof(status2), &bytes);
  452. ok(res, "QueryServiceStatusEx failed: %u\n", GetLastError());
  453. ok(status2.dwProcessId == 0 || broken(status2.dwProcessId != 0),
  454. "status2.dwProcessId = %d\n", status2.dwProcessId);
  455. res = DeleteService(service_handle);
  456. ok(res, "DeleteService failed: %u\n", GetLastError());
  457. res = QueryServiceStatus(service_handle, &status);
  458. ok(res, "QueryServiceStatus failed: %d\n", GetLastError());
  459. ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType);
  460. ok(status.dwCurrentState==SERVICE_STOPPED || status.dwCurrentState==SERVICE_STOP_PENDING,
  461. "status.dwCurrentState = %x\n", status.dwCurrentState);
  462. ok(status.dwControlsAccepted == 0, "status.dwControlsAccepted = %x\n", status.dwControlsAccepted);
  463. ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode);
  464. ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n",
  465. status.dwServiceSpecificExitCode);
  466. ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint);
  467. ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint);
  468. res = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (BYTE *)&status2, sizeof(status2), &bytes);
  469. ok(res, "QueryServiceStatusEx failed: %u\n", GetLastError());
  470. ok(status2.dwProcessId == 0 || broken(status2.dwProcessId != 0),
  471. "status2.dwProcessId = %d\n", status2.dwProcessId);
  472. CloseServiceHandle(service_handle);
  473. res = QueryServiceStatus(service_handle, &status);
  474. ok(!res, "QueryServiceStatus should have failed\n");
  475. ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError = %d\n", GetLastError());
  476. }
  477. static void test_runner(void (*p_run_test)(void))
  478. {
  479. HANDLE thread;
  480. sprintf(service_name, "WineTestService%d", GetTickCount());
  481. trace("service_name: %s\n", service_name);
  482. sprintf(named_pipe_name, "\\\\.\\pipe\\%s_pipe", service_name);
  483. pipe_handle = CreateNamedPipeA(named_pipe_name, PIPE_ACCESS_INBOUND,
  484. PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_WAIT, 10, 2048, 2048, 10000, NULL);
  485. ok(pipe_handle != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %u\n", GetLastError());
  486. if(pipe_handle == INVALID_HANDLE_VALUE)
  487. return;
  488. event_handle = CreateEventA(NULL, FALSE, FALSE, NULL);
  489. ok(event_handle != INVALID_HANDLE_VALUE, "CreateEvent failed: %u\n", GetLastError());
  490. if(event_handle == INVALID_HANDLE_VALUE)
  491. return;
  492. thread = CreateThread(NULL, 0, pipe_thread, NULL, 0, NULL);
  493. ok(thread != NULL, "CreateThread failed: %u\n", GetLastError());
  494. if(!thread)
  495. return;
  496. p_run_test();
  497. WaitForSingleObject(thread, INFINITE);
  498. CloseHandle(event_handle);
  499. CloseHandle(pipe_handle);
  500. CloseHandle(thread);
  501. }
  502. START_TEST(service)
  503. {
  504. char **argv;
  505. int argc;
  506. InitializeCriticalSection(&event_cs);
  507. pRegisterServiceCtrlHandlerExA = (void*)GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegisterServiceCtrlHandlerExA");
  508. if(!pRegisterServiceCtrlHandlerExA) {
  509. win_skip("RegisterServiceCtrlHandlerExA not available, skipping tests\n");
  510. return;
  511. }
  512. scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
  513. ok(scm_handle != NULL || GetLastError() == ERROR_ACCESS_DENIED, "OpenSCManager failed: %u\n", GetLastError());
  514. if(!scm_handle) {
  515. skip("OpenSCManager failed, skipping tests\n");
  516. return;
  517. }
  518. argc = winetest_get_mainargs(&argv);
  519. if(argc < 3) {
  520. test_runner(test_service);
  521. test_runner(test_no_stop);
  522. }else {
  523. strcpy(service_name, argv[3]);
  524. sprintf(named_pipe_name, "\\\\.\\pipe\\%s_pipe", service_name);
  525. if(!strcmp(argv[2], "simple_service"))
  526. service_process(service_main);
  527. else if(!strcmp(argv[2], "no_stop"))
  528. service_process(no_stop_main);
  529. }
  530. CloseServiceHandle(scm_handle);
  531. }