combase: Implement RoGetAgileReference().

This commit is contained in:
Zhiyi Zhang 2024-11-04 10:27:27 +08:00 committed by Alexandre Julliard
parent babb8730cc
commit a387549a27
Notes: Alexandre Julliard 2024-11-08 21:36:34 +01:00
Approved-by: Huw Davies (@huw)
Approved-by: Alexandre Julliard (@julliard)
Merge-Request: https://gitlab.winehq.org/wine/wine/merge_requests/6762
5 changed files with 192 additions and 1 deletions

View file

@ -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

View file

@ -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)
{

View file

@ -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.@)
*/

View file

@ -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)

View file

@ -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
}