3
votes

I have following code in Delphi 7 in some function:

 var
    objServiceConfig: PQueryServiceConfigA;
    ...
    ...
    objServiceConfig:= AllocMem(anySize);
    ...
    ...
    QueryServiceConfig(hSCService, objServiceConfig, anySize, anySize2)
    .....
    .....

I am getting error: E2010 Incompatible types: 'LPQUERY_SERVICE_CONFIGW' and 'PQueryServiceConfigA'

In Delphi 7 everything is working fine but migrating it to Delphi XE4, I am getting this error.

When I change the above declaration objServiceConfig: PQueryServiceConfigA; to objServiceConfig: LPQUERY_SERVICE_CONFIG; it works. Is it right or what else I have to do?

Update:

In Delphi XE4 WinSvc, QueryServiceConfig is declared like following

function QueryServiceConfig(hService: SC_HANDLE;
  lpServiceConfig: LPQUERY_SERVICE_CONFIG; cbBufSize: DWORD;
  var pcbBytesNeeded: DWORD): BOOL; stdcall;  

{$EXTERNALSYM QueryServiceConfigA}

function QueryServiceConfigA(hService: SC_HANDLE;
  lpServiceConfig: LPQUERY_SERVICE_CONFIGA; cbBufSize: DWORD;
  var pcbBytesNeeded: DWORD): BOOL; stdcall;

{$EXTERNALSYM QueryServiceConfigW}

function QueryServiceConfigW(hService: SC_HANDLE;
  lpServiceConfig: LPQUERY_SERVICE_CONFIGW; cbBufSize: DWORD;
  var pcbBytesNeeded: DWORD): BOOL; stdcall; 

In Delphi7, WinSvc, QueryServiceConfig is declared like following

function QueryServiceConfig(hService: SC_HANDLE;
  lpServiceConfig: PQueryServiceConfig; cbBufSize: DWORD;
  var pcbBytesNeeded: DWORD): BOOL; stdcall;

{$EXTERNALSYM QueryServiceConfigA}

function QueryServiceConfigA(hService: SC_HANDLE;
  lpServiceConfig: PQueryServiceConfigA; cbBufSize: DWORD;
  var pcbBytesNeeded: DWORD): BOOL; stdcall;

{$EXTERNALSYM QueryServiceConfigW}

function QueryServiceConfigW(hService: SC_HANDLE;
  lpServiceConfig: PQueryServiceConfigW; cbBufSize: DWORD;
  var pcbBytesNeeded: DWORD): BOOL; stdcall;

It means 2nd parameter in case of Delphi 7 is of type PQueryServiceConfig/A/W while in Delphi XE4 is of type LPQUERY_SERVICE_CONFIG/A/W

2
I'm sorry to nag, but you have asked a series of questions on your D7 -> XE4 migration now. That's just fine. But it seems to me that you are not making much effort to understand what you are doing. I get the sense that you just want to do whatever it takes to make your code compile. That will almost certainly lead your into a world of pain. Compiling your code is not enough. It must be correct as well, in order to be able to run it. I do feel that you would benefit from some more understanding. If you can gain that, you'll likely get to the end of your task quicker.David Heffernan

2 Answers

3
votes

Delphi XE4 supports Unicode, and Delphi 7 is an ANSI version. So QueryServiceConfig maps to QueryServiceConfigW on XE4, but QueryServiceConfigA on D7.

To fix the problem (but see below) you should replace PQueryServiceConfigA with PQueryServiceConfig. Now, PQueryServiceConfig will map to PQueryServiceConfigW in Unicode Delphi and PQueryServiceConfigA in ANSI Delphi. And that's precisely the behaviour that you need.

More importantly you should make sure that you have read and understood Marco Cantù's whitepaper on the Unicode changes introduced in Delphi 2009. If you don't do that, and it looks like you have not, then your migration will lead to pain and suffering.


Actually, it's more complex than that. The above would all be accurate, if the Delphi header translation was correct. But it's not. It's been done incorrectly.

The declaration of QueryServiceConfig is:

