很有挑战的问题,请参加,你会从中学到很多……(200分)

杨深

Unregistered / Unconfirmed
GUEST, unregistred user!
VC 中定义一可变参数的动态链接库函数Test.dll
int WINAPI TestParam(char * sFormat,...)
{
int first=3;
int count = 0, sum = 0, i = 0;
va_list marker;
va_start( marker, sFormat )

while( i != -1 )
{
i = va_arg( marker, int);
}
va_end( marker )

return 0;
}

在Delphi中调用

Delphi 中定义
unit Test;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ComCtrls, StdCtrls;
function TestParam(sDbName:pchar
const Args: array of const): integer
stdcall;
implementation
const
TDLL = 'Test.dll';
function TestParam
external TDLL name 'TestParam';
end.

执行
TestParam('%d,%d,%d',[1,2,4]);
出错,在VC中调试看到参数取不正确。
请问原因


其实delphi中可以定义
function testParam(sFormat:pchar;const args: array of const):extended;
var
i:integer;
begin
Result := 0;
for i := low(args) to high(args) do
case args.vtype of
vtinteger: Result := Result + args.vinteger;
vtboolean: if args.vboolean then Result := Result + Ord(args.vBoolean);
vtchar: Result := Result + Ord(args.vchar);
vtextended: Result := Result + args.vextended^;
vtstring: Result := Result + strtointdef((args.vstring^),0);
vtansistring: Result := Result + strtointdef(string(args.vansistring),0);
vtcurrency: Result := Result + args.vcurrency^;
end;
……
end;


请问变参在Delphi 中还可用别的办法吗?除了用const args: array of const
 
VC中一种定义
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) &amp
~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )

我想可能是Array 传过的的是个地址,而这边却把它当作一个参数了,应该再加个偏移。
 
function TestParam(sDbName:pchar
const Args: array of const): integer
cdcel;
这样做不知行不行,Help中讲对于变参应该用cdcel调用方式!
 
TestParam('%d,%d,%d',[1,2,4]);
对不起,刚才写错了应为:
TestParam('%d,%d,%d',[1,2,4,-1]);
但还是不对,前面的数据就不对。
 
想自己做一个取的方法
 
Array of const
原来数组中是一个结构
在开始两个取不到数据
后面的隔一个取到数据
 
Function TestParam(sFormat:pchar;const Args:array of const):integer;stdcall

external 'Test.DLL';
 
同意qiya,这种问题大部分原因是因为没有声明以c的方式传递参数
 
wonsfon:
请问怎么声明,我用了_cdcel(两边改都不行)。
 
你的方法基本上是行不通的.首先我们先不说调用堆栈的问题,
光是这个array of const就大有文章,这个const在Delphi编译
时实际上是当作TVarRec类型处理的,TVarRec的定义如下:
TVarRec = record { do not pack this record
it is compiler-generated }
case Byte of
vtInteger: (VInteger: Integer
VType: Byte);
vtBoolean: (VBoolean: Boolean);
vtChar: (VChar: Char);
vtExtended: (VExtended: PExtended);
vtString: (VString: PShortString);
vtPointer: (VPointer: Pointer);
vtPChar: (VPChar: PChar);
vtObject: (VObject: TObject);
vtClass: (VClass: TClass);
vtWideChar: (VWideChar: WideChar);
vtPWideChar: (VPWideChar: PWideChar);
vtAnsiString: (VAnsiString: Pointer);
vtCurrency: (VCurrency: PCurrency);
vtVariant: (VVariant: PVariant);
vtInterface: (VInterface: Pointer);
vtWideString: (VWideString: Pointer);
vtInt64: (VInt64: PInt64);
end;
每个TVarRec记录有16字节那么大.

C函数这边,开放参数调用是把实际使用的参数由调用者一个一个压入堆栈中,
完成调用后再由调用函数来清理堆栈.

而Delphi的参数数组调用则是在调用前构造一个参数数组,
然后只传递参数数组的指针给被调用函数...

很明显的,
假设调用为testParam('%d %s %d %s',[i,s,j,r]);
对于Delphi中申明的
function testParam(sFormat:pchar;const args: array of const):extended;
Delphi只传给testParam函数sFormat指针和args数组的指针,一共两个参数.

而在C中申明的
int WINAPI TestParam(char * sFormat,...)
则上C编译器以为一共传给它了5个参数
就算双方都以同样的调用约定进行编译,也不能正确地实现预期的目标.
毕竟Delphi的开放数组调用和C的开放参数调用在实现上是风牛马不相及的事情.

唯一可能有些类似的是Delphi的Write/Read函数,真正支持开放参数的,
因为是Pascal语法的一部份,实现上非常特殊,但工作原理可能和C也不尽相同.
 
skyweb
你说得很对,我正在找个变通的方法,可以把16字节作个处理,因为数据可以取到,分离看看,
 
多人接受答案了。
 
顶部