mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-03-31 11:10:48 +02:00
WICFactory: Observe COM apartment and invalidate factory
This commit is contained in:
parent
eede753027
commit
eb9b503f57
3 changed files with 134 additions and 13 deletions
|
|
@ -159,25 +159,135 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class COMWeakRegistration final
|
||||
: public IInitializeSpy
|
||||
{
|
||||
public:
|
||||
explicit COMWeakRegistration (void (*cleanup)(void)) noexcept
|
||||
: cleanup (cleanup)
|
||||
{
|
||||
HRESULT hr;
|
||||
hr = CoRegisterInitializeSpy (this, ®istration_id);
|
||||
if (FAILED (hr)) {
|
||||
|
||||
}
|
||||
else {
|
||||
registered = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Register ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Unregister ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void EnsureApartment ()
|
||||
{
|
||||
HRESULT hr = CoInitializeEx (NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
|
||||
if (FAILED (hr)) {
|
||||
if (hr != RPC_E_CHANGED_MODE) {
|
||||
_cairo ();
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
IFACEMETHOD (QueryInterface) (REFIID riid, void** ppv) noexcept override
|
||||
{
|
||||
if (!ppv)
|
||||
return E_POINTER;
|
||||
|
||||
if (riid == IID_IUnknown || riid == IID_IInitializeSpy) {
|
||||
*ppv = this;
|
||||
AddRef ();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
*ppv = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
IFACEMETHOD_(ULONG, AddRef) () noexcept override
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
IFACEMETHOD_(ULONG, Release) () noexcept override
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
IFACEMETHOD (PreInitialize) (DWORD dwCoInit, DWORD dwCurThreadAptRefs) noexcept override
|
||||
{
|
||||
bool user_requested_sta = !!(dwCoInit & COINIT_APARTMENTTHREADED);
|
||||
bool cairo_holds_last_reference = (dwCurThreadAptRefs == 1);
|
||||
|
||||
if (user_requested_sta && cairo_holds_last_reference) {
|
||||
cleanup ();
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHOD (PreInitialize) (DWORD dwCoInit, DWORD dwCurThreadAptRefs) noexcept override
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHOD (PreInitialize) (DWORD dwCoInit, DWORD dwCurThreadAptRefs) noexcept override
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHOD (PreInitialize) (DWORD dwCoInit, DWORD dwCurThreadAptRefs) noexcept override
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
void (* cleanup) (void);
|
||||
ULARGE_INTEGER registration_id { 0 };
|
||||
bool registered { false };
|
||||
bool have_reference { false };
|
||||
};
|
||||
|
||||
class WICImagingFactory
|
||||
{
|
||||
public:
|
||||
static RefPtr<IWICImagingFactory> Instance()
|
||||
{
|
||||
if (!mFactoryInstance) {
|
||||
CoInitialize(NULL);
|
||||
CoCreateInstance(CLSID_WICImagingFactory,
|
||||
NULL,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
IID_PPV_ARGS(&mFactoryInstance));
|
||||
}
|
||||
return mFactoryInstance;
|
||||
}
|
||||
private:
|
||||
static RefPtr<IWICImagingFactory> mFactoryInstance;
|
||||
};
|
||||
cairo_win32_thread_data_t *thread_data = cairo_win32_thread_data_get ();
|
||||
|
||||
RefPtr<IWICImagingFactory> WICImagingFactory::mFactoryInstance;
|
||||
if (!thread_data->wic_factory) {
|
||||
if (!thread_data->com_observer) {
|
||||
thread_data->com_observer = new (std::nothrow) COMObserver ();
|
||||
}
|
||||
thread_data->com_observer->EnsureApartment ();
|
||||
|
||||
CoInitializeEx (NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
|
||||
hr = CoCreateInstance (CLSID_WICImagingFactory,
|
||||
NULL,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
IID_PPV_ARGS (&thread_data->wic_factory));
|
||||
if (FAILED (hr)) {
|
||||
_cairo_win32_api_error_fatal_with_hr (hr, "%s (%s)",
|
||||
"CoCreateInstance",
|
||||
"CLSID_WICImagingFactory");
|
||||
}
|
||||
}
|
||||
|
||||
return thread_data->wic_factory;
|
||||
}
|
||||
};
|
||||
|
||||
cairo_atomic_once_t DWriteFactory::mOnceFactories = CAIRO_ATOMIC_ONCE_INIT;
|
||||
RefPtr<IDWriteFactory> DWriteFactory::mFactoryInstance;
|
||||
|
|
@ -186,6 +296,7 @@ RefPtr<IDWriteFactory2> DWriteFactory::mFactoryInstance2;
|
|||
RefPtr<IDWriteFactory3> DWriteFactory::mFactoryInstance3;
|
||||
RefPtr<IDWriteFactory4> DWriteFactory::mFactoryInstance4;
|
||||
RefPtr<IDWriteFactory8> DWriteFactory::mFactoryInstance8;
|
||||
|
||||
cairo_atomic_once_t DWriteFactory::mOnceSystemCollection = CAIRO_ATOMIC_ONCE_INIT;
|
||||
RefPtr<IDWriteFontCollection> DWriteFactory::mSystemCollection;
|
||||
|
||||
|
|
|
|||
|
|
@ -181,6 +181,9 @@ _cairo_win32_gdi_compositor_get (void);
|
|||
cairo_status_t
|
||||
_cairo_win32_print_api_error (const char *context, const char *api);
|
||||
|
||||
cairo_status_t
|
||||
_cairo_win32_api_error_fatal (const char *format, ...);
|
||||
|
||||
cairo_bool_t
|
||||
_cairo_surface_is_win32 (const cairo_surface_t *surface);
|
||||
|
||||
|
|
@ -249,6 +252,8 @@ cairo_win32_async_com_release (IUnknown *iface_ptr);
|
|||
|
||||
#if CAIRO_HAS_DWRITE_FONT
|
||||
interface ID2D1Factory;
|
||||
interface IWICImagingFactory;
|
||||
struct COMObserver;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -256,6 +261,8 @@ typedef struct {
|
|||
|
||||
#if CAIRO_HAS_DWRITE_FONT
|
||||
interface ID2D1Factory *d2d1_factory;
|
||||
interface IWICImagingFactory *wic_factory;
|
||||
struct COMObserver *com_observer;
|
||||
#endif
|
||||
|
||||
cairo_bool_t added_to_list;
|
||||
|
|
|
|||
|
|
@ -100,6 +100,9 @@ thread_data_free (cairo_win32_thread_data_t *data)
|
|||
*/
|
||||
cairo_win32_async_stdcall_free ((stdcall_free_func_t) DeleteDC, data->hdc);
|
||||
|
||||
if (data->com_observer)
|
||||
data->com_observer->Detach ();
|
||||
|
||||
#if CAIRO_HAS_DWRITE_FONT
|
||||
cairo_win32_async_com_release ((IUnknown*) data->d2d1_factory);
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue