在Windows编程中,除了在编译的时候链接lib文件跟dll挂上钩之外,还可以在运行的时候动态加载dll,这样更富于灵活性。这几天忙活这个问 题,搞得焦头烂额,因为GetProcAddress()始终得不到我说需要的函数名的地址。但是今天终于弄出结果来了,虽然有的地方还没有搞明白。
首先是__cdcel和__stdcall的问题。我就纠缠于这个问题上。最近几天都使用__stdcall,但是GetProcAddress始终不能成功。
我首先看到如下的程序:
SHOWHTMLDIALOGFN *pfnShowHTMLDialog;
pfnShowHTMLDialog = (SHOWHTMLDIALOGFN*) GetProcAddress(hinstMSHTML, "ShowHTMLDialog");
if(pfnShowHTMLDialog)
{
IMoniker *moniker=NULL;
//
if( FAILED(CreateURLMoniker( NULL, (LPWSTR)url, &moniker ) ))
{
FreeLibrary(hinstMSHTML);
return FALSE;
}
//调用ShowHTMLDialog函数显示URL上的HTML文件
pfnShowHTMLDialog(NULL, moniker, NULL, NULL, NULL);
这里调用是没有问题的。而我看了下 mshtmlst.h中的定义,SHOWHTMLDIALOGFN就是使用__stdcall修饰的,以至于我一直没有明白为什么我的程序使用__stdcall修饰就没有用。
之后我固执于extern "C" 的问题,但是仍然使用 __stdcall修饰,结果无论是C文件还是Cpp文件的dll都无法正确获得地址。
后来我使用VC6的Depends工具察看dll结构终于看出了一点端倪。生成的dll中的函数名称都带有很多别的符号,我才大概明白了一点。
如下代码:
#define CDll_Public __declspec(dllexport)
#ifdef __cplusplus
extern "C" {
#define YESDEFINE -1
#endif
CDll_Public void __stdcall init(int );
CDll_Public void __stdcall add(int ); /*__stdcall not nessessary*/
CDll_Public int __stdcall ret();
#ifdef __cplusplus
}
#endif
的依赖察看结果是:
这时候我使用GetProcAddress(hin, "_init@4")就能够得到正确的结果。
但是这样做毕竟不是办法,最后我想到了使用__cdecl修饰看看效果,居然好了。然后就OK了。
#ifdef __cplusplus
extern "C" {
#endif
extern __declspec(dllexport) void __cdecl hello();
extern __declspec(dllexport) void hi();
#ifdef __cplusplus
}
#endif
这段代码生成的dll中的函数名称如下:
这样做的话就能够正确地动态加载dll了(C程序没问题,Cpp程序需要extern "C")。
PS。这里顺便把编译dll,以及link lib的命令写下来:
#生成dll
cl /LD cdll.c
#生成exe
cl cdlltest.c /link cdll.lib
首先是__cdcel和__stdcall的问题。我就纠缠于这个问题上。最近几天都使用__stdcall,但是GetProcAddress始终不能成功。
我首先看到如下的程序:
SHOWHTMLDIALOGFN *pfnShowHTMLDialog;
pfnShowHTMLDialog = (SHOWHTMLDIALOGFN*) GetProcAddress(hinstMSHTML, "ShowHTMLDialog");
if(pfnShowHTMLDialog)
{
IMoniker *moniker=NULL;
//
if( FAILED(CreateURLMoniker( NULL, (LPWSTR)url, &moniker ) ))
{
FreeLibrary(hinstMSHTML);
return FALSE;
}
//调用ShowHTMLDialog函数显示URL上的HTML文件
pfnShowHTMLDialog(NULL, moniker, NULL, NULL, NULL);
这里调用是没有问题的。而我看了下 mshtmlst.h中的定义,SHOWHTMLDIALOGFN就是使用__stdcall修饰的,以至于我一直没有明白为什么我的程序使用__stdcall修饰就没有用。
之后我固执于extern "C" 的问题,但是仍然使用 __stdcall修饰,结果无论是C文件还是Cpp文件的dll都无法正确获得地址。
后来我使用VC6的Depends工具察看dll结构终于看出了一点端倪。生成的dll中的函数名称都带有很多别的符号,我才大概明白了一点。
如下代码:
#define CDll_Public __declspec(dllexport)
#ifdef __cplusplus
extern "C" {
#define YESDEFINE -1
#endif
CDll_Public void __stdcall init(int );
CDll_Public void __stdcall add(int ); /*__stdcall not nessessary*/
CDll_Public int __stdcall ret();
#ifdef __cplusplus
}
#endif
的依赖察看结果是:
但是这样做毕竟不是办法,最后我想到了使用__cdecl修饰看看效果,居然好了。然后就OK了。
#ifdef __cplusplus
extern "C" {
#endif
extern __declspec(dllexport) void __cdecl hello();
extern __declspec(dllexport) void hi();
#ifdef __cplusplus
}
#endif
这段代码生成的dll中的函数名称如下:
这样做的话就能够正确地动态加载dll了(C程序没问题,Cpp程序需要extern "C")。
PS。这里顺便把编译dll,以及link lib的命令写下来:
#生成dll
cl /LD cdll.c
#生成exe
cl cdlltest.c /link cdll.lib