最近项目里要重新编写程序加载器,也就是编译出一个可执行文件,在 Windows 上是 .exe
为什么要程序加载器?
个人理解是,可执行文件大小最好是越小越好,功能都可以由 dll 文件执行
而程序加载器里最重要的是两个 win32 函数,分别是 LoadLibrary 和 GetProcAddress
前者是加载 dll 并返回 instance 句柄,后者是从 instance 里提取所需的函数
我们从主 dll 中提取 wWinMain 函数入口,再执行 wWinMain 函数就可以执行程序了
旧版本的程序加载器也是简单依靠这两个函数加载特定的函数,但是在一个线上问题的排查中,发现程序加载器提示的错误消息太少了(只能依靠 MessageBox),导致我们无法快速定位到问题
所以我们新引入 sentry 模块,这个模块我们已经用于主程序了,现在在程序加载器中我们打算提取 sentry 的部分函数,用于上传错误事件
由于要提取很多函数,所以重复写 LoadLibrary 和 GetProcAddress 就显得代码比较臃肿,故要写一套比较简单复用的加载 dll 逻辑
参考 Nim 的逻辑,我们改进了一下
// load_dll.h #include <map> #include <string> #include <wtypes.h> class SDKInstance { public: SDKInstance(); virtual ~SDKInstance(); bool LoadSdkDll(const wchar_t* cur_module_dir, const wchar_t* sdk_dll_file_name); void UnloadSdkDll(); void* GetFunction(const std::string& function_name) { auto it = function_map_.find(function_name); if (it != function_map_.end()) { return it->second; } void* function_ptr = ::GetProcAddress(instance_, function_name.c_str()); function_map_[function_name] = function_ptr; return function_ptr; } private: HINSTANCE instance_; std::map<std::string, void*> function_map_; }; #define SDK_GET_FUNC(function_ptr, suffix, sdk_instance) \ ((function_ptr##suffix)sdk_instance->GetFunction(#function_ptr))
// load_dll.cpp #include "load_dll.h" SDKInstance::SDKInstance() { instance_ = nullptr; } SDKInstance::~SDKInstance() { UnloadSdkDll(); } bool SDKInstance::LoadSdkDll(const wchar_t *cur_module_dir, const wchar_t *sdk_dll_file_name) { std::wstring dir(cur_module_dir); dir.append(L"\\"); dir.append(sdk_dll_file_name); instance_ = LoadLibraryW(dir.c_str()); if (instance_ == nullptr) { return false; } return true; } void SDKInstance::UnloadSdkDll() { if (instance_) { FreeLibrary(instance_); instance_ = nullptr; } function_map_.clear(); }
main 函数使用:
#include "load_dll.h" #define SENTRY_GET_FUNC(function_ptr, sdk_instance) \ SDK_GET_FUNC(function_ptr, _func, sdk_instance) typedef decltype(sentry_options_new)* sentry_options_new_func; typedef decltype(sentry_options_set_handler_pathw)* sentry_options_set_handler_pathw_func; typedef decltype(sentry_options_set_dsn)* sentry_options_set_dsn_func; typedef decltype(sentry_options_set_system_crash_reporter_enabled)* sentry_options_set_system_crash_reporter_enabled_func; typedef decltype(sentry_options_set_environment)* sentry_options_set_environment_func; typedef decltype(sentry_options_set_debug)* sentry_options_set_debug_func; typedef decltype(sentry_init)* sentry_init_func; typedef decltype(sentry_set_tag)* sentry_set_tag_func; typedef decltype(sentry_value_new_message_event)* sentry_value_new_message_event_func; typedef decltype(sentry_capture_event)* sentry_capture_event_func; bool SendToSentry(PCWSTR dll_directory, PCWSTR current_version, const std::string& log, sentry_level_t level, SDKInstance* sdk_instance) { if (sdk_instance == nullptr || !sdk_instance->LoadSdkDll(dll_directory, L"sentry.dll")) { return false; } sentry_options_t* options = SENTRY_GET_FUNC(sentry_options_new, sdk_instance)(); auto crashpad_handler_path = std::wstring(dll_directory) + L"\\crashpad_handler.exe"; SENTRY_GET_FUNC(sentry_options_set_handler_pathw, sdk_instance) (options, crashpad_handler_path.c_str()); SENTRY_GET_FUNC(sentry_options_set_dsn, sdk_instance)(options, kSentryDsn); SENTRY_GET_FUNC(sentry_options_set_system_crash_reporter_enabled, sdk_instance)(options, 1); #if defined(NDEBUG) SENTRY_GET_FUNC(sentry_options_set_environment, sdk_instance) (options, "production"); #else SENTRY_GET_FUNC(sentry_options_set_environment, sdk_instance) (options, "staging"); SENTRY_GET_FUNC(sentry_options_set_debug, sdk_instance)(options, 1); #endif auto ret = SENTRY_GET_FUNC(sentry_init, sdk_instance)(options); if (ret != 0) { return false; } auto version = WideToUTF8(current_version); SENTRY_GET_FUNC(sentry_set_tag, sdk_instance)("version", version.c_str()); auto event = SENTRY_GET_FUNC(sentry_value_new_message_event, sdk_instance)( level, nullptr, log.c_str()); SENTRY_GET_FUNC(sentry_capture_event, sdk_instance)(event); return true; } int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); ... sentry_instance = std::make_unique<SDKInstance>(); SendToSentry(dll_path.c_str(), current_version.c_str(),"Load xxx.dll failed", SENTRY_LEVEL_FATAL, sentry_instance.get()); ... return 1; }
标签:set,sentry,C++,Dll,instance,API,dll,options,sdk From: https://www.cnblogs.com/strive-sun/p/17900895.html