uiautomationcore: Implement UiaRegisterProviderCallback.

Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
Connor McAdams 2022-10-13 12:45:57 -04:00 committed by Alexandre Julliard
parent 59589e1196
commit 329664392e
3 changed files with 987 additions and 12 deletions

View file

@ -68,7 +68,12 @@ static HRESULT (WINAPI *pUiaDisconnectProvider)(IRawElementProviderSimple *);
#define UIA_RUNTIME_ID_PREFIX 42
DEFINE_EXPECT(winproc_GETOBJECT_CLIENT);
DEFINE_EXPECT(prov_callback_base_hwnd);
DEFINE_EXPECT(prov_callback_nonclient);
DEFINE_EXPECT(prov_callback_proxy);
DEFINE_EXPECT(prov_callback_parent_proxy);
DEFINE_EXPECT(winproc_GETOBJECT_UiaRoot);
DEFINE_EXPECT(child_winproc_GETOBJECT_UiaRoot);
DEFINE_EXPECT(Accessible_accNavigate);
DEFINE_EXPECT(Accessible_get_accParent);
DEFINE_EXPECT(Accessible_get_accChildCount);
@ -1097,6 +1102,7 @@ static struct Provider
IRawElementProviderSimple IRawElementProviderSimple_iface;
IRawElementProviderFragment IRawElementProviderFragment_iface;
IRawElementProviderFragmentRoot IRawElementProviderFragmentRoot_iface;
IRawElementProviderHwndOverride IRawElementProviderHwndOverride_iface;
LONG ref;
const char *prov_name;
@ -1109,7 +1115,9 @@ static struct Provider
int runtime_id[2];
DWORD last_call_tid;
BOOL ignore_hwnd_prop;
HWND override_hwnd;
} Provider, Provider2, Provider_child, Provider_child2;
static struct Provider Provider_hwnd, Provider_nc, Provider_proxy, Provider_proxy2, Provider_override;
static const WCHAR *uia_bstr_prop_str = L"uia-string";
static const ULONG uia_i4_prop_val = 0xdeadbeef;
@ -1167,6 +1175,7 @@ enum {
FRAG_NAVIGATE,
FRAG_GET_RUNTIME_ID,
FRAG_GET_FRAGMENT_ROOT,
HWND_OVERRIDE_GET_OVERRIDE_PROVIDER,
};
static const char *prov_method_str[] = {
@ -1176,6 +1185,7 @@ static const char *prov_method_str[] = {
"Navigate",
"GetRuntimeId",
"get_FragmentRoot",
"GetOverrideProviderForHwnd",
};
static const char *get_prov_method_str(int method)
@ -1491,6 +1501,8 @@ HRESULT WINAPI ProviderSimple_QueryInterface(IRawElementProviderSimple *iface, R
*ppv = &This->IRawElementProviderFragment_iface;
else if (IsEqualIID(riid, &IID_IRawElementProviderFragmentRoot))
*ppv = &This->IRawElementProviderFragmentRoot_iface;
else if (IsEqualIID(riid, &IID_IRawElementProviderHwndOverride))
*ppv = &This->IRawElementProviderHwndOverride_iface;
else
return E_NOINTERFACE;
@ -1924,11 +1936,60 @@ static const IRawElementProviderFragmentRootVtbl ProviderFragmentRootVtbl = {
ProviderFragmentRoot_GetFocus,
};
static inline struct Provider *impl_from_ProviderHwndOverride(IRawElementProviderHwndOverride *iface)
{
return CONTAINING_RECORD(iface, struct Provider, IRawElementProviderHwndOverride_iface);
}
static HRESULT WINAPI ProviderHwndOverride_QueryInterface(IRawElementProviderHwndOverride *iface, REFIID riid,
void **ppv)
{
struct Provider *Provider = impl_from_ProviderHwndOverride(iface);
return IRawElementProviderSimple_QueryInterface(&Provider->IRawElementProviderSimple_iface, riid, ppv);
}
static ULONG WINAPI ProviderHwndOverride_AddRef(IRawElementProviderHwndOverride *iface)
{
struct Provider *Provider = impl_from_ProviderHwndOverride(iface);
return IRawElementProviderSimple_AddRef(&Provider->IRawElementProviderSimple_iface);
}
static ULONG WINAPI ProviderHwndOverride_Release(IRawElementProviderHwndOverride *iface)
{
struct Provider *Provider = impl_from_ProviderHwndOverride(iface);
return IRawElementProviderSimple_Release(&Provider->IRawElementProviderSimple_iface);
}
static HRESULT WINAPI ProviderHwndOverride_GetOverrideProviderForHwnd(IRawElementProviderHwndOverride *iface,
HWND hwnd, IRawElementProviderSimple **ret_val)
{
struct Provider *This = impl_from_ProviderHwndOverride(iface);
add_method_call(This, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER);
*ret_val = NULL;
if (This->override_hwnd == hwnd)
{
return IRawElementProviderSimple_QueryInterface(&Provider_override.IRawElementProviderSimple_iface,
&IID_IRawElementProviderSimple, (void **)ret_val);
}
return S_OK;
}
static const IRawElementProviderHwndOverrideVtbl ProviderHwndOverrideVtbl = {
ProviderHwndOverride_QueryInterface,
ProviderHwndOverride_AddRef,
ProviderHwndOverride_Release,
ProviderHwndOverride_GetOverrideProviderForHwnd,
};
static struct Provider Provider =
{
{ &ProviderSimpleVtbl },
{ &ProviderFragmentVtbl },
{ &ProviderFragmentRootVtbl },
{ &ProviderHwndOverrideVtbl },
1,
"Provider",
NULL, NULL,
@ -1940,6 +2001,7 @@ static struct Provider Provider2 =
{ &ProviderSimpleVtbl },
{ &ProviderFragmentVtbl },
{ &ProviderFragmentRootVtbl },
{ &ProviderHwndOverrideVtbl },
1,
"Provider2",
NULL, NULL,
@ -1951,6 +2013,7 @@ static struct Provider Provider_child =
{ &ProviderSimpleVtbl },
{ &ProviderFragmentVtbl },
{ &ProviderFragmentRootVtbl },
{ &ProviderHwndOverrideVtbl },
1,
"Provider_child",
&Provider.IRawElementProviderFragment_iface, &Provider.IRawElementProviderFragmentRoot_iface,
@ -1962,12 +2025,77 @@ static struct Provider Provider_child2 =
{ &ProviderSimpleVtbl },
{ &ProviderFragmentVtbl },
{ &ProviderFragmentRootVtbl },
{ &ProviderHwndOverrideVtbl },
1,
"Provider_child2",
&Provider.IRawElementProviderFragment_iface, &Provider.IRawElementProviderFragmentRoot_iface,
ProviderOptions_ServerSideProvider, 0, 0,
};
static struct Provider Provider_hwnd =
{
{ &ProviderSimpleVtbl },
{ &ProviderFragmentVtbl },
{ &ProviderFragmentRootVtbl },
{ &ProviderHwndOverrideVtbl },
1,
"Provider_hwnd",
NULL, NULL,
ProviderOptions_ClientSideProvider, 0, 0,
};
static struct Provider Provider_nc =
{
{ &ProviderSimpleVtbl },
{ &ProviderFragmentVtbl },
{ &ProviderFragmentRootVtbl },
{ &ProviderHwndOverrideVtbl },
1,
"Provider_nc",
NULL, NULL,
ProviderOptions_ClientSideProvider | ProviderOptions_NonClientAreaProvider,
0, 0,
};
static struct Provider Provider_proxy =
{
{ &ProviderSimpleVtbl },
{ &ProviderFragmentVtbl },
{ &ProviderFragmentRootVtbl },
{ &ProviderHwndOverrideVtbl },
1,
"Provider_proxy",
NULL, NULL,
ProviderOptions_ClientSideProvider,
0, 0,
};
static struct Provider Provider_proxy2 =
{
{ &ProviderSimpleVtbl },
{ &ProviderFragmentVtbl },
{ &ProviderFragmentRootVtbl },
{ &ProviderHwndOverrideVtbl },
1,
"Provider_proxy2",
NULL, NULL,
ProviderOptions_ClientSideProvider,
0, 0,
};
static struct Provider Provider_override =
{
{ &ProviderSimpleVtbl },
{ &ProviderFragmentVtbl },
{ &ProviderFragmentRootVtbl },
{ &ProviderHwndOverrideVtbl },
1,
"Provider_override",
NULL, NULL,
ProviderOptions_ServerSideProvider | ProviderOptions_OverrideProvider,
0, 0,
};
static IAccessible *acc_client;
static IRawElementProviderSimple *prov_root;
static LRESULT WINAPI test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
@ -2001,6 +2129,30 @@ static LRESULT WINAPI test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPAR
return DefWindowProcA(hwnd, message, wParam, lParam);
}
static IRawElementProviderSimple *child_win_prov_root;
static LRESULT WINAPI child_test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_GETOBJECT:
if (lParam == UiaRootObjectId)
{
CHECK_EXPECT(child_winproc_GETOBJECT_UiaRoot);
if (child_win_prov_root)
return UiaReturnRawElementProvider(hwnd, wParam, lParam, child_win_prov_root);
break;
}
break;
default:
break;
}
return DefWindowProcA(hwnd, message, wParam, lParam);
}
static void test_UiaHostProviderFromHwnd(void)
{
IRawElementProviderSimple *p, *p2;
@ -5829,6 +5981,696 @@ static void test_UiaNodeFromHandle(const char *name)
prov_root = NULL;
}
static const struct prov_method_sequence reg_prov_cb1[] = {
{ &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10+. */
{ &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */
{ 0 }
};
static const struct prov_method_sequence reg_prov_cb2[] = {
/* These two are only done on Win10v1809+. */
{ &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL },
{ &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */
{ &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10+. */
{ &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */
{ 0 }
};
static const struct prov_method_sequence reg_prov_cb3[] = {
{ &Provider_proxy2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_TODO },
/* These two are only done on Win10v1809+. */
{ &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL },
{ &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */
{ &Provider_proxy, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
/* These three only done on Win10+. */
{ &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider_proxy, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */
{ &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */
{ &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */
{ 0 }
};
static const struct prov_method_sequence reg_prov_cb4[] = {
{ &Provider_proxy2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_TODO },
/* These two are only done on Win10v1809+. */
{ &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL },
{ &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */
{ &Provider_override, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider_proxy, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
/* These four only done on Win10+. */
{ &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */
{ &Provider_proxy, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */
{ &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */
{ &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */
{ 0 }
};
static const struct prov_method_sequence reg_prov_cb5[] = {
{ &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ControlTypePropertyId */
{ 0 }
};
static const struct prov_method_sequence reg_prov_cb6[] = {
{ &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ControlTypePropertyId */
{ &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */
{ &Provider_proxy, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */
{ 0 }
};
static const struct prov_method_sequence reg_prov_cb7[] = {
{ &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ControlTypePropertyId */
{ &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */
{ &Provider_proxy, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */
{ &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */
{ &Provider_nc, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */
{ 0 }
};
static const struct prov_method_sequence reg_prov_cb8[] = {
{ &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ControlTypePropertyId */
{ &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */
{ &Provider_proxy, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */
{ &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */
{ &Provider_nc, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */
{ &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */
{ &Provider_hwnd, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */
{ 0 }
};
static const struct prov_method_sequence reg_prov_cb9[] = {
{ &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ControlTypePropertyId */
{ &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */
{ &Provider_proxy, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */
{ &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */
{ &Provider_nc, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */
{ &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */
{ &Provider_hwnd, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */
{ &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */
{ 0 }
};
static const struct prov_method_sequence reg_prov_cb10[] = {
{ &Provider_proxy2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_TODO },
/* These two are only done on Win10v1809+. */
{ &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL },
{ &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */
{ &Provider_override, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider_proxy, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
/* These four only done on Win10+. */
{ &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ 0 }
};
static const struct prov_method_sequence reg_prov_cb11[] = {
{ &Provider, PROV_GET_PROVIDER_OPTIONS },
/* Win10v1507 and below call this. */
{ &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */
{ &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER },
{ &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider, PROV_GET_PROVIDER_OPTIONS },
{ &Provider, PROV_GET_PROVIDER_OPTIONS },
{ &Provider_proxy2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_TODO },
/* These two are only done on Win10v1809+. */
{ &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL },
{ &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */
{ &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
/* These three only done on Win10+. */
{ &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */
{ &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */
{ &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */
{ 0 }
};
static const struct prov_method_sequence reg_prov_cb12[] = {
{ &Provider, PROV_GET_PROVIDER_OPTIONS },
/* Win10v1507 and below call this. */
{ &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */
{ &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER },
{ &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider, PROV_GET_PROVIDER_OPTIONS },
{ &Provider, PROV_GET_PROVIDER_OPTIONS },
{ &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO },
/* Win10v1507 and below call this. */
{ &Provider2, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */
{ &Provider2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO },
{ &Provider2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO },
{ &Provider2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_OPTIONAL }, /* Only done on Win10v1809+ */
{ &Provider_proxy2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_TODO },
/* These two are only done on Win10v1809+. */
{ &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL },
{ &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */
{ &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
/* These three only done on Win10+. */
{ &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */
{ &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */
{ &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */
{ 0 }
};
static const struct prov_method_sequence reg_prov_cb13[] = {
{ &Provider, PROV_GET_PROVIDER_OPTIONS },
/* Win10v1507 and below call this. */
{ &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */
{ &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER },
{ &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider, PROV_GET_PROVIDER_OPTIONS },
{ &Provider, PROV_GET_PROVIDER_OPTIONS },
{ &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO },
/* Win10v1507 and below call this. */
{ &Provider2, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */
{ &Provider2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO },
{ &Provider2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO },
{ &Provider2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_OPTIONAL }, /* Only done on Win10v1809+ */
/* Provider override only retrieved successfully on Win10v1809+ */
{ &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider_override, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL },
{ &Provider_override, FRAG_NAVIGATE, METHOD_OPTIONAL }, /* NavigateDirection_Parent */
{ &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider_proxy2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_OPTIONAL }, /* Only done on Win10v1507 and below. */
/* These two are only done on Win10v1809+. */
{ &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL },
{ &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */
/* Only done on Win10v1809+. */
{ &Provider_override, FRAG_NAVIGATE, METHOD_OPTIONAL }, /* NavigateDirection_Parent */
{ &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */
{ &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+ */
/* These three only done on Win10+. */
{ &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
/* Only done on Win10v1809+. */
{ &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_ProviderDescriptionPropertyId */
{ &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */
{ &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */
{ &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */
{ 0 }
};
static IRawElementProviderSimple *base_hwnd_prov, *proxy_prov, *parent_proxy_prov, *nc_prov;
static SAFEARRAY WINAPI *test_uia_provider_callback(HWND hwnd, enum ProviderType prov_type)
{
IRawElementProviderSimple *elprov = NULL;
switch (prov_type)
{
case ProviderType_BaseHwnd:
CHECK_EXPECT(prov_callback_base_hwnd);
elprov = base_hwnd_prov;
break;
case ProviderType_Proxy:
if (Provider_proxy.hwnd == hwnd)
{
CHECK_EXPECT(prov_callback_proxy);
elprov = proxy_prov;
}
else if (hwnd == GetParent(Provider_proxy.hwnd))
{
CHECK_EXPECT(prov_callback_parent_proxy);
elprov = parent_proxy_prov;
}
break;
case ProviderType_NonClientArea:
CHECK_EXPECT(prov_callback_nonclient);
elprov = nc_prov;
break;
default:
break;
}
if (elprov)
{
SAFEARRAY *sa;
LONG idx = 0;
sa = SafeArrayCreateVector(VT_UNKNOWN, 0, 1);
if (sa)
SafeArrayPutElement(sa, &idx, (void *)elprov);
return sa;
}
return NULL;
}
static void test_UiaRegisterProviderCallback(void)
{
HWND hwnd, hwnd2;
WNDCLASSA cls;
HUIANODE node;
HRESULT hr;
VARIANT v;
cls.style = 0;
cls.lpfnWndProc = test_wnd_proc;
cls.cbClsExtra = 0;
cls.cbWndExtra = 0;
cls.hInstance = GetModuleHandleA(NULL);
cls.hIcon = 0;
cls.hCursor = NULL;
cls.hbrBackground = NULL;
cls.lpszMenuName = NULL;
cls.lpszClassName = "UiaRegisterProviderCallback class";
RegisterClassA(&cls);
cls.lpfnWndProc = child_test_wnd_proc;
cls.lpszClassName = "UiaRegisterProviderCallback child class";
RegisterClassA(&cls);
hwnd = CreateWindowA("UiaRegisterProviderCallback class", "Test window", WS_OVERLAPPEDWINDOW,
0, 0, 100, 100, NULL, NULL, NULL, NULL);
hwnd2 = CreateWindowA("UiaRegisterProviderCallback child class", "Test child window", WS_CHILD,
0, 0, 100, 100, hwnd, NULL, NULL, NULL);
UiaRegisterProviderCallback(test_uia_provider_callback);
/* No providers returned by UiaRootObjectId or the provider callback. */
Provider_proxy.hwnd = hwnd2;
child_win_prov_root = prov_root = NULL;
node = (void *)0xdeadbeef;
SET_EXPECT(winproc_GETOBJECT_UiaRoot);
SET_EXPECT(child_winproc_GETOBJECT_UiaRoot);
SET_EXPECT(prov_callback_base_hwnd);
SET_EXPECT(prov_callback_nonclient);
SET_EXPECT(prov_callback_proxy);
SET_EXPECT(prov_callback_parent_proxy);
hr = UiaNodeFromHandle(hwnd2, &node);
/* Windows 7 returns S_OK with a NULL HUIANODE. */
ok(hr == E_FAIL || broken(hr == S_OK), "Unexpected hr %#lx.\n", hr);
ok(!node, "node != NULL\n");
todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(prov_callback_base_hwnd);
CHECK_CALLED(prov_callback_nonclient);
CHECK_CALLED(prov_callback_proxy);
todo_wine CHECK_CALLED(prov_callback_parent_proxy);
/* Return only nonclient proxy provider. */
base_hwnd_prov = proxy_prov = parent_proxy_prov = NULL;
nc_prov = &Provider_nc.IRawElementProviderSimple_iface;
child_win_prov_root = prov_root = NULL;
node = (void *)0xdeadbeef;
SET_EXPECT(winproc_GETOBJECT_UiaRoot);
SET_EXPECT(child_winproc_GETOBJECT_UiaRoot);
SET_EXPECT(prov_callback_base_hwnd);
SET_EXPECT(prov_callback_nonclient);
SET_EXPECT(prov_callback_proxy);
SET_EXPECT(prov_callback_parent_proxy);
hr = UiaNodeFromHandle(hwnd2, &node);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(Provider_nc.ref == 2, "Unexpected refcnt %ld\n", Provider_nc.ref);
ok(!!node, "node == NULL\n");
todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(prov_callback_base_hwnd);
CHECK_CALLED(prov_callback_nonclient);
CHECK_CALLED(prov_callback_proxy);
todo_wine CHECK_CALLED(prov_callback_parent_proxy);
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
if (SUCCEEDED(hr))
{
check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2);
check_node_provider_desc(V_BSTR(&v), L"Nonclient", L"Provider_nc", TRUE);
VariantClear(&v);
}
ok_method_sequence(reg_prov_cb1, "reg_prov_cb1");
UiaNodeRelease(node);
ok(Provider_nc.ref == 1, "Unexpected refcnt %ld\n", Provider_nc.ref);
/* Return only base_hwnd provider. */
nc_prov = proxy_prov = parent_proxy_prov = NULL;
base_hwnd_prov = &Provider_hwnd.IRawElementProviderSimple_iface;
child_win_prov_root = prov_root = NULL;
node = (void *)0xdeadbeef;
SET_EXPECT(winproc_GETOBJECT_UiaRoot);
SET_EXPECT(child_winproc_GETOBJECT_UiaRoot);
SET_EXPECT(prov_callback_base_hwnd);
SET_EXPECT(prov_callback_nonclient);
SET_EXPECT(prov_callback_proxy);
SET_EXPECT(prov_callback_parent_proxy);
hr = UiaNodeFromHandle(hwnd2, &node);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(Provider_hwnd.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd.ref);
ok(!!node, "node == NULL\n");
todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(prov_callback_base_hwnd);
CHECK_CALLED(prov_callback_nonclient);
CHECK_CALLED(prov_callback_proxy);
todo_wine CHECK_CALLED(prov_callback_parent_proxy);
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
if (SUCCEEDED(hr))
{
check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2);
check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider_hwnd", TRUE);
VariantClear(&v);
}
ok_method_sequence(reg_prov_cb2, "reg_prov_cb2");
UiaNodeRelease(node);
ok(Provider_hwnd.ref == 1, "Unexpected refcnt %ld\n", Provider_hwnd.ref);
/* Return providers for all ProviderTypes. */
base_hwnd_prov = &Provider_hwnd.IRawElementProviderSimple_iface;
proxy_prov = &Provider_proxy.IRawElementProviderSimple_iface;
parent_proxy_prov = &Provider_proxy2.IRawElementProviderSimple_iface;
nc_prov = &Provider_nc.IRawElementProviderSimple_iface;
Provider_proxy.hwnd = hwnd2;
child_win_prov_root = prov_root = NULL;
node = (void *)0xdeadbeef;
SET_EXPECT(winproc_GETOBJECT_UiaRoot);
SET_EXPECT(child_winproc_GETOBJECT_UiaRoot);
SET_EXPECT(prov_callback_base_hwnd);
SET_EXPECT(prov_callback_nonclient);
SET_EXPECT(prov_callback_proxy);
SET_EXPECT(prov_callback_parent_proxy);
hr = UiaNodeFromHandle(hwnd2, &node);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!!node, "node == NULL\n");
ok(Provider_proxy.ref == 2, "Unexpected refcnt %ld\n", Provider_proxy.ref);
ok(Provider_proxy2.ref == 1, "Unexpected refcnt %ld\n", Provider_proxy2.ref);
ok(Provider_nc.ref == 2, "Unexpected refcnt %ld\n", Provider_nc.ref);
ok(Provider_hwnd.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd.ref);
todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(prov_callback_base_hwnd);
CHECK_CALLED(prov_callback_nonclient);
CHECK_CALLED(prov_callback_proxy);
todo_wine CHECK_CALLED(prov_callback_parent_proxy);
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
if (SUCCEEDED(hr))
{
check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2);
check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider_proxy", TRUE);
check_node_provider_desc(V_BSTR(&v), L"Nonclient", L"Provider_nc", FALSE);
check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider_hwnd", FALSE);
VariantClear(&v);
}
ok_method_sequence(reg_prov_cb3, "reg_prov_cb3");
UiaNodeRelease(node);
ok(Provider_proxy.ref == 1, "Unexpected refcnt %ld\n", Provider_proxy.ref);
ok(Provider_nc.ref == 1, "Unexpected refcnt %ld\n", Provider_nc.ref);
ok(Provider_hwnd.ref == 1, "Unexpected refcnt %ld\n", Provider_hwnd.ref);
/* Return an override provider from Provider_proxy2. */
base_hwnd_prov = &Provider_hwnd.IRawElementProviderSimple_iface;
proxy_prov = &Provider_proxy.IRawElementProviderSimple_iface;
parent_proxy_prov = &Provider_proxy2.IRawElementProviderSimple_iface;
nc_prov = &Provider_nc.IRawElementProviderSimple_iface;
Provider_proxy2.override_hwnd = hwnd2;
child_win_prov_root = prov_root = NULL;
node = (void *)0xdeadbeef;
SET_EXPECT(winproc_GETOBJECT_UiaRoot);
SET_EXPECT(child_winproc_GETOBJECT_UiaRoot);
SET_EXPECT(prov_callback_base_hwnd);
SET_EXPECT(prov_callback_nonclient);
SET_EXPECT(prov_callback_proxy);
SET_EXPECT(prov_callback_parent_proxy);
hr = UiaNodeFromHandle(hwnd2, &node);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!!node, "node == NULL\n");
ok(Provider_proxy.ref == 2, "Unexpected refcnt %ld\n", Provider_proxy.ref);
ok(Provider_proxy2.ref == 1, "Unexpected refcnt %ld\n", Provider_proxy2.ref);
ok(Provider_nc.ref == 2, "Unexpected refcnt %ld\n", Provider_nc.ref);
ok(Provider_hwnd.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd.ref);
todo_wine ok(Provider_override.ref == 2, "Unexpected refcnt %ld\n", Provider_override.ref);
todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(prov_callback_base_hwnd);
CHECK_CALLED(prov_callback_nonclient);
CHECK_CALLED(prov_callback_proxy);
todo_wine CHECK_CALLED(prov_callback_parent_proxy);
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
if (SUCCEEDED(hr))
{
check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2);
check_node_provider_desc(V_BSTR(&v), L"Override", L"Provider_override", TRUE);
check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider_proxy", FALSE);
check_node_provider_desc(V_BSTR(&v), L"Nonclient", L"Provider_nc", FALSE);
check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider_hwnd", FALSE);
VariantClear(&v);
}
ok_method_sequence(reg_prov_cb4, "reg_prov_cb4");
/*
* Test the order that Providers are queried for properties. The order is:
* Override provider.
* Main provider.
* Nonclient provider.
* Hwnd provider.
*
* UI Automation tries to get a property from each in this order until one
* returns a value. If none do, the property isn't supported.
*/
if (Provider_override.ref == 2)
{
hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
ok(V_VT(&v) == VT_I4, "Unexpected vt %d\n", V_VT(&v));
ok(V_I4(&v) == uia_i4_prop_val, "Unexpected I4 %#lx\n", V_I4(&v));
ok_method_sequence(reg_prov_cb5, "reg_prov_cb5");
}
/* Property retrieved from Provider_proxy (Main) */
Provider_override.ret_invalid_prop_type = TRUE;
hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
ok(V_VT(&v) == VT_I4, "Unexpected vt %d\n", V_VT(&v));
ok(V_I4(&v) == uia_i4_prop_val, "Unexpected I4 %#lx\n", V_I4(&v));
ok_method_sequence(reg_prov_cb6, "reg_prov_cb6");
/* Property retrieved from Provider_nc (Nonclient) */
Provider_override.ret_invalid_prop_type = Provider_proxy.ret_invalid_prop_type = TRUE;
hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
ok(V_VT(&v) == VT_I4, "Unexpected vt %d\n", V_VT(&v));
ok(V_I4(&v) == uia_i4_prop_val, "Unexpected I4 %#lx\n", V_I4(&v));
ok_method_sequence(reg_prov_cb7, "reg_prov_cb7");
/* Property retrieved from Provider_hwnd (Hwnd) */
Provider_override.ret_invalid_prop_type = Provider_proxy.ret_invalid_prop_type = TRUE;
Provider_nc.ret_invalid_prop_type = TRUE;
hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
ok(V_VT(&v) == VT_I4, "Unexpected vt %d\n", V_VT(&v));
ok(V_I4(&v) == uia_i4_prop_val, "Unexpected I4 %#lx\n", V_I4(&v));
ok_method_sequence(reg_prov_cb8, "reg_prov_cb8");
/* Property retrieved from none of the providers. */
Provider_override.ret_invalid_prop_type = Provider_proxy.ret_invalid_prop_type = TRUE;
Provider_nc.ret_invalid_prop_type = Provider_hwnd.ret_invalid_prop_type = TRUE;
hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
ok(V_VT(&v) == VT_UNKNOWN, "Unexpected vt %d\n", V_VT(&v));
ok_method_sequence(reg_prov_cb9, "reg_prov_cb9");
UiaNodeRelease(node);
ok(Provider_proxy.ref == 1, "Unexpected refcnt %ld\n", Provider_proxy.ref);
ok(Provider_nc.ref == 1, "Unexpected refcnt %ld\n", Provider_nc.ref);
ok(Provider_hwnd.ref == 1, "Unexpected refcnt %ld\n", Provider_hwnd.ref);
ok(Provider_override.ref == 1, "Unexpected refcnt %ld\n", Provider_override.ref);
Provider_override.ret_invalid_prop_type = Provider_proxy.ret_invalid_prop_type = FALSE;
Provider_nc.ret_invalid_prop_type = Provider_hwnd.ret_invalid_prop_type = FALSE;
/*
* Provider_hwnd has ProviderOptions_UseComThreading, and COM hasn't been
* initialized. One provider failing will cause the entire node to fail
* creation on Win10+.
*/
Provider_hwnd.prov_opts = ProviderOptions_ClientSideProvider | ProviderOptions_UseComThreading;
node = (void *)0xdeadbeef;
SET_EXPECT(winproc_GETOBJECT_UiaRoot);
SET_EXPECT(child_winproc_GETOBJECT_UiaRoot);
SET_EXPECT(prov_callback_base_hwnd);
SET_EXPECT(prov_callback_nonclient);
SET_EXPECT(prov_callback_proxy);
SET_EXPECT(prov_callback_parent_proxy);
hr = UiaNodeFromHandle(hwnd2, &node);
ok(hr == CO_E_NOTINITIALIZED || broken(hr == S_OK), "Unexpected hr %#lx.\n", hr);
ok(!node || broken(!!node), "node != NULL\n");
todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(prov_callback_base_hwnd);
CHECK_CALLED(prov_callback_nonclient);
CHECK_CALLED(prov_callback_proxy);
todo_wine CHECK_CALLED(prov_callback_parent_proxy);
ok_method_sequence(reg_prov_cb10, "reg_prov_cb10");
UiaNodeRelease(node);
Provider_hwnd.prov_opts = ProviderOptions_ClientSideProvider;
/*
* Provider returned by UiaRootObjectId on hwnd2. No ProviderType_Proxy
* callback for hwnd2.
*/
Provider.hwnd = hwnd2;
Provider.prov_opts = ProviderOptions_ServerSideProvider;
child_win_prov_root = &Provider.IRawElementProviderSimple_iface;
Provider_proxy2.override_hwnd = NULL;
SET_EXPECT(winproc_GETOBJECT_UiaRoot);
SET_EXPECT(child_winproc_GETOBJECT_UiaRoot);
SET_EXPECT(prov_callback_base_hwnd);
SET_EXPECT(prov_callback_nonclient);
SET_EXPECT(prov_callback_parent_proxy);
hr = UiaNodeFromHandle(hwnd2, &node);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref);
todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(prov_callback_base_hwnd);
CHECK_CALLED(prov_callback_nonclient);
todo_wine CHECK_CALLED(prov_callback_parent_proxy);
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
if (SUCCEEDED(hr))
{
check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2);
check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", TRUE);
check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider_hwnd", FALSE);
check_node_provider_desc(V_BSTR(&v), L"Nonclient", L"Provider_nc", FALSE);
VariantClear(&v);
}
ok_method_sequence(reg_prov_cb11, "reg_prov_cb11");
UiaNodeRelease(node);
/*
* Provider returned by UiaRootObjectId on both HWNDs. Since Provider2
* doesn't give an HWND override provider, UIA will attempt to get a proxy
* provider to check it for an HWND override provider.
*/
Provider.hwnd = hwnd2;
Provider2.hwnd = hwnd;
Provider.prov_opts = Provider2.prov_opts = ProviderOptions_ServerSideProvider;
child_win_prov_root = &Provider.IRawElementProviderSimple_iface;
prov_root = &Provider2.IRawElementProviderSimple_iface;
Provider_proxy2.override_hwnd = NULL;
SET_EXPECT(winproc_GETOBJECT_UiaRoot);
SET_EXPECT(child_winproc_GETOBJECT_UiaRoot);
SET_EXPECT(prov_callback_base_hwnd);
SET_EXPECT(prov_callback_nonclient);
SET_EXPECT(prov_callback_parent_proxy);
hr = UiaNodeFromHandle(hwnd2, &node);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref);
todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(prov_callback_base_hwnd);
CHECK_CALLED(prov_callback_nonclient);
todo_wine CHECK_CALLED(prov_callback_parent_proxy);
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
if (SUCCEEDED(hr))
{
check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2);
check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", TRUE);
check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider_hwnd", FALSE);
check_node_provider_desc(V_BSTR(&v), L"Nonclient", L"Provider_nc", FALSE);
VariantClear(&v);
}
ok_method_sequence(reg_prov_cb12, "reg_prov_cb12");
UiaNodeRelease(node);
/*
* Provider returned by UiaRootObjectId on both HWNDs. Since Provider2
* returns an HWND override, no ProviderType_Proxy callback for hwnd.
*/
Provider.hwnd = hwnd2;
Provider2.hwnd = hwnd;
Provider2.override_hwnd = Provider_override.hwnd = hwnd2;
Provider2.ignore_hwnd_prop = Provider_override.ignore_hwnd_prop = TRUE;
Provider.prov_opts = Provider2.prov_opts = ProviderOptions_ServerSideProvider;
child_win_prov_root = &Provider.IRawElementProviderSimple_iface;
prov_root = &Provider2.IRawElementProviderSimple_iface;
Provider_proxy2.override_hwnd = NULL;
SET_EXPECT(winproc_GETOBJECT_UiaRoot);
SET_EXPECT(child_winproc_GETOBJECT_UiaRoot);
SET_EXPECT(prov_callback_base_hwnd);
SET_EXPECT(prov_callback_nonclient);
SET_EXPECT(prov_callback_parent_proxy);
hr = UiaNodeFromHandle(hwnd2, &node);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref);
todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(prov_callback_base_hwnd);
CHECK_CALLED(prov_callback_nonclient);
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
if (SUCCEEDED(hr))
{
check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2);
check_node_provider_desc(V_BSTR(&v), L"Override", L"Provider_override", TRUE);
check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", FALSE);
check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider_hwnd", FALSE);
check_node_provider_desc(V_BSTR(&v), L"Nonclient", L"Provider_nc", FALSE);
VariantClear(&v);
}
ok_method_sequence(reg_prov_cb13, "reg_prov_cb13");
UiaNodeRelease(node);
Provider2.ignore_hwnd_prop = Provider_override.ignore_hwnd_prop = FALSE;
UiaRegisterProviderCallback(NULL);
DestroyWindow(hwnd);
UnregisterClassA("UiaRegisterProviderCallback class", NULL);
UnregisterClassA("UiaRegisterProviderCallback child class", NULL);
}
/*
* Once a process returns a UI Automation provider with
* UiaReturnRawElementProvider it ends up in an implicit MTA until exit. This
@ -5876,6 +6718,8 @@ START_TEST(uiautomation)
test_UiaNodeFromHandle(argv[0]);
else if (!strcmp(argv[2], "UiaNodeFromHandle_client_proc"))
test_UiaNodeFromHandle_client_proc();
else if (!strcmp(argv[2], "UiaRegisterProviderCallback"))
test_UiaRegisterProviderCallback();
FreeLibrary(uia_dll);
return;
@ -5889,6 +6733,7 @@ START_TEST(uiautomation)
test_UiaGetRuntimeId();
test_UiaHUiaNodeFromVariant();
launch_test_process(argv[0], "UiaNodeFromHandle");
launch_test_process(argv[0], "UiaRegisterProviderCallback");
if (uia_dll)
{
pUiaProviderFromIAccessible = (void *)GetProcAddress(uia_dll, "UiaProviderFromIAccessible");

View file

@ -909,7 +909,7 @@ static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProvid
return S_OK;
}
static HRESULT uia_get_provider_from_hwnd(struct uia_node *node);
static HRESULT uia_get_providers_for_hwnd(struct uia_node *node);
HRESULT create_uia_node_from_elprov(IRawElementProviderSimple *elprov, HUIANODE *out_node,
BOOL get_hwnd_providers)
{
@ -958,7 +958,11 @@ HRESULT create_uia_node_from_elprov(IRawElementProviderSimple *elprov, HUIANODE
}
if (node->hwnd && get_hwnd_providers)
uia_get_provider_from_hwnd(node);
{
hr = uia_get_providers_for_hwnd(node);
if (FAILED(hr))
WARN("uia_get_providers_for_hwnd failed with hr %#lx\n", hr);
}
hr = prepare_uia_node(node);
if (FAILED(hr))
@ -1406,9 +1410,9 @@ static HRESULT uia_node_from_lresult(LRESULT lr, HUIANODE *huianode)
if (node->hwnd)
{
hr = uia_get_provider_from_hwnd(node);
hr = uia_get_providers_for_hwnd(node);
if (FAILED(hr))
WARN("uia_get_provider_from_hwnd failed with hr %#lx\n", hr);
WARN("uia_get_providers_for_hwnd failed with hr %#lx\n", hr);
}
hr = prepare_uia_node(node);
@ -1445,9 +1449,8 @@ static HRESULT uia_get_provider_from_hwnd(struct uia_node *node)
if (!args.lr)
{
FIXME("No native UIA provider for hwnd %p, MSAA proxy currently unimplemented.\n", node->hwnd);
uia_stop_client_thread();
return E_NOTIMPL;
return S_FALSE;
}
args.unwrap = GetCurrentThreadId() == GetWindowThreadProcessId(node->hwnd, NULL);
@ -1482,7 +1485,7 @@ HRESULT WINAPI UiaNodeFromHandle(HWND hwnd, HUIANODE *huianode)
list_init(&node->node_map_list_entry);
node->ref = 1;
hr = uia_get_provider_from_hwnd(node);
hr = uia_get_providers_for_hwnd(node);
if (FAILED(hr))
{
heap_free(node);
@ -1776,3 +1779,135 @@ HRESULT WINAPI UiaHUiaNodeFromVariant(VARIANT *in_val, HUIANODE *huianode)
return S_OK;
}
static SAFEARRAY WINAPI *default_uia_provider_callback(HWND hwnd, enum ProviderType prov_type)
{
switch (prov_type)
{
case ProviderType_Proxy:
FIXME("Default ProviderType_Proxy MSAA provider unimplemented.\n");
break;
case ProviderType_NonClientArea:
FIXME("Default ProviderType_NonClientArea provider unimplemented.\n");
break;
case ProviderType_BaseHwnd:
FIXME("Default ProviderType_BaseHwnd provider unimplemented.\n");
break;
default:
break;
}
return NULL;
}
static UiaProviderCallback *uia_provider_callback = default_uia_provider_callback;
static HRESULT uia_get_clientside_provider(struct uia_node *node, int prov_type,
int node_prov_type)
{
IRawElementProviderSimple *elprov;
LONG lbound, elems;
SAFEARRAY *sa;
IUnknown *unk;
VARTYPE vt;
HRESULT hr;
if (!(sa = uia_provider_callback(node->hwnd, prov_type)))
return S_OK;
hr = SafeArrayGetVartype(sa, &vt);
if (FAILED(hr) || (vt != VT_UNKNOWN))
goto exit;
hr = get_safearray_bounds(sa, &lbound, &elems);
if (FAILED(hr))
goto exit;
/* Returned SAFEARRAY can only have 1 element. */
if (elems != 1)
{
WARN("Invalid element count %ld for returned SAFEARRAY\n", elems);
goto exit;
}
hr = SafeArrayGetElement(sa, &lbound, &unk);
if (FAILED(hr))
goto exit;
hr = IUnknown_QueryInterface(unk, &IID_IRawElementProviderSimple, (void **)&elprov);
IUnknown_Release(unk);
if (FAILED(hr) || !elprov)
{
WARN("Failed to get IRawElementProviderSimple from returned SAFEARRAY.\n");
hr = S_OK;
goto exit;
}
hr = create_wine_uia_provider(node, elprov, node_prov_type);
IRawElementProviderSimple_Release(elprov);
exit:
if (FAILED(hr))
WARN("Failed to get clientside provider, hr %#lx\n", hr);
SafeArrayDestroy(sa);
return hr;
}
static HRESULT uia_get_providers_for_hwnd(struct uia_node *node)
{
HRESULT hr;
hr = uia_get_provider_from_hwnd(node);
if (FAILED(hr))
return hr;
if (!node->prov[PROV_TYPE_MAIN])
{
hr = uia_get_clientside_provider(node, ProviderType_Proxy, PROV_TYPE_MAIN);
if (FAILED(hr))
return hr;
}
if (!node->prov[PROV_TYPE_OVERRIDE])
FIXME("Override provider callback currently unimplemented.\n");
if (!node->prov[PROV_TYPE_NONCLIENT])
{
hr = uia_get_clientside_provider(node, ProviderType_NonClientArea, PROV_TYPE_NONCLIENT);
if (FAILED(hr))
return hr;
}
if (!node->prov[PROV_TYPE_HWND])
{
hr = uia_get_clientside_provider(node, ProviderType_BaseHwnd, PROV_TYPE_HWND);
if (FAILED(hr))
return hr;
}
if (!node->prov_count)
{
if (uia_provider_callback == default_uia_provider_callback)
return E_NOTIMPL;
else
return E_FAIL;
}
return S_OK;
}
/***********************************************************************
* UiaRegisterProviderCallback (uiautomationcore.@)
*/
void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *callback)
{
TRACE("(%p)\n", callback);
if (callback)
uia_provider_callback = callback;
else
uia_provider_callback = default_uia_provider_callback;
}

View file

@ -317,11 +317,6 @@ HRESULT WINAPI UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple
return S_OK;
}
void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *callback)
{
FIXME("(%p): stub\n", callback);
}
HRESULT WINAPI UiaHostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **provider)
{
struct hwnd_host_provider *host_prov;