在文件中存储设置,替换 MFC 中的 CSettingsStore 类
在文件中存储设置,替换 MFC 中的 CSettingsStore 类。
介绍
MFC的默认CSettingsStore
类将所有设置(包括UI自定义)都存储在注册表中。它还非常倾向于读写,导致注册表产生惊人的大量流量,并存储大量数据。
此贡献(由我编写并置于公共领域)允许您将此行为替换为一个类,该类将设置存储在用户应用程序数据文件夹中的单个文件中,并将设置保留在内存中以获得最佳读取速度。
Using the Code
要激活它,只需将这两个文件添加到您的项目中,并在
您的CMyApplication::InitInstance()
函数中添加以下行
#include "LocalSettingsStore.h"
BOOL CMyApplication::InitInstance()
{
// store settings in a file in local appdata, not in the registry
CSettingsStoreSP::SetRuntimeClass(RUNTIME_CLASS(CLocalSettingsStore));
此外,您需要在文件LocalSettingsStore.cpp中更改APPLICATION_NAME
宏定义
并删除说#undef APPLICATION_NAME
的行,以将设置存储在特定于您的应用程序的文件中
中。
该代码已与MFC 9.0和Visual Studio 2008 SP1一起测试,但应该与使用相同基本CSettingsStore
类的早期/后期版本一起使用。
它是如何工作的?
MFC使用一个访问注册表的包装器,称为CSettingsStore
。在您的应用程序中,您使用CSettingsStoreSP
类来实际访问此包装器,然后您get
/set
您的首选项项(窗口位置、首选颜色等)。内部框架大量使用此功能来存储和读取工具栏、菜单自定义等的设置。事实上,一个什么都不做的MFC应用程序就会产生大约20KB的注册表数据!
此类中有大量的虚拟函数,允许您重写存储方式。不幸的是,没有关于如何实际执行此操作的文档,因此我深入研究了Microsoft Visual C++ 2008 SP1附带的源代码。
virtual BOOL CreateKey(LPCTSTR lpszPath);
virtual BOOL Open(LPCTSTR lpszPath);
virtual void Close();
virtual BOOL DeleteValue(LPCTSTR lpszValue);
virtual BOOL DeleteKey(LPCTSTR lpszPath, BOOL bAdmin = FALSE);
virtual BOOL Write(LPCTSTR lpszValueName, int nValue);
virtual BOOL Write(LPCTSTR lpszValueName, DWORD dwVal);
virtual BOOL Write(LPCTSTR lpszValueName, LPCTSTR lpszVal);
virtual BOOL Write(LPCTSTR lpszValueName, const CRect& rect);
virtual BOOL Write(LPCTSTR lpszValueName, LPBYTE pData, UINT nBytes);
virtual BOOL Write(LPCTSTR lpszValueName, CObject& obj);
virtual BOOL Write(LPCTSTR lpszValueName, CObject* pObj);
virtual BOOL Read(LPCTSTR lpszValueName, int& nValue);
virtual BOOL Read(LPCTSTR lpszValueName, DWORD& dwValue);
virtual BOOL Read(LPCTSTR lpszValueName, CString& strValue);
virtual BOOL Read(LPCTSTR lpszValueName, CRect& rect);
virtual BOOL Read(LPCTSTR lpszValueName, BYTE** ppData, UINT* pcbData);
virtual BOOL Read(LPCTSTR lpszValueName, CObject& obj);
virtual BOOL Read(LPCTSTR lpszValueName, CObject*& pObj);
您从哪里开始?好吧,事实证明,您需要重写的唯一函数是DWORD
、LPCTSTR
和BYTE
/UINT
的读/写函数,以及创建/删除管理函数:
virtual BOOL CreateKey(LPCTSTR lpszPath);
virtual BOOL Open(LPCTSTR lpszPath);
virtual void Close();
virtual BOOL DeleteValue(LPCTSTR lpszValue);
virtual BOOL DeleteKey(LPCTSTR lpszPath, BOOL bAdmin = FALSE);
virtual BOOL Write(LPCTSTR lpszValueName, DWORD dwVal);
virtual BOOL Write(LPCTSTR lpszValueName, LPCTSTR lpszVal);
virtual BOOL Write(LPCTSTR lpszValueName, LPBYTE pData, UINT nBytes);
virtual BOOL Read(LPCTSTR lpszValueName, DWORD& dwValue);
virtual BOOL Read(LPCTSTR lpszValueName, CString& strValue);
virtual BOOL Read(LPCTSTR lpszValueName, BYTE** ppData, UINT* pcbData);
在内部,CSettingsStore
类会将所有其他请求重新格式化为这三个请求之一。例如,CSettingsStore
支持将CObject
对象封送进出注册表,但在I/O级别,这会通过BYTE**
、UINT*
。
在实现中,所有内容都存储为std::vector<char>
,我认为这是一个方便的“可调整大小的缓冲区”类。键存储为std::wstring
,通过C语言环境小写化,以提供通常在注册表中发生的、不区分大小写的搜索。所有这些都进入一个std::map<std::wstring
, std::vector<char>>
,它实现了完整的键/值映射。(如果您了解Win32,您会知道注册表项有多个命名值;我将其实现为一个没有特殊处理的单一长路径。例如,带有值64名“Bits”的键FOO\bar\baz将存储在映射中,作为foo\bar\baz\bits,指向一个存储DWORD
64的4字节向量。)
该实现仅加载一次设置,以避免不必要的磁盘I/O。加载后,它一直保留在内存中直到程序终止,这意味着性能非常好。为了确保在预期时将更改提交到文件,文件会在CLocalSettingsStore
对象被销毁时写入。不幸的是,这种情况经常发生(MFC实现非常喜欢创建/销毁对象),但为了优化这种情况,它会保留一个脏标记,并且只有在某些内容已更改时才会实际写入磁盘。
文件格式本身相当简单,并带有优化以节省磁盘空间。由于许多键路径具有共同的前缀,因此一个键存储为文件中上一个键中要使用的字符数,加上一个要附加到该键以获得下一个键路径的字符串。这个简单的更改实际上使默认设置文件从大约30KB减少到大约20KB!
关注点
CSettingsStore
的文档非常薄弱。事实证明,对象的封送需要使用基本实现所使用的特定格式,否则将无法正常工作。此外,事实证明您应该只重写三个用于写入数据的虚拟函数,而不是所有函数——有关详细信息,请参阅实现。
历史
- 版本1.0 -- 2009年2月4日
- 版本1.1 -- 2009年2月7日