一个有关VC写的动态链接库,在Delphi中调用的小问题?(30分)

  • 主题发起人 Archerfl
  • 开始时间
A

Archerfl

Unregistered / Unconfirmed
GUEST, unregistred user!
我在VC当中随便写了一个dll,名叫 test.dll。这里面有一个导出函数,内容如下:
extern "C" int __stdcall Sum(int m,int n)
{
return m + n;
}
假如我这样写的话,并在Def文件中的EXPORTS中写上Sum,那么在Delphi这边可以通过隐式调
用到该函数。(声明为:function Sum(m,n: Integer): Integer;stdcall;external 'test.dll';)
但假如我在dll中用如下这种形式导出该函数:
extern "C" __declspec(dllexport) int __stdcall Sum(int m,int n)
{
return m + n;
}
则在Delphi这边再通过如上的隐式调用的时候,在运行的时候就会得到报错,说:“找不到
相就的Sum函数在test.dll中的入口!”
请问各位大虾这是为什么?这两种VC的dll导出函数写出的dll,在VC程序当中调用是均可通
过的,为什么在Delphi只有一种可以用呢?请指点一二,谢!

 
去掉__stdcall,用cdecl(两边都改)试试
---------------------------------------
When you declare a procedure or function, you can specify a calling convention
using one of the directives register, pascal, cdecl, stdcall, and safecall. For example,

function MyFunction(X, Y: Real): Real; cdecl;

...

Calling conventions determine the order in which parameters are passed to the
routine. They also affect the removal of parameters from the stack, the use of
registers for passing parameters, and error and exception handling. The default
calling convention is register.

The register and pascal conventions pass parameters from left to right; that is,
the leftmost parameter is evaluated and passed first and the rightmost
parameter is evaluated and passed last. The cdecl, stdcall, and safecall
conventions pass parameters from right to left.
For all conventions except cdecl, the procedure or function removes
parameters from the stack upon returning. With the cdecl convention, the caller
removes parameters from the stack when the call returns.

The register convention uses up to three CPU registers to pass parameters,
while the other conventions pass all parameters on the stack.
The safecall convention implements COM error and exception handling.

The table below summarizes calling conventions.

Directive Parameter order Clean-up Passes parameters in registers?
register Left-to-right Routine Yes
pascal Left-to-right Routine No
cdecl Right-to-left Caller No
stdcall Right-to-left Routine No
safecall Right-to-left Routine No
The default register convention is the most efficient, since it usually avoids
creation of a stack frame. (Access methods for published properties must use
register.) The cdecl convention is useful when you call functions from DLLs
written in C or C++, while stdcall and safecall are used for Windows API calls.
The safecall convention must be used for declaring dual-interface methods.
The pascal convention is maintained for backward compatibility. For more
information on calling conventions, see Program control.

The directives near, far, and export refer to calling conventions in 16-bit
Windows programming. They have no effect in 32-bit applications and are
maintained for backward compatibility only.
 
改为cdecl后确实两种方式都可以用了,但是为什么呢?
 
stdcall和cdecl是两中不同的调用方式,stdcall是Win API的标准调用,cdecl是C/C++的调用方式,
我不是很懂,你仔细看看上面那段英文。
 
to zw84611:
  您上贴所述那段英文文字,其实我曾经看过。那是Delphi中介绍有关调用约定的叙述!
但是,在VC写的动态链接库中无论用哪种调用约定,只要Delphi支持相应的约定,在声明函
数的时候以相应的约定形式写出来不就可以了,为什么这里不行呢?
 
查一下MSDN:

dllimport, dllexport
Microsoft Specific

__declspec( dllimport ) declarator

__declspec( dllexport ) declarator

The dllexport and dllimport storage-class attributes are Microsoft-specific extensions to the C and C++ languages.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

明白了?

 
to zw84611:
   不好意思,我还是不明白您的意思,请详细叙述一下,谢!
 
抱歉,我对上面英文的理解有误。

问题:
"__declspec( dllexport ) xxx __stdcall ... " Delphi调用时会有问题(Delphi中申明也为stdcall),
"__declspec( dllexport ) xxx __cdecl ... " Delphi可以顺利调用(Delphi中申明也为cdecl),
而若用修改.def文件的方法(不用declspec( dllexport ) ),则stdcall和cdecl都可顺利调用。
这是为什么?

...我不知道,请大虾指教吧[:)]
 
VC与Delphi之间动态链接库互相调用


Delphi 调用VC的DLL


VC中DLL声名格式:

Extern “C” void __declspec(dllexport) __stdcall ShowMess(HWND hwnd, char* mess);

输出格式为:_ShowMess@8,“8”为函数参数字节数

为了避免名称分裂,可采用以下方法解决:

1.声明中不加__stdcall,采用VC默认格式__cdecl,但在Delphi中要注明调用格式为cdecl。

2.在VC工程中添加def文件,如:

LIBRARY

EXPORTS

ShowMess @1

则DLL中输出函数名称不分裂。


Delphi中调用格式:

Procedure ShowMess (h:HWND; mess:pChar); Stdcall;{Cdecl;} external LibName;

如无Stdcall或Cdecl声名,Delphi默认Register(FastCall)调用格式。


注意Delphi与VC的对齐格式不同,在VC中定义结构时要用以下格式:

#pragma pack(4)

//结构定义

#pragma pack()


常用工具:

TDump.exe-Delphi 4 和 C++ Builder 3 提供

Impdef.exe 和 Implib.exe - C++ Builder 3提供

DumpBin.exe-VC5.0提供

Lib.exe-VC5.0提供


VC调用Delphi的DLL



Delphi中的声名格式:

Function ShowDialog( hMainWnd:THandle; Msg:pChar ):integer; stdcall;

输出到Dll文件中时,名称不分裂。


VC中的调用格式:

extern "C" __declspec(dllimport) int __stdcall ShowDialog( HWND hwnd,char* Msg );

.如带有__stdcall,则要求Lib文件中对应函数名称分裂,可有以下步骤生成Lib文件:

.用Impdef.exe生成def文件,格式为:Impdef def文件名 dll文件名

.手工调制def文件参数,如ShowDialog改为ShowDialog@8

.用Lib.exe生成lib文件,格式为:Lib /def:def文件名

.如声名中无__stdcall,默认调用格式仍为stdcall,但不要求名称分裂,用以下批处理文件MkLib.bat可生成Lib文件:

@echo off

if %1.==. goto error

impdef %1.def %1.dll

lib /def:%1.def

goto end

:error

echo Usage: MkLib DllName

echo Note: Don't add extension ".dll" to parameter "DllName"

:end
 
多人接受答案了。
 
顶部