xxx.lib //静态库
xxxx.dll xxxx.lib //分别是动态库动态库的引入库
隐式链接:
1: 拷入动态库dll 引入库lib;
2: 加入头文件
3: alt+F7
第3步也可以用这句代码代替:#pragma comment(lib,"MyDll.lib")
然后下一句代码就是加入头文件(因头文件中开头有导入函数的相关语句:
如extern "C"_declspec(dllimport) int add(int a,int b);)可写成:
#define DLL_API_WIN32TEST extern "C"
_declspec(dllimport)//导入
DLL1_API int
如果同时隐式加载许多DLL,会造成程序启动慢,而且有些函数根本就不需要调用的,所以可以选择只有需要调用函数时才加载函数进行调用,这时候就会到下面的显示链接了,隐式加载其实也是调用函数LoadLibrary一个一个加载的.
显示链接:
要使用函数LoadLibrary
1:c++和c调用约定
HINSTANCE hInst;
if(!Add)
{//函数加载失败}
2:C++和标准调用约定
HINSTANCE hInst;
typedef int (_stdcall *ADDPROC)(int a,int b);//如果DLL是paska调用约定也就是标准调用约定
if(!Add)
{//函数加载失败}
3:C++和C++调用约定,编写DLL时没有加extern "C",查得DLL导出函数为
?add@YAHHH@Z
HINSTANCE hInst;
typedef int (*ADDPROC)(int a,int b);//如果DLL是paska调用约定也就是标准调用约定
//ADDPROC Add=(ADDPROC)GetProcAddress(hInst,MAKEINTRESOURCE(1));//或者这样写,指的是第1个函数add
if(!Add)
{//函数加载失败}
假设c盘有文件:xxx.exe xxxx.dll
在cmd下输入:
进入C盘.
执行命令: dumpin -imports xxx.exe 以查看导入xxx.exe 的函数
执行命令: dumpin -exports xxxx.dll 以查xxxx.dll 导出了哪些函数
C++编译器在导出函数的时候,会做名字改编(比如:?函数名@@YAHHH@Z),把函数名字改编后,C编译器编写的调用端程序,无法识别函数,所以需要加关键字 extern "C" 至使C++编译器没有发生名字改编(比如:函数名),以确保C调用端正确识别以调用。extern "C" 中的字母C要大写;这就是C++和C的调用约定了.
但是如果在函数名前面有加关键字 _stdcall 就成C++和标准调用语言 之间调用约定了.比如 得尔非语言..
例一 a:导出全局函数:c++与c 调用约定,
//头文件 dllxxx.h//是给调用者用的 比如: #include "dllxxx.h"
//DLL_API_WIN32TEST 在调用者不要再定义
#ifdef DLL_API_WIN32TEST
#else
#define DLL_API_WIN32TEST extern "C"
_declspec(dllimport)//导入
#endif
DLL_API_WIN32TEST int add(int a,int b);//未写成_stdcall add(int a,int b);
DLL_API_WIN32TEST int _stdcall subtract(int a,int b);//未写成_stdcall subtract(int a,int b);
//源文件
#define DLL_API_WIN32TEST extern "C"
_declspec(dllexport)//导出
#include "dllxxx.h"
int add(int a,int b
{
}
int subtract(int a,int b)
{
}
例一 b:导出全局函数:c++和标准调用语言
//头文件 dllxxx.h//是给调用者用的 比如: #include "dllxxx.h"
//所以DLL_API_WIN32TEST 在调用者不要再定义
#ifdef DLL_API_WIN32TEST
#else
#define DLL_API_WIN32TEST extern "C"
_declspec(dllimport)//导入
#endif
DLL_API_WIN32TEST int _stdcall add(int a,int b);
DLL_API_WIN32TEST int _stdcall subtract(int a,int b);
//源文件
#define DLL_API_WIN32TEST extern "C"
_declspec(dllexport)//导出
#include "dllxxx.h"
int _stdcall add(int a,int b)//_stdcall表示的是标准调用约定,表示winapi,paska调用约定
{
}
int _stdcall subtract(int a,int b))//_stdcall表示的是标准调用约定,表示winapi,paska调用约定
{
}
例二 导出整个类:
//头文件 dllxxx.h
#ifdef DLL_API_WIN32TEST
#else
#define DLL_API_WIN32TEST extern "C"
_declspec(dllimport)//导入
#endif
class
{
public:
private:
int x;
int y;
};
//源文件
#define DLL_API_WIN32TEST extern "C"
_declspec(dllexport)//导出
#include "dllxxx.h"
#include<iostream>
using namespace std;
void Point::output(int x,int y)
{
}
void Point::test()
{
cout<<endl<<"test"<<endl;
}
void input(int x,int y)
{
this->x = x;
this->y = y;
}
例三 导出类中各别函数:
//头文件 dllxxx.h
#ifdef DLL_API_WIN32TEST
#else
#define DLL_API_WIN32TEST extern "C"
_declspec(dllimport)//导入
#endif
class
{
public:
private:
int x;
int y;
};
//源文件
#define DLL_API_WIN32TEST extern "C"
_declspec(dllexport)//导出
#include "dllxxx.h"
#include<iostream>
using namespace std;
void Point::output(int x,int y)
{
}
void Point::test()
{
cout<<endl<<"test"<<endl;
}
void input(int x,int y)
{
this->x = x;
this->y = y;
}
孙鑫最后说"..那么为了让我们所写的这些动态链接库呢,在其它语言当中,在其它的编译器当中,那么都可以被调用,那么我们可以呢,采用模块定义文件,让我们所输入出的函数的符号名不发生改变.."
以下是模块定义文件方法:
//头文件 dllxxx.def
LIBRARY Dll2
EXPORTS
add
subtract
//源文件
int add(int a,int b)
{
}
int subtract(int a,int b)
{
}
调用方法就是上面所使用的动态加载方法:
{
}