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 >
Wrap
C/C++ Source or Header
|
1998-07-27
|
13KB
|
502 lines
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include "example.h"
#include "ntsvc.h"
// File globals
#define SYSTEM_USERID "SYSTEM"
#define MAX_NT_USERID_LEN 1024
static SERVICE_STATUS_HANDLE SvcStatusHandle;
static SERVICE_STATUS Status;
static HANDLE hSvcDoneEvt;
static HANDLE hInitializationDoneEvt;
static HANDLE hSvcShutdownCompleteEvt;
static a_bool Service = FALSE;
static a_bool GUIActive = TRUE;
static a_bool StartMinimized = FALSE;
static char *ServiceName = NULL;
static a_bool init_ok = FALSE;
static HINSTANCE hInst;
static HINSTANCE hPrevInst;
static int nShow;
static char * CmdLine;
void SvcGenerateLog( char * log_msg, WORD log_type )
/***********************************************/
// Generate an Application log message (see NT Event viewer)
{
HANDLE hevt_source;
char * errstrings[1];
if( !Service ) return;
hevt_source = RegisterEventSource( NULL, ServiceName );
errstrings[0] = log_msg;
ReportEvent( hevt_source, log_type, 0, 1, NULL, 1, 0,
(const char**)&errstrings[0], NULL );
DeregisterEventSource( hevt_source );
}
static void service_error_shutdown( char * shutdown_msg )
/*******************************************************/
// Report status as stopped and generate a log indicating an error shutdown
{
CloseHandle( hSvcDoneEvt );
// Note that there can't be any API calls between the one that
// failed and here otherwise GetLastError won't return the right code
SvcStatus( SERVICE_STOPPED, GetLastError(), 0, 0 );
SvcGenerateLog( shutdown_msg, EVENTLOG_ERROR_TYPE );
SetEvent( hSvcShutdownCompleteEvt );
}
static void display_args( int argc, char **argv )
/************************************************/
{
char buff[500];
int i;
strcpy( buff, "Args: " );
for( i=0; i < argc; ++i ) {
strcat( buff, argv[i] );
strcat( buff, " " );
}
sv_debug_info( buff );
}
a_bool SvcStatus(
long current_state,
long exit_code,
long checkpoint,
long wait_hint )
/***************************/
// Report status to service control manager
{
if( Service && SvcStatusHandle != (SERVICE_STATUS_HANDLE) NULL ) {
Status.dwCurrentState = current_state;
Status.dwWin32ExitCode = exit_code;
Status.dwCheckPoint = checkpoint;
Status.dwWaitHint = wait_hint;
if( current_state == SERVICE_START_PENDING ) {
Status.dwControlsAccepted = 0;
} else {
Status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE;
}
return( SetServiceStatus( SvcStatusHandle, &Status ) );
} else {
return( TRUE );
}
}
static void service_shutdown( void )
/**********************************/
// Report status as stopped and generate a log indicating a normal shutdown
{
char lbuff[100];
CloseHandle( hSvcDoneEvt );
sv_stop_service();
SvcStatus( SERVICE_STOPPED, 0, 0, 0 );
sprintf( lbuff, "Normal shutdown of service %s", ServiceName );
SvcGenerateLog( lbuff, EVENTLOG_INFORMATION_TYPE );
SetEvent( hSvcShutdownCompleteEvt );
}
void SvcSetRunning( void )
/****************************/
// Invoked from server to indicate service is running successfully
{
init_ok = TRUE;
SetEvent( hInitializationDoneEvt );
}
void SvcSetStopped( void )
/****************************/
// Invoked from server to indicate service is running successfully
{
SetEvent( hSvcDoneEvt );
}
void SvcSetInitError( void )
/******************************/
// Invoked from server to indicate service had a startup error
{
init_ok = FALSE;
SetEvent( hInitializationDoneEvt );
}
a_bool SvcIsService( void )
/*************************/
{
return( Service );
}
a_bool SvcGUIActive( void )
/*************************/
{
return( GUIActive );
}
a_bool SvcStartMinimized( void )
/******************************/
{
return( StartMinimized );
}
char *SvcServiceName( void )
/*************************/
{
return( ServiceName );
}
// extern int _argc;
// extern char ** _argv;
DWORD _exportkwd PASCAL main_thread( void * parm )
/**************************************/
// GUI thread for server (starts other threads)
{
parm = parm;
sv_debug_info( "main thread started" );
// display_args( _argc, _argv );
if( Service ) {
StartMinimized = TRUE;
} else {
STARTUPINFO si;
GetStartupInfo( &si );
if( si.dwFlags & STARTF_USESHOWWINDOW ) {
nShow = si.wShowWindow;
}
if( nShow == SW_SHOWMINIMIZED
|| nShow == SW_SHOWMINNOACTIVE
|| nShow == SW_MINIMIZE
|| nShow == SW_HIDE
) {
StartMinimized = TRUE;
}
}
sv_start_service( hInst, hPrevInst, CmdLine, nShow );
// SvcStatus( SERVICE_STOPPED, 0, SS_NONE, 0 );
SetEvent( hSvcDoneEvt );
return( 0 );
}
static a_bool start_service( int argc, char ** argv )
/**************************************************/
// Starts server by initiating server GUI thread and waiting for initialization
// to complete
{
DWORD server_tid;
HANDLE server_handle;
// If we're running as a service, _argc and _argv don't contain the actual
// server arguments -- set them up here so that they do
display_args( argc, argv );
// _argc = argc;
// _argv = argv;
sv_debug_info( "starting main thread" );
server_handle = CreateThread( NULL, 65535, &main_thread, NULL, 0, &server_tid );
if( server_handle == NULL ) return( FALSE );
WaitForSingleObject( hInitializationDoneEvt, INFINITE );
return( init_ok );
}
VOID PASCAL SvcCtrlHandler( DWORD ctrl_code )
/*******************************************/
// Service control handler
{
DWORD state = SERVICE_RUNNING;
switch( ctrl_code ) {
case SERVICE_CONTROL_STOP:
state = SERVICE_STOP_PENDING;
SvcStatus( SERVICE_STOP_PENDING, NO_ERROR, 0, 3000 );
SetEvent( hSvcDoneEvt );
return;
case SERVICE_CONTROL_PAUSE:
if( Status.dwCurrentState == SERVICE_RUNNING ) {
sv_pause_service();
state = SERVICE_PAUSED;
}
break;
case SERVICE_CONTROL_CONTINUE:
if( Status.dwCurrentState == SERVICE_PAUSED ) {
sv_resume_service();
state = SERVICE_RUNNING;
}
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
break;
}
SvcStatus( state, NO_ERROR, 0, 0 );
}
extern long _exportkwd PASCAL TestWndProc(
HWND hwnd,
unsigned message,
UINT wParam,
LONG lParam )
/*****************************************/
{
return( DefWindowProc( hwnd, message, wParam, lParam ) );
}
static a_bool can_create_windows( HINSTANCE hInstance )
/*****************************************************/
{
WNDCLASS wc;
char winclass[30] = "_WSQL_Test_class";
HWND hWnd;
wc.style = CS_GLOBALCLASS;
wc.lpfnWndProc = (WNDPROC)TestWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = winclass;
if( !RegisterClass( &wc ) ) {
return( FALSE );
}
hWnd = CreateWindow( winclass, "WSQL", WS_POPUP, 0, 0, 0, 0,
HWND_DESKTOP, NULL, hInstance, NULL );
if( hWnd == NULL ) {
return( FALSE );
}
DestroyWindow( hWnd );
return( TRUE );
}
VOID PASCAL SvcMain( DWORD argc, LPTSTR * argv )
/**********************************************/
// Service main
{
char lbuff[100];
char userid[MAX_NT_USERID_LEN];
DWORD userid_len = MAX_NT_USERID_LEN;
sv_debug_info( "starting SvcMain ..." );
display_args( argc, argv );
if( !GetUserName( userid, &userid_len ) ) {
service_error_shutdown( "Get user name failed" );
return;
}
strcpy( lbuff, "starting under userid -- " );
strcat( lbuff, userid );
sv_debug_info( lbuff );
if( strcmp( userid, SYSTEM_USERID ) != 0
|| !can_create_windows( hInst ) ) {
GUIActive = FALSE;
sv_debug_info( "starting with display FALSE" );
} else {
GUIActive = TRUE;
sv_debug_info( "starting with display TRUE" );
}
Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
Status.dwCurrentState = SERVICE_STOPPED;
Status.dwServiceSpecificExitCode = 0;
SvcStatusHandle = RegisterServiceCtrlHandler( ServiceName,
(LPHANDLER_FUNCTION) SvcCtrlHandler );
if( SvcStatusHandle == (SERVICE_STATUS_HANDLE) NULL ) {
service_error_shutdown( "Register handler failed" );
return;
}
sv_debug_info( "Control handler registered successfully" );
hSvcDoneEvt = CreateEvent( NULL, TRUE, FALSE, NULL );
if( hSvcDoneEvt == NULL ) {
service_error_shutdown( "Create event failed" );
return;
}
hInitializationDoneEvt = CreateEvent( NULL, TRUE, FALSE, NULL );
if( hInitializationDoneEvt == NULL ) {
service_error_shutdown( "Create event failed" );
return;
}
hSvcShutdownCompleteEvt = CreateEvent( NULL, TRUE, FALSE, NULL );
if( hSvcShutdownCompleteEvt == NULL ) {
service_error_shutdown( "Create event failed" );
return;
}
if( !start_service( argc, argv ) ) {
service_error_shutdown( "Could not start server" );
return;
}
if( !SvcStatus( SERVICE_RUNNING, NO_ERROR, 0, 0 ) ) {
service_error_shutdown( "Report status failed" );
return;
}
sprintf( lbuff, "Successfully started service %s", ServiceName );
SvcGenerateLog( lbuff, EVENTLOG_INFORMATION_TYPE );
WaitForSingleObject( hSvcDoneEvt, INFINITE );
service_shutdown();
}
int SvcWinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,
int nCmdShow )
/****************************/
{
SERVICE_TABLE_ENTRY dispatch_table[] = {
{ "APPService", (LPSERVICE_MAIN_FUNCTION) SvcMain },
{ NULL, NULL }
};
char *s;
char lbuff[100];
hInst = hInstance;
hPrevInst = hPrevInstance;
nShow = nCmdShow;
CmdLine = lpszCmdLine;
// Decide if we're running as a service or not
// based on -hv<name> switch.
// The SQL Anywhere Service Manager will automatically add
// the -hv<name> switch to a service.
// This allows the same .exe to be used as either a service
// or a regular exe.
Service = FALSE;
s = CmdLine;
while( isspace( *s ) ) ++s;
if( *s != '\0' ) {
if( (*s == '-' || *s == '/')
&& s[1] == 'h'
&& s[2] == 'v'
) {
Service = TRUE;
ServiceName = &s[3];
}
}
if( Service ) {
sprintf( lbuff, "Starting service %s", ServiceName );
SvcGenerateLog( lbuff, EVENTLOG_INFORMATION_TYPE );
if( !StartServiceCtrlDispatcher( dispatch_table ) ) {
sprintf( lbuff, "Error starting %s service [%d]", ServiceName, GetLastError() );
SvcGenerateLog( lbuff, EVENTLOG_ERROR_TYPE );
} else {
WaitForSingleObject( hSvcShutdownCompleteEvt, INFINITE );
}
} else {
main_thread( NULL );
}
ExitProcess( 0 );
return( 0 );
}
a_bool SvcGetParms( char *parms, int *len )
/*****************************************/
{
DWORD parms_size;
LONG rc;
char subkey_buf[_MAX_PATH];
HKEY hkey;
char buff[600];
if( parms != NULL ) {
parms[0] = '\0';
}
if( ServiceName == NULL ) {
SvcSetInitError();
return( FALSE );
}
sprintf( subkey_buf, SERVICE_SUBKEY, ServiceName );
rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE, subkey_buf, 0,
KEY_QUERY_VALUE, &hkey );
if( rc != ERROR_SUCCESS ) {
SvcSetInitError();
return( FALSE );
}
parms_size = 0;
rc = RegQueryValueEx( hkey, "Parameters", NULL, NULL, NULL,
&parms_size );
if( rc != ERROR_SUCCESS ) {
SvcSetInitError();
return( FALSE );
}
if( parms == NULL ) {
*len = parms_size + 1;
return( TRUE );
}
if( parms_size >= *len ) {
parms_size = *len - 1;
}
rc = RegQueryValueEx( hkey, "Parameters", NULL, NULL,
(unsigned char *)parms, &parms_size );
if( rc != ERROR_SUCCESS ) {
SvcSetInitError();
parms[0] = '\0';
return( FALSE );
}
strcpy( buff, "Command line -- " );
strcat( buff, parms );
sv_debug_info( buff );
return( TRUE );
}