feat: add some work
- add dialog parameter class for dialog helper. prepare to write real dialog popup function. - refactor file filters class in dialog helper to make it no const syntax conflict. - improve windows header import prefix and suffix header. remove the barrier limiting headers only can be imported once. fix define preprocessor usage bug. - move crt warning and errors macro from project settings to internal headers. - copy IronPad as ExceptionHandler but not adapted to this project.
This commit is contained in:
parent
359aff82ac
commit
84228b5f8c
|
@ -27,53 +27,52 @@ namespace YYCC::DialogHelper {
|
|||
return true;
|
||||
}
|
||||
|
||||
void FileFilters::Clear() {
|
||||
m_Filters.clear();
|
||||
}
|
||||
bool FileFilters::Generate(WinFileFilters& win_result) const {
|
||||
// clear Windows oriented data
|
||||
win_result.m_WinDataStruct.reset();
|
||||
win_result.m_WinFilters.clear();
|
||||
|
||||
bool FileFilters::Generate(UINT& filter_count, COMDLG_FILTERSPEC*& filter_specs) {
|
||||
// init defualt value to prevent the scenario that caller do not check return value.
|
||||
filter_count = 0u;
|
||||
filter_specs = nullptr;
|
||||
|
||||
// clear win string vector and build new one
|
||||
m_WinFilters.clear();
|
||||
// build new Windows oriented string vector first
|
||||
for (const auto& it : m_Filters) {
|
||||
// convert name to wchar
|
||||
WinFilterName name;
|
||||
WinFileFilters::WinFilterName name;
|
||||
if (!YYCC::EncodingHelper::UTF8ToWchar(it.first.c_str(), name))
|
||||
return false;
|
||||
|
||||
// convert pattern and join them
|
||||
std::string joined_modes(YYCC::StringHelper::Join(it.second, u8";"));
|
||||
WinFilterModes modes;
|
||||
WinFileFilters::WinFilterModes modes;
|
||||
if (!YYCC::EncodingHelper::UTF8ToWchar(joined_modes.c_str(), modes))
|
||||
return false;
|
||||
|
||||
// append new pair
|
||||
m_WinFilters.emplace_back(std::make_pair(name, modes));
|
||||
win_result.m_WinFilters.emplace_back(std::make_pair(name, modes));
|
||||
}
|
||||
|
||||
// check filter size
|
||||
// if it overflow the maximum value, return false
|
||||
size_t count = m_WinFilters.size();
|
||||
size_t count = win_result.m_WinFilters.size();
|
||||
if (count > std::numeric_limits<UINT>::max())
|
||||
return false;
|
||||
|
||||
// create new win data struct
|
||||
// and assign string pointer from internal built win string vector.
|
||||
m_WinDataStruct.reset(new COMDLG_FILTERSPEC[count]);
|
||||
win_result.m_WinDataStruct.reset(new COMDLG_FILTERSPEC[count]);
|
||||
for (size_t i = 0u; i < count; ++i) {
|
||||
m_WinDataStruct[i].pszName = m_WinFilters[i].first.c_str();
|
||||
m_WinDataStruct[i].pszSpec = m_WinFilters[i].second.c_str();
|
||||
win_result.m_WinDataStruct[i].pszName = win_result.m_WinFilters[i].first.c_str();
|
||||
win_result.m_WinDataStruct[i].pszSpec = win_result.m_WinFilters[i].second.c_str();
|
||||
}
|
||||
|
||||
// set return value
|
||||
filter_count = static_cast<UINT>(count);
|
||||
filter_specs = m_WinDataStruct.get();
|
||||
// everything is okey
|
||||
return true;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region FileDialog
|
||||
|
||||
|
||||
|
||||
#pragma endregion
|
||||
|
||||
|
||||
|
|
|
@ -15,15 +15,39 @@
|
|||
|
||||
namespace YYCC::DialogHelper {
|
||||
|
||||
/**
|
||||
* @brief The class represent the file types region in file dialog
|
||||
* @details THis class is specific for Windows use, not user oriented.
|
||||
*/
|
||||
class WinFileFilters {
|
||||
friend class FileFilters;
|
||||
public:
|
||||
WinFileFilters() : m_WinFilters(), m_WinDataStruct(nullptr) {}
|
||||
|
||||
UINT GetFilterCount() const {
|
||||
return static_cast<UINT>(m_WinFilters.size());
|
||||
}
|
||||
const COMDLG_FILTERSPEC* GetFilterSpecs() const {
|
||||
return m_WinDataStruct.get();
|
||||
}
|
||||
|
||||
protected:
|
||||
using WinFilterModes = std::wstring;
|
||||
using WinFilterName = std::wstring;
|
||||
using WinFilterPair = std::pair<WinFilterName, WinFilterModes>;
|
||||
|
||||
std::vector<WinFilterPair> m_WinFilters;
|
||||
std::unique_ptr<COMDLG_FILTERSPEC[]> m_WinDataStruct;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The class represent the file types region in file dialog.
|
||||
* @details THis class is user oriented. User can use function manipulate file types
|
||||
* and final fialog function will produce Windows-understood data struct from this.
|
||||
*/
|
||||
class FileFilters {
|
||||
public:
|
||||
FileFilters() :
|
||||
m_Filters(),
|
||||
m_WinFilters(), m_WinDataStruct(nullptr)
|
||||
{}
|
||||
FileFilters() : m_Filters(){}
|
||||
|
||||
/**
|
||||
* @brief Add a filter pair in file types list.
|
||||
|
@ -40,16 +64,19 @@ namespace YYCC::DialogHelper {
|
|||
/**
|
||||
* @brief Clear filter pairs for following re-use.
|
||||
*/
|
||||
void Clear();
|
||||
void Clear() { m_Filters.clear(); }
|
||||
/**
|
||||
* @brief Get the count of added filter pairs.
|
||||
* @return The count of already added filter pairs.
|
||||
*/
|
||||
size_t Count() const { return m_Filters.size(); }
|
||||
|
||||
/**
|
||||
* @brief Generate Windows dialog system used data struct.
|
||||
* @param filter_count[out] The count of generated filter data struct.
|
||||
* @param filter_specs[out] The pointer to generated filter data struct.
|
||||
* @remarks User should not call this function. This function is used by internal functions.
|
||||
* @param win_result[out] The class holding the generated filter data struct.
|
||||
* @return True if generation is success, otherwise false.
|
||||
*/
|
||||
bool Generate(UINT& filter_count, COMDLG_FILTERSPEC*& filter_specs);
|
||||
bool Generate(WinFileFilters& win_result) const;
|
||||
|
||||
protected:
|
||||
using FilterModes = std::vector<std::string>;
|
||||
|
@ -57,45 +84,70 @@ namespace YYCC::DialogHelper {
|
|||
using FilterPair = std::pair<FilterName, FilterModes>;
|
||||
|
||||
std::vector<FilterPair> m_Filters;
|
||||
|
||||
using WinFilterModes = std::wstring;
|
||||
using WinFilterName = std::wstring;
|
||||
using WinFilterPair = std::pair<WinFilterName, WinFilterModes>;
|
||||
|
||||
std::vector<WinFilterPair> m_WinFilters;
|
||||
std::unique_ptr<COMDLG_FILTERSPEC[]> m_WinDataStruct;
|
||||
};
|
||||
|
||||
//struct FileDialogParameter {
|
||||
// FileDialogParameter() :
|
||||
// m_Owner(nullptr),
|
||||
// m_Filter(), m_SelectedFilter(0),
|
||||
// m_Title(),
|
||||
// m_DefaultExtension(), m_InitialDirectory(), m_InitialFileName() {}
|
||||
class FileDialog {
|
||||
public:
|
||||
FileDialog() :
|
||||
m_Owner(NULL), m_Title(),
|
||||
m_FileTypes(),
|
||||
m_DefaultFileTypeIndex(0u),
|
||||
m_InitFileName(), m_InitDirectory() {}
|
||||
|
||||
// HWND m_Owner;
|
||||
// std::vector<std::pair<std::string, std::string>> m_Filter;
|
||||
// size_t m_SelectedFilter;
|
||||
// std::string m_Title;
|
||||
// std::string m_DefaultExtension;
|
||||
// std::string m_InitialFileName;
|
||||
// std::string m_InitialDirectory;
|
||||
//};
|
||||
void SetOwner(HWND owner) { m_Owner = owner; }
|
||||
HWND GetOwner() const { return m_Owner; }
|
||||
|
||||
//struct FolderDialogParameter {
|
||||
// FolderDialogParameter() :
|
||||
// m_Owner(nullptr),
|
||||
// m_Title() {}
|
||||
void SetTitle(const char* title) {
|
||||
if (title == nullptr) m_Title.clear();
|
||||
else m_Title = title;
|
||||
}
|
||||
const char* GetTitle() const {
|
||||
if (m_Title.empty()) return nullptr;
|
||||
else return m_Title.c_str();
|
||||
}
|
||||
|
||||
// HWND m_Owner;
|
||||
// std::string m_Title;
|
||||
//};
|
||||
FileFilters& GetFileTypes() {
|
||||
return m_FileTypes;
|
||||
}
|
||||
const FileFilters& GetFileTypes() const {
|
||||
return m_FileTypes;
|
||||
}
|
||||
|
||||
//bool OpenFileDialog(const FileDialogParameter& params, std::string& ret);
|
||||
//bool OpenMultipleFileDialog(const FileDialogParameter& params, std::vector<std::string>& ret);
|
||||
//bool SaveFileDialog(const FileDialogParameter& params, std::string& ret);
|
||||
void SetDefaultFileTypeIndex(UINT idx) { m_DefaultFileTypeIndex = idx; }
|
||||
UINT GetDefaultFileTypeIndex() const { return m_DefaultFileTypeIndex; }
|
||||
|
||||
//bool OpenFolderDialog(const FolderDialogParameter& params, std::string& ret);
|
||||
void SetInitFileName(const char* init_filename) {
|
||||
if (init_filename == nullptr) m_InitFileName.clear();
|
||||
else m_InitFileName = init_filename;
|
||||
}
|
||||
const char* GetInitFileName() const {
|
||||
if (m_InitFileName.empty()) return nullptr;
|
||||
else return m_InitFileName.c_str();
|
||||
}
|
||||
|
||||
void SetInitDirectory(const char* init_dir) {
|
||||
if (init_dir == nullptr) m_InitDirectory.clear();
|
||||
else m_InitDirectory = init_dir;
|
||||
}
|
||||
const char* GetInitDirectory() const {
|
||||
if (m_InitDirectory.empty()) return nullptr;
|
||||
else return m_InitDirectory.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
HWND m_Owner;
|
||||
std::string m_Title;
|
||||
FileFilters m_FileTypes;
|
||||
UINT m_DefaultFileTypeIndex;
|
||||
std::string m_InitFileName;
|
||||
std::string m_InitDirectory;
|
||||
};
|
||||
|
||||
bool OpenFileDialog(const FileDialog& params, std::string& ret);
|
||||
bool OpenMultipleFileDialog(const FileDialog& params, std::vector<std::string>& ret);
|
||||
bool SaveFileDialog(const FileDialog& params, std::string& ret);
|
||||
|
||||
bool OpenFolderDialog(const FileDialog& params, std::string& ret);
|
||||
|
||||
}
|
||||
|
||||
|
|
325
src/ExceptionHelper.cpp
Normal file
325
src/ExceptionHelper.cpp
Normal file
|
@ -0,0 +1,325 @@
|
|||
#include "ExceptionHelper.hpp"
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
|
||||
#include <filesystem>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cinttypes>
|
||||
|
||||
#include "WinImportPrefix.hpp"
|
||||
#include <Windows.h>
|
||||
#include <DbgHelp.h>
|
||||
#include "WinImportSuffix.hpp"
|
||||
|
||||
namespace YYCC::ExceptionHelper {
|
||||
|
||||
/**
|
||||
* @brief true if the exception handler already registered.
|
||||
* This variable is served for singleton.
|
||||
*/
|
||||
static bool g_IsRegistered = false;
|
||||
/**
|
||||
* @brief true if a exception handler is running.
|
||||
* This variable is served for blocking possible infinity recursive exception handling.
|
||||
*/
|
||||
static bool g_IsProcessing = false;
|
||||
/**
|
||||
* @brief The backup of original exception handler.
|
||||
*/
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER g_ProcBackup;
|
||||
|
||||
#pragma region Exception Handler Detail
|
||||
|
||||
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:
|
||||
return "access violation";
|
||||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
||||
return "array index out of bound";
|
||||
case EXCEPTION_BREAKPOINT:
|
||||
return "breakpoint reached";
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
||||
return "misaligned data access";
|
||||
case EXCEPTION_FLT_DENORMAL_OPERAND:
|
||||
return "operand had denormal value";
|
||||
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
||||
return "floating-point division by zero";
|
||||
case EXCEPTION_FLT_INEXACT_RESULT:
|
||||
return "no decimal fraction representation for value";
|
||||
case EXCEPTION_FLT_INVALID_OPERATION:
|
||||
return "invalid floating-point operation";
|
||||
case EXCEPTION_FLT_OVERFLOW:
|
||||
return "floating-point overflow";
|
||||
case EXCEPTION_FLT_STACK_CHECK:
|
||||
return "floating-point stack corruption";
|
||||
case EXCEPTION_FLT_UNDERFLOW:
|
||||
return "floating-point underflow";
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
return "illegal instruction";
|
||||
case EXCEPTION_IN_PAGE_ERROR:
|
||||
return "inaccessible page";
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||
return "integer division by zero";
|
||||
case EXCEPTION_INT_OVERFLOW:
|
||||
return "integer overflow";
|
||||
case EXCEPTION_INVALID_DISPOSITION:
|
||||
return "documentation says this should never happen";
|
||||
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
|
||||
return "can't continue after a noncontinuable exception";
|
||||
case EXCEPTION_PRIV_INSTRUCTION:
|
||||
return "attempted to execute a privileged instruction";
|
||||
case EXCEPTION_SINGLE_STEP:
|
||||
return "one instruction has been executed";
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
return "stack overflow";
|
||||
default:
|
||||
return "unknown exception";
|
||||
}
|
||||
}
|
||||
|
||||
static void UExceptionFormat(std::FILE* fs, const char* fmt, ...) {
|
||||
// write to file
|
||||
va_list arg1;
|
||||
va_start(arg1, fmt);
|
||||
std::vfprintf(fs, fmt, arg1);
|
||||
va_end(arg1);
|
||||
// write to stdout
|
||||
va_list arg2;
|
||||
va_start(arg2, fmt);
|
||||
std::vfprintf(stdout, fmt, arg2);
|
||||
va_end(arg2);
|
||||
}
|
||||
|
||||
static void UExceptionPrint(std::FILE* fs, const char* strl) {
|
||||
// write to file
|
||||
std::fputs(strl, fs);
|
||||
// write to stdout
|
||||
std::fputs(strl, stdout);
|
||||
}
|
||||
|
||||
static void UExceptionBacktrace(FILE* fs, LPCONTEXT context, int maxdepth) {
|
||||
// setup loading symbol options
|
||||
SymSetOptions(SymGetOptions() | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); // lazy load symbol, and load line number.
|
||||
|
||||
// setup handle
|
||||
HANDLE process = GetCurrentProcess();
|
||||
HANDLE thread = GetCurrentThread();
|
||||
|
||||
// init symbol
|
||||
if (!SymInitialize(process, 0, TRUE)) {
|
||||
// fail to load. return
|
||||
UExceptionPrint(fs, "Lost symbol file!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// ========== CORE DUMP ==========
|
||||
// prepare frame. setup correct fields
|
||||
// references:
|
||||
// https://github.com/rust-lang/backtrace-rs/blob/9ed25b581cfd2ee60e5a3b9054fd023bf6dced90/src/backtrace/dbghelp.rs
|
||||
// https://sourceforge.net/p/predef/wiki/Architectures/
|
||||
DWORD machine_type = 0;
|
||||
STACKFRAME64 frame;
|
||||
memset(&frame, 0, sizeof(frame));
|
||||
#if defined(_M_IX86) || defined(__i386__)
|
||||
// x86
|
||||
machine_type = IMAGE_FILE_MACHINE_I386;
|
||||
frame.AddrPC.Offset = context->Eip;
|
||||
frame.AddrStack.Offset = context->Esp;
|
||||
frame.AddrFrame.Offset = context->Ebp;
|
||||
#elif defined(_M_AMD64) || defined(__amd64__)
|
||||
// amd64
|
||||
machine_type = IMAGE_FILE_MACHINE_AMD64;
|
||||
frame.AddrPC.Offset = context->Rip;
|
||||
frame.AddrStack.Offset = context->Rsp;
|
||||
frame.AddrFrame.Offset = context->Rbp;
|
||||
#elif defined(_M_ARM) || defined(__arm__)
|
||||
// arm (32bit)
|
||||
machine_type = IMAGE_FILE_MACHINE_ARMNT;
|
||||
frame.AddrPC.Offset = context->Pc;
|
||||
frame.AddrStack.Offset = context->Sp;
|
||||
frame.AddrFrame.Offset = context->R11;
|
||||
#elif defined(_M_ARM64) || defined(__aarch64__)
|
||||
// arm64
|
||||
machine_type = IMAGE_FILE_MACHINE_ARM64;
|
||||
frame.AddrPC.Offset = context->Pc;
|
||||
frame.AddrStack.Offset = context->Sp;
|
||||
frame.AddrFrame.Offset = context->DUMMYUNIONNAME.DUMMYSTRUCTNAME.Fp;
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
//IA-64 anybody?
|
||||
|
||||
#endif
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
|
||||
// other variables
|
||||
char module_name_raw[MAX_PATH];
|
||||
|
||||
// stack walker
|
||||
while (StackWalk64(machine_type, process, thread, &frame, context,
|
||||
0, SymFunctionTableAccess64, SymGetModuleBase64, 0)) {
|
||||
|
||||
// depth breaker
|
||||
--maxdepth;
|
||||
if (maxdepth < 0) {
|
||||
UExceptionPrint(fs, "...\n"); // indicate there are some frames not listed
|
||||
break;
|
||||
}
|
||||
|
||||
// get module name
|
||||
DWORD64 module_base = SymGetModuleBase64(process, frame.AddrPC.Offset);
|
||||
const char* module_name = "[unknown module]";
|
||||
if (module_base && GetModuleFileNameA((HINSTANCE)module_base, module_name_raw, MAX_PATH)) {
|
||||
module_name = module_name_raw;
|
||||
}
|
||||
|
||||
// get source file and line
|
||||
const char* source_file = "[unknow_source_file]";
|
||||
DWORD64 source_file_line = 0;
|
||||
DWORD dwDisplacement;
|
||||
IMAGEHLP_LINE64 winline;
|
||||
winline.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &dwDisplacement, &winline)) {
|
||||
source_file = winline.FileName;
|
||||
source_file_line = winline.LineNumber;
|
||||
}
|
||||
|
||||
// write to file
|
||||
UExceptionFormat(fs, "0x%016llx(rel: 0x%016llx)[%s]\t%s#%llu\n",
|
||||
frame.AddrPC.Offset, frame.AddrPC.Offset - module_base, module_name,
|
||||
source_file, source_file_line
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// ========== END CORE DUMP ==========
|
||||
|
||||
// free symbol
|
||||
SymCleanup(process);
|
||||
}
|
||||
|
||||
static void UExceptionCoreDump(LPCWSTR filename, LPEXCEPTION_POINTERS info) {
|
||||
// open file and write
|
||||
HANDLE hFile = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile != INVALID_HANDLE_VALUE) {
|
||||
MINIDUMP_EXCEPTION_INFORMATION exception_info;
|
||||
exception_info.ThreadId = GetCurrentThreadId();
|
||||
exception_info.ExceptionPointers = info;
|
||||
exception_info.ClientPointers = TRUE;
|
||||
MiniDumpWriteDump(
|
||||
GetCurrentProcess(), GetCurrentProcessId(), hFile,
|
||||
MiniDumpNormal,
|
||||
&exception_info,
|
||||
NULL, NULL
|
||||
);
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
}
|
||||
|
||||
static LONG WINAPI UExceptionImpl(LPEXCEPTION_POINTERS info) {
|
||||
// detect loop calling
|
||||
if (g_IsProcessing) {
|
||||
goto end_proc;
|
||||
}
|
||||
// start process
|
||||
g_IsProcessing = true;
|
||||
|
||||
{
|
||||
// get main folder first
|
||||
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) {
|
||||
goto failed;
|
||||
}
|
||||
ironpad_path = module_path;
|
||||
ironpad_path = ironpad_path.parent_path();
|
||||
|
||||
// create 2 filename
|
||||
auto logfilename = ironpad_path / "IronPad.log";
|
||||
auto dmpfilename = ironpad_path / "IronPad.dmp";
|
||||
std::fputc('\n', stdout);
|
||||
std::fprintf(stdout, "Exception Log: %s\n", logfilename.string().c_str());
|
||||
std::fprintf(stdout, "Exception Coredump: %s\n", dmpfilename.string().c_str());
|
||||
|
||||
// output log file
|
||||
{
|
||||
std::FILE* fs = _wfopen(logfilename.wstring().c_str(), L"w");
|
||||
if (fs == nullptr) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
// record exception type first
|
||||
PEXCEPTION_RECORD rec = info->ExceptionRecord;
|
||||
fprintf(fs, "Unhandled exception occured at 0x%08p: %s (%lu).\n",
|
||||
rec->ExceptionAddress,
|
||||
UExceptionGetCodeName(rec->ExceptionCode),
|
||||
rec->ExceptionCode
|
||||
);
|
||||
|
||||
// special proc for 2 exceptions
|
||||
if (rec->ExceptionCode == EXCEPTION_ACCESS_VIOLATION || rec->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) {
|
||||
if (rec->NumberParameters >= 2) {
|
||||
const char* op =
|
||||
rec->ExceptionInformation[0] == 0 ? "read" :
|
||||
rec->ExceptionInformation[0] == 1 ? "written" : "executed";
|
||||
fprintf(fs, "The data at memory address 0x%016" PRIxPTR " could not be %s.\n",
|
||||
rec->ExceptionInformation[1], op);
|
||||
}
|
||||
}
|
||||
|
||||
// output stacktrace
|
||||
UExceptionBacktrace(fs, info->ContextRecord, 1024);
|
||||
|
||||
std::fclose(fs);
|
||||
}
|
||||
|
||||
// output minidump
|
||||
{
|
||||
UExceptionCoreDump(dmpfilename.wstring().c_str(), info);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// end process
|
||||
failed:
|
||||
g_IsProcessing = false;
|
||||
// if backup proc can be run, run it
|
||||
// otherwise directly return.
|
||||
end_proc:
|
||||
if (g_ProcBackup != nullptr) {
|
||||
return g_ProcBackup(info);
|
||||
} else {
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
void Register() {
|
||||
if (g_IsRegistered) return;
|
||||
g_ProcBackup = SetUnhandledExceptionFilter(UExceptionImpl);
|
||||
g_IsRegistered = true;
|
||||
}
|
||||
|
||||
void Unregister() {
|
||||
if (!g_IsRegistered) return;
|
||||
SetUnhandledExceptionFilter(g_ProcBackup);
|
||||
g_IsRegistered = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
20
src/ExceptionHelper.hpp
Normal file
20
src/ExceptionHelper.hpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
#include "YYCCInternal.hpp"
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
|
||||
namespace YYCC::ExceptionHelper {
|
||||
|
||||
/**
|
||||
* @brief Register unhandled exception handler
|
||||
* @detail This function frequently called at the start of program.
|
||||
*/
|
||||
void Register();
|
||||
/**
|
||||
* @brief Unregiister unhandled exception handler
|
||||
* @detail This function frequently called at the end of program.
|
||||
*/
|
||||
void Unregister();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,11 +1,19 @@
|
|||
#pragma once
|
||||
// It is by design that no pragma once or #if to prevent deplicated including.
|
||||
// Because this header is the part of wrapper, not a real header.
|
||||
// #pragma once
|
||||
|
||||
#include "YYCCInternal.hpp"
|
||||
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
|
||||
// Define 2 macros to disallow Windows generate MIN and MAX macros
|
||||
// which cause std::min and std::max can not function as normal.
|
||||
#if !defined(WIN32_LEAN_AND_MEAN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#if !defined(NOMINMAX)
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,4 +1,7 @@
|
|||
#pragma once
|
||||
// It is by design that no pragma once or #if to prevent deplicated including.
|
||||
// Because this header is the part of wrapper, not a real header.
|
||||
// #pragma once
|
||||
|
||||
#include "YYCCInternal.hpp"
|
||||
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
|
@ -6,6 +9,8 @@
|
|||
// Windows also will generate following macros
|
||||
// which may cause the function sign is different in Windows and other platforms.
|
||||
// So we simply remove them.
|
||||
// Because #undef will not throw error if there are no matched macro,
|
||||
// so we simply #undef them directly.
|
||||
#undef GetObject
|
||||
#undef GetClassName
|
||||
#undef LoadImage
|
||||
|
|
|
@ -10,6 +10,20 @@
|
|||
#define YYCC_OS YYCC_OS_LINUX
|
||||
#endif
|
||||
|
||||
// If we are in Windows,
|
||||
// we need add 2 macros to disable Windows shitty warnings and errors of
|
||||
// depracted functions and not secure functions.
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
|
||||
#if !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#if !defined(_CRT_NONSTDC_NO_DEPRECATE)
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//// Decide the char type we used
|
||||
//#include <string>
|
||||
//namespace YYCC {
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
|
||||
|
@ -110,7 +110,7 @@
|
|||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
|
||||
|
@ -126,7 +126,7 @@
|
|||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
|
||||
|
@ -142,7 +142,7 @@
|
|||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
|
||||
|
@ -157,6 +157,7 @@
|
|||
<ItemGroup>
|
||||
<ClInclude Include="DialogHelper.hpp" />
|
||||
<ClInclude Include="EncodingHelper.hpp" />
|
||||
<ClInclude Include="ExceptionHelper.hpp" />
|
||||
<ClInclude Include="IOHelper.hpp" />
|
||||
<ClInclude Include="ParserHelper.hpp" />
|
||||
<ClInclude Include="StringHelper.hpp" />
|
||||
|
@ -169,6 +170,7 @@
|
|||
<ItemGroup>
|
||||
<ClCompile Include="DialogHelper.cpp" />
|
||||
<ClCompile Include="EncodingHelper.cpp" />
|
||||
<ClCompile Include="ExceptionHelper.cpp" />
|
||||
<ClCompile Include="IOHelper.cpp" />
|
||||
<ClCompile Include="ParserHelper.cpp" />
|
||||
<ClCompile Include="StringHelper.cpp" />
|
||||
|
|
|
@ -45,6 +45,9 @@
|
|||
<ClInclude Include="DialogHelper.hpp">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ExceptionHelper.hpp">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="StringHelper.cpp">
|
||||
|
@ -65,5 +68,8 @@
|
|||
<ClCompile Include="DialogHelper.cpp">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ExceptionHelper.cpp">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -60,9 +60,8 @@ namespace Testbench {
|
|||
test.Add("Text File (*.*)", {"*.txt"});
|
||||
test.Add("All Files (*.*)", {"*.*"});
|
||||
|
||||
UINT count;
|
||||
COMDLG_FILTERSPEC* specs;
|
||||
bool ret = test.Generate(count, specs);
|
||||
YYCC::DialogHelper::WinFileFilters win_file_filters;
|
||||
bool ret = test.Generate(win_file_filters);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user