C++11 Range for-loop for Enumeration

在现代编程中,经常需要遍历各种数据集合,如Windows注册表键/值、文件夹中的文件以及Windows管理指令(WMI)查询结果。传统方法通常需要编写大量的初始化代码,并且需要深入了解底层的Win32 API。幸运的是,C++11引入了范围for循环(range for-loop),它提供了一种更简洁、更直观的方式来遍历集合。本文将介绍如何利用C++11范围for循环来枚举Windows注册表键/值、文件夹中的文件以及WMI查询结果,而无需编写繁琐的初始化代码或了解底层Win32 API。

这个库基于Marius Bancila的文章“Enabling MFC Collections to Work in Range-based for Loops”。Marius Bancila使得MFC集合可以在基于范围的for循环中使用,而这个库将他的概念应用到了非集合对象上,如注册表、文件夹中的文件和WMI查询。

优点:

  • 资源管理通过RAII(资源获取即初始化)完成:句柄和资源在枚举器的析构函数中释放。
  • 抽象了Windows API的使用细节,用户无需关心底层实现。
  • 减少了样板代码的编写,让用户可以专注于业务逻辑。
缺点:
  • 由枚举器产生的迭代器不能用于STL算法,因为底层枚举对象不是一个集合。
  • 不能应用于使用异步回调进行的枚举,因为回调不能重构为范围for循环迭代器。

枚举文件夹示例: #include "EnumFolder.h" EnumFolder enumFolder(L"c:\\temp"); for(auto const& ffd : enumFolder) { if(IsFolder(ffd)) { std::wcout << L"" << ffd.cFileName << L"

\n"; } else { LARGE_INTEGER filesize; filesize.LowPart = ffd.nFileSizeLow; filesize.HighPart = ffd.nFileSizeHigh; std::wcout << L"" << ffd.cFileName << L"" << filesize.QuadPart << L"bytes\n"; } }

枚举注册表键示例: 与MSDN提供的原始Win32注册表枚举示例相比,下面的示例更加简洁,开发者无需编写那么多的样板代码。 #include "EnumRegistryKey.h" EnumRegistryKey enumRegistryKey(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft"); for(auto const& szKey : enumRegistryKey) { std::wcout << szKey << L"\n"; }

枚举注册表值示例: 这是一个使用范围for循环枚举注册表值的示例。 #include "EnumRegistryValue.h" EnumRegistryValue enumRegistryValue(HKEY_CURRENT_USER, L"Software\\7-Zip\\Compression"); for(auto const& szValueName : enumRegistryValue) { std::wcout << szValueName << L"\n"; }

枚举WMI示例: 这是一个使用范围for循环枚举系统正在运行的进程的WMI查询结果的示例。注意:需要初始化和反初始化COM运行时。 #include "EnumWmi.h" if(!InitializeCOM()) { std::cerr << "InitializeCOM() fails! Program exits.\n"; return 1; } { EnumWmi enumWmi(L"SELECT * FROM Win32_Process"); for(const auto& process : enumWmi) { _bstr_t str = process[L"Name"].bstrVal; std::cout << "Program name: " << str << std::endl; } } CoUninitialize();

EnumFolder类的实现: 要启用C++11范围for循环,基本上需要编写两个类:作为“集合”类的枚举器类和一个迭代“集合”的迭代器类。由于其他涉及注册表和WMI的枚举器类需要深入了解它们的工作原理,这里只解释EnumFolder类。使用了Marius Bancila文章中提到的MFC CStringArray的迭代器类作为参考,以实现C++11范围for循环。

迭代器类的实现: class CStringArrayIterator { public: CStringArrayIterator(CStringArray& collection, INT_PTR const index) : m_index(index), m_collection(collection) { } bool operator!= (const CStringArrayIterator& other) const { return m_index != other.m_index; } CString& operator* () const { return m_collection[m_index]; } CStringArrayIterator const& operator++ () { ++m_index; return *this; } private: INT_PTR m_index; CStringArray& m_collection; }; inline CStringArrayIterator begin(CStringArray& collection) { return CStringArrayIterator(collection, 0); } inline CStringArrayIterator end(CStringArray& collection) { return CStringArrayIterator(collection, collection.GetCount()); }

C++11范围for循环在幕后调用begin()和end()来获取起始和结束迭代器。EnumFolder类就是这样实现的,使用FindFirstFile、FindNextFile和FindClose。

EnumFolder类的实现: class EnumFolder { public: EnumFolder(const std::wstring& folder) : m_Folder(folder), m_hFind(INVALID_HANDLE_VALUE) { m_Folder += L"\\*"; ::ZeroMemory(&m_Ffd, sizeof(m_Ffd)); } ~EnumFolder() { if(m_hFind != INVALID_HANDLE_VALUE) FindClose(m_hFind); m_hFind = INVALID_HANDLE_VALUE; } bool Init() { m_hFind = FindFirstFile(m_Folder.c_str(), &m_Ffd); return m_hFind != INVALID_HANDLE_VALUE; } bool Next() { return FindNextFile(m_hFind, &m_Ffd) != 0; } const WIN32_FIND_DATA& GetFFD() const { return m_Ffd; } private: std::wstring m_Folder; HANDLE m_hFind; WIN32_FIND_DATA m_Ffd; };

迭代器类的实现: class EnumFolderIterator { public: EnumFolderIterator(EnumFolder& collection, INT_PTR const index) : m_Index(index), m_Collection(collection) { if(index == 0) { if(!m_Collection.Init()) m_Index = -1; } } bool operator!= (const EnumFolderIterator& other) const { return m_Index != other.m_Index; } const WIN32_FIND_DATA& operator* () const { return m_Collection.GetFFD(); } EnumFolderIterator const& operator++ () { if(m_Index != -1) { if(m_Collection.Next()) ++m_Index; else m_Index = -1; } return *this; } private: INT_PTR m_Index; EnumFolder& m_Collection; }; inline EnumFolderIterator begin(EnumFolder& collection) { return EnumFolderIterator(collection, 0); } inline EnumFolderIterator end(EnumFolder& collection) { return EnumFolderIterator(collection, -1); }

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485