Commit 12dfa742 authored by Connor McAdams's avatar Connor McAdams Committed by Alexandre Julliard

uiautomationcore: Implement get_HostRawElementProvider for MSAA providers.

parent de280569
......@@ -23,9 +23,12 @@
#include "wine/debug.h"
#include "wine/heap.h"
#include "initguid.h"
WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
DEFINE_GUID(SID_AccFromDAWrapper, 0x33f139ee, 0xe509, 0x47f7, 0xbf,0x39, 0x83,0x76,0x44,0xf7,0x45,0x76);
static void variant_init_i4(VARIANT *v, int val)
{
V_VT(v) = VT_I4;
......@@ -51,6 +54,157 @@ static BOOL msaa_check_acc_state(IAccessible *acc, VARIANT cid, ULONG flag)
return FALSE;
}
static IAccessible *msaa_acc_da_unwrap(IAccessible *acc)
{
IServiceProvider *sp;
IAccessible *acc2;
HRESULT hr;
hr = IAccessible_QueryInterface(acc, &IID_IServiceProvider, (void**)&sp);
if (SUCCEEDED(hr))
{
hr = IServiceProvider_QueryService(sp, &SID_AccFromDAWrapper, &IID_IAccessible, (void**)&acc2);
IServiceProvider_Release(sp);
}
if (SUCCEEDED(hr) && acc2)
return acc2;
IAccessible_AddRef(acc);
return acc;
}
/*
* Compare role, state, child count, and location properties of the two
* IAccessibles. If all four are successfully retrieved and are equal, this is
* considered a match.
*/
static HRESULT msaa_acc_prop_match(IAccessible *acc, IAccessible *acc2)
{
BOOL role_match, state_match, child_count_match, location_match;
LONG child_count[2], left[2], top[2], width[2], height[2];
VARIANT cid, v, v2;
HRESULT hr, hr2;
role_match = state_match = child_count_match = location_match = FALSE;
variant_init_i4(&cid, CHILDID_SELF);
hr = IAccessible_get_accRole(acc, cid, &v);
if (SUCCEEDED(hr) && (V_VT(&v) == VT_I4))
{
VariantInit(&v2);
hr = IAccessible_get_accRole(acc2, cid, &v2);
if (SUCCEEDED(hr) && (V_VT(&v2) == VT_I4))
{
if (V_I4(&v) != V_I4(&v2))
return E_FAIL;
role_match = TRUE;
}
}
VariantInit(&v);
hr = IAccessible_get_accState(acc, cid, &v);
if (SUCCEEDED(hr) && (V_VT(&v) == VT_I4))
{
VariantInit(&v2);
hr = IAccessible_get_accState(acc2, cid, &v2);
if (SUCCEEDED(hr) && (V_VT(&v2) == VT_I4))
{
if (V_I4(&v) != V_I4(&v2))
return E_FAIL;
state_match = TRUE;
}
}
hr = IAccessible_get_accChildCount(acc, &child_count[0]);
hr2 = IAccessible_get_accChildCount(acc2, &child_count[1]);
if (SUCCEEDED(hr) && SUCCEEDED(hr2))
{
if (child_count[0] != child_count[1])
return E_FAIL;
child_count_match = TRUE;
}
hr = IAccessible_accLocation(acc, &left[0], &top[0], &width[0], &height[0], cid);
if (SUCCEEDED(hr))
{
hr = IAccessible_accLocation(acc2, &left[1], &top[1], &width[1], &height[1], cid);
if (SUCCEEDED(hr))
{
if ((left[0] != left[1]) || (top[0] != top[1]) || (width[0] != width[1]) ||
(height[0] != height[1]))
return E_FAIL;
location_match = TRUE;
}
}
if (role_match && state_match && child_count_match && location_match)
return S_OK;
return S_FALSE;
}
static BOOL msaa_acc_compare(IAccessible *acc, IAccessible *acc2)
{
IUnknown *unk, *unk2;
BOOL matched = FALSE;
BSTR name[2];
VARIANT cid;
HRESULT hr;
acc = msaa_acc_da_unwrap(acc);
acc2 = msaa_acc_da_unwrap(acc2);
IAccessible_QueryInterface(acc, &IID_IUnknown, (void**)&unk);
IAccessible_QueryInterface(acc2, &IID_IUnknown, (void**)&unk2);
if (unk == unk2)
{
matched = TRUE;
goto exit;
}
hr = msaa_acc_prop_match(acc, acc2);
if (FAILED(hr))
goto exit;
if (hr == S_OK)
matched = TRUE;
variant_init_i4(&cid, CHILDID_SELF);
hr = IAccessible_get_accName(acc, cid, &name[0]);
if (SUCCEEDED(hr))
{
hr = IAccessible_get_accName(acc2, cid, &name[1]);
if (SUCCEEDED(hr))
{
if (!name[0] && !name[1])
matched = TRUE;
else if (!name[0] || !name[1])
matched = FALSE;
else
{
if (!wcscmp(name[0], name[1]))
matched = TRUE;
else
matched = FALSE;
}
SysFreeString(name[1]);
}
SysFreeString(name[0]);
}
exit:
IUnknown_Release(unk);
IUnknown_Release(unk2);
IAccessible_Release(acc);
IAccessible_Release(acc2);
return matched;
}
static LONG msaa_role_to_uia_control_type(LONG role)
{
switch (role)
......@@ -141,8 +295,34 @@ struct msaa_provider {
VARIANT cid;
HWND hwnd;
LONG control_type;
BOOL root_acc_check_ran;
BOOL is_root_acc;
};
static BOOL msaa_check_root_acc(struct msaa_provider *msaa_prov)
{
IAccessible *acc;
HRESULT hr;
if (msaa_prov->root_acc_check_ran)
return msaa_prov->is_root_acc;
msaa_prov->root_acc_check_ran = TRUE;
if (V_I4(&msaa_prov->cid) != CHILDID_SELF)
return FALSE;
hr = AccessibleObjectFromWindow(msaa_prov->hwnd, OBJID_CLIENT, &IID_IAccessible, (void **)&acc);
if (FAILED(hr))
return FALSE;
if (msaa_acc_compare(msaa_prov->acc, acc))
msaa_prov->is_root_acc = TRUE;
IAccessible_Release(acc);
return msaa_prov->is_root_acc;
}
static inline struct msaa_provider *impl_from_msaa_provider(IRawElementProviderSimple *iface)
{
return CONTAINING_RECORD(iface, struct msaa_provider, IRawElementProviderSimple_iface);
......@@ -264,9 +444,15 @@ HRESULT WINAPI msaa_provider_GetPropertyValue(IRawElementProviderSimple *iface,
HRESULT WINAPI msaa_provider_get_HostRawElementProvider(IRawElementProviderSimple *iface,
IRawElementProviderSimple **ret_val)
{
FIXME("%p, %p: stub!\n", iface, ret_val);
struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
TRACE("%p, %p\n", iface, ret_val);
*ret_val = NULL;
return E_NOTIMPL;
if (msaa_check_root_acc(msaa_prov))
return UiaHostProviderFromHwnd(msaa_prov->hwnd, ret_val);
return S_OK;
}
static const IRawElementProviderSimpleVtbl msaa_provider_vtbl = {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment