首页 文章

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

提问于
浏览
2

我正在尝试使用一个用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] A pointer to a variable that receives the data type of the property that is being retrieved. This is one of the standard registry data types. This parameter is optional and can be 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 回答

  • 4

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

    你是正确的,因为它们是 var 参数,你不应该包括 @ 地址运算符 .

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

    EDIT

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

  • 2

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

相关问题