diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 13f481a670e..f7f16927b38 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -13952,11 +13952,11 @@ static void test_UiaAddEvent_client_proc(void) SET_EXPECT_MULTI(prov_callback_nonclient, 2); SET_EXPECT_MULTI(prov_callback_proxy, 3); hr = UiaEventAddWindow(event, hwnd); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine CHECK_CALLED(prov_callback_base_hwnd); - todo_wine CHECK_CALLED(prov_callback_nonclient); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); todo_wine CHECK_CALLED(prov_callback_proxy); - post_event_message(hwnd, WM_UIA_TEST_CHECK_EVENT_ADVISE_ADDED, UIA_AutomationFocusChangedEventId, PROVIDER_ID, TRUE); + post_event_message(hwnd, WM_UIA_TEST_CHECK_EVENT_ADVISE_ADDED, UIA_AutomationFocusChangedEventId, PROVIDER_ID, FALSE); /* Successfully raise event. */ GetWindowThreadProcessId(hwnd, &pid); @@ -14000,7 +14000,7 @@ static void test_UiaAddEvent_client_proc(void) hr = UiaRemoveEvent(event); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - post_event_message(hwnd, WM_UIA_TEST_CHECK_EVENT_ADVISE_REMOVED, UIA_AutomationFocusChangedEventId, PROVIDER_ID, TRUE); + post_event_message(hwnd, WM_UIA_TEST_CHECK_EVENT_ADVISE_REMOVED, UIA_AutomationFocusChangedEventId, PROVIDER_ID, FALSE); PostMessageW(hwnd, WM_UIA_TEST_RESET_EVENT_PROVIDERS, 0, 0); post_event_message(hwnd, WM_UIA_TEST_SET_EVENT_PROVIDER_DATA, HandleToUlong(hwnd), PROVIDER_ID, @@ -14093,9 +14093,9 @@ static void test_UiaAddEvent_client_proc(void) SET_EXPECT_MULTI(prov_callback_nonclient, 2); SET_EXPECT_MULTI(prov_callback_proxy, 3); hr = UiaEventAddWindow(event, hwnd); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine CHECK_CALLED(prov_callback_base_hwnd); - todo_wine CHECK_CALLED(prov_callback_nonclient); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); todo_wine CHECK_CALLED(prov_callback_proxy); /* Wrong runtime ID, no match. */ diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index 651df86d9d2..25417d6c549 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -72,7 +72,7 @@ library UIA_wine_private ] interface IWineUiaEvent : IUnknown { - HRESULT advise_events([in]BOOL advise_added); + HRESULT advise_events([in]BOOL advise_added, [in]long adviser_start_idx); HRESULT set_event_data([in]const GUID *event_guid, [in]long scope, [in]VARIANT runtime_id, [in]IWineUiaEvent *event_iface); } diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 6d468b68705..e5cdec27e0b 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -544,6 +544,7 @@ static HRESULT WINAPI uia_node_attach_event(IWineUiaNode *iface, long proc_id, l { struct uia_node *node = impl_from_IWineUiaNode(iface); struct uia_event *event = NULL; + int old_event_advisers_count; HRESULT hr; TRACE("%p, %ld, %ld, %p\n", node, proc_id, event_cookie, ret_event); @@ -557,6 +558,7 @@ static HRESULT WINAPI uia_node_attach_event(IWineUiaNode *iface, long proc_id, l if (hr == S_OK) *ret_event = &event->IWineUiaEvent_iface; + old_event_advisers_count = event->event_advisers_count; hr = attach_event_to_node_provider(iface, 0, (HUIAEVENT)event); if (FAILED(hr)) { @@ -575,6 +577,14 @@ static HRESULT WINAPI uia_node_attach_event(IWineUiaNode *iface, long proc_id, l event->u.serverside.node = iface; } + /* + * Pre-existing serverside event that has already had its initial + * advise call and gotten event data - if we've got new advisers, we need + * to advise them here. + */ + if (!(*ret_event) && event->event_id && (event->event_advisers_count != old_event_advisers_count)) + hr = IWineUiaEvent_advise_events(&event->IWineUiaEvent_iface, TRUE, old_event_advisers_count); + return hr; } @@ -3542,15 +3552,6 @@ exit: return hr; } -/*********************************************************************** - * UiaEventAddWindow (uiautomationcore.@) - */ -HRESULT WINAPI UiaEventAddWindow(HUIAEVENT huiaevent, HWND hwnd) -{ - FIXME("(%p, %p): stub\n", huiaevent, hwnd); - return E_NOTIMPL; -} - /*********************************************************************** * UiaEventRemoveWindow (uiautomationcore.@) */ diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c index 2cb2cff9ae2..dd3578e7bd5 100644 --- a/dlls/uiautomationcore/uia_event.c +++ b/dlls/uiautomationcore/uia_event.c @@ -272,15 +272,15 @@ static ULONG WINAPI uia_event_Release(IWineUiaEvent *iface) return ref; } -static HRESULT WINAPI uia_event_advise_events(IWineUiaEvent *iface, BOOL advise_added) +static HRESULT WINAPI uia_event_advise_events(IWineUiaEvent *iface, BOOL advise_added, long adviser_start_idx) { struct uia_event *event = impl_from_IWineUiaEvent(iface); HRESULT hr; int i; - TRACE("%p, %d\n", event, advise_added); + TRACE("%p, %d, %ld\n", event, advise_added, adviser_start_idx); - for (i = 0; i < event->event_advisers_count; i++) + for (i = adviser_start_idx; i < event->event_advisers_count; i++) { hr = IWineUiaEventAdviser_advise(event->event_advisers[i], advise_added, (UINT_PTR)event); if (FAILED(hr)) @@ -658,7 +658,7 @@ static HRESULT WINAPI uia_serverside_event_adviser_advise(IWineUiaEventAdviser * } } - return IWineUiaEvent_advise_events(adv_events->event_iface, advise_added); + return IWineUiaEvent_advise_events(adv_events->event_iface, advise_added, 0); } static const IWineUiaEventAdviserVtbl uia_serverside_event_adviser_vtbl = { @@ -706,6 +706,65 @@ HRESULT uia_event_add_serverside_event_adviser(IWineUiaEvent *serverside_event, return hr; } +static HRESULT uia_event_advise(struct uia_event *event, BOOL advise_added, long start_idx) +{ + IWineUiaEvent *event_iface; + HRESULT hr; + + if (event->u.clientside.git_cookie) + { + hr = get_interface_in_git(&IID_IWineUiaEvent, event->u.clientside.git_cookie, + (IUnknown **)&event_iface); + if (FAILED(hr)) + return hr; + } + else + { + event_iface = &event->IWineUiaEvent_iface; + IWineUiaEvent_AddRef(event_iface); + } + + hr = IWineUiaEvent_advise_events(event_iface, advise_added, start_idx); + IWineUiaEvent_Release(event_iface); + + return hr; +} + +/*********************************************************************** + * UiaEventAddWindow (uiautomationcore.@) + */ +HRESULT WINAPI UiaEventAddWindow(HUIAEVENT huiaevent, HWND hwnd) +{ + struct uia_event *event = unsafe_impl_from_IWineUiaEvent((IWineUiaEvent *)huiaevent); + int old_event_advisers_count; + HUIANODE node; + HRESULT hr; + + TRACE("(%p, %p)\n", huiaevent, hwnd); + + if (!event) + return E_INVALIDARG; + + assert(event->event_type == EVENT_TYPE_CLIENTSIDE); + + hr = UiaNodeFromHandle(hwnd, &node); + if (FAILED(hr)) + return hr; + + old_event_advisers_count = event->event_advisers_count; + hr = attach_event_to_uia_node(node, event); + if (FAILED(hr)) + goto exit; + + if (event->event_advisers_count != old_event_advisers_count) + hr = uia_event_advise(event, TRUE, old_event_advisers_count); + +exit: + UiaNodeRelease(node); + + return hr; +} + /*********************************************************************** * UiaAddEvent (uiautomationcore.@) */ @@ -752,7 +811,7 @@ HRESULT WINAPI UiaAddEvent(HUIANODE huianode, EVENTID event_id, UiaEventCallback if (FAILED(hr)) goto exit; - hr = IWineUiaEvent_advise_events(&event->IWineUiaEvent_iface, TRUE); + hr = uia_event_advise(event, TRUE, 0); if (FAILED(hr)) goto exit; @@ -775,7 +834,6 @@ exit: HRESULT WINAPI UiaRemoveEvent(HUIAEVENT huiaevent) { struct uia_event *event = unsafe_impl_from_IWineUiaEvent((IWineUiaEvent *)huiaevent); - IWineUiaEvent *event_iface; HRESULT hr; TRACE("(%p)\n", event); @@ -784,33 +842,18 @@ HRESULT WINAPI UiaRemoveEvent(HUIAEVENT huiaevent) return E_INVALIDARG; assert(event->event_type == EVENT_TYPE_CLIENTSIDE); + hr = uia_event_advise(event, FALSE, 0); + if (FAILED(hr)) + return hr; + if (event->u.clientside.git_cookie) { - hr = get_interface_in_git(&IID_IWineUiaEvent, event->u.clientside.git_cookie, (IUnknown **)&event_iface); - if (FAILED(hr)) - return hr; - hr = unregister_interface_in_git(event->u.clientside.git_cookie); if (FAILED(hr)) - { - IWineUiaEvent_Release(event_iface); return hr; - } - - /* - * We want the release of the event_iface proxy to set the reference - * count to 0, so we release our reference here. - */ - IWineUiaEvent_Release(&event->IWineUiaEvent_iface); } - else - event_iface = &event->IWineUiaEvent_iface; - - hr = IWineUiaEvent_advise_events(event_iface, FALSE); - IWineUiaEvent_Release(event_iface); - if (FAILED(hr)) - WARN("advise_events failed with hr %#lx\n", hr); + IWineUiaEvent_Release(&event->IWineUiaEvent_iface); return S_OK; }