function QueryServiceConfig(hService: SC_HANDLE;
  lpServiceConfig: LPQUERY_SERVICE_CONFIG; cbBufSize: DWORD;
  var pcbBytesNeeded: DWORD): BOOL; stdcall;                   

But it should be:

function QueryServiceConfig(hService: SC_HANDLE;
  lpServiceConfig: PQueryServiceConfig; cbBufSize: DWORD;
  var pcbBytesNeeded: DWORD): BOOL; stdcall;                   

Because of that you'll need to declare your variable to be of type LPQUERY_SERVICE_CONFIG to work around the error.

Sorry for taking so long to get to the bottom of this.


It seems that there's even more to it than this. TOndrej correctly points out that the state of the TYPEDADDRESS compiler directive, $T, has an impact. The default setting of this is OFF. In which case passing a PQueryServiceConfig to QueryServiceConfig results in the compiler error:

E2010 Incompatible types: 'LPQUERY_SERVICE_CONFIGW' and 'PQueryServiceConfigW'

If you switch the setting to ON, which I strongly recommend, then the compilation succeeds.

To understand why, we need to look at how these types and the function are declared. I've stripped out the ANSI declarations to keep the exposition simple:

type
  LPQUERY_SERVICE_CONFIGW = ^QUERY_SERVICE_CONFIGW;
  LPQUERY_SERVICE_CONFIG = LPQUERY_SERVICE_CONFIGW;
  QUERY_SERVICE_CONFIGW = record
    ...
  end;
  QUERY_SERVICE_CONFIG = QUERY_SERVICE_CONFIGW;
  _QUERY_SERVICE_CONFIGW = QUERY_SERVICE_CONFIGW;
  PQueryServiceConfigW = ^TQueryServiceConfigW;
  PQueryServiceConfig = PQueryServiceConfigW;
  TQueryServiceConfigW = QUERY_SERVICE_CONFIGW;
  TQueryServiceConfig = TQueryServiceConfigW;

function QueryServiceConfig(... lpServiceConfig: LPQUERY_SERVICE_CONFIG ...

Now, in the T- state, the documentation says:

In the {$T-} state, distinct pointer types other than Pointer are incompatible (even if they are pointers to the same type).

This explains the compilation error. Because LPQUERY_SERVICE_CONFIG is distinct from PQueryServiceConfig.

Now, the types could have been declared this way:

type
  QUERY_SERVICE_CONFIGW = record
  end;
  QUERY_SERVICE_CONFIG = QUERY_SERVICE_CONFIGW;
  _QUERY_SERVICE_CONFIGW = QUERY_SERVICE_CONFIGW;
  TQueryServiceConfigW = QUERY_SERVICE_CONFIGW;
  TQueryServiceConfig = TQueryServiceConfigW;

  LPQUERY_SERVICE_CONFIGW = ^QUERY_SERVICE_CONFIGW;
  LPQUERY_SERVICE_CONFIG = LPQUERY_SERVICE_CONFIGW;
  PQueryServiceConfigW = LPQUERY_SERVICE_CONFIGW;
  PQueryServiceConfig = PQueryServiceConfigW;

And then you could pass any of the four pointer types to the function since they are actually all aliases of the same type.

5
votes

You should simply use

var
  objServiceConfig: PQueryServiceConfig;

That's declared as PQueryServiceConfigA (ANSI version) in Delphi 7 and as PQueryServiceConfigW (Unicode version) in Delphi XE4.

Edit:

Unless you have "Typed @ operator" compiler option turned on ({$T+}), this produces a compiler error E2010 Incompatible types: 'LPQUERY_SERVICE_CONFIGW' and 'PQueryServiceConfigW' in Delphi XE4. So either use that option or simply redeclare the function like this:

function QueryServiceConfig(hService: SC_HANDLE; lpServiceConfig: PQueryServiceConfig; cbBufSize: DWORD;
  var pcbBytesNeeded: DWORD): BOOL; stdcall;
  external advapi32 name {$IFDEF UNICODE}'QueryServiceConfigW'{$ELSE}'QueryServiceConfigA'{$ENDIF};

This way it should compile in both Delphi 7 and XE4.