Nigel Thomas 35 Posted October 4 This is the Delphi 12.1 (and as far back as 10.1 at least, but not in D2007) definition of ShellExecuteInfoW (the A version has the same issue): _SHELLEXECUTEINFOW = record cbSize: DWORD; fMask: ULONG; Wnd: HWND; lpVerb: LPCWSTR; lpFile: LPCWSTR; lpParameters: LPCWSTR; lpDirectory: LPCWSTR; nShow: Integer; hInstApp: HINST; { Optional fields } lpIDList: Pointer; lpClass: LPCWSTR; hkeyClass: HKEY; dwHotKey: DWORD; case Integer of 0: ( hIcon: THandle); 1: ( hMonitor: THandle; hProcess: THandle;); end; According to the definition in MSDN, the hProcess Handle is not part of the union: typedef struct _SHELLEXECUTEINFOW { DWORD cbSize; ULONG fMask; HWND hwnd; LPCWSTR lpVerb; LPCWSTR lpFile; LPCWSTR lpParameters; LPCWSTR lpDirectory; int nShow; HINSTANCE hInstApp; void *lpIDList; LPCWSTR lpClass; HKEY hkeyClass; DWORD dwHotKey; union { HANDLE hIcon; HANDLE hMonitor; } DUMMYUNIONNAME; HANDLE hProcess; } SHELLEXECUTEINFOW, *LPSHELLEXECUTEINFOW; Does that mean that the Delphi translation is faulty? Share this post Link to post
Anders Melander 1782 Posted October 4 (edited) 44 minutes ago, Nigel Thomas said: Does that mean that the Delphi translation is faulty? No. In Delphi the variant part has to be the last in the record and, if you think about it, the hProcess field would have the same offset even if it was possible to declare it after the variant part. https://docwiki.embarcadero.com/RADStudio/Athens/en/Structured_Types_(Delphi)#Variant_Parts_in_Records Quote The variant part must follow the other fields in the record declaration. Edited October 4 by Anders Melander 1 Share this post Link to post
Remy Lebeau 1392 Posted October 4 (edited) 2 hours ago, Nigel Thomas said: Does that mean that the Delphi translation is faulty? Technically, no. The layout is fine. But, if they had done the "politically correct" thing by extracting the union into a separate type, eg: _SHELLEXECUTEINFOW_Union = record case Integer of 0: (hIcon: THandle); 1: (hMonitor: THandle); end; _SHELLEXECUTEINFOW = record cbSize: DWORD; fMask: ULONG; Wnd: HWND; lpVerb: LPCWSTR; lpFile: LPCWSTR; lpParameters: LPCWSTR; lpDirectory: LPCWSTR; nShow: Integer; hInstApp: HINST; { Optional fields } lpIDList: Pointer; lpClass: LPCWSTR; hkeyClass: HKEY; dwHotKey: DWORD; u: _SHELLEXECUTEINFOW_Union; // DUMMYUNIONNAME maps to 'u' for C/C++ hProcess: THandle; // compilers that don't support nameless unions... end; Then referencing the hIcon and hMonitor handles would have to be done as SHELLEXECUTEINFO.u.hIcon instead of as SHELLEXECUTEINFO.hIcon, etc. The variant part keeps the syntax a little cleaner. Edited October 4 by Remy Lebeau 1 Share this post Link to post
Virgo 18 Posted October 9 In the end it comes down to Delphi limitation, that duplicate fields are not allowed in variant types... Because logical translation with being at the end would be: case Integer of 0: ( hIcon: THandle; hProcess: THandle;); 1: ( hMonitor: THandle; hProcess: THandle;); end; But this duplicate hProcess is not allowed. Share this post Link to post