home *** CD-ROM | disk | FTP | other *** search
/ PC World 1998 December / PCWorld_1998-12_cd.iso / software / sybase / ASA / asa60.exe / data1.cab / cxmp_files / ntsvc.c < prev    next >
C/C++ Source or Header  |  1998-07-27  |  13KB  |  502 lines

  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <process.h>
  5. #include "example.h"
  6. #include "ntsvc.h"
  7.  
  8.  
  9. // File globals
  10.  
  11. #define SYSTEM_USERID "SYSTEM"
  12. #define MAX_NT_USERID_LEN 1024
  13.  
  14. static SERVICE_STATUS_HANDLE    SvcStatusHandle;
  15. static SERVICE_STATUS        Status;
  16. static HANDLE            hSvcDoneEvt;
  17. static HANDLE            hInitializationDoneEvt;
  18. static HANDLE            hSvcShutdownCompleteEvt;
  19.  
  20. static a_bool            Service = FALSE;
  21. static a_bool            GUIActive = TRUE;
  22. static a_bool            StartMinimized = FALSE;
  23. static char            *ServiceName = NULL;
  24. static a_bool            init_ok = FALSE;
  25.  
  26. static HINSTANCE        hInst;
  27. static HINSTANCE        hPrevInst;
  28. static int            nShow;
  29. static char *            CmdLine;
  30.  
  31.  
  32. void SvcGenerateLog( char * log_msg, WORD log_type )
  33. /***********************************************/
  34. // Generate an Application log message (see NT Event viewer)
  35. {
  36.     HANDLE hevt_source;
  37.     char * errstrings[1];
  38.  
  39.     if( !Service ) return;
  40.  
  41.     hevt_source   = RegisterEventSource( NULL, ServiceName );
  42.     errstrings[0] = log_msg;
  43.  
  44.     ReportEvent( hevt_source, log_type, 0, 1, NULL, 1, 0,
  45.          (const char**)&errstrings[0], NULL );
  46.  
  47.     DeregisterEventSource( hevt_source );
  48. }
  49.  
  50. static void service_error_shutdown( char * shutdown_msg )
  51. /*******************************************************/
  52. // Report status as stopped and generate a log indicating an error shutdown
  53. {
  54.     CloseHandle( hSvcDoneEvt );
  55.  
  56.     // Note that there can't be any API calls between the one that
  57.     // failed and here otherwise GetLastError won't return the right code
  58.     SvcStatus( SERVICE_STOPPED, GetLastError(), 0, 0 );
  59.  
  60.     SvcGenerateLog( shutdown_msg, EVENTLOG_ERROR_TYPE );
  61.  
  62.     SetEvent( hSvcShutdownCompleteEvt );
  63. }
  64.  
  65. static void display_args( int argc, char **argv )
  66. /************************************************/
  67. {
  68.     char      buff[500];
  69.     int               i;
  70.  
  71.     strcpy( buff, "Args: " );
  72.     for( i=0; i < argc; ++i ) {
  73.     strcat( buff, argv[i] );
  74.     strcat( buff, " " );
  75.     }
  76.     sv_debug_info( buff );
  77. }
  78.  
  79. a_bool SvcStatus(
  80.     long    current_state,
  81.     long    exit_code,
  82.     long    checkpoint,
  83.     long    wait_hint )
  84. /***************************/
  85. // Report status to service control manager
  86. {
  87.     if( Service  &&  SvcStatusHandle != (SERVICE_STATUS_HANDLE) NULL ) {
  88.     Status.dwCurrentState  = current_state;
  89.     Status.dwWin32ExitCode = exit_code;
  90.     Status.dwCheckPoint    = checkpoint;
  91.     Status.dwWaitHint      = wait_hint;
  92.  
  93.     if( current_state == SERVICE_START_PENDING ) {
  94.         Status.dwControlsAccepted = 0;
  95.     } else {
  96.         Status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  97.                     SERVICE_ACCEPT_PAUSE_CONTINUE;
  98.     }
  99.  
  100.     return( SetServiceStatus( SvcStatusHandle, &Status ) );
  101.     } else {
  102.     return( TRUE );
  103.     }
  104. }
  105.  
  106. static void service_shutdown( void )
  107. /**********************************/
  108. // Report status as stopped and generate a log indicating a normal shutdown
  109. {
  110.     char        lbuff[100];
  111.  
  112.     CloseHandle( hSvcDoneEvt );
  113.  
  114.     sv_stop_service();
  115.  
  116.     SvcStatus( SERVICE_STOPPED, 0, 0, 0 );
  117.  
  118.     sprintf( lbuff, "Normal shutdown of service %s", ServiceName );
  119.  
  120.     SvcGenerateLog( lbuff, EVENTLOG_INFORMATION_TYPE );
  121.  
  122.     SetEvent( hSvcShutdownCompleteEvt );
  123. }
  124.  
  125. void SvcSetRunning( void )
  126. /****************************/
  127. // Invoked from server to indicate service is running successfully
  128. {
  129.     init_ok = TRUE;
  130.  
  131.     SetEvent( hInitializationDoneEvt );
  132. }
  133.  
  134. void SvcSetStopped( void )
  135. /****************************/
  136. // Invoked from server to indicate service is running successfully
  137. {
  138.     SetEvent( hSvcDoneEvt );
  139. }
  140.  
  141. void SvcSetInitError( void )
  142. /******************************/
  143. // Invoked from server to indicate service had a startup error
  144. {
  145.     init_ok = FALSE;
  146.  
  147.     SetEvent( hInitializationDoneEvt );
  148. }
  149.  
  150. a_bool SvcIsService( void )
  151. /*************************/
  152. {
  153.     return( Service );
  154. }
  155.  
  156. a_bool SvcGUIActive( void )
  157. /*************************/
  158. {
  159.     return( GUIActive );
  160. }
  161.  
  162. a_bool SvcStartMinimized( void )
  163. /******************************/
  164. {
  165.     return( StartMinimized );
  166. }
  167.  
  168. char *SvcServiceName( void )
  169. /*************************/
  170. {
  171.     return( ServiceName );
  172. }
  173.  
  174.  
  175. // extern int _argc;
  176. // extern char ** _argv;
  177.  
  178. DWORD _exportkwd PASCAL main_thread( void * parm )
  179. /**************************************/
  180. // GUI thread for server (starts other threads)
  181. {
  182.     parm = parm;
  183.  
  184.     sv_debug_info( "main thread started" );
  185.     // display_args( _argc, _argv );
  186.  
  187.     if( Service ) {
  188.     StartMinimized = TRUE;
  189.     } else {
  190.         STARTUPINFO si;
  191.  
  192.     GetStartupInfo( &si );
  193.  
  194.     if( si.dwFlags & STARTF_USESHOWWINDOW ) {
  195.         nShow = si.wShowWindow;
  196.     }
  197.     if( nShow == SW_SHOWMINIMIZED
  198.     ||  nShow == SW_SHOWMINNOACTIVE
  199.     ||  nShow == SW_MINIMIZE
  200.     ||  nShow == SW_HIDE
  201.     ) {
  202.         StartMinimized = TRUE;
  203.     }
  204.  
  205.     }
  206.     sv_start_service( hInst, hPrevInst, CmdLine, nShow );
  207.  
  208.     // SvcStatus( SERVICE_STOPPED, 0, SS_NONE, 0 );
  209.  
  210.     SetEvent( hSvcDoneEvt );
  211.     return( 0 );
  212. }
  213.  
  214. static a_bool start_service( int argc, char ** argv )
  215. /**************************************************/
  216. // Starts server by initiating server GUI thread and waiting for initialization
  217. // to complete
  218. {
  219.     DWORD    server_tid;
  220.     HANDLE    server_handle;
  221.  
  222.     // If we're running as a service, _argc and _argv don't contain the actual
  223.     //   server arguments -- set them up here so that they do
  224.     display_args( argc, argv );
  225.     // _argc = argc;
  226.     // _argv = argv;
  227.  
  228.     sv_debug_info( "starting main thread" );
  229.     server_handle = CreateThread( NULL, 65535, &main_thread, NULL, 0, &server_tid );
  230.     if( server_handle == NULL ) return( FALSE );
  231.  
  232.     WaitForSingleObject( hInitializationDoneEvt, INFINITE );
  233.  
  234.     return( init_ok );
  235. }
  236.  
  237. VOID PASCAL SvcCtrlHandler( DWORD ctrl_code )
  238. /*******************************************/
  239. // Service control handler
  240. {
  241.     DWORD state = SERVICE_RUNNING;
  242.  
  243.     switch( ctrl_code ) {
  244.     case SERVICE_CONTROL_STOP:
  245.         state = SERVICE_STOP_PENDING;
  246.         SvcStatus( SERVICE_STOP_PENDING, NO_ERROR, 0, 3000 );
  247.         SetEvent( hSvcDoneEvt );
  248.         return;
  249.     case SERVICE_CONTROL_PAUSE:
  250.         if( Status.dwCurrentState == SERVICE_RUNNING ) {
  251.         sv_pause_service();
  252.         state = SERVICE_PAUSED;
  253.         }
  254.         break;
  255.     case SERVICE_CONTROL_CONTINUE:
  256.         if( Status.dwCurrentState == SERVICE_PAUSED ) {
  257.         sv_resume_service();
  258.         state = SERVICE_RUNNING;
  259.         }
  260.         break;
  261.     case SERVICE_CONTROL_INTERROGATE:
  262.         break;
  263.         default:
  264.         break;
  265.     }
  266.     SvcStatus( state, NO_ERROR, 0, 0 );
  267. }
  268.  
  269. extern long _exportkwd PASCAL TestWndProc(
  270.     HWND        hwnd,
  271.     unsigned        message,
  272.     UINT        wParam,
  273.     LONG        lParam )
  274. /*****************************************/
  275. {
  276.     return( DefWindowProc( hwnd, message, wParam, lParam ) );
  277. }
  278.  
  279. static a_bool can_create_windows( HINSTANCE hInstance )
  280. /*****************************************************/
  281. {
  282.     WNDCLASS        wc;
  283.     char        winclass[30] = "_WSQL_Test_class";
  284.     HWND        hWnd;
  285.  
  286.  
  287.     wc.style        = CS_GLOBALCLASS;
  288.     wc.lpfnWndProc    = (WNDPROC)TestWndProc;
  289.     wc.cbClsExtra    = 0;
  290.     wc.cbWndExtra    = 0;
  291.     wc.hInstance    = hInstance;
  292.     wc.hIcon        = NULL;
  293.     wc.hCursor        = NULL;
  294.     wc.hbrBackground    = NULL;
  295.     wc.lpszMenuName    = NULL;
  296.     wc.lpszClassName    = winclass;
  297.     if( !RegisterClass( &wc ) ) {
  298.     return( FALSE );
  299.     }
  300.  
  301.     hWnd = CreateWindow( winclass, "WSQL", WS_POPUP, 0, 0, 0, 0,
  302.                 HWND_DESKTOP, NULL, hInstance, NULL );
  303.  
  304.     if( hWnd == NULL ) {
  305.     return( FALSE );
  306.     }
  307.     DestroyWindow( hWnd );
  308.     return( TRUE );
  309. }
  310.  
  311. VOID PASCAL SvcMain( DWORD argc, LPTSTR * argv )
  312. /**********************************************/
  313. // Service main
  314. {
  315.     char    lbuff[100];
  316.     char    userid[MAX_NT_USERID_LEN];
  317.     DWORD    userid_len = MAX_NT_USERID_LEN;
  318.  
  319.     sv_debug_info( "starting SvcMain ..." );
  320.     display_args( argc, argv );
  321.     if( !GetUserName( userid, &userid_len ) ) {
  322.     service_error_shutdown( "Get user name failed" );
  323.     return;
  324.     }
  325.  
  326.     strcpy( lbuff, "starting under userid -- " );
  327.     strcat( lbuff, userid );
  328.     sv_debug_info( lbuff );
  329.  
  330.     if( strcmp( userid, SYSTEM_USERID ) != 0
  331.     ||  !can_create_windows( hInst ) ) {
  332.     GUIActive = FALSE;
  333.     sv_debug_info( "starting with display FALSE" );
  334.     } else {
  335.     GUIActive = TRUE;
  336.     sv_debug_info( "starting with display TRUE" );
  337.     }
  338.  
  339.     Status.dwServiceType             = SERVICE_WIN32_OWN_PROCESS;
  340.     Status.dwCurrentState            = SERVICE_STOPPED;
  341.     Status.dwServiceSpecificExitCode = 0;
  342.  
  343.     SvcStatusHandle = RegisterServiceCtrlHandler( ServiceName,
  344.                            (LPHANDLER_FUNCTION) SvcCtrlHandler );
  345.     if( SvcStatusHandle == (SERVICE_STATUS_HANDLE) NULL ) {
  346.     service_error_shutdown( "Register handler failed" );
  347.     return;
  348.     }
  349.     sv_debug_info( "Control handler registered successfully" );
  350.  
  351.     hSvcDoneEvt = CreateEvent( NULL, TRUE, FALSE, NULL );
  352.     if( hSvcDoneEvt == NULL ) {
  353.     service_error_shutdown( "Create event failed" );
  354.     return;
  355.     }
  356.  
  357.     hInitializationDoneEvt = CreateEvent( NULL, TRUE, FALSE, NULL );
  358.     if( hInitializationDoneEvt == NULL ) {
  359.     service_error_shutdown( "Create event failed" );
  360.     return;
  361.     }
  362.  
  363.     hSvcShutdownCompleteEvt = CreateEvent( NULL, TRUE, FALSE, NULL );
  364.     if( hSvcShutdownCompleteEvt == NULL ) {
  365.     service_error_shutdown( "Create event failed" );
  366.     return;
  367.     }
  368.  
  369.     if( !start_service( argc, argv ) ) {
  370.     service_error_shutdown( "Could not start server" );
  371.     return;
  372.     }
  373.  
  374.     if( !SvcStatus( SERVICE_RUNNING, NO_ERROR, 0, 0 ) ) {
  375.     service_error_shutdown( "Report status failed" );
  376.     return;
  377.     }
  378.  
  379.     sprintf( lbuff, "Successfully started service %s", ServiceName );
  380.  
  381.     SvcGenerateLog( lbuff, EVENTLOG_INFORMATION_TYPE );
  382.  
  383.     WaitForSingleObject( hSvcDoneEvt, INFINITE );
  384.  
  385.     service_shutdown();
  386. }
  387.  
  388. int SvcWinMain(
  389.     HINSTANCE    hInstance,
  390.     HINSTANCE    hPrevInstance,
  391.     LPSTR    lpszCmdLine,
  392.     int        nCmdShow )
  393. /****************************/
  394. {
  395.     SERVICE_TABLE_ENTRY dispatch_table[] = {
  396.     { "APPService", (LPSERVICE_MAIN_FUNCTION) SvcMain },
  397.     { NULL, NULL }
  398.     };
  399.     char    *s;
  400.     char    lbuff[100];
  401.  
  402.     hInst = hInstance;
  403.     hPrevInst = hPrevInstance;
  404.     nShow = nCmdShow;
  405.     CmdLine = lpszCmdLine;
  406.  
  407.     // Decide if we're running as a service or not
  408.     // based on -hv<name> switch.
  409.     // The SQL Anywhere Service Manager will automatically add
  410.     // the -hv<name> switch to a service.
  411.     // This allows the same .exe to be used as either a service
  412.     // or a regular exe.
  413.     Service = FALSE;
  414.     s = CmdLine;
  415.     while( isspace( *s ) ) ++s;
  416.     if( *s != '\0' ) {
  417.     if( (*s == '-'  ||  *s == '/')
  418.     && s[1] == 'h'
  419.     && s[2] == 'v'
  420.     ) {
  421.         Service = TRUE;
  422.         ServiceName = &s[3];
  423.     }
  424.     }
  425.  
  426.     if( Service ) {
  427.     sprintf( lbuff, "Starting service %s", ServiceName );
  428.     SvcGenerateLog( lbuff, EVENTLOG_INFORMATION_TYPE );
  429.  
  430.     if( !StartServiceCtrlDispatcher( dispatch_table ) ) {
  431.         sprintf( lbuff, "Error starting %s service [%d]", ServiceName, GetLastError() );
  432.         SvcGenerateLog( lbuff, EVENTLOG_ERROR_TYPE );
  433.     } else {
  434.         WaitForSingleObject( hSvcShutdownCompleteEvt, INFINITE );
  435.     }
  436.     } else {
  437.     main_thread( NULL );
  438.     }
  439.     
  440.     ExitProcess( 0 );
  441.     return( 0 );
  442. }
  443.  
  444. a_bool SvcGetParms( char *parms, int *len )
  445. /*****************************************/
  446. {
  447.     DWORD parms_size;
  448.     LONG  rc;
  449.     char  subkey_buf[_MAX_PATH];
  450.     HKEY  hkey;
  451.     char  buff[600];
  452.  
  453.     if( parms != NULL ) {
  454.     parms[0] = '\0';
  455.     }
  456.  
  457.     if( ServiceName == NULL ) {
  458.     SvcSetInitError();
  459.     return( FALSE );
  460.     }
  461.  
  462.     sprintf( subkey_buf, SERVICE_SUBKEY, ServiceName );
  463.  
  464.     rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE, subkey_buf, 0,
  465.                KEY_QUERY_VALUE, &hkey );
  466.     if( rc != ERROR_SUCCESS ) {
  467.     SvcSetInitError();
  468.     return( FALSE );
  469.     }
  470.  
  471.     parms_size = 0;
  472.     rc = RegQueryValueEx( hkey, "Parameters", NULL, NULL, NULL,
  473.               &parms_size );
  474.     if( rc != ERROR_SUCCESS ) {
  475.     SvcSetInitError();
  476.     return( FALSE );
  477.     }
  478.  
  479.     if( parms == NULL ) {
  480.     *len = parms_size + 1;
  481.     return( TRUE );
  482.     }
  483.     if( parms_size >= *len ) {
  484.     parms_size = *len - 1;
  485.     }
  486.  
  487.     rc = RegQueryValueEx( hkey, "Parameters", NULL, NULL,
  488.               (unsigned char *)parms, &parms_size );
  489.     if( rc != ERROR_SUCCESS ) {
  490.     SvcSetInitError();
  491.     parms[0] = '\0';
  492.     return( FALSE );
  493.     }
  494.  
  495.     strcpy( buff, "Command line -- " );
  496.     strcat( buff, parms );
  497.     sv_debug_info( buff );
  498.  
  499.     return( TRUE );
  500. }
  501.  
  502.