#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "user32.lib") //<-----------------------------------这
void main()
{
return 0;
}
系统提供了一些API,他们简化了开发人员的工作提高了其效率,怎么使用他们呢,因为其实现都放到了dll中,我们要包含头文件,连接他们的库,也就是你提到的这些,这样我们才能使用。(http://zhidao.baidu.com/question/55216828.html)
我的项目设置里已经包含了user32.lib,所以可以删掉。#pragma comment(lib, "user32.lib")
这些lib在这个文件夹里:
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
from:http://blog.163.com/laorenyuhai126@126/blog/static/1935077920103182310625/
.h用于编译阶段的审核,如在math.h中有函数声明:
int abs(int);
但是在使用中写为
#include <math.h>
...abs(3,5);
编译器阶段就会检测出错误。
.lib用于链接阶段,在链接各部分目标文件(通常为.obj)到可执行文件(通常为.exe)过程中,需要在.lib文件中查找动态调用函数(一般为DLL中的函数)的地址信息,此时需要在lib文件中查找,如查找SetWindowText()函数的地址偏移就需要查找user32.lib文件。(.lib也可用于静态链接的内嵌代码)
.lib是在你的程序编译连接的时候就连接的文件,因此你必须告知编译器连接的lib文件在那里。一般来说,与动态连接文件相对比,lib文件也被称为是静态连接库。
.dll用于运行阶段,如调用SetWindowText()函数等,需要在user32.dll中找到该函数。DLL可以简单认为是一种包含供别人调用的函数和资源的可执行文件。
.dll是在你的程序运行的时候才连接的文件,因此它是一种比较小的可执行文件格式,.dll还有其他的文件格式如.ocx等,所有的.dll文件都是可执行。
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
实践一下:
1、创建一个动态链接库项目:
2、编辑:
_declspec(dllexport):是一个声明,将一个函数声名为导出函数,就是说这个函数要被其他程序调用,即作为DLL的一个对外函数接口。
3、编译+链接后得到我们要的.dll,.lib:
4、我们可以通过VS自带的dumpbin工具(我的在C:\Program Files\Microsoft Visual Studio\VC98\Bin目录下,如果你的dumpbin不能用,请先运行“C:\Program Files\Microsoft Visual Studio\VC98\Bin\VCVARS32.BAT”)查看一下我们的dll文件的某些信息:进入dll1.dll文件所在目录;
(注:我们通过VS自带的dumpbin工具来查看一个DLL或EXE中的包含的函数或是依赖的函数之类的信息,具体应用信息可以百度、谷歌“DUMPBIN 实用程序的说明”,我们只需要知道它大体用来做什么就好了,需要时在查看参考资料就好了)
在我们的dll1.dll、dll1.lib中:
dll1.dll文件包含实际的函数和数据;
dll1.lib文件包含被DLL文件导出的函数和变量的符号名。
在编译时一定要有dll1.lib文件;在运行时一定要有dll1.dll文件。
6、
创建一个项目来检测一下我们的链接库:
#include <iostream>
using std::cout;
using std::endl;
#pragma comment(lib, "dll1.lib")
//
//extern add(int a,int b);
//_declspec(dllimport):告诉编译器,函数来自一个动态链接库,编译器会比extern声明生成执行效率更高的代码;
_declspec(dllimport) int add(int a,int b);
int main(){
cout<<"1+1="<<add(1,1)<<endl;
return 0;
}
注意文件夹结构(要将我们的DLL、LIB拷贝到这个测试项目中来,如果不拷贝,由上文的理论,会出现相应的链接、运行错误):
运行,得到期待的结果:
还可以通过VS自带的dependency walker来看可执行程序、DLL、函数之间的依赖关系:
8、关于加载动态链接库的说明:
我们上面将dll1.dll文件放到了当前目录,即,我们创建的项目的那个文件夹。
将上面的DLL文件从当前目录中去掉,会看到,系统为了查找这个dll文件,都查找了哪些目录(我的就显示了一个简略信息,大家可以看看自己的。)
debug----》当前目录----》系统路径……
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
9、
为了使其他人能够更方便的使用我们提供的动态链接库,而不是通过各种工具来揣测我们的dll文件用来干嘛。
我们需要相应地提供一个源文件(包含一些注释)给用户:
调用的项目:
10、整个程序源码:
dll1项目:
//D:\Workspace\C++\dll1\dll1.h #ifndef DLL1_API #define DLL1_API _declspec(dllimport) #endif DLL1_API int add(int a,int b); //-------------------------------------------------------------------------------------- //D:\Workspace\C++\dll1\dll1.cpp #define DLL1_API _declspec(dllexport) #include "dll1.h"
return a+b;} 编译链接后将DLL、LIB拷到dll1Test项目下;DLL1_API int add(int a,int b){
dll1Test项目:
//D:\Workspace\C++\dll1Test\dll1Test.cpp #include <iostream> #include "../dll1/dll1.h" using std::cout; using std::endl; #pragma comment(lib, "dll1.lib") int main(){ cout<<"1+1="<<add(1,1)<<endl; return 0; }
OK,完成!
11、其他:
从上面看出,DLL里面的函数名是经过函数名改编,当将某种编译器编译得到的DLL\LIB用于另一种编译器编译的项目时,由于他们对名称改编的方案不同,会不能正确找到函数,导致调用失败。
解决C与C++相互调用问题的方法:
export时不要改编函数名,imports时也不要改编函数名:
extern "C"只能确保全局函数不发生函数名改编
#define DLL1_API extern "C" _declspec(dllexport) #define DLL1_API extern "C" _declspec(dllimport)
………………
(上面的例子来自孙鑫的VC教程!)