#include <windows.h>
#include <strsafe.h>
#include <pdh.h>
#include <pdhmsg.h>
#include <Psapi.h>

// Registry location for configuration settings
#define CACHESVC_REG_KEY_LOC    L"SYSTEM\\CurrentControlSet\\Services\\DynCache\\Parameters"

// List of notifications for the service
#define INTERNAL_WAKEUP             0   // Internal wake up event (for pause/resume/stop)
#define REG_CHANGE_NOTIFICATION     1   // Registry settings were changed
#define LOW_MEMORY_NOTIFICATION     2   // Available memory is below threshold, backoff cache usage
#define MAX_NOTIFICATIONS           3   // Total number of notifications


// One node of a linked list of counters for a process.
// Each instance of a process will have one counter instance.
// For example, if you have three instances of notepad, you'll have 3 counter instances.  One for each process' working set size.
typedef struct _COUNTER_INSTANCE
{
    PDH_HCOUNTER hCounter;              // Handle to a counter for this process's working set size
    _COUNTER_INSTANCE *Next;            // Pointer to next counter instance
} COUNTER_INSTANCE, *PCOUNTER_INSTANCE;


// This is an entry for a process that the system cache will back off from
typedef struct _PROCESS_ENTRY
{
    LPWSTR  wszImageName;                   // The process's image file name (defined in the registry)
    size_t  WorkingSetSizeBytes;            // Size of the working set in bytes for all instances of this process
    size_t  AdditionalBackoffBytes;         // Size in bytes of additional back off (slack space) (defined in the registry)
    LPWSTR  wszAdditionalBackOffCounter;    // Additional counter to backoff from (defined in the registry)
    size_t  AdditionalCounterUnits;         // Additional counter's units.  Used to scale the value to bytes.
    PDH_HCOUNTER hAdditionalCounter;        // Handle to the additional counter
    PCOUNTER_INSTANCE pCounter;             // Pointer to the first counter instance for this process
    _PROCESS_ENTRY *Next;                   // Pointer to the next process entry
} PROCESS_ENTRY, *PPROCESS_ENTRY;


// Prototypes

// Main function
void DynCacheMain(DWORD dwArgc, LPWSTR *lpwszArgv);

// Set the cache limits
void LimitCache( size_t MaxCacheSize, size_t MinCacheSize );

// Service cleanup
void SvcCleanup( DWORD dwStatus );

// Functions for being a service
void ServiceCtrlHandler (DWORD dwControlCode);
void ResumeService();
void PauseService();
void StopService();
BOOL SendStatusToSCM( DWORD dwCurrentState, 
					  DWORD dwWin32ExitCode,
					  DWORD dwServiceSpecificExitCode,
					  DWORD dwCheckPoint,
					  DWORD dwWaitHint);

#ifdef DBG
// Used in debug builds to output logging messages
void DebugMessage(LPWSTR wszPrintString, ... );
void DebugError(DWORD dwError);
#else
// No logging occurs in retail builds
#define DebugMessage(x, ...)
#define DebugError(x)
#endif