Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- -v3: Match recent Windows behavior, fix tests for earlier Windows behavior.
dlls/uiautomationcore/Makefile.in | 1 + dlls/uiautomationcore/uia_main.c | 125 +++++++++++++++++++++++++++++- 2 files changed, 124 insertions(+), 2 deletions(-)
diff --git a/dlls/uiautomationcore/Makefile.in b/dlls/uiautomationcore/Makefile.in index 71ea7b99c94..1f6ad85c24f 100644 --- a/dlls/uiautomationcore/Makefile.in +++ b/dlls/uiautomationcore/Makefile.in @@ -1,5 +1,6 @@ MODULE = uiautomationcore.dll IMPORTLIB = uiautomationcore +IMPORTS = oleaut32 user32
EXTRADLLFLAGS = -Wb,--prefer-native
diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index 2dada95af80..8d4f91947aa 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -16,9 +16,14 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#define COBJMACROS + +#include "windows.h" +#include "initguid.h" #include "uiautomation.h"
#include "wine/debug.h" +#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
@@ -84,10 +89,126 @@ void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *callback) FIXME("(%p): stub\n", callback); }
+typedef struct { + IRawElementProviderSimple IRawElementProviderSimple_iface; + LONG ref; + + HWND hwnd; +} HwndProvider; + +static inline HwndProvider *impl_from_HwndProvider(IRawElementProviderSimple *iface) +{ + return CONTAINING_RECORD(iface, HwndProvider, IRawElementProviderSimple_iface); +} + +HRESULT WINAPI HwndProvider_QueryInterface(IRawElementProviderSimple *iface, REFIID riid, void **ppv) +{ + if (IsEqualIID(riid, &IID_IRawElementProviderSimple) || + IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else + { + *ppv = NULL; + return E_NOINTERFACE; + } + + IRawElementProviderSimple_AddRef(iface); + return S_OK; +} + +ULONG WINAPI HwndProvider_AddRef(IRawElementProviderSimple *iface) +{ + HwndProvider *This = impl_from_HwndProvider(iface); + return InterlockedIncrement(&This->ref); +} + +ULONG WINAPI HwndProvider_Release(IRawElementProviderSimple *iface) +{ + HwndProvider *This = impl_from_HwndProvider(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + if (!ref) + heap_free(This); + + return ref; +} + +HRESULT WINAPI HwndProvider_get_ProviderOptions(IRawElementProviderSimple *iface, + enum ProviderOptions *ret_val) +{ + *ret_val = ProviderOptions_ServerSideProvider; + return S_OK; +} + +HRESULT WINAPI HwndProvider_GetPatternProvider(IRawElementProviderSimple *iface, + PATTERNID pattern_id, IUnknown **ret_val) +{ + *ret_val = NULL; + return S_OK; +} + +HRESULT WINAPI HwndProvider_GetPropertyValue(IRawElementProviderSimple *iface, + PROPERTYID property_id, VARIANT *ret_val) +{ + HwndProvider *This = impl_from_HwndProvider(iface); + + switch (property_id) + { + case UIA_NativeWindowHandlePropertyId: + V_VT(ret_val) = VT_I4; + V_I4(ret_val) = ((long)This->hwnd); + break; + + case UIA_ProviderDescriptionPropertyId: + V_VT(ret_val) = VT_BSTR; + V_BSTR(ret_val) = SysAllocString(L"Wine: HWND Provider Proxy"); + break; + + default: + V_VT(ret_val) = VT_EMPTY; + break; + } + + return S_OK; +} + +HRESULT WINAPI HwndProvider_get_HostRawElementProvider(IRawElementProviderSimple *iface, + IRawElementProviderSimple **ret_val) +{ + *ret_val = NULL; + return S_OK; +} + +IRawElementProviderSimpleVtbl HwndProviderVtbl = { + HwndProvider_QueryInterface, + HwndProvider_AddRef, + HwndProvider_Release, + HwndProvider_get_ProviderOptions, + HwndProvider_GetPatternProvider, + HwndProvider_GetPropertyValue, + HwndProvider_get_HostRawElementProvider, +}; + HRESULT WINAPI UiaHostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **provider) { - FIXME("(%p, %p): stub\n", hwnd, provider); - return E_NOTIMPL; + HwndProvider *hwnd_prov; + + TRACE("(%p, %p)\n", hwnd, provider); + + *provider = NULL; + if (!IsWindow(hwnd)) + return E_INVALIDARG; + + hwnd_prov = heap_alloc_zero(sizeof(*hwnd_prov)); + if (!hwnd_prov) + return E_OUTOFMEMORY; + + hwnd_prov->IRawElementProviderSimple_iface.lpVtbl = &HwndProviderVtbl; + hwnd_prov->ref = 1; + hwnd_prov->hwnd = hwnd; + *provider = &hwnd_prov->IRawElementProviderSimple_iface; + + return S_OK; }
HRESULT WINAPI UiaDisconnectProvider(IRawElementProviderSimple *provider)
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/Makefile.in | 2 +- dlls/uiautomationcore/tests/uiautomation.c | 57 +++++++++++++++++++--- 2 files changed, 51 insertions(+), 8 deletions(-)
diff --git a/dlls/uiautomationcore/tests/Makefile.in b/dlls/uiautomationcore/tests/Makefile.in index c39b062b6fd..d780b9feaf2 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 oleaut32
C_SRCS = \ uiautomation.c diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index cbcba1af294..4ebd3eac33b 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -34,9 +34,12 @@ static LRESULT WINAPI test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPAR static void test_UiaHostProviderFromHwnd(void) { IRawElementProviderSimple *p, *p2; + enum ProviderOptions prov_opt; + unsigned int i; WNDCLASSA cls; HRESULT hr; HWND hwnd; + VARIANT v;
cls.style = 0; cls.lpfnWndProc = test_wnd_proc; @@ -58,17 +61,13 @@ static void test_UiaHostProviderFromHwnd(void)
p = (void *)0xdeadbeef; hr = UiaHostProviderFromHwnd(NULL, &p); -todo_wine { ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); ok(p == NULL, "Unexpected instance.\n"); -} p = NULL; + hr = UiaHostProviderFromHwnd(hwnd, &p); -todo_wine ok(hr == S_OK, "Failed to get host provider, hr %#x.\n", hr);
-if (hr == S_OK) -{ p2 = NULL; hr = UiaHostProviderFromHwnd(hwnd, &p2); ok(hr == S_OK, "Failed to get host provider, hr %#x.\n", hr); @@ -79,10 +78,54 @@ if (hr == S_OK) ok(hr == S_OK, "Unexpected hr %#x.\n", hr); ok(p2 == NULL, "Unexpected instance.\n");
- IRawElementProviderSimple_Release(p); -} + hr = IRawElementProviderSimple_GetPropertyValue(p, UIA_NativeWindowHandlePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(V_VT(&v) == VT_I4, "V_VT(&v) = %d\n", V_VT(&v)); + ok(V_I4(&v) == (INT)hwnd, "V_I4(&v) = %#x\n", V_I4(&v));
+ hr = IRawElementProviderSimple_GetPropertyValue(p, UIA_ProviderDescriptionPropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(V_VT(&v) == VT_BSTR, "V_VT(&v) = %d\n", V_VT(&v)); + SysFreeString(V_BSTR(&v)); + + /* No patterns are implemented on the HWND provider. */ + for (i = 10000; i < 10034; i++) + { + IUnknown *unk; + + unk = NULL; + hr = IRawElementProviderSimple_GetPatternProvider(p, i, &unk); + ok(hr == S_OK, "Unexpected hr %#x, %d.\n", hr, i); + ok(!unk, "Pattern %d returned %p\n", i, unk); + } + + hr = IRawElementProviderSimple_get_ProviderOptions(p, &prov_opt); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok((prov_opt == ProviderOptions_ServerSideProvider) || + broken(prov_opt == ProviderOptions_ClientSideProvider), /* Windows < 10 1507 */ + "Unexpected provider options %#x\n", prov_opt); + + /* Test behavior post Window destruction. */ DestroyWindow(hwnd); + + hr = IRawElementProviderSimple_GetPropertyValue(p, UIA_NativeWindowHandlePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(V_VT(&v) == VT_I4, "V_VT(&v) = %d\n", V_VT(&v)); + ok(V_I4(&v) == (INT)hwnd, "V_I4(&v) = %#x\n", V_I4(&v)); + + hr = IRawElementProviderSimple_GetPropertyValue(p, UIA_ProviderDescriptionPropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(V_VT(&v) == VT_BSTR, "V_VT(&v) = %d\n", V_VT(&v)); + SysFreeString(V_BSTR(&v)); + + hr = IRawElementProviderSimple_get_ProviderOptions(p, &prov_opt); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok((prov_opt == ProviderOptions_ServerSideProvider) || + broken(prov_opt == ProviderOptions_ClientSideProvider), /* Windows < 10 1507 */ + "Unexpected provider options %#x\n", prov_opt); + + IRawElementProviderSimple_Release(p); + UnregisterClassA("HostProviderFromHwnd class", NULL); }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=98382
Your paranoid android.
=== debiant2 (32 bit report) ===
uiautomationcore: uiautomation.c:62: Test succeeded inside todo block: Unexpected hr 0x80070057. uiautomation.c:63: Test succeeded inside todo block: Unexpected instance. uiautomation.c:68: Test succeeded inside todo block: Failed to get host provider, hr 0.
=== debiant2 (32 bit Chinese:China report) ===
uiautomationcore: uiautomation.c:62: Test succeeded inside todo block: Unexpected hr 0x80070057. uiautomation.c:63: Test succeeded inside todo block: Unexpected instance. uiautomation.c:68: Test succeeded inside todo block: Failed to get host provider, hr 0.
=== debiant2 (32 bit WoW report) ===
uiautomationcore: uiautomation.c:62: Test succeeded inside todo block: Unexpected hr 0x80070057. uiautomation.c:63: Test succeeded inside todo block: Unexpected instance. uiautomation.c:68: Test succeeded inside todo block: Failed to get host provider, hr 0.
=== debiant2 (64 bit WoW report) ===
uiautomationcore: uiautomation.c:62: Test succeeded inside todo block: Unexpected hr 0x80070057. uiautomation.c:63: Test succeeded inside todo block: Unexpected instance. uiautomation.c:68: Test succeeded inside todo block: Failed to get host provider, hr 0.