ntservice.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:12k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * ntservice.c: Windows NT/2K/XP service interface
  3.  *****************************************************************************
  4.  * Copyright (C) 2004 the VideoLAN team
  5.  * $Id: 62b097b23337b246ee82f957e4b1df7a00a02af4 $
  6.  *
  7.  * Authors: Gildas Bazin <gbazin@videolan.org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif
  29. #include <vlc_common.h>
  30. #include <vlc_plugin.h>
  31. #include <vlc_interface.h>
  32. #define VLCSERVICENAME "VLC media player"
  33. /*****************************************************************************
  34.  * Module descriptor
  35.  *****************************************************************************/
  36. static int  Activate( vlc_object_t * );
  37. static void Close   ( vlc_object_t * );
  38. #define INSTALL_TEXT N_( "Install Windows Service" )
  39. #define INSTALL_LONGTEXT N_( 
  40.     "Install the Service and exit." )
  41. #define UNINSTALL_TEXT N_( "Uninstall Windows Service" )
  42. #define UNINSTALL_LONGTEXT N_( 
  43.     "Uninstall the Service and exit." )
  44. #define NAME_TEXT N_( "Display name of the Service" )
  45. #define NAME_LONGTEXT N_( 
  46.     "Change the display name of the Service." )
  47. #define OPTIONS_TEXT N_("Configuration options")
  48. #define OPTIONS_LONGTEXT N_( 
  49.     "Configuration options that will be " 
  50.     "used by the Service (eg. --foo=bar --no-foobar). It should be specified "
  51.     "at install time so the Service is properly configured.")
  52. #define EXTRAINTF_TEXT N_("Extra interface modules")
  53. #define EXTRAINTF_LONGTEXT N_( 
  54.     "Additional interfaces spawned by the " 
  55.     "Service. It should be specified at install time so the Service is " 
  56.     "properly configured. Use a comma separated list of interface modules. " 
  57.     "(common values are: logger, sap, rc, http)")
  58. vlc_module_begin ()
  59.     set_shortname( N_("NT Service"))
  60.     set_description( N_("Windows Service interface") )
  61.     set_category( CAT_INTERFACE )
  62.     set_subcategory( SUBCAT_INTERFACE_CONTROL )
  63.     add_bool( "ntservice-install", 0, NULL,
  64.               INSTALL_TEXT, INSTALL_LONGTEXT, true )
  65.     add_bool( "ntservice-uninstall", 0, NULL,
  66.               UNINSTALL_TEXT, UNINSTALL_LONGTEXT, true )
  67.     add_string ( "ntservice-name", VLCSERVICENAME, NULL,
  68.                  NAME_TEXT, NAME_LONGTEXT, true )
  69.     add_string ( "ntservice-options", NULL, NULL,
  70.                  OPTIONS_TEXT, OPTIONS_LONGTEXT, true )
  71.     add_string ( "ntservice-extraintf", NULL, NULL,
  72.                  EXTRAINTF_TEXT, EXTRAINTF_LONGTEXT, true )
  73.     set_capability( "interface", 0 )
  74.     set_callbacks( Activate, Close )
  75. vlc_module_end ()
  76. struct intf_sys_t
  77. {
  78.     SERVICE_STATUS_HANDLE hStatus;
  79.     SERVICE_STATUS status;
  80.     char *psz_service;
  81. };
  82. /*****************************************************************************
  83.  * Local prototypes
  84.  *****************************************************************************/
  85. static void Run( intf_thread_t *p_intf );
  86. static int NTServiceInstall( intf_thread_t *p_intf );
  87. static int NTServiceUninstall( intf_thread_t *p_intf );
  88. static void WINAPI ServiceDispatch( DWORD numArgs, char **args );
  89. static void WINAPI ServiceCtrlHandler( DWORD control );
  90. /* We need this global */
  91. static intf_thread_t *p_global_intf;
  92. /*****************************************************************************
  93.  * Activate: initialize and create stuff
  94.  *****************************************************************************/
  95. static int Activate( vlc_object_t *p_this )
  96. {
  97.     intf_thread_t *p_intf = (intf_thread_t*)p_this;
  98.     p_intf->pf_run = Run;
  99.     return VLC_SUCCESS;
  100. }
  101. /*****************************************************************************
  102.  * Close: destroy interface
  103.  *****************************************************************************/
  104. void Close( vlc_object_t *p_this )
  105. {
  106.     (void)p_this;
  107. }
  108. /*****************************************************************************
  109.  * Run: interface thread
  110.  *****************************************************************************/
  111. static void Run( intf_thread_t *p_intf )
  112. {
  113.     intf_sys_t sys;
  114.     intf_thread_t *p_extraintf;
  115.     SERVICE_TABLE_ENTRY dispatchTable[] =
  116.     {
  117.         { VLCSERVICENAME, &ServiceDispatch },
  118.         { NULL, NULL }
  119.     };
  120.     int canc = vlc_savecancel();
  121.     p_global_intf = p_intf;
  122.     p_intf->p_sys = &sys;
  123.     p_intf->p_sys->psz_service = config_GetPsz( p_intf, "ntservice-name" );
  124.     p_intf->p_sys->psz_service = p_intf->p_sys->psz_service ?
  125.         p_intf->p_sys->psz_service : strdup(VLCSERVICENAME);
  126.     if( config_GetInt( p_intf, "ntservice-install" ) )
  127.     {
  128.         NTServiceInstall( p_intf );
  129.         return;
  130.     }
  131.     if( config_GetInt( p_intf, "ntservice-uninstall" ) )
  132.     {
  133.         NTServiceUninstall( p_intf );
  134.         return;
  135.     }
  136.     if( StartServiceCtrlDispatcher( dispatchTable ) == 0 )
  137.     {
  138.         msg_Err( p_intf, "StartServiceCtrlDispatcher failed" ); /* str review */
  139.     }
  140.     free( p_intf->p_sys->psz_service );
  141.     /* Make sure we exit (In case other interfaces have been spawned) */
  142.     libvlc_Quit( p_intf->p_libvlc );
  143.     vlc_restorecancel( canc );
  144. }
  145. /*****************************************************************************
  146.  * NT Service utility functions
  147.  *****************************************************************************/
  148. static int NTServiceInstall( intf_thread_t *p_intf )
  149. {
  150.     intf_sys_t *p_sys  = p_intf->p_sys;
  151.     char psz_path[10*MAX_PATH], psz_pathtmp[MAX_PATH], *psz_extra;
  152.     SC_HANDLE handle = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
  153.     if( handle == NULL )
  154.     {
  155.         msg_Err( p_intf,
  156.                  "could not connect to Services Control Manager database" );
  157.         return VLC_EGENERIC;
  158.     }
  159.     /* Find out the filename of ourselves so we can install it to the
  160.      * service control manager */
  161.     GetModuleFileName( NULL, psz_pathtmp, MAX_PATH );
  162.     sprintf( psz_path, ""%s" -I "MODULE_STRING, psz_pathtmp );
  163.     psz_extra = config_GetPsz( p_intf, "ntservice-extraintf" );
  164.     if( psz_extra && *psz_extra )
  165.     {
  166.         strcat( psz_path, " --ntservice-extraintf " );
  167.         strcat( psz_path, psz_extra );
  168.     }
  169.     free( psz_extra );
  170.     psz_extra = config_GetPsz( p_intf, "ntservice-options" );
  171.     if( psz_extra && *psz_extra )
  172.     {
  173.         strcat( psz_path, " " );
  174.         strcat( psz_path, psz_extra );
  175.     }
  176.     free( psz_extra );
  177.     SC_HANDLE service =
  178.         CreateService( handle, p_sys->psz_service, p_sys->psz_service,
  179.                        GENERIC_READ | GENERIC_EXECUTE,
  180.                        SERVICE_WIN32_OWN_PROCESS,
  181.                        SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
  182.                        psz_path, NULL, NULL, NULL, NULL, NULL );
  183.     if( service == NULL )
  184.     {
  185.         if( GetLastError() != ERROR_SERVICE_EXISTS )
  186.         {
  187.             msg_Err( p_intf, "could not create new service: "%s" (%s)",
  188.                      p_sys->psz_service ,psz_path );
  189.             CloseServiceHandle( handle );
  190.             return VLC_EGENERIC;
  191.         }
  192.         else
  193.         {
  194.             msg_Warn( p_intf, "service "%s" already exists",
  195.                       p_sys->psz_service );
  196.         }
  197.     }
  198.     else
  199.     {
  200.         msg_Warn( p_intf, "service successfuly created" );
  201.     }
  202.     if( service ) CloseServiceHandle( service );
  203.     CloseServiceHandle( handle );
  204.     return VLC_SUCCESS;
  205. }
  206. static int NTServiceUninstall( intf_thread_t *p_intf )
  207. {
  208.     intf_sys_t *p_sys  = p_intf->p_sys;
  209.     SC_HANDLE handle = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
  210.     if( handle == NULL )
  211.     {
  212.         msg_Err( p_intf,
  213.                  "could not connect to Services Control Manager database" );
  214.         return VLC_EGENERIC;
  215.     }
  216.     /* First, open a handle to the service */
  217.     SC_HANDLE service = OpenService( handle, p_sys->psz_service, DELETE );
  218.     if( service == NULL )
  219.     {
  220.         msg_Err( p_intf, "could not open service" );
  221.         CloseServiceHandle( handle );
  222.         return VLC_EGENERIC;
  223.     }
  224.     /* Remove the service */
  225.     if( !DeleteService( service ) )
  226.     {
  227.         msg_Err( p_intf, "could not delete service "%s"",
  228.                  p_sys->psz_service );
  229.     }
  230.     else
  231.     {
  232.         msg_Dbg( p_intf, "service deleted successfuly" );
  233.     }
  234.     CloseServiceHandle( service );
  235.     CloseServiceHandle( handle );
  236.     return VLC_SUCCESS;
  237. }
  238. static void WINAPI ServiceDispatch( DWORD numArgs, char **args )
  239. {
  240.     (void)numArgs;
  241.     (void)args;
  242.     intf_thread_t *p_intf = (intf_thread_t *)p_global_intf;
  243.     intf_sys_t    *p_sys  = p_intf->p_sys;
  244.     char *psz_modules, *psz_parser;
  245.     /* We have to initialize the service-specific stuff */
  246.     memset( &p_sys->status, 0, sizeof(SERVICE_STATUS) );
  247.     p_sys->status.dwServiceType = SERVICE_WIN32;
  248.     p_sys->status.dwCurrentState = SERVICE_START_PENDING;
  249.     p_sys->status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  250.     p_sys->hStatus =
  251.         RegisterServiceCtrlHandler( p_sys->psz_service, &ServiceCtrlHandler );
  252.     if( p_sys->hStatus == (SERVICE_STATUS_HANDLE)0 )
  253.     {
  254.         msg_Err( p_intf, "failed to register service control handler" );
  255.         return;
  256.     }
  257.     /*
  258.      * Load background interfaces
  259.      */
  260.     psz_modules = config_GetPsz( p_intf, "ntservice-extraintf" );
  261.     psz_parser = psz_modules;
  262.     while( psz_parser && *psz_parser )
  263.     {
  264.         char *psz_module, *psz_temp;
  265.         psz_module = psz_parser;
  266.         psz_parser = strchr( psz_module, ',' );
  267.         if( psz_parser )
  268.         {
  269.             *psz_parser = '';
  270.             psz_parser++;
  271.         }
  272.         if( asprintf( &psz_temp, "%s,none", psz_module ) != -1 )
  273.         {
  274.             intf_thread_t *p_new_intf;
  275.             /* Try to create the interface */
  276.             p_new_intf = intf_Create( p_intf, psz_temp );
  277.             if( p_new_intf == NULL )
  278.             {
  279.                 msg_Err( p_intf, "interface "%s" initialization failed",
  280.                          psz_temp );
  281.                 free( psz_temp );
  282.                 continue;
  283.             }
  284.             /* Try to run the interface */
  285.             if( intf_RunThread( p_new_intf ) )
  286.             {
  287.                 vlc_object_detach( p_new_intf );
  288.                 vlc_object_release( p_new_intf );
  289.                 msg_Err( p_intf, "interface "%s" cannot run", psz_temp );
  290.             }
  291.             free( psz_temp );
  292.         }
  293.     }
  294.     free( psz_modules );
  295.     /* Initialization complete - report running status */
  296.     p_sys->status.dwCurrentState = SERVICE_RUNNING;
  297.     p_sys->status.dwCheckPoint   = 0;
  298.     p_sys->status.dwWaitHint     = 0;
  299.     SetServiceStatus( p_sys->hStatus, &p_sys->status );
  300. }
  301. static void WINAPI ServiceCtrlHandler( DWORD control )
  302. {
  303.     intf_thread_t *p_intf = (intf_thread_t *)p_global_intf;
  304.     intf_sys_t    *p_sys  = p_intf->p_sys;
  305.     switch( control )
  306.     {
  307.     case SERVICE_CONTROL_SHUTDOWN:
  308.     case SERVICE_CONTROL_STOP:
  309.         p_sys->status.dwCurrentState = SERVICE_STOPPED;
  310.         p_sys->status.dwWin32ExitCode = 0;
  311.         p_sys->status.dwCheckPoint = 0;
  312.         p_sys->status.dwWaitHint = 0;
  313.         break;
  314.     case SERVICE_CONTROL_INTERROGATE:
  315.         /* just set the current state to whatever it is... */
  316.         break;
  317.     }
  318.     SetServiceStatus( p_sys->hStatus, &p_sys->status );
  319. }