2
votes

Good morning all.

I'm currently attempting to write a small application that's built around the features available through the Windows DWM API (e.g. DWM Thumbnails). One such feature would be the ability to dynamically select an area of the thumbnail from within the application, and have it scaled up/zoomed in. It may be possible to do this from DWM with some sort of 'set region' function, but I wanted to try my own route first before going too far into the API.

Having recently found an example for Delphi, I had hoped to expand from the demo and build something more specific. I set about moving the code over to a Firemonkey FM2 application (as I much prefer the visual features of the framework compared to VCL). With a few tweaks, I managed to get it built, but unfortunately it seems as though DWMRegisterThumbnail wouldn't return a valid result when running in the FMX application, despite the VCL version working flawlessly.

I then looked a little further and decided to give Hydra a shot. I copied the working VCL example over to a Hydra Plugin, and created a Firemonkey host application. I correctly set up both parts and compiled. The DLL loaded correctly and I could see the VCL plugin interface inside the FMX host as expected. However, upon trying to view the DWM Thumbnail of a window, I was once again faced with the same issue I had when running the non-hydra FMX application.

I then went about creating a VCL host application just to be sure it wasn't an issue specific to the VCL-FMX interaction. I compiled the VCL host, loaded in the VCL plugin, and again I could see the VCL plugin inside the VCL host. However once again, I was still finding that I couldn't view thumbnails from DWM. Evidently, it's not a Firemonkey-VCL interaction issue.

Therefore, I've concluded it's an issue with running the DWM code from a DLL. Ideally, I'd like to have an FMX host application simply because it's easier for me to drop a TSelection over the thumbnail, and deal with scaling in that way (e.g. very little code, and no need to look for a custom component) not to mention the additional bonuses such as MakeScreenshot.

So, to cut to the chase; Is it possible to call the DWM API from a Hydra Plugin, and/or output a DWM Thumbnail to a Firemonkey surface?

The code used in my Hydra Plugin is identical to that which is used in the linked example, and the code used in my host application(s) is based upon the simple example on the Remobject Youtube Channel.

1
DWM works fine in a DLL. Why are you hiding the code from us?David Heffernan
You've taken a very complicated route to get here (Hydra? DLLs? Host apps and plugins?!) Also I don't follow your logic for why you "concluded it's an issue with running the DWM code from a DLL", especially since it failed from a simple FMX app in the first place. Next time, ask a SO question when you get to the first point, ie DWMRegisterThumbnail failing for your FMX app :)David
It wasn't a case of hiding the code, it's just that I didn't want to quote what was in the source I linked and have a wall of text in addition to my question (which is already pretty long). I concluded it was a DLL issue simply because I couldn't get it working from either a VCL or FMX host. It was probably a case of me incorrectly moving the code to said DLL and relying entirely on that, and so an honest mistake on my part.Scott P

1 Answers

11
votes

Without source code, I will guess that you are not passing the proper windows handle to the DwmRegisterThumbnail function. you can use the FmxHandleToHWND function to convert the FMX Form handle to the Windows Handle.

Try this modified version of the code

unit Unit28;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, Winapi.Windows, Winapi.DwmApi;

type
  TForm28 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    FTumbnail: HTHUMBNAIL;
    FPreviewEnabled: Boolean;
    { Private declarations }
    procedure PreviewWindow(const ASource, ADest: HWND; const ARect: TRect);
    procedure PreviewDisable;
  public
    { Public declarations }
  end;

var
  Form28: TForm28;

implementation

uses
  FMX.Platform.Win;


{$R *.fmx}

procedure TForm28.Button1Click(Sender: TObject);
var
  Index: Integer;
  LRect: TRect;
begin
  LRect := Rect(5, 5, Self.Width -20,Self.Height -50);
  //here I'm using a fixed window handle ($000102EE) just a sample
  PreviewWindow($000102EE, FmxHandleToHWND(Self.Handle), LRect);
end;

procedure TForm28.FormCreate(Sender: TObject);
begin
  FPreviewEnabled := False;
end;

procedure TForm28.FormDestroy(Sender: TObject);
begin
  PreviewDisable;
end;

procedure TForm28.PreviewDisable;
begin
  if FPreviewEnabled then
    FPreviewEnabled := NOT Succeeded(DwmUnregisterThumbnail(FTumbnail));
end;

procedure TForm28.PreviewWindow(const ASource, ADest: HWND; const ARect: TRect);
var
  LResult: HRESULT;
  LThumpProp: DWM_THUMBNAIL_PROPERTIES;
begin
  if not DwmCompositionEnabled then begin
    ShowMessage('DWM composition is NOT enabled.');
    Exit;
  end;
  PreviewDisable;
  FPreviewEnabled := Succeeded(DwmRegisterThumbnail(ADest, ASource, @FTumbnail));
  if FPreviewEnabled then
  begin
    LThumpProp.dwFlags := DWM_TNP_SOURCECLIENTAREAONLY or DWM_TNP_VISIBLE or DWM_TNP_OPACITY or DWM_TNP_RECTDESTINATION;
    LThumpProp.fSourceClientAreaOnly := False;
    LThumpProp.fVisible := True;
    LThumpProp.opacity := 200;
    LThumpProp.rcDestination := ARect;
    LResult := DwmUpdateThumbnailProperties(FTumbnail, LThumpProp);
    FPreviewEnabled := (LResult = S_OK);
  end else
    ShowMessage('Cannot link to window  ' + IntToStr(ASource));
end;

end. 

enter image description here