uiautomationcore: Shutdown provider thread when all returned nodes are released.

Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
Connor McAdams 2022-09-12 11:42:20 -04:00 committed by Alexandre Julliard
parent d7c95765d0
commit 858596bbd5
3 changed files with 44 additions and 16 deletions

View file

@ -269,21 +269,6 @@ static IRawElementProviderSimple *get_provider_hwnd_fragment_root(IRawElementPro
/*
* IWineUiaNode interface.
*/
struct uia_node {
IWineUiaNode IWineUiaNode_iface;
LONG ref;
IWineUiaProvider *prov;
DWORD git_cookie;
HWND hwnd;
};
static inline struct uia_node *impl_from_IWineUiaNode(IWineUiaNode *iface)
{
return CONTAINING_RECORD(iface, struct uia_node, IWineUiaNode_iface);
}
static HRESULT WINAPI uia_node_QueryInterface(IWineUiaNode *iface, REFIID riid, void **ppv)
{
*ppv = NULL;
@ -328,6 +313,9 @@ static ULONG WINAPI uia_node_Release(IWineUiaNode *iface)
}
IWineUiaProvider_Release(node->prov);
if (node->nested_node)
uia_stop_provider_thread();
heap_free(node);
}

View file

@ -29,4 +29,24 @@ enum uia_prop_type {
PROP_TYPE_SPECIAL,
};
struct uia_node {
IWineUiaNode IWineUiaNode_iface;
LONG ref;
IWineUiaProvider *prov;
DWORD git_cookie;
HWND hwnd;
BOOL nested_node;
};
static inline struct uia_node *impl_from_IWineUiaNode(IWineUiaNode *iface)
{
return CONTAINING_RECORD(iface, struct uia_node, IWineUiaNode_iface);
}
/* uia_ids.c */
const struct uia_prop_info *uia_prop_info_from_id(PROPERTYID prop_id) DECLSPEC_HIDDEN;
/* uia_provider.c */
void uia_stop_provider_thread(void) DECLSPEC_HIDDEN;

View file

@ -1132,6 +1132,7 @@ struct uia_provider_thread
{
HANDLE hthread;
HWND hwnd;
LONG ref;
};
static struct uia_provider_thread provider_thread;
@ -1145,6 +1146,7 @@ static CRITICAL_SECTION_DEBUG provider_thread_cs_debug =
static CRITICAL_SECTION provider_thread_cs = { &provider_thread_cs_debug, -1, 0, 0, 0, 0 };
#define WM_GET_OBJECT_UIA_NODE (WM_USER + 1)
#define WM_UIA_PROVIDER_THREAD_STOP (WM_USER + 2)
static LRESULT CALLBACK uia_provider_thread_msg_proc(HWND hwnd, UINT msg, WPARAM wparam,
LPARAM lparam)
{
@ -1153,8 +1155,12 @@ static LRESULT CALLBACK uia_provider_thread_msg_proc(HWND hwnd, UINT msg, WPARAM
case WM_GET_OBJECT_UIA_NODE:
{
HUIANODE node = (HUIANODE)lparam;
struct uia_node *node_data;
LRESULT lr;
node_data = impl_from_IWineUiaNode((IWineUiaNode *)node);
node_data->nested_node = TRUE;
/*
* LresultFromObject returns an index into the global atom string table,
* which has a valid range of 0xc000-0xffff.
@ -1204,6 +1210,8 @@ static DWORD WINAPI uia_provider_thread_proc(void *arg)
TRACE("Provider thread started.\n");
while (GetMessageW(&msg, NULL, 0, 0))
{
if (msg.message == WM_UIA_PROVIDER_THREAD_STOP)
break;
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
@ -1220,7 +1228,7 @@ static BOOL uia_start_provider_thread(void)
BOOL started = TRUE;
EnterCriticalSection(&provider_thread_cs);
if (!provider_thread.hwnd)
if (++provider_thread.ref == 1)
{
HANDLE ready_event;
HANDLE events[2];
@ -1261,6 +1269,18 @@ exit:
return started;
}
void uia_stop_provider_thread(void)
{
EnterCriticalSection(&provider_thread_cs);
if (!--provider_thread.ref)
{
PostMessageW(provider_thread.hwnd, WM_UIA_PROVIDER_THREAD_STOP, 0, 0);
CloseHandle(provider_thread.hthread);
memset(&provider_thread, 0, sizeof(provider_thread));
}
LeaveCriticalSection(&provider_thread_cs);
}
/*
* Pass our IWineUiaNode interface to the provider thread for marshaling. UI
* Automation has to work regardless of whether or not COM is initialized on