TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / programs / services / rpc.c
blob89a8c91e54dd260406fdb12e626a818095ab0c08
1 /*
2 * Services.exe - RPC functions
4 * Copyright 2007 Google (Mikolaj Zalewski)
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define WIN32_LEAN_AND_MEAN
22 #define NONAMELESSUNION
24 #include <stdarg.h>
25 #include <windows.h>
26 #include <winternl.h>
27 #include <winsvc.h>
28 #include <ntsecapi.h>
29 #include <rpc.h>
31 #include "wine/list.h"
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
35 #include "services.h"
36 #include "svcctl.h"
38 extern HANDLE CDECL __wine_make_process_system(void);
40 WINE_DEFAULT_DEBUG_CHANNEL(service);
42 static const GENERIC_MAPPING g_scm_generic =
44 (STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS),
45 (STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG),
46 (STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK),
47 SC_MANAGER_ALL_ACCESS
50 static const GENERIC_MAPPING g_svc_generic =
52 (STANDARD_RIGHTS_READ | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS),
53 (STANDARD_RIGHTS_WRITE | SERVICE_CHANGE_CONFIG),
54 (STANDARD_RIGHTS_EXECUTE | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL),
55 SERVICE_ALL_ACCESS
58 typedef enum
60 SC_HTYPE_DONT_CARE = 0,
61 SC_HTYPE_MANAGER,
62 SC_HTYPE_SERVICE
63 } SC_HANDLE_TYPE;
65 struct sc_handle
67 SC_HANDLE_TYPE type;
68 DWORD access;
71 struct sc_manager_handle /* service control manager handle */
73 struct sc_handle hdr;
74 struct scmdatabase *db;
77 struct sc_service_handle /* service handle */
79 struct sc_handle hdr;
80 struct service_entry *service_entry;
83 struct sc_lock
85 struct scmdatabase *db;
88 static HANDLE timeout_queue_event;
89 static CRITICAL_SECTION timeout_queue_cs;
90 static CRITICAL_SECTION_DEBUG timeout_queue_cs_debug =
92 0, 0, &timeout_queue_cs,
93 { &timeout_queue_cs_debug.ProcessLocksList, &timeout_queue_cs_debug.ProcessLocksList },
94 0, 0, { (DWORD_PTR)(__FILE__ ": timeout_queue_cs") }
96 static CRITICAL_SECTION timeout_queue_cs = { &timeout_queue_cs_debug, -1, 0, 0, 0, 0 };
97 static struct list timeout_queue = LIST_INIT(timeout_queue);
98 struct timeout_queue_elem
100 struct list entry;
102 FILETIME time;
103 void (*func)(struct service_entry*);
104 struct service_entry *service_entry;
107 static void run_after_timeout(void (*func)(struct service_entry*), struct service_entry *service, DWORD timeout)
109 struct timeout_queue_elem *elem = HeapAlloc(GetProcessHeap(), 0, sizeof(struct timeout_queue_elem));
110 ULARGE_INTEGER time;
112 if(!elem) {
113 func(service);
114 return;
117 service->ref_count++;
118 elem->func = func;
119 elem->service_entry = service;
121 GetSystemTimeAsFileTime(&elem->time);
122 time.u.LowPart = elem->time.dwLowDateTime;
123 time.u.HighPart = elem->time.dwHighDateTime;
124 time.QuadPart += timeout*10000000;
125 elem->time.dwLowDateTime = time.u.LowPart;
126 elem->time.dwHighDateTime = time.u.HighPart;
128 EnterCriticalSection(&timeout_queue_cs);
129 list_add_head(&timeout_queue, &elem->entry);
130 LeaveCriticalSection(&timeout_queue_cs);
132 SetEvent(timeout_queue_event);
135 static void free_service_strings(struct service_entry *old, struct service_entry *new)
137 QUERY_SERVICE_CONFIGW *old_cfg = &old->config;
138 QUERY_SERVICE_CONFIGW *new_cfg = &new->config;
140 if (old_cfg->lpBinaryPathName != new_cfg->lpBinaryPathName)
141 HeapFree(GetProcessHeap(), 0, old_cfg->lpBinaryPathName);
143 if (old_cfg->lpLoadOrderGroup != new_cfg->lpLoadOrderGroup)
144 HeapFree(GetProcessHeap(), 0, old_cfg->lpLoadOrderGroup);
146 if (old_cfg->lpServiceStartName != new_cfg->lpServiceStartName)
147 HeapFree(GetProcessHeap(), 0, old_cfg->lpServiceStartName);
149 if (old_cfg->lpDisplayName != new_cfg->lpDisplayName)
150 HeapFree(GetProcessHeap(), 0, old_cfg->lpDisplayName);
152 if (old->dependOnServices != new->dependOnServices)
153 HeapFree(GetProcessHeap(), 0, old->dependOnServices);
155 if (old->dependOnGroups != new->dependOnGroups)
156 HeapFree(GetProcessHeap(), 0, old->dependOnGroups);
159 /* Check if the given handle is of the required type and allows the requested access. */
160 static DWORD validate_context_handle(SC_RPC_HANDLE handle, DWORD type, DWORD needed_access, struct sc_handle **out_hdr)
162 struct sc_handle *hdr = handle;
164 if (type != SC_HTYPE_DONT_CARE && hdr->type != type)
166 WINE_ERR("Handle is of an invalid type (%d, %d)\n", hdr->type, type);
167 return ERROR_INVALID_HANDLE;
170 if ((needed_access & hdr->access) != needed_access)
172 WINE_ERR("Access denied - handle created with access %x, needed %x\n", hdr->access, needed_access);
173 return ERROR_ACCESS_DENIED;
176 *out_hdr = hdr;
177 return ERROR_SUCCESS;
180 static DWORD validate_scm_handle(SC_RPC_HANDLE handle, DWORD needed_access, struct sc_manager_handle **manager)
182 struct sc_handle *hdr;
183 DWORD err = validate_context_handle(handle, SC_HTYPE_MANAGER, needed_access, &hdr);
184 if (err == ERROR_SUCCESS)
185 *manager = (struct sc_manager_handle *)hdr;
186 return err;
189 static DWORD validate_service_handle(SC_RPC_HANDLE handle, DWORD needed_access, struct sc_service_handle **service)
191 struct sc_handle *hdr;
192 DWORD err = validate_context_handle(handle, SC_HTYPE_SERVICE, needed_access, &hdr);
193 if (err == ERROR_SUCCESS)
194 *service = (struct sc_service_handle *)hdr;
195 return err;
198 DWORD __cdecl svcctl_OpenSCManagerW(
199 MACHINE_HANDLEW MachineName, /* Note: this parameter is ignored */
200 LPCWSTR DatabaseName,
201 DWORD dwAccessMask,
202 SC_RPC_HANDLE *handle)
204 struct sc_manager_handle *manager;
206 WINE_TRACE("(%s, %s, %x)\n", wine_dbgstr_w(MachineName), wine_dbgstr_w(DatabaseName), dwAccessMask);
208 if (DatabaseName != NULL && DatabaseName[0])
210 if (strcmpW(DatabaseName, SERVICES_FAILED_DATABASEW) == 0)
211 return ERROR_DATABASE_DOES_NOT_EXIST;
212 if (strcmpW(DatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
213 return ERROR_INVALID_NAME;
216 if (!(manager = HeapAlloc(GetProcessHeap(), 0, sizeof(*manager))))
217 return ERROR_NOT_ENOUGH_SERVER_MEMORY;
219 manager->hdr.type = SC_HTYPE_MANAGER;
221 if (dwAccessMask & MAXIMUM_ALLOWED)
222 dwAccessMask |= SC_MANAGER_ALL_ACCESS;
223 manager->hdr.access = dwAccessMask;
224 RtlMapGenericMask(&manager->hdr.access, &g_scm_generic);
225 manager->db = active_database;
226 *handle = &manager->hdr;
228 return ERROR_SUCCESS;
231 static void SC_RPC_HANDLE_destroy(SC_RPC_HANDLE handle)
233 struct sc_handle *hdr = handle;
234 switch (hdr->type)
236 case SC_HTYPE_MANAGER:
238 struct sc_manager_handle *manager = (struct sc_manager_handle *)hdr;
239 HeapFree(GetProcessHeap(), 0, manager);
240 break;
242 case SC_HTYPE_SERVICE:
244 struct sc_service_handle *service = (struct sc_service_handle *)hdr;
245 release_service(service->service_entry);
246 HeapFree(GetProcessHeap(), 0, service);
247 break;
249 default:
250 WINE_ERR("invalid handle type %d\n", hdr->type);
251 RpcRaiseException(ERROR_INVALID_HANDLE);
255 DWORD __cdecl svcctl_GetServiceDisplayNameW(
256 SC_RPC_HANDLE hSCManager,
257 LPCWSTR lpServiceName,
258 WCHAR *lpBuffer,
259 DWORD *cchBufSize)
261 struct sc_manager_handle *manager;
262 struct service_entry *entry;
263 DWORD err;
265 WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceName), *cchBufSize);
267 if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
268 return err;
270 scmdatabase_lock_shared(manager->db);
272 entry = scmdatabase_find_service(manager->db, lpServiceName);
273 if (entry != NULL)
275 LPCWSTR name;
276 int len;
277 service_lock_shared(entry);
278 name = get_display_name(entry);
279 len = strlenW(name);
280 if (len <= *cchBufSize)
282 err = ERROR_SUCCESS;
283 memcpy(lpBuffer, name, (len + 1)*sizeof(*name));
285 else
286 err = ERROR_INSUFFICIENT_BUFFER;
287 *cchBufSize = len;
288 service_unlock(entry);
290 else
291 err = ERROR_SERVICE_DOES_NOT_EXIST;
293 scmdatabase_unlock(manager->db);
295 if (err != ERROR_SUCCESS)
296 lpBuffer[0] = 0;
298 return err;
301 DWORD __cdecl svcctl_GetServiceKeyNameW(
302 SC_RPC_HANDLE hSCManager,
303 LPCWSTR lpServiceDisplayName,
304 WCHAR *lpBuffer,
305 DWORD *cchBufSize)
307 struct service_entry *entry;
308 struct sc_manager_handle *manager;
309 DWORD err;
311 WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceDisplayName), *cchBufSize);
313 if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
314 return err;
316 scmdatabase_lock_shared(manager->db);
318 entry = scmdatabase_find_service_by_displayname(manager->db, lpServiceDisplayName);
319 if (entry != NULL)
321 int len;
322 service_lock_shared(entry);
323 len = strlenW(entry->name);
324 if (len <= *cchBufSize)
326 err = ERROR_SUCCESS;
327 memcpy(lpBuffer, entry->name, (len + 1)*sizeof(*entry->name));
329 else
330 err = ERROR_INSUFFICIENT_BUFFER;
331 *cchBufSize = len;
332 service_unlock(entry);
334 else
335 err = ERROR_SERVICE_DOES_NOT_EXIST;
337 scmdatabase_unlock(manager->db);
339 if (err != ERROR_SUCCESS)
340 lpBuffer[0] = 0;
342 return err;
345 static DWORD create_handle_for_service(struct service_entry *entry, DWORD dwDesiredAccess, SC_RPC_HANDLE *phService)
347 struct sc_service_handle *service;
349 if (!(service = HeapAlloc(GetProcessHeap(), 0, sizeof(*service))))
351 release_service(entry);
352 return ERROR_NOT_ENOUGH_SERVER_MEMORY;
355 service->hdr.type = SC_HTYPE_SERVICE;
356 service->hdr.access = dwDesiredAccess;
357 RtlMapGenericMask(&service->hdr.access, &g_svc_generic);
358 service->service_entry = entry;
359 if (dwDesiredAccess & MAXIMUM_ALLOWED)
360 dwDesiredAccess |= SERVICE_ALL_ACCESS;
362 *phService = &service->hdr;
363 return ERROR_SUCCESS;
366 DWORD __cdecl svcctl_OpenServiceW(
367 SC_RPC_HANDLE hSCManager,
368 LPCWSTR lpServiceName,
369 DWORD dwDesiredAccess,
370 SC_RPC_HANDLE *phService)
372 struct sc_manager_handle *manager;
373 struct service_entry *entry;
374 DWORD err;
376 WINE_TRACE("(%s, 0x%x)\n", wine_dbgstr_w(lpServiceName), dwDesiredAccess);
378 if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
379 return err;
380 if (!validate_service_name(lpServiceName))
381 return ERROR_INVALID_NAME;
383 scmdatabase_lock_shared(manager->db);
384 entry = scmdatabase_find_service(manager->db, lpServiceName);
385 if (entry != NULL)
386 InterlockedIncrement(&entry->ref_count);
387 scmdatabase_unlock(manager->db);
389 if (entry == NULL)
390 return ERROR_SERVICE_DOES_NOT_EXIST;
392 return create_handle_for_service(entry, dwDesiredAccess, phService);
395 static DWORD parse_dependencies(const WCHAR *dependencies, struct service_entry *entry)
397 WCHAR *services = NULL, *groups, *s;
398 DWORD len, len_services = 0, len_groups = 0;
399 const WCHAR *ptr = dependencies;
401 if (!dependencies || !dependencies[0])
403 entry->dependOnServices = NULL;
404 entry->dependOnGroups = NULL;
405 return ERROR_SUCCESS;
408 while (*ptr)
410 len = strlenW(ptr) + 1;
411 if (ptr[0] == '+' && ptr[1])
412 len_groups += len - 1;
413 else
414 len_services += len;
415 ptr += len;
417 if (!len_services) entry->dependOnServices = NULL;
418 else
420 services = HeapAlloc(GetProcessHeap(), 0, (len_services + 1) * sizeof(WCHAR));
421 if (!services)
422 return ERROR_OUTOFMEMORY;
424 s = services;
425 ptr = dependencies;
426 while (*ptr)
428 len = strlenW(ptr) + 1;
429 if (*ptr != '+')
431 strcpyW(s, ptr);
432 s += len;
434 ptr += len;
436 *s = 0;
437 entry->dependOnServices = services;
439 if (!len_groups) entry->dependOnGroups = NULL;
440 else
442 groups = HeapAlloc(GetProcessHeap(), 0, (len_groups + 1) * sizeof(WCHAR));
443 if (!groups)
445 HeapFree(GetProcessHeap(), 0, services);
446 return ERROR_OUTOFMEMORY;
448 s = groups;
449 ptr = dependencies;
450 while (*ptr)
452 len = strlenW(ptr) + 1;
453 if (ptr[0] == '+' && ptr[1])
455 strcpyW(s, ptr + 1);
456 s += len - 1;
458 ptr += len;
460 *s = 0;
461 entry->dependOnGroups = groups;
464 return ERROR_SUCCESS;
467 static DWORD create_serviceW(
468 SC_RPC_HANDLE hSCManager,
469 LPCWSTR lpServiceName,
470 LPCWSTR lpDisplayName,
471 DWORD dwDesiredAccess,
472 DWORD dwServiceType,
473 DWORD dwStartType,
474 DWORD dwErrorControl,
475 LPCWSTR lpBinaryPathName,
476 LPCWSTR lpLoadOrderGroup,
477 DWORD *lpdwTagId,
478 const BYTE *lpDependencies,
479 DWORD dwDependenciesSize,
480 LPCWSTR lpServiceStartName,
481 const BYTE *lpPassword,
482 DWORD dwPasswordSize,
483 SC_RPC_HANDLE *phService,
484 BOOL is_wow64)
486 struct service_entry *entry, *found;
487 struct sc_manager_handle *manager;
488 DWORD err;
490 WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(lpServiceName), wine_dbgstr_w(lpDisplayName), dwDesiredAccess, wine_dbgstr_w(lpBinaryPathName));
492 if ((err = validate_scm_handle(hSCManager, SC_MANAGER_CREATE_SERVICE, &manager)) != ERROR_SUCCESS)
493 return err;
495 if (!validate_service_name(lpServiceName))
496 return ERROR_INVALID_NAME;
497 if (!check_multisz((LPCWSTR)lpDependencies, dwDependenciesSize) || !lpServiceName[0] || !lpBinaryPathName[0])
498 return ERROR_INVALID_PARAMETER;
500 if (lpPassword)
501 WINE_FIXME("Don't know how to add a password\n"); /* I always get ERROR_GEN_FAILURE */
503 err = service_create(lpServiceName, &entry);
504 if (err != ERROR_SUCCESS)
505 return err;
507 err = parse_dependencies((LPCWSTR)lpDependencies, entry);
508 if (err != ERROR_SUCCESS) {
509 free_service_entry(entry);
510 return err;
513 entry->ref_count = 1;
514 entry->is_wow64 = is_wow64;
515 entry->config.dwServiceType = entry->status.dwServiceType = dwServiceType;
516 entry->config.dwStartType = dwStartType;
517 entry->config.dwErrorControl = dwErrorControl;
518 entry->config.lpBinaryPathName = strdupW(lpBinaryPathName);
519 entry->config.lpLoadOrderGroup = strdupW(lpLoadOrderGroup);
520 entry->config.lpServiceStartName = strdupW(lpServiceStartName);
521 entry->config.lpDisplayName = strdupW(lpDisplayName);
523 if (lpdwTagId) /* TODO: In most situations a non-NULL TagId will generate an ERROR_INVALID_PARAMETER. */
524 entry->config.dwTagId = *lpdwTagId;
525 else
526 entry->config.dwTagId = 0;
528 /* other fields NULL*/
530 if (!validate_service_config(entry))
532 WINE_ERR("Invalid data while trying to create service\n");
533 free_service_entry(entry);
534 return ERROR_INVALID_PARAMETER;
537 scmdatabase_lock_exclusive(manager->db);
539 if ((found = scmdatabase_find_service(manager->db, lpServiceName)))
541 service_lock_exclusive(found);
542 err = is_marked_for_delete(found) ? ERROR_SERVICE_MARKED_FOR_DELETE : ERROR_SERVICE_EXISTS;
543 service_unlock(found);
544 scmdatabase_unlock(manager->db);
545 free_service_entry(entry);
546 return err;
549 if (scmdatabase_find_service_by_displayname(manager->db, get_display_name(entry)))
551 scmdatabase_unlock(manager->db);
552 free_service_entry(entry);
553 return ERROR_DUPLICATE_SERVICE_NAME;
556 err = scmdatabase_add_service(manager->db, entry);
557 if (err != ERROR_SUCCESS)
559 scmdatabase_unlock(manager->db);
560 free_service_entry(entry);
561 return err;
563 scmdatabase_unlock(manager->db);
565 return create_handle_for_service(entry, dwDesiredAccess, phService);
568 DWORD __cdecl svcctl_CreateServiceW(
569 SC_RPC_HANDLE hSCManager,
570 LPCWSTR lpServiceName,
571 LPCWSTR lpDisplayName,
572 DWORD dwDesiredAccess,
573 DWORD dwServiceType,
574 DWORD dwStartType,
575 DWORD dwErrorControl,
576 LPCWSTR lpBinaryPathName,
577 LPCWSTR lpLoadOrderGroup,
578 DWORD *lpdwTagId,
579 const BYTE *lpDependencies,
580 DWORD dwDependenciesSize,
581 LPCWSTR lpServiceStartName,
582 const BYTE *lpPassword,
583 DWORD dwPasswordSize,
584 SC_RPC_HANDLE *phService)
586 WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(lpServiceName), wine_dbgstr_w(lpDisplayName), dwDesiredAccess, wine_dbgstr_w(lpBinaryPathName));
587 return create_serviceW(hSCManager, lpServiceName, lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType,
588 dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, lpDependencies, dwDependenciesSize, lpServiceStartName,
589 lpPassword, dwPasswordSize, phService, FALSE);
592 DWORD __cdecl svcctl_DeleteService(
593 SC_RPC_HANDLE hService)
595 struct sc_service_handle *service;
596 DWORD err;
598 if ((err = validate_service_handle(hService, DELETE, &service)) != ERROR_SUCCESS)
599 return err;
601 service_lock_exclusive(service->service_entry);
603 if (!is_marked_for_delete(service->service_entry))
604 err = mark_for_delete(service->service_entry);
605 else
606 err = ERROR_SERVICE_MARKED_FOR_DELETE;
608 service_unlock(service->service_entry);
610 return err;
613 DWORD __cdecl svcctl_QueryServiceConfigW(
614 SC_RPC_HANDLE hService,
615 QUERY_SERVICE_CONFIGW *config,
616 DWORD buf_size,
617 DWORD *needed_size)
619 struct sc_service_handle *service;
620 DWORD err;
622 WINE_TRACE("(%p)\n", config);
624 if ((err = validate_service_handle(hService, SERVICE_QUERY_CONFIG, &service)) != 0)
625 return err;
627 service_lock_shared(service->service_entry);
628 config->dwServiceType = service->service_entry->config.dwServiceType;
629 config->dwStartType = service->service_entry->config.dwStartType;
630 config->dwErrorControl = service->service_entry->config.dwErrorControl;
631 config->lpBinaryPathName = strdupW(service->service_entry->config.lpBinaryPathName);
632 config->lpLoadOrderGroup = strdupW(service->service_entry->config.lpLoadOrderGroup);
633 config->dwTagId = service->service_entry->config.dwTagId;
634 config->lpDependencies = NULL; /* TODO */
635 config->lpServiceStartName = strdupW(service->service_entry->config.lpServiceStartName);
636 config->lpDisplayName = strdupW(service->service_entry->config.lpDisplayName);
637 service_unlock(service->service_entry);
639 return ERROR_SUCCESS;
642 DWORD __cdecl svcctl_ChangeServiceConfigW(
643 SC_RPC_HANDLE hService,
644 DWORD dwServiceType,
645 DWORD dwStartType,
646 DWORD dwErrorControl,
647 LPCWSTR lpBinaryPathName,
648 LPCWSTR lpLoadOrderGroup,
649 DWORD *lpdwTagId,
650 const BYTE *lpDependencies,
651 DWORD dwDependenciesSize,
652 LPCWSTR lpServiceStartName,
653 const BYTE *lpPassword,
654 DWORD dwPasswordSize,
655 LPCWSTR lpDisplayName)
657 struct service_entry new_entry, *entry;
658 struct sc_service_handle *service;
659 DWORD err;
661 WINE_TRACE("\n");
663 if ((err = validate_service_handle(hService, SERVICE_CHANGE_CONFIG, &service)) != 0)
664 return err;
666 if (!check_multisz((LPCWSTR)lpDependencies, dwDependenciesSize))
667 return ERROR_INVALID_PARAMETER;
669 /* first check if the new configuration is correct */
670 service_lock_exclusive(service->service_entry);
672 if (is_marked_for_delete(service->service_entry))
674 service_unlock(service->service_entry);
675 return ERROR_SERVICE_MARKED_FOR_DELETE;
678 if (lpDisplayName != NULL &&
679 (entry = scmdatabase_find_service_by_displayname(service->service_entry->db, lpDisplayName)) &&
680 (entry != service->service_entry))
682 service_unlock(service->service_entry);
683 return ERROR_DUPLICATE_SERVICE_NAME;
686 new_entry = *service->service_entry;
688 if (dwServiceType != SERVICE_NO_CHANGE)
689 new_entry.config.dwServiceType = dwServiceType;
691 if (dwStartType != SERVICE_NO_CHANGE)
692 new_entry.config.dwStartType = dwStartType;
694 if (dwErrorControl != SERVICE_NO_CHANGE)
695 new_entry.config.dwErrorControl = dwErrorControl;
697 if (lpBinaryPathName != NULL)
698 new_entry.config.lpBinaryPathName = (LPWSTR)lpBinaryPathName;
700 if (lpLoadOrderGroup != NULL)
701 new_entry.config.lpLoadOrderGroup = (LPWSTR)lpLoadOrderGroup;
703 if (lpdwTagId != NULL)
704 WINE_FIXME("Changing tag id not supported\n");
706 if (lpServiceStartName != NULL)
707 new_entry.config.lpServiceStartName = (LPWSTR)lpServiceStartName;
709 if (lpPassword != NULL)
710 WINE_FIXME("Setting password not supported\n");
712 if (lpDisplayName != NULL)
713 new_entry.config.lpDisplayName = (LPWSTR)lpDisplayName;
715 err = parse_dependencies((LPCWSTR)lpDependencies, &new_entry);
716 if (err != ERROR_SUCCESS)
718 service_unlock(service->service_entry);
719 return err;
722 if (!validate_service_config(&new_entry))
724 WINE_ERR("The configuration after the change wouldn't be valid\n");
725 service_unlock(service->service_entry);
726 return ERROR_INVALID_PARAMETER;
729 /* configuration OK. The strings needs to be duplicated */
730 if (lpBinaryPathName != NULL)
731 new_entry.config.lpBinaryPathName = strdupW(lpBinaryPathName);
733 if (lpLoadOrderGroup != NULL)
734 new_entry.config.lpLoadOrderGroup = strdupW(lpLoadOrderGroup);
736 if (lpServiceStartName != NULL)
737 new_entry.config.lpServiceStartName = strdupW(lpServiceStartName);
739 if (lpDisplayName != NULL)
740 new_entry.config.lpDisplayName = strdupW(lpDisplayName);
742 /* try to save to Registry, commit or rollback depending on success */
743 err = save_service_config(&new_entry);
744 if (ERROR_SUCCESS == err)
746 free_service_strings(service->service_entry, &new_entry);
747 *service->service_entry = new_entry;
749 else free_service_strings(&new_entry, service->service_entry);
750 service_unlock(service->service_entry);
752 return err;
755 DWORD __cdecl svcctl_SetServiceStatus(
756 SC_RPC_HANDLE hServiceStatus,
757 LPSERVICE_STATUS lpServiceStatus)
759 struct sc_service_handle *service;
760 DWORD err;
762 WINE_TRACE("(%p, %p)\n", hServiceStatus, lpServiceStatus);
764 if ((err = validate_service_handle(hServiceStatus, SERVICE_SET_STATUS, &service)) != 0)
765 return err;
767 service_lock_exclusive(service->service_entry);
768 /* FIXME: be a bit more discriminant about what parts of the status we set
769 * and check that fields are valid */
770 service->service_entry->status.dwServiceType = lpServiceStatus->dwServiceType;
771 service->service_entry->status.dwCurrentState = lpServiceStatus->dwCurrentState;
772 service->service_entry->status.dwControlsAccepted = lpServiceStatus->dwControlsAccepted;
773 service->service_entry->status.dwWin32ExitCode = lpServiceStatus->dwWin32ExitCode;
774 service->service_entry->status.dwServiceSpecificExitCode = lpServiceStatus->dwServiceSpecificExitCode;
775 service->service_entry->status.dwCheckPoint = lpServiceStatus->dwCheckPoint;
776 service->service_entry->status.dwWaitHint = lpServiceStatus->dwWaitHint;
777 service_unlock(service->service_entry);
779 if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED)
780 run_after_timeout(service_terminate, service->service_entry, service_kill_timeout);
781 else if (service->service_entry->status_changed_event)
782 SetEvent(service->service_entry->status_changed_event);
784 return ERROR_SUCCESS;
787 DWORD __cdecl svcctl_ChangeServiceConfig2W( SC_RPC_HANDLE hService, SC_RPC_CONFIG_INFOW config )
789 struct sc_service_handle *service;
790 DWORD err;
792 if ((err = validate_service_handle(hService, SERVICE_CHANGE_CONFIG, &service)) != 0)
793 return err;
795 switch (config.dwInfoLevel)
797 case SERVICE_CONFIG_DESCRIPTION:
799 WCHAR *descr = NULL;
801 if (config.u.descr->lpDescription[0])
803 if (!(descr = strdupW( config.u.descr->lpDescription )))
804 return ERROR_NOT_ENOUGH_MEMORY;
807 WINE_TRACE( "changing service %p descr to %s\n", service, wine_dbgstr_w(descr) );
808 service_lock_exclusive( service->service_entry );
809 HeapFree( GetProcessHeap(), 0, service->service_entry->description );
810 service->service_entry->description = descr;
811 save_service_config( service->service_entry );
812 service_unlock( service->service_entry );
814 break;
815 case SERVICE_CONFIG_FAILURE_ACTIONS:
816 WINE_FIXME( "SERVICE_CONFIG_FAILURE_ACTIONS not implemented: period %u msg %s cmd %s\n",
817 config.u.actions->dwResetPeriod,
818 wine_dbgstr_w(config.u.actions->lpRebootMsg),
819 wine_dbgstr_w(config.u.actions->lpCommand) );
820 break;
821 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
822 WINE_TRACE( "changing service %p preshutdown timeout to %d\n",
823 service, config.u.preshutdown->dwPreshutdownTimeout );
824 service_lock_exclusive( service->service_entry );
825 service->service_entry->preshutdown_timeout = config.u.preshutdown->dwPreshutdownTimeout;
826 save_service_config( service->service_entry );
827 service_unlock( service->service_entry );
828 break;
829 default:
830 WINE_FIXME("level %u not implemented\n", config.dwInfoLevel);
831 err = ERROR_INVALID_LEVEL;
832 break;
834 return err;
837 DWORD __cdecl svcctl_QueryServiceConfig2W( SC_RPC_HANDLE hService, DWORD level,
838 BYTE *buffer, DWORD size, LPDWORD needed )
840 struct sc_service_handle *service;
841 DWORD err;
843 memset(buffer, 0, size);
845 if ((err = validate_service_handle(hService, SERVICE_QUERY_STATUS, &service)) != 0)
846 return err;
848 switch (level)
850 case SERVICE_CONFIG_DESCRIPTION:
852 SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer;
854 service_lock_shared(service->service_entry);
855 *needed = sizeof(*descr);
856 if (service->service_entry->description)
857 *needed += (strlenW(service->service_entry->description) + 1) * sizeof(WCHAR);
858 if (size >= *needed)
860 if (service->service_entry->description)
862 /* store a buffer offset instead of a pointer */
863 descr->lpDescription = (WCHAR *)((BYTE *)(descr + 1) - buffer);
864 strcpyW( (WCHAR *)(descr + 1), service->service_entry->description );
866 else descr->lpDescription = NULL;
868 else err = ERROR_INSUFFICIENT_BUFFER;
869 service_unlock(service->service_entry);
871 break;
873 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
874 service_lock_shared(service->service_entry);
876 *needed = sizeof(SERVICE_PRESHUTDOWN_INFO);
877 if (size >= *needed)
878 ((LPSERVICE_PRESHUTDOWN_INFO)buffer)->dwPreshutdownTimeout =
879 service->service_entry->preshutdown_timeout;
880 else err = ERROR_INSUFFICIENT_BUFFER;
882 service_unlock(service->service_entry);
883 break;
885 default:
886 WINE_FIXME("level %u not implemented\n", level);
887 err = ERROR_INVALID_LEVEL;
888 break;
890 return err;
893 DWORD __cdecl svcctl_QueryServiceStatusEx(
894 SC_RPC_HANDLE hService,
895 SC_STATUS_TYPE InfoLevel,
896 BYTE *lpBuffer,
897 DWORD cbBufSize,
898 LPDWORD pcbBytesNeeded)
900 struct sc_service_handle *service;
901 DWORD err;
902 LPSERVICE_STATUS_PROCESS pSvcStatusData;
904 memset(lpBuffer, 0, cbBufSize);
906 if ((err = validate_service_handle(hService, SERVICE_QUERY_STATUS, &service)) != 0)
907 return err;
909 if (InfoLevel != SC_STATUS_PROCESS_INFO)
910 return ERROR_INVALID_LEVEL;
912 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
913 if (pSvcStatusData == NULL)
914 return ERROR_INVALID_PARAMETER;
916 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
918 if( pcbBytesNeeded != NULL)
919 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
921 return ERROR_INSUFFICIENT_BUFFER;
924 service_lock_shared(service->service_entry);
926 pSvcStatusData->dwServiceType = service->service_entry->status.dwServiceType;
927 pSvcStatusData->dwCurrentState = service->service_entry->status.dwCurrentState;
928 pSvcStatusData->dwControlsAccepted = service->service_entry->status.dwControlsAccepted;
929 pSvcStatusData->dwWin32ExitCode = service->service_entry->status.dwWin32ExitCode;
930 pSvcStatusData->dwServiceSpecificExitCode = service->service_entry->status.dwServiceSpecificExitCode;
931 pSvcStatusData->dwCheckPoint = service->service_entry->status.dwCheckPoint;
932 pSvcStatusData->dwWaitHint = service->service_entry->status.dwWaitHint;
933 pSvcStatusData->dwProcessId = service->service_entry->status.dwProcessId;
934 pSvcStatusData->dwServiceFlags = service->service_entry->status.dwServiceFlags;
936 service_unlock(service->service_entry);
938 return ERROR_SUCCESS;
941 /******************************************************************************
942 * service_accepts_control
944 static BOOL service_accepts_control(const struct service_entry *service, DWORD dwControl)
946 DWORD a = service->status.dwControlsAccepted;
948 switch (dwControl)
950 case SERVICE_CONTROL_INTERROGATE:
951 return TRUE;
952 case SERVICE_CONTROL_STOP:
953 if (a&SERVICE_ACCEPT_STOP)
954 return TRUE;
955 break;
956 case SERVICE_CONTROL_SHUTDOWN:
957 if (a&SERVICE_ACCEPT_SHUTDOWN)
958 return TRUE;
959 break;
960 case SERVICE_CONTROL_PAUSE:
961 case SERVICE_CONTROL_CONTINUE:
962 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
963 return TRUE;
964 break;
965 case SERVICE_CONTROL_PARAMCHANGE:
966 if (a&SERVICE_ACCEPT_PARAMCHANGE)
967 return TRUE;
968 break;
969 case SERVICE_CONTROL_NETBINDADD:
970 case SERVICE_CONTROL_NETBINDREMOVE:
971 case SERVICE_CONTROL_NETBINDENABLE:
972 case SERVICE_CONTROL_NETBINDDISABLE:
973 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
974 return TRUE;
975 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
976 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
977 return TRUE;
978 break;
979 case SERVICE_CONTROL_POWEREVENT:
980 if (a&SERVICE_ACCEPT_POWEREVENT)
981 return TRUE;
982 break;
983 case SERVICE_CONTROL_SESSIONCHANGE:
984 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
985 return TRUE;
986 break;
988 return FALSE;
991 /******************************************************************************
992 * service_send_command
994 BOOL service_send_command( struct service_entry *service, HANDLE pipe,
995 const void *data, DWORD size, DWORD *result )
997 OVERLAPPED overlapped;
998 DWORD count, ret;
999 BOOL r;
1001 overlapped.hEvent = service->overlapped_event;
1002 r = WriteFile(pipe, data, size, &count, &overlapped);
1003 if (!r && GetLastError() == ERROR_IO_PENDING)
1005 ret = WaitForSingleObject( service->overlapped_event, service_pipe_timeout );
1006 if (ret == WAIT_TIMEOUT)
1008 WINE_ERR("sending command timed out\n");
1009 *result = ERROR_SERVICE_REQUEST_TIMEOUT;
1010 return FALSE;
1012 r = GetOverlappedResult( pipe, &overlapped, &count, FALSE );
1014 if (!r || count != size)
1016 WINE_ERR("service protocol error - failed to write pipe!\n");
1017 *result = (!r ? GetLastError() : ERROR_WRITE_FAULT);
1018 return FALSE;
1020 r = ReadFile(pipe, result, sizeof *result, &count, &overlapped);
1021 if (!r && GetLastError() == ERROR_IO_PENDING)
1023 ret = WaitForSingleObject( service->overlapped_event, service_pipe_timeout );
1024 if (ret == WAIT_TIMEOUT)
1026 WINE_ERR("receiving command result timed out\n");
1027 *result = ERROR_SERVICE_REQUEST_TIMEOUT;
1028 return FALSE;
1030 r = GetOverlappedResult( pipe, &overlapped, &count, FALSE );
1032 if (!r || count != sizeof *result)
1034 WINE_ERR("service protocol error - failed to read pipe "
1035 "r = %d count = %d!\n", r, count);
1036 *result = (!r ? GetLastError() : ERROR_READ_FAULT);
1037 return FALSE;
1040 *result = ERROR_SUCCESS;
1041 return TRUE;
1044 /******************************************************************************
1045 * service_send_control
1047 static BOOL service_send_control(struct service_entry *service, HANDLE pipe, DWORD dwControl, DWORD *result)
1049 service_start_info *ssi;
1050 DWORD len;
1051 BOOL r;
1053 /* calculate how much space we need to send the startup info */
1054 len = strlenW(service->name) + 1;
1056 ssi = HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info, data[len]));
1057 ssi->cmd = WINESERV_SENDCONTROL;
1058 ssi->control = dwControl;
1059 ssi->total_size = FIELD_OFFSET(service_start_info, data[len]);
1060 ssi->name_size = strlenW(service->name) + 1;
1061 strcpyW( ssi->data, service->name );
1063 r = service_send_command( service, pipe, ssi, ssi->total_size, result );
1064 HeapFree( GetProcessHeap(), 0, ssi );
1065 return r;
1068 DWORD __cdecl svcctl_StartServiceW(
1069 SC_RPC_HANDLE hService,
1070 DWORD dwNumServiceArgs,
1071 LPCWSTR *lpServiceArgVectors)
1073 struct sc_service_handle *service;
1074 DWORD err;
1076 WINE_TRACE("(%p, %d, %p)\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1078 if ((err = validate_service_handle(hService, SERVICE_START, &service)) != 0)
1079 return err;
1081 if (service->service_entry->config.dwStartType == SERVICE_DISABLED)
1082 return ERROR_SERVICE_DISABLED;
1084 err = service_start(service->service_entry, dwNumServiceArgs, lpServiceArgVectors);
1086 return err;
1089 DWORD __cdecl svcctl_ControlService(
1090 SC_RPC_HANDLE hService,
1091 DWORD dwControl,
1092 SERVICE_STATUS *lpServiceStatus)
1094 DWORD access_required;
1095 struct sc_service_handle *service;
1096 DWORD result;
1097 BOOL ret;
1098 HANDLE control_mutex;
1100 WINE_TRACE("(%p, %d, %p)\n", hService, dwControl, lpServiceStatus);
1102 switch (dwControl)
1104 case SERVICE_CONTROL_CONTINUE:
1105 case SERVICE_CONTROL_NETBINDADD:
1106 case SERVICE_CONTROL_NETBINDDISABLE:
1107 case SERVICE_CONTROL_NETBINDENABLE:
1108 case SERVICE_CONTROL_NETBINDREMOVE:
1109 case SERVICE_CONTROL_PARAMCHANGE:
1110 case SERVICE_CONTROL_PAUSE:
1111 access_required = SERVICE_PAUSE_CONTINUE;
1112 break;
1113 case SERVICE_CONTROL_INTERROGATE:
1114 access_required = SERVICE_INTERROGATE;
1115 break;
1116 case SERVICE_CONTROL_STOP:
1117 access_required = SERVICE_STOP;
1118 break;
1119 default:
1120 if (dwControl >= 128 && dwControl <= 255)
1121 access_required = SERVICE_USER_DEFINED_CONTROL;
1122 else
1123 return ERROR_INVALID_PARAMETER;
1126 if ((result = validate_service_handle(hService, access_required, &service)) != 0)
1127 return result;
1129 service_lock_exclusive(service->service_entry);
1131 result = ERROR_SUCCESS;
1132 switch (service->service_entry->status.dwCurrentState)
1134 case SERVICE_STOPPED:
1135 result = ERROR_SERVICE_NOT_ACTIVE;
1136 break;
1137 case SERVICE_START_PENDING:
1138 if (dwControl==SERVICE_CONTROL_STOP)
1139 break;
1140 /* fall through */
1141 case SERVICE_STOP_PENDING:
1142 result = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1143 break;
1146 if (result==ERROR_SUCCESS && !service->service_entry->control_mutex) {
1147 result = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1148 service_terminate(service->service_entry);
1151 if (result != ERROR_SUCCESS)
1153 if (lpServiceStatus)
1155 lpServiceStatus->dwServiceType = service->service_entry->status.dwServiceType;
1156 lpServiceStatus->dwCurrentState = service->service_entry->status.dwCurrentState;
1157 lpServiceStatus->dwControlsAccepted = service->service_entry->status.dwControlsAccepted;
1158 lpServiceStatus->dwWin32ExitCode = service->service_entry->status.dwWin32ExitCode;
1159 lpServiceStatus->dwServiceSpecificExitCode = service->service_entry->status.dwServiceSpecificExitCode;
1160 lpServiceStatus->dwCheckPoint = service->service_entry->status.dwCheckPoint;
1161 lpServiceStatus->dwWaitHint = service->service_entry->status.dwWaitHint;
1163 service_unlock(service->service_entry);
1164 return result;
1167 if (!service_accepts_control(service->service_entry, dwControl))
1169 service_unlock(service->service_entry);
1170 return ERROR_INVALID_SERVICE_CONTROL;
1173 /* prevent races by caching control_mutex and clearing it on
1174 * stop instead of outside the services lock */
1175 control_mutex = service->service_entry->control_mutex;
1176 if (dwControl == SERVICE_CONTROL_STOP)
1177 service->service_entry->control_mutex = NULL;
1179 service_unlock(service->service_entry);
1181 ret = WaitForSingleObject(control_mutex, 30000);
1182 if (ret == WAIT_OBJECT_0)
1184 service_send_control(service->service_entry, service->service_entry->control_pipe,
1185 dwControl, &result);
1187 if (lpServiceStatus)
1189 service_lock_shared(service->service_entry);
1190 lpServiceStatus->dwServiceType = service->service_entry->status.dwServiceType;
1191 lpServiceStatus->dwCurrentState = service->service_entry->status.dwCurrentState;
1192 lpServiceStatus->dwControlsAccepted = service->service_entry->status.dwControlsAccepted;
1193 lpServiceStatus->dwWin32ExitCode = service->service_entry->status.dwWin32ExitCode;
1194 lpServiceStatus->dwServiceSpecificExitCode = service->service_entry->status.dwServiceSpecificExitCode;
1195 lpServiceStatus->dwCheckPoint = service->service_entry->status.dwCheckPoint;
1196 lpServiceStatus->dwWaitHint = service->service_entry->status.dwWaitHint;
1197 service_unlock(service->service_entry);
1200 if (dwControl == SERVICE_CONTROL_STOP)
1201 CloseHandle(control_mutex);
1202 else
1203 ReleaseMutex(control_mutex);
1205 return result;
1207 else
1209 if (dwControl == SERVICE_CONTROL_STOP)
1210 CloseHandle(control_mutex);
1211 return ERROR_SERVICE_REQUEST_TIMEOUT;
1215 DWORD __cdecl svcctl_CloseServiceHandle(
1216 SC_RPC_HANDLE *handle)
1218 WINE_TRACE("(&%p)\n", *handle);
1220 SC_RPC_HANDLE_destroy(*handle);
1221 *handle = NULL;
1223 return ERROR_SUCCESS;
1226 static void SC_RPC_LOCK_destroy(SC_RPC_LOCK hLock)
1228 struct sc_lock *lock = hLock;
1229 scmdatabase_unlock_startup(lock->db);
1230 HeapFree(GetProcessHeap(), 0, lock);
1233 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK hLock)
1235 SC_RPC_LOCK_destroy(hLock);
1238 DWORD __cdecl svcctl_LockServiceDatabase(
1239 SC_RPC_HANDLE hSCManager,
1240 SC_RPC_LOCK *phLock)
1242 struct sc_manager_handle *manager;
1243 struct sc_lock *lock;
1244 DWORD err;
1246 WINE_TRACE("(%p, %p)\n", hSCManager, phLock);
1248 if ((err = validate_scm_handle(hSCManager, SC_MANAGER_LOCK, &manager)) != ERROR_SUCCESS)
1249 return err;
1251 err = scmdatabase_lock_startup(manager->db);
1252 if (err != ERROR_SUCCESS)
1253 return err;
1255 lock = HeapAlloc(GetProcessHeap(), 0, sizeof(struct sc_lock));
1256 if (!lock)
1258 scmdatabase_unlock_startup(manager->db);
1259 return ERROR_NOT_ENOUGH_SERVER_MEMORY;
1262 lock->db = manager->db;
1263 *phLock = lock;
1265 return ERROR_SUCCESS;
1268 DWORD __cdecl svcctl_UnlockServiceDatabase(
1269 SC_RPC_LOCK *phLock)
1271 WINE_TRACE("(&%p)\n", *phLock);
1273 SC_RPC_LOCK_destroy(*phLock);
1274 *phLock = NULL;
1276 return ERROR_SUCCESS;
1279 static BOOL map_state(DWORD state, DWORD mask)
1281 switch (state)
1283 case SERVICE_START_PENDING:
1284 case SERVICE_STOP_PENDING:
1285 case SERVICE_RUNNING:
1286 case SERVICE_CONTINUE_PENDING:
1287 case SERVICE_PAUSE_PENDING:
1288 case SERVICE_PAUSED:
1289 if (SERVICE_ACTIVE & mask) return TRUE;
1290 break;
1291 case SERVICE_STOPPED:
1292 if (SERVICE_INACTIVE & mask) return TRUE;
1293 break;
1294 default:
1295 WINE_ERR("unknown state %u\n", state);
1296 break;
1298 return FALSE;
1301 DWORD __cdecl svcctl_EnumServicesStatusW(
1302 SC_RPC_HANDLE hmngr,
1303 DWORD type,
1304 DWORD state,
1305 BYTE *buffer,
1306 DWORD size,
1307 LPDWORD needed,
1308 LPDWORD returned,
1309 LPDWORD resume)
1311 DWORD err, sz, total_size, num_services;
1312 DWORD_PTR offset;
1313 struct sc_manager_handle *manager;
1314 struct service_entry *service;
1315 ENUM_SERVICE_STATUSW *s;
1317 WINE_TRACE("(%p, 0x%x, 0x%x, %p, %u, %p, %p, %p)\n", hmngr, type, state, buffer, size, needed, returned, resume);
1319 if (!type || !state)
1320 return ERROR_INVALID_PARAMETER;
1322 if ((err = validate_scm_handle(hmngr, SC_MANAGER_ENUMERATE_SERVICE, &manager)) != ERROR_SUCCESS)
1323 return err;
1325 if (resume)
1326 WINE_FIXME("resume index not supported\n");
1328 scmdatabase_lock_exclusive(manager->db);
1330 total_size = num_services = 0;
1331 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1333 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state))
1335 total_size += sizeof(ENUM_SERVICE_STATUSW);
1336 total_size += (strlenW(service->name) + 1) * sizeof(WCHAR);
1337 if (service->config.lpDisplayName)
1339 total_size += (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1341 num_services++;
1344 *returned = 0;
1345 *needed = total_size;
1346 if (total_size > size)
1348 scmdatabase_unlock(manager->db);
1349 return ERROR_MORE_DATA;
1351 s = (ENUM_SERVICE_STATUSW *)buffer;
1352 offset = num_services * sizeof(ENUM_SERVICE_STATUSW);
1353 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1355 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state))
1357 sz = (strlenW(service->name) + 1) * sizeof(WCHAR);
1358 memcpy(buffer + offset, service->name, sz);
1359 s->lpServiceName = (WCHAR *)offset; /* store a buffer offset instead of a pointer */
1360 offset += sz;
1362 if (!service->config.lpDisplayName) s->lpDisplayName = NULL;
1363 else
1365 sz = (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1366 memcpy(buffer + offset, service->config.lpDisplayName, sz);
1367 s->lpDisplayName = (WCHAR *)offset;
1368 offset += sz;
1370 memcpy(&s->ServiceStatus, &service->status, sizeof(SERVICE_STATUS));
1371 s++;
1374 *returned = num_services;
1375 *needed = 0;
1376 scmdatabase_unlock(manager->db);
1377 return ERROR_SUCCESS;
1380 static struct service_entry *find_service_by_group(struct scmdatabase *db, const WCHAR *group)
1382 struct service_entry *service;
1383 LIST_FOR_EACH_ENTRY(service, &db->services, struct service_entry, entry)
1385 if (service->config.lpLoadOrderGroup && !strcmpiW(group, service->config.lpLoadOrderGroup))
1386 return service;
1388 return NULL;
1391 static BOOL match_group(const WCHAR *g1, const WCHAR *g2)
1393 if (!g2) return TRUE;
1394 if (!g2[0] && (!g1 || !g1[0])) return TRUE;
1395 if (g1 && !strcmpW(g1, g2)) return TRUE;
1396 return FALSE;
1399 DWORD __cdecl svcctl_EnumServicesStatusExA(
1400 SC_RPC_HANDLE scmanager,
1401 SC_ENUM_TYPE info_level,
1402 DWORD service_type,
1403 DWORD service_state,
1404 BYTE *buffer,
1405 DWORD buf_size,
1406 DWORD *needed_size,
1407 DWORD *services_count,
1408 DWORD *resume_index,
1409 LPCSTR groupname)
1411 WINE_FIXME("\n");
1412 return ERROR_CALL_NOT_IMPLEMENTED;
1415 DWORD __cdecl svcctl_EnumServicesStatusExW(
1416 SC_RPC_HANDLE hmngr,
1417 SC_ENUM_TYPE info_level,
1418 DWORD type,
1419 DWORD state,
1420 BYTE *buffer,
1421 DWORD size,
1422 LPDWORD needed,
1423 LPDWORD returned,
1424 DWORD *resume_handle,
1425 LPCWSTR group)
1427 DWORD err, sz, total_size, num_services;
1428 DWORD_PTR offset;
1429 struct sc_manager_handle *manager;
1430 struct service_entry *service;
1431 ENUM_SERVICE_STATUS_PROCESSW *s;
1433 WINE_TRACE("(%p, 0x%x, 0x%x, %p, %u, %p, %p, %s)\n", hmngr, type, state, buffer, size,
1434 needed, returned, wine_dbgstr_w(group));
1436 if (resume_handle)
1437 FIXME("resume handle not supported\n");
1439 if (!type || !state)
1440 return ERROR_INVALID_PARAMETER;
1442 if ((err = validate_scm_handle(hmngr, SC_MANAGER_ENUMERATE_SERVICE, &manager)) != ERROR_SUCCESS)
1443 return err;
1445 scmdatabase_lock_exclusive(manager->db);
1447 if (group && !find_service_by_group(manager->db, group))
1449 scmdatabase_unlock(manager->db);
1450 return ERROR_SERVICE_DOES_NOT_EXIST;
1453 total_size = num_services = 0;
1454 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1456 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state)
1457 && match_group(service->config.lpLoadOrderGroup, group))
1459 total_size += sizeof(ENUM_SERVICE_STATUS_PROCESSW);
1460 total_size += (strlenW(service->name) + 1) * sizeof(WCHAR);
1461 if (service->config.lpDisplayName)
1463 total_size += (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1465 num_services++;
1468 *returned = 0;
1469 *needed = total_size;
1470 if (total_size > size)
1472 scmdatabase_unlock(manager->db);
1473 return ERROR_MORE_DATA;
1475 s = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1476 offset = num_services * sizeof(ENUM_SERVICE_STATUS_PROCESSW);
1477 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1479 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state)
1480 && match_group(service->config.lpLoadOrderGroup, group))
1482 sz = (strlenW(service->name) + 1) * sizeof(WCHAR);
1483 memcpy(buffer + offset, service->name, sz);
1484 s->lpServiceName = (WCHAR *)offset; /* store a buffer offset instead of a pointer */
1485 offset += sz;
1487 if (!service->config.lpDisplayName) s->lpDisplayName = NULL;
1488 else
1490 sz = (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1491 memcpy(buffer + offset, service->config.lpDisplayName, sz);
1492 s->lpDisplayName = (WCHAR *)offset;
1493 offset += sz;
1495 s->ServiceStatusProcess = service->status;
1496 s++;
1499 *returned = num_services;
1500 *needed = 0;
1501 scmdatabase_unlock(manager->db);
1502 return ERROR_SUCCESS;
1505 DWORD __cdecl svcctl_unknown43(void)
1507 WINE_FIXME("\n");
1508 return ERROR_CALL_NOT_IMPLEMENTED;
1511 DWORD __cdecl svcctl_CreateServiceWOW64A(
1512 SC_RPC_HANDLE scmanager,
1513 LPCSTR servicename,
1514 LPCSTR displayname,
1515 DWORD accessmask,
1516 DWORD service_type,
1517 DWORD start_type,
1518 DWORD error_control,
1519 LPCSTR imagepath,
1520 LPCSTR loadordergroup,
1521 DWORD *tagid,
1522 const BYTE *dependencies,
1523 DWORD depend_size,
1524 LPCSTR start_name,
1525 const BYTE *password,
1526 DWORD password_size,
1527 SC_RPC_HANDLE *service)
1529 WINE_FIXME("\n");
1530 return ERROR_CALL_NOT_IMPLEMENTED;
1533 DWORD __cdecl svcctl_CreateServiceWOW64W(
1534 SC_RPC_HANDLE scmanager,
1535 LPCWSTR servicename,
1536 LPCWSTR displayname,
1537 DWORD accessmask,
1538 DWORD service_type,
1539 DWORD start_type,
1540 DWORD error_control,
1541 LPCWSTR imagepath,
1542 LPCWSTR loadordergroup,
1543 DWORD *tagid,
1544 const BYTE *dependencies,
1545 DWORD depend_size,
1546 LPCWSTR start_name,
1547 const BYTE *password,
1548 DWORD password_size,
1549 SC_RPC_HANDLE *service)
1551 WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(servicename), wine_dbgstr_w(displayname), accessmask, wine_dbgstr_w(imagepath));
1552 return create_serviceW(scmanager, servicename, displayname, accessmask, service_type, start_type, error_control, imagepath,
1553 loadordergroup, tagid, dependencies, depend_size, start_name, password, password_size, service, TRUE);
1556 DWORD __cdecl svcctl_unknown46(void)
1558 WINE_FIXME("\n");
1559 return ERROR_CALL_NOT_IMPLEMENTED;
1562 DWORD __cdecl svcctl_NotifyServiceStatusChange(
1563 SC_RPC_HANDLE service,
1564 SC_RPC_NOTIFY_PARAMS params,
1565 GUID *clientprocessguid,
1566 GUID *scmprocessguid,
1567 BOOL *createremotequeue,
1568 SC_NOTIFY_RPC_HANDLE *notify)
1570 WINE_FIXME("\n");
1571 return ERROR_CALL_NOT_IMPLEMENTED;
1574 DWORD __cdecl svcctl_GetNotifyResults(
1575 SC_NOTIFY_RPC_HANDLE notify,
1576 SC_RPC_NOTIFY_PARAMS_LIST **params)
1578 WINE_FIXME("\n");
1579 return ERROR_CALL_NOT_IMPLEMENTED;
1582 DWORD __cdecl svcctl_CloseNotifyHandle(
1583 SC_NOTIFY_RPC_HANDLE *notify,
1584 BOOL *apc_fired)
1586 WINE_FIXME("\n");
1587 return ERROR_CALL_NOT_IMPLEMENTED;
1590 DWORD __cdecl svcctl_ControlServiceExA(
1591 SC_RPC_HANDLE service,
1592 DWORD control,
1593 DWORD info_level,
1594 SC_RPC_SERVICE_CONTROL_IN_PARAMSA *in_params,
1595 SC_RPC_SERVICE_CONTROL_OUT_PARAMSA *out_params)
1597 WINE_FIXME("\n");
1598 return ERROR_CALL_NOT_IMPLEMENTED;
1601 DWORD __cdecl svcctl_ControlServiceExW(
1602 SC_RPC_HANDLE service,
1603 DWORD control,
1604 DWORD info_level,
1605 SC_RPC_SERVICE_CONTROL_IN_PARAMSW *in_params,
1606 SC_RPC_SERVICE_CONTROL_OUT_PARAMSW *out_params)
1608 WINE_FIXME("\n");
1609 return ERROR_CALL_NOT_IMPLEMENTED;
1612 DWORD __cdecl svcctl_unknown52(void)
1614 WINE_FIXME("\n");
1615 return ERROR_CALL_NOT_IMPLEMENTED;
1618 DWORD __cdecl svcctl_unknown53(void)
1620 WINE_FIXME("\n");
1621 return ERROR_CALL_NOT_IMPLEMENTED;
1624 DWORD __cdecl svcctl_unknown54(void)
1626 WINE_FIXME("\n");
1627 return ERROR_CALL_NOT_IMPLEMENTED;
1630 DWORD __cdecl svcctl_unknown55(void)
1632 WINE_FIXME("\n");
1633 return ERROR_CALL_NOT_IMPLEMENTED;
1636 DWORD __cdecl svcctl_QueryServiceConfigEx(
1637 SC_RPC_HANDLE service,
1638 DWORD info_level,
1639 SC_RPC_CONFIG_INFOW *info)
1641 WINE_FIXME("\n");
1642 return ERROR_CALL_NOT_IMPLEMENTED;
1645 DWORD __cdecl svcctl_QueryServiceObjectSecurity(
1646 SC_RPC_HANDLE service,
1647 SECURITY_INFORMATION info,
1648 BYTE *descriptor,
1649 DWORD buf_size,
1650 DWORD *needed_size)
1652 WINE_FIXME("\n");
1653 return ERROR_CALL_NOT_IMPLEMENTED;
1656 DWORD __cdecl svcctl_SetServiceObjectSecurity(
1657 SC_RPC_HANDLE service,
1658 SECURITY_INFORMATION info,
1659 BYTE *descriptor,
1660 DWORD buf_size)
1662 WINE_FIXME("\n");
1663 return ERROR_CALL_NOT_IMPLEMENTED;
1666 DWORD __cdecl svcctl_QueryServiceStatus(
1667 SC_RPC_HANDLE service,
1668 SERVICE_STATUS *status)
1670 WINE_FIXME("\n");
1671 return ERROR_CALL_NOT_IMPLEMENTED;
1674 DWORD __cdecl svcctl_NotifyBootConfigStatus(
1675 SVCCTL_HANDLEW machinename,
1676 DWORD boot_acceptable)
1678 WINE_FIXME("\n");
1679 return ERROR_CALL_NOT_IMPLEMENTED;
1682 DWORD __cdecl svcctl_SCSetServiceBitsW(void)
1684 WINE_FIXME("\n");
1685 return ERROR_CALL_NOT_IMPLEMENTED;
1688 DWORD __cdecl svcctl_EnumDependentServicesW(
1689 SC_RPC_HANDLE service,
1690 DWORD state,
1691 BYTE *services,
1692 DWORD buf_size,
1693 DWORD *needed_size,
1694 DWORD *services_ret)
1696 WINE_FIXME("\n");
1697 return ERROR_CALL_NOT_IMPLEMENTED;
1700 DWORD __cdecl svcctl_QueryServiceLockStatusW(
1701 SC_RPC_HANDLE scmanager,
1702 QUERY_SERVICE_LOCK_STATUSW *status,
1703 DWORD buf_size,
1704 DWORD *needed_size)
1706 WINE_FIXME("\n");
1707 return ERROR_CALL_NOT_IMPLEMENTED;
1710 DWORD __cdecl svcctl_SCSetServiceBitsA(void)
1712 WINE_FIXME("\n");
1713 return ERROR_CALL_NOT_IMPLEMENTED;
1716 DWORD __cdecl svcctl_ChangeServiceConfigA(
1717 SC_RPC_HANDLE service,
1718 DWORD service_type,
1719 DWORD start_type,
1720 DWORD error_control,
1721 LPSTR binarypath,
1722 LPSTR loadordergroup,
1723 DWORD *tagid,
1724 BYTE *dependencies,
1725 DWORD depend_size,
1726 LPSTR startname,
1727 BYTE *password,
1728 DWORD password_size,
1729 LPSTR displayname)
1731 WINE_FIXME("\n");
1732 return ERROR_CALL_NOT_IMPLEMENTED;
1735 DWORD __cdecl svcctl_CreateServiceA(
1736 SC_RPC_HANDLE scmanager,
1737 LPCSTR servicename,
1738 LPCSTR displayname,
1739 DWORD desiredaccess,
1740 DWORD service_type,
1741 DWORD start_type,
1742 DWORD error_control,
1743 LPCSTR binarypath,
1744 LPCSTR loadordergroup,
1745 DWORD *tagid,
1746 const BYTE *dependencies,
1747 DWORD depend_size,
1748 LPCSTR startname,
1749 const BYTE *password,
1750 DWORD password_size,
1751 SC_RPC_HANDLE *service)
1753 WINE_FIXME("\n");
1754 return ERROR_CALL_NOT_IMPLEMENTED;
1757 DWORD __cdecl svcctl_EnumDependentServicesA(
1758 SC_RPC_HANDLE service,
1759 DWORD state,
1760 BYTE *services,
1761 DWORD buf_size,
1762 DWORD *needed_size,
1763 DWORD *services_ret)
1765 WINE_FIXME("\n");
1766 return ERROR_CALL_NOT_IMPLEMENTED;
1769 DWORD __cdecl svcctl_EnumServicesStatusA(
1770 SC_RPC_HANDLE hmngr,
1771 DWORD type,
1772 DWORD state,
1773 BYTE *buffer,
1774 DWORD size,
1775 DWORD *needed,
1776 DWORD *returned,
1777 DWORD *resume)
1779 WINE_FIXME("\n");
1780 return ERROR_CALL_NOT_IMPLEMENTED;
1783 DWORD __cdecl svcctl_OpenSCManagerA(
1784 MACHINE_HANDLEA MachineName,
1785 LPCSTR DatabaseName,
1786 DWORD dwAccessMask,
1787 SC_RPC_HANDLE *handle)
1789 WINE_FIXME("\n");
1790 return ERROR_CALL_NOT_IMPLEMENTED;
1793 DWORD __cdecl svcctl_OpenServiceA(
1794 SC_RPC_HANDLE hSCManager,
1795 LPCSTR lpServiceName,
1796 DWORD dwDesiredAccess,
1797 SC_RPC_HANDLE *phService)
1799 WINE_FIXME("\n");
1800 return ERROR_CALL_NOT_IMPLEMENTED;
1803 DWORD __cdecl svcctl_QueryServiceConfigA(
1804 SC_RPC_HANDLE hService,
1805 QUERY_SERVICE_CONFIGA *config,
1806 DWORD buf_size,
1807 DWORD *needed_size)
1809 WINE_FIXME("\n");
1810 return ERROR_CALL_NOT_IMPLEMENTED;
1813 DWORD __cdecl svcctl_QueryServiceLockStatusA(
1814 SC_RPC_HANDLE scmanager,
1815 QUERY_SERVICE_LOCK_STATUSA *status,
1816 DWORD buf_size,
1817 DWORD *needed_size)
1819 WINE_FIXME("\n");
1820 return ERROR_CALL_NOT_IMPLEMENTED;
1823 DWORD __cdecl svcctl_StartServiceA(
1824 SC_RPC_HANDLE service,
1825 DWORD argc,
1826 LPCSTR *args)
1828 WINE_FIXME("\n");
1829 return ERROR_CALL_NOT_IMPLEMENTED;
1832 DWORD __cdecl svcctl_GetServiceDisplayNameA(
1833 SC_RPC_HANDLE hSCManager,
1834 LPCSTR servicename,
1835 CHAR buffer[],
1836 DWORD *buf_size)
1838 WINE_FIXME("\n");
1839 return ERROR_CALL_NOT_IMPLEMENTED;
1842 DWORD __cdecl svcctl_GetServiceKeyNameA(
1843 SC_RPC_HANDLE hSCManager,
1844 LPCSTR servicename,
1845 CHAR buffer[],
1846 DWORD *buf_size)
1848 WINE_FIXME("\n");
1849 return ERROR_CALL_NOT_IMPLEMENTED;
1852 DWORD __cdecl svcctl_GetCurrentGroupStateW(void)
1854 WINE_FIXME("\n");
1855 return ERROR_CALL_NOT_IMPLEMENTED;
1858 DWORD __cdecl svcctl_EnumServiceGroupW(
1859 SC_RPC_HANDLE scmanager,
1860 DWORD service_type,
1861 DWORD service_state,
1862 BYTE *buffer,
1863 DWORD buf_size,
1864 DWORD *needed_size,
1865 DWORD *returned_size,
1866 DWORD *resume_index,
1867 LPCWSTR groupname)
1869 WINE_FIXME("\n");
1870 return ERROR_CALL_NOT_IMPLEMENTED;
1873 DWORD __cdecl svcctl_ChangeServiceConfig2A(
1874 SC_RPC_HANDLE service,
1875 SC_RPC_CONFIG_INFOA info)
1877 WINE_FIXME("\n");
1878 return ERROR_CALL_NOT_IMPLEMENTED;
1881 DWORD __cdecl svcctl_QueryServiceConfig2A(
1882 SC_RPC_HANDLE service,
1883 DWORD info_level,
1884 BYTE *buffer,
1885 DWORD buf_size,
1886 DWORD *needed_size)
1888 WINE_FIXME("\n");
1889 return ERROR_CALL_NOT_IMPLEMENTED;
1892 DWORD RPC_Init(void)
1894 WCHAR transport[] = SVCCTL_TRANSPORT;
1895 WCHAR endpoint[] = SVCCTL_ENDPOINT;
1896 DWORD err;
1898 if ((err = RpcServerUseProtseqEpW(transport, 0, endpoint, NULL)) != ERROR_SUCCESS)
1900 WINE_ERR("RpcServerUseProtseq failed with error %u\n", err);
1901 return err;
1904 if ((err = RpcServerRegisterIf(svcctl_v2_0_s_ifspec, 0, 0)) != ERROR_SUCCESS)
1906 WINE_ERR("RpcServerRegisterIf failed with error %u\n", err);
1907 return err;
1910 if ((err = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE)) != ERROR_SUCCESS)
1912 WINE_ERR("RpcServerListen failed with error %u\n", err);
1913 return err;
1915 return ERROR_SUCCESS;
1918 DWORD events_loop(void)
1920 struct timeout_queue_elem *iter, *iter_safe;
1921 DWORD err;
1922 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
1923 DWORD timeout = INFINITE;
1925 wait_handles[0] = __wine_make_process_system();
1926 wait_handles[1] = CreateEventW(NULL, FALSE, FALSE, NULL);
1927 timeout_queue_event = wait_handles[1];
1929 SetEvent(g_hStartedEvent);
1931 WINE_TRACE("Entered main loop\n");
1935 DWORD num_handles = 2;
1937 /* monitor tracked process handles for process end */
1938 EnterCriticalSection(&timeout_queue_cs);
1939 LIST_FOR_EACH_ENTRY(iter, &timeout_queue, struct timeout_queue_elem, entry)
1941 if(num_handles == MAXIMUM_WAIT_OBJECTS){
1942 WINE_TRACE("Exceeded maximum wait object count\n");
1943 break;
1945 wait_handles[num_handles] = iter->service_entry->process;
1946 num_handles++;
1948 LeaveCriticalSection(&timeout_queue_cs);
1950 err = WaitForMultipleObjects(num_handles, wait_handles, FALSE, timeout);
1951 WINE_TRACE("Wait returned %d\n", err);
1953 if(err > WAIT_OBJECT_0 || err == WAIT_TIMEOUT)
1955 FILETIME cur_time;
1956 ULARGE_INTEGER time;
1957 DWORD idx = 0;
1959 GetSystemTimeAsFileTime(&cur_time);
1960 time.u.LowPart = cur_time.dwLowDateTime;
1961 time.u.HighPart = cur_time.dwHighDateTime;
1963 EnterCriticalSection(&timeout_queue_cs);
1964 timeout = INFINITE;
1965 LIST_FOR_EACH_ENTRY_SAFE(iter, iter_safe, &timeout_queue, struct timeout_queue_elem, entry)
1967 if(CompareFileTime(&cur_time, &iter->time) >= 0 ||
1968 (err > WAIT_OBJECT_0 + 1 && idx == err - WAIT_OBJECT_0 - 2))
1970 LeaveCriticalSection(&timeout_queue_cs);
1971 iter->func(iter->service_entry);
1972 EnterCriticalSection(&timeout_queue_cs);
1974 release_service(iter->service_entry);
1975 list_remove(&iter->entry);
1976 HeapFree(GetProcessHeap(), 0, iter);
1978 else
1980 ULARGE_INTEGER time_diff;
1982 time_diff.u.LowPart = iter->time.dwLowDateTime;
1983 time_diff.u.HighPart = iter->time.dwHighDateTime;
1984 time_diff.QuadPart = (time_diff.QuadPart-time.QuadPart)/10000;
1986 if(time_diff.QuadPart < timeout)
1987 timeout = time_diff.QuadPart;
1989 idx++;
1991 LeaveCriticalSection(&timeout_queue_cs);
1993 if(timeout != INFINITE)
1994 timeout += 1000;
1996 } while (err != WAIT_OBJECT_0);
1998 WINE_TRACE("Object signaled - wine shutdown\n");
1999 EnterCriticalSection(&timeout_queue_cs);
2000 LIST_FOR_EACH_ENTRY_SAFE(iter, iter_safe, &timeout_queue, struct timeout_queue_elem, entry)
2002 LeaveCriticalSection(&timeout_queue_cs);
2003 iter->func(iter->service_entry);
2004 EnterCriticalSection(&timeout_queue_cs);
2006 release_service(iter->service_entry);
2007 list_remove(&iter->entry);
2008 HeapFree(GetProcessHeap(), 0, iter);
2010 LeaveCriticalSection(&timeout_queue_cs);
2012 CloseHandle(wait_handles[0]);
2013 CloseHandle(wait_handles[1]);
2014 return ERROR_SUCCESS;
2017 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE handle)
2019 SC_RPC_HANDLE_destroy(handle);
2022 void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE handle)
2026 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
2028 return HeapAlloc(GetProcessHeap(), 0, len);
2031 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
2033 HeapFree(GetProcessHeap(), 0, ptr);