ntservice.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:12k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * ntservice.c: Windows NT/2K/XP service interface
  3.  *****************************************************************************
  4.  * Copyright (C) 2004 VideoLAN
  5.  * $Id: ntservice.c 9028 2004-10-21 14:33:27Z gbazin $
  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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #include <stdlib.h>
  27. #include <vlc/vlc.h>
  28. #include <vlc/intf.h>
  29. #define VLCSERVICENAME "VLC media player"
  30. /*****************************************************************************
  31.  * Module descriptor
  32.  *****************************************************************************/
  33. static int  Activate( vlc_object_t * );
  34. static void Close   ( vlc_object_t * );
  35. #define INSTALL_TEXT N_( "Install Windows Service" )
  36. #define INSTALL_LONGTEXT N_( 
  37.     "If enabled the interface will install the Service and exit." )
  38. #define UNINSTALL_TEXT N_( "Uninstall Windows Service" )
  39. #define UNINSTALL_LONGTEXT N_( 
  40.     "If enabled the interface will uninstall the Service and exit." )
  41. #define NAME_TEXT N_( "Display name of the Service" )
  42. #define NAME_LONGTEXT N_( 
  43.     "This allows you to change the display name of the Service." )
  44. #define OPTIONS_TEXT N_("Configuration options")
  45. #define OPTIONS_LONGTEXT N_( 
  46.     "This option allows you to specify configuration options that will be " 
  47.     "used by the Service (eg. --foo=bar --no-foobar). It should be specified "
  48.     "at install time so the Service is properly configured.")
  49. #define EXTRAINTF_TEXT N_("Extra interface modules")
  50. #define EXTRAINTF_LONGTEXT N_( 
  51.     "This option allows you to select additional interfaces spawned by the " 
  52.     "Service. It should be specified at install time so the Service is " 
  53.     "properly configured. Use a comma separated list of interface modules. " 
  54.     "(common values are: logger, sap, rc, http)")
  55. vlc_module_begin();
  56.     set_description( _("Windows Service interface") );
  57.     add_bool( "ntservice-install", 0, NULL,
  58.               INSTALL_TEXT, INSTALL_LONGTEXT, VLC_TRUE );
  59.     add_bool( "ntservice-uninstall", 0, NULL,
  60.               UNINSTALL_TEXT, UNINSTALL_LONGTEXT, VLC_TRUE );
  61.     add_string ( "ntservice-name", VLCSERVICENAME, NULL,
  62.                  NAME_TEXT, NAME_LONGTEXT, VLC_TRUE );
  63.     add_string ( "ntservice-options", NULL, NULL,
  64.                  OPTIONS_TEXT, OPTIONS_LONGTEXT, VLC_TRUE );
  65.     add_string ( "ntservice-extraintf", NULL, NULL,
  66.                  EXTRAINTF_TEXT, EXTRAINTF_LONGTEXT, VLC_TRUE );
  67.     set_capability( "interface", 0 );
  68.     set_callbacks( Activate, Close );
  69. vlc_module_end();
  70. struct intf_sys_t
  71. {
  72.     SERVICE_STATUS_HANDLE hStatus;
  73.     SERVICE_STATUS status;
  74.     char *psz_service;
  75. };
  76. /*****************************************************************************
  77.  * Local prototypes
  78.  *****************************************************************************/
  79. static void Run( intf_thread_t *p_intf );
  80. static int NTServiceInstall( intf_thread_t *p_intf );
  81. static int NTServiceUninstall( intf_thread_t *p_intf );
  82. static void WINAPI ServiceDispatch( DWORD numArgs, char **args );
  83. static void WINAPI ServiceCtrlHandler( DWORD control );
  84. /* We need this global */
  85. static intf_thread_t *p_global_intf;
  86. /*****************************************************************************
  87.  * Activate: initialize and create stuff
  88.  *****************************************************************************/
  89. static int Activate( vlc_object_t *p_this )
  90. {
  91.     intf_thread_t *p_intf = (intf_thread_t*)p_this;
  92.     /* Only works on NT/2K/XP */
  93.     if( !IS_WINNT ) return VLC_EGENERIC;
  94.     p_intf->pf_run = Run;
  95.     return VLC_SUCCESS;
  96. }
  97. /*****************************************************************************
  98.  * Close: destroy interface
  99.  *****************************************************************************/
  100. void Close( vlc_object_t *p_this )
  101. {
  102. }
  103. /*****************************************************************************
  104.  * Run: interface thread
  105.  *****************************************************************************/
  106. static void Run( intf_thread_t *p_intf )
  107. {
  108.     intf_thread_t *p_extraintf;
  109.     SERVICE_TABLE_ENTRY dispatchTable[] =
  110.     {
  111.         { VLCSERVICENAME, &ServiceDispatch },
  112.         { NULL, NULL }
  113.     };
  114.     p_global_intf = p_intf;
  115.     p_intf->p_sys = alloca( sizeof( intf_sys_t ) );
  116.     p_intf->p_sys->psz_service = config_GetPsz( p_intf, "ntservice-name" );
  117.     p_intf->p_sys->psz_service = p_intf->p_sys->psz_service ?
  118.         p_intf->p_sys->psz_service : strdup(VLCSERVICENAME);
  119.     if( config_GetInt( p_intf, "ntservice-install" ) )
  120.     {
  121.         NTServiceInstall( p_intf );
  122.         return;
  123.     }
  124.     if( config_GetInt( p_intf, "ntservice-uninstall" ) )
  125.     {
  126.         NTServiceUninstall( p_intf );
  127.         return;
  128.     }
  129.     if( StartServiceCtrlDispatcher( dispatchTable ) == 0 )
  130.     {
  131.         msg_Err( p_intf, "StartServiceCtrlDispatcher failed" );
  132.     }
  133.     free( p_intf->p_sys->psz_service );
  134.     /* Stop and destroy the interfaces we spawned */
  135.     while( (p_extraintf = vlc_object_find(p_intf, VLC_OBJECT_INTF, FIND_CHILD)))
  136.     {
  137.         intf_StopThread( p_extraintf );
  138.         vlc_object_detach( p_extraintf );
  139.         vlc_object_release( p_extraintf );
  140.         intf_Destroy( p_extraintf );
  141.     }
  142.     /* Make sure we exit (In case other interfaces have been spawned) */
  143.     p_intf->p_vlc->b_die = VLC_TRUE;
  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, "could not connect to SCM database" );
  156.         return VLC_EGENERIC;
  157.     }
  158.     /* Find out the filename of ourselves so we can install it to the
  159.      * service control manager */
  160.     GetModuleFileName( NULL, psz_pathtmp, MAX_PATH );
  161.     sprintf( psz_path, ""%s" -I "MODULE_STRING, psz_pathtmp );
  162.     psz_extra = config_GetPsz( p_intf, "ntservice-extraintf" );
  163.     if( psz_extra && *psz_extra )
  164.     {
  165.         strcat( psz_path, " --ntservice-extraintf " );
  166.         strcat( psz_path, psz_extra );
  167.     }
  168.     if( psz_extra ) free( psz_extra );
  169.     psz_extra = config_GetPsz( p_intf, "ntservice-options" );
  170.     if( psz_extra && *psz_extra )
  171.     {
  172.         strcat( psz_path, " " );
  173.         strcat( psz_path, psz_extra );
  174.     }
  175.     if( psz_extra ) free( psz_extra );
  176.     SC_HANDLE service =
  177.         CreateService( handle, p_sys->psz_service, p_sys->psz_service,
  178.                        GENERIC_READ | GENERIC_EXECUTE,
  179.                        SERVICE_WIN32_OWN_PROCESS,
  180.                        SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
  181.                        psz_path, NULL, NULL, NULL, NULL, NULL );
  182.     if( service == NULL )
  183.     {
  184.         if( GetLastError() != ERROR_SERVICE_EXISTS )
  185.         {
  186.             msg_Err( p_intf, "could not create new service: "%s" (%s)",
  187.                      p_sys->psz_service ,psz_path );
  188.             CloseServiceHandle( handle );
  189.             return VLC_EGENERIC;
  190.         }
  191.         else
  192.         {
  193.             msg_Warn( p_intf, "service "%s" already exists",
  194.                       p_sys->psz_service );
  195.         }
  196.     }
  197.     else
  198.     {
  199.         msg_Warn( p_intf, "service successfuly created" );
  200.     }
  201.     if( service ) CloseServiceHandle( service );
  202.     CloseServiceHandle( handle );
  203.     return VLC_SUCCESS;
  204. }
  205. static int NTServiceUninstall( intf_thread_t *p_intf )
  206. {
  207.     intf_sys_t *p_sys  = p_intf->p_sys;
  208.     SC_HANDLE handle = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
  209.     if( handle == NULL )
  210.     {
  211.         msg_Err( p_intf, "could not connect to SCM database" );
  212.         return VLC_EGENERIC;
  213.     }
  214.     /* First, open a handle to the service */
  215.     SC_HANDLE service = OpenService( handle, p_sys->psz_service, DELETE );
  216.     if( service == NULL )
  217.     {
  218.         msg_Err( p_intf, "could not open service" );
  219.         CloseServiceHandle( handle );
  220.         return VLC_EGENERIC;
  221.     }
  222.     /* Remove the service */
  223.     if( !DeleteService( service ) )
  224.     {
  225.         msg_Err( p_intf, "could not delete service "%s"",
  226.                  p_sys->psz_service );
  227.     }
  228.     else
  229.     {
  230.         msg_Dbg( p_intf, "service deleted successfuly" );
  231.     }
  232.     CloseServiceHandle( service );
  233.     CloseServiceHandle( handle );
  234.     return VLC_SUCCESS;
  235. }
  236. static void WINAPI ServiceDispatch( DWORD numArgs, char **args )
  237. {
  238.     intf_thread_t *p_intf = (intf_thread_t *)p_global_intf;
  239.     intf_sys_t    *p_sys  = p_intf->p_sys;
  240.     char *psz_modules, *psz_parser;
  241.     /* We have to initialize the service-specific stuff */
  242.     memset( &p_sys->status, 0, sizeof(SERVICE_STATUS) );
  243.     p_sys->status.dwServiceType = SERVICE_WIN32;
  244.     p_sys->status.dwCurrentState = SERVICE_START_PENDING;
  245.     p_sys->status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  246.     p_sys->hStatus =
  247.         RegisterServiceCtrlHandler( p_sys->psz_service, &ServiceCtrlHandler );
  248.     if( p_sys->hStatus == (SERVICE_STATUS_HANDLE)0 )
  249.     {
  250.         msg_Err( p_intf, "failed to register service control handler" );
  251.         return;
  252.     }
  253.     /*
  254.      * Load background interfaces
  255.      */
  256.     psz_modules = config_GetPsz( p_intf, "ntservice-extraintf" );
  257.     psz_parser = psz_modules;
  258.     while( psz_parser && *psz_parser )
  259.     {
  260.         char *psz_module, *psz_temp;
  261.         psz_module = psz_parser;
  262.         psz_parser = strchr( psz_module, ',' );
  263.         if( psz_parser )
  264.         {
  265.             *psz_parser = '';
  266.             psz_parser++;
  267.         }
  268.         psz_temp = (char *)malloc( strlen(psz_module) + sizeof(",none") );
  269.         if( psz_temp )
  270.         {
  271.             intf_thread_t *p_new_intf;
  272.             sprintf( psz_temp, "%s,none", psz_module );
  273.             /* Try to create the interface */
  274.             p_new_intf = intf_Create( p_intf, psz_temp );
  275.             if( p_new_intf == NULL )
  276.             {
  277.                 msg_Err( p_intf, "interface "%s" initialization failed",
  278.                          psz_temp );
  279.                 free( psz_temp );
  280.                 continue;
  281.             }
  282.             /* Try to run the interface */
  283.             p_new_intf->b_block = VLC_FALSE;
  284.             if( intf_RunThread( p_new_intf ) )
  285.             {
  286.                 vlc_object_detach( p_new_intf );
  287.                 intf_Destroy( p_new_intf );
  288.                 msg_Err( p_intf, "interface "%s" cannot run", psz_temp );
  289.             }
  290.             free( psz_temp );
  291.         }
  292.     }
  293.     if( psz_modules )
  294.     {
  295.         free( psz_modules );
  296.     }
  297.     /* Initialization complete - report running status */
  298.     p_sys->status.dwCurrentState = SERVICE_RUNNING;
  299.     p_sys->status.dwCheckPoint   = 0;
  300.     p_sys->status.dwWaitHint     = 0;
  301.     SetServiceStatus( p_sys->hStatus, &p_sys->status );
  302. }
  303. static void WINAPI ServiceCtrlHandler( DWORD control )
  304. {
  305.     intf_thread_t *p_intf = (intf_thread_t *)p_global_intf;
  306.     intf_sys_t    *p_sys  = p_intf->p_sys;
  307.     switch( control )
  308.     {
  309.     case SERVICE_CONTROL_SHUTDOWN:
  310.     case SERVICE_CONTROL_STOP:
  311.         p_sys->status.dwCurrentState = SERVICE_STOPPED;
  312.         p_sys->status.dwWin32ExitCode = 0;
  313.         p_sys->status.dwCheckPoint = 0;
  314.         p_sys->status.dwWaitHint = 0;
  315.         break;
  316.     case SERVICE_CONTROL_INTERROGATE:
  317.         /* just set the current state to whatever it is... */
  318.         break;
  319.     }
  320.     SetServiceStatus( p_sys->hStatus, &p_sys->status );
  321. }