#pragma once #include "../Include/Types.h" #include "../Include/Winheaders.h" #include "Utils.h" #include "InitOnce.h" #include namespace blackbone { /// /// Dynamic import /// class DynImport { public: BLACKBONE_API static DynImport& Instance() { static DynImport instance; return instance; } DynImport() = default; DynImport( const DynImport& ) = delete; /// /// Get dll function /// /// Function name /// Function pointer template T get( const std::string& name ) { InitializeOnce(); CSLock lck( _mapGuard ); auto iter = _funcs.find( name ); if (iter != _funcs.end()) return reinterpret_cast(iter->second); return nullptr; } /// /// Safely call import /// If import not found - return STATUS_ORDINAL_NOT_FOUND /// /// Import name. /// Function args /// Function result or STATUS_ORDINAL_NOT_FOUND if import not found template NTSTATUS safeNativeCall( const std::string& name, Args&&... args ) { auto pfn = DynImport::get( name ); return pfn ? pfn( std::forward( args )... ) : STATUS_ORDINAL_NOT_FOUND; } /// /// Safely call import /// If import not found - return 0 /// /// Import name. /// Function args /// Function result or 0 if import not found template auto safeCall( const std::string& name, Args&&... args ) { auto pfn = DynImport::get( name ); return pfn ? pfn( std::forward( args )... ) : std::invoke_result_t(); } /// /// Load function into database /// /// Function name /// Module name /// true on success BLACKBONE_API FARPROC load( const std::string& name, const std::wstring& module ) { auto mod = GetModuleHandleW( module.c_str() ); return load( name, mod ); } /// /// Load function into database /// /// Function name /// Module base /// true on success BLACKBONE_API FARPROC load( const std::string& name, HMODULE hMod ) { CSLock lck( _mapGuard ); auto proc = GetProcAddress( hMod, name.c_str() ); if (proc) { _funcs.insert( std::make_pair( name, proc ) ); return proc; } return nullptr; } private: std::unordered_map _funcs; // function database CriticalSection _mapGuard; // function database guard }; // Syntax sugar #define LOAD_IMPORT(name, module) (DynImport::Instance().load( name, module )) #define GET_IMPORT(name) (DynImport::Instance().get( #name )) #define SAFE_NATIVE_CALL(name, ...) (DynImport::Instance().safeNativeCall( #name, __VA_ARGS__ )) #define SAFE_CALL(name, ...) (DynImport::Instance().safeCall( #name, __VA_ARGS__ )) }