Question Details

No question body available.

Tags

delphi winapi pascal freepascal

Answers (1)

Accepted Answer Available
Accepted Answer
January 13, 2026 Score: 4 Rep: 610,306 Quality: Expert Completeness: 100%

The definition of CERTLOGOTYPEIMAGEINFO that you have shown here doesn't match what MSDN defines:

CERTLOGOTYPEIMAGEINFO structure

typedef struct CERTLOGOTYPEIMAGEINFO {
  DWORD  dwLogotypeImageInfoChoice;
  DWORD  dwFileSize;
  DWORD  dwXSize;
  DWORD  dwYSize;
  DWORD  dwLogotypeImageResolutionChoice;
  union {
    DWORD dwNumBits;
    DWORD dwTableSize;
  } DUMMYUNIONNAME;
  LPWSTR pwszLanguage;
} CERTLOGOTYPEIMAGEINFO, PCERT_LOGOTYPE_IMAGE_INFO;

As you can see, there are 3 additional fields that your code is missing:

  • dwLogotypeImageInfoChoice
  • dwFileSize
  • dwXSize

And also, the pwszLanguage field is a LPWSTR (wchar_t
) pointer rather than a DWORD (unsigned int). This is important for Win64 compatibility, otherwise you would truncate the pointer when you compile for 64-bit.


That being said -

In Pascal, both Delphi and FreePascal, you simply can't have additional fields after the variant part of a record. So your original attempt at a translation will not work.

You will have to use a separate record to hold the union'ed fields, eg:

type
  CERTLOGOTYPEIMAGEINFOUNION = record
    case Boolean of
      True: (dwNumBits: DWORD);
      False: (dwTableSize: DWORD);
  end;
  CERTLOGOTYPEIMAGEINFO = record
    dwLogotypeImageInfoChoice: DWORD;
    dwFileSize: DWORD;
    dwXSize: DWORD;
    dwYSize: DWORD;
    dwLogotypeImageResolutionChoice: DWORD;
    DUMMYUNIONNAME: CERTLOGOTYPEIMAGEINFOUNION;
    pwszLanguage: LPWSTR;
  end;
  CERTLOGOTYPEIMAGEINFO = CERTLOGOTYPEIMAGEINFO;
  PCERTLOGOTYPEIMAGEINFO = ^CERTLOGOTYPEIMAGEINFO;

Alternatively, you can nest the 2nd record inside of the main record:

type
  CERTLOGOTYPEIMAGEINFO = record
    dwLogotypeImageInfoChoice: DWORD;
    dwFileSize: DWORD;
    dwXSize: DWORD;
    dwYSize: DWORD;
    dwLogotypeImageResolutionChoice: DWORD;
    DUMMYUNIONNAME: record
      case Boolean of
        True: (dwNumBits: DWORD);
        False: (dwTableSize: DWORD);
    end;
    pwszLanguage: LPWSTR;
  end;
  CERTLOGOTYPEIMAGEINFO = CERTLOGOTYPEIMAGEINFO;
  PCERTLOGOTYPEIMAGEINFO = ^CERTLOGOTYPEIMAGEINFO;

Whether you declare the 2nd record as a separate type or a nested type, you still need to put the union inside a 2nd record nonetheless. A variant part can only be used at the very end of a record.

The alternative would be to get rid of the union entirely. Since the union'ed fields in this example are the same type, you can declare a single field of that type, and then use properties to give other names to that field, eg:

type
  CERTLOGOTYPEIMAGEINFO = record
    dwLogotypeImageInfoChoice: DWORD;
    dwFileSize: DWORD;
    dwXSize: DWORD;
    dwYSize: DWORD;
    dwLogotypeImageResolutionChoice: DWORD;
    dwUnion: DWORD;
    pwszLanguage: LPWSTR;

property dwNumBits: DWORD read dwUnion write dwUnion; property dwTableSize: DWORD read dwUnion write dwUnion; end; CERTLOGOTYPEIMAGEINFO = CERTLOGOTYPEIMAGEINFO; PCERTLOGOTYPEIMAGEINFO = ^CERTLOGOTYPEIMAGEINFO;