mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / programs / winedevice / device.c
blob07a76b911e9dcc51794c55fa0f8da1d71a63bbfb
1 /*
2 * Service process to load a kernel driver
4 * Copyright 2007 Alexandre Julliard
5 * Copyright 2016 Sebastian Lackner
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
24 #include "ntstatus.h"
25 #define WIN32_NO_STATUS
26 #include "windef.h"
27 #include "winternl.h"
28 #include "ddk/wdm.h"
29 #include "wine/svcctl.h"
30 #include "wine/debug.h"
31 #include "wine/heap.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(winedevice);
35 static const WCHAR servicesW[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
37 extern NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event );
38 extern void CDECL wine_enumerate_root_devices( const WCHAR *driver_name );
40 static WCHAR winedeviceW[] = L"winedevice";
41 static SERVICE_STATUS_HANDLE service_handle;
42 static SC_HANDLE manager_handle;
43 static HANDLE stop_event;
45 /* helper function to update service status */
46 static void set_service_status( SERVICE_STATUS_HANDLE handle, DWORD state, DWORD accepted )
48 SERVICE_STATUS status;
49 status.dwServiceType = SERVICE_WIN32;
50 status.dwCurrentState = state;
51 status.dwControlsAccepted = accepted;
52 status.dwWin32ExitCode = 0;
53 status.dwServiceSpecificExitCode = 0;
54 status.dwCheckPoint = 0;
55 status.dwWaitHint = (state == SERVICE_START_PENDING) ? 10000 : 0;
56 SetServiceStatus( handle, &status );
59 #define SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES 128
61 static DWORD device_handler( DWORD ctrl, const WCHAR *driver_name )
63 UNICODE_STRING service_name;
64 DWORD result = NO_ERROR;
65 WCHAR *str;
67 if (!(str = heap_alloc( sizeof(servicesW) + lstrlenW(driver_name)*sizeof(WCHAR) )))
68 return STATUS_NO_MEMORY;
70 lstrcpyW( str, servicesW );
71 lstrcatW( str, driver_name );
72 RtlInitUnicodeString( &service_name, str );
74 switch (ctrl)
76 case SERVICE_CONTROL_START:
77 result = RtlNtStatusToDosError(ZwLoadDriver( &service_name ));
78 break;
80 case SERVICE_CONTROL_STOP:
81 result = RtlNtStatusToDosError(ZwUnloadDriver( &service_name ));
82 break;
84 case SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES:
85 wine_enumerate_root_devices( driver_name );
86 break;
88 default:
89 FIXME( "got driver ctrl %x for %s\n", ctrl, wine_dbgstr_w(driver_name) );
90 break;
93 RtlFreeUnicodeString( &service_name );
94 return result;
97 static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context )
99 const WCHAR *service_group = context;
101 if (ctrl & SERVICE_CONTROL_FORWARD_FLAG)
103 if (!event_data) return ERROR_INVALID_PARAMETER;
104 return device_handler( ctrl & ~SERVICE_CONTROL_FORWARD_FLAG, (const WCHAR *)event_data );
107 switch (ctrl)
109 case SERVICE_CONTROL_STOP:
110 case SERVICE_CONTROL_SHUTDOWN:
111 TRACE( "shutting down %s\n", wine_dbgstr_w(service_group) );
112 set_service_status( service_handle, SERVICE_STOP_PENDING, 0 );
113 SetEvent( stop_event );
114 return NO_ERROR;
115 default:
116 FIXME( "got service ctrl %x for %s\n", ctrl, wine_dbgstr_w(service_group) );
117 set_service_status( service_handle, SERVICE_RUNNING,
118 SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN );
119 return NO_ERROR;
123 static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
125 WCHAR driver_dir[MAX_PATH];
126 const WCHAR *service_group = (argc >= 2) ? argv[1] : argv[0];
128 if (!(stop_event = CreateEventW( NULL, TRUE, FALSE, NULL )))
129 return;
130 if (!(manager_handle = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
131 return;
132 if (!(service_handle = RegisterServiceCtrlHandlerExW( winedeviceW, service_handler, (void *)service_group )))
133 return;
135 GetSystemDirectoryW( driver_dir, MAX_PATH );
136 wcscat( driver_dir, L"\\drivers" );
137 AddDllDirectory( driver_dir );
139 TRACE( "starting service group %s\n", wine_dbgstr_w(service_group) );
140 set_service_status( service_handle, SERVICE_RUNNING,
141 SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN );
143 wine_ntoskrnl_main_loop( stop_event );
145 TRACE( "service group %s stopped\n", wine_dbgstr_w(service_group) );
146 set_service_status( service_handle, SERVICE_STOPPED, 0 );
147 CloseServiceHandle( manager_handle );
148 CloseHandle( stop_event );
151 int __cdecl wmain( int argc, WCHAR *argv[] )
153 SERVICE_TABLE_ENTRYW service_table[2];
155 service_table[0].lpServiceName = winedeviceW;
156 service_table[0].lpServiceProc = ServiceMain;
157 service_table[1].lpServiceName = NULL;
158 service_table[1].lpServiceProc = NULL;
160 StartServiceCtrlDispatcherW( service_table );
161 return 0;