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
|
target_sources(YYCCommonplace
|
||||||
PRIVATE
|
PRIVATE
|
||||||
# Sources
|
# Sources
|
||||||
|
COMHelper.cpp
|
||||||
ConsoleHelper.cpp
|
ConsoleHelper.cpp
|
||||||
DialogHelper.cpp
|
DialogHelper.cpp
|
||||||
EncodingHelper.cpp
|
EncodingHelper.cpp
|
||||||
ExceptionHelper.cpp
|
ExceptionHelper.cpp
|
||||||
FsPathPatch.cpp
|
FsPathPatch.cpp
|
||||||
IOHelper.cpp
|
IOHelper.cpp
|
||||||
ParserHelper.cpp
|
|
||||||
StringHelper.cpp
|
StringHelper.cpp
|
||||||
WinFctHelper.cpp
|
WinFctHelper.cpp
|
||||||
)
|
)
|
||||||
|
@ -20,6 +20,7 @@ FILE_SET HEADERS
|
||||||
FILES
|
FILES
|
||||||
# Headers
|
# Headers
|
||||||
# Common headers
|
# Common headers
|
||||||
|
COMHelper.hpp
|
||||||
ConsoleHelper.hpp
|
ConsoleHelper.hpp
|
||||||
DialogHelper.hpp
|
DialogHelper.hpp
|
||||||
EncodingHelper.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 {
|
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
|
#pragma region FileFilters
|
||||||
|
|
||||||
bool FileFilters::Add(const char* filter_name, std::initializer_list<const char*> il) {
|
bool FileFilters::Add(const char* filter_name, std::initializer_list<const char*> il) {
|
||||||
|
@ -185,7 +148,7 @@ namespace YYCC::DialogHelper {
|
||||||
LPWSTR _name;
|
LPWSTR _name;
|
||||||
HRESULT hr = item->GetDisplayName(SIGDN_FILESYSPATH, &_name);
|
HRESULT hr = item->GetDisplayName(SIGDN_FILESYSPATH, &_name);
|
||||||
if (FAILED(hr)) return false;
|
if (FAILED(hr)) return false;
|
||||||
SmartLPWSTR display_name(_name);
|
COMHelper::SmartLPWSTR display_name(_name);
|
||||||
|
|
||||||
// convert result
|
// convert result
|
||||||
if (!YYCC::EncodingHelper::WcharToUTF8(display_name.get(), ret))
|
if (!YYCC::EncodingHelper::WcharToUTF8(display_name.get(), ret))
|
||||||
|
@ -235,7 +198,7 @@ namespace YYCC::DialogHelper {
|
||||||
);
|
);
|
||||||
if (FAILED(hr)) return false;
|
if (FAILED(hr)) return false;
|
||||||
// create memory-safe dialog pointer
|
// create memory-safe dialog pointer
|
||||||
SmartIFileDialog pfd(_pfd);
|
COMHelper::SmartIFileDialog pfd(_pfd);
|
||||||
|
|
||||||
// set options for dialog
|
// set options for dialog
|
||||||
// before setting, always get the options first in order.
|
// before setting, always get the options first in order.
|
||||||
|
@ -320,7 +283,7 @@ namespace YYCC::DialogHelper {
|
||||||
IShellItem* _item;
|
IShellItem* _item;
|
||||||
hr = pfd->GetResult(&_item);
|
hr = pfd->GetResult(&_item);
|
||||||
if (FAILED(hr)) return false;
|
if (FAILED(hr)) return false;
|
||||||
SmartIShellItem result_item(_item);
|
COMHelper::SmartIShellItem result_item(_item);
|
||||||
|
|
||||||
// extract display name
|
// extract display name
|
||||||
std::string result_name;
|
std::string result_name;
|
||||||
|
@ -338,13 +301,13 @@ namespace YYCC::DialogHelper {
|
||||||
IFileOpenDialog* _pfod = nullptr;
|
IFileOpenDialog* _pfod = nullptr;
|
||||||
hr = pfd->QueryInterface(IID_PPV_ARGS(&_pfod));
|
hr = pfd->QueryInterface(IID_PPV_ARGS(&_pfod));
|
||||||
if (FAILED(hr)) return false;
|
if (FAILED(hr)) return false;
|
||||||
SmartIFileOpenDialog pfod(_pfod);
|
COMHelper::SmartIFileOpenDialog pfod(_pfod);
|
||||||
|
|
||||||
// obtain multiple file entires
|
// obtain multiple file entires
|
||||||
IShellItemArray* _items;
|
IShellItemArray* _items;
|
||||||
hr = pfod->GetResults(&_items);
|
hr = pfod->GetResults(&_items);
|
||||||
if (FAILED(hr)) return false;
|
if (FAILED(hr)) return false;
|
||||||
SmartIShellItemArray result_items(_items);
|
COMHelper::SmartIShellItemArray result_items(_items);
|
||||||
|
|
||||||
// analyze file entries
|
// analyze file entries
|
||||||
// get array count first
|
// get array count first
|
||||||
|
@ -357,7 +320,7 @@ namespace YYCC::DialogHelper {
|
||||||
IShellItem* _item;;
|
IShellItem* _item;;
|
||||||
hr = result_items->GetItemAt(i, &_item);
|
hr = result_items->GetItemAt(i, &_item);
|
||||||
if (FAILED(hr)) return false;
|
if (FAILED(hr)) return false;
|
||||||
SmartIShellItem result_item(_item);
|
COMHelper::SmartIShellItem result_item(_item);
|
||||||
|
|
||||||
// extract display name
|
// extract display name
|
||||||
std::string result_name;
|
std::string result_name;
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
#include "YYCCInternal.hpp"
|
#include "YYCCInternal.hpp"
|
||||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||||
|
|
||||||
|
#include "COMHelper.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "WinImportPrefix.hpp"
|
#include "WinImportPrefix.hpp"
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
@ -14,44 +14,6 @@
|
||||||
|
|
||||||
namespace YYCC::DialogHelper {
|
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
|
* @brief The class represent the file types region in file dialog
|
||||||
* @details THis class is specific for Windows use, not user oriented.
|
* @details THis class is specific for Windows use, not user oriented.
|
||||||
|
@ -169,7 +131,7 @@ namespace YYCC::DialogHelper {
|
||||||
UINT m_WinDefaultFileTypeIndex;
|
UINT m_WinDefaultFileTypeIndex;
|
||||||
bool m_HasTitle, m_HasInitFileName;
|
bool m_HasTitle, m_HasInitFileName;
|
||||||
std::wstring m_WinTitle, m_WinInitFileName;
|
std::wstring m_WinTitle, m_WinInitFileName;
|
||||||
SmartIShellItem m_WinInitDirectory;
|
COMHelper::SmartIShellItem m_WinInitDirectory;
|
||||||
|
|
||||||
void Clear() {
|
void Clear() {
|
||||||
m_WinOwner = nullptr;
|
m_WinOwner = nullptr;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||||
|
|
||||||
#include "EncodingHelper.hpp"
|
#include "EncodingHelper.hpp"
|
||||||
|
#include "COMHelper.hpp"
|
||||||
|
|
||||||
namespace YYCC::WinFctHelper {
|
namespace YYCC::WinFctHelper {
|
||||||
|
|
||||||
|
@ -70,6 +71,17 @@ namespace YYCC::WinFctHelper {
|
||||||
return YYCC::EncodingHelper::WcharToUTF8(wpath.c_str(), ret);
|
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
|
#endif
|
||||||
|
|
|
@ -49,6 +49,16 @@ namespace YYCC::WinFctHelper {
|
||||||
* @return True if success, otherwise false.
|
* @return True if success, otherwise false.
|
||||||
*/
|
*/
|
||||||
bool GetModuleFileName(HINSTANCE hModule, std::string& ret);
|
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
|
#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() {
|
static void WinFctTestbench() {
|
||||||
Console::FormatLine("Current Module HANDLE: 0x%" PRI_XPTR_LEFT_PADDING PRIXPTR, YYCC::WinFctHelper::GetCurrentModule());
|
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::StringTestbench();
|
||||||
//YYCCTestbench::ParserTestbench();
|
//YYCCTestbench::ParserTestbench();
|
||||||
//YYCCTestbench::DialogTestbench();
|
//YYCCTestbench::DialogTestbench();
|
||||||
|
//YYCCTestbench::ExceptionTestbench();
|
||||||
//YYCCTestbench::WinFctTestbench();
|
//YYCCTestbench::WinFctTestbench();
|
||||||
YYCCTestbench::FsPathPatch();
|
//YYCCTestbench::FsPathPatch();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user