Exetools

Exetools (https://forum.exetools.com/index.php)
-   Source Code (https://forum.exetools.com/forumdisplay.php?f=46)
-   -   [C] Winapi Call Dynamically and easily (https://forum.exetools.com/showthread.php?t=18714)

dosprog 04-06-2018 07:08

Quote:

Originally Posted by 0xall0c (Post 112899)
see the function prototype you defined, when there are lot functions to call, that's an extra headache.

It's programming..

In MASM32 we can invoke function using prototype or call function without prototype.
I tend to use the invoke.
It is convenient, however it is necessary to get used to.



0xall0c 04-06-2018 15:44

its just one more way to call api's, i am just saying use it if you want to else dont. i never said it is the best way to call an api, it is just another way. as i said previously it is subjective you like your own way of programming same way everyone like thiers.

IT IS JUST ONE ANOTHER WAY OF DOING IT.

mcp 04-06-2018 16:50

Sure, it's another way of doing it (i never questioned that), and I argued rationally why it doesn't give significant benefits, what it's downsides are, and thus why it isn't worth the trouble.
If you don't want your advice to be discussed and have the pros & cons be weighted against each other, then why even post it? This forum obviously should foster technical discussions, which is exactly what i did.

Note that not everyone has the ability to discriminate good from bad solutions, so it's valuable to have these kinds of discussions in order to avoid spreading non-ideal solutions.

Also, no need for screaming...

dosprog 04-06-2018 17:45

1 Attachment(s)
Quote:

Originally Posted by 0xall0c (Post 112913)
IT IS JUST ONE ANOTHER WAY OF DOING IT.

) Ok.
I'm written once more usage example of DynCall(). [minor fixed]

See attached archive.

Also it is here - Pass: exetools



mcp 04-06-2018 17:51

Taking what I said previously into account, a much safer variant could look like this:

Code:

template < typename RetType, typename... ArgTypes >
RetType DynCall(const char* dll_name, const char* api_name, ArgTypes...args) {
  typedef RetType(__stdcall* F)(ArgTypes...);
  HMODULE module = LoadLibrary(dll_name);
  assert(module != INVALID_MODULE_HANDLE && "Failed to load library");
  F fptr = (F)GetProcAddress(module, api_name);
  assert(fptr && "Unable to resolve API");
  return fptr(args...);
}

Usage would look like this:

Code:

int main() {
  std::cout << "GetTickCount1: "
            << DynCal< DWORD >("kernel32.dll", "GetTickCount") << "\n";
  DynCall< VOID, DWORD >("kernel32.dll", "Sleep", 1000);
  std::cout << "GetTickCount2: "
            << DynCall< DWORD >("kernel32.dll", "GetTickCount") << "\n"
}


produces this output:
Code:

GetTickCount1: 16462234
GetTickCount2: 16463250
Press any key to continue . . .

The first template argument specifies the return type of the API, after that you pass the argument types. Note that the function assumes stdcall!

The advantage here is that the compiler does all the type checking for you, so this cannot fail unless you mess up the function prototype itself - but that problem cannot be fixed anyhow unless we're using a correct import library which would defeat the whole purpose of this exercise.

Things to improve:
  • Throw an exception if loading library or resolving the function fails. Alternatively, wrap the result into std::optional so callers are aware they need to check for error.
  • Add string type as template param so code is agnostic of whether compiled with unicode or MBCS.
  • Invoke FreeLibrary after API was invoked; possibly add an overload that takes an already loaded library handle without freeing it (i.e. do not transfer ownership).

Edit: the template argument do not display correctly due to forum system :/ I fixed it by adding a blank to the template arguments, now it displays correctly.

0xall0c 04-06-2018 18:05

sorry for taking criticism in a wrong way, thank you, for your valuable opinions, they are appreciated.

appologies

mcp 04-06-2018 18:36

absolutely no worries :)

mcp 04-06-2018 18:50

Another idea worth exploring could be to return a functor from DynCall (instead of invoking the API directly). The functor would basically just capture the function pointer in the c'tor, and provide an overloaded operator(), so the user could call the same API as often as they like (it would also make the code more readable). The functor could then invoke FreeLibrary in the d'tor to free the OS resources.

0xall0c 04-06-2018 19:45

that would be nice.

bugficks 04-09-2018 08:30

1 Attachment(s)
i have to deal a lot w/ dyn sym libs/calls for my stuff @samygo and came up w/ some self-including .h file.
its basically for *nix but i ve hacked some windows support though not all features are available there

- should compile as C and C++
- type safe
- easy to use (imho)
- supports logging

here some example usage:
PHP Code:

// msvc doesn't support weak linking
#define DYNSYM_LOG __dynsym_log

#define DYNSYM_CALL_DECL WINAPI
#define DYNSYM_H "u32.h"
#include "dynsym.h"

#define DYNSYM_CALL_DECL WINAPI
#define DYNSYM_H "k32.h"
#include "dynsym.h"

void main()
{
    if(
user32_init() > 0)
    {
        
user32.MessageBoxA(0"test""test"0);
        
user32_deinit();
    }
    
    if(
k32_init() > 0)
    {
        
k32.Sleep(0);
        
k32_deinit();
    }


u32.h:
PHP Code:

#ifdef DYNSYM_BEGIN

DYNSYM_BEGIN("user32"user32)
DYNSYM_DEF(intMessageBoxAHWND hWndLPCSTR lpTextLPCSTR lpCaptionUINT uType)
DYNSYM_END(user32)

#endif // #ifdef DYNSYM_BEGIN 

dynsym.h macro hell :)
PHP Code:

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// bugficks@samygo
// (c) 2016 - 2018
//
// License: GPLv3
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//lib_blub.h:
// DYNSYM_BEGIN("lib_blub.so.0", lib_blub)
// supports patterns (glob w/ braces) and colon-separated list of libs
// //DYNSYM_BEGIN("{/usr/lib/{lib_blub.so,lib_bla.so*}}", lib_blub)
// //DYNSYM_BEGIN("lib_blub.so*:lib_bla.so*", lib_blub)
// //DYNSYM_BEGIN("lib_blub.so:lib_blub.so.0:lib_blub.so.1", lib_blub)
// // required symbols
// DYNSYM_DEF(int, func_bla, int)
// DYNSYM_DEF_EX(int, short_bla, func_loooooooong_bla, int)
// //optional symbols
// DYNSYM_OPT(int, func_blub, int)
// DYNSYM_OPT_EX(int, short_blub, func_loooooooong_blub, int)
// DYNSYM_END(lib_blub)
//
// // add additional data to lib_blub structure
//#ifndef DYNSYM_DATA
//#define DYNSYM_DATA \
//    int bla; \
//    void *blub;
//#endif
//
//code:
// #define DYNSYM_H    "lib_blub.h"
// optionally supply a colon-separated list of directories as library search path
// #define DYNSYM_LIB_PATH "/usr/lib:/some/lib/dir"
// #include <samygo/dynsym.h>
//
// lib_blub_init();
// lib_blub.func_bla(0);
// if(lib_blub.func_blub)
//    lib_blub.func_blub(0);
// lib_blub_deinit();

// < 0 : error
// else: num resolved symbols
// int xxx_init();
// int xxx_init_ex(void *lib);
//
// void xxx_deinit();

#ifndef __DYNSYM_DONE_H__

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef DYNSYM_H
#error DYNSYM_H is not defined.
#endif

#ifdef DYNSYM_BEGIN
#undef DYNSYM_BEGIN
#endif

#ifdef DYNSYM_END
#undef DYNSYM_END
#endif

#ifdef DYNSYM_DEF
#undef DYNSYM_DEF
#endif

#ifdef DYNSYM_DEF_EX
#undef DYNSYM_DEF_EX
#endif

#ifdef DYNSYM_VAR
#undef DYNSYM_VAR
#endif

#ifdef DYNSYM_VAR_EX
#undef DYNSYM_VAR_EX
#endif

#ifdef DYNSYM_OPT
#undef DYNSYM_OPT
#endif

#ifdef DYNSYM_OPT_EX
#undef DYNSYM_OPT_EX
#endif

#ifdef DYNSYM_VAR_OPT
#undef DYNSYM_VAR_OPT
#endif

#ifdef DYNSYM_VAR_OPT_EX
#undef DYNSYM_VAR_OPT_EX
#endif

#ifdef DYNSYM_INIT
#undef DYNSYM_INIT
#endif

#ifdef DYNSYM_DEINIT
#undef DYNSYM_DEINIT
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#if __DYNSYM_INC_LEVEL == 1
#undef __DYNSYM_INC_LEVEL
#define __DYNSYM_INC_LEVEL 2
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef DYNSYM_DATA
#define DYNSYM_DATA void *_dummy_;
#endif

#define DYNSYM_BEGIN(DLL, STRUCT) \
    
typedef union \
    { \
        
struct \
        { \
            const 
uint32_t nSyms;

#define DYNSYM_END(STRUCT) \
            
DYNSYM_DATA \
        }; \
        
dynsym_tab_t symtab; \
    } 
STRUCT##_t; \
    
DYNSYM_STRUCT_DATA(STRUCT);

#define DYNSYM_DEF(RET, NAME, ...) \
    
DYNSYM_DEF_EX(RETNAMENAME__VA_ARGS__)

#define DYNSYM_DEF_EX(RET, FUNC, NAME, ...) \
    
struct FUNC##_t FUNC; const char *name_##FUNC; };

#define DYNSYM_VAR(TYPE, NAME) \
    
DYNSYM_VAR_EX(TYPENAMENAME)

#define DYNSYM_VAR_EX(TYPE, VNAME, SNAME) \
    
struct TYPE *VNAME; const char *name_##VNAME; };

#define DYNSYM_OPT(RET, NAME, ...) \
    
DYNSYM_DEF_EX(RETNAMENAME__VA_ARGS__)

#define DYNSYM_OPT_EX(RET, FUNC, NAME, ...) \
    
DYNSYM_DEF_EX(RETFUNCNAME__VA_ARGS__)

#define DYNSYM_VAR_OPT(TYPE, NAME) \
    
DYNSYM_VAR_EX(TYPENAMENAME)

#define DYNSYM_VAR_OPT_EX(TYPE, VNAME, SNAME) \
    
DYNSYM_VAR_EX(TYPEVNAMESNAME)

#define DYNSYM_STRUCT_DATA(STRUCT) \
    
typedef struct \
    { \
        
DYNSYM_DATA \
    } 
STRUCT##_data_t;


#include DYNSYM_H

#undef DYNSYM_DATA
#undef DYNSYM_STRUCT_DATA

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#elif __DYNSYM_INC_LEVEL == 2
#undef __DYNSYM_INC_LEVEL
#define __DYNSYM_INC_LEVEL 3
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#define DYNSYM_BEGIN(DLL, STRUCT) \
    
static STRUCT##_t STRUCT = \
    
{ {\
        (((
sizeof(STRUCT##_t) - sizeof(STRUCT##_data_t)) - sizeof(STRUCT.symtab)) / sizeof(dynsym_sym_t)),

#define DYNSYM_END(STRUCT) \
    
} }; \
    
DYNSYM_INIT(DLLSTRUCT) \
    
DYNSYM_DEINIT(DLLSTRUCT)

#define DYNSYM_DEF(RET, NAME, ...) \
    
DYNSYM_DEF_EX(RETNAMENAME__VA_ARGS__)

#define DYNSYM_DEF_EX(RET, FUNC, NAME, ...) \
    
0#NAME },

#define DYNSYM_VAR(TYPE, NAME) \
    
DYNSYM_VAR_EX(TYPENAMENAME)

#define DYNSYM_VAR_EX(TYPE, VNAME, SNAME) \
    
0#SNAME },

#define DYNSYM_OPT(RET, NAME, ...) \
    
DYNSYM_OPT_EX(RETNAMENAME__VA_ARGS__)

#define DYNSYM_OPT_EX(RET, FUNC, NAME, ...) \
    
{ (FUNC##_t)eDYNSYM_OPTIONAL, #NAME },

#define DYNSYM_VAR_OPT(TYPE, NAME) \
    
DYNSYM_VAR_OPT_EX(TYPENAMENAME)

#define DYNSYM_VAR_OPT_EX(TYPE, VNAME, SNAME) \
    
{ (TYPE*)eDYNSYM_OPTIONAL#SNAME },


#ifndef DYNSYM_LIB_PATH
#define DYNSYM_LIB_PATH "/lib:/usr/lib"
#endif

#define DYNSYM_INIT(DLL, STRUCT) \
    
static int STRUCT##_init_ex(void *lib) \
    
{ \
        return 
dynsym_init_ex(lib, &STRUCT##_lib, &STRUCT.symtab); \
    
} \
    \
    static 
int STRUCT##_init() \
    
{ \
        return 
dynsym_init(&STRUCT##_lib, &STRUCT.symtab, DYNSYM_LIB_PATH); \
    
}

#define DYNSYM_DEINIT(DLL, STRUCT) \
    
static void STRUCT##_deinit() \
    
{ \
        
dynsym_tab_deinit(&STRUCT##_lib, &STRUCT.symtab); \
        
STRUCT##_lib.lib = 0; \
    
}


#include DYNSYM_H

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#elif __DYNSYM_INC_LEVEL == 3
#define __DYNSYM_DONE_H__

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#else
#define __DYNSYM_INC_LEVEL 1
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __DYNSYM_H__
#define __DYNSYM_H__

#include <stdint.h>
#include <errno.h>

#ifdef _WIN32

#include <windows.h>
#include <tchar.h>
#define  __attribute__(...)
#define PATH_MAX MAX_PATH

enum {
    
RTLD_LAZY 0x0001
};
inline voiddlopen(const char *nint)
{
    return (
void*)LoadLibraryA(n);
}
inline int dlclose(void *h)
{
    return 
FreeLibrary((HMODULE)h) ? : -1;
}
inline voiddlsym(void *h, const char *n)
{
    return (
void*)GetProcAddress((HMODULE)hn);
}

#define LIBRARY_PATH        "PATH"
#define TOKEN_PATH_SPLIT    ";"
#define strtok_r(A, B, C) strtok(A, B)

#else

#include <dlfcn.h>
#include <link.h>
#include <glob.h>

#define LIBRARY_PATH        "LD_LIBRARY_PATH"
#define TOKEN_PATH_SPLIT    ":"

#endif

typedef struct
{
    const 
char *name;//[PATH_MAX];
    
void *lib;
dynsym_lib_t;

typedef struct
{
    
void *fn;
    const 
char *name;
dynsym_sym_t;

typedef struct
{
    
uint32_t nSyms;
    
dynsym_sym_t syms[];
dynsym_tab_t;

typedef enum
{
    
eDYNSYM_DEFAULT       0,
    
eDYNSYM_OPTIONAL      = (<< 0),
    
eDYNSYM_MASK          3,
dynsym_flags_t;

typedef enum
{
    
eDYNSYM_LOG_NONE,
    
eDYNSYM_LOG_ERROR,
    
eDYNSYM_LOG_WARN,
    
eDYNSYM_LOG_INFO,
    
eDYNSYM_LOG_DBG
dynsym_log_level_t;


void dynsym_log(
        
int l, const char *fmt, ...) __attribute__ ((weak));

#ifndef DYNSYM_LOG
#define DYNSYM_LOG(L, ...) \
    
{ \
        if(
dynsym_log) \
            
dynsym_log(L__VA_ARGS__); \
        else \
            
__dynsym_log(L__VA_ARGS__); \
    }
#endif

static void __dynsym_log(
        
int l, const char *fmt, ...)
{
    
va_list ap;
    
va_start(apfmt);
    switch(
l)
    {
        case 
eDYNSYM_LOG_ERROR:
            
printf("[E]");
            break;
        case 
eDYNSYM_LOG_WARN:
            
printf("[W]");
            break;
        case 
eDYNSYM_LOG_INFO:
            
printf("[I]");
            break;
        case 
eDYNSYM_LOG_DBG:
            
printf("[D]");
            break;
        default:
            break;
    }
    
printf("[DYNSYM] ");
    
vprintf(fmtap);
    
va_end(ap);
    
fflush(stdout);
}

static 
inline const char *dynsym_libname(
        const 
dynsym_lib_t *lib)
{
    const 
char *lib_name "(nil)";
    if(!
lib)
        return 
lib_name;
    if(!
lib->name)
        return 
lib_name;
    if(!
lib->name[0])
        return 
lib_name;
    return 
lib->name;
}

static 
int dynsym_tab_init(
        
dynsym_lib_t *libdynsym_tab_t *symtab)
{
    
int n 0;
    const 
char *lib_name dynsym_libname(lib);
    
dynsym_sym_t *syms symtab->syms;
    for(
uint32_t i 0symtab->nSymsi++)
    {
        
uintptr_t flags = (uintptr_t)syms[i].fn;
        
int opt flags eDYNSYM_OPTIONAL;
        
void *fn dlsym(lib->libsyms[i].name);
        if(!
fn)
        {
            
int l opt eDYNSYM_LOG_WARN eDYNSYM_LOG_ERROR;
            
DYNSYM_LOG(l,"dlsym lib: '%s' '%s' failed.\n"lib_namesyms[i].name);
            if(!
opt)
                return -
1;
        }
        else
        {
            
DYNSYM_LOG(eDYNSYM_LOG_INFO,"dlsym lib: '%s' '%s' %p.\n"lib_namesyms[i].namefn);
            
n++;
        }

        
syms[i].fn fn;
    }
    return 
n;
}

static 
void dynsym_tab_deinit(
        
dynsym_lib_t *libdynsym_tab_t *symtab)
{
    
void *_lib lib->lib;
    if(
_lib)
    {
        
lib->lib 0;
        
dynsym_sym_t *syms symtab->syms;
        for(
uint32_t i 0symtab->nSymsi++)
            
syms[i].fn 0;

        
dlclose(_lib);
    }
    const 
char *name lib->name;
    if(
name)
    {
        
lib->name 0;
        
free((void*)name);
    }
}

static 
int dynsym_init_ex(
        
void *libdynsym_lib_t *dynsymlibdynsym_tab_t *symtab)
{
    if(!
lib)
        return -
1;
    if(
dynsymlib->lib)
        return -
1;

    
dynsymlib->lib lib;

#ifndef _WIN32
    
struct link_map *lm 0;
    
dlinfo(libRTLD_DI_LINKMAP, &lm);
    if(
lm && lm->l_name && lm->l_name[0])
        
dynsymlib->name strdup(lm->l_name);
    else if(!
dynsymlib->name || !dynsymlib->name[0])
        
dynsymlib->name realpath(program_invocation_name0);
#else
    
{
        
char tmp[MAX_PATH];
        
memset(tmp0sizeof(tmp));
        if(
GetModuleFileNameA((HMODULE)libtmpARRAYSIZE(tmp)))
            
dynsymlib->name _strdup(tmp);
    }
#endif

    
DYNSYM_LOG(eDYNSYM_LOG_DBG,"lib: '%s' %p.\n"dynsym_libname(dynsymlib), dynsymlib->lib);

    
int n dynsym_tab_init(dynsymlibsymtab);
    return 
n;
}

typedef int (*sgo_log_t)(
        
int l, const char *tag, const char *comp, const char *fmt, ...);

static 
void *dynsym_dlopen(
        const 
char *name_patterndynsym_lib_t *dynsymlib, const char *const _LIB_PATHsgo_log_t logger)
{
    if(!
name_pattern)
    {
        
void *lib dlopen(0RTLD_LAZY);
        return 
lib;
    }

    
char *strtok_name 0;
    
char name_wrk[PATH_MAX];
    
memset(name_wrk0sizeof(name_wrk));
    
strncpy(name_wrkname_patternsizeof(name_wrk));
    const 
char *name strtok_r(name_wrkTOKEN_PATH_SPLIT, &strtok_name);
    while(
name)
    {
        
// no pattern, just use dlopen
        
if(!strpbrk(name"?*[]{}"))
        {
            
void *lib dlopen(nameRTLD_LAZY);
            if(
lib)
                return 
lib;
        }
#ifdef HAVE_GLOB
        // pattern, we need absolute path for dlopen, fill lib search dirs
        
char LIB_PATH[PATH_MAX] = { };
        if(!
strchr(name'/'))
        {
            const 
char *const LD_LIBRARY_PATH getenv(LIBRARY_PATH);

            if(
LD_LIBRARY_PATH && LD_LIBRARY_PATH[0])
                
snprintf(LIB_PATHsizeof(LIB_PATH) - 1"%s:"LD_LIBRARY_PATH);
            
strncat(LIB_PATH_LIB_PATHsizeof(LIB_PATH) - 1);

            
DYNSYM_LOG(eDYNSYM_LOG_DBG"LIB_PATH: '%s'\n"LIB_PATH);
        }

        
char *strtok_dir 0;
        const 
char *libdir strtok_r(LIB_PATHTOKEN_PATH_SPLIT, &strtok_dir);
        
void *lib 0;
        do
        {
            
char libpath[PATH_MAX];
            
memset(libpath0sizeof(libpath));
            if(
libdir)
                
snprintf(libpathsizeof(libpath) - 1"%s/%s"libdirname);
            else
                
strncpy(libpathnamesizeof(libpath) - 1);

            
glob_t blob;
            
int r glob(libpathGLOB_BRACE0, &blob);
            if(
r)
            {
                
DYNSYM_LOG(eDYNSYM_LOG_DBG"glob('%s') failed. [%s]\n"libpathstrerror(ENOENT));
            }
            else
            {
                for(
size_t i 0blob.gl_pathci++)
                {
                    const 
char *name blob.gl_pathv[i];
                    
lib dlopen(nameRTLD_LAZY);
                    if(
lib)
                        break;
                }
            }

            
globfree(&blob);

            if(
lib)
                return 
lib;

            
libdir strtok_r(0TOKEN_PATH_SPLIT, &strtok_dir);
        }
        while(
libdir);
#endif

        
name strtok_r(0TOKEN_PATH_SPLIT, &strtok_name);
    }

    return 
0;
}

static 
int dynsym_init(
        
dynsym_lib_t *dynsymlibdynsym_tab_t *symtab, const char *const LIB_PATH)
{
    
void *lib dynsym_dlopen(dynsymlib->namedynsymlibLIB_PATH0);
    if(!
lib)
    {
        
DYNSYM_LOG(eDYNSYM_LOG_ERROR,"dlopen lib: '%s' failed.\n"dynsym_libname(dynsymlib));
    }

    return 
dynsym_init_ex(libdynsymlibsymtab);
}

#endif // #ifndef __DYNSYM_H__


#ifndef DYNSYM_CALL_DECL
#define DYNSYM_CALL_DECL
#endif

#define DYNSYM_DEF(RET, NAME, ...) \
    
DYNSYM_DEF_EX(RETNAMENAME__VA_ARGS__)

#define DYNSYM_DEF_EX(RET, FUNC, NAME, ...) \
    
typedef RET (DYNSYM_CALL_DECL FUNC##_t)(__VA_ARGS__);

#define DYNSYM_VAR(T, NAME) \
    
DYNSYM_VAR_EX(TVNAMESNAME)

#define DYNSYM_VAR_EX(T, VNAME, SNAME)

#define DYNSYM_OPT(RET, NAME, ...) \
    
DYNSYM_DEF_EX(RETNAMENAME__VA_ARGS__)

#define DYNSYM_OPT_EX(RET, FUNC, NAME, ...) \
    
DYNSYM_DEF_EX(RETFUNCNAME__VA_ARGS__)

#define DYNSYM_VAR_OPT(T, NAME) \
    
DYNSYM_VAR_OPT_EX(TNAMENAME)

#define DYNSYM_VAR_OPT_EX(T, VNAME, SNAME)

#define DYNSYM_BEGIN(DLL, STRUCT) \
    
static dynsym_lib_t STRUCT##_lib = { DLL, 0 };

#define DYNSYM_END(STRUCT)

#include DYNSYM_H

#undef DYNSYM_CALL_DECL

#endif

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#if __DYNSYM_INC_LEVEL < 4
#include "dynsym.h"
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#else // #ifndef __DYNSYM_DONE_H__

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#undef __DYNSYM_DONE_H__

#ifdef DYNSYM_LIB_PATH
#undef DYNSYM_LIB_PATH
#endif

#undef DYNSYM_H
#undef __DYNSYM_INC_LEVEL

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#endif  // #ifndef __DYNSYM_DONE_H__

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 


bugficks 04-14-2018 08:39

just for the fun of it, a c++14 version :)

PHP Code:

#include <string>
#include <memory>
#include <map>
#include <system_error>

template <typename Ftypename... ArgTypes>
auto DynCallT(LPCTSTR libNameLPCSTR funcNameArgTypes... args)
{
    
using tstring std::basic_string<TCHARstd::char_traits<TCHAR>, std::allocator<TCHAR>>;
    
using lib_ptr std::shared_ptr<std::remove_pointer_t<const HMODULE>>;
    
using lib_map std::map<const tstringlib_ptr>;

    static 
lib_map libMap;

    
HMODULE h nullptr;
    const 
auto &libMap.find(libName);
    if(
!= libMap.end())
        
l->second.get();
    else if((
= ::LoadLibrary(libName)) != nullptr)
        
libMap[libName] = lib_ptr(h, ::FreeLibrary);
    else
        throw 
std::system_error(std::make_error_code(std::errc::invalid_argument));

    
F f reinterpret_cast<F>(::GetProcAddress(hfuncName));
    if(!
f)
        throw 
std::system_error(std::make_error_code(std::errc::function_not_supported));

    return 
f(args...);


usage:
PHP Code:

    // using 'decltype' when you have a prototype 
    
auto r DynCallT<decltype(&MessageBoxA)>(_T("user32"), "MessageBoxA"nullptr"123""321"0);

    
// or using func decl as template arg
    
auto tc1 DynCallT<DWORD(WINAPI*)()>(_T("kernel32"), "GetTickCount");

    
// using "i dont give a shit" decl :)
    
auto tc2 DynCallT<void*(WINAPI*)(...)>(_T("kernel32"), "GetTickCount"1"asd");

    
void WINAPI blub(DWORD);
    
DynCallT<decltype(&blub)>(_T("kernel32"), "Sleep"0); 


mcp 04-14-2018 18:04

What is C++14 specific about this code?
One drawback is that it's not thread safe.

bugficks 04-14-2018 18:38

auto as return type is c++14 specific.

well thread safety wasn't my goal but it should be virtually thread safe. i mean the worst thing that can happen is that you replace a already loaded lib which isn't much of a problem

mcp 04-14-2018 23:40

Ah right, didn't spot auto return type deduction.

Data races yield undefined behavior, so the worst thing that could happen is that this code produces hard to find bugs/crashes. There is no such thing as "virtually thread safe" ;)

dosprog 04-15-2018 11:35

Quote:

Originally Posted by bugficks (Post 113034)
auto as return type is c++14 specific.

There is such a thing as the portability of the source code.


All times are GMT +8. The time now is 02:38.

Powered by vBulletin® Version 3.8.8
Copyright ©2000 - 2026, vBulletin Solutions, Inc.
Always Your Best Friend: Aaron, JMI, ahmadmansoor, ZeNiX