C/C++调用Delphi制作的dll时发现的一些问题

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.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Delphi是一种编程语言和开发环境,用于创建各种类型的应用程序。它支持连接到非托管内存dll的功能,通过使用一些特定的技术和函数库来实现。 非托管内存dll是指由其他语言,如C/C++编写的动态链接库。这些dll通常包含了实现某些特定功能的代码和数据。Delphi可以通过调用这些dll中的函数来使用这些功能。 要使用非托管内存dll,首先需要在Delphi中创建一个包含对应dll函数接口的类型库。这可以通过使用Delphi自带的类型库导入工具来实现,该工具可以从dll文件中自动生成相应的接口定义。 一旦类型库被创建,就可以在Delphi中使用这些dll函数了。通过使用函数接口,在代码中调用dll中的函数,并传递所需的参数。这样可以利用dll的功能,让Delphi应用程序具有更多的功能和灵活性。 在使用非托管内存dll,需要注意内存管理的问题Delphi的垃圾回收机制只能回收托管内存,而不能回收非托管内存。所以在与非托管内存dll交互,需要确保正确地分配和释放内存,以防止内存泄漏和访问冲突。 为了管理非托管内存,Delphi提供了一些用于分配和释放内存的函数和方法。在调用非托管内存dll的函数之前,可以使用这些函数来分配所需的内存空间。在调用完成后,使用相应的函数来释放已分配的内存空间。 总结来说,Delphi可以通过连接到非托管内存dll来扩展应用程序的功能。通过创建函数接口,调用dll中的函数,并正确管理非托管内存,可以实现与dll的交互。这样,就能够利用dll中的功能,提供更多的功能和灵活性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

c_feers

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值