DirectWrite的RegisterFontFileLoader:创建一个字体文件加载器和德尔福

2019-10-20 18:17发布

我想注册一个DirectWrite的(Windows 7中的Windows 8)基于API的字体文件加载程序,并在Delphi中,重新从Windows 7 SDK CustomFont的演示 ,演示如何使用DirectWrite API的使用自定义的字体集合。 这使得DirectWrite的使用你从内未在全球范围内Windows字体系统注册的应用程序资源加载自己的字体。 我坚持访问冲突。 一个最小的样品如下。

首先一个疑问我对德尔福的Direct2D界面,船舶XE6。 在Delphi单元Winapi.D2D1是IDWriteFactory类型。 一个特定的接口方法可以让你注册一个字体文件加载程序: RegisterFontFileLoader

IDWriteFactory = interface(IUnknown)
    [SID_IDWriteFactory]
....
    function RegisterFontFileLoader(
      var fontFileLoader: IDWriteFontFileLoader): HResult; stdcall;
....
end;

在这个比较对C ++的Direct2D头,我发现自己想知道如果上述被正确翻译。 下面是C / C ++的Direct2D头(dwrite.h)当量:

interface DWRITE_DECLARE_INTERFACE("b859ee5a-d838-4b5b-a2e8-1adc7d93db48") IDWriteFactory : public IUnknown
{    ...
    STDMETHOD(RegisterFontFileLoader)(
        IDWriteFontFileLoader* fontFileLoader
        ) PURE;
...
}

请注意,在普通的C ++你不类型的变量工作“IDWriteFontFileLoader fontFileLoader”,接口引用的类型是“IDWriteFontFileLoader *”。 因此,我质疑的适用性var在上面的接口关键字。

这里是一个内部崩溃我的示例代码dwrite.dll访问冲突。 我做得显然是错误的吗? 该TLoader对象是平凡的,它是一个TInterfacedObject,我创建它,可是,我不能注册的对象。 我怀疑这个方法的单一参数不正确传递中,我不知道如果我做错了事,或者如果我发现在德尔福RTL的Direct2D的包装代码中的错误。

unit DirectWriteBugMain;

interface

uses
  WinApi.Windows,
  System.Types,
  Vcl.Direct2D,
  WinAPI.D2D1,
  System.SysUtils;

type
  TLoader =class(TInterfacedObject,IDWriteFontFileLoader)

      function CreateStreamFromKey(
      fontFileReferenceKey: Pointer;
      fontFileReferenceKeySize: Cardinal;
      out fontFileStream: IDWriteFontFileStream): HResult; stdcall;
  end;


procedure main; { called from dpr, in a console app }

implementation

function TLoader.CreateStreamFromKey(
      fontFileReferenceKey: Pointer;
      fontFileReferenceKeySize: Cardinal;
      out fontFileStream: IDWriteFontFileStream): HResult; stdcall;
begin
   fontFileStream := nil;
   result := E_FAIL;
end;

procedure main;
var
  Loader:IDWriteFontFileLoader;
begin
  try
     Loader := TLoader.Create as IDWriteFontFileLoader;

    DWriteFactory.RegisterFontFileLoader( Loader);
  except
    on E: Exception do
    begin
      Writeln(E.ClassName, ': ', E.Message);

      ReadLn;
    end;
  end;
end;

end.

在C ++工作示例在Windows SDK中找到。 上面的代码,在C ++出现在C ++演示,随着工厂的DirectWrite和D2D1厂之后完成的第一件事被创建:

if (FAILED(hr = g_dwriteFactory->RegisterFontFileLoader(ResourceFontFileLoader::GetLoader())))
        return hr;

所述ResourceFontFileLoader::GetLoader()简单地返回一个构造C ++对象投射到接口类型,在通常的C ++方法:

class ResourceFontFileLoader : public IDWriteFontFileLoader
{
public:
    ResourceFontFileLoader() : refCount_(0)
    {
    }

    // IUnknown methods
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
    virtual ULONG STDMETHODCALLTYPE AddRef();
    virtual ULONG STDMETHODCALLTYPE Release();

    // IDWriteFontFileLoader methods
    virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey(
        void const* fontFileReferenceKey,       // [fontFileReferenceKeySize] in bytes
        UINT32 fontFileReferenceKeySize,
        OUT IDWriteFontFileStream** fontFileStream
        );

    // Gets the singleton loader instance.
    static IDWriteFontFileLoader* GetLoader()
    {
        return instance_;
    }
...
}

上面的代码手动C ++实现的IUnknown,而我的代码使用的Delphi TInterfacedObject其干净地实现的IUnknown。 只有一个在接口IDWriteFontFileLoader方法,CreateStreamFromKey方法,并且它不是在当注册发生C ++演示调用,因此实际的代码就不可能是一个因素,仅调用约定,堆栈和先决条件状态或用于DirectWrite的出厂设置步骤似乎是可能的原因。

Answer 1:

看来我的预感是正确的,并且有在的Direct2D头转换为的DirectWrite接口,XE6错误。

RTL代码需要这个犯了错地方进行修改。 VAR关键字在这里不适用:

在IDWriteFactory :: RegisterFontFileLoader,在WinAPI.D2D1,大约线4421,去掉var关键字,并将其替换const

 function RegisterFontFileLoader(
    var fontFileLoader: IDWriteFontFileLoader): HResult; stdcall;

需要注意的是相同的变化有可能被其他地方作出IDWriteFactory,IDWriteFontCollectionLoader,和任何其他IDWrite*这个RTL单元,其中内接口var选择不正确。 这是大部分的地方,但不是所有的人。 基本上是在C ++中的每个“被通过引用传递入接口引用,如IDWriteFactory *”,“const的IDWriteFactory”是帕斯卡右等效。



Answer 2:

在COM中,一个接口是一个指向虚表一。 在Delphi中的间接是隐含的。 在C ++中的间接是明确的。 因此,这种形式的德尔福声明:

Intf: IUnknown

确实是一个指针的声明。 到IUnknown虚函数表。 在C ++中的对应声明

IUnknown *Intf

所以,你的假设是正确的。 德尔福头翻译是伪造的。 该var是错误的,应予删除。 按值,或使用为普通纸传递const



文章来源: DirectWrite RegisterFontFileLoader :create a font file loader and register it in Delphi without access violation