service.c 23 KB

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