Форма FireMonkey в dll, загруженная из приложения VCL - PullRequest
2 голосов
/ 19 декабря 2011

Я пытаюсь загрузить dll на основе FMX, которая включает в себя форму FMX, из приложения VCL, которое включает в себя форму VCL.

Взято из заметок о выпуске - http://docwiki.embarcadero.com/RADStudio/en/Release_Notes_for_XE2_Update_2:

Чтобы создать DLL, которая использует GDI +, вам нужно вместо этого запустить GDI + из вашего хост-приложения следующим образом:

Для Delphi добавьте Winapi.GDIPOBJ в раздел интерфейса, использующий предложение вашего основного модуля формы.

Звучит все хорошо, но на практике я получаю нарушение прав доступа при выходе из приложения VCL.Я считаю, что все это связано с инициализацией и освобождением GDI +, но не могу найти больше информации по этому поводу.

Я прочитал оба этих поста:

https://forums.embarcadero.com/thread.jspa?threadID=63425

Delphi XE2: можно создать экземпляр формы FireMonkey в приложении VCL?

Кто-нибудь еще сталкивался с этим?В конце концов я надеюсь, что наше приложение на C загрузит dll FMX (и GDI +), но часть этого процесса заключается в том, чтобы заставить работать VCL и dll FireMonkey.

1 Ответ

2 голосов
/ 20 декабря 2011

Этот ответ относится к Delphi XE2, обновление 2, я не знаю, изменились ли вещи с обновлением 3.

Я запустил тему Embarcadero. Запуск GDI + из хост-приложения для меня не вариант. Пока что все работает со стороны DLL без ошибок, но пока еще ничего не выпущено во внешний мир.

Если вы можете изменить свое хост-приложение C, вам может пригодиться документация MSDN GdiplusStartup () .

====

Использование FireMonkey в DLL без запуска GDI + в хост-приложении

Добавьте этот блок в ваш проект:

unit InitFmxHack;

interface

procedure InitGDIP; // Call before using FMX.
procedure FreeGDIP; // Call after using FMX.

// NOTE:
// InitGDIP() must be called before instantiating a FireMonkey form.
// FreeGDIP() must be called after all FireMonkey forms are destroyed.
//
// InitGDIP/FreeGDIP can not be called from the initalization or finalization sections,
// or any method called from these sections.
//


implementation

uses
  System.SysUtils,
  Winapi.GDIPAPI,
  Winapi.GDIPOBJ,
  FMX.Types;

var
  NeedToShutdownGDIPlus: Boolean;
  GDIPlusInput: TGDIPlusStartupInput;
  gdiplusToken: Cardinal;
  TempRgn: GpRegion;

type
  TBitmapAccess = class(TBitmap);

procedure InitGDIP;
begin
  NeedToShutdownGDIPlus := False;
  case GdipCreateRegion(TempRgn) of
    Ok: GdipDeleteRegion(TempRgn);
    GdiplusNotInitialized:
    begin
      GDIPlusInput.GdiplusVersion := 1;
      GDIPlusInput.DebugEventCallback := nil;
      GDIPlusInput.SuppressBackgroundThread := False;
      GDIPlusInput.SuppressExternalCodecs := False;
      GdiplusStartup(GDIPlusToken, @GDIPlusInput, nil);
      NeedToShutdownGDIPlus := True;
    end;
  end;

end;

procedure FreeGDIP;
begin
  // HACK: Need to forcibly release a GDI+ object held in a global variable.
  FreeAndNil(TBitmapAccess(GetMeasureBitmap).FCanvas);

  // These lines have been copied from Winapi.GDIPOBJ. I'm not 100% sure
  // if there needed but it's probably safer to include them as they are part of
  // the standard FireMonkey shutdown sequence. Similar code is also found in
  // the VGScene library.
  if Assigned(GenericSansSerifFontFamily)           then FreeAndNil(GenericSansSerifFontFamily);
  if Assigned(GenericSerifFontFamily)               then FreeAndNil(GenericSerifFontFamily);
  if Assigned(GenericMonospaceFontFamily)           then FreeAndNil(GenericMonospaceFontFamily);
  if Assigned(GenericTypographicStringFormatBuffer) then FreeAndNil(GenericTypographicStringFormatBuffer);
  if Assigned(GenericDefaultStringFormatBuffer)     then FreeAndNil(GenericDefaultStringFormatBuffer);

  // Finalise GDI+ here if needed...
  if NeedToShutdownGDIPlus then GdiplusShutdown(GDIPlusToken);
end;

end.

Для использования:

InitFmxHack.InitGDIP;

// 1. Create form here.
// 2. Use form.
// 3. Destroy form. 

InitFmxHack.FreeGDIP;
...