From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/combase/combase.spec | 2 +- dlls/combase/combase_private.h | 1 + dlls/combase/roapi.c | 182 +++++++++++++++++++++++++++++++++ dlls/ole32/ole32.spec | 1 + include/combaseapi.h | 7 ++ 5 files changed, 192 insertions(+), 1 deletion(-)
diff --git a/dlls/combase/combase.spec b/dlls/combase/combase.spec index b3f4d25b42c..4bdc14334e2 100644 --- a/dlls/combase/combase.spec +++ b/dlls/combase/combase.spec @@ -292,7 +292,7 @@ @ stub RoFreeParameterizedTypeExtra @ stub RoGetActivatableClassRegistration @ stdcall RoGetActivationFactory(ptr ptr ptr) -@ stub RoGetAgileReference +@ stdcall RoGetAgileReference(long ptr ptr ptr) @ stdcall RoGetApartmentIdentifier(ptr) @ stub RoGetErrorReportingFlags @ stub RoGetMatchingRestrictedErrorInfo diff --git a/dlls/combase/combase_private.h b/dlls/combase/combase_private.h index 04d251962ec..ca79356e8eb 100644 --- a/dlls/combase/combase_private.h +++ b/dlls/combase/combase_private.h @@ -96,6 +96,7 @@ struct tlsdata };
extern HRESULT WINAPI InternalTlsAllocData(struct tlsdata **data); +extern BOOL WINAPI InternalIsProcessInitialized(void);
static inline HRESULT com_get_tlsdata(struct tlsdata **data) { diff --git a/dlls/combase/roapi.c b/dlls/combase/roapi.c index 02d9e0b536e..0f8a9438821 100644 --- a/dlls/combase/roapi.c +++ b/dlls/combase/roapi.c @@ -233,6 +233,188 @@ HRESULT WINAPI RoActivateInstance(HSTRING classid, IInspectable **instance) return hr; }
+struct agile_reference +{ + IAgileReference IAgileReference_iface; + enum AgileReferenceOptions option; + IStream *marshal_stream; + CRITICAL_SECTION cs; + IUnknown *obj; + LONG ref; +}; + +static HRESULT marshal_object_in_agile_reference(struct agile_reference *ref, REFIID riid, IUnknown *obj) +{ + HRESULT hr; + + hr = CreateStreamOnHGlobal(0, TRUE, &ref->marshal_stream); + if (FAILED(hr)) + return hr; + + hr = CoMarshalInterface(ref->marshal_stream, riid, obj, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLESTRONG); + if (FAILED(hr)) + { + IStream_Release(ref->marshal_stream); + ref->marshal_stream = NULL; + } + return hr; +} + +static inline struct agile_reference *impl_from_IAgileReference(IAgileReference *iface) +{ + return CONTAINING_RECORD(iface, struct agile_reference, IAgileReference_iface); +} + +static HRESULT WINAPI agile_ref_QueryInterface(IAgileReference *iface, REFIID riid, void **obj) +{ + TRACE("(%p, %s, %p)\n", iface, debugstr_guid(riid), obj); + + if (!riid || !obj) return E_INVALIDARG; + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IAgileObject) + || IsEqualGUID(riid, &IID_IAgileReference)) + { + IUnknown_AddRef(iface); + *obj = iface; + return S_OK; + } + + *obj = NULL; + FIXME("interface %s is not implemented\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI agile_ref_AddRef(IAgileReference *iface) +{ + struct agile_reference *impl = impl_from_IAgileReference(iface); + return InterlockedIncrement(&impl->ref); +} + +static ULONG WINAPI agile_ref_Release(IAgileReference *iface) +{ + struct agile_reference *impl = impl_from_IAgileReference(iface); + LONG ref = InterlockedDecrement(&impl->ref); + + if (!ref) + { + TRACE("destroying %p\n", iface); + + if (impl->obj) + IUnknown_Release(impl->obj); + + if (impl->marshal_stream) + { + LARGE_INTEGER zero = {0}; + + IStream_Seek(impl->marshal_stream, zero, STREAM_SEEK_SET, NULL); + CoReleaseMarshalData(impl->marshal_stream); + IStream_Release(impl->marshal_stream); + } + DeleteCriticalSection(&impl->cs); + free(impl); + } + + return ref; +} + +static HRESULT WINAPI agile_ref_Resolve(IAgileReference *iface, REFIID riid, void **obj) +{ + struct agile_reference *impl = impl_from_IAgileReference(iface); + LARGE_INTEGER zero = {0}; + HRESULT hr; + + TRACE("(%p, %s, %p)\n", iface, debugstr_guid(riid), obj); + + EnterCriticalSection(&impl->cs); + if (impl->option == AGILEREFERENCE_DELAYEDMARSHAL && impl->marshal_stream == NULL) + { + if (FAILED(hr = marshal_object_in_agile_reference(impl, riid, impl->obj))) + { + LeaveCriticalSection(&impl->cs); + return hr; + } + + IUnknown_Release(impl->obj); + impl->obj = NULL; + } + + if (SUCCEEDED(hr = IStream_Seek(impl->marshal_stream, zero, STREAM_SEEK_SET, NULL))) + hr = CoUnmarshalInterface(impl->marshal_stream, riid, obj); + + LeaveCriticalSection(&impl->cs); + return hr; +} + +static const IAgileReferenceVtbl agile_ref_vtbl = +{ + agile_ref_QueryInterface, + agile_ref_AddRef, + agile_ref_Release, + agile_ref_Resolve, +}; + +/*********************************************************************** + * RoGetAgileReference (combase.@) + */ +HRESULT WINAPI RoGetAgileReference(enum AgileReferenceOptions option, REFIID riid, IUnknown *obj, + IAgileReference **agile_reference) +{ + struct agile_reference *impl; + IUnknown *unknown; + HRESULT hr; + + TRACE("(%d, %s, %p, %p).\n", option, debugstr_guid(riid), obj, agile_reference); + + if (option != AGILEREFERENCE_DEFAULT && option != AGILEREFERENCE_DELAYEDMARSHAL) + return E_INVALIDARG; + + if (!InternalIsProcessInitialized()) + { + ERR("Apartment not initialized\n"); + return CO_E_NOTINITIALIZED; + } + + hr = IUnknown_QueryInterface(obj, riid, (void **)&unknown); + if (FAILED(hr)) + return E_NOINTERFACE; + IUnknown_Release(unknown); + + hr = IUnknown_QueryInterface(obj, &IID_INoMarshal, (void **)&unknown); + if (SUCCEEDED(hr)) + { + IUnknown_Release(unknown); + return CO_E_NOT_SUPPORTED; + } + + impl = calloc(1, sizeof(*impl)); + if (!impl) + return E_OUTOFMEMORY; + + impl->IAgileReference_iface.lpVtbl = &agile_ref_vtbl; + impl->option = option; + impl->ref = 1; + + if (option == AGILEREFERENCE_DEFAULT) + { + if (FAILED(hr = marshal_object_in_agile_reference(impl, riid, obj))) + { + free(impl); + return hr; + } + } + else if (option == AGILEREFERENCE_DELAYEDMARSHAL) + { + impl->obj = obj; + IUnknown_AddRef(impl->obj); + } + + InitializeCriticalSection(&impl->cs); + + *agile_reference = &impl->IAgileReference_iface; + return S_OK; +} + /*********************************************************************** * RoGetApartmentIdentifier (combase.@) */ diff --git a/dlls/ole32/ole32.spec b/dlls/ole32/ole32.spec index e9982036eeb..7ec85fc963f 100644 --- a/dlls/ole32/ole32.spec +++ b/dlls/ole32/ole32.spec @@ -254,6 +254,7 @@ @ stdcall RegisterDragDrop(long ptr) @ stdcall ReleaseStgMedium(ptr) @ stdcall RevokeDragDrop(long) +@ stdcall RoGetAgileReference(long ptr ptr ptr) combase.RoGetAgileReference @ stdcall SNB_UserFree(ptr ptr) @ stdcall SNB_UserMarshal(ptr ptr ptr) @ stdcall SNB_UserSize(ptr long ptr) diff --git a/include/combaseapi.h b/include/combaseapi.h index 4b8cb457328..41461f22e98 100644 --- a/include/combaseapi.h +++ b/include/combaseapi.h @@ -44,7 +44,14 @@ typedef struct tagServerInformation UINT64 ui64ServerAddress; } ServerInformation, *PServerInformation;
+enum AgileReferenceOptions +{ + AGILEREFERENCE_DEFAULT, + AGILEREFERENCE_DELAYEDMARSHAL +}; + HRESULT WINAPI CoDecodeProxy(DWORD client_pid, UINT64 proxy_addr, ServerInformation *server_info); +HRESULT WINAPI RoGetAgileReference(enum AgileReferenceOptions options, REFIID riid, IUnknown *obj, IAgileReference **agile_reference);
#ifdef __cplusplus }