更方便地動態呼叫DLL匯出函式

2021-06-16 01:44:24 字數 2383 閱讀 2309

在一般情況下,動態呼叫dll匯出函式的方法是:

用typedef為目標函式定義函式指標型別。

用getprocaddress獲取函式指標。

用函式指標進行呼叫。

但是,如果要呼叫的函式太多的話,這個方法難免流於繁瑣——有太多的typedef、太多的getprocaddress和太多的函式指標。在本文中將給出乙個通用的解決方法,使這些動態呼叫更加簡便。

先看看我們這個函式的宣告:

bool __cdecl dllcall(

pctstr lpszdll, // 目標函式所在dll的名稱

pcstr lpszfunc, // 目標函式名稱

int argc,   // 要呼叫的引數個數

pvoid pret, // 函式呼叫的返回值

...);

以messageboxa為例,使用方法為:

int ret;

dllcall(_t("user32.dll"), "messageboxa", 4, &ret,

null, "hello, world!", "hello", mb_iconinformation | mb_yesno);

換用乙個引數的messageboxindirecta,則是:

msgboxparamsa param;

zeromemory(¶m, sizeof(msgboxparamsa));

param.cbsize = sizeof(msgboxparamsa);

param.dwlanguageid = getsystemdefaultlangid();

param.dwstyle = mb_iconinformation;

param.lpszcaption = "hello";

param.lpsztext = "hello, world";

int ret;

dllcall(_t("user32.dll"), "messageboxindirecta", 1, &ret, ¶m);

實現的原理是動態生成彙編**,也就是類似這樣的一段:

__declspec(naked) dword __cdecl dllcallproc(void);}

下面列出dllcall的**,和所有可變引數函式的實現(如sprintf)都差不多。

bool __cdecl dllcall(

pctstr lpszdll,

pcstr lpszfunc,

int argc,

pvoid pret,

...)

最為關鍵的就是vdllcall的**了,如下:

#pragma pack(push, 1)

typedef

struct  opcode, *popcode;

#pragma pack(pop)

typedef

dword (__cdecl * dllcall)(void);

bool __cdecl vdllcall(

pctstr lpszdll,

pcstr lpszfunc,

int argc,

pvoid pret,

va_list arglist)

// call proc

p[argc].op = 0xe8;

p[argc].dwvalue = (int_ptr)proc - (int_ptr)&p[argc + 1];

// ret

p[argc + 1].op = 0xc3;

p[argc + 1].dwvalue = 0x90909090; // nop nop nop nop

dllcall pfn = (dllcall)p;

dword ret = pfn();

heapfree(hheap, 0, p);

freelibrary(hdll);

if (null != pret)

*(pdword)pret = ret;

return true;

}其中的指標p就是我們動態生成的呼叫**,最後轉換成dllcall型別的函式指標進行了呼叫。

最後,需要補充說明四點:

dllcall只適用於__stdcall呼叫約定的目標函式。

這份vdllcall的**只適用於x86的cpu,如果在wince的環境下(如arm或mips的cpu)使用,需要酌情重新編寫動態呼叫的彙編**。

其中argc引數是指實際壓棧的引數個數,而不是c語言呼叫的引數個數。如api函式windowfrompoint,雖然函式宣告中只有乙個引數,但是實際上是將point::x、point::y分別壓棧的。在這種情況下,需要將argc設定為2。

dllcall的返回值只獲取了eax,如果有的函式會返回乙個超過4位元組的龐大結構,那麼這個返回值將並不是你想要的。

c 呼叫dll函式,匯出類中的成員函式

對於dll的操作,我們可以使用dumpbin檢視dll 和lib。注意寫好dll後 用depends檢視匯出函式時會發現匯出的函式名不是你寫的那樣出現所謂的亂碼入?等 這就注定dll不能通過顯示連線的方式匯入。如果想通過顯示連線的方式匯入可以為類新增乙個友元函式去實現顯示連線建立類得物件 這裡對於匯...

C 動態呼叫C 編寫的DLL函式

c 動態呼叫c 編寫的dll函式 c 動態呼叫c 編寫的dll函式 動態載入 dll 需要使用 windows api 函式 loadlibrary getprocaddress 以及 freelibrary 我們可以使用 dllimport 在 c 中使用這三個函式。dllimport kerne...

C 動態呼叫C 編寫的DLL函式

動態載入dll需要使用windows api函式 loadlibrary getprocaddress以及freelibrary。我們可以使用dllimport在c 中使用這三個函式。dllimport kernel32 public static extern int getprocaddress...