feat: add windows function helper
- add windows function helper namespace for some commonly used windows functions. - add corresponding testbench for added code.
This commit is contained in:
parent
ab12268395
commit
015ff874f8
|
@ -12,6 +12,7 @@ PRIVATE
|
|||
${CMAKE_CURRENT_LIST_DIR}/IOHelper.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/ParserHelper.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/StringHelper.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/WinFctHelper.hpp
|
||||
# Windows including guard pair
|
||||
${CMAKE_CURRENT_LIST_DIR}/WinImportPrefix.hpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/WinImportSuffix.hpp
|
||||
|
@ -27,6 +28,7 @@ PRIVATE
|
|||
${CMAKE_CURRENT_LIST_DIR}/IOHelper.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/ParserHelper.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/StringHelper.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/WinFctHelper.cpp
|
||||
)
|
||||
# Setup header infomations
|
||||
target_include_directories(YYCCommonplace
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cinttypes>
|
||||
#include "WinFctHelper.hpp"
|
||||
|
||||
#include "WinImportPrefix.hpp"
|
||||
#include <Windows.h>
|
||||
|
@ -14,33 +15,40 @@
|
|||
namespace YYCC::ExceptionHelper {
|
||||
|
||||
/**
|
||||
* @brief true if the exception handler already registered.
|
||||
* This variable is served for singleton.
|
||||
* @brief True if the exception handler already registered, otherwise false.
|
||||
* @details
|
||||
* This variable is designed to prevent multiple register operation
|
||||
* because unhandled exception handler should only be registered once.
|
||||
* \n
|
||||
* Register function should check whether this variable is false before registering,
|
||||
* and set this variable to true after registing.
|
||||
* Unregister as well as should do the same check.
|
||||
*/
|
||||
static bool g_IsRegistered = false;
|
||||
/**
|
||||
* @brief true if a exception handler is running.
|
||||
* @brief True if a exception handler is running, otherwise false.
|
||||
* @details
|
||||
* This variable is served for blocking possible infinity recursive exception handling.
|
||||
* \n
|
||||
* When entering unhandled exception handler, we must check whether this variable is true.
|
||||
* If it is true, it mean that there is another unhandled exception handler running.
|
||||
* Then we should exit immediately.
|
||||
* Otherwise, this variable should be set to true indicating we are processing unhandled exception.
|
||||
* After processing exception, at the end of unhandled exception handler,
|
||||
* we should restore this value to false.
|
||||
*
|
||||
*/
|
||||
static bool g_IsProcessing = false;
|
||||
/**
|
||||
* @brief The backup of original exception handler.
|
||||
* @details
|
||||
* This variable was set when registering unhandled exception handler.
|
||||
* And will be used when unregistering for restoring.
|
||||
*/
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER g_ProcBackup;
|
||||
static LPTOP_LEVEL_EXCEPTION_FILTER g_ProcBackup;
|
||||
|
||||
#pragma region Exception Handler Implementation
|
||||
|
||||
static HMODULE GetCurrentModule() {
|
||||
// Reference: https://stackoverflow.com/questions/557081/how-do-i-get-the-hmodule-for-the-currently-executing-code
|
||||
HMODULE hModule = NULL;
|
||||
GetModuleHandleExW(
|
||||
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, // get address and do not inc ref counter.
|
||||
(LPCWSTR)GetCurrentModule,
|
||||
&hModule);
|
||||
|
||||
return hModule;
|
||||
}
|
||||
|
||||
static const char* UExceptionGetCodeName(DWORD code) {
|
||||
switch (code) {
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
|
@ -241,7 +249,7 @@ namespace YYCC::ExceptionHelper {
|
|||
std::filesystem::path ironpad_path;
|
||||
WCHAR module_path[MAX_PATH];
|
||||
std::memset(module_path, 0, sizeof(module_path));
|
||||
if (GetModuleFileNameW(GetCurrentModule(), module_path, MAX_PATH) == 0) {
|
||||
if (GetModuleFileNameW(WinFctHelper::GetCurrentModule(), module_path, MAX_PATH) == 0) {
|
||||
goto failed;
|
||||
}
|
||||
ironpad_path = module_path;
|
||||
|
|
|
@ -6,12 +6,28 @@ namespace YYCC::ExceptionHelper {
|
|||
|
||||
/**
|
||||
* @brief Register unhandled exception handler
|
||||
* @detail This function frequently called at the start of program.
|
||||
* @details
|
||||
* This function will set an internal function as unhandled exception handler on Windows.
|
||||
* \n
|
||||
* When unhandled exception raised,
|
||||
* That internal function will output error stacktrace in standard output
|
||||
* and log file (located in temp folder), and also generate a dump file
|
||||
* in temp folder (for convenient debugging of developer when reporting bugs) if it can.
|
||||
* \n
|
||||
* This function usually is called at the start of program.
|
||||
* @remarks This function is Windows only.
|
||||
*/
|
||||
void Register();
|
||||
/**
|
||||
* @brief Unregiister unhandled exception handler
|
||||
* @detail This function frequently called at the end of program.
|
||||
* @brief Unregister unhandled exception handler
|
||||
* @details
|
||||
* The reverse operation of Register().
|
||||
* \n
|
||||
* This function and Register() should always be used as a pair.
|
||||
* You must call this function if you have called Register() before.
|
||||
* \n
|
||||
* This function usually is called at the end of program.
|
||||
* @remarks This function is Windows only.
|
||||
*/
|
||||
void Unregister();
|
||||
|
||||
|
|
78
src/WinFctHelper.cpp
Normal file
78
src/WinFctHelper.cpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
#include "WinFctHelper.hpp"
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
|
||||
#include "EncodingHelper.hpp"
|
||||
|
||||
namespace YYCC::WinFctHelper {
|
||||
|
||||
HMODULE GetCurrentModule() {
|
||||
// Reference: https://stackoverflow.com/questions/557081/how-do-i-get-the-hmodule-for-the-currently-executing-code
|
||||
HMODULE hModule = NULL;
|
||||
GetModuleHandleExW(
|
||||
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, // get address and do not inc ref counter.
|
||||
(LPCWSTR)GetCurrentModule,
|
||||
&hModule);
|
||||
|
||||
return hModule;
|
||||
}
|
||||
|
||||
std::string GetTempDirectory() {
|
||||
// create wchar buffer for receiving the temp path.
|
||||
std::wstring wpath(MAX_PATH + 1u, L'\0');
|
||||
DWORD expected_size;
|
||||
|
||||
// fetch temp folder
|
||||
while (true) {
|
||||
if ((expected_size = GetTempPathW(static_cast<DWORD>(wpath.size()), wpath.data())) == 0) {
|
||||
// failed, set to empty
|
||||
expected_size = 0;
|
||||
// and break while
|
||||
break;
|
||||
}
|
||||
|
||||
if (expected_size > static_cast<DWORD>(wpath.size())) {
|
||||
// buffer is too short, need enlarge and do fetching again
|
||||
wpath.resize(expected_size);
|
||||
} else {
|
||||
// ok. shrink to real length, break while
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// resize result
|
||||
wpath.resize(expected_size);
|
||||
// convert to utf8 and return
|
||||
return YYCC::EncodingHelper::WcharToUTF8(wpath.c_str());
|
||||
}
|
||||
|
||||
std::string GetModuleName(HINSTANCE hModule) {
|
||||
// create wchar buffer for receiving the temp path.
|
||||
std::wstring wpath(MAX_PATH + 1u, L'\0');
|
||||
DWORD copied_size;
|
||||
|
||||
while (true) {
|
||||
if ((copied_size = GetModuleFileNameW(hModule, wpath.data(), static_cast<DWORD>(wpath.size()))) == 0) {
|
||||
// failed, return empty string
|
||||
copied_size = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// check insufficient buffer
|
||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||||
// buffer is not enough, enlarge it and try again.
|
||||
wpath.resize(wpath.size() + MAX_PATH);
|
||||
} else {
|
||||
// ok, break while
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// resize result
|
||||
wpath.resize(copied_size);
|
||||
// convert to utf8 and return
|
||||
return YYCC::EncodingHelper::WcharToUTF8(wpath.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
43
src/WinFctHelper.hpp
Normal file
43
src/WinFctHelper.hpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
#include "YYCCInternal.hpp"
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "WinImportPrefix.hpp"
|
||||
#include <Windows.h>
|
||||
#include "WinImportSuffix.hpp"
|
||||
|
||||
namespace YYCC::WinFctHelper {
|
||||
|
||||
/**
|
||||
* @brief Get Windows used HANDLE for current module.
|
||||
* @details
|
||||
* If your target is EXE, the current module simply is your program self.
|
||||
* However, if your target is DLL, the current module is your DLL, not the EXE loading your DLL.
|
||||
* \n
|
||||
* This function is frequently used by DLL.
|
||||
* Because some design need the HANDLE of current module, not the host EXE loading your DLL.
|
||||
* For example, you may want to get the name of your built DLL at runtime, then you should pass current module HANDLE, not the HANDLE of EXE.
|
||||
* Or, if you want to get the path to your DLL, you also should pass current module HANDLE.
|
||||
* @return A Windows HANDLE pointing to current module, NULL if failed.
|
||||
*/
|
||||
HMODULE GetCurrentModule();
|
||||
|
||||
/**
|
||||
* @brief Get path to Windows temp folder.
|
||||
* @return UTF8 encoded path to Windows temp folder. Empty string if failed.
|
||||
*/
|
||||
std::string GetTempDirectory();
|
||||
|
||||
/**
|
||||
* @brief Get the file name of given module HANDLE
|
||||
* @param hModule[in]
|
||||
* The HANDLE to the module where we want get file name.
|
||||
* It is same as the HANDLE parameter of GetModuleFileName.
|
||||
* @return UTF8 encoded file name of given module. Empty string if failed.
|
||||
*/
|
||||
std::string GetModuleName(HINSTANCE hModule);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -7,3 +7,6 @@
|
|||
#include "ConsoleHelper.hpp"
|
||||
#include "DialogHelper.hpp"
|
||||
#include "ParserHelper.hpp"
|
||||
#include "ExceptionHelper.hpp"
|
||||
#include "IOHelper.hpp"
|
||||
#include "WinFctHelper.hpp"
|
||||
|
|
|
@ -215,11 +215,18 @@ namespace YYCCTestbench {
|
|||
}
|
||||
}
|
||||
|
||||
static void WinFctTestbench() {
|
||||
Console::WriteLine("Current Module HANDLE: 0x%016" PRIXPTR, YYCC::WinFctHelper::GetCurrentModule());
|
||||
Console::WriteLine("Temp Directory: %s", YYCC::WinFctHelper::GetTempDirectory().c_str());
|
||||
Console::WriteLine("Current Module Name: %s", YYCC::WinFctHelper::GetModuleName(YYCC::WinFctHelper::GetCurrentModule()).c_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char** args) {
|
||||
YYCCTestbench::ConsoleTestbench();
|
||||
//YYCCTestbench::ConsoleTestbench();
|
||||
//YYCCTestbench::StringTestbench();
|
||||
//YYCCTestbench::ParserTestbench();
|
||||
//YYCCTestbench::DialogTestbench();
|
||||
YYCCTestbench::WinFctTestbench();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user