动态链接库相关&函数指针

 

======================动态链接库=======================

可以用dumpbin.exe查看dll文件的导出函数。

 

extern 声明外部函数,以;结束。

_declspec(dllimport)

告诉编译器我们引用的函数是从一个动态链接库.lib中输入的。以便让编译器生成更有效的代码。建议引用dll中的函数时用_declspec这个标识。最好放在一个头文件中。例子在孙鑫VC教程19课第40分钟时。

要使dll中导出的函数名名字不发生改变,可以在_declspec(dllimport)加上extern "C"

即#define DLL1_API extern "C" _declspec(dllimport) 其中DLL1_API为自取名。这种方法不能用来导出类的成员函数。

 

可以在dll所在文件目录中新建文本文档取名为.def 模块定义文件。将这个文件加入到工程当中。选择:工程->增加到工程->所有文件 添加模块定义文件。

在模块定义文件中: DLL2为dll名称。add和subtract为函数名。可以再msdn中查询EXPORTS详细用法。

LIBRARY DLL2

 

EXPORTS

add

subtract

 

动态加载一个dll,需要用到一个函数:LoadLibrary 映射一个可执行模块到一个调用进程的地址空间。还可以加载一个可执行程序。可在msdn中查询。

 

再就是得到dll导出的可用的函数地址:GetProcAddress 是用来获取指定的dll导出的函数的地址。下面是定义一个函数指针类型:

typedef int (*ADDPROC)(int a,int b);定义一个新类型。可以将(*ADDPROC)(int a,int b)看成一个整体,相当于定义了一个新的整型类型。我们分开来看,把(*ADDPROC)当做一个整体,那么他是一个函数,有2个变量,返回值是int。 我们再把(*ADDPROC) 拆开来看,*表示一个指针,这里是函数指针。他有2个整型参数,返回类型int。

函数指针类型是用来在需要的时候用它来产生一个函数指针变量,用来接收我们用GetProcAddress返回的函数地址。

用上述类型定义一个变量: ADDPROC Add=(ADDPROC)GetProcAddress(hInst,"add");

---------------延伸阅读----------------

FARPROC在windef.h中定义如下: 

typedef   int   (FAR   WINAPI   *FARPROC)(); 

就是说FARPROC是一个(int   FAR   WINAPI*)()类型的指针。 

 

可是 

        HINSTANCE   hUser32   ; 

        FARPROC   ptr; 

 

        hUser32   =   LoadLibrary( "user32.dll ");   

        ptr   =   GetProcAddress   (hUser32   ,   "MessageBoxA ");   

 

MessageBoxA显然是有参数的。 

为什么编译程序不报错哪?

---记住,兄弟,你的LoadLibrary和GetProcAddress都是执行期的东东,编译器是没有能力检查执行期的错误的

---LZ,你去看看这调用MessageBoxA(...)时,程序的汇编代码就知道了,

 

隐式调用:

push MB_OK

push lpCaption

push lpText

push hwnd

call MessageBox

 

显示调用:

push MB_OK

push lpCaption

push lpText

push hwnd

call ptr

 

typedef int (FAR WINAPI *FARPROC)();这句是定义了一个函数指针,仅仅是一个指针,是用来存放函数入口地址的,并不是函数原形。

 

FARPROC ptr;中ptr的值只有在ptr = GetProcAddress(hUser32, "MessageBoxA ");执行后才有意义(指向函数MessageBoxA的入口)。换句话说,只用程序运行过了,ptr的值才会指向MessageBoxA函数,否则ptr是随机值。

 

所以编译器在编译时不检查他的格式和参数,编译器甚至不知道此处调用的是MessageBexA()这个函数。既然都不知道将会调用哪一个API函数,如何检查参数是否合法?是吧!

 

链接时,链接器也不会在lib文件中链接MessageBoxA,原因相同:不知到ptr指向的是哪一个函数。

 

1. C与汇编的关系

2. C函数的调用方式(跳转操作、堆栈操作)

3. 显示调用、隐式调用的特点和不同之处

----------------------------

MAKEINTRESOURCE

  MAKEINTRESOURCE是一个资源名转换的宏,  VC的定义是(winuser.h):  #define MAKEINTRESOURCEA(i) (LPSTR)((ULONG_PTR)((WORD)(i)))  #define MAKEINTRESOURCEW(i) (LPWSTR)((ULONG_PTR)((WORD)(i)))  #ifdef UNICODE  #define MAKEINTRESOURCE MAKEINTRESOURCEW  #else  #define MAKEINTRESOURCE MAKEINTRESOURCEA  #endif // !UNICODE  这个宏是把一个数字类型转换成指针类型的宏,它不存在释放的问题.  用这个宏的主要原因是有的资源是用序号定义的,而不是字符串.所以要把数字转换成字符串指针,然后再传递给LoadResource之类的函数,这样才加载了资源.  要释放资源(用LoadResource加载的)可以调用FreeResource函数把LoadResource返回的指针传递给FreeResource.  MAKEINTRESOURCE 的作用:  是把一个"数字形ID",转化为"字符串".但是执行前后,输入的数据的内容和长度是不变的!它只不过就是C语言里面"强制类型转换"而已.  请看 Winuser.h 代码:  #define MAKEINTRESOURCEA(i) (LPSTR)((DWORD)((WORD)(i)))  #define MAKEINTRESOURCEW(i) (LPWSTR)((DWORD)((WORD)(i)))  #ifdef UNICODE  #define MAKEINTRESOURCE MAKEINTRESOURCEW  #else  #define MAKEINTRESOURCE MAKEINTRESOURCEA  #endif // !UNICODE  现在,再来归纳它的用法.就用FindResource来说明.(这个函数与MFC的AfxFindResourceHandle)  HRSRC FindResource(  HMODULE hModule, // module handle  LPCTSTR lpName, // resource name  LPCTSTR lpType // resource type  );  就是lpName参数需要使用MAKEINTRESOURCE ,因为它需要LPCTSTR类型的参数输入.那么,情况就很清楚了.凡涉及"资源"的API或者MFC类,在参数类型为LPCTSTR时,就应该使用 MAKEINTRESOURCE.这是针对"资源名字"为"数字类型"时的情况.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值