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
eeb098e7
Commit
eeb098e7
authored
Mar 13, 2023
by
Connor McAdams
Committed by
Alexandre Julliard
Mar 16, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
uiautomationcore: Implement IUIAutomationElement::FindFirst{BuildCache}.
Signed-off-by:
Connor McAdams
<
cmcadams@codeweavers.com
>
parent
fdb3c9f9
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
161 additions
and
95 deletions
+161
-95
uiautomation.c
dlls/uiautomationcore/tests/uiautomation.c
+61
-75
uia_com_client.c
dlls/uiautomationcore/uia_com_client.c
+100
-20
No files found.
dlls/uiautomationcore/tests/uiautomation.c
View file @
eeb098e7
...
...
@@ -11418,62 +11418,53 @@ static void test_Element_Find(IUIAutomation *uia_iface)
* root is TRUE. element2 now represents Provider_child.
*/
hr
=
IUIAutomationElement_FindFirstBuildCache
(
element
,
TreeScope_Children
,
condition
,
cache_req
,
&
element2
);
todo_wine
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx.
\n
"
,
hr
);
todo_wine
ok
(
Provider_child
.
ref
==
2
,
"Unexpected refcnt %ld
\n
"
,
Provider_child
.
ref
);
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx.
\n
"
,
hr
);
ok
(
Provider_child
.
ref
==
2
,
"Unexpected refcnt %ld
\n
"
,
Provider_child
.
ref
);
hr
=
IUIAutomationElement_GetCurrentPropertyValueEx
(
element2
,
UIA_ProviderDescriptionPropertyId
,
TRUE
,
&
v
);
todo_wine
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx
\n
"
,
hr
);
if
(
SUCCEEDED
(
hr
))
{
hr
=
IUIAutomationElement_GetCurrentPropertyValueEx
(
element2
,
UIA_ProviderDescriptionPropertyId
,
TRUE
,
&
v
);
todo_wine
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx
\n
"
,
hr
);
if
(
SUCCEEDED
(
hr
))
{
check_node_provider_desc_prefix
(
V_BSTR
(
&
v
),
GetCurrentProcessId
(),
NULL
);
check_node_provider_desc
(
V_BSTR
(
&
v
),
L"Main"
,
L"Provider_child"
,
TRUE
);
VariantClear
(
&
v
);
}
ok_method_sequence
(
find_seq4
,
"find_seq4"
);
check_node_provider_desc_prefix
(
V_BSTR
(
&
v
),
GetCurrentProcessId
(),
NULL
);
check_node_provider_desc
(
V_BSTR
(
&
v
),
L"Main"
,
L"Provider_child"
,
TRUE
);
VariantClear
(
&
v
);
}
if
(
element2
)
{
/*
* Equivalent to: Maximum find depth of 0, find first is FALSE, exclude
* root is FALSE. Provider_child doesn't have a runtime id for UI
* Automation to use as a way to check if it has navigated back to the
* node that began the search, so it will get siblings.
*/
hr
=
IUIAutomationElement_FindAllBuildCache
(
element2
,
TreeScope_Element
,
condition
,
cache_req
,
&
element_arr
);
todo_wine
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx.
\n
"
,
hr
);
if
(
SUCCEEDED
(
hr
))
{
set_elem_desc
(
&
exp_elems
[
0
],
&
Provider_child
,
NULL
,
GetCurrentProcessId
(),
2
,
2
);
add_provider_desc
(
&
exp_elems
[
0
].
prov_desc
,
L"Main"
,
L"Provider_child"
,
TRUE
);
set_elem_desc
(
&
exp_elems
[
1
],
&
Provider_child2
,
NULL
,
GetCurrentProcessId
(),
2
,
1
);
add_provider_desc
(
&
exp_elems
[
1
].
prov_desc
,
L"Main"
,
L"Provider_child2"
,
TRUE
);
ok_method_sequence
(
find_seq4
,
"find_seq4"
);
test_uia_element_arr
(
element_arr
,
exp_elems
,
2
);
ok_method_sequence
(
find_seq5
,
"find_seq5"
);
}
/*
* Equivalent to: Maximum find depth of 0, find first is FALSE, exclude
* root is FALSE. Provider_child doesn't have a runtime id for UI
* Automation to use as a way to check if it has navigated back to the
* node that began the search, so it will get siblings.
*/
hr
=
IUIAutomationElement_FindAllBuildCache
(
element2
,
TreeScope_Element
,
condition
,
cache_req
,
&
element_arr
);
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx.
\n
"
,
hr
);
/*
* Equivalent to: Maximum find depth of 0, find first is FALSE, exclude
* root is FALSE. Provider_child now has a runtime ID, so we don't get
* its sibling.
*/
Provider_child
.
runtime_id
[
0
]
=
Provider_child
.
runtime_id
[
1
]
=
0xdeadbeef
;
hr
=
IUIAutomationElement_FindAllBuildCache
(
element2
,
TreeScope_Element
,
condition
,
cache_req
,
&
element_arr
);
IUIAutomationElement_Release
(
element2
);
todo_wine
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx.
\n
"
,
hr
);
if
(
SUCCEEDED
(
hr
))
{
set_elem_desc
(
&
exp_elems
[
0
],
&
Provider_child
,
NULL
,
GetCurrentProcessId
(),
2
,
1
);
add_provider_desc
(
&
exp_elems
[
0
].
prov_desc
,
L"Main"
,
L"Provider_child"
,
TRUE
);
set_elem_desc
(
&
exp_elems
[
0
],
&
Provider_child
,
NULL
,
GetCurrentProcessId
(),
2
,
2
);
add_provider_desc
(
&
exp_elems
[
0
].
prov_desc
,
L"Main"
,
L"Provider_child"
,
TRUE
);
set_elem_desc
(
&
exp_elems
[
1
],
&
Provider_child2
,
NULL
,
GetCurrentProcessId
(),
2
,
1
);
add_provider_desc
(
&
exp_elems
[
1
].
prov_desc
,
L"Main"
,
L"Provider_child2"
,
TRUE
);
test_uia_element_arr
(
element_arr
,
exp_elems
,
1
);
ok_method_sequence
(
find_seq6
,
"find_seq6"
);
}
initialize_provider_tree
(
FALSE
);
}
test_uia_element_arr
(
element_arr
,
exp_elems
,
2
);
ok_method_sequence
(
find_seq5
,
"find_seq5"
);
/*
* Equivalent to: Maximum find depth of 0, find first is FALSE, exclude
* root is FALSE. Provider_child now has a runtime ID, so we don't get
* its sibling.
*/
Provider_child
.
runtime_id
[
0
]
=
Provider_child
.
runtime_id
[
1
]
=
0xdeadbeef
;
hr
=
IUIAutomationElement_FindAllBuildCache
(
element2
,
TreeScope_Element
,
condition
,
cache_req
,
&
element_arr
);
IUIAutomationElement_Release
(
element2
);
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx.
\n
"
,
hr
);
set_elem_desc
(
&
exp_elems
[
0
],
&
Provider_child
,
NULL
,
GetCurrentProcessId
(),
2
,
1
);
add_provider_desc
(
&
exp_elems
[
0
].
prov_desc
,
L"Main"
,
L"Provider_child"
,
TRUE
);
test_uia_element_arr
(
element_arr
,
exp_elems
,
1
);
ok_method_sequence
(
find_seq6
,
"find_seq6"
);
initialize_provider_tree
(
FALSE
);
IUIAutomationCondition_Release
(
condition
);
...
...
@@ -11618,22 +11609,20 @@ static void test_Element_Find(IUIAutomation *uia_iface)
* to match our condition.
*/
hr
=
IUIAutomationElement_FindFirstBuildCache
(
element
,
TreeScope_SubTree
,
condition
,
cache_req
,
&
element2
);
todo_wine
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx.
\n
"
,
hr
);
todo_wine
ok
(
Provider_child_child2
.
ref
==
2
,
"Unexpected refcnt %ld
\n
"
,
Provider_child_child2
.
ref
);
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx.
\n
"
,
hr
);
ok
(
Provider_child_child2
.
ref
==
2
,
"Unexpected refcnt %ld
\n
"
,
Provider_child_child2
.
ref
);
hr
=
IUIAutomationElement_GetCurrentPropertyValueEx
(
element2
,
UIA_ProviderDescriptionPropertyId
,
TRUE
,
&
v
);
todo_wine
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx
\n
"
,
hr
);
if
(
SUCCEEDED
(
hr
))
{
hr
=
IUIAutomationElement_GetCurrentPropertyValueEx
(
element2
,
UIA_ProviderDescriptionPropertyId
,
TRUE
,
&
v
);
todo_wine
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx
\n
"
,
hr
);
if
(
SUCCEEDED
(
hr
))
{
check_node_provider_desc_prefix
(
V_BSTR
(
&
v
),
GetCurrentProcessId
(),
NULL
);
check_node_provider_desc
(
V_BSTR
(
&
v
),
L"Main"
,
L"Provider_child_child2"
,
TRUE
);
VariantClear
(
&
v
);
}
IUIAutomationElement_Release
(
element2
);
ok_method_sequence
(
find_seq11
,
"find_seq11"
);
check_node_provider_desc_prefix
(
V_BSTR
(
&
v
),
GetCurrentProcessId
(),
NULL
);
check_node_provider_desc
(
V_BSTR
(
&
v
),
L"Main"
,
L"Provider_child_child2"
,
TRUE
);
VariantClear
(
&
v
);
}
IUIAutomationElement_Release
(
element2
);
ok_method_sequence
(
find_seq11
,
"find_seq11"
);
initialize_provider_tree
(
FALSE
);
IUIAutomationCondition_Release
(
condition
);
...
...
@@ -11688,23 +11677,20 @@ static void test_Element_Find(IUIAutomation *uia_iface)
set_provider_prop_override
(
&
Provider_child_child
,
&
prop_override
,
1
);
hr
=
IUIAutomationElement_FindFirst
(
element
,
TreeScope_SubTree
,
condition
,
&
element2
);
todo_wine
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx.
\n
"
,
hr
);
todo_wine
ok
(
Provider_child_child2
.
ref
==
2
,
"Unexpected refcnt %ld
\n
"
,
Provider_child_child2
.
ref
);
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx.
\n
"
,
hr
);
ok
(
Provider_child_child2
.
ref
==
2
,
"Unexpected refcnt %ld
\n
"
,
Provider_child_child2
.
ref
);
hr
=
IUIAutomationElement_GetCurrentPropertyValueEx
(
element2
,
UIA_ProviderDescriptionPropertyId
,
TRUE
,
&
v
);
todo_wine
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx
\n
"
,
hr
);
if
(
SUCCEEDED
(
hr
))
{
hr
=
IUIAutomationElement_GetCurrentPropertyValueEx
(
element2
,
UIA_ProviderDescriptionPropertyId
,
TRUE
,
&
v
);
todo_wine
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx
\n
"
,
hr
);
if
(
SUCCEEDED
(
hr
))
{
check_node_provider_desc_prefix
(
V_BSTR
(
&
v
),
GetCurrentProcessId
(),
NULL
);
check_node_provider_desc
(
V_BSTR
(
&
v
),
L"Main"
,
L"Provider_child_child2"
,
TRUE
);
VariantClear
(
&
v
);
}
IUIAutomationElement_Release
(
element2
);
ok_method_sequence
(
element_find_seq2
,
"element_find_seq2"
);
check_node_provider_desc_prefix
(
V_BSTR
(
&
v
),
GetCurrentProcessId
(),
NULL
);
check_node_provider_desc
(
V_BSTR
(
&
v
),
L"Main"
,
L"Provider_child_child2"
,
TRUE
);
VariantClear
(
&
v
);
}
IUIAutomationElement_Release
(
element2
);
ok_method_sequence
(
element_find_seq2
,
"element_find_seq2"
);
initialize_provider_tree
(
TRUE
);
IUIAutomationCondition_Release
(
condition
);
...
...
dlls/uiautomationcore/uia_com_client.c
View file @
eeb098e7
...
...
@@ -1110,8 +1110,23 @@ static HRESULT WINAPI uia_element_GetRuntimeId(IUIAutomationElement9 *iface, SAF
static
HRESULT
WINAPI
uia_element_FindFirst
(
IUIAutomationElement9
*
iface
,
enum
TreeScope
scope
,
IUIAutomationCondition
*
condition
,
IUIAutomationElement
**
found
)
{
FIXME
(
"%p: stub
\n
"
,
iface
);
return
E_NOTIMPL
;
IUIAutomationCacheRequest
*
cache_req
;
HRESULT
hr
;
TRACE
(
"%p, %#x, %p, %p
\n
"
,
iface
,
scope
,
condition
,
found
);
if
(
!
found
)
return
E_POINTER
;
*
found
=
NULL
;
hr
=
create_uia_cache_request_iface
(
&
cache_req
);
if
(
FAILED
(
hr
))
return
hr
;
hr
=
IUIAutomationElement9_FindFirstBuildCache
(
iface
,
scope
,
condition
,
cache_req
,
found
);
IUIAutomationCacheRequest_Release
(
cache_req
);
return
hr
;
}
static
HRESULT
WINAPI
uia_element_FindAll
(
IUIAutomationElement9
*
iface
,
enum
TreeScope
scope
,
...
...
@@ -1136,13 +1151,93 @@ static HRESULT WINAPI uia_element_FindAll(IUIAutomationElement9 *iface, enum Tre
return
hr
;
}
static
HRESULT
set_find_params_struct
(
struct
UiaFindParams
*
params
,
IUIAutomationCondition
*
cond
,
int
scope
,
BOOL
find_first
)
{
HRESULT
hr
;
hr
=
get_uia_condition_struct_from_iface
(
cond
,
&
params
->
pFindCondition
);
if
(
FAILED
(
hr
))
return
hr
;
if
(
!
scope
||
(
scope
&
(
~
TreeScope_SubTree
)))
return
E_INVALIDARG
;
params
->
FindFirst
=
find_first
;
if
(
scope
&
TreeScope_Element
)
params
->
ExcludeRoot
=
FALSE
;
else
params
->
ExcludeRoot
=
TRUE
;
if
(
scope
&
TreeScope_Descendants
)
params
->
MaxDepth
=
-
1
;
else
if
(
scope
&
TreeScope_Children
)
params
->
MaxDepth
=
1
;
else
params
->
MaxDepth
=
0
;
return
S_OK
;
}
static
HRESULT
create_uia_element_from_cache_req
(
IUIAutomationElement
**
iface
,
BOOL
from_cui8
,
struct
UiaCacheRequest
*
cache_req
,
LONG
start_idx
,
SAFEARRAY
*
req_data
,
BSTR
tree_struct
);
static
HRESULT
WINAPI
uia_element_FindFirstBuildCache
(
IUIAutomationElement9
*
iface
,
enum
TreeScope
scope
,
IUIAutomationCondition
*
condition
,
IUIAutomationCacheRequest
*
cache_req
,
IUIAutomationElement
**
found
)
{
FIXME
(
"%p: stub
\n
"
,
iface
);
return
E_NOTIMPL
;
struct
uia_element
*
element
=
impl_from_IUIAutomationElement9
(
iface
);
LONG
lbound_offsets
,
lbound_tree_structs
,
elems_count
,
offset_idx
;
struct
UiaFindParams
find_params
=
{
0
};
struct
UiaCacheRequest
*
cache_req_struct
;
SAFEARRAY
*
sa
,
*
tree_structs
,
*
offsets
;
IUIAutomationElement
*
elem
;
BSTR
tree_struct_str
;
HRESULT
hr
;
TRACE
(
"%p, %#x, %p, %p, %p
\n
"
,
iface
,
scope
,
condition
,
cache_req
,
found
);
if
(
!
found
)
return
E_POINTER
;
*
found
=
elem
=
NULL
;
hr
=
get_uia_cache_request_struct_from_iface
(
cache_req
,
&
cache_req_struct
);
if
(
FAILED
(
hr
))
return
hr
;
hr
=
set_find_params_struct
(
&
find_params
,
condition
,
scope
,
TRUE
);
if
(
FAILED
(
hr
))
return
hr
;
sa
=
offsets
=
tree_structs
=
NULL
;
hr
=
UiaFind
(
element
->
node
,
&
find_params
,
cache_req_struct
,
&
sa
,
&
offsets
,
&
tree_structs
);
if
(
FAILED
(
hr
)
||
!
sa
)
goto
exit
;
hr
=
get_safearray_bounds
(
tree_structs
,
&
lbound_tree_structs
,
&
elems_count
);
if
(
FAILED
(
hr
))
goto
exit
;
hr
=
SafeArrayGetElement
(
tree_structs
,
&
lbound_tree_structs
,
&
tree_struct_str
);
if
(
FAILED
(
hr
))
goto
exit
;
hr
=
get_safearray_bounds
(
offsets
,
&
lbound_offsets
,
&
elems_count
);
if
(
FAILED
(
hr
))
goto
exit
;
hr
=
SafeArrayGetElement
(
offsets
,
&
lbound_offsets
,
&
offset_idx
);
if
(
FAILED
(
hr
))
goto
exit
;
hr
=
create_uia_element_from_cache_req
(
&
elem
,
element
->
from_cui8
,
cache_req_struct
,
offset_idx
,
sa
,
tree_struct_str
);
if
(
SUCCEEDED
(
hr
))
*
found
=
elem
;
exit:
SafeArrayDestroy
(
tree_structs
);
SafeArrayDestroy
(
offsets
);
SafeArrayDestroy
(
sa
);
return
hr
;
}
static
HRESULT
WINAPI
uia_element_FindAllBuildCache
(
IUIAutomationElement9
*
iface
,
enum
TreeScope
scope
,
...
...
@@ -1168,25 +1263,10 @@ static HRESULT WINAPI uia_element_FindAllBuildCache(IUIAutomationElement9 *iface
if
(
FAILED
(
hr
))
return
hr
;
hr
=
get_uia_condition_struct_from_iface
(
condition
,
&
find_params
.
pFindCondition
);
hr
=
set_find_params_struct
(
&
find_params
,
condition
,
scope
,
FALSE
);
if
(
FAILED
(
hr
))
return
hr
;
if
(
!
scope
||
(
scope
&
(
~
TreeScope_SubTree
)))
return
E_INVALIDARG
;
if
(
scope
&
TreeScope_Element
)
find_params
.
ExcludeRoot
=
FALSE
;
else
find_params
.
ExcludeRoot
=
TRUE
;
if
(
scope
&
TreeScope_Descendants
)
find_params
.
MaxDepth
=
-
1
;
else
if
(
scope
&
TreeScope_Children
)
find_params
.
MaxDepth
=
1
;
else
find_params
.
MaxDepth
=
0
;
sa
=
offsets
=
tree_structs
=
NULL
;
hr
=
UiaFind
(
element
->
node
,
&
find_params
,
cache_req_struct
,
&
sa
,
&
offsets
,
&
tree_structs
);
if
(
FAILED
(
hr
)
||
!
sa
)
...
...
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