- 浏览: 261446 次
- 性别:
- 来自: 深圳
-
最新评论
-
whizkid:
[img] private void enableNdefEx ...
android通过NFC读写数据 -
zhangminglife:
您好!不错,最近正在弄这个东西,能否把demo发给我一份谢谢了 ...
SSL双向认证java实现(转) -
water卡:
android如何调用显示和隐藏系统默认的输入法 -
water卡:
android如何调用显示和隐藏系统默认的输入法 -
sjp524617477:
good
生成android使用的BKS证书
C/C++调用Delphi制作的dll时发现的一些问题 收藏
做了一个网络业务逻辑实体,是用C++编写的dll,内部有一个全局的业务实体,外部准备用Delphi编写的界面程序来控制并显示状态......
1. C++的dll中不能用C++风格的导出方式:_declspec(dllexport)来导出函数,要用C风格的导出方式:extern "C" _declspec(dllexport),否则Delphi在加载C++的dll时报错:无法定位函数xxxFun()于xxxDll.dll上。(这里假设只讨论这两种导出方式)不知道delphi能不能调用其他C风格的dll...?
例子:
C++中要这样声明函数,
extern "C" _declspec(dllexport) int Initialize();
Delphi中声明要这样,
Function Initialize():Integer; cdecl; external 'c_test.dll' name 'Initialize';
注意,这里的 cdecl 是必须的,其他的(如stdcall,pascal...)貌似都不行......似乎它是delphi调用c编写的dll的唯一合法标识,因为这由C++的dll中的_declspec方式决定了,然而在C++中为了能给delphi调用,又不允许使用其他的(如WINAPI,CALLBACK,PASCAL...)导出方式,所以就只能这样使用_declspec了。
但是,有人说过这样的对应方式:
C++的参数调用方式 对应的DELPHI的参数调用方式
_declspec cdecl
WINAPI,CALLBACK stdcall
PASCAL pascal
附注:C++中的char *对应PASCAL中的PChar。
不是没有试过,只是没有调试成功过,所以最终还是用的以上方式,即在C++中用extern "C" _declspec(dllexport)声明函数,在Delphi中用cdecl声明函数,然后Delphi应用程序调用C++的dll。
2.在1中的调用为主动调用,即delphi主动调用C++的dll,倘若反过来,用C++或者C来调用Delphi的函数,问题有些不一致了,这里又要分为两种情形:
1)C++的应用程序,调用Delphi编写的dll。
2)Delphi在调用C++的dll时,传递函数指针给dll,在dll内部根据业务逻辑,回叫这个delphi函数。
(其实1)和2)的情形似乎都一样...)
因为pascal和c是两种不同风格的语言,它们的参数列表的出栈进栈方式不一样,所以,最容易出问题的就是函数的参数列表了。不光参数列表中参数顺序会乱,而且乱得没有规律可循,当只涉及到一个整型参数时,没有问题,正常调用,但是,这只是碰巧没有问题而已......
首先,对于C++应用程序调用Delphi编写的dll,
可以这样,在C++程序里,
#include <Windows.h>
#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
typedef int(*myFun)(int arg1,int arg2,int arg3,int arg4);
int main(int argi,char* argv[])
{
HINSTANCE hDll;
hDll=LoadLibrary("delphi_dll.dll");
if (hDll!=NULL)
{
myFun fun;
fun=(myFun)GetProcAddress(hDll, "c_exe_test2");
if(fun!=NULL)
{
for(int i=0;i<5;i++)
{
printf("%d,%d,%d,%d\n",i,i+1,i+2,i+3);
fun(i,i+1,i+2,i+3);
}
}
FreeLibrary(hDll);
}
system("pause");
return 0;
}
然后在Delphi编写的dl内部,
library delphi_dll;
uses
SysUtils,
Classes,
Dialogs;
Function c_exe_test2(arg1,arg2,arg3,arg4: Integer): Integer; cdecl;
Begin
ShowMessage(
'arg1='+IntToStr(arg1)+' '+
'arg2='+IntToStr(arg2)+' '+
'arg3='+IntToStr(arg3)+' '+
'arg4='+IntToStr(arg4));
end;
exports
c_exe_test2 index 1;
begin
//todo...dll被加载时执行一次...
end.
注意了,在Delphi的dll内部,cdecl 声明是必不可少的,否则就会出现参数列表的混乱...
接下来,就去调试下C++的dll内部回叫Delphi程序的函数指针,再次检查参数列表是否正确,
在C++的dll中,
//--------------------------------------------------------------------------------
//xxx.h:
typedef int(*OnTest)(int arg1,int arg2,int arg3,int arg4);
extern "C" _declspec(dllexport) int setcb_on_test(OnTest pFun);
//--------------------------------------------------------------------------------
//xxx.cpp:
#include <Windows.h>
static OnTest CallBackOnTest = NULL;
extern "C" _declspec(dllexport) int setcb_on_test(OnTest pFun)
{
CallBackOnTest=pFun;
return 0;
}
void fun(void* arg)
{
int i=0,arg1=1,arg2=2,arg3=3,arg4=4;
while(1)
{
i++;
if(i%5==0)
if(CallBackOnTest)
{
CallBackOnTest(arg1,arg2,arg3,arg4);
arg1++;arg2++;arg3++;arg4++
}
Sleep(1000);
if(i>=100) break;
}
}
BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved )
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
HANDLE threadHandle;
DWORD threadID;
threadHandle = CreateThread(
NULL,
0,
(LPTHREAD_START_ROUTINE)fun,
NULL,
0,
&threadID);
}
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
在Delphi应用程序中,
unit UnitMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Dialogs;
Type
TObjMain = class(TObject)
private
{ Private declarations }
Public
{ Public declarations }
Constructor Create(owner: TObject);
Destructor Free();
end;
var
myObj: TObjMain ;
type
TOnTest = Function(arg1,arg2,arg3,arg4: Integer): Integer; cdecl;
Function SetCB_OnTest(pFun: TOnTest): Integer; cdecl; external 'c_test.dll' name 'setcb_on_test';
Function OnTest(arg1,arg2,arg3,arg4: Integer): Integer; cdecl;
implementation
{$R *.pas}
Function OnTest(arg1,arg2,arg3,arg4: Integer): Integer;
begin
ShowMessage(
'arg1='+IntToStr(arg1)+' '+
'arg2='+IntToStr(arg2)+' '+
'arg3='+IntToStr(arg3)+' '+
'arg4='+IntToStr(arg4 );
result:=0;
end;
constructor myObj.Create(owner: TObject);
begin
inherited;
//todo...
SetCB_OnTest(OnTest);
end;
destructor myObj.Free();
begin
//todo...
inherited;
end;
再在工程文档中,
program d_test;
uses
UnitMain in 'UnitMain.pas' {myObj};
{$R *.res}
Begin
Application.Initialize;
myObj:=TObjMain.Create(Application);
Application.Run;
end.
做了一个网络业务逻辑实体,是用C++编写的dll,内部有一个全局的业务实体,外部准备用Delphi编写的界面程序来控制并显示状态......
1. C++的dll中不能用C++风格的导出方式:_declspec(dllexport)来导出函数,要用C风格的导出方式:extern "C" _declspec(dllexport),否则Delphi在加载C++的dll时报错:无法定位函数xxxFun()于xxxDll.dll上。(这里假设只讨论这两种导出方式)不知道delphi能不能调用其他C风格的dll...?
例子:
C++中要这样声明函数,
extern "C" _declspec(dllexport) int Initialize();
Delphi中声明要这样,
Function Initialize():Integer; cdecl; external 'c_test.dll' name 'Initialize';
注意,这里的 cdecl 是必须的,其他的(如stdcall,pascal...)貌似都不行......似乎它是delphi调用c编写的dll的唯一合法标识,因为这由C++的dll中的_declspec方式决定了,然而在C++中为了能给delphi调用,又不允许使用其他的(如WINAPI,CALLBACK,PASCAL...)导出方式,所以就只能这样使用_declspec了。
但是,有人说过这样的对应方式:
C++的参数调用方式 对应的DELPHI的参数调用方式
_declspec cdecl
WINAPI,CALLBACK stdcall
PASCAL pascal
附注:C++中的char *对应PASCAL中的PChar。
不是没有试过,只是没有调试成功过,所以最终还是用的以上方式,即在C++中用extern "C" _declspec(dllexport)声明函数,在Delphi中用cdecl声明函数,然后Delphi应用程序调用C++的dll。
2.在1中的调用为主动调用,即delphi主动调用C++的dll,倘若反过来,用C++或者C来调用Delphi的函数,问题有些不一致了,这里又要分为两种情形:
1)C++的应用程序,调用Delphi编写的dll。
2)Delphi在调用C++的dll时,传递函数指针给dll,在dll内部根据业务逻辑,回叫这个delphi函数。
(其实1)和2)的情形似乎都一样...)
因为pascal和c是两种不同风格的语言,它们的参数列表的出栈进栈方式不一样,所以,最容易出问题的就是函数的参数列表了。不光参数列表中参数顺序会乱,而且乱得没有规律可循,当只涉及到一个整型参数时,没有问题,正常调用,但是,这只是碰巧没有问题而已......
首先,对于C++应用程序调用Delphi编写的dll,
可以这样,在C++程序里,
#include <Windows.h>
#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
typedef int(*myFun)(int arg1,int arg2,int arg3,int arg4);
int main(int argi,char* argv[])
{
HINSTANCE hDll;
hDll=LoadLibrary("delphi_dll.dll");
if (hDll!=NULL)
{
myFun fun;
fun=(myFun)GetProcAddress(hDll, "c_exe_test2");
if(fun!=NULL)
{
for(int i=0;i<5;i++)
{
printf("%d,%d,%d,%d\n",i,i+1,i+2,i+3);
fun(i,i+1,i+2,i+3);
}
}
FreeLibrary(hDll);
}
system("pause");
return 0;
}
然后在Delphi编写的dl内部,
library delphi_dll;
uses
SysUtils,
Classes,
Dialogs;
Function c_exe_test2(arg1,arg2,arg3,arg4: Integer): Integer; cdecl;
Begin
ShowMessage(
'arg1='+IntToStr(arg1)+' '+
'arg2='+IntToStr(arg2)+' '+
'arg3='+IntToStr(arg3)+' '+
'arg4='+IntToStr(arg4));
end;
exports
c_exe_test2 index 1;
begin
//todo...dll被加载时执行一次...
end.
注意了,在Delphi的dll内部,cdecl 声明是必不可少的,否则就会出现参数列表的混乱...
接下来,就去调试下C++的dll内部回叫Delphi程序的函数指针,再次检查参数列表是否正确,
在C++的dll中,
//--------------------------------------------------------------------------------
//xxx.h:
typedef int(*OnTest)(int arg1,int arg2,int arg3,int arg4);
extern "C" _declspec(dllexport) int setcb_on_test(OnTest pFun);
//--------------------------------------------------------------------------------
//xxx.cpp:
#include <Windows.h>
static OnTest CallBackOnTest = NULL;
extern "C" _declspec(dllexport) int setcb_on_test(OnTest pFun)
{
CallBackOnTest=pFun;
return 0;
}
void fun(void* arg)
{
int i=0,arg1=1,arg2=2,arg3=3,arg4=4;
while(1)
{
i++;
if(i%5==0)
if(CallBackOnTest)
{
CallBackOnTest(arg1,arg2,arg3,arg4);
arg1++;arg2++;arg3++;arg4++
}
Sleep(1000);
if(i>=100) break;
}
}
BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved )
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
HANDLE threadHandle;
DWORD threadID;
threadHandle = CreateThread(
NULL,
0,
(LPTHREAD_START_ROUTINE)fun,
NULL,
0,
&threadID);
}
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
在Delphi应用程序中,
unit UnitMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Dialogs;
Type
TObjMain = class(TObject)
private
{ Private declarations }
Public
{ Public declarations }
Constructor Create(owner: TObject);
Destructor Free();
end;
var
myObj: TObjMain ;
type
TOnTest = Function(arg1,arg2,arg3,arg4: Integer): Integer; cdecl;
Function SetCB_OnTest(pFun: TOnTest): Integer; cdecl; external 'c_test.dll' name 'setcb_on_test';
Function OnTest(arg1,arg2,arg3,arg4: Integer): Integer; cdecl;
implementation
{$R *.pas}
Function OnTest(arg1,arg2,arg3,arg4: Integer): Integer;
begin
ShowMessage(
'arg1='+IntToStr(arg1)+' '+
'arg2='+IntToStr(arg2)+' '+
'arg3='+IntToStr(arg3)+' '+
'arg4='+IntToStr(arg4 );
result:=0;
end;
constructor myObj.Create(owner: TObject);
begin
inherited;
//todo...
SetCB_OnTest(OnTest);
end;
destructor myObj.Free();
begin
//todo...
inherited;
end;
再在工程文档中,
program d_test;
uses
UnitMain in 'UnitMain.pas' {myObj};
{$R *.res}
Begin
Application.Initialize;
myObj:=TObjMain.Create(Application);
Application.Run;
end.
发表评论
-
PBOC规范研究之六、变长记录文件
2014-08-14 20:11 962PBOC规范研究之六、变长记录文件 此博文包含图片 (20 ... -
Windows桌面共享中一些常见的抓屏技术
2014-06-06 15:01 11021. BitBlt 我想做Windows开 ... -
error C2440 “static_cast” 无法从“void (__thiscall )(void)”转换为“LRESULT
2013-11-18 13:51 1588error C2440 “static_cast” 无法从 ... -
WOSA/XFS结构、背景等介绍
2013-11-14 13:28 1257前言: 写给 ... -
查看oracle用户数据库连接数
2013-10-30 12:31 705查看oracle用户数据库连接数 1、查询oracle的连接 ... -
几种穿透防火墙技术
2013-07-12 18:28 1071本人对几种穿透防火墙技术 以下是本人对几种穿透技术学习笔记和一 ... -
C# Socket编程笔记
2013-06-16 08:58 0看到这个题目,是不是 ... -
金融行业密钥详解
2013-05-15 16:48 987金融行业因为对数据比较敏感,所以对数据的加密也相应的比较重视。 ... -
rdp delphi实现远程桌面
2012-11-11 00:17 76821. 首先确保你的机器上存在mstscax.dll,如果没有这 ... -
xml通配符
2012-11-09 09:33 2481解析xml字符串 < -> < &g ... -
cobol中常用的数据类型
2012-08-22 15:13 1303COBOL上的基本类型大致分为:常量、变量、直接数和结构体。下 ... -
(转)学习maven的使用,看到一篇很实用的入门教程(菜鸟级入门)
2012-07-12 15:19 892一、前言 早 ... -
NFC相关研究
2012-05-15 14:07 1183NFC概述 NFC是短距离的无线通信,通常距 ... -
Android 面试题
2012-05-15 14:05 1005Android 面试题 经典 1、 Android dvm的进 ... -
使用Java实现CA
2012-04-11 14:31 951一. 准备 1. JDK 1.6 2. 安 ... -
Eclipse快捷键汇总
2012-03-20 10:39 834自动补齐类名 Alt+. 作用 ... -
SSL的工作流程简介(转)
2012-03-01 16:47 9741:客户端的浏览器向服务器传送客户端 SSL 协议的版本号,加 ... -
Http之Get/Post请求区别
2011-09-06 15:24 9131.HTTP请求格式: <request line> ... -
keystore提取私钥和证书
2011-07-19 10:46 2749keytool -genkey -alias test -ke ... -
Keytool命令行参数说明
2011-07-11 15:47 1190Keytool命令行参数说明 2010-03-19 17:05 ...
相关推荐
在本技术文档中,我们将深入探讨如何利用Delphi来调用C++编写的DLL(动态链接库)。这一过程不仅能够帮助我们充分利用C++代码的强大功能,还能让Delphi应用程序更加灵活多变。以下将详细介绍Delphi调用C++ DLL的技术...
总结来说,本示例展示了VC(或C#)如何调用Delphi DLL,传递类对象并实现回调功能。这涉及到了跨语言接口设计、数据类型映射、内存管理以及回调函数的实现。通过这种方式,我们可以充分利用各种编程语言的优点,实现...
// 调用Delphi DLL中的函数 } ``` 5. **编译本地代码** 使用合适的C++编译器(如GCC或Visual Studio)编译本地代码,生成动态链接库(.dll文件)。确保编译时链接到JNI库,并正确设置系统路径以找到Java的库。 ...
本文将深入探讨如何在C# 2013中调用Delphi 7编写的DLL库文件,包括通过函数和存储过程两种方式。 首先,理解基本原理:C#调用DLL主要依赖于P/Invoke(Platform Invoke)特性,这是.NET Framework提供的一种机制,...
本案例涉及的是C++调用Delphi编写的动态链接库(DLL)的实践,这是一种混合编程技术,旨在利用两种语言的优势。下面将详细阐述这个主题。 首先,Delphi是一种基于Pascal语言的开发工具,以其高效、易读的语法和强大...
**C++调用DLL** 在C++中,调用DLL主要通过`LoadLibrary`和`GetProcAddress`函数来实现。首先,`LoadLibrary`用于加载指定路径的DLL文件,返回一个句柄。然后,`GetProcAddress`使用该句柄获取DLL中特定函数的地址,...
在IT行业中,跨语言通信是常见的需求,本教程将详细探讨如何使用VC++(Visual C++)和C#调用Lazarus(基于Delphi的IDE)编写的DLL(动态链接库),并演示各种参数传递方式,包括普通类型、结构体、字符串以及回调...
extern "C" JNIEXPORT void JNICALL Java_DelphiDll_callDelphiFunction(JNIEnv *env, jobject obj, jint input) { // 调用Delphi DLL中的函数 // 假设Delphi DLL有一个名为CallFromJava的函数接受int参数并无...
在Delphi编程中,动态调用DLL(Dynamic Link Library)是一种常见的技术,它允许你在运行时加载和使用库函数,而无需在编译时硬编码这些依赖。这为程序提供了更大的灵活性,因为你可以根据需要加载特定的DLL,或者在...
在VC项目中调用Delphi DLL,首先需要添加生成的LIB文件到项目的链接器输入中。然后通过`#pragma comment(lib, "yourlib.lib")`来指定库文件。接着,通过`extern "C"`来确保C++的名称修饰不影响函数调用,因为Delphi...
"Delphi 调用VC生成的DLL"是跨平台编程的一个常见场景,涉及到两种不同的编程环境——Delphi和Visual C++(VC)的交互。 1. **在VC中创建DLL**: - 首先,在VC中创建一个新的DLL工程。 - 定义导出函数,使用`...
本实例探讨了如何在C++ Builder环境中调用Delphi编写的PAS(Pascal)文件,这涉及到接口设计、动态链接库(DLL)的使用以及跨语言的类型映射等关键知识点。 首先,Delphi是一种基于Pascal语言的开发工具,其编译后...
- Delphi 和 C++ 之间的 DLL 调用需要注意函数调用约定。Delphi 默认使用 `stdcall`,而 C 使用 `cdecl`。如果不匹配,可能导致调用错误。 - 可以使用 `extern "C"` 或 Delphi 的 `{$APPTYPE CONSOLE}` 来调整调用...
本篇将深入探讨如何使用Delphi调用由VC(Visual C++)编写的DLL(动态链接库)文件,重点在于参数传递的过程。首先,理解DLL的基本概念是必要的。DLL是一种共享代码的机制,允许多个程序同时使用同一段代码,从而...
- 要使用JNI调用Delphi DLL,需要创建一个C接口作为桥接,将Delphi的函数包装在C函数中,然后再由JNI调用这些C函数。这涉及到了双层封装,可能会导致稳定性问题。 - 另一种方法是在Delphi开发DLL时直接引用`jni....
如果DLL位于其他位置,如`C:\`,则需要完整地指定路径,例如`external 'C:\Delphi.dll'`。 #### 三、静态调用DLL示例 假设我们需要编写一个简单的DLL,包含一个名为`TestDll`的函数,该函数接受一个整数参数,并...
由于C++的名称修饰(name mangling),在导出C++类时,通常建议使用纯虚基类接口(C-style)或者使用ATL的`IClassFactory`接口,以避免名称兼容性问题。这样,Delphi可以更容易地识别和调用导出的方法。 3. **...
当Java程序需要调用C、C++或Delphi等本地代码时,可以通过JNI来实现。在Java端,我们创建一个本地方法,该方法的声明会关联到Delphi DLL中的相应函数。 1. **创建Delphi动态库** - 使用Delphi编写DLL项目,定义...
综上所述,这个项目展示了如何在Java桌面应用程序中通过JNI调用Delphi编写的DLL,实现RFID读卡功能。这种跨语言的编程方式结合了Java的平台无关性和Delphi的高效性,为RFID应用提供了灵活且高效的解决方案。
JNI允许Java代码调用C、C++等本地代码,从而间接调用Delphi DLL。以下是一些关键步骤: 1. **创建Delphi DLL**:在Delphi中,你需要创建一个新的项目,定义一个或多个导出函数。导出函数应该遵循C调用约定,因为JNI...