Commit 890faf87 authored by Connor McAdams's avatar Connor McAdams Committed by Alexandre Julliard

uiautomationcore: Implement UiaDisconnectProvider.

parent 858e9a4c
......@@ -56,5 +56,6 @@ library UIA_wine_private
{
HRESULT get_provider([out, retval]IWineUiaProvider **out_prov);
HRESULT get_prop_val([in]const GUID *prop_guid, [out, retval]VARIANT *ret_val);
HRESULT disconnect();
}
}
......@@ -49,6 +49,54 @@ static HRESULT get_safearray_bounds(SAFEARRAY *sa, LONG *lbound, LONG *elems)
return S_OK;
}
int uia_compare_runtime_ids(SAFEARRAY *sa1, SAFEARRAY *sa2)
{
LONG i, idx, lbound[2], elems[2];
int val[2];
HRESULT hr;
hr = get_safearray_bounds(sa1, &lbound[0], &elems[0]);
if (FAILED(hr))
{
ERR("Failed to get safearray bounds from sa1 with hr %#lx\n", hr);
return -1;
}
hr = get_safearray_bounds(sa2, &lbound[1], &elems[1]);
if (FAILED(hr))
{
ERR("Failed to get safearray bounds from sa2 with hr %#lx\n", hr);
return -1;
}
if (elems[0] != elems[1])
return (elems[0] > elems[1]) - (elems[0] < elems[1]);
for (i = 0; i < elems[0]; i++)
{
idx = lbound[0] + i;
hr = SafeArrayGetElement(sa1, &idx, &val[0]);
if (FAILED(hr))
{
ERR("Failed to get element from sa1 with hr %#lx\n", hr);
return -1;
}
idx = lbound[1] + i;
hr = SafeArrayGetElement(sa2, &idx, &val[1]);
if (FAILED(hr))
{
ERR("Failed to get element from sa2 with hr %#lx\n", hr);
return -1;
}
if (val[0] != val[1])
return (val[0] > val[1]) - (val[0] < val[1]);
}
return 0;
}
static void clear_uia_node_ptr_safearray(SAFEARRAY *sa, LONG elems)
{
HUIANODE node;
......@@ -312,7 +360,8 @@ static ULONG WINAPI uia_node_Release(IWineUiaNode *iface)
}
}
IWineUiaProvider_Release(node->prov);
if (node->prov)
IWineUiaProvider_Release(node->prov);
if (!list_empty(&node->prov_thread_list_entry))
uia_provider_thread_remove_node((HUIANODE)iface);
if (node->nested_node)
......@@ -328,6 +377,12 @@ static HRESULT WINAPI uia_node_get_provider(IWineUiaNode *iface, IWineUiaProvide
{
struct uia_node *node = impl_from_IWineUiaNode(iface);
if (node->disconnected)
{
*out_prov = NULL;
return UIA_E_ELEMENTNOTAVAILABLE;
}
if (node->git_cookie)
{
IGlobalInterfaceTable *git;
......@@ -360,11 +415,18 @@ static HRESULT WINAPI uia_node_get_prop_val(IWineUiaNode *iface, const GUID *pro
VARIANT *ret_val)
{
int prop_id = UiaLookupId(AutomationIdentifierType_Property, prop_guid);
struct uia_node *node = impl_from_IWineUiaNode(iface);
HRESULT hr;
VARIANT v;
TRACE("%p, %s, %p\n", iface, debugstr_guid(prop_guid), ret_val);
if (node->disconnected)
{
VariantInit(ret_val);
return UIA_E_ELEMENTNOTAVAILABLE;
}
hr = UiaGetPropertyValue((HUIANODE)iface, prop_id, &v);
/* VT_UNKNOWN is UiaGetReservedNotSupported value, no need to marshal it. */
......@@ -376,12 +438,47 @@ static HRESULT WINAPI uia_node_get_prop_val(IWineUiaNode *iface, const GUID *pro
return hr;
}
static HRESULT WINAPI uia_node_disconnect(IWineUiaNode *iface)
{
struct uia_node *node = impl_from_IWineUiaNode(iface);
TRACE("%p\n", node);
if (node->disconnected)
{
ERR("Attempted to disconnect node which was already disconnected.\n");
return E_FAIL;
}
if (node->git_cookie)
{
IGlobalInterfaceTable *git;
HRESULT hr;
hr = get_global_interface_table(&git);
if (SUCCEEDED(hr))
{
hr = IGlobalInterfaceTable_RevokeInterfaceFromGlobal(git, node->git_cookie);
if (FAILED(hr))
WARN("Failed to get revoke provider interface from Global Interface Table, hr %#lx\n", hr);
}
node->git_cookie = 0;
}
IWineUiaProvider_Release(node->prov);
node->prov = NULL;
node->disconnected = TRUE;
return S_OK;
}
static const IWineUiaNodeVtbl uia_node_vtbl = {
uia_node_QueryInterface,
uia_node_AddRef,
uia_node_Release,
uia_node_get_provider,
uia_node_get_prop_val,
uia_node_disconnect,
};
static struct uia_node *unsafe_impl_from_IWineUiaNode(IWineUiaNode *iface)
......
......@@ -346,12 +346,6 @@ HRESULT WINAPI UiaHostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **pr
return S_OK;
}
HRESULT WINAPI UiaDisconnectProvider(IRawElementProviderSimple *provider)
{
FIXME("(%p): stub\n", provider);
return E_NOTIMPL;
}
/***********************************************************************
* DllMain (uiautomationcore.@)
*/
......
......@@ -39,6 +39,9 @@ struct uia_node {
HWND hwnd;
BOOL nested_node;
BOOL disconnected;
/* This RuntimeId is used as a comparison for UiaDisconnectProvider(). */
SAFEARRAY *runtime_id;
struct list prov_thread_list_entry;
};
......@@ -47,6 +50,9 @@ static inline struct uia_node *impl_from_IWineUiaNode(IWineUiaNode *iface)
return CONTAINING_RECORD(iface, struct uia_node, IWineUiaNode_iface);
}
/* uia_client.c */
int uia_compare_runtime_ids(SAFEARRAY *sa1, SAFEARRAY *sa2) DECLSPEC_HIDDEN;
/* uia_ids.c */
const struct uia_prop_info *uia_prop_info_from_id(PROPERTYID prop_id) DECLSPEC_HIDDEN;
......
......@@ -1155,18 +1155,58 @@ void uia_provider_thread_remove_node(HUIANODE node)
EnterCriticalSection(&provider_thread_cs);
list_remove(&node_data->prov_thread_list_entry);
list_init(&node_data->prov_thread_list_entry);
SafeArrayDestroy(node_data->runtime_id);
node_data->runtime_id = NULL;
LeaveCriticalSection(&provider_thread_cs);
}
static void uia_provider_thread_disconnect_node(SAFEARRAY *sa)
{
struct list *cursor, *cursor2;
struct uia_node *node_data;
EnterCriticalSection(&provider_thread_cs);
/* Provider thread hasn't been started, no nodes to disconnect. */
if (!provider_thread.ref)
goto exit;
LIST_FOR_EACH_SAFE(cursor, cursor2, &provider_thread.nodes_list)
{
node_data = LIST_ENTRY(cursor, struct uia_node, prov_thread_list_entry);
if (node_data->runtime_id)
{
if (!uia_compare_runtime_ids(sa, node_data->runtime_id))
{
list_remove(cursor);
list_init(&node_data->prov_thread_list_entry);
IWineUiaNode_disconnect(&node_data->IWineUiaNode_iface);
SafeArrayDestroy(node_data->runtime_id);
node_data->runtime_id = NULL;
}
}
}
exit:
LeaveCriticalSection(&provider_thread_cs);
}
static HRESULT uia_provider_thread_add_node(HUIANODE node)
{
struct uia_node *node_data = impl_from_IWineUiaNode((IWineUiaNode *)node);
TRACE("Adding node %p\n", node);
SAFEARRAY *sa;
HRESULT hr;
node_data->nested_node = TRUE;
hr = UiaGetRuntimeId(node, &sa);
if (FAILED(hr))
return hr;
TRACE("Adding node %p\n", node);
EnterCriticalSection(&provider_thread_cs);
node_data->runtime_id = sa;
list_add_tail(&provider_thread.nodes_list, &node_data->prov_thread_list_entry);
LeaveCriticalSection(&provider_thread_cs);
......@@ -1363,3 +1403,33 @@ LRESULT WINAPI UiaReturnRawElementProvider(HWND hwnd, WPARAM wparam,
return uia_lresult_from_node(node);
}
/***********************************************************************
* UiaDisconnectProvider (uiautomationcore.@)
*/
HRESULT WINAPI UiaDisconnectProvider(IRawElementProviderSimple *elprov)
{
SAFEARRAY *sa;
HUIANODE node;
HRESULT hr;
TRACE("(%p)\n", elprov);
hr = UiaNodeFromProvider(elprov, &node);
if (FAILED(hr))
return hr;
hr = UiaGetRuntimeId(node, &sa);
UiaNodeRelease(node);
if (FAILED(hr))
return hr;
if (!sa)
return E_INVALIDARG;
uia_provider_thread_disconnect_node(sa);
SafeArrayDestroy(sa);
return S_OK;
}
......@@ -398,6 +398,7 @@ 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);
HRESULT WINAPI UiaDisconnectProvider(IRawElementProviderSimple *elprov);
#ifdef __cplusplus
}
......
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