本文介绍了一个DLL中的FireMonkey表单,从VCL应用程序加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am attempting to load an FMX based dll, which includes an FMX form, from a VCL application which includes a VCL form.

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

对于Delphi,将Winapi.GDIPOBJ添加到主窗体单元的接口部分uses子句。

For Delp add Winapi.GDIPOBJ to the interface section uses clause of your main form unit.

很好,但实际上,我现在在退出我的VCL应用程序时遇到访问冲突。我相信这一切都与初始化和释放GDI +有关,但是找不到任何有关此信息的信息。

Sounds all well and good, but in practice I am now getting an access violation on exiting my VCL application. I believe this is all linked to Initializing and Freeing the GDI+ but cannot find any more information regarding this.

我已阅读这两篇文章:

有人遇到这个吗?最终,我希望得到我们的C应用程序加载FMX dll(和GDI +),但这个过程的一部分涉及到获得VCL和FireMonkey dll。

Anyone else come across this? Eventually I am hoping to get our C application loading the FMX dll (and GDI+), but part of this process involves getting VCL and a FireMonkey dll to work.

推荐答案

这个答案适用于Delphi XE2 Update 2,我不知道事情是否随着Update 3更改。

This answer applies to Delphi XE2 Update 2, I don't know if things have changed with Update 3.

我启动了Embarcadero线程。从主机应用程序启动GDI +不是我的选择。到目前为止,一切都是从DLL一边工作而没有错误,但是还没有任何东西被释放到外界。

I started the Embarcadero thread. Starting up GDI+ from the host application isn't an option for me. So far everything is working from the DLL side without errors but nothing has been released to the outside world yet either.

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

If you are able to modify your C host application, you may find the MSDN GdiplusStartup() documentation useful.

====

将此单位添加到您的项目中:

Add this unit to your project:

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;

这篇关于一个DLL中的FireMonkey表单,从VCL应用程序加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-12 20:37