uiautomationcore: Add a default ProviderType_Proxy MSAA bridge clientside provider.
Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
parent
2a089f52f0
commit
a19c1ff169
4 changed files with 160 additions and 28 deletions
|
@ -90,6 +90,7 @@ DEFINE_EXPECT(Accessible2_get_accName);
|
||||||
DEFINE_EXPECT(Accessible2_get_accRole);
|
DEFINE_EXPECT(Accessible2_get_accRole);
|
||||||
DEFINE_EXPECT(Accessible2_get_accState);
|
DEFINE_EXPECT(Accessible2_get_accState);
|
||||||
DEFINE_EXPECT(Accessible2_accLocation);
|
DEFINE_EXPECT(Accessible2_accLocation);
|
||||||
|
DEFINE_EXPECT(Accessible_QI_IAccIdentity);
|
||||||
DEFINE_EXPECT(Accessible2_QI_IAccIdentity);
|
DEFINE_EXPECT(Accessible2_QI_IAccIdentity);
|
||||||
DEFINE_EXPECT(Accessible2_get_uniqueID);
|
DEFINE_EXPECT(Accessible2_get_uniqueID);
|
||||||
DEFINE_EXPECT(Accessible_child_accNavigate);
|
DEFINE_EXPECT(Accessible_child_accNavigate);
|
||||||
|
@ -177,7 +178,10 @@ static HRESULT WINAPI Accessible_QueryInterface(IAccessible *iface, REFIID riid,
|
||||||
{
|
{
|
||||||
if (This == &Accessible2)
|
if (This == &Accessible2)
|
||||||
CHECK_EXPECT(Accessible2_QI_IAccIdentity);
|
CHECK_EXPECT(Accessible2_QI_IAccIdentity);
|
||||||
ok(This == &Accessible2, "unexpected call\n");
|
else if (This == &Accessible)
|
||||||
|
CHECK_EXPECT(Accessible_QI_IAccIdentity);
|
||||||
|
|
||||||
|
ok(This == &Accessible2 || This == &Accessible, "unexpected call\n");
|
||||||
return E_NOINTERFACE;
|
return E_NOINTERFACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6738,10 +6742,17 @@ static void test_UiaNodeFromHandle(const char *name)
|
||||||
/* Only sent twice on Win7. */
|
/* Only sent twice on Win7. */
|
||||||
SET_EXPECT_MULTI(winproc_GETOBJECT_CLIENT, 2);
|
SET_EXPECT_MULTI(winproc_GETOBJECT_CLIENT, 2);
|
||||||
hr = UiaNodeFromHandle(hwnd, &node);
|
hr = UiaNodeFromHandle(hwnd, &node);
|
||||||
/* Windows 10 and below return E_FAIL, Windows 11 returns S_OK. */
|
/*
|
||||||
ok(hr == S_OK || broken(hr == E_FAIL), "Unexpected hr %#lx.\n", hr);
|
* On all versions of Windows prior to Windows 11, this would fail due to
|
||||||
|
* COM being uninitialized, presumably because it tries to get an MSAA
|
||||||
|
* proxy. Windows 11 now has the thread end up in an implicit MTA after
|
||||||
|
* the call to UiaNodeFromHandle, which is probably why this now succeeds.
|
||||||
|
* I don't know of anything that relies on this behavior, so for now we
|
||||||
|
* won't match it.
|
||||||
|
*/
|
||||||
|
todo_wine ok(hr == S_OK || broken(hr == E_FAIL), "Unexpected hr %#lx.\n", hr);
|
||||||
CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
|
CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
|
||||||
todo_wine CHECK_CALLED(winproc_GETOBJECT_CLIENT);
|
CHECK_CALLED(winproc_GETOBJECT_CLIENT);
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
UiaNodeRelease(node);
|
UiaNodeRelease(node);
|
||||||
|
|
||||||
|
@ -6757,7 +6768,7 @@ static void test_UiaNodeFromHandle(const char *name)
|
||||||
hr = UiaNodeFromHandle(hwnd, &node);
|
hr = UiaNodeFromHandle(hwnd, &node);
|
||||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
|
CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
|
||||||
todo_wine CHECK_CALLED(winproc_GETOBJECT_CLIENT);
|
CHECK_CALLED(winproc_GETOBJECT_CLIENT);
|
||||||
|
|
||||||
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
|
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
|
||||||
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
|
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
|
||||||
|
@ -6783,7 +6794,7 @@ static void test_UiaNodeFromHandle(const char *name)
|
||||||
hr = UiaNodeFromHandle(hwnd, &node);
|
hr = UiaNodeFromHandle(hwnd, &node);
|
||||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
|
CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
|
||||||
todo_wine CHECK_CALLED(winproc_GETOBJECT_CLIENT);
|
CHECK_CALLED(winproc_GETOBJECT_CLIENT);
|
||||||
|
|
||||||
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
|
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
|
||||||
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
|
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
|
||||||
|
@ -6818,7 +6829,7 @@ static void test_UiaNodeFromHandle(const char *name)
|
||||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
ok(Provider.ref == 1 || broken(Provider.ref == 2), "Unexpected refcnt %ld\n", Provider.ref);
|
ok(Provider.ref == 1 || broken(Provider.ref == 2), "Unexpected refcnt %ld\n", Provider.ref);
|
||||||
CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
|
CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
|
||||||
todo_wine CHECK_CALLED(winproc_GETOBJECT_CLIENT);
|
CHECK_CALLED(winproc_GETOBJECT_CLIENT);
|
||||||
|
|
||||||
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
|
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
|
||||||
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
|
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
|
||||||
|
@ -12684,6 +12695,93 @@ static void test_default_clientside_providers(void)
|
||||||
UiaNodeRelease(node);
|
UiaNodeRelease(node);
|
||||||
prov_root = NULL;
|
prov_root = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test default ProviderType_Proxy clientside provider. Provider will be
|
||||||
|
* the HWND provider for this node, and Accessible will be the main
|
||||||
|
* provider.
|
||||||
|
*/
|
||||||
|
initialize_provider(&Provider, ProviderOptions_ClientSideProvider, hwnd, FALSE);
|
||||||
|
set_accessible_props(&Accessible, ROLE_SYSTEM_TEXT, STATE_SYSTEM_FOCUSABLE, 0, L"Accessible", 0, 0, 20, 20);
|
||||||
|
set_accessible_ia2_props(&Accessible, FALSE, 0);
|
||||||
|
acc_client = &Accessible.IAccessible_iface;
|
||||||
|
prov_root = child_win_prov_root = NULL;
|
||||||
|
|
||||||
|
SET_EXPECT(Accessible_QI_IAccIdentity);
|
||||||
|
SET_EXPECT(Accessible_get_accParent);
|
||||||
|
SET_EXPECT(winproc_GETOBJECT_UiaRoot);
|
||||||
|
/* Only sent twice on Win7. */
|
||||||
|
SET_EXPECT_MULTI(winproc_GETOBJECT_CLIENT, 2);
|
||||||
|
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(Accessible.ref >= 2, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||||
|
todo_wine CHECK_CALLED(Accessible_QI_IAccIdentity);
|
||||||
|
todo_wine CHECK_CALLED(Accessible_get_accParent);
|
||||||
|
CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
|
||||||
|
CHECK_CALLED(winproc_GETOBJECT_CLIENT);
|
||||||
|
|
||||||
|
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
|
||||||
|
check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd);
|
||||||
|
check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider", FALSE);
|
||||||
|
check_node_provider_desc_todo(V_BSTR(&v), L"Nonclient", NULL, FALSE);
|
||||||
|
check_node_provider_desc(V_BSTR(&v), L"Main", NULL, TRUE);
|
||||||
|
VariantClear(&v);
|
||||||
|
|
||||||
|
SET_EXPECT(Accessible_get_accRole);
|
||||||
|
hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v);
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
|
||||||
|
ok(V_VT(&v) == VT_I4, "Unexpected VT %d\n", V_VT(&v));
|
||||||
|
ok(V_I4(&v) == UIA_EditControlTypeId, "Unexpected I4 %#lx\n", V_I4(&v));
|
||||||
|
VariantClear(&v);
|
||||||
|
CHECK_CALLED(Accessible_get_accRole);
|
||||||
|
|
||||||
|
UiaNodeRelease(node);
|
||||||
|
ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref);
|
||||||
|
ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unlike UiaProviderFromIAccessible which won't create a provider for an
|
||||||
|
* MSAA proxy, the default clientside proxy provider will.
|
||||||
|
*/
|
||||||
|
hwnd2 = CreateWindowA("EDIT", "", WS_VISIBLE | WS_CHILD | ES_PASSWORD,
|
||||||
|
0, 0, 100, 100, hwnd, NULL, NULL, NULL);
|
||||||
|
initialize_provider(&Provider, ProviderOptions_ClientSideProvider, hwnd2, FALSE);
|
||||||
|
|
||||||
|
/* Tries to get override provider from parent HWND. */
|
||||||
|
SET_EXPECT(winproc_GETOBJECT_UiaRoot);
|
||||||
|
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);
|
||||||
|
todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
|
||||||
|
|
||||||
|
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
|
||||||
|
check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2);
|
||||||
|
check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider", FALSE);
|
||||||
|
check_node_provider_desc_todo(V_BSTR(&v), L"Main", NULL, FALSE);
|
||||||
|
check_node_provider_desc_todo(V_BSTR(&v), L"Annotation", NULL, TRUE);
|
||||||
|
VariantClear(&v);
|
||||||
|
|
||||||
|
hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v);
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
|
||||||
|
ok(V_VT(&v) == VT_I4, "Unexpected VT %d\n", V_VT(&v));
|
||||||
|
ok(V_I4(&v) == UIA_EditControlTypeId, "Unexpected I4 %#lx\n", V_I4(&v));
|
||||||
|
VariantClear(&v);
|
||||||
|
|
||||||
|
hr = UiaGetPropertyValue(node, UIA_IsPasswordPropertyId, &v);
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
|
||||||
|
ok(V_VT(&v) == VT_BOOL, "Unexpected VT %d\n", V_VT(&v));
|
||||||
|
ok(check_variant_bool(&v, TRUE), "V_BOOL(&v) = %#x\n", V_BOOL(&v));
|
||||||
|
VariantClear(&v);
|
||||||
|
|
||||||
|
UiaNodeRelease(node);
|
||||||
|
DestroyWindow(hwnd2);
|
||||||
|
|
||||||
|
set_accessible_props(&Accessible, 0, 0, 0, NULL, 0, 0, 0, 0);
|
||||||
|
acc_client = NULL;
|
||||||
|
prov_root = child_win_prov_root = NULL;
|
||||||
|
|
||||||
method_sequences_enabled = TRUE;
|
method_sequences_enabled = TRUE;
|
||||||
DestroyWindow(hwnd);
|
DestroyWindow(hwnd);
|
||||||
DestroyWindow(hwnd_child);
|
DestroyWindow(hwnd_child);
|
||||||
|
|
|
@ -2653,8 +2653,20 @@ static SAFEARRAY WINAPI *default_uia_provider_callback(HWND hwnd, enum ProviderT
|
||||||
switch (prov_type)
|
switch (prov_type)
|
||||||
{
|
{
|
||||||
case ProviderType_Proxy:
|
case ProviderType_Proxy:
|
||||||
FIXME("Default ProviderType_Proxy MSAA provider unimplemented.\n");
|
{
|
||||||
|
IAccessible *acc;
|
||||||
|
|
||||||
|
hr = AccessibleObjectFromWindow(hwnd, OBJID_CLIENT, &IID_IAccessible, (void **)&acc);
|
||||||
|
if (FAILED(hr) || !acc)
|
||||||
|
break;
|
||||||
|
|
||||||
|
hr = create_msaa_provider(acc, CHILDID_SELF, hwnd, TRUE, &elprov);
|
||||||
|
if (FAILED(hr))
|
||||||
|
WARN("Failed to create MSAA proxy provider with hr %#lx\n", hr);
|
||||||
|
|
||||||
|
IAccessible_Release(acc);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ProviderType_NonClientArea:
|
case ProviderType_NonClientArea:
|
||||||
FIXME("Default ProviderType_NonClientArea provider unimplemented.\n");
|
FIXME("Default ProviderType_NonClientArea provider unimplemented.\n");
|
||||||
|
|
|
@ -155,3 +155,5 @@ HRESULT create_base_hwnd_provider(HWND hwnd, IRawElementProviderSimple **elprov)
|
||||||
void uia_stop_provider_thread(void) DECLSPEC_HIDDEN;
|
void uia_stop_provider_thread(void) DECLSPEC_HIDDEN;
|
||||||
void uia_provider_thread_remove_node(HUIANODE node) DECLSPEC_HIDDEN;
|
void uia_provider_thread_remove_node(HUIANODE node) DECLSPEC_HIDDEN;
|
||||||
LRESULT uia_lresult_from_node(HUIANODE huianode) DECLSPEC_HIDDEN;
|
LRESULT uia_lresult_from_node(HUIANODE huianode) DECLSPEC_HIDDEN;
|
||||||
|
HRESULT create_msaa_provider(IAccessible *acc, long child_id, HWND hwnd, BOOL known_root_acc,
|
||||||
|
IRawElementProviderSimple **elprov) DECLSPEC_HIDDEN;
|
||||||
|
|
|
@ -796,7 +796,7 @@ static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface,
|
||||||
else
|
else
|
||||||
acc = msaa_prov->acc;
|
acc = msaa_prov->acc;
|
||||||
|
|
||||||
hr = UiaProviderFromIAccessible(acc, CHILDID_SELF, 0, &elprov);
|
hr = create_msaa_provider(acc, CHILDID_SELF, NULL, FALSE, &elprov);
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
struct msaa_provider *prov = impl_from_msaa_provider(elprov);
|
struct msaa_provider *prov = impl_from_msaa_provider(elprov);
|
||||||
|
@ -827,7 +827,7 @@ static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface,
|
||||||
if (FAILED(hr) || !acc)
|
if (FAILED(hr) || !acc)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
hr = UiaProviderFromIAccessible(acc, child_id, 0, &elprov);
|
hr = create_msaa_provider(acc, child_id, NULL, FALSE, &elprov);
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
struct msaa_provider *prov = impl_from_msaa_provider(elprov);
|
struct msaa_provider *prov = impl_from_msaa_provider(elprov);
|
||||||
|
@ -877,7 +877,7 @@ static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface,
|
||||||
if (FAILED(hr) || !acc)
|
if (FAILED(hr) || !acc)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
hr = UiaProviderFromIAccessible(acc, child_id, 0, &elprov);
|
hr = create_msaa_provider(acc, child_id, NULL, FALSE, &elprov);
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
struct msaa_provider *prov = impl_from_msaa_provider(elprov);
|
struct msaa_provider *prov = impl_from_msaa_provider(elprov);
|
||||||
|
@ -1134,13 +1134,48 @@ static const ILegacyIAccessibleProviderVtbl msaa_acc_provider_vtbl = {
|
||||||
msaa_acc_provider_get_DefaultAction,
|
msaa_acc_provider_get_DefaultAction,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
HRESULT create_msaa_provider(IAccessible *acc, long child_id, HWND hwnd, BOOL known_root_acc,
|
||||||
|
IRawElementProviderSimple **elprov)
|
||||||
|
{
|
||||||
|
struct msaa_provider *msaa_prov = heap_alloc_zero(sizeof(*msaa_prov));
|
||||||
|
|
||||||
|
if (!msaa_prov)
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
|
msaa_prov->IRawElementProviderSimple_iface.lpVtbl = &msaa_provider_vtbl;
|
||||||
|
msaa_prov->IRawElementProviderFragment_iface.lpVtbl = &msaa_fragment_vtbl;
|
||||||
|
msaa_prov->ILegacyIAccessibleProvider_iface.lpVtbl = &msaa_acc_provider_vtbl;
|
||||||
|
msaa_prov->refcount = 1;
|
||||||
|
variant_init_i4(&msaa_prov->cid, child_id);
|
||||||
|
msaa_prov->acc = acc;
|
||||||
|
IAccessible_AddRef(acc);
|
||||||
|
msaa_prov->ia2 = msaa_acc_get_ia2(acc);
|
||||||
|
|
||||||
|
if (!hwnd)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
hr = WindowFromAccessibleObject(acc, &msaa_prov->hwnd);
|
||||||
|
if (FAILED(hr))
|
||||||
|
WARN("WindowFromAccessibleObject failed with hr %#lx\n", hr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
msaa_prov->hwnd = hwnd;
|
||||||
|
|
||||||
|
if (known_root_acc)
|
||||||
|
msaa_prov->root_acc_check_ran = msaa_prov->is_root_acc = TRUE;
|
||||||
|
|
||||||
|
*elprov = &msaa_prov->IRawElementProviderSimple_iface;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* UiaProviderFromIAccessible (uiautomationcore.@)
|
* UiaProviderFromIAccessible (uiautomationcore.@)
|
||||||
*/
|
*/
|
||||||
HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD flags,
|
HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD flags,
|
||||||
IRawElementProviderSimple **elprov)
|
IRawElementProviderSimple **elprov)
|
||||||
{
|
{
|
||||||
struct msaa_provider *msaa_prov;
|
|
||||||
IServiceProvider *serv_prov;
|
IServiceProvider *serv_prov;
|
||||||
HWND hwnd = NULL;
|
HWND hwnd = NULL;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
@ -1184,22 +1219,7 @@ HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD
|
||||||
if (!hwnd)
|
if (!hwnd)
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
|
|
||||||
msaa_prov = heap_alloc_zero(sizeof(*msaa_prov));
|
return create_msaa_provider(acc, child_id, hwnd, FALSE, elprov);
|
||||||
if (!msaa_prov)
|
|
||||||
return E_OUTOFMEMORY;
|
|
||||||
|
|
||||||
msaa_prov->IRawElementProviderSimple_iface.lpVtbl = &msaa_provider_vtbl;
|
|
||||||
msaa_prov->IRawElementProviderFragment_iface.lpVtbl = &msaa_fragment_vtbl;
|
|
||||||
msaa_prov->ILegacyIAccessibleProvider_iface.lpVtbl = &msaa_acc_provider_vtbl;
|
|
||||||
msaa_prov->refcount = 1;
|
|
||||||
msaa_prov->hwnd = hwnd;
|
|
||||||
variant_init_i4(&msaa_prov->cid, child_id);
|
|
||||||
msaa_prov->acc = acc;
|
|
||||||
IAccessible_AddRef(acc);
|
|
||||||
msaa_prov->ia2 = msaa_acc_get_ia2(acc);
|
|
||||||
*elprov = &msaa_prov->IRawElementProviderSimple_iface;
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT uia_get_hr_for_last_error(void)
|
static HRESULT uia_get_hr_for_last_error(void)
|
||||||
|
|
Loading…
Add table
Reference in a new issue