From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/uia_classes.idl | 1 + dlls/uiautomationcore/uia_client.c | 130 +++++++++++++++++++- dlls/uiautomationcore/uiautomationcore.spec | 2 +- include/uiautomationcoreapi.h | 1 + 4 files changed, 132 insertions(+), 2 deletions(-)
diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index 030606cec93..e2889901fbb 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -55,5 +55,6 @@ library UIA_wine_private interface IWineUiaNode : IUnknown { HRESULT get_provider([out, retval]IWineUiaProvider **out_prov); + HRESULT get_prop_val([in]const GUID *prop_guid, [out, retval]VARIANT *ret_val); } } diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index c1fb880c9f1..193bad60230 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -354,11 +354,32 @@ static HRESULT WINAPI uia_node_get_provider(IWineUiaNode *iface, IWineUiaProvide return S_OK; }
+static HRESULT WINAPI uia_node_get_prop_val(IWineUiaNode *iface, const GUID *prop_guid, + VARIANT *ret_val) +{ + int prop_id = UiaLookupId(AutomationIdentifierType_Property, prop_guid); + HRESULT hr; + VARIANT v; + + TRACE("%p, %s, %p\n", iface, debugstr_guid(prop_guid), ret_val); + + hr = UiaGetPropertyValue((HUIANODE)iface, prop_id, &v); + + /* VT_UNKNOWN is UiaGetReservedNotSupported value, no need to marshal it. */ + if (V_VT(&v) == VT_UNKNOWN) + V_VT(ret_val) = VT_EMPTY; + else + *ret_val = v; + + return hr; +} + static const IWineUiaNodeVtbl uia_node_vtbl = { uia_node_QueryInterface, uia_node_AddRef, uia_node_Release, uia_node_get_provider, + uia_node_get_prop_val, };
static struct uia_node *unsafe_impl_from_IWineUiaNode(IWineUiaNode *iface) @@ -377,6 +398,7 @@ struct uia_provider { LONG ref;
IRawElementProviderSimple *elprov; + IWineUiaNode *node; };
static inline struct uia_provider *impl_from_IWineUiaProvider(IWineUiaProvider *iface) @@ -413,7 +435,10 @@ static ULONG WINAPI uia_provider_Release(IWineUiaProvider *iface) TRACE("%p, refcount %ld\n", prov, ref); if (!ref) { - IRawElementProviderSimple_Release(prov->elprov); + if (prov->node) + IWineUiaNode_Release(prov->node); + else + IRawElementProviderSimple_Release(prov->elprov); heap_free(prov); }
@@ -625,6 +650,18 @@ static HRESULT WINAPI uia_provider_get_prop_val(IWineUiaProvider *iface,
TRACE("%p, %p, %p\n", iface, prop_info, ret_val);
+ VariantInit(ret_val); + if (prov->node) + { + if (prop_info->type == UIAutomationType_Element || prop_info->type == UIAutomationType_ElementArray) + { + FIXME("Element property types currently unsupported for nested nodes.\n"); + return E_NOTIMPL; + } + + return IWineUiaNode_get_prop_val(prov->node, prop_info->guid, ret_val); + } + switch (prop_info->prop_type) { case PROP_TYPE_ELEM_PROP: @@ -735,6 +772,97 @@ HRESULT WINAPI UiaNodeFromProvider(IRawElementProviderSimple *elprov, HUIANODE * return hr; }
+static HRESULT create_wine_uia_nested_node_provider(struct uia_node *node, LRESULT lr) +{ + IGlobalInterfaceTable *git; + struct uia_provider *prov; + IWineUiaNode *nested_node; + HRESULT hr; + + hr = ObjectFromLresult(lr, &IID_IWineUiaNode, 0, (void **)&nested_node); + if (FAILED(hr)) + return hr; + + prov = heap_alloc_zero(sizeof(*prov)); + if (!prov) + return E_OUTOFMEMORY; + + prov->IWineUiaProvider_iface.lpVtbl = &uia_provider_vtbl; + prov->node = nested_node; + prov->ref = 1; + node->prov = &prov->IWineUiaProvider_iface; + + /* + * We need to use the GIT on all nested node providers so that our + * IWineUiaNode proxy is used in the correct apartment. + */ + hr = get_global_interface_table(&git); + if (FAILED(hr)) + goto exit; + + hr = IGlobalInterfaceTable_RegisterInterfaceInGlobal(git, (IUnknown *)&prov->IWineUiaProvider_iface, + &IID_IWineUiaProvider, &node->git_cookie); +exit: + if (FAILED(hr)) + IWineUiaProvider_Release(&prov->IWineUiaProvider_iface); + + return hr; +} + +static HRESULT uia_get_provider_from_hwnd(struct uia_node *node) +{ + LRESULT lr; + + lr = SendMessageW(node->hwnd, WM_GETOBJECT, 0, UiaRootObjectId); + if (!lr) + { + if (!IsWindow(node->hwnd) && GetLastError() == ERROR_INVALID_WINDOW_HANDLE) + return UIA_E_ELEMENTNOTAVAILABLE; + FIXME("No native UIA provider for hwnd %p, MSAA proxy currently unimplemented.\n", node->hwnd); + return E_NOTIMPL; + } + + return create_wine_uia_nested_node_provider(node, lr); +} + +/*********************************************************************** + * UiaNodeFromHandle (uiautomationcore.@) + */ +HRESULT WINAPI UiaNodeFromHandle(HWND hwnd, HUIANODE *huianode) +{ + struct uia_node *node; + HRESULT hr; + + TRACE("(%p, %p)\n", hwnd, huianode); + + if (!huianode) + return E_INVALIDARG; + + *huianode = NULL; + + if (!IsWindow(hwnd)) + return UIA_E_ELEMENTNOTAVAILABLE; + + node = heap_alloc_zero(sizeof(*node)); + if (!node) + return E_OUTOFMEMORY; + + node->hwnd = hwnd; + node->IWineUiaNode_iface.lpVtbl = &uia_node_vtbl; + node->ref = 1; + + hr = uia_get_provider_from_hwnd(node); + if (FAILED(hr) || !node->prov) + { + heap_free(node); + return hr; + } + + *huianode = (void *)&node->IWineUiaNode_iface; + + return S_OK; +} + /*********************************************************************** * UiaNodeRelease (uiautomationcore.@) */ diff --git a/dlls/uiautomationcore/uiautomationcore.spec b/dlls/uiautomationcore/uiautomationcore.spec index f4e745a644a..03a747219ed 100644 --- a/dlls/uiautomationcore/uiautomationcore.spec +++ b/dlls/uiautomationcore/uiautomationcore.spec @@ -77,7 +77,7 @@ @ stdcall UiaLookupId(long ptr) @ stub UiaNavigate @ stub UiaNodeFromFocus -@ stub UiaNodeFromHandle +@ stdcall UiaNodeFromHandle(long ptr) @ stub UiaNodeFromPoint @ stdcall UiaNodeFromProvider(ptr ptr) @ stdcall UiaNodeRelease(ptr) diff --git a/include/uiautomationcoreapi.h b/include/uiautomationcoreapi.h index 946c8b0fadc..b4814b9e857 100644 --- a/include/uiautomationcoreapi.h +++ b/include/uiautomationcoreapi.h @@ -397,6 +397,7 @@ HRESULT WINAPI UiaNodeFromProvider(IRawElementProviderSimple *elprov, HUIANODE * BOOL WINAPI UiaNodeRelease(HUIANODE huianode); HRESULT WINAPI UiaGetRuntimeId(HUIANODE huianode, SAFEARRAY **runtime_id); HRESULT WINAPI UiaHUiaNodeFromVariant(VARIANT *in_val, HUIANODE *huianode); +HRESULT WINAPI UiaNodeFromHandle(HWND hwnd, HUIANODE *huianode);
#ifdef __cplusplus }