使用DLL进行不同语言之间的调用
生活随笔
收集整理的這篇文章主要介紹了
使用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; }?
接下來是使用結構體的,由于結構體會對成員進行對齊,所以在調用的時候需要注意和這里的結構體有相同的內存布局 復制內容到剪貼板
代碼:
#include<string.h> struct 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 ); }
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 __cplusplusextern "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);#include<string.h> typedef 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<stdio.h> #pragma comment(lib,"dlltest.lib") #include<windows.h>int __stdcall CallBackFunc(const char*lp) {return printf("%s ",lp); } int main() {int x=2,y=3;testStruct s1;testStruct2 s2; #ifdef __cplusplusprintf("%d ",Min( 2,3 ) );printf("%f ",Min( 2.0,3.0 ) ); #elseint(__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 ) ); #endifswap( &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} usesSysUtils,Classes,Math,Windows;typetestStruct = recorda:Char;b:Integer;c:Double;sz:array[0..4] of char;end; {$A1}{定義record使之和 修改了對齊的結構體有相同的內存布局 }testStruct2 = recorda: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;beginwriteln( '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;beginwriteln( 'Min(1,2)=' , Min( 1,2 ) );writeln( 'Min_d(1.0,2.1)=' , Min_d( 1.0,2.1 ) );end;varx,y:Integer;a_struct:testStruct;b_struct:testStruct2; beginwriteln( '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 testStructa As Byteb As Longc As Doublesz As String * 5 End Type Public Type Tempsz As String * 5 End Type Public Declare Function Max_d Lib "dlltest" (ByVal a As Double, ByVal b As Double) As Double Public Declare Function Min Lib "dlltest" Alias "?Min@@YGHHH@Z" (ByVal a As Long, ByVal b As Long) As Long Public Declare Function UseStruct Lib "dlltest" (ByRef a As testStruct) As Long Public Declare Function UseStruct2 Lib "dlltest" (ByRef a As Any) As Long Public Declare Function UserCallBackFunc Lib "dlltest" (ByVal s As String, ByVal f As Long) As LongFunction CallBack(ByVal lp As Long) As LongDim L As LongL = lstrlen(lp)Dim s As Strings = String$(L + 1, vbNullChar)CopyMemory s, lp, LMsgBox s & " , " & Str$(L)Debug.Print "CallBack", sCallBack = 3 End FunctionSub Main()Debug.Print Max_d(4, 5), Min(4, 6)Dim a As testStructDebug.Print UseStruct(a)Debug.Print Chr(a.a), a.b, a.c, a.szDim buf(18) As ByteDebug.Print "----------------"Debug.Print UseStruct2(buf(0))Dim t As ByteCopyMemory t, buf(0), 1Dim L As LongCopyMemory L, buf(1), 4Dim d As DoubleCopyMemory d, buf(5), 8Dim s As TempCopyMemory s, buf(13), 5Debug.Print Chr(t), L, d, s.szDebug.Print UserCallBackFunc("_測試asdasd中文sdfasdf", AddressOf CallBack) End Sub?
VB版本需要注意的是lstrlen 的聲明 參數不是String而是Long類型,這是因為如果是String的話VB會對參數進行改造,將字符串指針轉化為String類型,而我這里不需要改變,就需要一個原始的Long類型的指針.所以就更改了API的函數聲明.以適應我的需求。總結
以上是生活随笔為你收集整理的使用DLL进行不同语言之间的调用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java调用c dll,指针参数和结构体
- 下一篇: 字节对齐的作用