C++ - DirectWrite:在运行时从文件加载字体
C++ - DirectWrite: Load font from file at runtime
我正在尝试在运行时从文件加载字体并使用 DirectWrite 显示它。以下代码应使用该字体初始化 IDWriteTextFormat 对象:
hr = pDWriteFactory->CreateTextFormat(
L"Font Family", // Font family name
NULL, // Font collection (NULL sets it to use the system font collection)
// Somehow, a custom font collection should be used here, but I don't know how to do that
DWRITE_FONT_WEIGHT_REGULAR,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
16.0f,
L"en-us",
&pTextFormat // IDWriteTextFormat object
);
它与系统字体完美配合,但我不知道如何加载自定义字体文件。我将不胜感激有关如何实现这一目标的任何示例。
到目前为止我尝试了什么:
• 我阅读了 this article and this question on Whosebug 但我看不到应该将字体文件的文件路径传递到哪里(因此,我完全没有实现这两页上提供的任何代码)
• 我也读过 this article 但如果我是对的,它与 DirectWrite 无关(?)(我试图实现 AddFontResourceEx 方法,但无济于事)
• 最后, suggested using ResourceFontContext::CreateFontCollection could solve the problem but after reading this page 的答案(它是德文的,但屏幕截图是英文的)我认为它只能与作为资源嵌入的字体一起使用(在我的情况下这不是一个选项)
当然可以。您需要:
在您的代码中实现 IDWriteFontCollectionLoader
接口;
显然,您还应该实现 IDWriteFontFileEnumerator
,但这应该是微不足道的。
使用 RegisterFontCollectionLoader
向工厂注册加载器
使用 CreateCustomFontCollection
和同一工厂创建一个集合;
将其传递给在同一工厂调用的 CreateTextFormat
。
当您调用 CreateCustomFontCollection
时,您必须提供一个集合键及其大小,它是一个只对您有意义的 blob,可以是任何东西。稍后将使用此密钥调用您的加载程序,因此您可以识别它。例如,您可以使用字符串 'myspecialkey' 作为键,并在 CreateEnumeratorFromKey
中检查它是否使用该键调用,拒绝任何其他键。
如果您只想从文件路径创建字体对象,则不需要以上任何一项,只需使用 CreateFontFileReference
后跟 CreateFontFace
。
如果有人对最终运行的代码感兴趣:
将 Common.h
、FontLoader.h
和 FontLoader.cpp
添加到您的项目(代码如下),并将以下行添加到您的应用程序:
#include "FontLoader.h"
// ...
IDWriteFactory* pDWriteFactory;
IDWriteFontCollection *fCollection;
IDWriteTextFormat* pTextFormat;
// ...
MFFontContext fContext(pDWriteFactory);
std::vector<std::wstring> filePaths; // vector containing ABSOLUTE file paths of the font files which are to be added to the collection
std::wstring fontFileFilePath = L"C:\xyz\abc.ttf";
filePaths.push_back(fontFileFilePath);
HRESULT hr = fContext.CreateFontCollection(filePaths, &fCollection); // create custom font collection
hr = pDWriteFactory->CreateTextFormat(
L"Font Family", // Font family name
fCollection,
DWRITE_FONT_WEIGHT_REGULAR,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
16.0f,
L"en-us",
&pTextFormat // IDWriteTextFormat object
);
FontLoader.h
#pragma once
#include <string>
#include "Common.h"
typedef std::vector<std::wstring> MFCollection;
class MFFontCollectionLoader : public IDWriteFontCollectionLoader
{
public:
MFFontCollectionLoader() : refCount_(0)
{
}
// IUnknown methods
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
virtual ULONG STDMETHODCALLTYPE AddRef();
virtual ULONG STDMETHODCALLTYPE Release();
// IDWriteFontCollectionLoader methods
virtual HRESULT STDMETHODCALLTYPE CreateEnumeratorFromKey(
IDWriteFactory* factory,
void const* collectionKey, // [collectionKeySize] in bytes
UINT32 collectionKeySize,
OUT IDWriteFontFileEnumerator** fontFileEnumerator
);
// Gets the singleton loader instance.
static IDWriteFontCollectionLoader* GetLoader()
{
return instance_;
}
static bool IsLoaderInitialized()
{
return instance_ != NULL;
}
private:
ULONG refCount_;
static IDWriteFontCollectionLoader* instance_;
};
class MFFontFileEnumerator : public IDWriteFontFileEnumerator
{
public:
MFFontFileEnumerator(
IDWriteFactory* factory
);
HRESULT Initialize(
UINT const* collectionKey, // [resourceCount]
UINT32 keySize
);
~MFFontFileEnumerator()
{
SafeRelease(¤tFile_);
SafeRelease(&factory_);
}
// IUnknown methods
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
virtual ULONG STDMETHODCALLTYPE AddRef();
virtual ULONG STDMETHODCALLTYPE Release();
// IDWriteFontFileEnumerator methods
virtual HRESULT STDMETHODCALLTYPE MoveNext(OUT BOOL* hasCurrentFile);
virtual HRESULT STDMETHODCALLTYPE GetCurrentFontFile(OUT IDWriteFontFile** fontFile);
private:
ULONG refCount_;
IDWriteFactory* factory_;
IDWriteFontFile* currentFile_;
std::vector<std::wstring> filePaths_;
size_t nextIndex_;
};
class MFFontContext
{
public:
MFFontContext(IDWriteFactory *pFactory);
~MFFontContext();
HRESULT Initialize();
HRESULT CreateFontCollection(
MFCollection &newCollection,
OUT IDWriteFontCollection** result
);
private:
// Not copyable or assignable.
MFFontContext(MFFontContext const&);
void operator=(MFFontContext const&);
HRESULT InitializeInternal();
IDWriteFactory *g_dwriteFactory;
static std::vector<unsigned int> cKeys;
// Error code from Initialize().
HRESULT hr_;
};
class MFFontGlobals
{
public:
MFFontGlobals() {}
static unsigned int push(MFCollection &addCollection)
{
unsigned int ret = fontCollections.size();
fontCollections.push_back(addCollection);
return ret;
}
static std::vector<MFCollection>& collections()
{
return fontCollections;
}
private:
static std::vector<MFCollection> fontCollections;
};
FontLoader.cpp
#include "FontLoader.h"
IDWriteFontCollectionLoader* MFFontCollectionLoader::instance_(
new(std::nothrow) MFFontCollectionLoader()
);
HRESULT STDMETHODCALLTYPE MFFontCollectionLoader::QueryInterface(REFIID iid, void** ppvObject)
{
if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontCollectionLoader))
{
*ppvObject = this;
AddRef();
return S_OK;
}
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
}
ULONG STDMETHODCALLTYPE MFFontCollectionLoader::AddRef()
{
return InterlockedIncrement(&refCount_);
}
ULONG STDMETHODCALLTYPE MFFontCollectionLoader::Release()
{
ULONG newCount = InterlockedDecrement(&refCount_);
if (newCount == 0)
delete this;
return newCount;
}
HRESULT STDMETHODCALLTYPE MFFontCollectionLoader::CreateEnumeratorFromKey(
IDWriteFactory* factory,
void const* collectionKey, // [collectionKeySize] in bytes
UINT32 collectionKeySize,
OUT IDWriteFontFileEnumerator** fontFileEnumerator
)
{
*fontFileEnumerator = NULL;
HRESULT hr = S_OK;
if (collectionKeySize % sizeof(UINT) != 0)
return E_INVALIDARG;
MFFontFileEnumerator* enumerator = new(std::nothrow) MFFontFileEnumerator(
factory
);
if (enumerator == NULL)
return E_OUTOFMEMORY;
UINT const* mfCollectionKey = static_cast<UINT const*>(collectionKey);
UINT32 const mfKeySize = collectionKeySize;
hr = enumerator->Initialize(
mfCollectionKey,
mfKeySize
);
if (FAILED(hr))
{
delete enumerator;
return hr;
}
*fontFileEnumerator = SafeAcquire(enumerator);
return hr;
}
// ------------------------------ MFFontFileEnumerator ----------------------------------------------------------
MFFontFileEnumerator::MFFontFileEnumerator(
IDWriteFactory* factory
) :
refCount_(0),
factory_(SafeAcquire(factory)),
currentFile_(),
nextIndex_(0)
{
}
HRESULT MFFontFileEnumerator::Initialize(
UINT const* collectionKey, // [resourceCount]
UINT32 keySize
)
{
try
{
// dereference collectionKey in order to get index of collection in MFFontGlobals::fontCollections vector
UINT cPos = *collectionKey;
for (MFCollection::iterator it = MFFontGlobals::collections()[cPos].begin(); it != MFFontGlobals::collections()[cPos].end(); ++it)
{
filePaths_.push_back(it->c_str());
}
}
catch (...)
{
return ExceptionToHResult();
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE MFFontFileEnumerator::QueryInterface(REFIID iid, void** ppvObject)
{
if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileEnumerator))
{
*ppvObject = this;
AddRef();
return S_OK;
}
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
}
ULONG STDMETHODCALLTYPE MFFontFileEnumerator::AddRef()
{
return InterlockedIncrement(&refCount_);
}
ULONG STDMETHODCALLTYPE MFFontFileEnumerator::Release()
{
ULONG newCount = InterlockedDecrement(&refCount_);
if (newCount == 0)
delete this;
return newCount;
}
HRESULT STDMETHODCALLTYPE MFFontFileEnumerator::MoveNext(OUT BOOL* hasCurrentFile)
{
HRESULT hr = S_OK;
*hasCurrentFile = FALSE;
SafeRelease(¤tFile_);
if (nextIndex_ < filePaths_.size())
{
hr = factory_->CreateFontFileReference(
filePaths_[nextIndex_].c_str(),
NULL,
¤tFile_
);
if (SUCCEEDED(hr))
{
*hasCurrentFile = TRUE;
++nextIndex_;
}
}
return hr;
}
HRESULT STDMETHODCALLTYPE MFFontFileEnumerator::GetCurrentFontFile(OUT IDWriteFontFile** fontFile)
{
*fontFile = SafeAcquire(currentFile_);
return (currentFile_ != NULL) ? S_OK : E_FAIL;
}
// ---------------------------------------- MFFontContext ---------------------------------------------------------
MFFontContext::MFFontContext(IDWriteFactory *pFactory) : hr_(S_FALSE), g_dwriteFactory(pFactory)
{
}
MFFontContext::~MFFontContext()
{
g_dwriteFactory->UnregisterFontCollectionLoader(MFFontCollectionLoader::GetLoader());
}
HRESULT MFFontContext::Initialize()
{
if (hr_ == S_FALSE)
{
hr_ = InitializeInternal();
}
return hr_;
}
HRESULT MFFontContext::InitializeInternal()
{
HRESULT hr = S_OK;
if (!MFFontCollectionLoader::IsLoaderInitialized())
{
return E_FAIL;
}
// Register our custom loader with the factory object.
hr = g_dwriteFactory->RegisterFontCollectionLoader(MFFontCollectionLoader::GetLoader());
return hr;
}
HRESULT MFFontContext::CreateFontCollection(
MFCollection &newCollection,
OUT IDWriteFontCollection** result
)
{
*result = NULL;
HRESULT hr = S_OK;
// save new collection in MFFontGlobals::fontCollections vector
UINT collectionKey = MFFontGlobals::push(newCollection);
cKeys.push_back(collectionKey);
const void *fontCollectionKey = &cKeys.back();
UINT32 keySize = sizeof(collectionKey);
hr = Initialize();
if (FAILED(hr))
return hr;
hr = g_dwriteFactory->CreateCustomFontCollection(
MFFontCollectionLoader::GetLoader(),
fontCollectionKey,
keySize,
result
);
return hr;
}
std::vector<unsigned int> MFFontContext::cKeys = std::vector<unsigned int>(0);
// ----------------------------------- MFFontGlobals ---------------------------------------------------------
std::vector<MFCollection> MFFontGlobals::fontCollections = std::vector<MFCollection>(0);
Common.h
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
//
//----------------------------------------------------------------------------
#pragma once
// The following macros define the minimum required platform. The minimum required platform
// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
// your application. The macros work by enabling all features available on platform versions up to and
// including the version specified.
// Modify the following defines if you have to target a platform prior to the ones specified below.
// Refer to MSDN for the latest info on corresponding values for different platforms.
#ifndef WINVER // Minimum platform is Windows 7
#define WINVER 0x0601
#endif
#ifndef _WIN32_WINNT // Minimum platform is Windows 7
#define _WIN32_WINNT 0x0601
#endif
#ifndef _WIN32_WINDOWS // Minimum platform is Windows 7
#define _WIN32_WINDOWS 0x0601
#endif
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#ifndef UNICODE
#define UNICODE
#endif
// Windows header files
#include <windows.h>
#include <dwrite.h>
#include <d2d1.h>
// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <memory>
#include <vector>
// Ignore unreferenced parameters, since they are very common
// when implementing callbacks.
#pragma warning(disable : 4100)
////////////////////////////////////////
// COM inheritance helpers.
// Releases a COM object and nullifies pointer.
template <typename InterfaceType>
inline void SafeRelease(InterfaceType** currentObject)
{
if (*currentObject != NULL)
{
(*currentObject)->Release();
*currentObject = NULL;
}
}
// Acquires an additional reference, if non-null.
template <typename InterfaceType>
inline InterfaceType* SafeAcquire(InterfaceType* newObject)
{
if (newObject != NULL)
newObject->AddRef();
return newObject;
}
// Sets a new COM object, releasing the old one.
template <typename InterfaceType>
inline void SafeSet(InterfaceType** currentObject, InterfaceType* newObject)
{
SafeAcquire(newObject);
SafeRelease(¤tObject);
currentObject = newObject;
}
// Maps exceptions to equivalent HRESULTs,
inline HRESULT ExceptionToHResult() throw()
{
try
{
throw; // Rethrow previous exception.
}
catch (std::bad_alloc&)
{
return E_OUTOFMEMORY;
}
catch (...)
{
return E_FAIL;
}
}
代码当然不完美,但对我有用。
如果您对这段代码有任何疑问,请发表评论(尽管我可能无法再给出令人满意的答案)。请注意,我从 here.
复制了大部分代码
我正在尝试在运行时从文件加载字体并使用 DirectWrite 显示它。以下代码应使用该字体初始化 IDWriteTextFormat 对象:
hr = pDWriteFactory->CreateTextFormat(
L"Font Family", // Font family name
NULL, // Font collection (NULL sets it to use the system font collection)
// Somehow, a custom font collection should be used here, but I don't know how to do that
DWRITE_FONT_WEIGHT_REGULAR,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
16.0f,
L"en-us",
&pTextFormat // IDWriteTextFormat object
);
它与系统字体完美配合,但我不知道如何加载自定义字体文件。我将不胜感激有关如何实现这一目标的任何示例。
到目前为止我尝试了什么:
• 我阅读了 this article and this question on Whosebug 但我看不到应该将字体文件的文件路径传递到哪里(因此,我完全没有实现这两页上提供的任何代码)
• 我也读过 this article 但如果我是对的,它与 DirectWrite 无关(?)(我试图实现 AddFontResourceEx 方法,但无济于事)
• 最后,
当然可以。您需要:
在您的代码中实现
IDWriteFontCollectionLoader
接口;显然,您还应该实现
IDWriteFontFileEnumerator
,但这应该是微不足道的。使用
向工厂注册加载器RegisterFontCollectionLoader
使用
CreateCustomFontCollection
和同一工厂创建一个集合;将其传递给在同一工厂调用的
CreateTextFormat
。
当您调用 CreateCustomFontCollection
时,您必须提供一个集合键及其大小,它是一个只对您有意义的 blob,可以是任何东西。稍后将使用此密钥调用您的加载程序,因此您可以识别它。例如,您可以使用字符串 'myspecialkey' 作为键,并在 CreateEnumeratorFromKey
中检查它是否使用该键调用,拒绝任何其他键。
如果您只想从文件路径创建字体对象,则不需要以上任何一项,只需使用 CreateFontFileReference
后跟 CreateFontFace
。
如果有人对最终运行的代码感兴趣:
将 Common.h
、FontLoader.h
和 FontLoader.cpp
添加到您的项目(代码如下),并将以下行添加到您的应用程序:
#include "FontLoader.h"
// ...
IDWriteFactory* pDWriteFactory;
IDWriteFontCollection *fCollection;
IDWriteTextFormat* pTextFormat;
// ...
MFFontContext fContext(pDWriteFactory);
std::vector<std::wstring> filePaths; // vector containing ABSOLUTE file paths of the font files which are to be added to the collection
std::wstring fontFileFilePath = L"C:\xyz\abc.ttf";
filePaths.push_back(fontFileFilePath);
HRESULT hr = fContext.CreateFontCollection(filePaths, &fCollection); // create custom font collection
hr = pDWriteFactory->CreateTextFormat(
L"Font Family", // Font family name
fCollection,
DWRITE_FONT_WEIGHT_REGULAR,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
16.0f,
L"en-us",
&pTextFormat // IDWriteTextFormat object
);
FontLoader.h
#pragma once
#include <string>
#include "Common.h"
typedef std::vector<std::wstring> MFCollection;
class MFFontCollectionLoader : public IDWriteFontCollectionLoader
{
public:
MFFontCollectionLoader() : refCount_(0)
{
}
// IUnknown methods
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
virtual ULONG STDMETHODCALLTYPE AddRef();
virtual ULONG STDMETHODCALLTYPE Release();
// IDWriteFontCollectionLoader methods
virtual HRESULT STDMETHODCALLTYPE CreateEnumeratorFromKey(
IDWriteFactory* factory,
void const* collectionKey, // [collectionKeySize] in bytes
UINT32 collectionKeySize,
OUT IDWriteFontFileEnumerator** fontFileEnumerator
);
// Gets the singleton loader instance.
static IDWriteFontCollectionLoader* GetLoader()
{
return instance_;
}
static bool IsLoaderInitialized()
{
return instance_ != NULL;
}
private:
ULONG refCount_;
static IDWriteFontCollectionLoader* instance_;
};
class MFFontFileEnumerator : public IDWriteFontFileEnumerator
{
public:
MFFontFileEnumerator(
IDWriteFactory* factory
);
HRESULT Initialize(
UINT const* collectionKey, // [resourceCount]
UINT32 keySize
);
~MFFontFileEnumerator()
{
SafeRelease(¤tFile_);
SafeRelease(&factory_);
}
// IUnknown methods
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
virtual ULONG STDMETHODCALLTYPE AddRef();
virtual ULONG STDMETHODCALLTYPE Release();
// IDWriteFontFileEnumerator methods
virtual HRESULT STDMETHODCALLTYPE MoveNext(OUT BOOL* hasCurrentFile);
virtual HRESULT STDMETHODCALLTYPE GetCurrentFontFile(OUT IDWriteFontFile** fontFile);
private:
ULONG refCount_;
IDWriteFactory* factory_;
IDWriteFontFile* currentFile_;
std::vector<std::wstring> filePaths_;
size_t nextIndex_;
};
class MFFontContext
{
public:
MFFontContext(IDWriteFactory *pFactory);
~MFFontContext();
HRESULT Initialize();
HRESULT CreateFontCollection(
MFCollection &newCollection,
OUT IDWriteFontCollection** result
);
private:
// Not copyable or assignable.
MFFontContext(MFFontContext const&);
void operator=(MFFontContext const&);
HRESULT InitializeInternal();
IDWriteFactory *g_dwriteFactory;
static std::vector<unsigned int> cKeys;
// Error code from Initialize().
HRESULT hr_;
};
class MFFontGlobals
{
public:
MFFontGlobals() {}
static unsigned int push(MFCollection &addCollection)
{
unsigned int ret = fontCollections.size();
fontCollections.push_back(addCollection);
return ret;
}
static std::vector<MFCollection>& collections()
{
return fontCollections;
}
private:
static std::vector<MFCollection> fontCollections;
};
FontLoader.cpp
#include "FontLoader.h"
IDWriteFontCollectionLoader* MFFontCollectionLoader::instance_(
new(std::nothrow) MFFontCollectionLoader()
);
HRESULT STDMETHODCALLTYPE MFFontCollectionLoader::QueryInterface(REFIID iid, void** ppvObject)
{
if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontCollectionLoader))
{
*ppvObject = this;
AddRef();
return S_OK;
}
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
}
ULONG STDMETHODCALLTYPE MFFontCollectionLoader::AddRef()
{
return InterlockedIncrement(&refCount_);
}
ULONG STDMETHODCALLTYPE MFFontCollectionLoader::Release()
{
ULONG newCount = InterlockedDecrement(&refCount_);
if (newCount == 0)
delete this;
return newCount;
}
HRESULT STDMETHODCALLTYPE MFFontCollectionLoader::CreateEnumeratorFromKey(
IDWriteFactory* factory,
void const* collectionKey, // [collectionKeySize] in bytes
UINT32 collectionKeySize,
OUT IDWriteFontFileEnumerator** fontFileEnumerator
)
{
*fontFileEnumerator = NULL;
HRESULT hr = S_OK;
if (collectionKeySize % sizeof(UINT) != 0)
return E_INVALIDARG;
MFFontFileEnumerator* enumerator = new(std::nothrow) MFFontFileEnumerator(
factory
);
if (enumerator == NULL)
return E_OUTOFMEMORY;
UINT const* mfCollectionKey = static_cast<UINT const*>(collectionKey);
UINT32 const mfKeySize = collectionKeySize;
hr = enumerator->Initialize(
mfCollectionKey,
mfKeySize
);
if (FAILED(hr))
{
delete enumerator;
return hr;
}
*fontFileEnumerator = SafeAcquire(enumerator);
return hr;
}
// ------------------------------ MFFontFileEnumerator ----------------------------------------------------------
MFFontFileEnumerator::MFFontFileEnumerator(
IDWriteFactory* factory
) :
refCount_(0),
factory_(SafeAcquire(factory)),
currentFile_(),
nextIndex_(0)
{
}
HRESULT MFFontFileEnumerator::Initialize(
UINT const* collectionKey, // [resourceCount]
UINT32 keySize
)
{
try
{
// dereference collectionKey in order to get index of collection in MFFontGlobals::fontCollections vector
UINT cPos = *collectionKey;
for (MFCollection::iterator it = MFFontGlobals::collections()[cPos].begin(); it != MFFontGlobals::collections()[cPos].end(); ++it)
{
filePaths_.push_back(it->c_str());
}
}
catch (...)
{
return ExceptionToHResult();
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE MFFontFileEnumerator::QueryInterface(REFIID iid, void** ppvObject)
{
if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileEnumerator))
{
*ppvObject = this;
AddRef();
return S_OK;
}
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
}
ULONG STDMETHODCALLTYPE MFFontFileEnumerator::AddRef()
{
return InterlockedIncrement(&refCount_);
}
ULONG STDMETHODCALLTYPE MFFontFileEnumerator::Release()
{
ULONG newCount = InterlockedDecrement(&refCount_);
if (newCount == 0)
delete this;
return newCount;
}
HRESULT STDMETHODCALLTYPE MFFontFileEnumerator::MoveNext(OUT BOOL* hasCurrentFile)
{
HRESULT hr = S_OK;
*hasCurrentFile = FALSE;
SafeRelease(¤tFile_);
if (nextIndex_ < filePaths_.size())
{
hr = factory_->CreateFontFileReference(
filePaths_[nextIndex_].c_str(),
NULL,
¤tFile_
);
if (SUCCEEDED(hr))
{
*hasCurrentFile = TRUE;
++nextIndex_;
}
}
return hr;
}
HRESULT STDMETHODCALLTYPE MFFontFileEnumerator::GetCurrentFontFile(OUT IDWriteFontFile** fontFile)
{
*fontFile = SafeAcquire(currentFile_);
return (currentFile_ != NULL) ? S_OK : E_FAIL;
}
// ---------------------------------------- MFFontContext ---------------------------------------------------------
MFFontContext::MFFontContext(IDWriteFactory *pFactory) : hr_(S_FALSE), g_dwriteFactory(pFactory)
{
}
MFFontContext::~MFFontContext()
{
g_dwriteFactory->UnregisterFontCollectionLoader(MFFontCollectionLoader::GetLoader());
}
HRESULT MFFontContext::Initialize()
{
if (hr_ == S_FALSE)
{
hr_ = InitializeInternal();
}
return hr_;
}
HRESULT MFFontContext::InitializeInternal()
{
HRESULT hr = S_OK;
if (!MFFontCollectionLoader::IsLoaderInitialized())
{
return E_FAIL;
}
// Register our custom loader with the factory object.
hr = g_dwriteFactory->RegisterFontCollectionLoader(MFFontCollectionLoader::GetLoader());
return hr;
}
HRESULT MFFontContext::CreateFontCollection(
MFCollection &newCollection,
OUT IDWriteFontCollection** result
)
{
*result = NULL;
HRESULT hr = S_OK;
// save new collection in MFFontGlobals::fontCollections vector
UINT collectionKey = MFFontGlobals::push(newCollection);
cKeys.push_back(collectionKey);
const void *fontCollectionKey = &cKeys.back();
UINT32 keySize = sizeof(collectionKey);
hr = Initialize();
if (FAILED(hr))
return hr;
hr = g_dwriteFactory->CreateCustomFontCollection(
MFFontCollectionLoader::GetLoader(),
fontCollectionKey,
keySize,
result
);
return hr;
}
std::vector<unsigned int> MFFontContext::cKeys = std::vector<unsigned int>(0);
// ----------------------------------- MFFontGlobals ---------------------------------------------------------
std::vector<MFCollection> MFFontGlobals::fontCollections = std::vector<MFCollection>(0);
Common.h
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
//
//----------------------------------------------------------------------------
#pragma once
// The following macros define the minimum required platform. The minimum required platform
// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
// your application. The macros work by enabling all features available on platform versions up to and
// including the version specified.
// Modify the following defines if you have to target a platform prior to the ones specified below.
// Refer to MSDN for the latest info on corresponding values for different platforms.
#ifndef WINVER // Minimum platform is Windows 7
#define WINVER 0x0601
#endif
#ifndef _WIN32_WINNT // Minimum platform is Windows 7
#define _WIN32_WINNT 0x0601
#endif
#ifndef _WIN32_WINDOWS // Minimum platform is Windows 7
#define _WIN32_WINDOWS 0x0601
#endif
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#ifndef UNICODE
#define UNICODE
#endif
// Windows header files
#include <windows.h>
#include <dwrite.h>
#include <d2d1.h>
// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <memory>
#include <vector>
// Ignore unreferenced parameters, since they are very common
// when implementing callbacks.
#pragma warning(disable : 4100)
////////////////////////////////////////
// COM inheritance helpers.
// Releases a COM object and nullifies pointer.
template <typename InterfaceType>
inline void SafeRelease(InterfaceType** currentObject)
{
if (*currentObject != NULL)
{
(*currentObject)->Release();
*currentObject = NULL;
}
}
// Acquires an additional reference, if non-null.
template <typename InterfaceType>
inline InterfaceType* SafeAcquire(InterfaceType* newObject)
{
if (newObject != NULL)
newObject->AddRef();
return newObject;
}
// Sets a new COM object, releasing the old one.
template <typename InterfaceType>
inline void SafeSet(InterfaceType** currentObject, InterfaceType* newObject)
{
SafeAcquire(newObject);
SafeRelease(¤tObject);
currentObject = newObject;
}
// Maps exceptions to equivalent HRESULTs,
inline HRESULT ExceptionToHResult() throw()
{
try
{
throw; // Rethrow previous exception.
}
catch (std::bad_alloc&)
{
return E_OUTOFMEMORY;
}
catch (...)
{
return E_FAIL;
}
}
代码当然不完美,但对我有用。
如果您对这段代码有任何疑问,请发表评论(尽管我可能无法再给出令人满意的答案)。请注意,我从 here.