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 ファクトリのセットアップ手順が考えられる理由のようです。