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
e382997c
Commit
e382997c
authored
Jun 20, 2022
by
Connor McAdams
Committed by
Alexandre Julliard
Jul 21, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
uiautomationcore: Add support for ProviderOptions_UseComThreading flag.
Signed-off-by:
Connor McAdams
<
cmcadams@codeweavers.com
>
parent
0cea0119
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
233 additions
and
20 deletions
+233
-20
uiautomation.c
dlls/uiautomationcore/tests/uiautomation.c
+126
-0
uia_classes.idl
dlls/uiautomationcore/uia_classes.idl
+25
-15
uia_client.c
dlls/uiautomationcore/uia_client.c
+79
-4
uia_main.c
dlls/uiautomationcore/uia_main.c
+3
-1
No files found.
dlls/uiautomationcore/tests/uiautomation.c
View file @
e382997c
...
...
@@ -1101,6 +1101,7 @@ static struct Provider
enum
ProviderOptions
prov_opts
;
HWND
hwnd
;
BOOL
ret_invalid_prop_type
;
DWORD
expected_tid
;
}
Provider
,
Provider2
,
Provider_child
,
Provider_child2
;
static
const
WCHAR
*
uia_bstr_prop_str
=
L"uia-string"
;
...
...
@@ -1443,6 +1444,8 @@ HRESULT WINAPI ProviderSimple_get_ProviderOptions(IRawElementProviderSimple *ifa
struct
Provider
*
This
=
impl_from_ProviderSimple
(
iface
);
add_method_call
(
This
,
PROV_GET_PROVIDER_OPTIONS
);
if
(
This
->
expected_tid
)
ok
(
This
->
expected_tid
==
GetCurrentThreadId
(),
"Unexpected tid %ld
\n
"
,
GetCurrentThreadId
());
*
ret_val
=
0
;
if
(
This
->
prov_opts
)
...
...
@@ -1467,6 +1470,8 @@ HRESULT WINAPI ProviderSimple_GetPropertyValue(IRawElementProviderSimple *iface,
struct
Provider
*
This
=
impl_from_ProviderSimple
(
iface
);
add_method_call
(
This
,
PROV_GET_PROPERTY_VALUE
);
if
(
This
->
expected_tid
)
ok
(
This
->
expected_tid
==
GetCurrentThreadId
(),
"Unexpected tid %ld
\n
"
,
GetCurrentThreadId
());
VariantInit
(
ret_val
);
switch
(
prop_id
)
...
...
@@ -1654,6 +1659,8 @@ HRESULT WINAPI ProviderSimple_get_HostRawElementProvider(IRawElementProviderSimp
struct
Provider
*
This
=
impl_from_ProviderSimple
(
iface
);
add_method_call
(
This
,
PROV_GET_HOST_RAW_ELEMENT_PROVIDER
);
if
(
This
->
expected_tid
)
ok
(
This
->
expected_tid
==
GetCurrentThreadId
(),
"Unexpected tid %ld
\n
"
,
GetCurrentThreadId
());
*
ret_val
=
NULL
;
if
(
This
->
hwnd
)
...
...
@@ -1702,6 +1709,8 @@ static HRESULT WINAPI ProviderFragment_Navigate(IRawElementProviderFragment *ifa
struct
Provider
*
This
=
impl_from_ProviderFragment
(
iface
);
add_method_call
(
This
,
FRAG_NAVIGATE
);
if
(
This
->
expected_tid
)
ok
(
This
->
expected_tid
==
GetCurrentThreadId
(),
"Unexpected tid %ld
\n
"
,
GetCurrentThreadId
());
*
ret_val
=
NULL
;
if
((
direction
==
NavigateDirection_Parent
)
&&
This
->
parent
)
...
...
@@ -3759,6 +3768,108 @@ static const struct prov_method_sequence node_from_prov8[] = {
{
0
}
};
static
void
check_uia_prop_val
(
PROPERTYID
prop_id
,
enum
UIAutomationType
type
,
VARIANT
*
v
);
static
DWORD
WINAPI
uia_node_from_provider_test_com_thread
(
LPVOID
param
)
{
HUIANODE
node
=
param
;
HRESULT
hr
;
VARIANT
v
;
/*
* Since this is a node representing an IRawElementProviderSimple with
* ProviderOptions_UseComThreading set, it is only usable in threads that
* have initialized COM.
*/
hr
=
UiaGetPropertyValue
(
node
,
UIA_ProcessIdPropertyId
,
&
v
);
ok
(
hr
==
CO_E_NOTINITIALIZED
,
"Unexpected hr %#lx
\n
"
,
hr
);
CoInitializeEx
(
NULL
,
COINIT_MULTITHREADED
);
hr
=
UiaGetPropertyValue
(
node
,
UIA_ProcessIdPropertyId
,
&
v
);
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx
\n
"
,
hr
);
check_uia_prop_val
(
UIA_ProcessIdPropertyId
,
UIAutomationType_Int
,
&
v
);
/*
* When retrieving a UIAutomationType_Element property, if UseComThreading
* is set, we'll get an HUIANODE that will make calls inside of the
* apartment of the node it is retrieved from. I.e, if we received a node
* with UseComThreading set from another node with UseComThreading set
* inside of an STA, the returned node will have all of its methods called
* from the STA thread.
*/
Provider_child
.
prov_opts
=
ProviderOptions_UseComThreading
|
ProviderOptions_ServerSideProvider
;
Provider_child
.
expected_tid
=
Provider
.
expected_tid
;
hr
=
UiaGetPropertyValue
(
node
,
UIA_LabeledByPropertyId
,
&
v
);
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx
\n
"
,
hr
);
check_uia_prop_val
(
UIA_LabeledByPropertyId
,
UIAutomationType_Element
,
&
v
);
/* Unset ProviderOptions_UseComThreading. */
Provider_child
.
prov_opts
=
ProviderOptions_ServerSideProvider
;
hr
=
UiaGetPropertyValue
(
node
,
UIA_LabeledByPropertyId
,
&
v
);
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx
\n
"
,
hr
);
/*
* ProviderOptions_UseComThreading not set, GetPropertyValue will be
* called on the current thread.
*/
Provider_child
.
expected_tid
=
GetCurrentThreadId
();
check_uia_prop_val
(
UIA_LabeledByPropertyId
,
UIAutomationType_Element
,
&
v
);
CoUninitialize
();
return
0
;
}
static
void
test_uia_node_from_prov_com_threading
(
void
)
{
HANDLE
thread
;
HUIANODE
node
;
HRESULT
hr
;
/* Test ProviderOptions_UseComThreading. */
Provider
.
hwnd
=
NULL
;
prov_root
=
NULL
;
Provider
.
prov_opts
=
ProviderOptions_ServerSideProvider
|
ProviderOptions_UseComThreading
;
hr
=
UiaNodeFromProvider
(
&
Provider
.
IRawElementProviderSimple_iface
,
&
node
);
ok_method_sequence
(
node_from_prov8
,
"node_from_prov8"
);
/*
* On Windows versions prior to Windows 10, UiaNodeFromProvider ignores the
* ProviderOptions_UseComThreading flag.
*/
if
(
hr
==
S_OK
)
{
win_skip
(
"Skipping ProviderOptions_UseComThreading tests for UiaNodeFromProvider.
\n
"
);
UiaNodeRelease
(
node
);
return
;
}
ok
(
hr
==
CO_E_NOTINITIALIZED
,
"Unexpected hr %#lx.
\n
"
,
hr
);
CoInitializeEx
(
NULL
,
COINIT_APARTMENTTHREADED
);
hr
=
UiaNodeFromProvider
(
&
Provider
.
IRawElementProviderSimple_iface
,
&
node
);
ok
(
hr
==
S_OK
,
"Unexpected hr %#lx.
\n
"
,
hr
);
ok
(
Provider
.
ref
==
2
,
"Unexpected refcnt %ld
\n
"
,
Provider
.
ref
);
ok_method_sequence
(
node_from_prov8
,
"node_from_prov8"
);
Provider
.
expected_tid
=
GetCurrentThreadId
();
thread
=
CreateThread
(
NULL
,
0
,
uia_node_from_provider_test_com_thread
,
(
void
*
)
node
,
0
,
NULL
);
while
(
MsgWaitForMultipleObjects
(
1
,
&
thread
,
FALSE
,
INFINITE
,
QS_ALLINPUT
)
!=
WAIT_OBJECT_0
)
{
MSG
msg
;
while
(
PeekMessageW
(
&
msg
,
0
,
0
,
0
,
PM_REMOVE
))
{
TranslateMessage
(
&
msg
);
DispatchMessageW
(
&
msg
);
}
}
CloseHandle
(
thread
);
ok
(
UiaNodeRelease
(
node
),
"UiaNodeRelease returned FALSE
\n
"
);
ok
(
Provider
.
ref
==
1
,
"Unexpected refcnt %ld
\n
"
,
Provider
.
ref
);
Provider_child
.
expected_tid
=
Provider
.
expected_tid
=
0
;
CoUninitialize
();
}
static
void
test_UiaNodeFromProvider
(
void
)
{
WNDCLASSA
cls
;
...
...
@@ -3784,6 +3895,9 @@ static void test_UiaNodeFromProvider(void)
hwnd
=
CreateWindowA
(
"UiaNodeFromProvider class"
,
"Test window"
,
WS_OVERLAPPEDWINDOW
,
0
,
0
,
100
,
100
,
NULL
,
NULL
,
NULL
,
NULL
);
/* Run these tests early, we end up in an implicit MTA later. */
test_uia_node_from_prov_com_threading
();
CoInitializeEx
(
NULL
,
COINIT_MULTITHREADED
);
hr
=
UiaNodeFromProvider
(
NULL
,
&
node
);
...
...
@@ -4352,6 +4466,18 @@ static void test_UiaGetPropertyValue(void)
START_TEST
(
uiautomation
)
{
HMODULE
uia_dll
=
LoadLibraryA
(
"uiautomationcore.dll"
);
BOOL
(
WINAPI
*
pImmDisableIME
)(
DWORD
);
HMODULE
hModuleImm32
;
/* Make sure COM isn't initialized by imm32. */
hModuleImm32
=
LoadLibraryA
(
"imm32.dll"
);
if
(
hModuleImm32
)
{
pImmDisableIME
=
(
void
*
)
GetProcAddress
(
hModuleImm32
,
"ImmDisableIME"
);
if
(
pImmDisableIME
)
pImmDisableIME
(
0
);
}
pImmDisableIME
=
NULL
;
FreeLibrary
(
hModuleImm32
);
test_UiaHostProviderFromHwnd
();
test_uia_reserved_value_ifaces
();
...
...
dlls/uiautomationcore/uia_classes.idl
View file @
e382997c
...
...
@@ -16,7 +16,7 @@
*
Foundation
,
Inc
.
,
51
Franklin
St
,
Fifth
Floor
,
Boston
,
MA
02110
-
1301
,
USA
*/
#
pragma
makedep
header
#
pragma
makedep
regtypelib
import
"oaidl.idl"
;
...
...
@@ -27,21 +27,31 @@ struct uia_prop_info {
}
;
[
object
,
uuid
(
57865755
-
6
c05
-
4522
-
98
df
-
4
ca658b768ef
),
pointer_default
(
unique
),
version
(
1.0
),
uuid
(
8
a9ca8eb
-
856b
-
43
d9
-
abd7
-
4
a590054064f
),
]
interface
IWineUiaProvider
:
IUnknown
library
UIA_wine_private
{
HRESULT
get_prop_val
(
[
in
]
const
struct
uia_prop_info
*
prop_info
,
[
out
,
retval
]
VARIANT
*
ret_val
)
;
}
importlib
(
"stdole2.tlb"
)
;
[
object
,
uuid
(
bccb6799
-
d831
-
4057
-
bd50
-
6425823
ff1a3
),
pointer_default
(
unique
),
]
interface
IWineUiaNode
:
IUnknown
{
HRESULT
get_provider
(
[
out
,
retval
]
IWineUiaProvider
**
out_prov
)
;
[
object
,
uuid
(
57865755
-
6
c05
-
4522
-
98
df
-
4
ca658b768ef
),
pointer_default
(
unique
),
oleautomation
,
]
interface
IWineUiaProvider
:
IUnknown
{
HRESULT
get_prop_val
(
[
in
]
const
struct
uia_prop_info
*
prop_info
,
[
out
,
retval
]
VARIANT
*
ret_val
)
;
}
[
object
,
uuid
(
bccb6799
-
d831
-
4057
-
bd50
-
6425823
ff1a3
),
pointer_default
(
unique
),
]
interface
IWineUiaNode
:
IUnknown
{
HRESULT
get_provider
(
[
out
,
retval
]
IWineUiaProvider
**
out_prov
)
;
}
}
dlls/uiautomationcore/uia_client.c
View file @
e382997c
...
...
@@ -148,6 +148,18 @@ exit:
}
}
static
HRESULT
get_global_interface_table
(
IGlobalInterfaceTable
**
git
)
{
HRESULT
hr
;
hr
=
CoCreateInstance
(
&
CLSID_StdGlobalInterfaceTable
,
NULL
,
CLSCTX_INPROC_SERVER
,
&
IID_IGlobalInterfaceTable
,
(
void
**
)
git
);
if
(
FAILED
(
hr
))
WARN
(
"Failed to get GlobalInterfaceTable, hr %#lx
\n
"
,
hr
);
return
hr
;
}
/*
* IWineUiaNode interface.
*/
...
...
@@ -156,6 +168,7 @@ struct uia_node {
LONG
ref
;
IWineUiaProvider
*
prov
;
DWORD
git_cookie
;
};
static
inline
struct
uia_node
*
impl_from_IWineUiaNode
(
IWineUiaNode
*
iface
)
...
...
@@ -192,6 +205,20 @@ static ULONG WINAPI uia_node_Release(IWineUiaNode *iface)
TRACE
(
"%p, refcount %ld
\n
"
,
node
,
ref
);
if
(
!
ref
)
{
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
);
}
}
IWineUiaProvider_Release
(
node
->
prov
);
heap_free
(
node
);
}
...
...
@@ -203,8 +230,30 @@ static HRESULT WINAPI uia_node_get_provider(IWineUiaNode *iface, IWineUiaProvide
{
struct
uia_node
*
node
=
impl_from_IWineUiaNode
(
iface
);
*
out_prov
=
node
->
prov
;
IWineUiaProvider_AddRef
(
node
->
prov
);
if
(
node
->
git_cookie
)
{
IGlobalInterfaceTable
*
git
;
IWineUiaProvider
*
prov
;
HRESULT
hr
;
hr
=
get_global_interface_table
(
&
git
);
if
(
FAILED
(
hr
))
return
hr
;
hr
=
IGlobalInterfaceTable_GetInterfaceFromGlobal
(
git
,
node
->
git_cookie
,
&
IID_IWineUiaProvider
,
(
void
**
)
&
prov
);
if
(
FAILED
(
hr
))
{
ERR
(
"Failed to get provider interface from GlobalInterfaceTable, hr %#lx
\n
"
,
hr
);
return
hr
;
}
*
out_prov
=
prov
;
}
else
{
*
out_prov
=
node
->
prov
;
IWineUiaProvider_AddRef
(
node
->
prov
);
}
return
S_OK
;
}
...
...
@@ -377,7 +426,7 @@ static const IWineUiaProviderVtbl uia_provider_vtbl = {
static
HRESULT
create_wine_uia_provider
(
struct
uia_node
*
node
,
IRawElementProviderSimple
*
elprov
)
{
static
const
int
supported_prov_opts
=
ProviderOptions_ServerSideProvider
;
static
const
int
supported_prov_opts
=
ProviderOptions_ServerSideProvider
|
ProviderOptions_UseComThreading
;
enum
ProviderOptions
prov_opts
;
struct
uia_provider
*
prov
;
HRESULT
hr
;
...
...
@@ -395,10 +444,36 @@ static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProvid
prov
->
IWineUiaProvider_iface
.
lpVtbl
=
&
uia_provider_vtbl
;
prov
->
elprov
=
elprov
;
IRawElementProviderSimple_AddRef
(
elprov
);
prov
->
ref
=
1
;
node
->
prov
=
&
prov
->
IWineUiaProvider_iface
;
/*
* If the UseComThreading ProviderOption is specified, all calls to the
* provided IRawElementProviderSimple need to respect the apartment type
* of the thread that creates the HUIANODE. i.e, if it's created in an
* STA, and the HUIANODE is used in an MTA, we need to provide a proxy.
*/
if
(
prov_opts
&
ProviderOptions_UseComThreading
)
{
IGlobalInterfaceTable
*
git
;
hr
=
get_global_interface_table
(
&
git
);
if
(
FAILED
(
hr
))
{
heap_free
(
prov
);
return
hr
;
}
hr
=
IGlobalInterfaceTable_RegisterInterfaceInGlobal
(
git
,
(
IUnknown
*
)
&
prov
->
IWineUiaProvider_iface
,
&
IID_IWineUiaProvider
,
&
node
->
git_cookie
);
if
(
FAILED
(
hr
))
{
heap_free
(
prov
);
return
hr
;
}
}
IRawElementProviderSimple_AddRef
(
elprov
);
return
S_OK
;
}
...
...
dlls/uiautomationcore/uia_main.c
View file @
e382997c
...
...
@@ -16,9 +16,11 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define COBJMACROS
#include "combaseapi.h"
#include "initguid.h"
#include "uia_private.h"
#include "ocidl.h"
#include "wine/debug.h"
#include "wine/heap.h"
...
...
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