From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 79 ++++++++++++++++++++++ dlls/uiautomationcore/uia_com_client.c | 13 ++++ 2 files changed, 92 insertions(+)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 0dd75ce862f..5bd8e52fddb 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -10620,6 +10620,79 @@ static void test_UiaFind(void) CoUninitialize(); }
+struct marshal_thread_data { + IUnknown *iface; + const GUID *iface_iid; + BOOL expect_proxy; + const char *file; + int line; + + IStream *marshal_stream; +}; + +static DWORD WINAPI interface_marshal_proxy_thread(LPVOID param) +{ + struct marshal_thread_data *data = (struct marshal_thread_data *)param; + IUnknown *proxy_iface, *unk, *unk2; + HRESULT hr; + + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + proxy_iface = unk = unk2 = NULL; + hr = CoGetInterfaceAndReleaseStream(data->marshal_stream, data->iface_iid, (void **)&proxy_iface); + ok_(data->file, data->line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IUnknown_QueryInterface(data->iface, &IID_IUnknown, (void **)&unk); + ok_(data->file, data->line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok_(data->file, data->line)(!!unk, "unk == NULL\n"); + + hr = IUnknown_QueryInterface(proxy_iface, &IID_IUnknown, (void **)&unk2); + ok_(data->file, data->line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok_(data->file, data->line)(!!unk2, "unk2 == NULL\n"); + + if (data->expect_proxy) + ok_(data->file, data->line)(unk != unk2, "unk == unk2\n"); + else + ok_(data->file, data->line)(unk == unk2, "unk != unk2\n"); + + IUnknown_Release(proxy_iface); + IUnknown_Release(unk); + IUnknown_Release(unk2); + + CoUninitialize(); + return 0; +} + +#define check_interface_marshal_proxy_creation( iface, iid, expect_proxy ) \ + check_interface_marshal_proxy_creation_( (iface), (iid), (expect_proxy), __FILE__, __LINE__) +static void check_interface_marshal_proxy_creation_(IUnknown *iface, REFIID iid, BOOL expect_proxy, const char *file, + int line) +{ + struct marshal_thread_data data = { NULL, iid, expect_proxy, file, line }; + HANDLE thread; + HRESULT hr; + + hr = IUnknown_QueryInterface(iface, data.iface_iid, (void **)&data.iface); + ok_(file, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = CoMarshalInterThreadInterfaceInStream(data.iface_iid, data.iface, &data.marshal_stream); + ok_(file, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + thread = CreateThread(NULL, 0, interface_marshal_proxy_thread, (void *)&data, 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); + + IUnknown_Release(data.iface); +} + static HWND create_test_hwnd(const char *class_name) { WNDCLASSA cls = { 0 }; @@ -10717,6 +10790,12 @@ static void test_ElementFromHandle(IUIAutomation *uia_iface, BOOL is_cui8) else ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr);
+ /* + * The IUIAutomationElement interface uses the free threaded marshaler, so + * no actual proxy interface will be created. + */ + check_interface_marshal_proxy_creation((IUnknown *)element, &IID_IUIAutomationElement, FALSE); + IUIAutomationElement_Release(element); ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref);
diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 75c722771c3..66326ad9574 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -1186,6 +1186,8 @@ struct uia_element {
struct uia_cache_property *cached_props; int cached_props_count; + + IUnknown *marshal; };
static inline struct uia_element *impl_from_IUIAutomationElement9(IUIAutomationElement9 *iface) @@ -1203,6 +1205,8 @@ static HRESULT WINAPI uia_element_QueryInterface(IUIAutomationElement9 *iface, R IsEqualIID(riid, &IID_IUIAutomationElement6) || IsEqualIID(riid, &IID_IUIAutomationElement7) || IsEqualIID(riid, &IID_IUIAutomationElement8) || IsEqualIID(riid, &IID_IUIAutomationElement9)))) *ppv = iface; + else if (IsEqualIID(riid, &IID_IMarshal)) + return IUnknown_QueryInterface(element->marshal, riid, ppv); else return E_NOINTERFACE;
@@ -1235,6 +1239,7 @@ static ULONG WINAPI uia_element_Release(IUIAutomationElement9 *iface) VariantClear(&element->cached_props[i].prop_val); }
+ IUnknown_Release(element->marshal); heap_free(element->cached_props); UiaNodeRelease(element->node); heap_free(element); @@ -2484,6 +2489,7 @@ static const IUIAutomationElement9Vtbl uia_element_vtbl = { static HRESULT create_uia_element(IUIAutomationElement **iface, BOOL from_cui8, HUIANODE node) { struct uia_element *element = heap_alloc_zero(sizeof(*element)); + HRESULT hr;
*iface = NULL; if (!element) @@ -2494,6 +2500,13 @@ static HRESULT create_uia_element(IUIAutomationElement **iface, BOOL from_cui8, element->from_cui8 = from_cui8; element->node = node;
+ hr = CoCreateFreeThreadedMarshaler((IUnknown *)&element->IUIAutomationElement9_iface, &element->marshal); + if (FAILED(hr)) + { + heap_free(element); + return hr; + } + *iface = (IUIAutomationElement *)&element->IUIAutomationElement9_iface; return S_OK; }