refactor: move COM type and guard into independent file
- move COM types and guard into independent file and namespace COMHelper because not only dialog, but also other parts also need to use COM related fucntion. - remove ParserHelper.cpp because it is empty (ParserHelper is header only namespace). - Add a function fetching LOCALAPPDATA in WinFctHelper.
This commit is contained in:
parent
8465d80a54
commit
e20c03a5f1
|
@ -4,13 +4,13 @@ add_library(YYCCommonplace STATIC "")
|
|||
target_sources(YYCCommonplace
|
||||
PRIVATE
|
||||
# Sources
|
||||
COMHelper.cpp
|
||||
ConsoleHelper.cpp
|
||||
DialogHelper.cpp
|
||||
EncodingHelper.cpp
|
||||
ExceptionHelper.cpp
|
||||
FsPathPatch.cpp
|
||||
IOHelper.cpp
|
||||
ParserHelper.cpp
|
||||
StringHelper.cpp
|
||||
WinFctHelper.cpp
|
||||
)
|
||||
|
@ -20,6 +20,7 @@ FILE_SET HEADERS
|
|||
FILES
|
||||
# Headers
|
||||
# Common headers
|
||||
COMHelper.hpp
|
||||
ConsoleHelper.hpp
|
||||
DialogHelper.hpp
|
||||
EncodingHelper.hpp
|
||||
|
|
40
src/COMHelper.cpp
Normal file
40
src/COMHelper.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
#include "COMHelper.hpp"
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
|
||||
namespace YYCC::COMHelper {
|
||||
|
||||
/**
|
||||
* @brief The guard for initialize COM environment.
|
||||
* @details This class will try initializing COM environment by calling CoInitialize when constructing,
|
||||
* and it also will try uninitializing COM environment when destructing.
|
||||
* If initialization failed, uninitialization will not be executed.
|
||||
*/
|
||||
class ComGuard {
|
||||
public:
|
||||
ComGuard() : m_HasInit(false) {
|
||||
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
|
||||
if (SUCCEEDED(hr)) m_HasInit = true;
|
||||
}
|
||||
~ComGuard() {
|
||||
if (m_HasInit) {
|
||||
CoUninitialize();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
bool m_HasInit;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The instance of COM environment guard.
|
||||
* @details Dialog related function need COM environment,
|
||||
* so we need initializing COM environment when loading this module,
|
||||
* and uninitializing COM environment when we no longer use this module.
|
||||
* So we use a static instance in here.
|
||||
* And make it be const so no one can change it.
|
||||
*/
|
||||
static const ComGuard c_ComGuard;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
69
src/COMHelper.hpp
Normal file
69
src/COMHelper.hpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
#include "YYCCInternal.hpp"
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "WinImportPrefix.hpp"
|
||||
#include <Windows.h>
|
||||
#include <shlobj_core.h>
|
||||
#include "WinImportSuffix.hpp"
|
||||
|
||||
/**
|
||||
* @brief COM fucntions related namespace.
|
||||
* @details
|
||||
* This namespace is Windows specific and it will disappear on other platforms.
|
||||
*
|
||||
* This namespace contain a COM Guard which make sure COM was initialized in current module when loading current module.
|
||||
* It is essential because all calling to COM functions should be under the premise that COM has been initialized.
|
||||
* This guard also will uninitialize COM when unloading this module.
|
||||
*
|
||||
* This namespace also provided various memory-safe types for interacting with COM functions.
|
||||
* Although Microsoft also has similar smart pointer called CComPtr.
|
||||
* But this library is eager to hide all Microsoft-related functions calling.
|
||||
* Using CComPtr is not corresponding with the philosophy of this library.
|
||||
* So these std-based smart pointer type were created.
|
||||
*
|
||||
* This namespace is used by internal functions as intended.
|
||||
* They should not be used outside of this library.
|
||||
* But if you compel to use them, it is also okey.
|
||||
*/
|
||||
namespace YYCC::COMHelper {
|
||||
|
||||
/**
|
||||
* @brief C++ standard deleter for every COM interfaces inheriting IUnknown.
|
||||
*/
|
||||
class ComPtrDeleter {
|
||||
public:
|
||||
ComPtrDeleter() {}
|
||||
void operator() (IUnknown* com_ptr) {
|
||||
if (com_ptr != nullptr) {
|
||||
com_ptr->Release();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using SmartIFileDialog = std::unique_ptr<IFileDialog, ComPtrDeleter>;
|
||||
using SmartIFileOpenDialog = std::unique_ptr<IFileOpenDialog, ComPtrDeleter>;
|
||||
using SmartIShellItem = std::unique_ptr<IShellItem, ComPtrDeleter>;
|
||||
using SmartIShellItemArray = std::unique_ptr<IShellItemArray, ComPtrDeleter>;
|
||||
using SmartIShellFolder = std::unique_ptr<IShellFolder, ComPtrDeleter>;
|
||||
|
||||
/**
|
||||
* @brief C++ standard deleter for almost raw pointer used in COM which need to be free by CoTaskMemFree()
|
||||
*/
|
||||
class CoTaskMemDeleter {
|
||||
public:
|
||||
CoTaskMemDeleter() {}
|
||||
void operator() (void* com_ptr) {
|
||||
if (com_ptr != nullptr) {
|
||||
CoTaskMemFree(com_ptr);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using SmartLPWSTR = std::unique_ptr<std::remove_pointer_t<LPWSTR>, CoTaskMemDeleter>;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -6,43 +6,6 @@
|
|||
|
||||
namespace YYCC::DialogHelper {
|
||||
|
||||
#pragma region COM Guard
|
||||
|
||||
/**
|
||||
* @brief The guard for initialize COM environment.
|
||||
* @details This class will try initializing COM environment by calling CoInitialize when constructing,
|
||||
* and it also will try uninitializing COM environment when destructing.
|
||||
* If initialization failed, uninitialization will not be executed.
|
||||
*/
|
||||
class ComGuard {
|
||||
public:
|
||||
ComGuard() : m_HasInit(false) {
|
||||
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
|
||||
if (SUCCEEDED(hr)) m_HasInit = true;
|
||||
}
|
||||
~ComGuard() {
|
||||
if (m_HasInit) {
|
||||
CoUninitialize();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
bool m_HasInit;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The instance of COM environment guard.
|
||||
* @details Dialog related function need COM environment,
|
||||
* so we need initializing COM environment when loading this module,
|
||||
* and uninitializing COM environment when we no longer use this module.
|
||||
* So we use a static instance in here.
|
||||
* And make it be const so no one can change it.
|
||||
*/
|
||||
static const ComGuard c_ComGuard;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
|
||||
#pragma region FileFilters
|
||||
|
||||
bool FileFilters::Add(const char* filter_name, std::initializer_list<const char*> il) {
|
||||
|
@ -185,7 +148,7 @@ namespace YYCC::DialogHelper {
|
|||
LPWSTR _name;
|
||||
HRESULT hr = item->GetDisplayName(SIGDN_FILESYSPATH, &_name);
|
||||
if (FAILED(hr)) return false;
|
||||
SmartLPWSTR display_name(_name);
|
||||
COMHelper::SmartLPWSTR display_name(_name);
|
||||
|
||||
// convert result
|
||||
if (!YYCC::EncodingHelper::WcharToUTF8(display_name.get(), ret))
|
||||
|
@ -235,7 +198,7 @@ namespace YYCC::DialogHelper {
|
|||
);
|
||||
if (FAILED(hr)) return false;
|
||||
// create memory-safe dialog pointer
|
||||
SmartIFileDialog pfd(_pfd);
|
||||
COMHelper::SmartIFileDialog pfd(_pfd);
|
||||
|
||||
// set options for dialog
|
||||
// before setting, always get the options first in order.
|
||||
|
@ -320,7 +283,7 @@ namespace YYCC::DialogHelper {
|
|||
IShellItem* _item;
|
||||
hr = pfd->GetResult(&_item);
|
||||
if (FAILED(hr)) return false;
|
||||
SmartIShellItem result_item(_item);
|
||||
COMHelper::SmartIShellItem result_item(_item);
|
||||
|
||||
// extract display name
|
||||
std::string result_name;
|
||||
|
@ -338,13 +301,13 @@ namespace YYCC::DialogHelper {
|
|||
IFileOpenDialog* _pfod = nullptr;
|
||||
hr = pfd->QueryInterface(IID_PPV_ARGS(&_pfod));
|
||||
if (FAILED(hr)) return false;
|
||||
SmartIFileOpenDialog pfod(_pfod);
|
||||
COMHelper::SmartIFileOpenDialog pfod(_pfod);
|
||||
|
||||
// obtain multiple file entires
|
||||
IShellItemArray* _items;
|
||||
hr = pfod->GetResults(&_items);
|
||||
if (FAILED(hr)) return false;
|
||||
SmartIShellItemArray result_items(_items);
|
||||
COMHelper::SmartIShellItemArray result_items(_items);
|
||||
|
||||
// analyze file entries
|
||||
// get array count first
|
||||
|
@ -357,7 +320,7 @@ namespace YYCC::DialogHelper {
|
|||
IShellItem* _item;;
|
||||
hr = result_items->GetItemAt(i, &_item);
|
||||
if (FAILED(hr)) return false;
|
||||
SmartIShellItem result_item(_item);
|
||||
COMHelper::SmartIShellItem result_item(_item);
|
||||
|
||||
// extract display name
|
||||
std::string result_name;
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
#include "YYCCInternal.hpp"
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
|
||||
#include "COMHelper.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
|
||||
#include "WinImportPrefix.hpp"
|
||||
#include <Windows.h>
|
||||
|
@ -14,44 +14,6 @@
|
|||
|
||||
namespace YYCC::DialogHelper {
|
||||
|
||||
#pragma region COM Pointer Management
|
||||
|
||||
/**
|
||||
* @brief C++ standard deleter for every COM interfaces inheriting IUnknown.
|
||||
*/
|
||||
class ComPtrDeleter {
|
||||
public:
|
||||
ComPtrDeleter() {}
|
||||
void operator() (IUnknown* com_ptr) {
|
||||
if (com_ptr != nullptr) {
|
||||
com_ptr->Release();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using SmartIFileDialog = std::unique_ptr<IFileDialog, ComPtrDeleter>;
|
||||
using SmartIFileOpenDialog = std::unique_ptr<IFileOpenDialog, ComPtrDeleter>;
|
||||
using SmartIShellItem = std::unique_ptr<IShellItem, ComPtrDeleter>;
|
||||
using SmartIShellItemArray = std::unique_ptr<IShellItemArray, ComPtrDeleter>;
|
||||
using SmartIShellFolder = std::unique_ptr<IShellFolder, ComPtrDeleter>;
|
||||
|
||||
/**
|
||||
* @brief C++ standard deleter for almost raw pointer used in COM which need to be free by CoTaskMemFree()
|
||||
*/
|
||||
class CoTaskMemDeleter {
|
||||
public:
|
||||
CoTaskMemDeleter() {}
|
||||
void operator() (void* com_ptr) {
|
||||
if (com_ptr != nullptr) {
|
||||
CoTaskMemFree(com_ptr);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using SmartLPWSTR = std::unique_ptr<std::remove_pointer_t<LPWSTR>, CoTaskMemDeleter>;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
/**
|
||||
* @brief The class represent the file types region in file dialog
|
||||
* @details THis class is specific for Windows use, not user oriented.
|
||||
|
@ -169,7 +131,7 @@ namespace YYCC::DialogHelper {
|
|||
UINT m_WinDefaultFileTypeIndex;
|
||||
bool m_HasTitle, m_HasInitFileName;
|
||||
std::wstring m_WinTitle, m_WinInitFileName;
|
||||
SmartIShellItem m_WinInitDirectory;
|
||||
COMHelper::SmartIShellItem m_WinInitDirectory;
|
||||
|
||||
void Clear() {
|
||||
m_WinOwner = nullptr;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
|
||||
#include "EncodingHelper.hpp"
|
||||
#include "COMHelper.hpp"
|
||||
|
||||
namespace YYCC::WinFctHelper {
|
||||
|
||||
|
@ -70,6 +71,17 @@ namespace YYCC::WinFctHelper {
|
|||
return YYCC::EncodingHelper::WcharToUTF8(wpath.c_str(), ret);
|
||||
}
|
||||
|
||||
bool GetLocalAppData(std::string& ret) {
|
||||
// fetch path
|
||||
LPWSTR _known_path;
|
||||
HRESULT hr = SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &_known_path);
|
||||
if (FAILED(hr)) return false;
|
||||
COMHelper::SmartLPWSTR known_path(_known_path);
|
||||
|
||||
// convert to utf8
|
||||
return YYCC::EncodingHelper::WcharToUTF8(known_path.get(), ret);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -49,6 +49,16 @@ namespace YYCC::WinFctHelper {
|
|||
* @return True if success, otherwise false.
|
||||
*/
|
||||
bool GetModuleFileName(HINSTANCE hModule, std::string& ret);
|
||||
|
||||
/**
|
||||
* @brief Get the path to LOCALAPPDATA.
|
||||
* @details LOCALAPPDATA usually was used as putting local app data files
|
||||
* @param[out] ret
|
||||
* The variable receiving UTF8 encoded path to LOCALAPPDATA.
|
||||
* @return
|
||||
*/
|
||||
bool GetLocalAppData(std::string& ret);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -217,6 +217,16 @@ namespace YYCCTestbench {
|
|||
}
|
||||
}
|
||||
|
||||
static void ExceptionTestbench() {
|
||||
YYCC::ExceptionHelper::Register();
|
||||
|
||||
// Perform a div zero exception.
|
||||
int i = 1, j = 0;
|
||||
int k = i / j;
|
||||
|
||||
YYCC::ExceptionHelper::Unregister();
|
||||
}
|
||||
|
||||
static void WinFctTestbench() {
|
||||
Console::FormatLine("Current Module HANDLE: 0x%" PRI_XPTR_LEFT_PADDING PRIXPTR, YYCC::WinFctHelper::GetCurrentModule());
|
||||
|
||||
|
@ -256,6 +266,7 @@ int main(int argc, char** args) {
|
|||
//YYCCTestbench::StringTestbench();
|
||||
//YYCCTestbench::ParserTestbench();
|
||||
//YYCCTestbench::DialogTestbench();
|
||||
//YYCCTestbench::ExceptionTestbench();
|
||||
//YYCCTestbench::WinFctTestbench();
|
||||
YYCCTestbench::FsPathPatch();
|
||||
//YYCCTestbench::FsPathPatch();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user