2
votes

I'm trying to use a function that calls SetupDiGetDeviceRegistryProperty with Delphi 7. The call is from the example function SetupEnumAvailableComPorts. It looks like this:

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

I get the error "Types of actual and formal parameters must be identical" on the parameters @PropertyRegDataType, and @RequiredSize. These parameters are declared:

var
  RequiredSize: Cardinal;
  PropertyRegDataType: DWORD;

MSDN describes these parameters as: "RequiredSize [out, optional] A pointer to a variable of type DWORD that receives the required size, in bytes, of the PropertyBuffer buffer that is required to hold the data for the requested property. This parameter is optional and can be NULL." and "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."

The declaration of SetupDiGetDeviceRegistryProperty (in SetupAPI.pas from JVCL) looks like:

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

Since PropertyRegDataType and RequiredSize are var parameters, they should be able to be passed without the @ operator. In fact, if I remove the @ operators from the function call parameters, the code compiles, but crashes with an access violation (read of address 0). The original code was written for Delphi 7, so why would they use the @ operator on these parameters? What am I missing?

2
You should report this issue to JEDI's WINAPI team, because var modifier violates optional clause in function contract (it is still possible to pass nil but using rather dirty hack) - Free Consulting
Are you sure the code really compiled in Delphi 7? It's not unheard of for people to publish code that doesn't compile. Also consider that the Jedi code could have changed during the six years since your code was published. Besides, the Jedi declaration is wrong — pointer parameters that are allowed to be null should always be declared as pointers in Delphi. - Rob Kennedy

2 Answers

2
votes

Both of your variables PropertyRegDataType and RequiredSize should be declared as DWORD. You actually declare RequiredSize as Cardinal although that is equivalent.

You are correct that since they are var parameters you should not include the @ address operator.

It's hard to say why you are getting the error message without actually knowing what you pass for the other parameters.

EDIT

As commentators have pointed out, the JEDI translation is incorrect and PropertyRegDataType, because it is an optional parameter, should be passed by value and typed as PDWORD so that you are able to pass nil.

4
votes

Delphi supports "reference parameters" via the var and out keywords and in some API conversions, the C-like pointers may be replaced by this convention; these paremeters are mandatory and must be passed as-is, w/o the address operator @.
If the parameter declaration is left as pointer, allowing you to pass nil, you have to ensure the parameter is optional -or- set it to valid memory memory location of appropriate size via the @ operator; no typechecking is performed in this case.