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