Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
26227450
Commit
26227450
authored
Jul 03, 2023
by
Connor McAdams
Committed by
Alexandre Julliard
Jul 10, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
uiautomationcore: Add support for matching serverside events through navigation.
Signed-off-by:
Connor McAdams
<
cmcadams@codeweavers.com
>
parent
68d0c88b
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
114 additions
and
45 deletions
+114
-45
uiautomation.c
dlls/uiautomationcore/tests/uiautomation.c
+5
-5
uia_classes.idl
dlls/uiautomationcore/uia_classes.idl
+1
-1
uia_event.c
dlls/uiautomationcore/uia_event.c
+108
-39
No files found.
dlls/uiautomationcore/tests/uiautomation.c
View file @
26227450
...
...
@@ -14063,11 +14063,11 @@ static void test_UiaAddEvent_client_proc(void)
SET_EXPECT
(
uia_event_callback
);
post_event_message
(
hwnd
,
WM_UIA_TEST_RAISE_EVENT
,
0
,
PROVIDER_CHILD_ID
,
ProviderOptions_ServerSideProvider
);
todo_wine
ok
(
!
WaitForSingleObject
(
EventData
.
event_handle
,
2000
),
"Wait for event_handle failed.
\n
"
);
todo_wine
CHECK_CALLED
(
prov_callback_base_hwnd
);
todo_wine
CHECK_CALLED_MULTI
(
prov_callback_nonclient
,
2
);
ok
(
!
WaitForSingleObject
(
EventData
.
event_handle
,
2000
),
"Wait for event_handle failed.
\n
"
);
CHECK_CALLED
(
prov_callback_base_hwnd
);
CHECK_CALLED_MULTI
(
prov_callback_nonclient
,
2
);
todo_wine
CHECK_CALLED_MULTI
(
prov_callback_proxy
,
2
);
todo_wine
CHECK_CALLED
(
uia_event_callback
);
CHECK_CALLED
(
uia_event_callback
);
hr
=
UiaRemoveEvent
(
event
);
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx.
\n
"
,
hr
);
...
...
@@ -14696,7 +14696,7 @@ static void test_UiaAddEvent(const char *name)
}
}
todo_wine
CHECK_CALLED_AT_LEAST
(
winproc_GETOBJECT_UiaRoot
,
5
);
CHECK_CALLED_AT_LEAST
(
winproc_GETOBJECT_UiaRoot
,
5
);
GetExitCodeProcess
(
proc
.
hProcess
,
&
exit_code
);
if
(
exit_code
>
255
)
ok
(
0
,
"unhandled exception %08x in child process %04x
\n
"
,
(
UINT
)
exit_code
,
(
UINT
)
GetProcessId
(
proc
.
hProcess
));
...
...
dlls/uiautomationcore/uia_classes.idl
View file @
26227450
...
...
@@ -75,7 +75,7 @@ library UIA_wine_private
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
)
;
HRESULT
raise_event
(
[
in
]
VARIANT
in_node
)
;
HRESULT
raise_event
(
[
in
]
VARIANT
in_node
,
[
in
]
VARIANT
in_nav_start_node
)
;
}
[
...
...
dlls/uiautomationcore/uia_event.c
View file @
26227450
...
...
@@ -282,9 +282,11 @@ struct uia_queue_event
union
{
struct
{
HUIANODE
node
;
HUIANODE
nav_start_node
;
}
serverside
;
struct
{
LRESULT
node
;
LRESULT
nav_start_node
;
}
clientside
;
}
u
;
};
...
...
@@ -316,18 +318,44 @@ static struct uia_queue_event *uia_event_queue_pop(struct list *event_queue)
return
queue_event
;
}
static
HRESULT
uia_event_invoke
(
HUIANODE
node
,
struct
uia_event_args
*
args
,
struct
uia_event
*
event
);
static
void
uia_node_lresult_release
(
LRESULT
lr
)
{
IWineUiaNode
*
node
;
if
(
lr
&&
SUCCEEDED
(
ObjectFromLresult
(
lr
,
&
IID_IWineUiaNode
,
0
,
(
void
**
)
&
node
)))
IWineUiaNode_Release
(
node
);
}
static
HRESULT
uia_event_invoke
(
HUIANODE
node
,
HUIANODE
nav_start_node
,
struct
uia_event_args
*
args
,
struct
uia_event
*
event
);
static
HRESULT
uia_raise_clientside_event
(
struct
uia_queue_event
*
event
)
{
HUIANODE
node
;
HUIANODE
node
,
nav_start_node
;
HRESULT
hr
;
node
=
nav_start_node
=
NULL
;
hr
=
uia_node_from_lresult
(
event
->
u
.
clientside
.
node
,
&
node
);
if
(
SUCCEEDED
(
hr
))
if
(
FAILED
(
hr
))
{
WARN
(
"Failed to create node from lresult, hr %#lx
\n
"
,
hr
);
uia_node_lresult_release
(
event
->
u
.
clientside
.
nav_start_node
);
return
hr
;
}
if
(
event
->
u
.
clientside
.
nav_start_node
)
{
hr
=
uia_node_from_lresult
(
event
->
u
.
clientside
.
nav_start_node
,
&
nav_start_node
);
if
(
FAILED
(
hr
))
{
hr
=
uia_event_invoke
(
node
,
event
->
args
,
event
->
event
);
WARN
(
"Failed to create nav_start_node from lresult, hr %#lx
\n
"
,
hr
);
UiaNodeRelease
(
node
);
return
hr
;
}
}
hr
=
uia_event_invoke
(
node
,
nav_start_node
,
event
->
args
,
event
->
event
);
UiaNodeRelease
(
node
);
UiaNodeRelease
(
nav_start_node
);
return
hr
;
}
...
...
@@ -335,33 +363,37 @@ static HRESULT uia_raise_clientside_event(struct uia_queue_event *event)
static
HRESULT
uia_raise_serverside_event
(
struct
uia_queue_event
*
event
)
{
HRESULT
hr
=
S_OK
;
LRESULT
lr
;
LRESULT
lr
,
lr2
;
VARIANT
v
,
v2
;
/*
* uia_lresult_from_node is expected to release the node here upon
* failure.
*/
if
((
lr
=
uia_lresult_from_node
(
event
->
u
.
serverside
.
node
)))
lr
=
lr2
=
0
;
if
(
!
(
lr
=
uia_lresult_from_node
(
event
->
u
.
serverside
.
node
)))
{
VARIANT
v
;
UiaNodeRelease
(
event
->
u
.
serverside
.
nav_start_node
);
return
E_FAIL
;
}
V_VT
(
&
v
)
=
VT_I4
;
V_I4
(
&
v
)
=
lr
;
hr
=
IWineUiaEvent_raise_event
(
event
->
event
->
u
.
serverside
.
event_iface
,
v
);
if
(
FAILED
(
hr
))
if
(
event
->
u
.
serverside
.
nav_start_node
&&
!
(
lr2
=
uia_lresult_from_node
(
event
->
u
.
serverside
.
nav_start_node
)))
{
IWineUiaNode
*
node
;
/*
* If the method returned failure, make sure we don't leave a
* dangling IWineUiaNode.
*/
if
(
SUCCEEDED
(
ObjectFromLresult
(
lr
,
&
IID_IWineUiaNode
,
0
,
(
void
**
)
&
node
)))
IWineUiaNode_Release
(
node
);
uia_node_lresult_release
(
lr
);
return
E_FAIL
;
}
VariantInit
(
&
v2
);
variant_init_i4
(
&
v
,
lr
);
if
(
lr2
)
variant_init_i4
(
&
v2
,
lr2
);
hr
=
IWineUiaEvent_raise_event
(
event
->
event
->
u
.
serverside
.
event_iface
,
v
,
v2
);
if
(
FAILED
(
hr
))
{
uia_node_lresult_release
(
lr
);
uia_node_lresult_release
(
lr2
);
}
else
hr
=
E_FAIL
;
return
hr
;
}
...
...
@@ -635,13 +667,13 @@ static HRESULT WINAPI uia_event_set_event_data(IWineUiaEvent *iface, const GUID
return
S_OK
;
}
static
HRESULT
WINAPI
uia_event_raise_event
(
IWineUiaEvent
*
iface
,
VARIANT
in_node
)
static
HRESULT
WINAPI
uia_event_raise_event
(
IWineUiaEvent
*
iface
,
VARIANT
in_node
,
VARIANT
in_nav_start_node
)
{
struct
uia_event
*
event
=
impl_from_IWineUiaEvent
(
iface
);
struct
uia_queue_event
*
queue_event
;
struct
uia_event_args
*
args
;
TRACE
(
"%p, %s
\n
"
,
iface
,
debugstr_variant
(
&
in
_node
));
TRACE
(
"%p, %s
, %s
\n
"
,
iface
,
debugstr_variant
(
&
in_node
),
debugstr_variant
(
&
in_nav_start
_node
));
assert
(
event
->
event_type
!=
EVENT_TYPE_SERVERSIDE
);
...
...
@@ -658,6 +690,8 @@ static HRESULT WINAPI uia_event_raise_event(IWineUiaEvent *iface, VARIANT in_nod
queue_event
->
args
=
args
;
queue_event
->
event
=
event
;
queue_event
->
u
.
clientside
.
node
=
V_I4
(
&
in_node
);
if
(
V_VT
(
&
in_nav_start_node
)
==
VT_I4
)
queue_event
->
u
.
clientside
.
nav_start_node
=
V_I4
(
&
in_nav_start_node
);
IWineUiaEvent_AddRef
(
&
event
->
IWineUiaEvent_iface
);
uia_event_queue_push
(
queue_event
);
...
...
@@ -1193,7 +1227,9 @@ HRESULT WINAPI UiaRemoveEvent(HUIAEVENT huiaevent)
return
S_OK
;
}
static
HRESULT
uia_event_invoke
(
HUIANODE
node
,
struct
uia_event_args
*
args
,
struct
uia_event
*
event
)
static
HRESULT
uia_event_check_match
(
HUIANODE
node
,
HUIANODE
nav_start_node
,
SAFEARRAY
*
rt_id
,
struct
uia_event_args
*
args
,
struct
uia_event
*
event
);
static
HRESULT
uia_event_invoke
(
HUIANODE
node
,
HUIANODE
nav_start_node
,
struct
uia_event_args
*
args
,
struct
uia_event
*
event
)
{
HRESULT
hr
=
S_OK
;
...
...
@@ -1202,6 +1238,9 @@ static HRESULT uia_event_invoke(HUIANODE node, struct uia_event_args *args, stru
SAFEARRAY
*
out_req
;
BSTR
tree_struct
;
if
(
nav_start_node
)
return
uia_event_check_match
(
node
,
nav_start_node
,
NULL
,
args
,
event
);
hr
=
UiaGetUpdatedCache
(
node
,
&
event
->
u
.
clientside
.
cache_req
,
NormalizeState_View
,
NULL
,
&
out_req
,
&
tree_struct
);
if
(
SUCCEEDED
(
hr
))
...
...
@@ -1214,11 +1253,12 @@ static HRESULT uia_event_invoke(HUIANODE node, struct uia_event_args *args, stru
else
{
struct
uia_queue_event
*
queue_event
;
HUIANODE
node2
;
HUIANODE
node2
,
nav_start_node2
;
if
(
!
(
queue_event
=
heap_alloc_zero
(
sizeof
(
*
queue_event
))))
return
E_OUTOFMEMORY
;
node2
=
nav_start_node2
=
NULL
;
hr
=
clone_uia_node
(
node
,
&
node2
);
if
(
FAILED
(
hr
))
{
...
...
@@ -1226,10 +1266,22 @@ static HRESULT uia_event_invoke(HUIANODE node, struct uia_event_args *args, stru
return
hr
;
}
if
(
nav_start_node
)
{
hr
=
clone_uia_node
(
nav_start_node
,
&
nav_start_node2
);
if
(
FAILED
(
hr
))
{
heap_free
(
queue_event
);
UiaNodeRelease
(
node2
);
return
hr
;
}
}
queue_event
->
queue_event_type
=
QUEUE_EVENT_TYPE_SERVERSIDE
;
queue_event
->
args
=
args
;
queue_event
->
event
=
event
;
queue_event
->
u
.
serverside
.
node
=
node2
;
queue_event
->
u
.
serverside
.
nav_start_node
=
nav_start_node2
;
InterlockedIncrement
(
&
args
->
ref
);
IWineUiaEvent_AddRef
(
&
event
->
IWineUiaEvent_iface
);
...
...
@@ -1239,14 +1291,21 @@ static HRESULT uia_event_invoke(HUIANODE node, struct uia_event_args *args, stru
return
hr
;
}
static
void
set_refuse_hwnd_providers
(
struct
uia_node
*
node
,
BOOL
refuse_hwnd_providers
)
{
struct
uia_provider
*
prov_data
=
impl_from_IWineUiaProvider
(
node
->
prov
[
get_node_provider_type_at_idx
(
node
,
0
)]);
prov_data
->
refuse_hwnd_node_providers
=
refuse_hwnd_providers
;
}
/*
* Check if the provider that raised the event matches this particular event.
*/
static
HRESULT
uia_event_check_match
(
HUIANODE
node
,
SAFEARRAY
*
rt_id
,
struct
uia_event_args
*
args
,
struct
uia_event
*
event
)
static
HRESULT
uia_event_check_match
(
HUIANODE
node
,
HUIANODE
nav_start_node
,
SAFEARRAY
*
rt_id
,
struct
uia_event
_args
*
args
,
struct
uia_event
*
event
)
{
struct
UiaPropertyCondition
prop_cond
=
{
ConditionType_Property
,
UIA_RuntimeIdPropertyId
};
struct
uia_node
*
node_data
=
impl_from_IWineUiaNode
((
IWineUiaNode
*
)
node
);
struct
uia_node
*
node_data
=
impl_from_IWineUiaNode
((
IWineUiaNode
*
)
n
av_start_n
ode
);
HRESULT
hr
=
S_OK
;
/* Event is no longer valid. */
...
...
@@ -1258,24 +1317,18 @@ static HRESULT uia_event_check_match(HUIANODE node, SAFEARRAY *rt_id, struct uia
return
S_OK
;
if
(
event
->
desktop_subtree_event
)
return
uia_event_invoke
(
node
,
args
,
event
);
return
uia_event_invoke
(
node
,
NULL
,
args
,
event
);
if
(
rt_id
&&
!
uia_compare_safearrays
(
rt_id
,
event
->
runtime_id
,
UIAutomationType_IntArray
))
{
if
(
event
->
scope
&
TreeScope_Element
)
hr
=
uia_event_invoke
(
node
,
args
,
event
);
hr
=
uia_event_invoke
(
node
,
NULL
,
args
,
event
);
return
hr
;
}
if
(
!
(
event
->
scope
&
(
TreeScope_Descendants
|
TreeScope_Children
)))
return
S_OK
;
if
(
event
->
event_type
==
EVENT_TYPE_SERVERSIDE
)
{
FIXME
(
"Matching serverside events through navigation currently unimplemented
\n
"
);
return
S_OK
;
}
V_VT
(
&
prop_cond
.
Value
)
=
VT_I4
|
VT_ARRAY
;
V_ARRAY
(
&
prop_cond
.
Value
)
=
event
->
runtime_id
;
...
...
@@ -1284,6 +1337,22 @@ static HRESULT uia_event_check_match(HUIANODE node, SAFEARRAY *rt_id, struct uia
{
HUIANODE
node2
=
NULL
;
/*
* When trying to match serverside events through navigation, we
* don't want any clientside providers added in the server process.
* Once we encounter a provider with an HWND, we pass it off to the
* client for any further navigation.
*/
if
(
event
->
event_type
==
EVENT_TYPE_SERVERSIDE
)
{
if
(
node_data
->
hwnd
)
{
hr
=
uia_event_invoke
(
node
,
(
HUIANODE
)
&
node_data
->
IWineUiaNode_iface
,
args
,
event
);
break
;
}
set_refuse_hwnd_providers
(
node_data
,
TRUE
);
}
hr
=
navigate_uia_node
(
node_data
,
NavigateDirection_Parent
,
&
node2
);
IWineUiaNode_Release
(
&
node_data
->
IWineUiaNode_iface
);
if
(
FAILED
(
hr
)
||
!
node2
)
...
...
@@ -1296,7 +1365,7 @@ static HRESULT uia_event_check_match(HUIANODE node, SAFEARRAY *rt_id, struct uia
if
(
uia_condition_matched
(
hr
))
{
hr
=
uia_event_invoke
(
node
,
args
,
event
);
hr
=
uia_event_invoke
(
node
,
NULL
,
args
,
event
);
break
;
}
...
...
@@ -1355,7 +1424,7 @@ static HRESULT uia_raise_event(IRawElementProviderSimple *elprov, struct uia_eve
{
struct
uia_event
*
event
=
LIST_ENTRY
(
cursor
,
struct
uia_event
,
event_list_entry
);
hr
=
uia_event_check_match
(
node
,
sa
,
args
,
event
);
hr
=
uia_event_check_match
(
node
,
node
,
sa
,
args
,
event
);
if
(
FAILED
(
hr
))
break
;
}
...
...
@@ -1366,7 +1435,7 @@ static HRESULT uia_raise_event(IRawElementProviderSimple *elprov, struct uia_eve
{
struct
uia_event
*
event
=
LIST_ENTRY
(
cursor
,
struct
uia_event
,
event_list_entry
);
hr
=
uia_event_check_match
(
node
,
sa
,
args
,
event
);
hr
=
uia_event_check_match
(
node
,
node
,
sa
,
args
,
event
);
if
(
FAILED
(
hr
))
break
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment