0

I have a problem with the following code in Delphi 10.1:

ShellExecute(handle,'open',PChar(filename), '','',SW_SHOWNORMAL);

When I try to run the code it gives me this error:

Incompatible Types: 'HWND' and 'TWindowHandle'

Crytox
  • 9
  • 1
  • 3
  • Try change `handle` parameter to `0`. –  Oct 09 '16 at 23:02
  • 1
    Ask yourself why you are passing `handle` there. That's the FMX `handle` of a form in your app, I presume. Do you know what `ShellExecute` will do with that argument? Is there any good reason why you would not just pass `0`? What drove you to pass a different value? How well, if at all, do you understand how that argument will be used? If you don't understand it well, why are you even calling the function? – David Heffernan Oct 10 '16 at 08:43
  • Don't use `ShellExecute` because it does not report errors in a useful way. Use `ShellExecuteEx` which does. Are you even checking for errors? Do you want to use the `open` verb explicitly, or do you really want to execute the default verb? Is `filename` an executable file? If so then you should create a new process with `CreateProcess` rather than getting the shell to do the work. – David Heffernan Oct 10 '16 at 08:43

2 Answers2

5

In FireMonkey, a Form's Handle property is of type TWindowHandle (a class defined in the FMX.Types unit). On Windows, it is implemented as TWinWindowHandle (a subclass of TWindowHandle defined in the FMX.Platform.Win unit).

TWinWindowHandle stores the HWND handle in its Wnd property.

To get the actual HWND handle, you would need to use FmxHandleToHWND():

ShellExecute(FmxHandleToHWND(Handle), 'open', PChar(filename), '', '', SW_SHOWNORMAL);

This casts the TWindowHandle to TWinWindowHandle (using WindowHandleToPlatform) and then returns its Wnd property value.

Updated (based on Remy's comments):

Remy points out that the FmxHandleToHWND is documented to be deprecated (from XE4 onwards). This doesn't appear to be backed up by the latest source code, which seems in the case of Delphi 10.1 Berlin RTM version to have dropped the usual deprecated modifier, but let's take the documentation's word for it just to be safe.

Instead of FmxHandleToHWND you are advised to do exactly what FmxHandleToHWND does, which is to call WindowHandleToPlatform and access the Wnd property, so:

ShellExecute(WindowHandleToPlatform(Handle).Wnd, 'open', PChar(filename), '', '', SW_SHOWNORMAL);

A better option, though, would be to use FormToHWND, which is more a direct replacement for FmxHandleToHWND than WindowHandleToPlatform (and we can wonder why the docs don't point us at this routine, though the likely answer is the docs writer just got it wrong):

ShellExecute(FormToHWND(Handle), 'open', PChar(filename), '', '', SW_SHOWNORMAL);
blong
  • 2,145
  • 13
  • 23
  • `FmxHandleToHWND()` is deprecated, you are supposed to use `WindowHandleToPlatform()` directly now, eg: `ShellExecute(WindowHandleToPlatform(Handle)->Wnd, 'open', PChar(filename), '', '', SW_SHOWNORMAL);` – Remy Lebeau Oct 10 '16 at 16:45
  • Updated answer to take the documentation's allegation into account – blong Oct 10 '16 at 18:28
  • It is not an allegation, it really is marked as deprecated in the source code, and has been for awhile. Also, an easier way to get the `HWND` of a `TForm` is to use the [`FormToHWND()`](http://docwiki.embarcadero.com/Libraries/en/FMX.Platform.Win.FormToHWND) function in the `FMX.Platform.Win` unit, eg: `ShellExecute(FormToHWND(Self), 'open', PChar(filename), '', '', SW_SHOWNORMAL);` – Remy Lebeau Oct 10 '16 at 21:48
  • The source I looked in was Delphi 10.1 Berlin. No `deprecated` there. Maybe that changed in the Update? Now I look back at Seattle and earlier, I see it there, but not in Berlin RTM. Please check. – blong Oct 10 '16 at 21:56
  • Moreover, if `FormToHWND` is the effective non-deprecated replacement, why does the doc page on `FmxHandleToHWND` refer to coder to `WindowHandleToPlatform`, which is notably not a replacement?? – blong Oct 10 '16 at 21:58
  • `FmxHandleToHWND()` has been marked as `deprecated` since XE4 (when `WindowHandleToPlatform()` was first added) and its documentation reflects that. If it is no longer marked in Berlin, I would consider that a bug. As for `FormToHWND()`, that was added in XE5, but I don't know why. – Remy Lebeau Oct 10 '16 at 22:45
1

A TWindowHandle is a FireMonkey class. A HWND is a Windows handle. These are completely different types.

For the VCL, it is fine to pass something like TForm.Handle, which is a HWND, to ShellExecute(). For FireMonkey (FMX), it isn't, since that is a TWindowHandle.

Use GetDesktopWindow() from unit Winapi.Windows instead:

ShellExecute(GetDesktopWindow, 'open', PChar(filename), '', '', SW_SHOWNORMAL);
Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
  • Don't use the desktop window as a window owner ever. Pass 0 is probably the cleanest. – David Heffernan Oct 10 '16 at 04:41
  • @David - Like Jordan (inno-setup) commented on the page you linked, the example Raymond gives is not accurate. I doubt if it was ever accurate. Maybe on 9x.. systems.... – Sertac Akyuz Oct 10 '16 at 21:27