我对VC没什么了解,现在的程序要调用VC编写的一个dll文件。
我用VC调用这个dll文件的话,是没有问题的,可以正常的运行,
但是我用delphi调用的话,死活不行。
这个dll中的函数用
extern "C" _declspec(dllexport)输出的,
按照c中默认为cdecl,所以我在delphi中也是按照cdecl方式调用。开始以为是传参出现了问题,因为VC调用是没有问题的,所以我用VC在这个dll文件的基础上又重新做了个dll文件,没有参数传送。但是用delphi调用结果是一样的。有哪位大虾知道是怎么回事?这个dll文件是别人做好的,再改动的可能性不大,现在是使用VC可以正常使用,有什么方法让delphi也可以使用呢?

解决方案 »

  1.   

    >>按照c中默认为cdecl,所以我在delphi中也是按照cdecl方式调用。
    用 stdcall
      

  2.   

    你按照调用其它DLL的方式就可以了.
    function Csdn(CsdnStr:PChar):PChar;stdcall;external 'CSDN.dll';你可以把导出函数帖出来,我猜可能是你的类型没有搞对....
      

  3.   

    to aiirii(ari-爱的眼睛)
    我都试过了,再说原dll是不能改动的,我不可能都对应成stdcall。to  ksaiy(真爱不是取代,而是心中永恒的存在)
    我现在不方便贴原函数,不过我说了,VC中调用是可以的,所以我已经在这个dll的基础上又打包了一个dll,我在VC的代码中都把参数填充好了(基本上就是把VC下调用成功的APP中的代码拷贝过来的),因为涉及到头文件声名的问题,所以我经常这样做。按照道理不管原dll文件是不是标准通用的dll,只要我在它的基础上重新按照标准把函数输出,delphi都是应该可以调用的呀。
    我的delphi程序调用了很多VC编写的dll,从来都没出现过这样的问题,这个太奇怪了。
      

  4.   

    我也一直在DELPHI下调用DLL,并且DLL调用也有很复杂的,只要参数类型正确就没有什么问题.
      

  5.   

    对呀,我也是这么想的,以前的调用的比这个复杂的也有很多,但是都没出过什么问题,不知道这个是怎么回事。觉得不是参数的问题,因为我没有在delphi传参给dll。
    而且参数的类型也不复杂,就是有char *,PBYTE,unsigned char *,int,int *,不知道是不是内存管理不同造成的。
      

  6.   

    错误应该是从原Dll中产生的,说是“除数不能为零”的意思。
      

  7.   

    只要参数类型正确,应该没有问题的。cdecl方式调用VC的DLL是没有问题的,我用一直用这种方式来调用VC的DLL.其中注意一下结构体和指针的传送问题!
    char *,PBYTE,unsigned char *,int,int *,这些参数应该是指针的问题,才说是“除数不能为零”的意思。
      

  8.   

    >>extern "C" _declspec(dllexport)输出的,这不能表示函数是cdecl方式的参数堆栈约定。。
    它仅表示函数在导出表中名称是C方式而非C++方式。
      

  9.   

    大家在软件开发时经常会遇到这样的情况,在不同的开发环境中为实现一些功能相同的过程,由于开发所使用的设计语言不同,因而不得不编写许多类似的代码,甚至有时要在同一个开发环境不同项目中重写代码,这就造成了很大的资源浪费。动态链接库能较好的解决这个问题,重复利用代码将大大提高了开发效率。一般,用户在应用程序中基于如下要求创建和使用DLL:1. 在不同的可执行文件之间共享的程序;2. 在设计应用程序时,将其拆分成各个相互独立功能部件,为以后这些功能部件各自升级提供方便的途径。动态链接库将共享程序或功能部件做成库中的函数,形成DLL文件,其它应用程序通过使用DLL调用这些函数。在这里将对Delphi和VC中创建和使用动态链接库的方法做一介绍。Delphi和VC定义的动态链接库均可在两者的开发环境中使用。一、 用Delphi创建DLLDelphi的DLL创建并不复杂,下面向大家介绍Delphi的DLL创建方法。(1)首先创建一个新的DLL项目(NewProject)project1,文件头部为:library Project1; (2)USES语句后面加入ExPorts语句,指明调用DLL的函数名,形式为:exports  checkpwd name 'checkpwd'; (3)在DLL的Pas文件中Type......End后加入该DLL的函数或过程的声明,形式如下:FunctionName(argment):Boolean;export; 该函数也可以存在于另一个pas文件中(如Unit1.pas),此时只需在项目文件中加入:uses  Unit1 in 'Unit1.pas' {Form1}; 值得注意的是,该函数或过程应加入窗体的Create和Free(产生和释放)方法。(4)对项目进行编译即形成DLL文件,可被其它项目调用。二、Delphi中DLL的调用调用DLL有两种方法,一种是在应用程序装载时调用,另一种是在应用程序运行时调用。(1) 装载时调用DLL在调用DLL的Pas文件中,对DLL函数进行外部声明,声明应位于Implementation后,形式如下:Implementation  Function functionname(argment):Boolean;far;External 'DllName'; 其中External关键字后面的引号内是DLL的文件名,该文件一般应放在系统的system目录下,或与调用它的项目同一目录。声明以后即可在Pas文件任何地方引用DLL函数。装载时调用DLL的优点是速度较快,程序间也可共享代码。(2) 运行时调用DLLDLL的另一种调用方法是在运行时调用。这种方法要调用到Windows的API函数LoadLibrary,GetProcAddress,FreeLibrary等。此方法主要用于调用其它语言,特别是C++编译的DLL。假定你欲调用的DLL中包括一个函数:Function checkpwd(pwd:string):boolean;export; 那么,首先在欲调用DLL的程序Type类型声明处加入一句:Type  Tcheckpwd= function(pwd:string):boolean; 此句的作用如同C++中声明的函数指针。然后定义如下变量∶Var  aptr:TFarproc;  lhnd:THandle;  flag:boolean; 其中Aptr,lhnd两变量声明必须有,flag是DLL函数返回值,视情况而定。在调用DLL处加入如下语句进行DLL装载:lhnd:=Loadlibrary('路径:DLL文件名');{如lhnd:=Loadlibrary('c:\project1.dll');  aptr:=GetprocAddress(lhnd,'checkpwd'); 下面可直接调用DLL了:flag:=Tcheckpwd(aptr)( 'pwd');{根据函数填相应的变量参数} 调用完以后,用FreeLibrary释放DLL占用的内存:FreeLibrary(lhnd);三、用VC创建DLL在VC中创建DLL,与Delphi中的创建过程相似,步骤如下:(1)新建一个DLL项目。MFC提供两种类型的动态链接库:常规型DLL、扩展型DLL。其中,常规型DLL适合于非MFC开发环境下采用支持DLL调用的程序设计语言开发的应用程序,扩展型DLL只能被MFC程序使用。(2)创建该DLL中的过程或函数,只需在程序中加入下列语句:extern "C" _declspec(dllexport)   int yanzheng(CString input,char* zcm)  {  AFX_MANAGE_STATE(AfxGetStaticModuleState());  file://具体实现过程  } 该函数的功能是验证注册码是否合法,其中yanzheng为函数名,int为函数返回值类型,()内为函数参数。编译通过后即可使用。四、 VC中DLL的调用在VC中调用动态链接库时,类似于Delphi中运行时调用DLL的方法。也要调用到Windows的API函数LoadLibrary,GetProcAddress等。此方法对于调用其它语言和VC编译的DLL均适用。假定DLL中包括一个函数:int yanzheng(CString input,char* zcm) 首先在欲调用DLL函数的cpp文件前部先声明函数指针,定义函数类型:typedef int (* _YANZHENG)(CString,char* zcm); 然后定义如下变量∶HINSTANCE hLibrary;  _YANZHENG yanzheng; 在调用DLL处加入如下语句进行DLL装载: hLibrary=LoadLibrary("zcdll.dll");  yanzheng=(_YANZHENG)GetProcAddress(hLibrary,"yanzheng");  shuchu= (*yanzheng)(shuru,zcm);  FreeLibrary(hLibrary); 五、 几点提示(1)如果用Delphi创建DLL时用到其它的form,则在DLL的输出函数中应包括form的create(创建)和free(释放),而且在显示该窗口时只能用showmodal过程,不能用show过程,在后面的例子中能详细看到。(2)如果Delphi创建的DLL中的函数或过程,用string类型作为参数输入或返回string类型,当用VC或其它程序调用时,经常会出错,反之亦然。为了解决这种情况,使不同程序之间在使用字符串类型时,接口更安全,建议使用pchar类型,而不是string类型。而且要在程序中加入内存管理,使用系统提供的sharemem单元。下面是一个实现将星期标识由数字转换成英文的例子:uses  sharemem;  exports  makeitaday;  var   mydate:pchar;  function makeitaday(S:integer):pchar;stdcall;export;  implementation  function makeitaday(S:integer):pchar;stdcall;export;  var  thedate:array[0..20] of char;  begin  GetMem(mydate, 200);  if s=1 then thedate:='Sunday ';  file://……….  strpcopy(mydate,thedate);  makeitaday:=mydate;  end; 六、实例因为用Delphi创建和调用DLL,过程与用VC创建和调用DLL相似,只是前者代码要比在VC环境中稍微复杂一些,因此在文章的最后给出一个完整的用Delphi创建和调用DLL的例子。该DLL主要用来检查输入的口令是否正确,窗体含有一个Edit编辑框,一个按钮Button,在编辑框内输入口令,比较编辑框的值和输入参数返回真假值。//文件名为checkpassword.dpr;编译此文件生成checkpassword.dll   library checkpassword;  uses  SysUtils, Classes, Unit1 in 'Unit1.pas' {Form1};  exports  checkpwd name 'checkpwd';//声明DLL函数  {$R *.RES}  begin  end.file://文件名为unit1.pas   unit Unit1;  interface  uses  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;  type  TForm1 = class(TForm)  password: TEdit;  Button1: TButton;  procedure Button1Click(Sender: TObject);  private  { Private declarations }  public  { Public declarations }  end;  var  Form1: TForm1;  flag:boolean;//返回输入密码是否正确  rightpwd:string;//记录输入参数(正确的密码)  function checkpwd(pwd:string):boolean;export;//声明DLL函数  implementation  {$R *.DFM}  procedure TForm1.Button1Click(Sender: TObject);  begin  if password.text=rightpwd then  flag:=true;  form1.close;  end;function checkpwd(pwd:string):boolean;export;  begin  flag:=false;  rightpwd:=pwd;//读入正确的密码值  form1:=Tform1.create(Application);//创建密码验证窗口  form1.ShowModal;//显示窗口  checkpwd:=flag;  form1.free;//释放资源  end;  end.file://主程序main.pas,调用DLL  unit main;  interface  uses  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;  type  TForm1 = class(TForm)  jieguo: TEdit;  Button1: TButton;  procedure Button1Click(Sender: TObject);  private  { Private declarations }   public  { Public declarations }  end;  var  Form1: TForm1;  implementation  function checkpwd(pwd:string):boolean;external 'project1.dll' ;//函数说明  {$R *.DFM}  procedure TForm1.Button1Click(Sender: TObject);  begin  if checkpwd('congrong') then//调用函数  jieguo.text:='true'  else  jieguo.text:='false';  end;  end.  
      

  10.   

    是呀 同意楼上的
    1 表示为导出函数
    2 表示导出的函数为C方式 如果是C++方式就是 ?aaa@...之类的 这样外边就链接不到
    所以用C方式的话 编译器就不会改变其函数在内部的名称...只要参数类型正确,应该没有问题的。cdecl方式调用VC的DLL是没有问题的,我用一直用这种方式来调用VC的DLL.其中注意一下结构体和指针的传送问题!
    // 哦 是么 CDECL STDCALL你会汇编一下代码就好了 包括最开始的堆栈压入 以及堆栈恢复。。的方式 。char *,PBYTE,unsigned char *,int,int *,这些参数应该是指针的问题,才说是“除数不能为零”的意思。
    // 除数不能为0?? 可能你传入了空指针 然后取空指针的值...
    char* -> PChar;
    unsigned char* -> PBYTE;
    int* -> PInteger; // 或者 var Integer;
      

  11.   

    是吗? CDECL和STDCALL有这么复杂吗?汇编里面也只是顺序的问题吧有必要把问题看得那么复杂吗
      

  12.   

    to  回复人: beyondtkl(大龙驹<*step by step:Cpp&&Crack*>) ( )我已经说过了,我在VC中调用这个dll是没有问题的,所以我就直接把这个VC程序改成dll形式,也就是说参数都是在VC程序中设定好的,打个比方吧,原来的dll文件是a.dll,我在VC程序中调用这个a.dll文件是没有问题的,然后我把这个程序改成一个dll工程,生成b.dll,因为在b.dll文件中都已经设置好了参数了,所以b.dll文件导出一个无参的函数供delphi调用,这样也就是,delphi程序调用b.dll,b.dll再去调用a.dll,但是这样出现的错误是一样的。上面你们说的那些我都知道,因为我做过很多这样的程序了。但是这个就是这么怪。很显然这不是参数顺序,也不是参数类型的问题,
    可能是内存管理的问题,因为原dll文件是用来处理图片的,工作量很大。
      

  13.   

    OK 就是以DLL的形式封装另一个DLL呀 相当于代理DLL............................
    那偶也不知道虾米问题了....
      

  14.   

    楼主可以试验一下用vc的dll生成文件,然后再用delpihi调用vc的dll生成的文件来传递数据这样就不该有错了吧,cdecl方式调用应该不会有问题,偶用过好多次了
      

  15.   

    to yaven365(天涯网客)我试过了,我甚至又用VC调用了我编写的那个代理Dll,都是正常的。
    但是就是不能用Delphi调用。
      

  16.   

    这个问题真是太奇怪了,我又试了一下用VB调用,也是可以正常运行的!!!
    我想知道除了参数以外,还有什么东西使得VC编写的dll文件死活不能让Delphi调用!!!
      

  17.   

    看来没人知道是怎么回事,我只好用我最不想用的一招了,就是使用shell。sigh。
      

  18.   

    这个东西我可以给点建议:
        首先,cdecl方式输出的VC的DLL在Delphi中进行stdcall调用肯定是行不通的。参数压栈方式不同,造成取参时参数错位,这可能是楼主遇到问题的主要原因。
        解决方式楼主可以考虑:
        1.想办法以stdcall方式重新编译一下VC的DLL,这必竟是最方便省心的办法。而且要养成好习惯,想在非VC语言中使用的DLL,都要做成stdcall形式。
        2.在Delphi声明中把参数顺序倒过来,并且不要带stdcall关键字。成不成我没试过。希望对楼主有帮助。
      

  19.   

    回复人: zijida(深水游鱼,吐泡泡被追殴) ( ) 信誉:99  2004-12-03 11:40:00  得分: 0  
     
     
       这个东西我可以给点建议:
        首先,cdecl方式输出的VC的DLL在Delphi中进行stdcall调用肯定是行不通的。参数压栈方式不同,造成取参时参数错位,这可能是楼主遇到问题的主要原因。
    ----------------------
    这个不是问题,因为我不是用stdcall调用的,这点常识我还是有的。
        解决方式楼主可以考虑:
        1.想办法以stdcall方式重新编译一下VC的DLL,这必竟是最方便省心的办法。而且要养成好习惯,想在非VC语言中使用的DLL,都要做成stdcall形式。
    ------------------------------------------------
    这个没有办法,因为dll不是我写的,对方提供给我时就是用的cdecl方式。
        2.在Delphi声明中把参数顺序倒过来,并且不要带stdcall关键字。成不成我没试过。希望对楼主有帮助。
    ----------------------------------------------------能试的方法我都试了,基本上得出了结论,和参数类型,以及调用方式无关,
    猜想是内存管理不同造成的。
      

  20.   

    先看看 http://community.csdn.net/Expert/FAQ/FAQ_Index.asp?id=195669我的建议:
    使用 VC 重新包装 Dll 为 stdcall 方式,同时使用 def 文件导出 新 的 Dll
    再使用 Delphi 调用
      

  21.   

    调用是一样的,.dll文件是经过编译之后的文件基本上所有语言都可以调用.dll文件,不过的是调用函数的所使用的语法或者参数类型不一致会导致错误!
      

  22.   

    okey,看来我还是揭帖好了,大家说来说去都是那几句。