xref: /reactos/dll/win32/oleacc/main.c (revision 4166e504)
1 /*
2  * Implementation of the OLEACC dll
3  *
4  * Copyright 2003 Mike McCormack for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #define COBJMACROS
22 
23 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "ole2.h"
27 #include "commctrl.h"
28 #include "rpcproxy.h"
29 
30 #ifdef __REACTOS__
31 #include <wchar.h>
32 #include <winnls.h>
33 #endif
34 
35 #include "initguid.h"
36 #include "oleacc_private.h"
37 #include "resource.h"
38 
39 #include "wine/debug.h"
40 
41 WINE_DEFAULT_DEBUG_CHANNEL(oleacc);
42 
43 static const WCHAR lresult_atom_prefix[] = {'w','i','n','e','_','o','l','e','a','c','c',':'};
44 
45 static const WCHAR menuW[] = {'#','3','2','7','6','8',0};
46 static const WCHAR desktopW[] = {'#','3','2','7','6','9',0};
47 static const WCHAR dialogW[] = {'#','3','2','7','7','0',0};
48 static const WCHAR winswitchW[] = {'#','3','2','7','7','1',0};
49 static const WCHAR mdi_clientW[] = {'M','D','I','C','l','i','e','n','t',0};
50 static const WCHAR richeditW[] = {'R','I','C','H','E','D','I','T',0};
51 static const WCHAR richedit20aW[] = {'R','i','c','h','E','d','i','t','2','0','A',0};
52 static const WCHAR richedit20wW[] = {'R','i','c','h','E','d','i','t','2','0','W',0};
53 
54 typedef HRESULT (WINAPI *accessible_create)(HWND, const IID*, void**);
55 
56 extern HRESULT WINAPI OLEACC_DllGetClassObject(REFCLSID, REFIID, void**) DECLSPEC_HIDDEN;
57 extern BOOL WINAPI OLEACC_DllMain(HINSTANCE, DWORD, void*) DECLSPEC_HIDDEN;
58 extern HRESULT WINAPI OLEACC_DllRegisterServer(void) DECLSPEC_HIDDEN;
59 extern HRESULT WINAPI OLEACC_DllUnregisterServer(void) DECLSPEC_HIDDEN;
60 
61 static struct {
62     const WCHAR *name;
63     DWORD idx;
64     accessible_create create_client;
65     accessible_create create_window;
66 } builtin_classes[] = {
67     {WC_LISTBOXW,           0x10000, NULL, NULL},
68     {menuW,                 0x10001, NULL, NULL},
69     {WC_BUTTONW,            0x10002, NULL, NULL},
70     {WC_STATICW,            0x10003, NULL, NULL},
71     {WC_EDITW,              0x10004, NULL, NULL},
72     {WC_COMBOBOXW,          0x10005, NULL, NULL},
73     {dialogW,               0x10006, NULL, NULL},
74     {winswitchW,            0x10007, NULL, NULL},
75     {mdi_clientW,           0x10008, NULL, NULL},
76     {desktopW,              0x10009, NULL, NULL},
77     {WC_SCROLLBARW,         0x1000a, NULL, NULL},
78     {STATUSCLASSNAMEW,      0x1000b, NULL, NULL},
79     {TOOLBARCLASSNAMEW,     0x1000c, NULL, NULL},
80     {PROGRESS_CLASSW,       0x1000d, NULL, NULL},
81     {ANIMATE_CLASSW,        0x1000e, NULL, NULL},
82     {WC_TABCONTROLW,        0x1000f, NULL, NULL},
83     {HOTKEY_CLASSW,         0x10010, NULL, NULL},
84     {WC_HEADERW,            0x10011, NULL, NULL},
85     {TRACKBAR_CLASSW,       0x10012, NULL, NULL},
86     {WC_LISTVIEWW,          0x10013, NULL, NULL},
87     {UPDOWN_CLASSW,         0x10016, NULL, NULL},
88     {TOOLTIPS_CLASSW,       0x10018, NULL, NULL},
89     {WC_TREEVIEWW,          0x10019, NULL, NULL},
90     {MONTHCAL_CLASSW,       0,       NULL, NULL},
91     {DATETIMEPICK_CLASSW,   0,       NULL, NULL},
92     {WC_IPADDRESSW,         0,       NULL, NULL},
93     {richeditW,             0x1001c, NULL, NULL},
94     {richedit20aW,          0,       NULL, NULL},
95     {richedit20wW,          0,       NULL, NULL},
96 };
97 
98 static HINSTANCE oleacc_handle = 0;
99 
convert_child_id(VARIANT * v)100 int convert_child_id(VARIANT *v)
101 {
102     switch(V_VT(v)) {
103     case VT_I4:
104         return V_I4(v);
105     default:
106         FIXME("unhandled child ID variant type: %d\n", V_VT(v));
107         return -1;
108     }
109 }
110 
get_builtin_accessible_obj(HWND hwnd,LONG objid)111 static accessible_create get_builtin_accessible_obj(HWND hwnd, LONG objid)
112 {
113     WCHAR class_name[64];
114     int i, idx;
115 
116     if(!RealGetWindowClassW(hwnd, class_name, ARRAY_SIZE(class_name)))
117         return NULL;
118     TRACE("got window class: %s\n", debugstr_w(class_name));
119 
120     for(i=0; i<ARRAY_SIZE(builtin_classes); i++) {
121         if(!wcsicmp(class_name, builtin_classes[i].name)) {
122             accessible_create ret;
123 
124             ret = (objid==OBJID_CLIENT ?
125                     builtin_classes[i].create_client :
126                     builtin_classes[i].create_window);
127             if(!ret)
128                 FIXME("unhandled window class: %s\n", debugstr_w(class_name));
129             return ret;
130         }
131     }
132 
133     idx = SendMessageW(hwnd, WM_GETOBJECT, 0, OBJID_QUERYCLASSNAMEIDX);
134     if(idx) {
135         for(i=0; i<ARRAY_SIZE(builtin_classes); i++) {
136             if(idx == builtin_classes[i].idx) {
137                 accessible_create ret;
138 
139                 ret = (objid==OBJID_CLIENT ?
140                         builtin_classes[i].create_client :
141                         builtin_classes[i].create_window);
142                 if(!ret)
143                     FIXME("unhandled class name idx: %x\n", idx);
144                 return ret;
145             }
146         }
147 
148         WARN("unhandled class name idx: %x\n", idx);
149     }
150 
151     return NULL;
152 }
153 
CreateStdAccessibleObject(HWND hwnd,LONG idObject,REFIID riidInterface,void ** ppvObject)154 HRESULT WINAPI CreateStdAccessibleObject( HWND hwnd, LONG idObject,
155         REFIID riidInterface, void** ppvObject )
156 {
157     accessible_create create;
158 
159     TRACE("%p %d %s %p\n", hwnd, idObject,
160           debugstr_guid( riidInterface ), ppvObject );
161 
162     switch(idObject) {
163     case OBJID_CLIENT:
164         create = get_builtin_accessible_obj(hwnd, idObject);
165         if(create) return create(hwnd, riidInterface, ppvObject);
166         return create_client_object(hwnd, riidInterface, ppvObject);
167     case OBJID_WINDOW:
168         create = get_builtin_accessible_obj(hwnd, idObject);
169         if(create) return create(hwnd, riidInterface, ppvObject);
170         return create_window_object(hwnd, riidInterface, ppvObject);
171     default:
172         FIXME("unhandled object id: %d\n", idObject);
173         return E_NOTIMPL;
174     }
175 }
176 
ObjectFromLresult(LRESULT result,REFIID riid,WPARAM wParam,void ** ppObject)177 HRESULT WINAPI ObjectFromLresult( LRESULT result, REFIID riid, WPARAM wParam, void **ppObject )
178 {
179     WCHAR atom_str[ARRAY_SIZE(lresult_atom_prefix)+3*8+3];
180     HANDLE server_proc, server_mapping, mapping;
181     DWORD proc_id, size;
182     IStream *stream;
183     HGLOBAL data;
184     void *view;
185     HRESULT hr;
186     WCHAR *p;
187 
188     TRACE("%ld %s %ld %p\n", result, debugstr_guid(riid), wParam, ppObject );
189 
190     if(wParam)
191         FIXME("unsupported wParam = %lx\n", wParam);
192 
193     if(!ppObject)
194         return E_INVALIDARG;
195     *ppObject = NULL;
196 
197     if(result != (ATOM)result)
198         return E_FAIL;
199 
200     if(!GlobalGetAtomNameW(result, atom_str, ARRAY_SIZE(atom_str)))
201         return E_FAIL;
202     if(memcmp(atom_str, lresult_atom_prefix, sizeof(lresult_atom_prefix)))
203         return E_FAIL;
204     p = atom_str + ARRAY_SIZE(lresult_atom_prefix);
205     proc_id = wcstoul(p, &p, 16);
206     if(*p != ':')
207         return E_FAIL;
208     server_mapping = ULongToHandle( wcstoul(p+1, &p, 16) );
209     if(*p != ':')
210         return E_FAIL;
211     size = wcstoul(p+1, &p, 16);
212     if(*p != 0)
213         return E_FAIL;
214 
215     server_proc = OpenProcess(PROCESS_DUP_HANDLE, FALSE, proc_id);
216     if(!server_proc)
217         return E_FAIL;
218 
219     if(!DuplicateHandle(server_proc, server_mapping, GetCurrentProcess(), &mapping,
220                 0, FALSE, DUPLICATE_CLOSE_SOURCE|DUPLICATE_SAME_ACCESS))
221         return E_FAIL;
222     CloseHandle(server_proc);
223     GlobalDeleteAtom(result);
224 
225     view = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
226     CloseHandle(mapping);
227     if(!view)
228         return E_FAIL;
229 
230     data = GlobalAlloc(GMEM_FIXED, size);
231     if(!data) {
232         UnmapViewOfFile(view);
233         return E_OUTOFMEMORY;
234     }
235     memcpy(data, view, size);
236     UnmapViewOfFile(view);
237 
238     hr = CreateStreamOnHGlobal(data, TRUE, &stream);
239     if(FAILED(hr)) {
240         GlobalFree(data);
241         return hr;
242     }
243 
244     hr = CoUnmarshalInterface(stream, riid, ppObject);
245     IStream_Release(stream);
246     return hr;
247 }
248 
LresultFromObject(REFIID riid,WPARAM wParam,LPUNKNOWN pAcc)249 LRESULT WINAPI LresultFromObject( REFIID riid, WPARAM wParam, LPUNKNOWN pAcc )
250 {
251     static const WCHAR atom_fmt[] = {'%','0','8','x',':','%','0','8','x',':','%','0','8','x',0};
252     static const LARGE_INTEGER seek_zero = {{0}};
253 
254     WCHAR atom_str[ARRAY_SIZE(lresult_atom_prefix)+3*8+3];
255     IStream *stream;
256     HANDLE mapping;
257     STATSTG stat;
258     HRESULT hr;
259     ATOM atom;
260     void *view;
261 
262     TRACE("%s %ld %p\n", debugstr_guid(riid), wParam, pAcc);
263 
264     if(wParam)
265         FIXME("unsupported wParam = %lx\n", wParam);
266 
267     if(!pAcc)
268         return E_INVALIDARG;
269 
270     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
271     if(FAILED(hr))
272         return hr;
273 
274     hr = CoMarshalInterface(stream, riid, pAcc, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL);
275     if(FAILED(hr)) {
276         IStream_Release(stream);
277         return hr;
278     }
279 
280     hr = IStream_Seek(stream, seek_zero, STREAM_SEEK_SET, NULL);
281     if(FAILED(hr)) {
282         IStream_Release(stream);
283         return hr;
284     }
285 
286     hr = IStream_Stat(stream, &stat, STATFLAG_NONAME);
287     if(FAILED(hr)) {
288         CoReleaseMarshalData(stream);
289         IStream_Release(stream);
290         return hr;
291     }else if(stat.cbSize.u.HighPart) {
292         FIXME("stream size to big\n");
293         CoReleaseMarshalData(stream);
294         IStream_Release(stream);
295         return E_NOTIMPL;
296     }
297 
298     mapping = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
299             stat.cbSize.u.HighPart, stat.cbSize.u.LowPart, NULL);
300     if(!mapping) {
301         CoReleaseMarshalData(stream);
302         IStream_Release(stream);
303         return hr;
304     }
305 
306     view = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0);
307     if(!view) {
308         CloseHandle(mapping);
309         CoReleaseMarshalData(stream);
310         IStream_Release(stream);
311         return E_FAIL;
312     }
313 
314     hr = IStream_Read(stream, view, stat.cbSize.u.LowPart, NULL);
315     UnmapViewOfFile(view);
316     if(FAILED(hr)) {
317         CloseHandle(mapping);
318         hr = IStream_Seek(stream, seek_zero, STREAM_SEEK_SET, NULL);
319         if(SUCCEEDED(hr))
320             CoReleaseMarshalData(stream);
321         IStream_Release(stream);
322         return hr;
323 
324     }
325 
326     memcpy(atom_str, lresult_atom_prefix, sizeof(lresult_atom_prefix));
327     swprintf(atom_str+ARRAY_SIZE(lresult_atom_prefix), atom_fmt, GetCurrentProcessId(),
328              HandleToUlong(mapping), stat.cbSize.u.LowPart);
329     atom = GlobalAddAtomW(atom_str);
330     if(!atom) {
331         CloseHandle(mapping);
332         hr = IStream_Seek(stream, seek_zero, STREAM_SEEK_SET, NULL);
333         if(SUCCEEDED(hr))
334             CoReleaseMarshalData(stream);
335         IStream_Release(stream);
336         return E_FAIL;
337     }
338 
339     IStream_Release(stream);
340     return atom;
341 }
342 
AccessibleObjectFromPoint(POINT ptScreen,IAccessible ** ppacc,VARIANT * pvarChild)343 HRESULT WINAPI AccessibleObjectFromPoint( POINT ptScreen, IAccessible** ppacc, VARIANT* pvarChild )
344 {
345     FIXME("{%d,%d} %p %p: stub\n", ptScreen.x, ptScreen.y, ppacc, pvarChild );
346     return E_NOTIMPL;
347 }
348 
AccessibleObjectFromWindow(HWND hwnd,DWORD dwObjectID,REFIID riid,void ** ppvObject)349 HRESULT WINAPI AccessibleObjectFromWindow( HWND hwnd, DWORD dwObjectID,
350                              REFIID riid, void** ppvObject )
351 {
352     TRACE("%p %d %s %p\n", hwnd, dwObjectID,
353           debugstr_guid( riid ), ppvObject );
354 
355     if(!ppvObject)
356         return E_INVALIDARG;
357     *ppvObject = NULL;
358 
359     if(IsWindow(hwnd)) {
360         LRESULT lres;
361 
362         lres = SendMessageW(hwnd, WM_GETOBJECT, 0xffffffff, dwObjectID);
363         if(FAILED(lres))
364             return lres;
365         else if(lres)
366             return ObjectFromLresult(lres, riid, 0, ppvObject);
367     }
368 
369     return CreateStdAccessibleObject(hwnd, dwObjectID, riid, ppvObject);
370 }
371 
WindowFromAccessibleObject(IAccessible * acc,HWND * phwnd)372 HRESULT WINAPI WindowFromAccessibleObject(IAccessible *acc, HWND *phwnd)
373 {
374     IDispatch *parent;
375     IOleWindow *ow;
376     HRESULT hres;
377 
378     TRACE("%p %p\n", acc, phwnd);
379 
380     IAccessible_AddRef(acc);
381     while(1) {
382         hres = IAccessible_QueryInterface(acc, &IID_IOleWindow, (void**)&ow);
383         if(SUCCEEDED(hres)) {
384             hres = IOleWindow_GetWindow(ow, phwnd);
385             IOleWindow_Release(ow);
386             IAccessible_Release(acc);
387             return hres;
388         }
389 
390         hres = IAccessible_get_accParent(acc, &parent);
391         IAccessible_Release(acc);
392         if(FAILED(hres))
393             return hres;
394         if(hres!=S_OK || !parent) {
395             *phwnd = NULL;
396             return hres;
397         }
398 
399         hres = IDispatch_QueryInterface(parent, &IID_IAccessible, (void**)&acc);
400         IDispatch_Release(parent);
401         if(FAILED(hres))
402             return hres;
403     }
404 }
405 
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)406 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
407                     LPVOID lpvReserved)
408 {
409     TRACE("%p, %d, %p\n", hinstDLL, fdwReason, lpvReserved);
410 
411     switch (fdwReason)
412     {
413         case DLL_PROCESS_ATTACH:
414             oleacc_handle = hinstDLL;
415             DisableThreadLibraryCalls(hinstDLL);
416             break;
417     }
418 
419     return OLEACC_DllMain(hinstDLL, fdwReason, lpvReserved);
420 }
421 
DllRegisterServer(void)422 HRESULT WINAPI DllRegisterServer(void)
423 {
424     return OLEACC_DllRegisterServer();
425 }
426 
DllUnregisterServer(void)427 HRESULT WINAPI DllUnregisterServer(void)
428 {
429     return OLEACC_DllUnregisterServer();
430 }
431 
DllGetClassObject(REFCLSID rclsid,REFIID iid,void ** ppv)432 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, void **ppv)
433 {
434     if(IsEqualGUID(&CLSID_CAccPropServices, rclsid)) {
435         TRACE("(CLSID_CAccPropServices %s %p)\n", debugstr_guid(iid), ppv);
436         return get_accpropservices_factory(iid, ppv);
437     }
438 
439     if(IsEqualGUID(&CLSID_PSFactoryBuffer, rclsid)) {
440         TRACE("(CLSID_PSFactoryBuffer %s %p)\n", debugstr_guid(iid), ppv);
441         return OLEACC_DllGetClassObject(rclsid, iid, ppv);
442     }
443 
444     FIXME("%s %s %p: stub\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv);
445     return E_NOTIMPL;
446 }
447 
GetOleaccVersionInfo(DWORD * pVersion,DWORD * pBuild)448 void WINAPI GetOleaccVersionInfo(DWORD* pVersion, DWORD* pBuild)
449 {
450 #ifdef __REACTOS__
451     *pVersion = MAKELONG(2,4); /* Windows XP version of oleacc: 4.2.5406.0 */
452     *pBuild = MAKELONG(0,5406);
453 #else
454     *pVersion = MAKELONG(0,7); /* Windows 7 version of oleacc: 7.0.0.0 */
455     *pBuild = MAKELONG(0,0);
456 #endif
457 }
458 
GetProcessHandleFromHwnd(HWND hwnd)459 HANDLE WINAPI GetProcessHandleFromHwnd(HWND hwnd)
460 {
461     DWORD proc_id;
462 
463     TRACE("%p\n", hwnd);
464 
465     if(!GetWindowThreadProcessId(hwnd, &proc_id))
466         return NULL;
467     return OpenProcess(PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION |
468             PROCESS_VM_READ | PROCESS_VM_WRITE | SYNCHRONIZE, TRUE, proc_id);
469 }
470 
GetRoleTextW(DWORD role,LPWSTR lpRole,UINT rolemax)471 UINT WINAPI GetRoleTextW(DWORD role, LPWSTR lpRole, UINT rolemax)
472 {
473     INT ret;
474     WCHAR *resptr;
475 
476     TRACE("%u %p %u\n", role, lpRole, rolemax);
477 
478     /* return role text length */
479     if(!lpRole)
480         return LoadStringW(oleacc_handle, role, (LPWSTR)&resptr, 0);
481 
482     ret = LoadStringW(oleacc_handle, role, lpRole, rolemax);
483     if(!(ret > 0)){
484         if(rolemax > 0) lpRole[0] = '\0';
485         return 0;
486     }
487 
488     return ret;
489 }
490 
GetRoleTextA(DWORD role,LPSTR lpRole,UINT rolemax)491 UINT WINAPI GetRoleTextA(DWORD role, LPSTR lpRole, UINT rolemax)
492 {
493     UINT length;
494     WCHAR *roletextW;
495 
496     TRACE("%u %p %u\n", role, lpRole, rolemax);
497 
498     if(lpRole && !rolemax)
499         return 0;
500 
501     length = GetRoleTextW(role, NULL, 0);
502     if(!length) {
503         if(lpRole && rolemax)
504             lpRole[0] = 0;
505         return 0;
506     }
507 
508     roletextW = HeapAlloc(GetProcessHeap(), 0, (length + 1)*sizeof(WCHAR));
509     if(!roletextW)
510         return 0;
511 
512     GetRoleTextW(role, roletextW, length + 1);
513 
514     length = WideCharToMultiByte( CP_ACP, 0, roletextW, -1, NULL, 0, NULL, NULL );
515 
516     if(!lpRole){
517         HeapFree(GetProcessHeap(), 0, roletextW);
518         return length - 1;
519     }
520 
521     if(rolemax < length) {
522         HeapFree(GetProcessHeap(), 0, roletextW);
523         lpRole[0] = 0;
524         return 0;
525     }
526 
527     WideCharToMultiByte( CP_ACP, 0, roletextW, -1, lpRole, rolemax, NULL, NULL );
528 
529     if(rolemax < length){
530         lpRole[rolemax-1] = '\0';
531         length = rolemax;
532     }
533 
534     HeapFree(GetProcessHeap(), 0, roletextW);
535 
536     return length - 1;
537 }
538 
GetStateTextW(DWORD state_bit,WCHAR * state_str,UINT state_str_len)539 UINT WINAPI GetStateTextW(DWORD state_bit, WCHAR *state_str, UINT state_str_len)
540 {
541     DWORD state_id;
542 
543     TRACE("%x %p %u\n", state_bit, state_str, state_str_len);
544 
545     if(state_bit & ~(STATE_SYSTEM_VALID | STATE_SYSTEM_HASPOPUP)) {
546         if(state_str && state_str_len)
547             state_str[0] = 0;
548         return 0;
549     }
550 
551     state_id = IDS_STATE_NORMAL;
552     while(state_bit) {
553         state_id++;
554         state_bit /= 2;
555     }
556 
557     if(state_str) {
558         UINT ret = LoadStringW(oleacc_handle, state_id, state_str, state_str_len);
559         if(!ret && state_str_len)
560             state_str[0] = 0;
561         return ret;
562     }else {
563         WCHAR *tmp;
564         return LoadStringW(oleacc_handle, state_id, (WCHAR*)&tmp, 0);
565     }
566 
567 }
568 
GetStateTextA(DWORD state_bit,CHAR * state_str,UINT state_str_len)569 UINT WINAPI GetStateTextA(DWORD state_bit, CHAR *state_str, UINT state_str_len)
570 {
571     DWORD state_id;
572 
573     TRACE("%x %p %u\n", state_bit, state_str, state_str_len);
574 
575     if(state_str && !state_str_len)
576         return 0;
577 
578     if(state_bit & ~(STATE_SYSTEM_VALID | STATE_SYSTEM_HASPOPUP)) {
579         if(state_str && state_str_len)
580             state_str[0] = 0;
581         return 0;
582     }
583 
584     state_id = IDS_STATE_NORMAL;
585     while(state_bit) {
586         state_id++;
587         state_bit /= 2;
588     }
589 
590     if(state_str) {
591         UINT ret = LoadStringA(oleacc_handle, state_id, state_str, state_str_len);
592         if(!ret && state_str_len)
593             state_str[0] = 0;
594         return ret;
595     }else {
596         CHAR tmp[256];
597         return LoadStringA(oleacc_handle, state_id, tmp, sizeof(tmp));
598     }
599 }
600 
AccessibleChildren(IAccessible * container,LONG start,LONG count,VARIANT * children,LONG * children_cnt)601 HRESULT WINAPI AccessibleChildren(IAccessible *container,
602         LONG start, LONG count, VARIANT *children, LONG *children_cnt)
603 {
604     IEnumVARIANT *ev;
605     LONG i, child_no;
606     HRESULT hr;
607 
608     TRACE("%p %d %d %p %p\n", container, start, count, children, children_cnt);
609 
610     if(!container || !children || !children_cnt)
611         return E_INVALIDARG;
612 
613     for(i=0; i<count; i++)
614         VariantInit(children+i);
615 
616     hr = IAccessible_QueryInterface(container, &IID_IEnumVARIANT, (void**)&ev);
617     if(SUCCEEDED(hr)) {
618         hr = IEnumVARIANT_Reset(ev);
619         if(SUCCEEDED(hr))
620             hr = IEnumVARIANT_Skip(ev, start);
621         if(SUCCEEDED(hr))
622             hr = IEnumVARIANT_Next(ev, count, children, (ULONG*)children_cnt);
623         IEnumVARIANT_Release(ev);
624         return hr;
625     }
626 
627     hr = IAccessible_get_accChildCount(container, &child_no);
628     if(FAILED(hr))
629         return hr;
630 
631     for(i=0; i<count && start+i+1<=child_no; i++) {
632         IDispatch *disp;
633 
634         V_VT(children+i) = VT_I4;
635         V_I4(children+i) = start+i+1;
636 
637         hr = IAccessible_get_accChild(container, children[i], &disp);
638         if(SUCCEEDED(hr) && disp) {
639             V_VT(children+i) = VT_DISPATCH;
640             V_DISPATCH(children+i) = disp;
641         }
642     }
643 
644     *children_cnt = i;
645     return i==count ? S_OK : S_FALSE;
646 }
647