Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/programs/plugplay/main.c
4388 views
1
/*
2
* Copyright 2011 Hans Leidekker 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
19
#define WIN32_LEAN_AND_MEAN
20
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"
27
28
WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
29
30
static WCHAR plugplayW[] = L"PlugPlay";
31
32
static SERVICE_STATUS_HANDLE service_handle;
33
static HANDLE stop_event;
34
35
void __RPC_FAR * __RPC_USER MIDL_user_allocate( SIZE_T len )
36
{
37
return malloc( len );
38
}
39
40
void __RPC_USER MIDL_user_free( void __RPC_FAR *ptr )
41
{
42
free( ptr );
43
}
44
45
static CRITICAL_SECTION plugplay_cs;
46
static CRITICAL_SECTION_DEBUG plugplay_cs_debug =
47
{
48
0, 0, &plugplay_cs,
49
{ &plugplay_cs_debug.ProcessLocksList, &plugplay_cs_debug.ProcessLocksList },
50
0, 0, { (DWORD_PTR)(__FILE__ ": plugplay_cs") }
51
};
52
static CRITICAL_SECTION plugplay_cs = { &plugplay_cs_debug, -1, 0, 0, 0, 0 };
53
54
static struct list listener_list = LIST_INIT(listener_list);
55
56
struct listener
57
{
58
struct list entry;
59
struct list events;
60
CONDITION_VARIABLE cv;
61
};
62
63
struct event
64
{
65
struct list entry;
66
DWORD code;
67
BYTE *data;
68
WCHAR *path;
69
unsigned int size;
70
};
71
72
73
static void destroy_listener( struct listener *listener )
74
{
75
struct event *event, *next;
76
77
EnterCriticalSection( &plugplay_cs );
78
list_remove( &listener->entry );
79
LeaveCriticalSection( &plugplay_cs );
80
81
LIST_FOR_EACH_ENTRY_SAFE(event, next, &listener->events, struct event, entry)
82
{
83
MIDL_user_free( event->data );
84
list_remove( &event->entry );
85
free( event );
86
}
87
free( listener );
88
}
89
90
void __RPC_USER plugplay_rpc_handle_rundown( plugplay_rpc_handle handle )
91
{
92
destroy_listener( handle );
93
}
94
95
plugplay_rpc_handle __cdecl plugplay_register_listener(void)
96
{
97
struct listener *listener;
98
99
if (!(listener = calloc( 1, sizeof(*listener) )))
100
return NULL;
101
102
list_init( &listener->events );
103
InitializeConditionVariable( &listener->cv );
104
105
EnterCriticalSection( &plugplay_cs );
106
list_add_tail( &listener_list, &listener->entry );
107
LeaveCriticalSection( &plugplay_cs );
108
109
return listener;
110
}
111
112
DWORD __cdecl plugplay_get_event( plugplay_rpc_handle handle, WCHAR **path, BYTE **data, unsigned int *size )
113
{
114
struct listener *listener = handle;
115
struct event *event;
116
struct list *entry;
117
DWORD ret;
118
119
EnterCriticalSection( &plugplay_cs );
120
121
while (!(entry = list_head( &listener->events )))
122
SleepConditionVariableCS( &listener->cv, &plugplay_cs, INFINITE );
123
124
event = LIST_ENTRY(entry, struct event, entry);
125
list_remove( &event->entry );
126
127
LeaveCriticalSection( &plugplay_cs );
128
129
ret = event->code;
130
*path = event->path;
131
*data = event->data;
132
*size = event->size;
133
free( event );
134
return ret;
135
}
136
137
void __cdecl plugplay_unregister_listener( plugplay_rpc_handle handle )
138
{
139
destroy_listener( handle );
140
}
141
142
void __cdecl plugplay_send_event( const WCHAR *path, DWORD code, const BYTE *data, unsigned int size )
143
{
144
struct listener *listener;
145
struct event *event;
146
const DEV_BROADCAST_HDR *header = (const DEV_BROADCAST_HDR *)data;
147
148
if (header->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
149
{
150
BroadcastSystemMessageW( 0, NULL, WM_DEVICECHANGE, code, (LPARAM)data );
151
BroadcastSystemMessageW( 0, NULL, WM_DEVICECHANGE, DBT_DEVNODES_CHANGED, 0 );
152
}
153
154
EnterCriticalSection( &plugplay_cs );
155
156
LIST_FOR_EACH_ENTRY(listener, &listener_list, struct listener, entry)
157
{
158
if (!(event = malloc( sizeof(*event) )))
159
break;
160
161
if (!(event->data = malloc( size )))
162
{
163
free( event );
164
break;
165
}
166
167
event->path = wcsdup( path );
168
event->code = code;
169
memcpy( event->data, data, size );
170
event->size = size;
171
list_add_tail( &listener->events, &event->entry );
172
WakeConditionVariable( &listener->cv );
173
}
174
175
LeaveCriticalSection( &plugplay_cs );
176
}
177
178
static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context )
179
{
180
SERVICE_STATUS status;
181
182
status.dwServiceType = SERVICE_WIN32;
183
status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
184
status.dwWin32ExitCode = 0;
185
status.dwServiceSpecificExitCode = 0;
186
status.dwCheckPoint = 0;
187
status.dwWaitHint = 0;
188
189
switch(ctrl)
190
{
191
case SERVICE_CONTROL_STOP:
192
case SERVICE_CONTROL_SHUTDOWN:
193
WINE_TRACE( "shutting down\n" );
194
status.dwCurrentState = SERVICE_STOP_PENDING;
195
status.dwControlsAccepted = 0;
196
SetServiceStatus( service_handle, &status );
197
SetEvent( stop_event );
198
return NO_ERROR;
199
default:
200
WINE_FIXME( "got service ctrl %lx\n", ctrl );
201
status.dwCurrentState = SERVICE_RUNNING;
202
SetServiceStatus( service_handle, &status );
203
return NO_ERROR;
204
}
205
}
206
207
static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
208
{
209
unsigned char endpoint[] = "\\pipe\\wine_plugplay";
210
unsigned char protseq[] = "ncacn_np";
211
SERVICE_STATUS status;
212
RPC_STATUS err;
213
214
WINE_TRACE( "starting service\n" );
215
216
if ((err = RpcServerUseProtseqEpA( protseq, 0, endpoint, NULL )))
217
{
218
ERR("RpcServerUseProtseqEp() failed, error %lu\n", err);
219
return;
220
}
221
if ((err = RpcServerRegisterIf( plugplay_v0_0_s_ifspec, NULL, NULL )))
222
{
223
ERR("RpcServerRegisterIf() failed, error %lu\n", err);
224
return;
225
}
226
if ((err = RpcServerListen( 1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE )))
227
{
228
ERR("RpcServerListen() failed, error %lu\n", err);
229
return;
230
}
231
232
stop_event = CreateEventW( NULL, TRUE, FALSE, NULL );
233
234
service_handle = RegisterServiceCtrlHandlerExW( plugplayW, service_handler, NULL );
235
if (!service_handle)
236
return;
237
238
status.dwServiceType = SERVICE_WIN32;
239
status.dwCurrentState = SERVICE_RUNNING;
240
status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
241
status.dwWin32ExitCode = 0;
242
status.dwServiceSpecificExitCode = 0;
243
status.dwCheckPoint = 0;
244
status.dwWaitHint = 10000;
245
SetServiceStatus( service_handle, &status );
246
247
WaitForSingleObject( stop_event, INFINITE );
248
249
RpcMgmtStopServerListening( NULL );
250
RpcServerUnregisterIf( plugplay_v0_0_s_ifspec, NULL, TRUE );
251
RpcMgmtWaitServerListen();
252
253
status.dwCurrentState = SERVICE_STOPPED;
254
status.dwControlsAccepted = 0;
255
SetServiceStatus( service_handle, &status );
256
WINE_TRACE( "service stopped\n" );
257
}
258
259
int __cdecl wmain( int argc, WCHAR *argv[] )
260
{
261
static const SERVICE_TABLE_ENTRYW service_table[] =
262
{
263
{ plugplayW, ServiceMain },
264
{ NULL, NULL }
265
};
266
267
StartServiceCtrlDispatcherW( service_table );
268
return 0;
269
}
270
271