Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/Makefile.in | 1 + dlls/uiautomationcore/uia_main.c | 147 +++++++++++++++++++++++++++++- 2 files changed, 146 insertions(+), 2 deletions(-)
diff --git a/dlls/uiautomationcore/Makefile.in b/dlls/uiautomationcore/Makefile.in index 71ea7b99c94..5a72ea144c4 100644 --- a/dlls/uiautomationcore/Makefile.in +++ b/dlls/uiautomationcore/Makefile.in @@ -1,5 +1,6 @@ MODULE = uiautomationcore.dll IMPORTLIB = uiautomationcore +IMPORTS = uuid ole32
EXTRADLLFLAGS = -Wb,--prefer-native
diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index 2dada95af80..51c220c6041 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -16,12 +16,150 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#define COBJMACROS + #include "uiautomation.h"
#include "wine/debug.h" +#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
+struct uia_rsrv_ftmarshaler +{ + IUnknown IUnknown_iface; + LONG refcount; + + IUnknown *inner; + IUnknown *rsrv_val; +}; + +static struct uia_rsrv_ftmarshaler *uia_rsrv_ns_val_ftmarshaler = NULL; + +static struct uia_rsrv_ftmarshaler *impl_uia_rsrv_ftmarshaler_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct uia_rsrv_ftmarshaler, IUnknown_iface); +} + +static HRESULT WINAPI uia_rsrv_ftmarshaler_QueryInterface(IUnknown *iface, + REFIID riid, void **ppv) +{ + struct uia_rsrv_ftmarshaler *marshaler = impl_uia_rsrv_ftmarshaler_from_IUnknown(iface); + + return IUnknown_QueryInterface(marshaler->rsrv_val, riid, ppv); +} + +static ULONG WINAPI uia_rsrv_ftmarshaler_AddRef(IUnknown *iface) +{ + struct uia_rsrv_ftmarshaler *marshaler = impl_uia_rsrv_ftmarshaler_from_IUnknown(iface); + ULONG refcount = InterlockedIncrement(&marshaler->refcount); + + TRACE("%p, refcount %d\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI uia_rsrv_ftmarshaler_Release(IUnknown *iface) +{ + struct uia_rsrv_ftmarshaler *marshaler = impl_uia_rsrv_ftmarshaler_from_IUnknown(iface); + ULONG refcount = InterlockedDecrement(&marshaler->refcount); + + TRACE("%p, refcount %d\n", iface, refcount); + if (!refcount) + { + if (marshaler == uia_rsrv_ns_val_ftmarshaler) + uia_rsrv_ns_val_ftmarshaler = NULL; + + IUnknown_Release(marshaler->inner); + heap_free(marshaler); + } + + return refcount; +} + +static const IUnknownVtbl uia_rsrv_ftmarshaler_vtbl = { + uia_rsrv_ftmarshaler_QueryInterface, + uia_rsrv_ftmarshaler_AddRef, + uia_rsrv_ftmarshaler_Release, +}; + +/* + * When passing the ReservedNotSupportedValue/ReservedMixedAttributeValue + * interface pointers across apartments within the same process, create a free + * threaded marshaler so that the pointer value is preserved. + */ +static HRESULT uia_rsrv_val_create_ftmarshaler(IUnknown *reserved, struct uia_rsrv_ftmarshaler **marshaler) +{ + struct uia_rsrv_ftmarshaler *object; + HRESULT hr; + + TRACE("%p, %p\n", reserved, marshaler); + + object = heap_alloc(sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + + object->IUnknown_iface.lpVtbl = &uia_rsrv_ftmarshaler_vtbl; + object->refcount = 1; + + hr = CoCreateFreeThreadedMarshaler(&object->IUnknown_iface, &object->inner); + if (FAILED(hr = CoCreateFreeThreadedMarshaler(&object->IUnknown_iface, &object->inner))) + { + heap_free(object); + return hr; + } + + *marshaler = object; + + return hr; +} + +/* + * UiaReservedNotSupported object. + */ +static HRESULT WINAPI uia_reserved_ns_QueryInterface(IUnknown *iface, + REFIID riid, void **ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else if (IsEqualIID(riid, &IID_IMarshal)) + { + if (!uia_rsrv_ns_val_ftmarshaler) + { + if (FAILED(uia_rsrv_val_create_ftmarshaler(iface, &uia_rsrv_ns_val_ftmarshaler))) + return E_NOINTERFACE; + } + + if (FAILED(IUnknown_QueryInterface(uia_rsrv_ns_val_ftmarshaler->inner, riid, ppv))) + return E_NOINTERFACE; + + IUnknown_Release(&uia_rsrv_ns_val_ftmarshaler->IUnknown_iface); + } + else + return E_NOINTERFACE; + + return S_OK; +} + +static ULONG WINAPI uia_reserved_ns_AddRef(IUnknown *iface) +{ + return 1; +} + +static ULONG WINAPI uia_reserved_ns_Release(IUnknown *iface) +{ + return 1; +} + +static const IUnknownVtbl uia_reserved_ns_vtbl = { + uia_reserved_ns_QueryInterface, + uia_reserved_ns_AddRef, + uia_reserved_ns_Release, +}; + +static IUnknown uia_reserved_ns_iface = {&uia_reserved_ns_vtbl}; + /*********************************************************************** * UiaClientsAreListening (uiautomationcore.@) */ @@ -46,8 +184,13 @@ HRESULT WINAPI UiaGetReservedMixedAttributeValue(IUnknown **value) */ HRESULT WINAPI UiaGetReservedNotSupportedValue(IUnknown **value) { - FIXME("(%p) stub!\n", value); - *value = NULL; + TRACE("(%p)\n", value); + + if (!value) + return E_INVALIDARG; + + *value = &uia_reserved_ns_iface; + return S_OK; }
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/uia_main.c | 58 ++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-)
diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index 51c220c6041..17ddc19016f 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -35,6 +35,7 @@ struct uia_rsrv_ftmarshaler };
static struct uia_rsrv_ftmarshaler *uia_rsrv_ns_val_ftmarshaler = NULL; +static struct uia_rsrv_ftmarshaler *uia_rsrv_ma_val_ftmarshaler = NULL;
static struct uia_rsrv_ftmarshaler *impl_uia_rsrv_ftmarshaler_from_IUnknown(IUnknown *iface) { @@ -69,6 +70,8 @@ static ULONG WINAPI uia_rsrv_ftmarshaler_Release(IUnknown *iface) { if (marshaler == uia_rsrv_ns_val_ftmarshaler) uia_rsrv_ns_val_ftmarshaler = NULL; + else if (marshaler == uia_rsrv_ma_val_ftmarshaler) + uia_rsrv_ma_val_ftmarshaler = NULL;
IUnknown_Release(marshaler->inner); heap_free(marshaler); @@ -160,6 +163,52 @@ static const IUnknownVtbl uia_reserved_ns_vtbl = {
static IUnknown uia_reserved_ns_iface = {&uia_reserved_ns_vtbl};
+/* + * UiaReservedMixedAttribute object. + */ +static HRESULT WINAPI uia_reserved_ma_QueryInterface(IUnknown *iface, + REFIID riid, void **ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else if (IsEqualIID(riid, &IID_IMarshal)) + { + if (!uia_rsrv_ma_val_ftmarshaler) + { + if (FAILED(uia_rsrv_val_create_ftmarshaler(iface, &uia_rsrv_ma_val_ftmarshaler))) + return E_NOINTERFACE; + } + + if (FAILED(IUnknown_QueryInterface(uia_rsrv_ma_val_ftmarshaler->inner, riid, ppv))) + return E_NOINTERFACE; + + IUnknown_Release(&uia_rsrv_ma_val_ftmarshaler->IUnknown_iface); + } + else + return E_NOINTERFACE; + + return S_OK; +} + +static ULONG WINAPI uia_reserved_ma_AddRef(IUnknown *iface) +{ + return 1; +} + +static ULONG WINAPI uia_reserved_ma_Release(IUnknown *iface) +{ + return 1; +} + +static const IUnknownVtbl uia_reserved_ma_vtbl = { + uia_reserved_ma_QueryInterface, + uia_reserved_ma_AddRef, + uia_reserved_ma_Release, +}; + +static IUnknown uia_reserved_ma_iface = {&uia_reserved_ma_vtbl}; + /*********************************************************************** * UiaClientsAreListening (uiautomationcore.@) */ @@ -174,8 +223,13 @@ BOOL WINAPI UiaClientsAreListening(void) */ HRESULT WINAPI UiaGetReservedMixedAttributeValue(IUnknown **value) { - FIXME("(%p) stub!\n", value); - *value = NULL; + TRACE("(%p)\n", value); + + if (!value) + return E_INVALIDARG; + + *value = &uia_reserved_ma_iface; + return S_OK; }
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/Makefile.in | 2 +- dlls/uiautomationcore/tests/uiautomation.c | 133 +++++++++++++++++++++ 2 files changed, 134 insertions(+), 1 deletion(-)
diff --git a/dlls/uiautomationcore/tests/Makefile.in b/dlls/uiautomationcore/tests/Makefile.in index c39b062b6fd..1d08e19093f 100644 --- a/dlls/uiautomationcore/tests/Makefile.in +++ b/dlls/uiautomationcore/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = uiautomationcore.dll -IMPORTS = uiautomationcore user32 +IMPORTS = uiautomationcore user32 ole32
C_SRCS = \ uiautomation.c diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index cbcba1af294..52a6648dad2 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -86,7 +86,140 @@ if (hr == S_OK) UnregisterClassA("HostProviderFromHwnd class", NULL); }
+static DWORD WINAPI uia_reserved_val_iface_marshal_thread(LPVOID param) +{ + IStream **stream = param; + IUnknown *unk_ns, *unk_ns2, *unk_ma, *unk_ma2; + HRESULT hr; + + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + hr = CoGetInterfaceAndReleaseStream(stream[0], &IID_IUnknown, (void **)&unk_ns); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = CoGetInterfaceAndReleaseStream(stream[1], &IID_IUnknown, (void **)&unk_ma); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = UiaGetReservedNotSupportedValue(&unk_ns2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = UiaGetReservedMixedAttributeValue(&unk_ma2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + ok(unk_ns2 == unk_ns, "UiaGetReservedNotSupported pointer mismatch, unk_ns2 %p, unk_ns %p\n", unk_ns2, unk_ns); + ok(unk_ma2 == unk_ma, "UiaGetReservedMixedAttribute pointer mismatch, unk_ma2 %p, unk_ma %p\n", unk_ma2, unk_ma); + + CoUninitialize(); + + return 0; +} + +static void test_uia_reserved_value_ifaces(void) +{ + IUnknown *unk_ns, *unk_ns2, *unk_ma, *unk_ma2; + IStream *stream[2]; + IMarshal *marshal; + HANDLE thread; + ULONG refcnt; + HRESULT hr; + + /* ReservedNotSupportedValue. */ + hr = UiaGetReservedNotSupportedValue(NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = UiaGetReservedNotSupportedValue(&unk_ns); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(unk_ns != NULL, "UiaGetReservedNotSupportedValue returned NULL interface.\n"); + + refcnt = IUnknown_AddRef(unk_ns); + ok(refcnt == 1, "Expected refcnt %d, got %d\n", 1, refcnt); + + refcnt = IUnknown_AddRef(unk_ns); + ok(refcnt == 1, "Expected refcnt %d, got %d\n", 1, refcnt); + + refcnt = IUnknown_Release(unk_ns); + ok(refcnt == 1, "Expected refcnt %d, got %d\n", 1, refcnt); + + hr = UiaGetReservedNotSupportedValue(&unk_ns2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(unk_ns2 != NULL, "UiaGetReservedNotSupportedValue returned NULL interface."); + ok(unk_ns2 == unk_ns, "UiaGetReservedNotSupported pointer mismatch, unk_ns2 %p, unk_ns %p\n", unk_ns2, unk_ns); + + marshal = NULL; + hr = IUnknown_QueryInterface(unk_ns, &IID_IMarshal, (void **)&marshal); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(marshal != NULL, "Failed to get IMarshal interface.\n"); + + refcnt = IMarshal_AddRef(marshal); + ok(refcnt == 2, "Expected refcnt %d, got %d\n", 2, refcnt); + + refcnt = IMarshal_Release(marshal); + ok(refcnt == 1, "Expected refcnt %d, got %d\n", 1, refcnt); + + refcnt = IMarshal_Release(marshal); + ok(refcnt == 0, "Expected refcnt %d, got %d\n", 0, refcnt); + + /* ReservedMixedAttributeValue. */ + hr = UiaGetReservedMixedAttributeValue(NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = UiaGetReservedMixedAttributeValue(&unk_ma); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(unk_ma != NULL, "UiaGetReservedMixedAttributeValue returned NULL interface."); + + refcnt = IUnknown_AddRef(unk_ma); + ok(refcnt == 1, "Expected refcnt %d, got %d\n", 1, refcnt); + + refcnt = IUnknown_AddRef(unk_ma); + ok(refcnt == 1, "Expected refcnt %d, got %d\n", 1, refcnt); + + refcnt = IUnknown_Release(unk_ma); + ok(refcnt == 1, "Expected refcnt %d, got %d\n", 1, refcnt); + + hr = UiaGetReservedMixedAttributeValue(&unk_ma2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(unk_ma2 != NULL, "UiaGetReservedMixedAttributeValue returned NULL interface."); + ok(unk_ma2 == unk_ma, "UiaGetReservedMixedAttribute pointer mismatch, unk_ma2 %p, unk_ma %p\n", unk_ma2, unk_ma); + + marshal = NULL; + hr = IUnknown_QueryInterface(unk_ma, &IID_IMarshal, (void **)&marshal); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(marshal != NULL, "Failed to get IMarshal interface.\n"); + + refcnt = IMarshal_AddRef(marshal); + ok(refcnt == 2, "Expected refcnt %d, got %d\n", 2, refcnt); + + refcnt = IMarshal_Release(marshal); + ok(refcnt == 1, "Expected refcnt %d, got %d\n", 1, refcnt); + + refcnt = IMarshal_Release(marshal); + ok(refcnt == 0, "Expected refcnt %d, got %d\n", 0, refcnt); + + /* Test cross-thread marshaling behavior. */ + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, unk_ns, &stream[0]); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, unk_ma, &stream[1]); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + thread = CreateThread(NULL, 0, uia_reserved_val_iface_marshal_thread, (void *)stream, 0, NULL); + while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0) + { + MSG msg; + while(PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + CloseHandle(thread); + + CoUninitialize(); +} + START_TEST(uiautomation) { test_UiaHostProviderFromHwnd(); + test_uia_reserved_value_ifaces(); }
On 10/28/21 6:17 PM, Connor McAdams wrote:
Signed-off-by: Connor McAdams cmcadams@codeweavers.com
dlls/uiautomationcore/Makefile.in | 1 + dlls/uiautomationcore/uia_main.c | 147 +++++++++++++++++++++++++++++- 2 files changed, 146 insertions(+), 2 deletions(-)
diff --git a/dlls/uiautomationcore/Makefile.in b/dlls/uiautomationcore/Makefile.in index 71ea7b99c94..5a72ea144c4 100644 --- a/dlls/uiautomationcore/Makefile.in +++ b/dlls/uiautomationcore/Makefile.in @@ -1,5 +1,6 @@ MODULE = uiautomationcore.dll IMPORTLIB = uiautomationcore +IMPORTS = uuid ole32
EXTRADLLFLAGS = -Wb,--prefer-native
diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index 2dada95af80..51c220c6041 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -16,12 +16,150 @@
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#define COBJMACROS
#include "uiautomation.h"
#include "wine/debug.h" +#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
+struct uia_rsrv_ftmarshaler +{
- IUnknown IUnknown_iface;
- LONG refcount;
- IUnknown *inner;
- IUnknown *rsrv_val;
+};
I think naming is confusing. 'inner' here really means marshaler, rsrv_val is the object marshaler is associated with, and the whole thing is not an ftmarshaler, but something like a host or a wrapper.
+static struct uia_rsrv_ftmarshaler *uia_rsrv_ns_val_ftmarshaler = NULL;
I thought you said that new instances are created every time?
+static struct uia_rsrv_ftmarshaler *impl_uia_rsrv_ftmarshaler_from_IUnknown(IUnknown *iface) +{
- return CONTAINING_RECORD(iface, struct uia_rsrv_ftmarshaler, IUnknown_iface);
+}
+static HRESULT WINAPI uia_rsrv_ftmarshaler_QueryInterface(IUnknown *iface,
REFIID riid, void **ppv)
+{
- struct uia_rsrv_ftmarshaler *marshaler = impl_uia_rsrv_ftmarshaler_from_IUnknown(iface);
- return IUnknown_QueryInterface(marshaler->rsrv_val, riid, ppv);
+}
+static ULONG WINAPI uia_rsrv_ftmarshaler_AddRef(IUnknown *iface) +{
- struct uia_rsrv_ftmarshaler *marshaler = impl_uia_rsrv_ftmarshaler_from_IUnknown(iface);
- ULONG refcount = InterlockedIncrement(&marshaler->refcount);
- TRACE("%p, refcount %d\n", iface, refcount);
- return refcount;
+}
+static ULONG WINAPI uia_rsrv_ftmarshaler_Release(IUnknown *iface) +{
- struct uia_rsrv_ftmarshaler *marshaler = impl_uia_rsrv_ftmarshaler_from_IUnknown(iface);
- ULONG refcount = InterlockedDecrement(&marshaler->refcount);
- TRACE("%p, refcount %d\n", iface, refcount);
- if (!refcount)
- {
if (marshaler == uia_rsrv_ns_val_ftmarshaler)
uia_rsrv_ns_val_ftmarshaler = NULL;
IUnknown_Release(marshaler->inner);
heap_free(marshaler);
- }
- return refcount;
+}
+static const IUnknownVtbl uia_rsrv_ftmarshaler_vtbl = {
- uia_rsrv_ftmarshaler_QueryInterface,
- uia_rsrv_ftmarshaler_AddRef,
- uia_rsrv_ftmarshaler_Release,
+};
+/*
- When passing the ReservedNotSupportedValue/ReservedMixedAttributeValue
- interface pointers across apartments within the same process, create a free
- threaded marshaler so that the pointer value is preserved.
- */
+static HRESULT uia_rsrv_val_create_ftmarshaler(IUnknown *reserved, struct uia_rsrv_ftmarshaler **marshaler) +{
- struct uia_rsrv_ftmarshaler *object;
- HRESULT hr;
- TRACE("%p, %p\n", reserved, marshaler);
- object = heap_alloc(sizeof(*object));
- if (!object)
return E_OUTOFMEMORY;
- object->IUnknown_iface.lpVtbl = &uia_rsrv_ftmarshaler_vtbl;
- object->refcount = 1;
- hr = CoCreateFreeThreadedMarshaler(&object->IUnknown_iface, &object->inner);
- if (FAILED(hr = CoCreateFreeThreadedMarshaler(&object->IUnknown_iface, &object->inner)))
- {
heap_free(object);
return hr;
- }
This one is obviously copy-paste typo.
- *marshaler = object;
- return hr;
+}
+/*
- UiaReservedNotSupported object.
- */
+static HRESULT WINAPI uia_reserved_ns_QueryInterface(IUnknown *iface,
REFIID riid, void **ppv)
+{
- *ppv = NULL;
- if (IsEqualIID(riid, &IID_IUnknown))
*ppv = iface;
- else if (IsEqualIID(riid, &IID_IMarshal))
- {
if (!uia_rsrv_ns_val_ftmarshaler)
{
if (FAILED(uia_rsrv_val_create_ftmarshaler(iface, &uia_rsrv_ns_val_ftmarshaler)))
return E_NOINTERFACE;
}
if (FAILED(IUnknown_QueryInterface(uia_rsrv_ns_val_ftmarshaler->inner, riid, ppv)))
return E_NOINTERFACE;
IUnknown_Release(&uia_rsrv_ns_val_ftmarshaler->IUnknown_iface);
- }
- else
return E_NOINTERFACE;
- return S_OK;
+}
It's not safe to handle shared pointer like that, when you know you're going to run in multithreaded environment.
I think creating that helper wrapper/host object, and then creating marshaler on every call should be fine.
+static ULONG WINAPI uia_reserved_ns_AddRef(IUnknown *iface) +{
- return 1;
+}
+static ULONG WINAPI uia_reserved_ns_Release(IUnknown *iface) +{
- return 1;
+}
That probably doesn't matter, but I'll mentioned it anyway, occasionally for such singleton objects they still maintain refcount field, that doesn't do anything, expect changing its value.
+static const IUnknownVtbl uia_reserved_ns_vtbl = {
- uia_reserved_ns_QueryInterface,
- uia_reserved_ns_AddRef,
- uia_reserved_ns_Release,
+};
+static IUnknown uia_reserved_ns_iface = {&uia_reserved_ns_vtbl};
/***********************************************************************
UiaClientsAreListening (uiautomationcore.@)
*/ @@ -46,8 +184,13 @@ HRESULT WINAPI UiaGetReservedMixedAttributeValue(IUnknown **value) */ HRESULT WINAPI UiaGetReservedNotSupportedValue(IUnknown **value) {
- FIXME("(%p) stub!\n", value);
- *value = NULL;
- TRACE("(%p)\n", value);
- if (!value)
return E_INVALIDARG;
- *value = &uia_reserved_ns_iface;
- return S_OK;
}
On Thu, Oct 28, 2021 at 09:02:40PM +0300, Nikolay Sivov wrote:
On 10/28/21 6:17 PM, Connor McAdams wrote:
Signed-off-by: Connor McAdams cmcadams@codeweavers.com
dlls/uiautomationcore/Makefile.in | 1 + dlls/uiautomationcore/uia_main.c | 147 +++++++++++++++++++++++++++++- 2 files changed, 146 insertions(+), 2 deletions(-)
diff --git a/dlls/uiautomationcore/Makefile.in b/dlls/uiautomationcore/Makefile.in index 71ea7b99c94..5a72ea144c4 100644 --- a/dlls/uiautomationcore/Makefile.in +++ b/dlls/uiautomationcore/Makefile.in @@ -1,5 +1,6 @@ MODULE = uiautomationcore.dll IMPORTLIB = uiautomationcore +IMPORTS = uuid ole32
EXTRADLLFLAGS = -Wb,--prefer-native
diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index 2dada95af80..51c220c6041 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -16,12 +16,150 @@
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#define COBJMACROS
#include "uiautomation.h"
#include "wine/debug.h" +#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
+struct uia_rsrv_ftmarshaler +{
- IUnknown IUnknown_iface;
- LONG refcount;
- IUnknown *inner;
- IUnknown *rsrv_val;
+};
I think naming is confusing. 'inner' here really means marshaler, rsrv_val is the object marshaler is associated with, and the whole thing is not an ftmarshaler, but something like a host or a wrapper.
Yeah, I agree the naming is a bit confusing. I was having trouble with that, but I'll use the name you've suggested in the next version.
+static struct uia_rsrv_ftmarshaler *uia_rsrv_ns_val_ftmarshaler = NULL;
I thought you said that new instances are created every time?
+static struct uia_rsrv_ftmarshaler *impl_uia_rsrv_ftmarshaler_from_IUnknown(IUnknown *iface) +{
- return CONTAINING_RECORD(iface, struct uia_rsrv_ftmarshaler, IUnknown_iface);
+}
+static HRESULT WINAPI uia_rsrv_ftmarshaler_QueryInterface(IUnknown *iface,
REFIID riid, void **ppv)
+{
- struct uia_rsrv_ftmarshaler *marshaler = impl_uia_rsrv_ftmarshaler_from_IUnknown(iface);
- return IUnknown_QueryInterface(marshaler->rsrv_val, riid, ppv);
+}
+static ULONG WINAPI uia_rsrv_ftmarshaler_AddRef(IUnknown *iface) +{
- struct uia_rsrv_ftmarshaler *marshaler = impl_uia_rsrv_ftmarshaler_from_IUnknown(iface);
- ULONG refcount = InterlockedIncrement(&marshaler->refcount);
- TRACE("%p, refcount %d\n", iface, refcount);
- return refcount;
+}
+static ULONG WINAPI uia_rsrv_ftmarshaler_Release(IUnknown *iface) +{
- struct uia_rsrv_ftmarshaler *marshaler = impl_uia_rsrv_ftmarshaler_from_IUnknown(iface);
- ULONG refcount = InterlockedDecrement(&marshaler->refcount);
- TRACE("%p, refcount %d\n", iface, refcount);
- if (!refcount)
- {
if (marshaler == uia_rsrv_ns_val_ftmarshaler)
uia_rsrv_ns_val_ftmarshaler = NULL;
IUnknown_Release(marshaler->inner);
heap_free(marshaler);
- }
- return refcount;
+}
+static const IUnknownVtbl uia_rsrv_ftmarshaler_vtbl = {
- uia_rsrv_ftmarshaler_QueryInterface,
- uia_rsrv_ftmarshaler_AddRef,
- uia_rsrv_ftmarshaler_Release,
+};
+/*
- When passing the ReservedNotSupportedValue/ReservedMixedAttributeValue
- interface pointers across apartments within the same process, create a free
- threaded marshaler so that the pointer value is preserved.
- */
+static HRESULT uia_rsrv_val_create_ftmarshaler(IUnknown *reserved, struct uia_rsrv_ftmarshaler **marshaler) +{
- struct uia_rsrv_ftmarshaler *object;
- HRESULT hr;
- TRACE("%p, %p\n", reserved, marshaler);
- object = heap_alloc(sizeof(*object));
- if (!object)
return E_OUTOFMEMORY;
- object->IUnknown_iface.lpVtbl = &uia_rsrv_ftmarshaler_vtbl;
- object->refcount = 1;
- hr = CoCreateFreeThreadedMarshaler(&object->IUnknown_iface, &object->inner);
- if (FAILED(hr = CoCreateFreeThreadedMarshaler(&object->IUnknown_iface, &object->inner)))
- {
heap_free(object);
return hr;
- }
This one is obviously copy-paste typo.
Oof, yeah, good catch.
- *marshaler = object;
- return hr;
+}
+/*
- UiaReservedNotSupported object.
- */
+static HRESULT WINAPI uia_reserved_ns_QueryInterface(IUnknown *iface,
REFIID riid, void **ppv)
+{
- *ppv = NULL;
- if (IsEqualIID(riid, &IID_IUnknown))
*ppv = iface;
- else if (IsEqualIID(riid, &IID_IMarshal))
- {
if (!uia_rsrv_ns_val_ftmarshaler)
{
if (FAILED(uia_rsrv_val_create_ftmarshaler(iface, &uia_rsrv_ns_val_ftmarshaler)))
return E_NOINTERFACE;
}
if (FAILED(IUnknown_QueryInterface(uia_rsrv_ns_val_ftmarshaler->inner, riid, ppv)))
return E_NOINTERFACE;
IUnknown_Release(&uia_rsrv_ns_val_ftmarshaler->IUnknown_iface);
- }
- else
return E_NOINTERFACE;
- return S_OK;
+}
It's not safe to handle shared pointer like that, when you know you're going to run in multithreaded environment.
I think creating that helper wrapper/host object, and then creating marshaler on every call should be fine.
Ah, okay. In our last discussion you had asked if it was really that important that QI returns a new instance each time, so I assumed you wanted a shared instance across each call. I can go back to creating a unique one each time though like I was doing before.
+static ULONG WINAPI uia_reserved_ns_AddRef(IUnknown *iface) +{
- return 1;
+}
+static ULONG WINAPI uia_reserved_ns_Release(IUnknown *iface) +{
- return 1;
+}
That probably doesn't matter, but I'll mentioned it anyway, occasionally for such singleton objects they still maintain refcount field, that doesn't do anything, expect changing its value.
+static const IUnknownVtbl uia_reserved_ns_vtbl = {
- uia_reserved_ns_QueryInterface,
- uia_reserved_ns_AddRef,
- uia_reserved_ns_Release,
+};
+static IUnknown uia_reserved_ns_iface = {&uia_reserved_ns_vtbl};
/***********************************************************************
UiaClientsAreListening (uiautomationcore.@)
*/ @@ -46,8 +184,13 @@ HRESULT WINAPI UiaGetReservedMixedAttributeValue(IUnknown **value) */ HRESULT WINAPI UiaGetReservedNotSupportedValue(IUnknown **value) {
- FIXME("(%p) stub!\n", value);
- *value = NULL;
- TRACE("(%p)\n", value);
- if (!value)
return E_INVALIDARG;
- *value = &uia_reserved_ns_iface;
- return S_OK;
}
Thanks for the review.