device.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /*
  2. * Service process to load a kernel driver
  3. *
  4. * Copyright 2007 Alexandre Julliard
  5. * Copyright 2016 Sebastian Lackner
  6. *
  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.
  11. *
  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.
  16. *
  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
  20. */
  21. #include <stdarg.h>
  22. #include "ntstatus.h"
  23. #define WIN32_NO_STATUS
  24. #include "windef.h"
  25. #include "winternl.h"
  26. #include "ddk/wdm.h"
  27. #include "wine/svcctl.h"
  28. #include "wine/debug.h"
  29. #include "wine/heap.h"
  30. WINE_DEFAULT_DEBUG_CHANNEL(winedevice);
  31. static const WCHAR servicesW[] = {'\\','R','e','g','i','s','t','r','y',
  32. '\\','M','a','c','h','i','n','e',
  33. '\\','S','y','s','t','e','m',
  34. '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
  35. '\\','S','e','r','v','i','c','e','s',
  36. '\\',0};
  37. extern NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event );
  38. static const WCHAR winedeviceW[] = {'w','i','n','e','d','e','v','i','c','e',0};
  39. static SERVICE_STATUS_HANDLE service_handle;
  40. static SC_HANDLE manager_handle;
  41. static HANDLE stop_event;
  42. /* helper function to update service status */
  43. static void set_service_status( SERVICE_STATUS_HANDLE handle, DWORD state, DWORD accepted )
  44. {
  45. SERVICE_STATUS status;
  46. status.dwServiceType = SERVICE_WIN32;
  47. status.dwCurrentState = state;
  48. status.dwControlsAccepted = accepted;
  49. status.dwWin32ExitCode = 0;
  50. status.dwServiceSpecificExitCode = 0;
  51. status.dwCheckPoint = 0;
  52. status.dwWaitHint = (state == SERVICE_START_PENDING) ? 10000 : 0;
  53. SetServiceStatus( handle, &status );
  54. }
  55. static DWORD device_handler( DWORD ctrl, const WCHAR *driver_name )
  56. {
  57. UNICODE_STRING service_name;
  58. DWORD result = NO_ERROR;
  59. WCHAR *str;
  60. if (!(str = heap_alloc( sizeof(servicesW) + lstrlenW(driver_name)*sizeof(WCHAR) )))
  61. return STATUS_NO_MEMORY;
  62. lstrcpyW( str, servicesW );
  63. lstrcatW( str, driver_name );
  64. RtlInitUnicodeString( &service_name, str );
  65. switch (ctrl)
  66. {
  67. case SERVICE_CONTROL_START:
  68. result = RtlNtStatusToDosError(ZwLoadDriver( &service_name ));
  69. break;
  70. case SERVICE_CONTROL_STOP:
  71. result = RtlNtStatusToDosError(ZwUnloadDriver( &service_name ));
  72. break;
  73. default:
  74. FIXME( "got driver ctrl %x for %s\n", ctrl, wine_dbgstr_w(driver_name) );
  75. break;
  76. }
  77. RtlFreeUnicodeString( &service_name );
  78. return result;
  79. }
  80. static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context )
  81. {
  82. const WCHAR *service_group = context;
  83. if (ctrl & SERVICE_CONTROL_FORWARD_FLAG)
  84. {
  85. if (!event_data) return ERROR_INVALID_PARAMETER;
  86. return device_handler( ctrl & ~SERVICE_CONTROL_FORWARD_FLAG, (const WCHAR *)event_data );
  87. }
  88. switch (ctrl)
  89. {
  90. case SERVICE_CONTROL_STOP:
  91. case SERVICE_CONTROL_SHUTDOWN:
  92. TRACE( "shutting down %s\n", wine_dbgstr_w(service_group) );
  93. set_service_status( service_handle, SERVICE_STOP_PENDING, 0 );
  94. SetEvent( stop_event );
  95. return NO_ERROR;
  96. default:
  97. FIXME( "got service ctrl %x for %s\n", ctrl, wine_dbgstr_w(service_group) );
  98. set_service_status( service_handle, SERVICE_RUNNING,
  99. SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN );
  100. return NO_ERROR;
  101. }
  102. }
  103. static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv )
  104. {
  105. const WCHAR *service_group = (argc >= 2) ? argv[1] : argv[0];
  106. if (!(stop_event = CreateEventW( NULL, TRUE, FALSE, NULL )))
  107. return;
  108. if (!(manager_handle = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
  109. return;
  110. if (!(service_handle = RegisterServiceCtrlHandlerExW( winedeviceW, service_handler, (void *)service_group )))
  111. return;
  112. TRACE( "starting service group %s\n", wine_dbgstr_w(service_group) );
  113. set_service_status( service_handle, SERVICE_RUNNING,
  114. SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN );
  115. wine_ntoskrnl_main_loop( stop_event );
  116. TRACE( "service group %s stopped\n", wine_dbgstr_w(service_group) );
  117. set_service_status( service_handle, SERVICE_STOPPED, 0 );
  118. CloseServiceHandle( manager_handle );
  119. CloseHandle( stop_event );
  120. }
  121. int __cdecl wmain( int argc, WCHAR *argv[] )
  122. {
  123. SERVICE_TABLE_ENTRYW service_table[2];
  124. service_table[0].lpServiceName = (void *)winedeviceW;
  125. service_table[0].lpServiceProc = ServiceMain;
  126. service_table[1].lpServiceName = NULL;
  127. service_table[1].lpServiceProc = NULL;
  128. StartServiceCtrlDispatcherW( service_table );
  129. return 0;
  130. }