delphifiremonkeydwmremobjectsfiremonkey-fm2

DWM Interaction from a DLL


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.


Solution

  • 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