|
Posted on 2008-06-16 05:00 nt05 阅读(414) 评论(0) 编辑 收藏 引用 所属分类: cpp
__declspec(dllexport)是告诉编译器用来导出函数的,在代码中不另作说明了 extern "C"的意思就是用C的方式来导出函数,为什么要用C的方式来导出呢. 因为C++中有重载,编译器会对函数名进行更改,修饰成唯一的函数名. __stdcall告诉编译器函数调用方式.这点可以参考其他文章, 我预计也会在blog中写上一篇关于函数调用方式. C++编写的DLL extern "C" __declspec(dllexport) int Max(int x,int y)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) ...{
return x>y?x:y;
}
__declspec(dllexport) int __stdcall Min(int x,int y)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) ...{
return x<y?x:y;
}
__declspec(dllexport) double Min(double x,double y)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) ...{
return x<y?x:y;
}
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
这是一段代码,使用参数和返回值为int和double是有目的的 在VC8下int是32位的double是64位. 使用重载也是有目的的. 编译命令如下 cl /c dlltest.cpp link /DLL dlltest.obj 编译后使用Depends查看dll中的内容.能看到dll中有3个函数. ?Min@@YANNN@Z ?Min@@YGHHH@Z Max 其中的?Min@@YANNN@Z和?Min@@YGHHH@Z就是重载两个Min函数. 可以使用运行库中未公开函数__unDNameEx看到相对应的函数声明. 这两个名字就是C++函数和二进制文件中的函数名相对应的. 重载的时候根据参数不同链接到不同的函数名字 C如果使用的话得动态加载函数 接下来看如何传递指针类型.在以下的部分都使用C可以使用函数 于是将extern "C" __declspec(dllexport)定义为一个宏 #define DLLEXPORT extern "C" __declspec(dllexport)
DLLEXPORT int swap(int* x,int& y)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) ...{
int z = *x;
*x = y ;
y = z;
return 0;
}
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) /**//*
这和前面的例子重复了,主要用于调用的例子
*/
DLLEXPORT double __stdcall Max_d(double x,double y)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) ...{
return x>y?x:y;
}接下来是使用结构体的,由于结构体会对成员进行对齐, 所以在调用的时候需要注意和这里的结构体有相同的内存布局 #include<string.h>
struct testStruct
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) ...{
char a;
int b;
double c;
char sz[5];
};
DLLEXPORT int __stdcall UseStruct(testStruct* p)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) ...{
p->a = 'a';
p->b = 20;
p->c = 1.234;
strcpy( p->sz , "abcd" );
return sizeof(testStruct);
}
/**//*这是修改了内存对齐的结构体使用,主要在调用的时候有区别*/
#pragma pack(push)
#pragma pack( 1 )
struct testStruct2
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) ...{
char a;
int b;
double c;
char sz[5];
};
#pragma pack(pop)
DLLEXPORT int __stdcall UseStruct2(testStruct2* p)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) ...{
p->a = 'a';
p->b = 20;
p->c = 1.234;
strcpy( p->sz , "abcd" );
return sizeof(testStruct2);
}这是使用回调函数的例子,这里想成功调用主要还是要看如何调用. DLLEXPORT int __stdcall UserCallBackFunc( const char* lp, int (__stdcall *p)(const char*) )
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) ...{
return p( lp );
}def文件内容如下 EXPORTS Max swap Max_d UseStruct UseStruct2 UserCallBackFunc 这里的def文件不是必须的,如果不使用def文件编译,则dll中的一些函数名前面会被加上_后面加上参数大小 ?Min@@YANNN@Z ?Min@@YGHHH@Z Max _Max_d@16 _UseStruct2@4 _UseStruct@4 _UserCallBackFunc@8 swap当然如果只是C使用的话不使用def文件也是可以的,但要是其他语言的话就有一些不方便了也得使用 _Max_d@16这样的函数名字,有些不美观.在这里增加def文件也就是改名的意思 编译方法如下 cl /c dlltest.cpp link /DLL /DEF:dlltest.def dlltest.obj 使用了def文件后dll中所导出的函数如下 ?Min@@YANNN@Z ?Min@@YGHHH@Z Max Max_d UseStruct2 UseStruct UserCallBackFunc swap除去重载的两个函数,凡是使用extern "C"的函数都可以正常现实 C/C++使用方法分别使用.c和.cpp的扩展名编译,就是C的调用方法和C++的调用方法了 #ifdef __cplusplus
extern "C" __declspec(dllimport) int Max(int x,int y);
int __stdcall Min(int x,int y);
double Min(double x,double y);
#else
__declspec(dllimport) int Max(int x,int y);
#endif
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
#ifdef __cplusplus
# define DLLIMPORT extern "C" __declspec(dllimport)
#else
# define DLLIMPORT __declspec(dllimport)
#endif
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
DLLIMPORT int swap(int* x,int* y);
DLLIMPORT double __stdcall Max_d(double x,double y);
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
#include<string.h>
typedef struct __testStruct
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) ...{
char a;
int b;
double c;
char sz[5];
}testStruct;
DLLIMPORT int __stdcall UseStruct(testStruct* p);
#pragma pack(push)
#pragma pack( 1 )
typedef struct __testStruct2
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) ...{
char a;
int b;
double c;
char sz[5];
} testStruct2;
#pragma pack(pop)
DLLIMPORT int __stdcall UseStruct2(testStruct2* p);
DLLIMPORT int __stdcall UserCallBackFunc( const char* lp, int (__stdcall *p)(const char*) );
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
#include<stdio.h>
#pragma comment(lib,"dlltest.lib")
#include<windows.h>
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
int __stdcall CallBackFunc(const char*lp)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) ...{
return printf("%s ",lp);
}
int main()
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) ...{
int x=2,y=3;
testStruct s1;
testStruct2 s2;
#ifdef __cplusplus
printf("%d ",Min( 2,3 ) );
printf("%f ",Min( 2.0,3.0 ) );
#else
int(__stdcall *pMin)(int,int)=0;
double(*pMin_d)(double,double)=0;
HMODULE hDll = GetModuleHandle("dlltest.dll");
pMin_d = (double(*)(double,double)) GetProcAddress( hDll , "?Min@@YANNN@Z" );
if( pMin_d )
printf("%f ",pMin_d(3.0,5.0 ) );
pMin = (int(__stdcall*)(int,int)) GetProcAddress( hDll , "?Min@@YGHHH@Z" );
if( pMin )
printf("%d ",pMin( 3 , 5 ) );
#endif
swap( &x,&y );
printf("swap = %d,%d ",x,y);
printf( "%d " , Max( 2,4 ) );
printf( "%f " , Max_d( 2.0,4.0 ) );
UseStruct(&s1);
UseStruct2( &s2 );
printf( "%c,%d,%f,%s ",s1.a,s1.b,s1.c,s1.sz);
printf( "%c,%d,%f,%s ",s2.a,s2.b,s2.c,s2.sz);
UserCallBackFunc("abcdef",CallBackFunc);
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
return 0;
}; Delphi的使用方法. program test;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) ...{$APPtype CONSOLE}
uses
SysUtils,Classes,Math,Windows;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
type
testStruct = record
a:Char;
b:Integer;
c:Double;
sz:array[0..4] of char;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) ...{$A1}...{定义record使之和 修改了对齐的结构体有相同的内存布局 }
testStruct2 = record
a:Char;
b:Integer;
c:Double;
sz:array[0..4] of char;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) ...{$A8}
CallBackFunc type = function(x:PChar):Integer;stdcall;
function Max( x:Integer;y:Integer ):Integer;cdecl;external 'dlltest.dll' name 'Max';
function Max_d( x:Double;y:Double):Double ;stdcall;external 'dlltest.dll' name 'Max_d';
function swap(var x:Integer;var y:Integer):Integer;stdcall;external 'dlltest.dll' name 'swap' ;
function UseStruct(var x:testStruct):Integer;stdcall;external 'dlltest.dll' name 'UseStruct' ;
function UseStruct2(var x:testStruct2):Integer;stdcall;external 'dlltest.dll' name 'UseStruct2' ;
function UserCallBackFunc( lp:PChar ; F:CallBackFunctype ):Integer;stdcall;external 'dlltest.dll' name 'UserCallBackFunc' ;
function CallFunc(lp:PChar):Integer;stdcall;
begin
writeln( 'CallFunc=' , lp );
result := 0 ;
end;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) ...{
这里是使用重载函数
}
function Min(x:Integer;y:Integer):Integer;stdcall;external 'dlltest.dll' name '?Min@@YGHHH@Z';
function Min_d(x:Double;y:Double):Double;cdecl;external 'dlltest.dll' name '?Min@@YANNN@Z';
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
procedure test_overland;
begin
writeln( 'Min(1,2)=' , Min( 1,2 ) );
writeln( 'Min_d(1.0,2.1)=' , Min_d( 1.0,2.1 ) );
end;
var
x,y:Integer;
a_struct:testStruct;
b_struct:testStruct2;
begin
writeln( 'Max(1,2)=' , Max( 1,2 ) );
writeln( 'Max(1.0,2.0)=' , Max_d( 1.0,2.0 ) );
writeln( 'x=1,y=2' );
x :=1;y :=2 ;
swap( x, y);
writeln( 'swap(x,y)=' , x , ' ', y );
writeln( 'UseStruct( a_struct ) result=' , UseStruct( a_struct ) , ',sizeof=' , sizeof(a_struct) );
writeln( 'UseStruct=' , a_struct.a, ' ' , a_struct.b, ' ' , a_struct.c , ' ' ,a_struct.sz );
writeln( 'UseStruct2( b_struct ) result=' , UseStruct2( b_struct ) , ',sizeof=' , sizeof(b_struct) );
writeln( 'UseStruct2=' , b_struct.a, ' ' , b_struct.b, ' ' , b_struct.c , ' ' ,b_struct.sz );
UserCallBackFunc( PChar('abcdef') , CallFunc );
test_overland;
readln;
end. VB6的使用方法由于VB6只能使用__stdcall方式的函数,所以只有部分函数能被VB6所调用, ![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif) Public Declare Sub CopyMemory()Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif) Public Declare Function lstrlen()Function lstrlen Lib "kernel32" Alias "lstrlenA" (ByVal lpString As Long) As Long
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Public Type testStruct
a As Byte
b As Long
c As Double
sz As String * 5
End Type
Public Type Temp
sz As String * 5
End Type
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif) Public Declare Function Max_d()Function Max_d Lib "dlltest" (ByVal a As Double, ByVal b As Double) As Double
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif) Public Declare Function Min()Function Min Lib "dlltest" Alias "?Min@@YGHHH@Z" (ByVal a As Long, ByVal b As Long) As Long
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif) Public Declare Function UseStruct()Function UseStruct Lib "dlltest" (ByRef a As testStruct) As Long
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif) Public Declare Function UseStruct2()Function UseStruct2 Lib "dlltest" (ByRef a As Any) As Long
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif) Public Declare Function UserCallBackFunc()Function UserCallBackFunc Lib "dlltest" (ByVal s As String, ByVal f As Long) As Long
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif) Function CallBack()Function CallBack(ByVal lp As Long) As Long
Dim L As Long
L = lstrlen(lp)
Dim s As String
s = String$(L + 1, vbNullChar)
CopyMemory s, lp, L
MsgBox s & " , " & Str$(L)
Debug.Print "CallBack", s
CallBack = 3
End Function
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif) Sub Main()Sub Main()
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Debug.Print Max_d(4, 5), Min(4, 6)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Dim a As testStruct
Debug.Print UseStruct(a)
Debug.Print Chr(a.a), a.b, a.c, a.sz
Dim buf(18) As Byte
Debug.Print "----------------"
Debug.Print UseStruct2(buf(0))
Dim t As Byte
CopyMemory t, buf(0), 1
Dim L As Long
CopyMemory L, buf(1), 4
Dim d As Double
CopyMemory d, buf(5), 8
Dim s As Temp
CopyMemory s, buf(13), 5
Debug.Print Chr(t), L, d, s.sz
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
Debug.Print UserCallBackFunc("_测试asdasd中文sdfasdf", AddressOf CallBack)
End Sub
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
VB版本需要注意的是 lstrlen 的声明 参数不是String而是Long类型,这是因为如果是String的话VB会对参数进行改造,将字符串指针转化为String类型,而我这里不需要改变,就需要一个原始的Long类型的指针.所以就更改了API的函数声明.以适应我的需求
Delphi编写DLL
library dlltest;
uses SysUtils, Classes;
function Max(X, Y: Integer): Integer; cdecl; begin if X > Y then Max := X else Max := Y; end;
function Min(X, Y: Integer): Integer;overload; stdcall; begin if X < Y then Min := X else Min := Y; end;
function Min(X, Y: Double): Double;overload; cdecl; begin if X < Y then Min := X else Min := Y; end;
function swap( var x: Integer; var y: Integer): Integer; cdecl; var z:integer; begin z := x; x := y; y := z; result := 1; end;
function Max_d(X, Y:Double):Double;stdcall; begin if X > Y then Max_d := X else Max_d := Y; end;
type testStruct = record a:Char; b: Integer; c:Double; sz: array[0..4] of char; end; function UseStruct( var x:testStruct): Integer;stdcall; begin x.a := 'a' ; x.b := 20 ; x.c := 1.234 ; StrCopy( x.sz , PChar('abcd') ); UseStruct:=SizeOf(testStruct) ; end;
{$A1} type testStruct2 = record a:Char; b: Integer; c:Double; sz: array[0..4] of char; end; {$A8} function UseStruct2( var x:testStruct2): Integer;stdcall; begin x.a := 'a' ; x.b := 20 ; x.c := 1.234 ; StrCopy( x.sz , PChar('abcd') ); UseStruct2 := SizeOf(testStruct2) ; end;
type CallBackFuncType = function(x:PChar): Integer;stdcall; function UserCallBackFunc( lp:PChar ; F:CallBackFuncType ): Integer;stdcall; begin F( lp ); UserCallBackFunc:= StrLen( lp ) ; end;
exports Max, Min(X, Y: Integer) name '?Min@@YGHHH@Z',//和C++导出的重载函数名字一样 Min(X, Y: Double)name '?Min@@YANNN@Z', swap, Max_d, UseStruct, UseStruct2, UserCallBackFunc;
begin end.
Delphi导出的时候可以自由设置输出的名字,这样就可以写出来和C++写出来的DLL有相同的导出表. 也就是说可以和C++写的dll互相替换着调用. 关于VB编写DLL 由于VB6不容易编写类似功能的DLL的,主要是官方未支持.虽说有人发布相应的SDK. 但毕竟没有官方支持,应用也很难推广开来,所以在这里说明一下,也就不提供VB6编写这样的DLL的. 预计我会写一篇使用COM的方式实现多语言编程,到时候就可以看到VB6版的DLL.
总结一下 说来DLL要想能够在多种语言中都可以使用,那么就需要使用__stdcall方式调用(VB只支持这中方式), 以及都有的数据类型.这样就限定了,只能使用整形(1字节char,2字节short ,4字节long,8字节的long long),浮点型(4字节的float,8字节的double),以及指针类型(包括函数指针).精确的说只有CPU所支持的类型,才容易做到无障碍的通用.
小技巧 由于C/C++程序在使用静态载入DLL的方式的时候,需要lib文件参与链接,这个时候可以自己创建一个DLL 工程,然后导出原本DLL中的函数,函数实现为空就可以了,然后用这个lib参与链接,在调用你所要使用的DLL是可以的.
|