1

DirectWrite (Windows 7、Windows 8) API ベースのフォント ファイル ローダーを登録し、カスタム フォント コレクションで APIを使用する方法を示すWindows 7 SDK の CustomFont デモをDelphi で再作成しようとしています。DirectWriteこれにより、DirectWrite は、Windows フォント システムにグローバルに登録されていないアプリケーション リソース内から自分で読み込んだフォントを使用できます。アクセス違反で困っています。最小限のサンプルを以下に示します。

最初に、XE6 に同梱されている Delphi Direct2D インターフェイスについて疑問を持っています。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 であり、私が作成しましたが、オブジェクトを登録できません。このメソッドへの 1 つのパラメーターが正しく渡されていないのではないかと思います。何か間違ったことをしたのか、それとも Delphi 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++ のコードは、DirectWrite ファクトリと D2D1 ファクトリが作成された後に最初に行われることの 1 つとして、C++ デモに表示されます。

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 を手動で実装していますが、私のコードではTInterfacedObjectIUnknown をクリーンに実装する Delphi を使用しています。インターフェイス IDWriteFontFileLoader メソッド CreateStreamFromKey にはメソッドが 1 つしかなく、登録が行われるときに C++ デモで呼び出されないため、実際のコードには要因がなく、呼び出し規約、スタック、および前提条件の状態のみが含まれます。または DirectWrite ファクトリのセットアップ手順が考えられる理由のようです。

4

2 に答える 2

1

COM では、インターフェイスは vtable へのポインターです。Delphi では、間接化は暗黙的です。C++ では、間接化は明示的です。したがって、この形式の Delphi 宣言は次のようになります。

Intf: IUnknown

は実際にはポインタの宣言です。IUnknownvtableに。C++ では、対応する宣言は次のとおりです。

IUnknown *Intf

したがって、あなたの推測は正しいです。Delphi ヘッダーの翻訳は偽物です。はvar誤りであり、削除する必要があります。通常の値渡し、または のいずれかを使用しますconst

于 2014-08-22T19:55:47.307 に答える
1

XE6 では、DirectWrite インターフェイスの Direct2D ヘッダー変換にエラーがあるようです。

この誤りがあった場合は、RTL コードを修正する必要があります。VAR キーワードはここでは適用できません:

IDWriteFactory::RegisterFontFileLoader の WinAPI.D2D1 の 4421 行目あたりで、varキーワードを削除し、 const.

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

IDWrite*IDWriteFactory、IDWriteFontCollectionLoader、およびこの RTL ユニット内のその他のインターフェイスのどこでも同じ変更を行う必要があることに注意してくださいvar。それはほとんどの場所ですが、すべてではありません。基本的に、C++ の「IDWriteFactory* として参照によって渡される受信インターフェイス参照」ごとに、「const IDWriteFactory」は Pascal と同等です。

于 2014-08-22T13:49:09.220 に答える