Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/oleacc/main.c | 52 +++++++++++++++++++++++++++++++++++++++++ dlls/oleacc/oleacc.spec | 2 +- 2 files changed, 53 insertions(+), 1 deletion(-)
diff --git a/dlls/oleacc/main.c b/dlls/oleacc/main.c index f6b66a8bcab..db05d9dac92 100644 --- a/dlls/oleacc/main.c +++ b/dlls/oleacc/main.c @@ -331,6 +331,58 @@ HRESULT WINAPI AccessibleObjectFromPoint( POINT ptScreen, IAccessible** ppacc, V return E_NOTIMPL; }
+HRESULT WINAPI AccessibleObjectFromEvent( HWND hwnd, DWORD dwObjectID, DWORD dwChildID, + IAccessible** ppacc, VARIANT* pvarChild ) +{ + IAccessible *iface = NULL; + IDispatch *disp = NULL; + VARIANT vid; + HRESULT hr; + + TRACE("%p %d %d %p %p\n", hwnd, dwObjectID, dwChildID, ppacc, pvarChild); + + hr = AccessibleObjectFromWindow(hwnd, dwObjectID, &IID_IAccessible, (void **)&iface); + if (!SUCCEEDED(hr)) + return hr; + + *ppacc = iface; + VariantInit(&vid); + V_VT(&vid) = VT_I4; + V_I4(&vid) = dwChildID; + + /* + * FIXME: Should also probably handle the possibility that the child isn't + * an object itself. + */ + hr = IAccessible_get_accChild(iface, vid, &disp); + + /* + * If we fail to get a child with the given ChildID, we instead return the + * IAccessible interface we retrieved from AccessibleObjectFromWindow. + */ + if (SUCCEEDED(hr)) + { + hr = IDispatch_QueryInterface(disp, &IID_IAccessible, (void **)ppacc); + if (SUCCEEDED(hr)) + { + V_I4(&vid) = CHILDID_SELF; + IAccessible_Release(iface); + } + else + { + *ppacc = iface; + } + + IDispatch_Release(disp); + } + + VariantInit(pvarChild); + V_VT(pvarChild) = VT_I4; + V_I4(pvarChild) = V_I4(&vid); + + return S_OK; +} + HRESULT WINAPI AccessibleObjectFromWindow( HWND hwnd, DWORD dwObjectID, REFIID riid, void** ppvObject ) { diff --git a/dlls/oleacc/oleacc.spec b/dlls/oleacc/oleacc.spec index 4cff0b8effc..9ad6e915965 100644 --- a/dlls/oleacc/oleacc.spec +++ b/dlls/oleacc/oleacc.spec @@ -1,5 +1,5 @@ @ stdcall AccessibleChildren(ptr long long ptr ptr) -@ stub AccessibleObjectFromEvent +@ stdcall AccessibleObjectFromEvent(ptr long long ptr ptr) @ stdcall AccessibleObjectFromPoint(int64 ptr ptr) @ stdcall AccessibleObjectFromWindow(ptr long ptr ptr) @ stdcall CreateStdAccessibleObject(ptr long ptr ptr)
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- -This may need more tests, I'm struggling to think up more. -V2: Remove wprintf debugging function left in by accident. --- dlls/oleacc/tests/main.c | 619 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 619 insertions(+)
diff --git a/dlls/oleacc/tests/main.c b/dlls/oleacc/tests/main.c index ce44e06abe4..c8cd1d991bd 100644 --- a/dlls/oleacc/tests/main.c +++ b/dlls/oleacc/tests/main.c @@ -304,6 +304,566 @@ static IAccessibleVtbl AccessibleVtbl = {
static IAccessible Accessible = {&AccessibleVtbl};
+/* + * Create a tree of objects that looks like this: + * --ACC_OBJ_ID_MAIN, + * ----ACC_OBJ_ID_CHILD_0, + * ----ACC_OBJ_ID_CHILD_1, + * ------ACC_OBJ_ID_CHILD_1_0, + * ------ACC_OBJ_ID_CHILD_1_1, + * --------ACC_OBJ_ID_CHILD_1_1_0 + * ------ACC_OBJ_ID_CHILD_1_2, + * ----ACC_OBJ_ID_CHILD_2, + * ------ACC_OBJ_ID_CHILD_2_0, + */ +enum { + ACC_OBJ_ID_NONE = -1, + ACC_OBJ_ID_MAIN = 1, + ACC_OBJ_ID_CHILD_0, + ACC_OBJ_ID_CHILD_1, + ACC_OBJ_ID_CHILD_1_0, + ACC_OBJ_ID_CHILD_1_1, + ACC_OBJ_ID_CHILD_1_1_0, + ACC_OBJ_ID_CHILD_1_2, + ACC_OBJ_ID_CHILD_2, + ACC_OBJ_ID_CHILD_2_0, +}; + +/* + * Custom accesibility tree object info structure. + */ +typedef struct { + const WCHAR *obj_name; + + int parent_id, child_id, child_pos; + unsigned int child_count, role; +} acc_object_info; + +typedef struct { + IAccessible IAccessible_iface; + IEnumVARIANT IEnumVARIANT_iface; + + LONG ref; + + BSTR name; + HWND hwnd; + UINT child_id, role, enum_pos; + + IAccessible *parent; + + UINT child_count; + IAccessible **children; +} Server; + +Server *server_obj_tree = NULL; + +const acc_object_info obj_tree_info[] = { + { .obj_name = L"acc_main", + .parent_id = ACC_OBJ_ID_NONE, + .child_id = ACC_OBJ_ID_MAIN, + .child_pos = 0, + .child_count = 3, + .role = ROLE_SYSTEM_DIALOG, + }, + { .obj_name = L"acc_child_0", + .parent_id = ACC_OBJ_ID_MAIN, + .child_id = ACC_OBJ_ID_CHILD_0, + .child_pos = 0, + .child_count = 0, + .role = ROLE_SYSTEM_CHECKBUTTON, + }, + { .obj_name = L"acc_child_1", + .parent_id = ACC_OBJ_ID_MAIN, + .child_id = ACC_OBJ_ID_CHILD_1, + .child_pos = 1, + .child_count = 3, + .role = ROLE_SYSTEM_CHECKBUTTON, + }, + { .obj_name = L"acc_child_1_0", + .parent_id = ACC_OBJ_ID_CHILD_1, + .child_id = ACC_OBJ_ID_CHILD_1_0, + .child_pos = 0, + .child_count = 0, + .role = ROLE_SYSTEM_CHECKBUTTON, + }, + { .obj_name = L"acc_child_1_1", + .parent_id = ACC_OBJ_ID_CHILD_1, + .child_id = ACC_OBJ_ID_CHILD_1_1, + .child_pos = 1, + .child_count = 1, + .role = ROLE_SYSTEM_CHECKBUTTON, + }, + { .obj_name = L"acc_child_1_1_0", + .parent_id = ACC_OBJ_ID_CHILD_1_1, + .child_id = ACC_OBJ_ID_CHILD_1_1_0, + .child_pos = 0, + .child_count = 0, + .role = ROLE_SYSTEM_CHECKBUTTON, + }, + { .obj_name = L"acc_child_1_2", + .parent_id = ACC_OBJ_ID_CHILD_1, + .child_id = ACC_OBJ_ID_CHILD_1_2, + .child_pos = 2, + .child_count = 0, + .role = ROLE_SYSTEM_CHECKBUTTON, + }, + { .obj_name = L"acc_child_2", + .parent_id = ACC_OBJ_ID_MAIN, + .child_id = ACC_OBJ_ID_CHILD_2, + .child_pos = 2, + .child_count = 1, + .role = ROLE_SYSTEM_CHECKBUTTON, + }, + { .obj_name = L"acc_child_2_0", + .parent_id = ACC_OBJ_ID_CHILD_2, + .child_id = ACC_OBJ_ID_CHILD_2_0, + .child_pos = 0, + .child_count = 0, + .role = ROLE_SYSTEM_CHECKBUTTON, + }, +}; + +/* + * Custom server IAccessible. + */ +static inline Server* impl_from_Server(IAccessible *iface) +{ + return CONTAINING_RECORD(iface, Server, IAccessible_iface); +} + +static void find_accessible(IAccessible *iface, IAccessible **found, UINT child_id) +{ + Server *data = impl_from_Server(iface); + LONG i; + + for (i = 0; i < data->child_count; i++) + { + Server *child = impl_from_Server(data->children[i]); + + if (child->child_id == child_id) + { + *found = &child->IAccessible_iface; + return; + } + + if (child->child_count) + find_accessible(&child->IAccessible_iface, found, child_id); + + if (*found) + return; + } +} + +HRESULT WINAPI Server_QueryInterface(IAccessible *iface, REFIID riid, void **ppv) +{ + Server *This = impl_from_Server(iface); + + if(IsEqualIID(riid, &IID_IAccessible) || + IsEqualIID(riid, &IID_IDispatch) || + IsEqualIID(riid, &IID_IUnknown)) { + *ppv = iface; + }else if(IsEqualIID(riid, &IID_IEnumVARIANT)) { + *ppv = &This->IEnumVARIANT_iface; + }else { + *ppv = NULL; + return E_NOINTERFACE; + } + + IAccessible_AddRef(iface); + return S_OK; +} + +ULONG WINAPI Server_AddRef(IAccessible *iface) +{ + Server *This = impl_from_Server(iface); + return InterlockedIncrement(&This->ref); +} + +ULONG WINAPI Server_Release(IAccessible *iface) +{ + Server *This = impl_from_Server(iface); + return InterlockedDecrement(&This->ref); +} + +HRESULT WINAPI Server_GetTypeInfoCount( + IAccessible *iface, UINT *pctinfo) +{ + *pctinfo = 0; + + return S_OK; +} + +HRESULT WINAPI Server_GetTypeInfo(IAccessible *iface, + UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) +{ + *ppTInfo = NULL; + + return S_OK; +} + +HRESULT WINAPI Server_GetIDsOfNames(IAccessible *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + return E_NOTIMPL; +} + +HRESULT WINAPI Server_Invoke(IAccessible *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + return S_OK; +} + +HRESULT WINAPI Server_get_accParent( + IAccessible *iface, IDispatch **ppdispParent) +{ + Server *This = impl_from_Server(iface); + + if (This->parent) + { + Server_QueryInterface(This->parent, &IID_IDispatch, (void **)ppdispParent); + return S_OK; + } + + *ppdispParent = NULL; + + return S_FALSE; +} + +HRESULT WINAPI Server_get_accChildCount( + IAccessible *iface, LONG *pcountChildren) +{ + Server *This = impl_from_Server(iface); + + *pcountChildren = This->child_count; + + return S_OK; +} + +HRESULT WINAPI Server_get_accChild(IAccessible *iface, + VARIANT varChildID, IDispatch **ppdispChild) +{ + IAccessible *child = NULL; + + if (V_VT(&varChildID) != VT_I4) + return E_FAIL; + + if (V_I4(&varChildID) == CHILDID_SELF) + child = iface; + else + find_accessible(iface, &child, V_I4(&varChildID)); + + if (child) + { + Server_QueryInterface(child, &IID_IDispatch, (void **)ppdispChild); + return S_OK; + } + + return E_FAIL; +} + +HRESULT WINAPI Server_get_accName(IAccessible *iface, + VARIANT varID, BSTR *pszName) +{ + Server *This = impl_from_Server(iface); + + *pszName = This->name; + + return S_OK; +} + +HRESULT WINAPI Server_get_accValue(IAccessible *iface, + VARIANT varID, BSTR *pszValue) +{ + return E_NOTIMPL; +} + +HRESULT WINAPI Server_get_accDescription(IAccessible *iface, + VARIANT varID, BSTR *pszDescription) +{ + return E_NOTIMPL; +} + +HRESULT WINAPI Server_get_accRole(IAccessible *iface, + VARIANT varID, VARIANT *pvarRole) +{ + Server *This = impl_from_Server(iface); + + if ((V_VT(&varID) == VT_I4) && (V_I4(&varID) == CHILDID_SELF)) + { + V_VT(pvarRole) = VT_I4; + V_I4(pvarRole) = This->role; + + return S_OK; + } + + return E_INVALIDARG; +} + +HRESULT WINAPI Server_get_accState(IAccessible *iface, + VARIANT varID, VARIANT *pvarState) +{ + return E_NOTIMPL; +} + +HRESULT WINAPI Server_get_accHelp(IAccessible *iface, + VARIANT varID, BSTR *pszHelp) +{ + return E_NOTIMPL; +} + +HRESULT WINAPI Server_get_accHelpTopic(IAccessible *iface, + BSTR *pszHelpFile, VARIANT varID, LONG *pidTopic) +{ + return E_NOTIMPL; +} + +HRESULT WINAPI Server_get_accKeyboardShortcut(IAccessible *iface, + VARIANT varID, BSTR *pszKeyboardShortcut) +{ + return E_NOTIMPL; +} + +HRESULT WINAPI Server_get_accFocus(IAccessible *iface, VARIANT *pvarID) +{ + return E_NOTIMPL; +} + +HRESULT WINAPI Server_get_accSelection( + IAccessible *iface, VARIANT *pvarID) +{ + return E_NOTIMPL; +} + +HRESULT WINAPI Server_get_accDefaultAction(IAccessible *iface, + VARIANT varID, BSTR *pszDefaultAction) +{ + return E_NOTIMPL; +} + +HRESULT WINAPI Server_accSelect(IAccessible *iface, + LONG flagsSelect, VARIANT varID) +{ + return E_NOTIMPL; +} + +HRESULT WINAPI Server_accLocation(IAccessible *iface, LONG *pxLeft, + LONG *pyTop, LONG *pcxWidth, LONG *pcyHeight, VARIANT varID) +{ + return E_NOTIMPL; +} + +HRESULT WINAPI Server_accNavigate(IAccessible *iface, + LONG navDir, VARIANT varStart, VARIANT *pvarEnd) +{ + return E_NOTIMPL; +} + +HRESULT WINAPI Server_accHitTest(IAccessible *iface, + LONG xLeft, LONG yTop, VARIANT *pvarID) +{ + return E_NOTIMPL; +} + +HRESULT WINAPI Server_accDoDefaultAction( + IAccessible *iface, VARIANT varID) +{ + return E_NOTIMPL; +} + +HRESULT WINAPI Server_put_accName(IAccessible *iface, + VARIANT varID, BSTR pszName) +{ + return E_NOTIMPL; +} + +HRESULT WINAPI Server_put_accValue(IAccessible *iface, + VARIANT varID, BSTR pszValue) +{ + return E_NOTIMPL; +} + +IAccessibleVtbl ServerAccessibleVtbl = { + Server_QueryInterface, + Server_AddRef, + Server_Release, + Server_GetTypeInfoCount, + Server_GetTypeInfo, + Server_GetIDsOfNames, + Server_Invoke, + Server_get_accParent, + Server_get_accChildCount, + Server_get_accChild, + Server_get_accName, + Server_get_accValue, + Server_get_accDescription, + Server_get_accRole, + Server_get_accState, + Server_get_accHelp, + Server_get_accHelpTopic, + Server_get_accKeyboardShortcut, + Server_get_accFocus, + Server_get_accSelection, + Server_get_accDefaultAction, + Server_accSelect, + Server_accLocation, + Server_accNavigate, + Server_accHitTest, + Server_accDoDefaultAction, + Server_put_accName, + Server_put_accValue +}; + +/* + * Server enumVARIANT Vtbl. + */ +inline Server* impl_from_Server_EnumVARIANT(IEnumVARIANT *iface) +{ + return CONTAINING_RECORD(iface, Server, IEnumVARIANT_iface); +} + +HRESULT WINAPI Server_EnumVARIANT_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **ppv) +{ + Server *This = impl_from_Server_EnumVARIANT(iface); + return IAccessible_QueryInterface(&This->IAccessible_iface, riid, ppv); +} + +ULONG WINAPI Server_EnumVARIANT_AddRef(IEnumVARIANT *iface) +{ + Server *This = impl_from_Server_EnumVARIANT(iface); + return IAccessible_AddRef(&This->IAccessible_iface); +} + +ULONG WINAPI Server_EnumVARIANT_Release(IEnumVARIANT *iface) +{ + Server *This = impl_from_Server_EnumVARIANT(iface); + return IAccessible_Release(&This->IAccessible_iface); +} + +HRESULT WINAPI Server_EnumVARIANT_Next(IEnumVARIANT *iface, + ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched) +{ + Server *This = impl_from_Server_EnumVARIANT(iface); + ULONG fetched = 0; + UINT i; + + for (i = This->enum_pos; i < This->child_count; i++) + { + Server *child = impl_from_Server(This->children[i]); + + V_VT(&rgVar[i]) = VT_I4; + V_I4(&rgVar[i]) = child->child_id; + fetched++; + } + + *pCeltFetched = fetched; + + return celt == fetched ? S_OK : S_FALSE; +} + +HRESULT WINAPI Server_EnumVARIANT_Skip(IEnumVARIANT *iface, ULONG celt) +{ + Server *This = impl_from_Server_EnumVARIANT(iface); + + if ((celt + This->enum_pos) < This->child_count) + { + This->enum_pos += celt; + return S_OK; + } + + return S_FALSE; +} + +HRESULT WINAPI Server_EnumVARIANT_Reset(IEnumVARIANT *iface) +{ + Server *This = impl_from_Server_EnumVARIANT(iface); + + This->enum_pos = 0; + + return S_OK; +} + +HRESULT WINAPI Server_EnumVARIANT_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum) +{ + return E_NOTIMPL; +} + +const IEnumVARIANTVtbl ServerEnumVARIANTVtbl = { + Server_EnumVARIANT_QueryInterface, + Server_EnumVARIANT_AddRef, + Server_EnumVARIANT_Release, + Server_EnumVARIANT_Next, + Server_EnumVARIANT_Skip, + Server_EnumVARIANT_Reset, + Server_EnumVARIANT_Clone +}; + +static HRESULT create_server_obj_tree(Server **tree, HWND hwnd) +{ + Server *acc_objs; + unsigned int i; + + if (!IsWindow(hwnd)) + return E_FAIL; + + acc_objs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(*acc_objs) * ARRAY_SIZE(obj_tree_info)); + if (!acc_objs) + return E_OUTOFMEMORY; + + for (i = 0; i < ARRAY_SIZE(obj_tree_info); i++) + { + const acc_object_info *obj_info = &obj_tree_info[i]; + Server *obj = &acc_objs[i]; + + obj->IAccessible_iface.lpVtbl = &ServerAccessibleVtbl; + obj->IEnumVARIANT_iface.lpVtbl = &ServerEnumVARIANTVtbl; + obj->ref = 1; + obj->hwnd = hwnd; + obj->name = SysAllocString(obj_info->obj_name); + if (!obj->name && obj_info->obj_name) + return E_OUTOFMEMORY; + obj->child_id = obj_info->child_id; + obj->role = obj_info->role; + obj->child_count = obj_info->child_count; + if (obj->child_count) + { + obj->children = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(*obj->children) * obj->child_count); + if (!obj->children) + return E_OUTOFMEMORY; + } + + if (obj_info->parent_id >= 0) + { + obj->parent = &acc_objs[obj_info->parent_id - 1].IAccessible_iface; + acc_objs[obj_info->parent_id - 1].children[obj_info->child_pos] = &obj->IAccessible_iface; + } + } + + *tree = acc_objs; + + return S_OK; +} + +static void free_server_obj_tree(Server *tree) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(obj_tree_info); i++) + { + Server *obj = &tree[i]; + + if (obj->name) + SysFreeString(obj->name); + if (obj->children) + HeapFree(GetProcessHeap(), 0, obj->children); + IAccessible_Release(&obj->IAccessible_iface); + } + + HeapFree(GetProcessHeap(), 0, tree); +} + static void test_getroletext(void) { INT ret, role; @@ -564,7 +1124,13 @@ static LRESULT WINAPI test_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARA if(lparam == (DWORD)OBJID_CURSOR) return E_UNEXPECTED; if(lparam == (DWORD)OBJID_CLIENT) + { + if (server_obj_tree) + return LresultFromObject(&IID_IAccessible, wparam, + (IUnknown *)&server_obj_tree->IAccessible_iface); + return LresultFromObject(&IID_IUnknown, wparam, &Object); + } if(lparam == (DWORD)OBJID_WINDOW) return 0;
@@ -621,6 +1187,58 @@ static void test_AccessibleObjectFromWindow(void) DestroyWindow(hwnd); }
+static void test_AccessibleObjectFromEvent(void) +{ + IAccessible *acc = NULL; + BSTR name = NULL; + VARIANT var; + HRESULT hr; + HWND hwnd; + + hwnd = CreateWindowA("oleacc_test", "test", WS_OVERLAPPEDWINDOW, + 0, 0, 0, 0, NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "CreateWindow failed\n"); + + hr = create_server_obj_tree(&server_obj_tree, hwnd); + ok(SUCCEEDED(hr), "got %#x\n", hr); + + hr = AccessibleObjectFromEvent(hwnd, OBJID_CLIENT, CHILDID_SELF, &acc, &var); + ok(SUCCEEDED(hr), "got %#x\n", hr); + + hr = IAccessible_get_accName(acc, var, &name); + ok(SUCCEEDED(hr), "got %#x\n", hr); + ok(!lstrcmpW(name, L"acc_main"), "name = %s\n", wine_dbgstr_w(name)); + IAccessible_Release(acc); + + acc = NULL; + hr = AccessibleObjectFromEvent(hwnd, OBJID_CLIENT, ACC_OBJ_ID_CHILD_1_1_0, &acc, &var); + ok(SUCCEEDED(hr), "got %#x\n", hr); + ok(V_VT(&var) == VT_I4, "got %#x, expected %#x\n", V_VT(&var), VT_I4); + ok(V_I4(&var) == CHILDID_SELF, "got %#x, expected %#x\n", V_I4(&var), CHILDID_SELF); + + hr = IAccessible_get_accName(acc, var, &name); + ok(SUCCEEDED(hr), "got %#x\n", hr); + ok(!lstrcmpW(name, L"acc_child_1_1_0"), "name = %s\n", wine_dbgstr_w(name)); + IAccessible_Release(acc); + + /* + * Invalid Child ID, in this case we just get the same result as + * AccessibleObjectFromWindow. + */ + acc = NULL; + hr = AccessibleObjectFromEvent(hwnd, OBJID_CLIENT, ACC_OBJ_ID_CHILD_2_0 + 1, &acc, &var); + ok(SUCCEEDED(hr), "got %#x\n", hr); + + hr = IAccessible_get_accName(acc, var, &name); + ok(SUCCEEDED(hr), "got %#x\n", hr); + ok(!lstrcmpW(name, L"acc_main"), "name = %s\n", wine_dbgstr_w(name)); + IAccessible_Release(acc); + + DestroyWindow(hwnd); + free_server_obj_tree(server_obj_tree); + server_obj_tree = NULL; +} + static void test_GetProcessHandleFromHwnd(void) { HANDLE proc; @@ -1061,6 +1679,7 @@ START_TEST(main) test_GetProcessHandleFromHwnd(); test_default_client_accessible_object(); test_AccessibleChildren(&Accessible); + test_AccessibleObjectFromEvent();
unregister_window_class(); CoUninitialize();
On Mon, May 24, 2021 at 10:15:23PM -0400, Connor McAdams wrote:
Signed-off-by: Connor McAdams cmcadams@codeweavers.com
dlls/oleacc/main.c | 52 +++++++++++++++++++++++++++++++++++++++++ dlls/oleacc/oleacc.spec | 2 +- 2 files changed, 53 insertions(+), 1 deletion(-)
diff --git a/dlls/oleacc/main.c b/dlls/oleacc/main.c index f6b66a8bcab..db05d9dac92 100644 --- a/dlls/oleacc/main.c +++ b/dlls/oleacc/main.c @@ -331,6 +331,58 @@ HRESULT WINAPI AccessibleObjectFromPoint( POINT ptScreen, IAccessible** ppacc, V return E_NOTIMPL; }
+HRESULT WINAPI AccessibleObjectFromEvent( HWND hwnd, DWORD dwObjectID, DWORD dwChildID,
IAccessible** ppacc, VARIANT* pvarChild )
+{
- IAccessible *iface = NULL;
- IDispatch *disp = NULL;
- VARIANT vid;
- HRESULT hr;
- TRACE("%p %d %d %p %p\n", hwnd, dwObjectID, dwChildID, ppacc, pvarChild);
- hr = AccessibleObjectFromWindow(hwnd, dwObjectID, &IID_IAccessible, (void **)&iface);
- if (!SUCCEEDED(hr))
return hr;
- *ppacc = iface;
- VariantInit(&vid);
- V_VT(&vid) = VT_I4;
- V_I4(&vid) = dwChildID;
- /*
* FIXME: Should also probably handle the possibility that the child isn't
* an object itself.
*/
- hr = IAccessible_get_accChild(iface, vid, &disp);
- /*
* If we fail to get a child with the given ChildID, we instead return the
* IAccessible interface we retrieved from AccessibleObjectFromWindow.
*/
- if (SUCCEEDED(hr))
- {
hr = IDispatch_QueryInterface(disp, &IID_IAccessible, (void **)ppacc);
if (SUCCEEDED(hr))
{
V_I4(&vid) = CHILDID_SELF;
IAccessible_Release(iface);
}
else
{
*ppacc = iface;
}
IDispatch_Release(disp);
- }
- VariantInit(pvarChild);
- V_VT(pvarChild) = VT_I4;
- V_I4(pvarChild) = V_I4(&vid);
- return S_OK;
+}
HRESULT WINAPI AccessibleObjectFromWindow( HWND hwnd, DWORD dwObjectID, REFIID riid, void** ppvObject ) { diff --git a/dlls/oleacc/oleacc.spec b/dlls/oleacc/oleacc.spec index 4cff0b8effc..9ad6e915965 100644 --- a/dlls/oleacc/oleacc.spec +++ b/dlls/oleacc/oleacc.spec @@ -1,5 +1,5 @@ @ stdcall AccessibleChildren(ptr long long ptr ptr) -@ stub AccessibleObjectFromEvent +@ stdcall AccessibleObjectFromEvent(ptr long long ptr ptr) @ stdcall AccessibleObjectFromPoint(int64 ptr ptr) @ stdcall AccessibleObjectFromWindow(ptr long ptr ptr) @ stdcall CreateStdAccessibleObject(ptr long ptr ptr) -- 2.25.1
This patch for now can be ignored, I've since figured out how the ChildID's are supposed to be treated if they aren't associated with an object, and am in the process of writing new tests to account for this.