#include "DynCache.h" // The name of the service LPWSTR SERVICE_NAME = L"DynCache"; // Flag to signal that the service is shutting down BOOL g_bServiceShutdown = FALSE; // Handle used to communicate status info to the Service Control Manager. Created by RegisterServiceHandler SERVICE_STATUS_HANDLE g_ServiceStatusHandle; // Found in DynCache.cpp extern HANDLE g_hEvents[MAX_NOTIFICATIONS]; // Handles to notification events extern HANDLE g_hPauseService; // Event to pause the service extern BOOL g_bInitializationComplete; extern size_t g_MaxCacheSizeBytesLimit; extern size_t g_CurrentMinCacheSizeBytes; // Report an error then clean up void SvcCleanup( DWORD dwStatus ) { DebugMessage(L"DynCache is exiting.\n"); if (dwStatus != ERROR_SUCCESS) { DebugError(dwStatus); } if (g_bInitializationComplete) { // Set the cache limits back to what was defined in the registry LimitCache(g_MaxCacheSizeBytesLimit, g_CurrentMinCacheSizeBytes); } // Notify the Service Control Manager that we are stopping if (g_ServiceStatusHandle) SendStatusToSCM(SERVICE_STOPPED, dwStatus, 0, 0, 0); } // Dispatches events received from the Service Control Manager void ServiceCtrlHandler (DWORD dwControlCode) { DWORD dwCurrentState = SERVICE_RUNNING; switch(dwControlCode) { // There is no START option because the main function gets called when starting case SERVICE_CONTROL_STOP: // Tell the Service Control Manager that we are stopping SendStatusToSCM(SERVICE_STOP_PENDING, NO_ERROR, 0, 1, 5000); // Stop the service StopService(); return; case SERVICE_CONTROL_PAUSE: // Tell the Service Control Manager that we are pausing SendStatusToSCM( SERVICE_PAUSE_PENDING, NO_ERROR, 0, 1, 5000); // Pause the service PauseService(); // Set our status to paused dwCurrentState = SERVICE_PAUSED; break; case SERVICE_CONTROL_CONTINUE: // Tell the Service Control Manager that we are resuming SendStatusToSCM(SERVICE_CONTINUE_PENDING, NO_ERROR, 0, 1, 5000); // Resume the service ResumeService(); // Set our status to running dwCurrentState = SERVICE_RUNNING; break; // Do nothing in a shutdown. Could do cleanup here but it must be very quick. case SERVICE_CONTROL_SHUTDOWN: // The Service Control Manager is shutting down, so should we StopService(); return; default: break; } // Upate the Service Control Manager with our new status SendStatusToSCM(dwCurrentState, NO_ERROR, 0, 0, 0); } // Resume the service from a paused state void ResumeService() { DebugMessage(L"Dynamic Cache Service is resuming.\n"); // Set the event so that we are no longer paused SetEvent(g_hPauseService); } // Pauses the service void PauseService() { DebugMessage(L"Dynamic Cache Service is pausing.\n"); // Clear the event to pause the service ResetEvent(g_hPauseService); // Issue a wake-up event so that we don't do any more work and immediately pause the service SetEvent(g_hEvents[INTERNAL_WAKEUP]); } // Stops the service by allowing the main function to complete void StopService() { DebugMessage(L"Dynamic Cache Service is stopping because the Service Control Manager requested it.\n"); // Set the event so that we are no longer paused SetEvent(g_hPauseService); // Set the flag that we are shutting down g_bServiceShutdown = TRUE; // Issue a wake-up event so that we don't do any more work and immediately exit SetEvent(g_hEvents[INTERNAL_WAKEUP]); } // Update the Service Control Manager with our status BOOL SendStatusToSCM( DWORD dwCurrentState, // Current state to report DWORD dwWin32ExitCode, // Win32 exit code to report DWORD dwServiceSpecificExitCode, // Service exit code to report DWORD dwCheckPoint, // Checkpoint number to report back to the Service Control Manager DWORD dwWaitHint) // Wait hint for the Service Control Manager { BOOL bSuccess = TRUE; SERVICE_STATUS ServiceStatus; // Fill in all the SERVICE_STATUS fields ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ServiceStatus.dwCurrentState = dwCurrentState; // If we are in transition then accept no control events, else accept anything if ((dwCurrentState == SERVICE_START_PENDING) || (dwCurrentState == SERVICE_PAUSE_PENDING)) ServiceStatus.dwControlsAccepted = 0; else ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN; // Set the service's Win32 exit code if (dwServiceSpecificExitCode == 0) ServiceStatus.dwWin32ExitCode = dwWin32ExitCode; else ServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; // Set the service's exit code ServiceStatus.dwServiceSpecificExitCode = dwServiceSpecificExitCode; // Set the checkpoint and wait hint ServiceStatus.dwCheckPoint = dwCheckPoint; ServiceStatus.dwWaitHint = dwWaitHint; // Send the status record to the Service Control Manager bSuccess = SetServiceStatus (g_ServiceStatusHandle, &ServiceStatus); if (!bSuccess) { DebugMessage(L"SetServiceStatus failed!\n"); DebugError(GetLastError()); StopService(); } return bSuccess; } // Main function for this process __cdecl wmain(void) { DWORD dwStatus = ERROR_SUCCESS; SERVICE_TABLE_ENTRY ServiceTable[] = { // Define the service's name and its main function {SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) DynCacheMain}, { NULL, NULL} }; // Register with the Service Control Manager if (!StartServiceCtrlDispatcher(ServiceTable)) { DebugMessage(L"StartServiceCtrlDispatcher failed!\n"); DebugError(GetLastError()); } }