Delphi中的Windows API参数 - 使用或不使用@运算符传递var参数?

时间:2011-02-15 14:26:29

标签: windows delphi winapi delphi-7

我正在尝试使用一个用Delphi 7调用SetupDiGetDeviceRegistryProperty的函数。 该调用来自示例函数SetupEnumAvailableComPorts。它看起来像这样:

SetupDiGetDeviceRegistryProperty(
  DevInfoHandle,
  DeviceInfoData,
  RegProperty,
  @PropertyRegDataType,
  nil,
  0,
  @RequiredSize
);

我在参数@PropertyRegDataType和@RequiredSize上得到错误“实际和形式参数的类型必须相同”。声明了这些参数:

var
  RequiredSize: Cardinal;
  PropertyRegDataType: DWORD;

MSDN将这些参数描述为:“RequiredSize [out,optional]指向DWORD类型变量的指针,该变量接收PropertyBuffer缓冲区所需的大小(以字节为单位),该缓冲区需要保存所请求的数据此参数是可选的,可以为NULL。“和”PropertyRegDataType [out,optional]指向接收正在检索的属性的数据类型的变量的指针。这是其中一个标准注册表数据类型。此参数是可选的,可以为NULL。“

SetupDiGetDeviceRegistryProperty的声明(在JVCL的SetupAPI.pas中)声明如下:

function SetupDiGetDeviceRegistryProperty(
  DeviceInfoSet: HDEVINFO;
  const DeviceInfoData: TSPDevInfoData; 
  Property_: DWORD;
  var PropertyRegDataType: DWORD; 
  PropertyBuffer: PBYTE; 
  PropertyBufferSize: DWORD;
  var RequiredSize: DWORD
): BOOL; stdcall; {$EXTERNALSYM SetupDiGetDeviceRegistryProperty}

由于PropertyRegDataType和RequiredSize是var参数,因此它们应该能够在没有@运算符的情况下传递。实际上,如果我从函数调用参数中删除@运算符,代码就会编译,但会因访问冲突而崩溃(读取地址0)。 original code是为Delphi 7编写的,为什么他们会在这些参数上使用@运算符?我错过了什么?

2 个答案:

答案 0 :(得分:4)

Delphi通过varout关键字支持“参考参数”,在某些API转换中,类似C的指针可能被此约定所取代;这些参数是强制性的,必须按原样传递,没有地址操作员@ 如果参数声明保留为指针,允许您传递nil,则必须确保参数是可选的 - 或者 - 通过{将其设置为适当大小的有效内存位置{1}}运算符; 在这种情况下不执行类型检查

答案 1 :(得分:2)

您的变量PropertyRegDataTypeRequiredSize都应声明为DWORD。您实际上将RequiredSize声明为Cardinal,尽管这是等效的。

您是正确的,因为它们是var参数,您不应该包含@地址运算符。

很难说为什么在没有真正知道你为其他参数传递的内容的情况下收到错误消息。

修改

正如评论员指出的那样,JEDI翻译不正确且PropertyRegDataType,因为它是一个可选参数,应该按值传递并输入为PDWORD,以便您能够通过{{ 1}}。