/*-------------------------------------------------------------- * * FILE: SKeys.c * * PURPOSE: The main interface routines between the service * manager and the Serial Keys program. * * CREATION: June 1994 * * COPYRIGHT: Black Diamond Software (C) 1994 * * AUTHOR: Ronald Moak * * NOTES: * * This file, and all others associated with it contains trade secrets * and information that is proprietary to Black Diamond Software. * It may not be copied copied or distributed to any person or firm * without the express written permission of Black Diamond Software. * This permission is available only in the form of a Software Source * License Agreement. * * $Header: %Z% %F% %H% %T% %I% * *--- Includes ---------------------------------------------------------*/ #include #include #include #include #include #include "vars.h" #include "w95trace.c" #define DEFDATA 1 #include "sk_defs.h" #include "sk_comm.h" #include "sk_reg.h" #include "sk_dll.h" #include "sk_login.h" #include "sk_ex.h" #include "..\skdll\skeys.h" #define LONGSTRINGSIZE 1024 #define WAITMAX 0x7FFFFFFF #define RUNNINGEVENT TEXT("SkeysRunning") #if defined(DEBUG) && 0 // give us a long time to startup in case we're debugging #define WAITSTARTUP WAITMAX #else // normal startup time #define WAITSTARTUP 60000 #endif // --- Local Variables -------------------------------------------------- static SERVICE_STATUS_HANDLE s_sshStatusHandle; static SERVICE_STATUS s_ssStatus; // current status of the service PTSTR SERVICENAME = TEXT("SerialKeys"); PTSTR SKEYSUSERINITCMD = TEXT("SKEYS /I"); PTSTR WINLOGONPATH = TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"); PTSTR USERINIT = TEXT("Userinit"); PTSTR USERINITCMDSEP = TEXT(","); DWORD s_dwServiceCommand; static HANDLE s_hEventServiceRequest = NULL; static HANDLE s_hEventServiceRequestReady = NULL; static HANDLE s_hEventServiceTerminate = NULL; static HANDLE s_hEventSkeysServiceRunning = NULL; void DoService(); void DoInit(); void InstallUserInit(); BOOL IsSerialKeysAutoStart(); //--- SCM Function Prototypes ------------------------------------------------ // // Note: The following fuctions manage the connection of the service // with the Service Contol Manager. void PostEventLog(LPTSTR lpszMsg,DWORD Error); VOID ServiceMain(DWORD dwArgc, LPTSTR *ppszArgv); VOID StopSerialKeys(LPTSTR lpszMsg); BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwCheckPoint, DWORD dwWaitHint); LPHANDLER_FUNCTION ServiceCtrl(DWORD dwCtrlCode); // Service Routines ----------------------------------------------- // // Note: The following fuctions manage the internal control of the // Service static void InitReg(); static BOOL InitService(); static void PauseService(); static void ProcessService(); static void ResumeService(); static void TerminateService(); static void ProcessLogout(DWORD dwCtrlType); static BOOL InstallLogout(); static BOOL TerminateLogout(); static void EnableService(BOOL fOn); // CONSIDER - Removing this code. It only gets executed when SKeys is // run from the command line. When run as a service, ServiceMain is // called when the service is started. The sources file pulls in // winmain from the runtime lib. DoInit and DoService could also be // removed with _tWinMain. int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PTSTR pszCmdLine, int nCmdShow) { if ((TEXT('/') == pszCmdLine[0] || TEXT('-') == pszCmdLine[0]) && (TEXT('I') == pszCmdLine[1] || TEXT('i') == pszCmdLine[1])) { DoInit(); } else { DoService(); } ExitProcess(0); return(0); } /*--------------------------------------------------------------- * * FUNCTION DoInit() * * TYPE Global * * PURPOSE This function is called to read skeys configuration * from HKEY_CURRENT_USER at logon session startup and * send the information to the service * * INPUTS None * * RETURNS None * *---------------------------------------------------------------*/ void DoInit() { HANDLE hEventSkeysServiceRunning = NULL; PSECURITY_DESCRIPTOR pSD; SECURITY_ATTRIBUTES sa; pSD = CreateSd(SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE); if (pSD) { sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = pSD; hEventSkeysServiceRunning = CreateEvent( &sa, // Security TRUE, // Manual reset? FALSE, // initial state - not signaled RUNNINGEVENT); // name free(pSD); } if (NULL != hEventSkeysServiceRunning) { DWORD dwWait; dwWait = WaitForSingleObject(hEventSkeysServiceRunning, 60 * 1000); if (WAIT_OBJECT_0 == dwWait) { SKEY_SystemParametersInfo((UINT)SK_SPI_INITUSER, 0, NULL, 0); } CloseHandle(hEventSkeysServiceRunning); } return; } /*--------------------------------------------------------------- * * SCM Interface Functions * /*--------------------------------------------------------------- * * FUNCTION DoService() * * TYPE Global * * PURPOSE all DoService does is call StartServiceCtrlDispatcher * to register the main service thread. When the * API returns, the service has stopped, so exit. * * INPUTS None * * RETURNS None * *---------------------------------------------------------------*/ void DoService() { SERVICE_TABLE_ENTRY dispatchTable[] = { { SERVICENAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain }, { NULL, NULL } }; PSECURITY_DESCRIPTOR pSD; SECURITY_ATTRIBUTES sa; s_hEventServiceRequest = CreateEvent( NULL, // Security FALSE, // Manual reset? FALSE, // initial state - not signaled NULL); // name s_hEventServiceRequestReady = CreateEvent( NULL, // Security FALSE, // Manual reset? TRUE, // initial state - signaled (can accept one request even before ready) NULL); // name s_hEventServiceTerminate = CreateEvent( NULL, // Security TRUE, // Manual reset? FALSE, // initial state - not signaled NULL); // name s_hEventSkeysServiceRunning = NULL; pSD = CreateSd(SYNCHRONIZE|EVENT_MODIFY_STATE|GENERIC_READ|GENERIC_WRITE); DBPRINTF(TEXT("DoService: CreateSd %s\r\n"), (pSD)?TEXT("Succeeded"):TEXT("Failed")); if (pSD) { sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = pSD; s_hEventSkeysServiceRunning = CreateEvent( &sa, // Security TRUE, // Manual reset? FALSE, // initial state - not signaled RUNNINGEVENT); // name free(pSD); } if (NULL != s_hEventServiceRequest && NULL != s_hEventServiceRequestReady && NULL != s_hEventServiceTerminate && NULL != s_hEventSkeysServiceRunning) { DBPRINTF(TEXT("DoService: calling StartServiceCtrlDispatcher... \r\n")); if (!StartServiceCtrlDispatcher(dispatchTable)) { DBPRINTF(TEXT("DoService: StartServiceCtrlDispatcher FAILED\r\n")); StopSerialKeys(TEXT("StartServiceCtrlDispatcher failed.")); } } else { DBPRINTF(TEXT("DoService: Unable to create event %p %p %p %p\r\n"), s_hEventServiceRequest, s_hEventServiceRequestReady, s_hEventServiceTerminate, s_hEventSkeysServiceRunning); StopSerialKeys(TEXT("Unable to create event.")); } if (NULL != s_hEventServiceRequest) { CloseHandle(s_hEventServiceRequest); } if (NULL != s_hEventServiceRequestReady) { CloseHandle(s_hEventServiceRequestReady); } if (NULL != s_hEventServiceTerminate) { CloseHandle(s_hEventServiceTerminate); } if (NULL != s_hEventSkeysServiceRunning) { ResetEvent(s_hEventSkeysServiceRunning); CloseHandle(s_hEventSkeysServiceRunning); } } /*--------------------------------------------------------------- * * FUNCTION ServiceMain() * * TYPE Global * * PURPOSE this function takes care of actually starting the service, * informing the service controller at each step along the way. * After launching the worker thread, it waits on the event * that the worker thread will signal at its termination. * * INPUTS None * * RETURNS None * *---------------------------------------------------------------*/ VOID ServiceMain(DWORD dwArgc, LPTSTR *ppszArgv) { DBPRINTF(TEXT("ServiceMain()\r\n")); // // SERVICE_STATUS members that don't change s_ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; s_ssStatus.dwServiceSpecificExitCode = 0; // // register our service control handler: s_sshStatusHandle = RegisterServiceCtrlHandler( SERVICENAME, (LPHANDLER_FUNCTION) ServiceCtrl); if (!s_sshStatusHandle) { TerminateService(GetLastError()); return; } // report the status to Service Control Manager. ReportStatusToSCMgr( SERVICE_START_PENDING, // service state NO_ERROR, // exit code 1, // checkpoint WAITSTARTUP); // wait hint #if defined(DEBUG) && 0 ///////////////////////////////////////////////// // This debug code gives us time to attach a debugger { int i; for (i = 0; i < 180; i++) // 180 sec = 3 min { Sleep(1000); // one second } } #endif //////////////////////////////////////////////////////// InitReg(); GetUserValues(REG_DEF); ////EnableService(skNewKey.dwFlags & SERKF_SERIALKEYSON); if (!InitService()) // Did Service Initiate successfully? { TerminateService(GetLastError()); // No Terminate With Error return; } ReportStatusToSCMgr( // report status to service manager. SERVICE_RUNNING, // service state NO_ERROR, // exit code 0, // checkpoint 0); // wait hint SetEvent(s_hEventSkeysServiceRunning); ProcessService(); // Process the Service TerminateService(0); // Terminate return; } BOOL IsSerialKeysAutoStart() { BOOL fAutoStart = FALSE; BOOL fOk; SC_HANDLE schService = NULL; SC_HANDLE schSCManager = NULL; schSCManager = OpenSCManager( // Open Service Manager NULL, // machine (NULL == local) NULL, // database (NULL == default) MAXIMUM_ALLOWED); if (NULL != schSCManager) // Did Open Service succeed? { schService = OpenService( schSCManager , __TEXT("SerialKeys"), MAXIMUM_ALLOWED); if (NULL != schService) { BYTE abServiceConfig[1024]; LPQUERY_SERVICE_CONFIG pqsc = (LPQUERY_SERVICE_CONFIG)abServiceConfig; DWORD cbBytesNeeded; fOk = QueryServiceConfig( schService, pqsc, sizeof(abServiceConfig), &cbBytesNeeded); if (fOk) { fAutoStart = (SERVICE_AUTO_START == pqsc->dwStartType); } CloseServiceHandle(schService); } CloseServiceHandle(schSCManager); } return fAutoStart; } void InstallUserInit() { BOOL fOk = FALSE; HKEY hkey; LONG lErr; DWORD dwType; TCHAR szUserinit[LONGSTRINGSIZE]; DWORD cbData = sizeof(szUserinit); lErr = RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINLOGONPATH, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, &hkey); if (ERROR_SUCCESS == lErr) { lErr = RegQueryValueEx( hkey, USERINIT, 0, &dwType, (LPBYTE)szUserinit, &cbData); szUserinit[LONGSTRINGSIZE-1]='\0'; if (ERROR_SUCCESS == lErr && dwType == REG_SZ) { // check to see if we are already installed and if we have // enough room to install // the + 2 allows for the terminating null and for the command seperator char if (NULL == _tcsstr(szUserinit, SKEYSUSERINITCMD) && lstrlen(szUserinit) + lstrlen(SKEYSUSERINITCMD) + 2 < ARRAY_SIZE(szUserinit)) { lstrcat(szUserinit, USERINITCMDSEP); lstrcat(szUserinit, SKEYSUSERINITCMD); RegSetValueEx( hkey, USERINIT, 0, REG_SZ, (CONST LPBYTE)szUserinit, (lstrlen(szUserinit) + 1) * sizeof(*szUserinit)); } } RegCloseKey(hkey); } return; } void RemoveUserInit() { BOOL fOk = FALSE; HKEY hkey; LONG lErr; DWORD dwType; TCHAR szUserinit[LONGSTRINGSIZE]; PTSTR pszDest; PTSTR pszSrc; DWORD cbData = sizeof(szUserinit); lErr = RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINLOGONPATH, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, &hkey); if (ERROR_SUCCESS == lErr) { lErr = RegQueryValueEx( hkey, USERINIT, 0, &dwType, (LPBYTE)szUserinit, &cbData); szUserinit[LONGSTRINGSIZE-1]='\0'; if (ERROR_SUCCESS == lErr && dwType == REG_SZ) { // check to see if we are already installed pszDest = _tcsstr(szUserinit, SKEYSUSERINITCMD); if (NULL != pszDest) { pszSrc =_tcsstr(pszDest, USERINITCMDSEP); if (NULL != pszSrc) { _tcscpy(pszDest, pszSrc+1); } else { while(szUserinit < pszDest && *SKEYSUSERINITCMD != *pszDest) { --pszDest; } *pszDest = 0; // null terminate } } RegSetValueEx( hkey, USERINIT, 0, REG_SZ, (CONST LPBYTE)szUserinit, (lstrlen(szUserinit) + 1) * sizeof(*szUserinit)); } RegCloseKey(hkey); } return; } static void EnableService(BOOL fOn) { SC_HANDLE schService = NULL; SC_HANDLE schSCManager = NULL; schSCManager = OpenSCManager( // Open Service Manager NULL, // machine (NULL == local) NULL, // database (NULL == default) MAXIMUM_ALLOWED); if (NULL != schSCManager) // Did Open Service succeed? { schService = OpenService( schSCManager , __TEXT("SerialKeys"), SERVICE_CHANGE_CONFIG | SERVICE_STOP); if (NULL != schService) { ChangeServiceConfig( schService, SERVICE_WIN32_OWN_PROCESS, (fOn) ? SERVICE_AUTO_START : SERVICE_DEMAND_START, SERVICE_NO_CHANGE, // severity if service fails to start NULL, // pointer to service binary file name NULL, // pointer to load ordering group name NULL, // pointer to variable to get tag identifier NULL, // pointer to array of dependency names NULL, // pointer to account name of service NULL, // pointer to password for service account __TEXT("SerialKeys")); // name to display CloseServiceHandle(schService); } CloseServiceHandle(schSCManager); } if (fOn) { InstallUserInit(); } else { RemoveUserInit(); } return; } //--------------------------------------------------------------- // // FUNCTION void ServiceCtrl(DWORD dwCtrlCode) // // TYPE Global // // PURPOSE this function is called by the Service Controller whenever // someone calls ControlService in reference to our service. // // INPUTS DWORD dwCtrlCode - // // RETURNS None // //----------------------------------------------------------------- LPHANDLER_FUNCTION ServiceCtrl(DWORD dwCtrlCode) { DWORD dwState = SERVICE_RUNNING; DWORD dwWait = 0; DBPRINTF(TEXT("ServiceCtrl()\r\n")); // Handle the requested control code. switch(dwCtrlCode) { case SERVICE_CONTROL_PAUSE: // Pause the service if it is running. if (s_ssStatus.dwCurrentState == SERVICE_RUNNING) { PauseService(); dwState = SERVICE_PAUSED; } break; case SERVICE_CONTROL_CONTINUE: // Resume the paused service. if (s_ssStatus.dwCurrentState == SERVICE_PAUSED) { ResumeService(); dwState = SERVICE_RUNNING; } break; case SERVICE_CONTROL_STOP: // Stop the service. // Report the status, specifying the checkpoint and waithint, // before setting the termination event. if (s_ssStatus.dwCurrentState == SERVICE_RUNNING) { dwState = SERVICE_STOP_PENDING; dwWait = 20000; SetEvent(s_hEventServiceTerminate); } break; case SERVICE_CONTROL_INTERROGATE: // Update the service status. default: // invalid control code break; } // send a status response. ReportStatusToSCMgr(dwState, NO_ERROR, 0, dwWait); return(0); } /*--------------------------------------------------------------- * * FUNCTION BOOL ReportStatusToSCMgr() * * TYPE Global * * PURPOSE This function is called by the ServMainFunc() and * ServCtrlHandler() functions to update the service's status * to the service control manager. * * INPUTS DWORD dwCurrentState * DWORD dwWin32ExitCode * DWORD dwCheckPoint * DWORD dwWaitHint * * RETURNS None * *---------------------------------------------------------------*/ BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwCheckPoint, DWORD dwWaitHint) { BOOL fResult; #ifdef DEBUG { switch (dwCurrentState) { case SERVICE_START_PENDING: DBPRINTF(TEXT("ReportStatusToSCMgr(SERVICE_START_PENDING:)\r\n")); break; case SERVICE_PAUSED: DBPRINTF(TEXT("ReportStatusToSCMgr(SERVICE_PAUSED:)\r\n")); break; case SERVICE_CONTINUE_PENDING: DBPRINTF(TEXT("ReportStatusToSCMgr(SERVICE_CONTINUE_PENDING:)\r\n")); break; case SERVICE_STOP_PENDING: DBPRINTF(TEXT("ReportStatusToSCMgr(SERVICE_STOP_PENDING:)\r\n")); break; case SERVICE_STOPPED: DBPRINTF(TEXT("ReportStatusToSCMgr(SERVICE_STOPPED:)\r\n")); break; case SERVICE_RUNNING: DBPRINTF(TEXT("ReportStatusToSCMgr(SERVICE_RUNNING:)\r\n")); break; default: DBPRINTF(TEXT("ReportStatusToSCMgr(ERROR - SERVICE_UNKNOWN)\r\n")); break; } } #endif switch (dwCurrentState) { case SERVICE_STOPPED: case SERVICE_START_PENDING: case SERVICE_STOP_PENDING: s_ssStatus.dwControlsAccepted = 0; break; default: s_ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE; break; } // These SERVICE_STATUS members are set from parameters. s_ssStatus.dwCurrentState = dwCurrentState; s_ssStatus.dwWin32ExitCode = dwWin32ExitCode; s_ssStatus.dwCheckPoint = dwCheckPoint; s_ssStatus.dwWaitHint = dwWaitHint; // Report the status of the service to the service control manager. fResult = SetServiceStatus( s_sshStatusHandle, // service reference handle &s_ssStatus); // SERVICE_STATUS structure if (!fResult) { StopSerialKeys(TEXT("SetServiceStatus")); // If an error occurs, stop the service. } return fResult; } /*--------------------------------------------------------------- * * FUNCTION void StopSerialKeys(LPTSTR lpszMsg) * * TYPE Global * * PURPOSE The StopSerialKeys function can be used by any thread * to report an error, or stop the service. * * INPUTS LPTSTR lpszMsg - * * RETURNS None * *---------------------------------------------------------------*/ VOID StopSerialKeys(LPTSTR lpszMsg) { DBPRINTF(TEXT("StopSerialKeys()\r\n")); PostEventLog(lpszMsg,GetLastError()); // Post to Event Log SetEvent(s_hEventServiceTerminate); } /*--------------------------------------------------------------- * * FUNCTION void PostEventLog(LPTSTR lpszMsg, DWORD Error) * * TYPE Local * * PURPOSE This function post strings to the Event Log * * INPUTS LPTSTR lpszMsg - String to send * DWORD Error - Error Code (if 0 no error) * * RETURNS None * *---------------------------------------------------------------*/ void PostEventLog(LPTSTR lpszMsg,DWORD Error) { WORD ErrType = EVENTLOG_INFORMATION_TYPE; WORD ErrStrings = 0; TCHAR szMsg[256]; HANDLE hEventSource; LPTSTR lpszStrings[2]; DBPRINTF(TEXT("PostEventLog()\r\n")); lpszStrings[0] = lpszMsg; if (Error) { ErrType = EVENTLOG_ERROR_TYPE; ErrStrings = 2; wsprintf(szMsg, TEXT("SerialKeys error: %d"), Error); lpszStrings[0] = szMsg; lpszStrings[1] = lpszMsg; } hEventSource = RegisterEventSource(NULL,SERVICENAME); if (hEventSource != NULL) { ReportEvent ( hEventSource, // handle of event source ErrType, // event type 0, // event category 0, // event ID NULL, // current user's SID ErrStrings, // strings in lpszStrings 0, // no bytes of raw data lpszStrings, // array of error strings NULL // no raw data ); (VOID) DeregisterEventSource(hEventSource); } } /*--------------------------------------------------------------- * * Internal Service Control Functions * /*--------------------------------------------------------------- * * FUNCTION void InitService() * * PURPOSE This function Initializes the Service & starts the * major threads of the service. * * INPUTS None * * RETURNS None * *---------------------------------------------------------------*/ static BOOL InitService() { DBPRINTF(TEXT("InitService()\r\n")); InstallLogout(); if (!InitDLL()) return(FALSE); if (!InitLogin()) return(FALSE); if (!InitComm()) return(FALSE); DoServiceCommand(SC_LOG_IN); // Set ProcessService to Login Serial Keys return(TRUE); } static void InitReg() { // Set Structure pointers to Buffers skNewKey.cbSize = sizeof(skNewKey); skNewKey.lpszActivePort = szNewActivePort; skNewKey.lpszPort = szNewPort; skCurKey.cbSize = sizeof(skCurKey); skCurKey.lpszActivePort = szCurActivePort; skCurKey.lpszPort = szCurPort; // Set Default Values skNewKey.dwFlags = SERKF_AVAILABLE; skNewKey.iBaudRate = 300; skNewKey.iPortState = 2; lstrcpy(szNewPort,TEXT("COM1:")); lstrcpy(szNewActivePort,TEXT("COM1:")); } /*--------------------------------------------------------------- * * FUNCTION void PauseService() * * PURPOSE This function is called to pause the service * * INPUTS None * * RETURNS None * *---------------------------------------------------------------*/ static void PauseService() { DBPRINTF(TEXT("PauseService()\r\n")); SuspendDLL(); SuspendComm(); SuspendLogin(); } /*--------------------------------------------------------------- * * FUNCTION void DoServiceCommand() * * PURPOSE Passes a command to the service thread * * INPUTS None * * RETURNS None * *---------------------------------------------------------------*/ void DoServiceCommand(DWORD dwServiceCommand) { DWORD dwWaitRet; dwWaitRet = WaitForSingleObject(s_hEventServiceRequestReady, 10*1000); if (WAIT_OBJECT_0 == dwWaitRet) { s_dwServiceCommand = dwServiceCommand; SetEvent(s_hEventServiceRequest); } else { DBPRINTF(TEXT("DoServiceCommand - wait failed or timed-out, request ignored\r\n")); } } /*--------------------------------------------------------------- * * FUNCTION void ProcessService() * * PURPOSE This function is the main service thread for Serial * Keys. Is monitors the status of the other theads * and responds to their request. * * INPUTS None * * RETURNS None * *---------------------------------------------------------------*/ static void ProcessService() { DWORD dwServiceCommand; DWORD dwWaitRet; typedef enum { iheventServiceRequest, iheventServiceTerminate }; HANDLE ahevent[2] = {s_hEventServiceRequest, s_hEventServiceTerminate}; DBPRINTF(TEXT("ProcessService()\r\n")); dwWaitRet = WaitForMultipleObjects(ARRAY_SIZE(ahevent), ahevent, FALSE, // wait all? INFINITE); // This loop will terminate when iheventServiceTerminate is signaled or // WaitForMultipleObjects fails while (iheventServiceRequest == dwWaitRet - WAIT_OBJECT_0) { dwServiceCommand = s_dwServiceCommand; SetEvent(s_hEventServiceRequestReady); switch (dwServiceCommand) { case SC_LOG_OUT: // Login to New User DBPRINTF(TEXT("---- User Logging Out\r\n")); StopComm(); // Stop SerialKey Processing if(GetUserValues(REG_DEF)) // Get Default values & Do we Start? { EnableService(skNewKey.dwFlags & SERKF_SERIALKEYSON); StartComm(); // Yes - Process SerialKey } break; case SC_LOG_IN: // Login to New User DBPRINTF(TEXT("---- User Logging In\r\n")); StopComm(); // Stop SerialKey Processing if(GetUserValues(REG_DEF)) { EnableService(skNewKey.dwFlags & SERKF_SERIALKEYSON); StartComm(); // Yes - Process SerialKey } break; case SC_CHANGE_COMM: // Change Comm Configuration DBPRINTF(TEXT("---- Making Comm Change\r\n")); StopComm(); // Stop SerialKey Processing StartComm(); // Restart SerialKey Processing break; case SC_DISABLE_SKEY: // Disable Serial Keys DBPRINTF(TEXT("---- Disable Serial Keys\r\n")); StopComm(); break; case SC_ENABLE_SKEY: // Enable Serial Keys DBPRINTF(TEXT("---- Enable Serial Keys\r\n")); StartComm(); break; } dwWaitRet = WaitForMultipleObjects(ARRAY_SIZE(ahevent), ahevent, FALSE, // wait all? INFINITE); } } /*--------------------------------------------------------------- * * FUNCTION void ResumeService() * * PURPOSE This function is called to restore the service * * INPUTS None * * RETURNS None * *---------------------------------------------------------------*/ static void ResumeService() { DBPRINTF(TEXT("ResumeService()\r\n")); ResumeDLL(); ResumeComm(); ResumeLogin(); } //--------------------------------------------------------------- // // FUNCTION void TerminateService(DWORD Error) // // TYPE Local // // PURPOSE This function is called by ServiceMain to terminate // the server. It closes all of the open handles & // and reports the service is stopped. // // INPUTS DWORD Error - Any Errors that could abort the // Service. 0 = Normal Stop // // RETURNS None // //--------------------------------------------------------------- static void TerminateService(DWORD Error) { DBPRINTF(TEXT("TerminateService()\r\n")); TerminateLogout(); // Remove Logout Monitoring TerminateComm(); // Init Comm Thread Shutdown TerminateDLL(); // Init DLL Thread Shutdown TerminateLogin(); // Init Login Thread Shutdown // Loop untill all of the Threads are shut down. while (!DoneLogin()) // Loop until Login Thread is terminated Sleep(250); // Sleep while (!DoneDLL()) // Loop until DLL Thread is terminated Sleep(250); // Sleep // reload registery values to insure we have the current values GetUserValues(REG_DEF); EnableService(skNewKey.dwFlags & SERKF_SERIALKEYSON); // Report the status is stopped if (s_sshStatusHandle) (VOID)ReportStatusToSCMgr(SERVICE_STOPPED,Error,0,0); } /*--------------------------------------------------------------- * * Logout Functions - Process Logout request * /*--------------------------------------------------------------- * * FUNCTION void InstallLogout() * * PURPOSE This function installs a Control Handler to process * logout events. * * INPUTS None * * RETURNS None * *---------------------------------------------------------------*/ static BOOL InstallLogout() { DBPRINTF(TEXT("InstallLogout()\r\n")); return(SetConsoleCtrlHandler((PHANDLER_ROUTINE)ProcessLogout,TRUE)); } /*--------------------------------------------------------------- * * FUNCTION void TerminateLogout() * * PURPOSE This function Removes a Control Handler to process * logout events. * * INPUTS None * * RETURNS None * *---------------------------------------------------------------*/ static BOOL TerminateLogout() { DBPRINTF(TEXT("TerminateLogout()\r\n")); return(SetConsoleCtrlHandler((PHANDLER_ROUTINE)ProcessLogout,FALSE)); } /*--------------------------------------------------------------- * * FUNCTION void ProcessLogout() * * PURPOSE This function processes logout events. * * INPUTS None * * RETURNS None * *---------------------------------------------------------------*/ static void ProcessLogout(DWORD dwCtrlType) { DBPRINTF(TEXT("ProcessLogout()\r\n")); if (dwCtrlType == CTRL_LOGOFF_EVENT) { DoServiceCommand(SC_LOG_OUT); // we'll do this each time the currently logged in user logs out } }