使用DLL进行不同语言之间的调用

来源:本站
导读:目前正在解读《使用DLL进行不同语言之间的调用》的相关信息,《使用DLL进行不同语言之间的调用》是由用户自行发布的知识型内容!下面请观看由(电工技术网 - www.9ddd.net)用户发布《使用DLL进行不同语言之间的调用》的详细说明。
简介:__declspec(dllexport) 是告诉编译器用来导出函数的,在代码中不另作说明了。extern "C" 的意思就是用C的方式来导出函数。为什么要用C的方式来导出呢。

因为C++中有重载,编译器会对函数名进行更改,修饰成唯一的函数名。

__stdcall 告诉编译器函数调用方式。这点可以参考其他文章,我预计也会在blog中写上一篇关于函数调用方式。

extern "C" __declspec(dllexport) int  Max(int x,int y){    return x>y?x:y;}__declspec(dllexport) int __stdcall Min(int x,int y){    return x<y?x:y;}__declspec(dllexport) double Min(double x,double y){    return x<y?x:y;}

这是一段代码,使用参数和返回值为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){    int z = *x;    *x = y ;    y = z;    return 0;}/*这和前面的例子重复了,主要用于调用的例子*/DLLEXPORT double __stdcall Max_d(double x,double y){    return x>y?x:y;}

接下来是使用结构体的,由于结构体会对成员进行对齐,所以在调用的时候需要注意和这里的结构体有相同的内存布局。

#includestruct testStruct{    char a;    int b;    double c;    char sz[5];};DLLEXPORT int __stdcall UseStruct(testStruct* p){    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{    char a;    int b;    double c;    char sz[5];};#pragma pack(pop)DLLEXPORT int __stdcall UseStruct2(testStruct2* p){    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*) ){    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#ifdef __cplusplus#    define DLLIMPORT extern "C" __declspec(dllimport)#else#    define DLLIMPORT __declspec(dllimport)#endifDLLIMPORT int swap(int* x,int* y);DLLIMPORT double __stdcall Max_d(double x,double y);#includetypedef struct __testStruct{    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{    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*) );#include#pragma comment(lib,"dlltest.lib")#includeint __stdcall CallBackFunc(const char*lp){    return printf("%s ",lp);}int main(){    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);    return 0;};

Delphi的使用方法

program test;{$APPtype CONSOLE}uses  SysUtils,Classes,Math,Windows;type  testStruct = record    a:Char;    b:Integer;    c:Double;    sz:array[0..4] of char;  end;{$A1}{定义record使之和 修改了对齐的结构体有相同的内存布局 }  testStruct2 = record    a:Char;    b:Integer;    c:Double;    sz:array[0..4] of char;  end;{$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;{    这里是使用重载函数}  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';  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所调用。

Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)Public Declare Function lstrlen Lib "kernel32" Alias "lstrlenA" (ByVal lpString As Long) As LongPublic Type testStruct        a As Byte        b As Long        c As Double        sz As String * 5End TypePublic Type Temp    sz As String * 5End TypePublic Declare Function Max_d Lib "dlltest" (ByVal a As Double, ByVal b As Double) As DoublePublic Declare Function Min Lib "dlltest" Alias "?Min@@YGHHH@Z" (ByVal a As Long, ByVal b As Long) As LongPublic Declare Function UseStruct Lib "dlltest" (ByRef a As testStruct) As LongPublic Declare Function UseStruct2 Lib "dlltest" (ByRef a As Any) As LongPublic Declare Function UserCallBackFunc Lib "dlltest" (ByVal s As String, ByVal f As Long) As LongFunction 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 = 3End FunctionSub Main()    Debug.Print Max_d(4, 5), Min(4, 6)    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    Debug.Print UserCallBackFunc("_测试asdasd中文sdfasdf", AddressOf CallBack)End Sub

VB版本需要注意的是lstrlen 的声明 参数不是String而是Long类型,这是因为如果是String的话VB会对参数进行改造,将字符串指针转化为String类型,而我这里不需要改变,就需要一个原始的Long类型的指针.所以就更改了API的函数声明.以适应我的需求。

提醒:《使用DLL进行不同语言之间的调用》最后刷新时间 2024-03-14 01:00:20,本站为公益型个人网站,仅供个人学习和记录信息,不进行任何商业性质的盈利。如果内容、图片资源失效或内容涉及侵权,请反馈至,我们会及时处理。本站只保证内容的可读性,无法保证真实性,《使用DLL进行不同语言之间的调用》该内容的真实性请自行鉴别。