main.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  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. #define WIN32_LEAN_AND_MEAN
  19. #include <windows.h>
  20. #include <dbt.h>
  21. #include "winsvc.h"
  22. #include "wine/debug.h"
  23. #include "wine/list.h"
  24. #include "plugplay.h"
  25. WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
  26. static WCHAR plugplayW[] = L"PlugPlay";
  27. static SERVICE_STATUS_HANDLE service_handle;
  28. static HANDLE stop_event;
  29. void __RPC_FAR * __RPC_USER MIDL_user_allocate( SIZE_T len )
  30. {
  31. return malloc( len );
  32. }
  33. void __RPC_USER MIDL_user_free( void __RPC_FAR *ptr )
  34. {
  35. free( ptr );
  36. }
  37. static CRITICAL_SECTION plugplay_cs;
  38. static CRITICAL_SECTION_DEBUG plugplay_cs_debug =
  39. {
  40. 0, 0, &plugplay_cs,
  41. { &plugplay_cs_debug.ProcessLocksList, &plugplay_cs_debug.ProcessLocksList },
  42. 0, 0, { (DWORD_PTR)(__FILE__ ": plugplay_cs") }
  43. };
  44. static CRITICAL_SECTION plugplay_cs = { &plugplay_cs_debug, -1, 0, 0, 0, 0 };
  45. static struct list listener_list = LIST_INIT(listener_list);
  46. struct listener
  47. {
  48. struct list entry;
  49. struct list events;
  50. CONDITION_VARIABLE cv;
  51. };
  52. struct event
  53. {
  54. struct list entry;
  55. DWORD code;
  56. BYTE *data;
  57. unsigned int size;
  58. };
  59. static void destroy_listener( struct listener *listener )
  60. {
  61. struct event *event, *next;
  62. EnterCriticalSection( &plugplay_cs );
  63. list_remove( &listener->entry );
  64. LeaveCriticalSection( &plugplay_cs );
  65. LIST_FOR_EACH_ENTRY_SAFE(event, next, &listener->events, struct event, entry)
  66. {
  67. MIDL_user_free( event->data );
  68. list_remove( &event->entry );
  69. free( event );
  70. }
  71. free( listener );
  72. }
  73. void __RPC_USER plugplay_rpc_handle_rundown( plugplay_rpc_handle handle )
  74. {
  75. destroy_listener( handle );
  76. }
  77. plugplay_rpc_handle __cdecl plugplay_register_listener(void)
  78. {
  79. struct listener *listener;
  80. if (!(listener = calloc( 1, sizeof(*listener) )))
  81. return NULL;
  82. list_init( &listener->events );
  83. InitializeConditionVariable( &listener->cv );
  84. EnterCriticalSection( &plugplay_cs );
  85. list_add_tail( &listener_list, &listener->entry );
  86. LeaveCriticalSection( &plugplay_cs );
  87. return listener;
  88. }
  89. DWORD __cdecl plugplay_get_event( plugplay_rpc_handle handle, BYTE **data, unsigned int *size )
  90. {
  91. struct listener *listener = handle;
  92. struct event *event;
  93. struct list *entry;
  94. DWORD ret;
  95. EnterCriticalSection( &plugplay_cs );
  96. while (!(entry = list_head( &listener->events )))
  97. SleepConditionVariableCS( &listener->cv, &plugplay_cs, INFINITE );
  98. event = LIST_ENTRY(entry, struct event, entry);
  99. list_remove( &event->entry );
  100. LeaveCriticalSection( &plugplay_cs );
  101. ret = event->code;
  102. *data = event->data;
  103. *size = event->size;
  104. free( event );
  105. return ret;
  106. }
  107. void __cdecl plugplay_unregister_listener( plugplay_rpc_handle handle )
  108. {
  109. destroy_listener( handle );
  110. }
  111. void __cdecl plugplay_send_event( DWORD code, const BYTE *data, unsigned int size )
  112. {
  113. struct listener *listener;
  114. struct event *event;
  115. BroadcastSystemMessageW( 0, NULL, WM_DEVICECHANGE, code, (LPARAM)data );
  116. BroadcastSystemMessageW( 0, NULL, WM_DEVICECHANGE, DBT_DEVNODES_CHANGED, 0 );
  117. EnterCriticalSection( &plugplay_cs );
  118. LIST_FOR_EACH_ENTRY(listener, &listener_list, struct listener, entry)
  119. {
  120. if (!(event = malloc( sizeof(*event) )))
  121. break;
  122. if (!(event->data = malloc( size )))
  123. {
  124. free( event );
  125. break;
  126. }
  127. event->code = code;
  128. memcpy( event->data, data, size );
  129. event->size = size;
  130. list_add_tail( &listener->events, &event->entry );
  131. WakeConditionVariable( &listener->cv );
  132. }
  133. LeaveCriticalSection( &plugplay_cs );
  134. }
  135. static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context )
  136. {
  137. SERVICE_STATUS status;
  138. status.dwServiceType = SERVICE_WIN32;
  139. status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  140. status.dwWin32ExitCode = 0;
  141. status.dwServiceSpecificExitCode = 0;
  142. status.dwCheckPoint = 0;
  143. status.dwWaitHint = 0;
  144. switch(ctrl)
  145. {
  146. case SERVICE_CONTROL_STOP:
  147. case SERVICE_CONTROL_SHUTDOWN:
  148. WINE_TRACE( "shutting down\n" );
  149. status.dwCurrentState = SERVICE_STOP_PENDING;
  150. status.dwControlsAccepted = 0;
  151. SetServiceStatus( service_handle, &status );
  152. SetEvent( stop_event );
  153. return NO_ERROR;
  154. default:
  155. WINE_FIXME( "got service ctrl %x\n", ctrl );
  156. status.dwCurrentState = SERVICE_RUNNING;
  157. SetServiceStatus( service_handle, &status );
  158. return NO_ERROR;
  159. }
  160. }
  161. static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
  162. {
  163. unsigned char endpoint[] = "\\pipe\\wine_plugplay";
  164. unsigned char protseq[] = "ncalrpc";
  165. SERVICE_STATUS status;
  166. RPC_STATUS err;
  167. WINE_TRACE( "starting service\n" );
  168. if ((err = RpcServerUseProtseqEpA( protseq, 0, endpoint, NULL )))
  169. {
  170. ERR("RpcServerUseProtseqEp() failed, error %u\n", err);
  171. return;
  172. }
  173. if ((err = RpcServerRegisterIf( plugplay_v0_0_s_ifspec, NULL, NULL )))
  174. {
  175. ERR("RpcServerRegisterIf() failed, error %u\n", err);
  176. return;
  177. }
  178. if ((err = RpcServerListen( 1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE )))
  179. {
  180. ERR("RpcServerListen() failed, error %u\n", err);
  181. return;
  182. }
  183. stop_event = CreateEventW( NULL, TRUE, FALSE, NULL );
  184. service_handle = RegisterServiceCtrlHandlerExW( plugplayW, service_handler, NULL );
  185. if (!service_handle)
  186. return;
  187. status.dwServiceType = SERVICE_WIN32;
  188. status.dwCurrentState = SERVICE_RUNNING;
  189. status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
  190. status.dwWin32ExitCode = 0;
  191. status.dwServiceSpecificExitCode = 0;
  192. status.dwCheckPoint = 0;
  193. status.dwWaitHint = 10000;
  194. SetServiceStatus( service_handle, &status );
  195. WaitForSingleObject( stop_event, INFINITE );
  196. RpcMgmtStopServerListening( NULL );
  197. RpcServerUnregisterIf( plugplay_v0_0_s_ifspec, NULL, TRUE );
  198. RpcMgmtWaitServerListen();
  199. status.dwCurrentState = SERVICE_STOPPED;
  200. status.dwControlsAccepted = 0;
  201. SetServiceStatus( service_handle, &status );
  202. WINE_TRACE( "service stopped\n" );
  203. }
  204. int __cdecl wmain( int argc, WCHAR *argv[] )
  205. {
  206. static const SERVICE_TABLE_ENTRYW service_table[] =
  207. {
  208. { plugplayW, ServiceMain },
  209. { NULL, NULL }
  210. };
  211. StartServiceCtrlDispatcherW( service_table );
  212. return 0;
  213. }