从VCL应用程序加载的DLL中的FireMonkey表单

时间:2011-12-19 16:00:12

标签: delphi gdi+ delphi-xe2 firemonkey

我正在尝试从包含VCL表单的VCL应用程序加载基于FMX的dll,其中包括FMX表单。

摘自发行说明 - http://docwiki.embarcadero.com/RADStudio/en/Release_Notes_for_XE2_Update_2

  

要创建使用GDI +的DLL,您需要从主机应用程序启动GDI +,如下所示:

     

对于Delphi,将Winapi.GDIPOBJ添加到主窗体单元的interface section uses子句中。

听起来很好,但实际上我现在在退出我的VCL应用程序时遇到访问冲突。我相信这与初始化和释放GDI +有关,但无法找到有关此内容的更多信息。

我已经阅读了这两篇文章:

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

Delphi XE2: Possible to instantiate a FireMonkey Form in VCL application?

其他人遇到过这个?最终我希望我们的C应用程序加载FMX dll(和GDI +),但是这个过程的一部分涉及让VCL和FireMonkey dll工作。

1 个答案:

答案 0 :(得分:2)

这个答案适用于Delphi XE2 Update 2,我不知道Update 3是否发生了变化。

我开始了Embarcadero线程。从主机应用程序启动GDI +对我来说不是一个选择。到目前为止,一切都在DLL方面正常工作而没有错误,但也没有任何东西被释放到外部世界。

如果您能够修改C主机应用程序,您可能会发现MSDN GdiplusStartup() documentation很有用。

====

在DLL中使用FireMonkey而不在主机应用程序中启动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;