From: Esme Povirk esme@codeweavers.com
--- dlls/comctl32/tests/Makefile.in | 2 +- dlls/comctl32/tests/syslink.c | 49 +++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-)
diff --git a/dlls/comctl32/tests/Makefile.in b/dlls/comctl32/tests/Makefile.in index 0c96203a2f6..ee7fe6527fe 100644 --- a/dlls/comctl32/tests/Makefile.in +++ b/dlls/comctl32/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = comctl32.dll -IMPORTS = ole32 user32 gdi32 advapi32 imm32 uxtheme +IMPORTS = ole32 user32 gdi32 advapi32 imm32 uxtheme oleacc oleaut32
SOURCES = \ animate.c \ diff --git a/dlls/comctl32/tests/syslink.c b/dlls/comctl32/tests/syslink.c index f6c31d92981..0dd905aa81e 100644 --- a/dlls/comctl32/tests/syslink.c +++ b/dlls/comctl32/tests/syslink.c @@ -17,9 +17,13 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#define COBJMACROS #include <windows.h> #include <commctrl.h>
+#include <initguid.h> +#include <oleacc.h> + #include "wine/test.h" #include "v6util.h" #include "msg.h" @@ -275,6 +279,50 @@ static void test_link_id(void) DestroyWindow(hwnd); }
+static void test_msaa(void) +{ + HWND hwnd; + HRESULT hr; + LRESULT lr; + IAccessible *acc; + VARIANT varChild, varResult; + + hwnd = create_syslink(WS_CHILD | WS_TABSTOP | WS_VISIBLE, hWndParent); + ok(hwnd != NULL, "Failed to create SysLink window.\n"); + + lr = SendMessageA(hwnd, WM_GETOBJECT, 0, OBJID_CLIENT); + todo_wine ok(lr != 0, "No IAccessible object\n"); + if (lr == 0) + { + DestroyWindow(hwnd); + return; + } + + hr = ObjectFromLresult(lr, &IID_IAccessible, 0, (void**)&acc); + ok(hr == S_OK, "ObjectFromLresult failed, hr=%lx", hr); + + VariantInit(&varChild); + VariantInit(&varResult); + + V_VT(&varChild) = VT_I4; + V_I4(&varChild) = CHILDID_SELF; + + hr = IAccessible_get_accRole(acc, varChild, &varResult); + ok(hr == S_OK, "accRole failed, hr=%lx\n", hr); + ok(V_VT(&varResult) == VT_I4, "accRole returned vt=%x\n", V_VT(&varResult)); + ok(V_I4(&varResult) == ROLE_SYSTEM_CLIENT, "accRole returned %li\n", V_I4(&varResult)); + + VariantClear(&varResult); + hr = IAccessible_get_accState(acc, varChild, &varResult); + ok(hr == S_OK, "accState failed, hr=%lx\n", hr); + ok(V_VT(&varResult) == VT_I4, "accState returned vt=%x\n", V_VT(&varResult)); + ok(V_I4(&varResult) == STATE_SYSTEM_FOCUSABLE, "accState returned %li\n", V_I4(&varResult)); + + IAccessible_Release(acc); + + DestroyWindow(hwnd); +} + START_TEST(syslink) { ULONG_PTR ctx_cookie; @@ -304,6 +352,7 @@ START_TEST(syslink) test_LM_GETIDEALHEIGHT(); test_LM_GETIDEALSIZE(); test_link_id(); + test_msaa();
DestroyWindow(hWndParent); unload_v6_module(ctx_cookie, hCtx);
From: Esme Povirk esme@codeweavers.com
--- dlls/comctl32/tests/syslink.c | 109 +++++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-)
diff --git a/dlls/comctl32/tests/syslink.c b/dlls/comctl32/tests/syslink.c index 0dd905aa81e..318a68961ec 100644 --- a/dlls/comctl32/tests/syslink.c +++ b/dlls/comctl32/tests/syslink.c @@ -281,11 +281,15 @@ static void test_link_id(void)
static void test_msaa(void) { - HWND hwnd; + HWND hwnd, ret_hwnd; HRESULT hr; LRESULT lr; IAccessible *acc; VARIANT varChild, varResult; + BSTR name; + LONG left, top, width, height, count=0; + IDispatch *child; + IOleWindow *ole_window;
hwnd = create_syslink(WS_CHILD | WS_TABSTOP | WS_VISIBLE, hWndParent); ok(hwnd != NULL, "Failed to create SysLink window.\n"); @@ -318,6 +322,109 @@ static void test_msaa(void) ok(V_VT(&varResult) == VT_I4, "accState returned vt=%x\n", V_VT(&varResult)); ok(V_I4(&varResult) == STATE_SYSTEM_FOCUSABLE, "accState returned %li\n", V_I4(&varResult));
+ hr = IAccessible_get_accName(acc, varChild, &name); + ok(hr == S_OK, "accName failed, hr=%lx\n", hr); + if (SUCCEEDED(hr)) { + ok(!!name && !wcscmp(name, L"Head Name1 Middle Name2 Tail"), + "unexpected name %s\n", debugstr_w(name)); + SysFreeString(name); + } + + hr = IAccessible_get_accDefaultAction(acc, varChild, &name); + ok(hr == S_FALSE, "accDefaultAction failed, hr=%lx\n", hr); + if (SUCCEEDED(hr)) + ok(!name, "unexpected default action %s\n", debugstr_w(name)); + + hr = IAccessible_accLocation(acc, &left, &top, &width, &height, varChild); + ok(hr == S_OK, "accLocation failed, hr=%lx\n", hr); + + hr = IAccessible_get_accChildCount(acc, &count); + ok(hr == S_OK, "accChildCount failed, hr=%lx\n", hr); + ok(count == 2, "accChildCount returned %li\n", count); + + /* child 1 */ + V_I4(&varChild) = 1; + hr = IAccessible_get_accChild(acc, varChild, &child); + ok(hr == S_FALSE, "accChild hr=%lx\n", hr); + ok(!child, "accChild returned IDispatch\n"); + + hr = IAccessible_get_accRole(acc, varChild, &varResult); + ok(hr == S_OK, "accRole failed, hr=%lx\n", hr); + ok(V_VT(&varResult) == VT_I4, "accRole returned vt=%x\n", V_VT(&varResult)); + ok(V_I4(&varResult) == ROLE_SYSTEM_LINK, "accRole returned %li\n", V_I4(&varResult)); + + VariantClear(&varResult); + hr = IAccessible_get_accState(acc, varChild, &varResult); + ok(hr == S_OK, "accState failed, hr=%lx\n", hr); + ok(V_VT(&varResult) == VT_I4, "accState returned vt=%x\n", V_VT(&varResult)); + ok(V_I4(&varResult) == (STATE_SYSTEM_FOCUSABLE|STATE_SYSTEM_LINKED), "accState returned %li\n", V_I4(&varResult)); + + hr = IAccessible_get_accName(acc, varChild, &name); + ok(hr == S_OK, "accName failed, hr=%lx\n", hr); + if (SUCCEEDED(hr)) { + ok(!!name && !wcscmp(name, L"Name1"), + "unexpected name %s\n", debugstr_w(name)); + SysFreeString(name); + } + + hr = IAccessible_get_accDefaultAction(acc, varChild, &name); + ok(hr == S_OK, "accDefaultAction failed, hr=%lx\n", hr); + if (SUCCEEDED(hr)) + { + ok(!!name && !wcscmp(name, L"Click"), + "unexpected name %s\n", debugstr_w(name)); + SysFreeString(name); + } + + hr = IAccessible_accLocation(acc, &left, &top, &width, &height, varChild); + ok(hr == S_OK, "accLocation failed, hr=%lx\n", hr); + + /* child 2 */ + V_I4(&varChild) = 2; + hr = IAccessible_get_accChild(acc, varChild, &child); + ok(hr == S_FALSE, "accChild hr=%lx\n", hr); + ok(!child, "accChild returned IDispatch\n"); + + hr = IAccessible_get_accRole(acc, varChild, &varResult); + ok(hr == S_OK, "accRole failed, hr=%lx\n", hr); + ok(V_VT(&varResult) == VT_I4, "accRole returned vt=%x\n", V_VT(&varResult)); + ok(V_I4(&varResult) == ROLE_SYSTEM_LINK, "accRole returned %li\n", V_I4(&varResult)); + + VariantClear(&varResult); + hr = IAccessible_get_accState(acc, varChild, &varResult); + ok(hr == S_OK, "accState failed, hr=%lx\n", hr); + ok(V_VT(&varResult) == VT_I4, "accState returned vt=%x\n", V_VT(&varResult)); + ok(V_I4(&varResult) == (STATE_SYSTEM_FOCUSABLE|STATE_SYSTEM_LINKED), "accState returned %li\n", V_I4(&varResult)); + + hr = IAccessible_get_accName(acc, varChild, &name); + ok(hr == S_OK, "accName failed, hr=%lx\n", hr); + if (SUCCEEDED(hr)) { + ok(!!name && !wcscmp(name, L"Name2"), + "unexpected name %s\n", debugstr_w(name)); + SysFreeString(name); + } + + hr = IAccessible_get_accDefaultAction(acc, varChild, &name); + ok(hr == S_OK, "accDefaultAction failed, hr=%lx\n", hr); + if (SUCCEEDED(hr)) + { + ok(!!name && !wcscmp(name, L"Click"), + "unexpected name %s\n", debugstr_w(name)); + SysFreeString(name); + } + + hr = IAccessible_accLocation(acc, &left, &top, &width, &height, varChild); + ok(hr == S_OK, "accLocation failed, hr=%lx\n", hr); + + hr = IAccessible_QueryInterface(acc, &IID_IOleWindow, (void**)&ole_window); + ok(hr == S_OK, "QueryInterface failed, hr=%lx\n", hr); + + hr = IOleWindow_GetWindow(ole_window, &ret_hwnd); + ok(hr == S_OK, "GetWindow failed, hr=%lx\n", hr); + ok(ret_hwnd == hwnd, "GetWindow returned wrong hwnd\n"); + + IOleWindow_Release(ole_window); + IAccessible_Release(acc);
DestroyWindow(hwnd);
From: Esme Povirk esme@codeweavers.com
--- dlls/comctl32/Makefile.in | 2 +- dlls/comctl32/syslink.c | 274 +++++++++++++++++++++++++++++++++- dlls/comctl32/tests/syslink.c | 14 +- 3 files changed, 283 insertions(+), 7 deletions(-)
diff --git a/dlls/comctl32/Makefile.in b/dlls/comctl32/Makefile.in index 8e9a6e44577..383faee35ad 100644 --- a/dlls/comctl32/Makefile.in +++ b/dlls/comctl32/Makefile.in @@ -1,7 +1,7 @@ EXTRADEFS = -D_COMCTL32_ MODULE = comctl32.dll IMPORTLIB = comctl32 -IMPORTS = uuid user32 gdi32 advapi32 imm32 kernelbase +IMPORTS = uuid user32 gdi32 advapi32 imm32 kernelbase oleacc DELAYIMPORTS = winmm uxtheme
SOURCES = \ diff --git a/dlls/comctl32/syslink.c b/dlls/comctl32/syslink.c index f5a70e982c3..76d95b77848 100644 --- a/dlls/comctl32/syslink.c +++ b/dlls/comctl32/syslink.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#define COBJMACROS #include <stdarg.h> #include <string.h> #include "windef.h" @@ -27,6 +28,9 @@ #include "winnls.h" #include "commctrl.h" #include "comctl32.h" +#include "oaidl.h" +#include "initguid.h" +#include "oleacc.h" #include "wine/debug.h" #include "wine/list.h"
@@ -70,7 +74,16 @@ typedef struct _DOC_ITEM WCHAR Text[1]; /* Text of the document item */ } DOC_ITEM, *PDOC_ITEM;
+typedef struct SYSLINK_INFO SYSLINK_INFO; + typedef struct +{ + IAccessible IAccessible_iface; + struct SYSLINK_INFO *infoPtr; + LONG refcount; +} SYSLINK_ACC; + +struct SYSLINK_INFO { HWND Self; /* The window handle for this control */ HWND Notify; /* The parent handle to receive notifications */ @@ -85,7 +98,8 @@ typedef struct COLORREF VisitedColor; /* Color of visited links */ WCHAR BreakChar; /* Break Character for the current font */ BOOL IgnoreReturn; /* (infoPtr->Style & LWS_IGNORERETURN) on creation */ -} SYSLINK_INFO; + SYSLINK_ACC *AccessibleImpl; /* IAccessible implementation */ +};
/* Control configuration constants */
@@ -94,6 +108,251 @@ typedef struct #define SL_RIGHTMARGIN (0) #define SL_BOTTOMMARGIN (0)
+static inline SYSLINK_ACC *impl_from_IAccessible(IAccessible *iface) +{ + return CONTAINING_RECORD(iface, SYSLINK_ACC, IAccessible_iface); +} + +static HRESULT WINAPI Accessible_QueryInterface(IAccessible *iface, REFIID iid, void **ppv) +{ + SYSLINK_ACC *This = impl_from_IAccessible(iface); + TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); + + if (!ppv) return E_INVALIDARG; + + if (IsEqualIID(&IID_IUnknown, iid) || + IsEqualIID(&IID_IAccessible, iid)) + { + *ppv = &This->IAccessible_iface; + } + else + { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI Accessible_AddRef(IAccessible *iface) +{ + SYSLINK_ACC *This = impl_from_IAccessible(iface); + return InterlockedIncrement(&This->refcount); +} + +static ULONG WINAPI Accessible_Release(IAccessible *iface) +{ + SYSLINK_ACC *This = impl_from_IAccessible(iface); + ULONG ref = InterlockedDecrement(&This->refcount); + + if (ref == 0) + Free(This); + + return ref; +} + +static HRESULT WINAPI Accessible_GetTypeInfo(IAccessible *iface, UINT index, LCID lcid, ITypeInfo **info) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_GetIDsOfNames(IAccessible *iface, REFIID iid, LPOLESTR *names, UINT count, LCID lcid, DISPID *dispid) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_Invoke(IAccessible *iface, DISPID dispid, REFIID iid, LCID lcid, + WORD flags, DISPPARAMS *dispparams, VARIANT *result, EXCEPINFO *excepinfo, UINT *argerr) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_GetTypeInfoCount(IAccessible *iface, UINT *count) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accParent(IAccessible *iface, IDispatch** disp) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accChildCount(IAccessible *iface, long *count) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accChild(IAccessible *iface, VARIANT childid, IDispatch **disp) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accName(IAccessible *iface, VARIANT childid, BSTR *name) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accValue(IAccessible *iface, VARIANT childid, BSTR *value) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accDescription(IAccessible *iface, VARIANT childid, BSTR *description) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accRole(IAccessible *iface, VARIANT childid, VARIANT *role) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accState(IAccessible *iface, VARIANT childid, VARIANT *state) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accHelp(IAccessible *iface, VARIANT childid, BSTR *help) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accHelpTopic(IAccessible *iface, BSTR *helpFile, VARIANT childid, long *topic) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accKeyboardShortcut(IAccessible *iface, VARIANT childid, BSTR *shortcut) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accFocus(IAccessible *iface, VARIANT *childid) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accSelection(IAccessible *iface, VARIANT *childid) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accDefaultAction(IAccessible *iface, VARIANT childid, BSTR *action) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_accSelect(IAccessible *iface, long flags, VARIANT childid) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_accLocation(IAccessible *iface, long *left, long *top, long *width, long *height, VARIANT childid) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_accNavigate(IAccessible *iface, long dir, VARIANT start, VARIANT *end) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_accHitTest(IAccessible *iface, long left, long top, VARIANT* childid) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_accDoDefaultAction(IAccessible *iface, VARIANT childid) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_put_accName(IAccessible *iface, VARIANT childid, BSTR name) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_put_accValue(IAccessible *iface, VARIANT childid, BSTR value) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static const IAccessibleVtbl Accessible_Vtbl = { + Accessible_QueryInterface, + Accessible_AddRef, + Accessible_Release, + Accessible_GetTypeInfoCount, + Accessible_GetTypeInfo, + Accessible_GetIDsOfNames, + Accessible_Invoke, + Accessible_get_accParent, + Accessible_get_accChildCount, + Accessible_get_accChild, + Accessible_get_accName, + Accessible_get_accValue, + Accessible_get_accDescription, + Accessible_get_accRole, + Accessible_get_accState, + Accessible_get_accHelp, + Accessible_get_accHelpTopic, + Accessible_get_accKeyboardShortcut, + Accessible_get_accFocus, + Accessible_get_accSelection, + Accessible_get_accDefaultAction, + Accessible_accSelect, + Accessible_accLocation, + Accessible_accNavigate, + Accessible_accHitTest, + Accessible_accDoDefaultAction, + Accessible_put_accName, + Accessible_put_accValue +}; + +static void Accessible_Create(SYSLINK_INFO* infoPtr) +{ + SYSLINK_ACC *This; + + This = Alloc(sizeof(*This)); + if (!This) return; + + This->IAccessible_iface.lpVtbl = &Accessible_Vtbl; + This->infoPtr = infoPtr; + This->refcount = 1; + infoPtr->AccessibleImpl = This; +} + +static void Accessible_WindowDestroyed(SYSLINK_ACC *This) +{ + This->infoPtr = NULL; + IAccessible_Release(&This->IAccessible_iface); +} + /*********************************************************************** * SYSLINK_FreeDocItem * Frees all data and gdi objects associated with a document item @@ -1713,9 +1972,22 @@ static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message, SYSLINK_ClearDoc(infoPtr); if(infoPtr->LinkFont != 0) DeleteObject(infoPtr->LinkFont); SetWindowLongPtrW(hwnd, 0, 0); + if(infoPtr->AccessibleImpl) Accessible_WindowDestroyed(infoPtr->AccessibleImpl); Free (infoPtr); return 0;
+ case WM_GETOBJECT: + { + if ((DWORD)lParam == (DWORD)OBJID_CLIENT) { + if (!infoPtr->AccessibleImpl) + Accessible_Create(infoPtr); + + if (infoPtr->AccessibleImpl) + return LresultFromObject(&IID_IAccessible, wParam, (IUnknown*)&infoPtr->AccessibleImpl->IAccessible_iface); + } + return DefWindowProcW(hwnd, message, wParam, lParam); + } + case WM_SYSCOLORCHANGE: COMCTL32_RefreshSysColors(); return 0; diff --git a/dlls/comctl32/tests/syslink.c b/dlls/comctl32/tests/syslink.c index 318a68961ec..4ce0daa8c0e 100644 --- a/dlls/comctl32/tests/syslink.c +++ b/dlls/comctl32/tests/syslink.c @@ -295,7 +295,7 @@ static void test_msaa(void) ok(hwnd != NULL, "Failed to create SysLink window.\n");
lr = SendMessageA(hwnd, WM_GETOBJECT, 0, OBJID_CLIENT); - todo_wine ok(lr != 0, "No IAccessible object\n"); + ok(lr != 0, "No IAccessible object\n"); if (lr == 0) { DestroyWindow(hwnd); @@ -311,6 +311,7 @@ static void test_msaa(void) V_VT(&varChild) = VT_I4; V_I4(&varChild) = CHILDID_SELF;
+todo_wine { hr = IAccessible_get_accRole(acc, varChild, &varResult); ok(hr == S_OK, "accRole failed, hr=%lx\n", hr); ok(V_VT(&varResult) == VT_I4, "accRole returned vt=%x\n", V_VT(&varResult)); @@ -418,12 +419,15 @@ static void test_msaa(void)
hr = IAccessible_QueryInterface(acc, &IID_IOleWindow, (void**)&ole_window); ok(hr == S_OK, "QueryInterface failed, hr=%lx\n", hr); +}
- hr = IOleWindow_GetWindow(ole_window, &ret_hwnd); - ok(hr == S_OK, "GetWindow failed, hr=%lx\n", hr); - ok(ret_hwnd == hwnd, "GetWindow returned wrong hwnd\n"); + if (SUCCEEDED(hr)) { + hr = IOleWindow_GetWindow(ole_window, &ret_hwnd); + ok(hr == S_OK, "GetWindow failed, hr=%lx\n", hr); + ok(ret_hwnd == hwnd, "GetWindow returned wrong hwnd\n");
- IOleWindow_Release(ole_window); + IOleWindow_Release(ole_window); + }
IAccessible_Release(acc);
From: Esme Povirk esme@codeweavers.com
--- dlls/comctl32/syslink.c | 59 +++++++++++++++++++++++++++++++++-- dlls/comctl32/tests/syslink.c | 6 +++- 2 files changed, 62 insertions(+), 3 deletions(-)
diff --git a/dlls/comctl32/syslink.c b/dlls/comctl32/syslink.c index 76d95b77848..ac6192df724 100644 --- a/dlls/comctl32/syslink.c +++ b/dlls/comctl32/syslink.c @@ -177,6 +177,45 @@ static HRESULT WINAPI Accessible_GetTypeInfoCount(IAccessible *iface, UINT *coun return E_NOTIMPL; }
+static HRESULT Accessible_FindChild(SYSLINK_ACC *This, VARIANT childid, DOC_ITEM** result) +{ + DOC_ITEM *current; + int index; + + if (!This->infoPtr) + { + WARN("control was destroyed\n"); + return E_FAIL; + } + + if (V_VT(&childid) == VT_EMPTY) + index = 0; + else if (V_VT(&childid) == VT_I4) + index = V_I4(&childid); + else { + WARN("not implemented for vt %s\n", debugstr_vt(V_VT(&childid))); + return E_INVALIDARG; + } + + if (index == 0) + { + *result = NULL; + return S_OK; + } + + LIST_FOR_EACH_ENTRY(current, &This->infoPtr->Items, DOC_ITEM, entry) + { + if (!--index) + { + *result = current; + return S_OK; + } + } + + WARN("index out of range\n"); + return E_INVALIDARG; +} + static HRESULT WINAPI Accessible_get_accParent(IAccessible *iface, IDispatch** disp) { FIXME("%p\n", iface); @@ -215,8 +254,24 @@ static HRESULT WINAPI Accessible_get_accDescription(IAccessible *iface, VARIANT
static HRESULT WINAPI Accessible_get_accRole(IAccessible *iface, VARIANT childid, VARIANT *role) { - FIXME("%p\n", iface); - return E_NOTIMPL; + SYSLINK_ACC *This = impl_from_IAccessible(iface); + HRESULT hr; + DOC_ITEM* item; + + TRACE("%p, %s\n", iface, debugstr_variant(&childid)); + + hr = Accessible_FindChild(This, childid, &item); + if (FAILED(hr)) + return hr; + + V_VT(role) = VT_I4; + + if (item) + V_I4(role) = ROLE_SYSTEM_LINK; + else + V_I4(role) = ROLE_SYSTEM_CLIENT; + + return S_OK; }
static HRESULT WINAPI Accessible_get_accState(IAccessible *iface, VARIANT childid, VARIANT *state) diff --git a/dlls/comctl32/tests/syslink.c b/dlls/comctl32/tests/syslink.c index 4ce0daa8c0e..e8a76f8a5ae 100644 --- a/dlls/comctl32/tests/syslink.c +++ b/dlls/comctl32/tests/syslink.c @@ -311,12 +311,12 @@ static void test_msaa(void) V_VT(&varChild) = VT_I4; V_I4(&varChild) = CHILDID_SELF;
-todo_wine { hr = IAccessible_get_accRole(acc, varChild, &varResult); ok(hr == S_OK, "accRole failed, hr=%lx\n", hr); ok(V_VT(&varResult) == VT_I4, "accRole returned vt=%x\n", V_VT(&varResult)); ok(V_I4(&varResult) == ROLE_SYSTEM_CLIENT, "accRole returned %li\n", V_I4(&varResult));
+todo_wine { VariantClear(&varResult); hr = IAccessible_get_accState(acc, varChild, &varResult); ok(hr == S_OK, "accState failed, hr=%lx\n", hr); @@ -348,12 +348,14 @@ todo_wine { hr = IAccessible_get_accChild(acc, varChild, &child); ok(hr == S_FALSE, "accChild hr=%lx\n", hr); ok(!child, "accChild returned IDispatch\n"); +}
hr = IAccessible_get_accRole(acc, varChild, &varResult); ok(hr == S_OK, "accRole failed, hr=%lx\n", hr); ok(V_VT(&varResult) == VT_I4, "accRole returned vt=%x\n", V_VT(&varResult)); ok(V_I4(&varResult) == ROLE_SYSTEM_LINK, "accRole returned %li\n", V_I4(&varResult));
+todo_wine { VariantClear(&varResult); hr = IAccessible_get_accState(acc, varChild, &varResult); ok(hr == S_OK, "accState failed, hr=%lx\n", hr); @@ -385,12 +387,14 @@ todo_wine { hr = IAccessible_get_accChild(acc, varChild, &child); ok(hr == S_FALSE, "accChild hr=%lx\n", hr); ok(!child, "accChild returned IDispatch\n"); +}
hr = IAccessible_get_accRole(acc, varChild, &varResult); ok(hr == S_OK, "accRole failed, hr=%lx\n", hr); ok(V_VT(&varResult) == VT_I4, "accRole returned vt=%x\n", V_VT(&varResult)); ok(V_I4(&varResult) == ROLE_SYSTEM_LINK, "accRole returned %li\n", V_I4(&varResult));
+todo_wine { VariantClear(&varResult); hr = IAccessible_get_accState(acc, varChild, &varResult); ok(hr == S_OK, "accState failed, hr=%lx\n", hr);
Connor McAdams (@cmcadams) commented about dlls/comctl32/tests/syslink.c:
- hr = IAccessible_get_accName(acc, varChild, &name);
- ok(hr == S_OK, "accName failed, hr=%lx\n", hr);
- if (SUCCEEDED(hr)) {
ok(!!name && !wcscmp(name, L"Head Name1 Middle Name2 Tail"),
"unexpected name %s\n", debugstr_w(name));
SysFreeString(name);
- }
- hr = IAccessible_get_accDefaultAction(acc, varChild, &name);
- ok(hr == S_FALSE, "accDefaultAction failed, hr=%lx\n", hr);
- if (SUCCEEDED(hr))
ok(!name, "unexpected default action %s\n", debugstr_w(name));
- hr = IAccessible_accLocation(acc, &left, &top, &width, &height, varChild);
- ok(hr == S_OK, "accLocation failed, hr=%lx\n", hr);
Not a big deal, but is there any reason you aren't checking the values returned here? Just want to make sure it's intentional and not an oversight. Same goes for the other `accLocation` calls with child IDs.
Connor McAdams (@cmcadams) commented about dlls/comctl32/syslink.c:
#define SL_RIGHTMARGIN (0) #define SL_BOTTOMMARGIN (0)
+static inline SYSLINK_ACC *impl_from_IAccessible(IAccessible *iface) +{
- return CONTAINING_RECORD(iface, SYSLINK_ACC, IAccessible_iface);
+}
+static HRESULT WINAPI Accessible_QueryInterface(IAccessible *iface, REFIID iid, void **ppv) +{
- SYSLINK_ACC *This = impl_from_IAccessible(iface);
- TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
Nitpicky, but a newline between `SYSLINK_ACC *This = impl_from_IAccessible(iface);` and the TRACE message seems like a good idea.
This merge request was approved by Connor McAdams.
Aside from minor nitpicks, this looks good to me.
On Thu Feb 13 14:05:21 2025 +0000, Connor McAdams wrote:
Not a big deal, but is there any reason you aren't checking the values returned here? Just want to make sure it's intentional and not an oversight. Same goes for the other `accLocation` calls with child IDs.
Not sure how to do it properly since they depend on the font/rendering.
On Thu Feb 13 14:13:38 2025 +0000, Esme Povirk wrote:
Not sure how to do it properly since they depend on the font/rendering.
Got it, I had figured it was something to do with the values being inconsistent but wanted to make sure.