Hi Connor,
On 8/30/21 5:27 PM, Connor McAdams wrote:
+typedef struct {
- IAccessible IAccessible_iface;
- IEnumVARIANT IEnumVARIANT_iface;
- LONG ref;
- const acc_tree_object_info *info;
- HWND hwnd;
- UINT enum_pos;
- IAccessible *parent;
- IAccessible **children;
You can just define it as: IAccessible *children[3]; and avoid allocations/frees.
+} AccTreeObject;
+AccTreeObject *object_tree = NULL; +BOOL acc_query_interface_test_fail = FALSE;
static
+static IAccessible *get_acc_tree_obj_child(IAccessible *iface, VARIANT child_id) +{
- AccTreeObject *obj = impl_from_AccTreeObject(iface);
- IAccessible *acc = NULL;
- LONG i;
- if (V_VT(&child_id) != VT_I4)
return NULL;- if (V_I4(&child_id) == CHILDID_SELF)
return iface;- for (i = 0; i < obj->info->child_count; i++)
- {
AccTreeObject *child = impl_from_AccTreeObject(obj->children[i]);if (child->info->child_id == V_I4(&child_id)){acc = &child->IAccessible_iface;
Even so it's internal function it's good to update refcount: IAccessible_AddRef(acc); There's lot's of places that are hard to follow without it.
+static void check_acc_tree_obj_for_child(IAccessible *acc,
INT child_id, IAccessible **found_acc, VARIANT *found_vid)+{
- IDispatch *disp_child;
- VARIANT vid;
- HRESULT hr;
- V_VT(&vid) = VT_I4;
- V_I4(&vid) = child_id;
- hr = IAccessible_get_accChild(acc, vid, &disp_child);
- if (SUCCEEDED(hr))
- {
/** If S_FALSE is returned, the childID was found, but it's a simple* element.*/if (hr == S_FALSE){*found_acc = acc;V_VT(found_vid) = VT_I4;V_I4(found_vid) = child_id;}else{IDispatch_QueryInterface(disp_child, &IID_IAccessible,(void **)found_acc);V_VT(found_vid) = VT_I4;V_I4(found_vid) = CHILDID_SELF;IDispatch_Release(disp_child);}- }
+}
The function depends on found_acc and found_vid to be initialized to handle get_accChild errors. While it's a helper it's still not the best design. You can also avoid indentation level by returning early on get_accChild failure.
- children = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(*children) * child_cnt);- hr = AccessibleChildren(acc, 0, child_cnt, children, &rcv);
- ok(SUCCEEDED(hr), "AccessibleChildren failed with %#x!\n", hr);
It would be better to check exact hr value: ok(hr == S_OK, ...
+static void search_acc_tree_for_child_navigate(IAccessible *acc,
INT child_id, IAccessible **found_acc, VARIANT *found_vid)+{
- VARIANT vid, res;
- HRESULT hr;
- check_acc_tree_obj_for_child(acc, child_id, found_acc, found_vid);
- if (*found_acc)
return;- V_VT(&vid) = VT_I4;
- V_I4(&vid) = CHILDID_SELF;
- hr = IAccessible_accNavigate(acc, NAVDIR_FIRSTCHILD, vid, &res);
- if (FAILED(hr))
return;- while (SUCCEEDED(hr) && V_VT(&res) != VT_EMPTY && !(*found_acc))
- {
switch (V_VT(&res)){case VT_I4:vid = res;hr = IAccessible_accNavigate(acc, NAVDIR_NEXT, vid, &res);break;case VT_DISPATCH:{IAccessible *acc_child;hr = IDispatch_QueryInterface(V_DISPATCH(&res), &IID_IAccessible, (void **)&acc_child);IDispatch_Release(V_DISPATCH(&res));if (SUCCEEDED(hr)){search_acc_tree_for_child_navigate(acc_child, child_id, found_acc, found_vid);if (!(*found_acc)){V_VT(&vid) = VT_I4;V_I4(&vid) = CHILDID_SELF;hr = IAccessible_accNavigate(acc_child, NAVDIR_NEXT, vid, &res);}if (*found_acc != acc_child)IAccessible_Release(acc_child);}break;}/** Shouldn't ever reach here, if type isn't VT_I4 or VT_DISPATCH,* we've got a problem.*/default:return;
It's better to remove the comment and add something like: ok(0, ...
+HRESULT WINAPI AccTreeObject_GetTypeInfoCount(
IAccessible *iface, UINT *pctinfo)+{
- *pctinfo = 0;
- return S_OK;
+}
The function is not called. It's better to do something like: ok(0, "unexpected call\n"); return E_NOTIMPL; The same applies to other IDispatch methods (the ok() call may be even skipped).
+HRESULT WINAPI AccTreeObject_get_accParent(
IAccessible *iface, IDispatch **ppdispParent)+{
- AccTreeObject *This = impl_from_AccTreeObject(iface);
- *ppdispParent = NULL;
- if (This->parent)
- {
IAccessible_QueryInterface(This->parent, &IID_IDispatch, (void **)ppdispParent);- return S_OK;
- }
- return S_FALSE;
There's a '\t' before return S_OK. I would implement the function in following way: if (This->parent) return IAccessible_QueryInterface(...); *ppdispParent = NULL; return S_FALSE; It would be also nice to change the ppdispParent argument name.
+static void test_AccessibleObjectFromEvent(void) +{
- IAccessible *acc, *acc_child;
- const WCHAR *expected_name;
- BSTR obj_name;
- VARIANT cid;
- 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_acc_obj_tree(acc_from_event_obj_tree,
ARRAY_SIZE(acc_from_event_obj_tree));- if (FAILED(hr))
- {
trace("Failed to create accessible object tree, hr %#x, aborting test.\n", hr);DestroyWindow(hwnd);return;- }
Are you ever expecting it to fail? A simple ok(hr == S_OK, ...) should be enough.
Thanks, Piotr