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
24 #include "wine/debug.h"
25 #include "wine/list.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
)
40 void __RPC_USER
MIDL_user_free( void __RPC_FAR
*ptr
)
45 static CRITICAL_SECTION plugplay_cs
;
46 static CRITICAL_SECTION_DEBUG plugplay_cs_debug
=
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
);
60 CONDITION_VARIABLE cv
;
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
);
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
) )))
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
);
111 DWORD __cdecl
plugplay_get_event( plugplay_rpc_handle handle
, BYTE
**data
, unsigned int *size
)
113 struct listener
*listener
= handle
;
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
);
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
;
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
) )))
155 if (!(event
->data
= malloc( size
)))
162 memcpy( event
->data
, data
, 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;
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
);
193 WINE_FIXME( "got service ctrl %lx\n", ctrl
);
194 status
.dwCurrentState
= SERVICE_RUNNING
;
195 SetServiceStatus( service_handle
, &status
);
200 static void WINAPI
ServiceMain( DWORD argc
, LPWSTR
*argv
)
202 unsigned char endpoint
[] = "\\pipe\\wine_plugplay";
203 unsigned char protseq
[] = "ncacn_np";
204 SERVICE_STATUS status
;
207 WINE_TRACE( "starting service\n" );
209 if ((err
= RpcServerUseProtseqEpA( protseq
, 0, endpoint
, NULL
)))
211 ERR("RpcServerUseProtseqEp() failed, error %lu\n", err
);
214 if ((err
= RpcServerRegisterIf( plugplay_v0_0_s_ifspec
, NULL
, NULL
)))
216 ERR("RpcServerRegisterIf() failed, error %lu\n", err
);
219 if ((err
= RpcServerListen( 1, RPC_C_LISTEN_MAX_CALLS_DEFAULT
, TRUE
)))
221 ERR("RpcServerListen() failed, error %lu\n", err
);
225 stop_event
= CreateEventW( NULL
, TRUE
, FALSE
, NULL
);
227 service_handle
= RegisterServiceCtrlHandlerExW( plugplayW
, service_handler
, NULL
);
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
},
260 StartServiceCtrlDispatcherW( service_table
);