Взаимодействие DWM из библиотеки DLL


Всем доброе утро.

В настоящее время я пытаюсь написать небольшое приложение, построенное на функциях, доступных через Windows DWM API (например, миниатюры DWM). Одной из таких функций может быть возможность динамического выбора области миниатюры из приложения и ее масштабирования/увеличения. Возможно, это можно сделать из DWM с помощью какой-то функции "set region", но я хотел сначала попробовать свой собственный маршрут, прежде чем заходить слишком далеко в область ПРИКЛАДНОЙ ПРОГРАММНЫЙ ИНТЕРФЕЙС.

Недавно найдяпример для Delphi , я надеялся расширить демонстрацию и построить что-то более конкретное. Я приступил к перемещению кода в приложение Firemonkey FM2 (поскольку я предпочитаю визуальные особенности фреймворка по сравнению с VCL). С помощью нескольких настроек мне удалось построить его, но, к сожалению, похоже, что DWMRegisterThumbnail не вернет действительный результат при запуске в приложении FMX, несмотря на безупречную работу версии VCL.

Я тогда посмотрел немного дальше и решил дать Гидре шанс. Я скопировал пример рабочей ссылки на плагин Гидры, и создали множество приложений технологии FireMonkey. Я правильно настроил обе части и скомпилировал. DLL загрузилась правильно, и я мог видеть интерфейс плагина VCL внутри хоста FMX, как и ожидалось. Однако при попытке просмотреть миниатюру окна DWM я снова столкнулся с той же проблемой, что и при запуске приложения non-hydra FMX.

Затем я приступил к созданию хоста VCL приложение просто, чтобы убедиться, что это не было проблемой, специфичной для взаимодействия VCL-FMX. Я собрал в VCL узлов, загруженных в модуле VCL, и я снова мог видеть плагин в VCL внутри хост-модулей. Однако еще раз я обнаружил, что не могу просматривать миниатюры из DWM. Очевидно, это не проблема взаимодействия Firemonkey-VCL.

Поэтому я пришел к выводу, что это проблема с запуском кода DWM из DLL. В идеале я хотел бы иметь хост-приложение FMX просто потому, что это проще для меня, чтобы бросить TSelection над миниатюрой, и иметь дело с масштабированием таким образом (например, очень мало кода, и нет необходимости искать пользовательский компонент), не говоря уже о дополнительных бонусах, таких как MakeScreenshot.

Итак, чтобы перейти к делу; можно ли вызвать DWM API из плагина Hydra и / или вывести миниатюру DWM на поверхность Firemonkey?

Код, используемый в моем плагине Hydra, идентичен тому, который используется в связанном примере , и код, используемый в моем хосте приложение(ы) основано на простом примере на канале Remobject Youtube.

1 2

1 ответ:

Без исходного кода я предположу, что вы не передаете надлежащий дескриптор windows в DwmRegisterThumbnail функция. вы можете использовать FmxHandleToHWND функция для преобразования дескриптора формы FMX в дескриптор Windows.

Попробуйте эту модифицированную версию кода

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. 

Введите описание изображения здесь