po: Fixed typos in French translation.
[wine.git] / programs / plugplay / main.c
blob1156cb9f03624eb62803709657e30e62dc72cde2
1 /*
2 * Copyright 2011 Hans Leidekker for CodeWeavers
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.
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.
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
19 #define WIN32_LEAN_AND_MEAN
21 #include <windows.h>
22 #include <dbt.h>
23 #include "winsvc.h"
24 #include "wine/debug.h"
25 #include "wine/list.h"
26 #include "plugplay.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
30 static WCHAR plugplayW[] = L"PlugPlay";
32 static SERVICE_STATUS_HANDLE service_handle;
33 static HANDLE stop_event;
35 void __RPC_FAR * __RPC_USER MIDL_user_allocate( SIZE_T len )
37 return malloc( len );
40 void __RPC_USER MIDL_user_free( void __RPC_FAR *ptr )
42 free( ptr );
45 static CRITICAL_SECTION plugplay_cs;
46 static CRITICAL_SECTION_DEBUG plugplay_cs_debug =
48 0, 0, &plugplay_cs,
49 { &plugplay_cs_debug.ProcessLocksList, &plugplay_cs_debug.ProcessLocksList },
50 0, 0, { (DWORD_PTR)(__FILE__ ": plugplay_cs") }
52 static CRITICAL_SECTION plugplay_cs = { &plugplay_cs_debug, -1, 0, 0, 0, 0 };
54 static struct list listener_list = LIST_INIT(listener_list);
56 struct listener
58 struct list entry;
59 struct list events;
60 CONDITION_VARIABLE cv;
63 struct event
65 struct list entry;
66 DWORD code;
67 BYTE *data;
68 unsigned int size;
72 static void destroy_listener( struct listener *listener )
74 struct event *event, *next;
76 EnterCriticalSection( &plugplay_cs );
77 list_remove( &listener->entry );
78 LeaveCriticalSection( &plugplay_cs );
80 LIST_FOR_EACH_ENTRY_SAFE(event, next, &listener->events, struct event, entry)
82 MIDL_user_free( event->data );
83 list_remove( &event->entry );
84 free( event );
86 free( listener );
89 void __RPC_USER plugplay_rpc_handle_rundown( plugplay_rpc_handle handle )
91 destroy_listener( handle );
94 plugplay_rpc_handle __cdecl plugplay_register_listener(void)
96 struct listener *listener;
98 if (!(listener = calloc( 1, sizeof(*listener) )))
99 return NULL;
101 list_init( &listener->events );
102 InitializeConditionVariable( &listener->cv );
104 EnterCriticalSection( &plugplay_cs );
105 list_add_tail( &listener_list, &listener->entry );
106 LeaveCriticalSection( &plugplay_cs );
108 return listener;
111 DWORD __cdecl plugplay_get_event( plugplay_rpc_handle handle, BYTE **data, unsigned int *size )
113 struct listener *listener = handle;
114 struct event *event;
115 struct list *entry;
116 DWORD ret;
118 EnterCriticalSection( &plugplay_cs );
120 while (!(entry = list_head( &listener->events )))
121 SleepConditionVariableCS( &listener->cv, &plugplay_cs, INFINITE );
123 event = LIST_ENTRY(entry, struct event, entry);
124 list_remove( &event->entry );
126 LeaveCriticalSection( &plugplay_cs );
128 ret = event->code;
129 *data = event->data;
130 *size = event->size;
131 free( event );
132 return ret;
135 void __cdecl plugplay_unregister_listener( plugplay_rpc_handle handle )
137 destroy_listener( handle );
140 void __cdecl plugplay_send_event( DWORD code, const BYTE *data, unsigned int size )
142 struct listener *listener;
143 struct event *event;
145 BroadcastSystemMessageW( 0, NULL, WM_DEVICECHANGE, code, (LPARAM)data );
146 BroadcastSystemMessageW( 0, NULL, WM_DEVICECHANGE, DBT_DEVNODES_CHANGED, 0 );
148 EnterCriticalSection( &plugplay_cs );
150 LIST_FOR_EACH_ENTRY(listener, &listener_list, struct listener, entry)
152 if (!(event = malloc( sizeof(*event) )))
153 break;
155 if (!(event->data = malloc( size )))
157 free( event );
158 break;
161 event->code = code;
162 memcpy( event->data, data, size );
163 event->size = size;
164 list_add_tail( &listener->events, &event->entry );
165 WakeConditionVariable( &listener->cv );
168 LeaveCriticalSection( &plugplay_cs );
171 static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context )
173 SERVICE_STATUS status;
175 status.dwServiceType = SERVICE_WIN32;
176 status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
177 status.dwWin32ExitCode = 0;
178 status.dwServiceSpecificExitCode = 0;
179 status.dwCheckPoint = 0;
180 status.dwWaitHint = 0;
182 switch(ctrl)
184 case SERVICE_CONTROL_STOP:
185 case SERVICE_CONTROL_SHUTDOWN:
186 WINE_TRACE( "shutting down\n" );
187 status.dwCurrentState = SERVICE_STOP_PENDING;
188 status.dwControlsAccepted = 0;
189 SetServiceStatus( service_handle, &status );
190 SetEvent( stop_event );
191 return NO_ERROR;
192 default:
193 WINE_FIXME( "got service ctrl %x\n", ctrl );
194 status.dwCurrentState = SERVICE_RUNNING;
195 SetServiceStatus( service_handle, &status );
196 return NO_ERROR;
200 static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
202 unsigned char endpoint[] = "\\pipe\\wine_plugplay";
203 unsigned char protseq[] = "ncalrpc";
204 SERVICE_STATUS status;
205 RPC_STATUS err;
207 WINE_TRACE( "starting service\n" );
209 if ((err = RpcServerUseProtseqEpA( protseq, 0, endpoint, NULL )))
211 ERR("RpcServerUseProtseqEp() failed, error %u\n", err);
212 return;
214 if ((err = RpcServerRegisterIf( plugplay_v0_0_s_ifspec, NULL, NULL )))
216 ERR("RpcServerRegisterIf() failed, error %u\n", err);
217 return;
219 if ((err = RpcServerListen( 1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE )))
221 ERR("RpcServerListen() failed, error %u\n", err);
222 return;
225 stop_event = CreateEventW( NULL, TRUE, FALSE, NULL );
227 service_handle = RegisterServiceCtrlHandlerExW( plugplayW, service_handler, NULL );
228 if (!service_handle)
229 return;
231 status.dwServiceType = SERVICE_WIN32;
232 status.dwCurrentState = SERVICE_RUNNING;
233 status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
234 status.dwWin32ExitCode = 0;
235 status.dwServiceSpecificExitCode = 0;
236 status.dwCheckPoint = 0;
237 status.dwWaitHint = 10000;
238 SetServiceStatus( service_handle, &status );
240 WaitForSingleObject( stop_event, INFINITE );
242 RpcMgmtStopServerListening( NULL );
243 RpcServerUnregisterIf( plugplay_v0_0_s_ifspec, NULL, TRUE );
244 RpcMgmtWaitServerListen();
246 status.dwCurrentState = SERVICE_STOPPED;
247 status.dwControlsAccepted = 0;
248 SetServiceStatus( service_handle, &status );
249 WINE_TRACE( "service stopped\n" );
252 int __cdecl wmain( int argc, WCHAR *argv[] )
254 static const SERVICE_TABLE_ENTRYW service_table[] =
256 { plugplayW, ServiceMain },
257 { NULL, NULL }
260 StartServiceCtrlDispatcherW( service_table );
261 return 0;