/*------------------------------------------------------------------------- * Config.h * * The definitions, etc. for a set of classes that are helpful in * maintaining a set of settings in an organized fashion. The class is * generic and extendible to support any implementaion of where the * settings are stored (e.g., registry, database, etc.). * * Owner: * * Copyright 1986-1998 Microsoft Corporation, All Rights Reserved *-----------------------------------------------------------------------*/ #ifdef _CONFIG_H #error config.h included twice #endif #define _CONFIG_H #define HKLM_Sentinal "SYSTEM\\CurrentControlSet\\Services\\Sentinal\\Parameters" // Settings are grouped by "component". Here's the list of different components: typedef enum { kCompId_Sentinal, // Settings related to Sentinal // !!NOTE!! If you add to this table, update REGCFG.CPP's CompIdToKey() // so when we run in registry mode we know where to look... // !!NOTE!! Also, since data can be stored in the database, you should coordinate // adding values in here with everyone, so we don't get database // corruption, where two people use the same component ID in the database to store // different component's settings... kCompId_Last // Must be last... } ComponentId; typedef enum { kConfigType_SZ, kConfigType_DWORD, } ConfigItemType; class ConfigItem { public: ConfigItemType m_type; // Item is an int or string? ZString m_zsName; // Item's name. ZString m_zsValue; // Item's value. }; typedef struct { char * pszKeyName; ConfigItemType type; int cb; int nRequired; // for ReadMany: True/False on if required. union // for ReadRgMany: Required up and including to this index... { DWORD dwDefault; char * pszDefault; }; } ConfigInfo; typedef struct { ConfigInfo info; BYTE * pBuf; } ConfigInfoBuffer; // pure virtual base class for configuration reader. class ConfigReader { public: ConfigReader(ComponentId compId) : m_compId(compId) { } virtual ~ConfigReader() {} virtual BOOL ReadRg (const ConfigInfoBuffer *prgItems, int cItems); virtual BOOL ReadRgRg (int cRepeat, const ConfigInfoBuffer *prgItems, int cItems); // ReadMany() but, the szKeyName has "00x" appended to it (where x is 0 thru cRepeat). pb is assumed to be an array... virtual BOOL ReadInt (const char *pszItem, int *pnVal, BOOL fRequired, int nDefault); virtual BOOL ReadSz (const char *pszItem, char *psz, int cchMax, BOOL fRequired, const char *pszDefault); virtual BOOL WriteInt (const char *pszItem, int nVal); virtual BOOL WriteSz (const char *pszItem, const char *psz, int cch); virtual BOOL DeleteItem(const char *pszItem) = 0; protected: ComponentId m_compId; virtual BOOL Open() = 0; virtual BOOL Close() = 0; virtual BOOL FastReadInt (const char *pszItem, int *pnVal, BOOL fRequired, int nDefault) = 0; virtual BOOL FastReadSz (const char *pszItem, char *psz, int cchMax, BOOL fRequired, const char *pszDefault) = 0; virtual BOOL FastWriteInt(const char *pszItem, int nVal) = 0; virtual BOOL FastWriteSz (const char *pszItem, const char *psz, int cch) = 0; }; // Registry based configuration reader: class RegConfigReader : public ConfigReader { public: RegConfigReader(ComponentId compId) : ConfigReader(compId), m_hk(NULL) { CompIdToKey(); } virtual ~RegConfigReader() { } virtual BOOL DeleteItem(const char *pszItem); protected: virtual BOOL Open(); virtual BOOL Close(); virtual BOOL FastReadInt (const char *pszItem, int *pnVal, BOOL fRequired, int nDefault); virtual BOOL FastReadSz (const char *pszItem, char *psz, int cchMax, BOOL fRequired, const char *pszDefault); virtual BOOL FastWriteInt(const char *pszItem, int nVal); virtual BOOL FastWriteSz (const char *pszItem, const char *psz, int cch); private: BOOL CompIdToKey(); char m_szKey[255]; HKEY m_hk; }; // This routine can be used to create the "appropriate" configuration reader type (registry // or whatever) based on whether a #define is set... // Currently, though we just have a Registry-based solution, so it doesn't matter much. ConfigReader * CreateConfigReader (ComponentId compId); RegConfigReader *CreateRegConfigReader(ComponentId compId); //////////////////////////////////////////////////////////////////////// // This object contains a list of settings stored for a given ComponentId, and list of settings. class Config { public: Config(ComponentId compId) : m_compId(compId), m_pArgs(NULL), m_nArgs(0), m_pConfigInfo(NULL) {} virtual ~Config() { KillArgs(); } BOOL Init(const ConfigInfo *pConfigInfo, int cItems, BOOL fRange, int cRange); BOOL GetDWORDArg(DWORD nArg, DWORD *pdw, int nRange); // only look at nRange, if m_fRange BOOL GetStringArg(DWORD nArg, char *pszBuf, int cchBuf, int nRange); // only look at nRange, if m_fRange // Caller must delete pointer returned: ConfigInfo *GetConfigInfo(int *pcConfig); inline ComponentId GetComponentId() const { return m_compId; } private: ComponentId m_compId; BOOL m_fRange; // TRUE if we're storing a bunch of settings (e.g. a bunch of strings or a bunch of DWORDs). BOOL m_cRange; typedef struct { ConfigItemType type; DWORD cb; union // for ReadRgMany: Required up and including to this index... { DWORD dwVal; // Used if we're not storing a range, and type == kConfigType_DWORD char *pszVal; // Used to store strings, for both range and non range storage DWORD *pdwVal; // Used to store DWORD's when we're storing a range. }; } ARGS; ARGS *m_pArgs; DWORD m_nArgs; ConfigInfoBuffer *m_pConfigInfo; void KillArgs(); }; class ConfigCache { public: ConfigCache() { m_pcsEditList = new CriticalSection; ZeroMemory(&m_rgpConfigList, sizeof(m_rgpConfigList)); } virtual ~ConfigCache() { DeleteConfigList(); delete m_pcsEditList; } Config * FindConfig(ComponentId compId); void AddConfig(Config *pConfig); Config * ReplaceConfig(ComponentId compId, Config *pConfig); void AddConfigToTail(Config *pConfig); Config * RemoveHead(ComponentId compId); Config * RemoveHeadIfOld(ComponentId compId, DWORD dwDeltaOld); private: typedef struct tag_CONFIG_LIST { Config * pConfig; DWORD dwTimeAdded; struct tag_CONFIG_LIST *pNext; } CONFIG_LIST; CONFIG_LIST * m_rgpConfigList[kCompId_Last]; CriticalSection *m_pcsEditList; // this is a pointer, solely cuz we CriticalSection isn't __declspec(dllexport)... void DeleteConfigList(); }; // This class maintains a bunch of different configuration information for various components. // It allows a new configuration to be loaded to replace an existing one in the list in a thread // safe manner, without needing to use a CriticalSection to guard list read access... It does // this by using garbage collection when it deletes a node, making the assumption that some thread // that accesses the list of configurations will traverse the entire list in a short period of time. class ConfigManager { public: ConfigManager() : m_hevtDie(NULL), m_hthrGarbageCollect(NULL), m_pcsAdd(NULL) {} virtual ~ConfigManager(); BOOL Init(); BOOL LoadConfig (ComponentId compId, const ConfigInfo *pInfo, int cInfo); BOOL ReloadConfig (ComponentId compId); BOOL IsConfigLoaded (ComponentId compId); // Routines for getting at our settings. BOOL GetConfigDWORD (ComponentId compId, DWORD nArg, DWORD *pdw); BOOL GetConfigString (ComponentId compId, DWORD nArg, char *pszBuf, int cchBuf); virtual void GarbageCollectThread(); private: ConfigCache m_cacheComponent; // Settings stored by Component ConfigCache m_cacheGarbage; // Garbage collection guys -- we lazy delete these. CriticalSection * m_pcsAdd; // Guards adding to our list/deleting old guy. This is a ptr, solely cuz CriticalSection isn't __declspec(dllexport). HANDLE m_hevtDie; // Signalled when the Garbage Collect thread should go away. HANDLE m_hthrGarbageCollect; // Handle to garbage collector thread. static int CALLBACK GarbageCollectThreadThunk(ConfigManager *pMgr) { ZAssert(pMgr); pMgr->GarbageCollectThread(); return 0; } };