What is the best way for using HANDLE object from WINAPI when I want to write my code consider RAII principle in c++
I write the following code:
bool Uninstall(wstring folder, const bool removeDir = NULL)
{
//init for run over file in dir by winapi
unique_ptr<WIN32_FIND_DATA> ffd = make_unique<WIN32_FIND_DATA>();
HANDLE handle;
wstring path_for_search = folder + L"\\*"; // for include all the things in path when run over the files or directories
//List files
handle = FindFirstFileW(path_for_search.c_str(), ffd.get());
// run over files and directories by handle
do {
if (wcscmp(ffd->cFileName, L".") != 0 && wcscmp(ffd->cFileName, L"..") != 0) // pass the default '.' and ".."
{
wstring file_or_dir_path = folder + L"\\" + ffd->cFileName; // get the full file or dir path
if (GetFileAttributes(file_or_dir_path.c_str()) & FILE_ATTRIBUTE_DIRECTORY) // check if directory
{
Uninstall(file_or_dir_path, false); // recursive call for uninstall the content in the sub dir itself your text
}
else
{
DeleteFileW(file_or_dir_path.c_str()); // delete the file
}
}
} while (FindNextFile(handle, ffd.get()));
FindClose(handle);
delete handle;
//check if remove the original dir
if (!removeDir)
{
RemoveDirectoryW(folder.c_str());
}
return true;
}
But I'm not sure How to implement automatic RAII class for this object.
The best solution is to make a deleter that can call FindClose
:
struct FindCloser {
typedef HANDLE pointer;
void operator()(HANDLE h) const {FindClose(h);}
};
And then we make a typedef:
using FindHandle = std::unique_ptr<HANDLE, FindCloser>;
And then RAII in your code is trivial:
FindHandle handle = FindFirstFileW(path_for_search.c_str(), ffd.get());
You'll probably also want similar for CloseHandle:
struct HandleCloser {
typedef HANDLE pointer;
void operator()(HANDLE h) const {CloseHandle(h);}
};
using RaiiHandle = std::unique_ptr<HANDLE, HandleCloser>;
In theory, one could use a std::unique_ptr<void,BOOL(WINAPI *)(HANDLE)>
and then pass CloseHandle
as a second parameter to the constructor, but that's (A) obnoxious, (B) bigger and (C) slower. The FindCloser
struct is stateless (takes 0 bytes in memory), and is trivially inlinable. A BOOL(WINAPI *)(HANDLE)
takes an extra ~8 bytes in each unique_ptr
, and is harder for the compiler to prove that the BOOL(WINAPI *)(HANDLE)
will always point at FindClose
, so it often can't be inlined.