Create the AHCI branch for Aman's work
[reactos.git] / dll / win32 / oleacc / client.c
1 /*
2 * Copyright 2014 Piotr Caban for CodeWeavers
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include "oleacc_private.h"
20
21 typedef struct {
22 IAccessible IAccessible_iface;
23 IOleWindow IOleWindow_iface;
24 IEnumVARIANT IEnumVARIANT_iface;
25
26 LONG ref;
27
28 HWND hwnd;
29 HWND enum_pos;
30 } Client;
31
32 static inline Client* impl_from_Client(IAccessible *iface)
33 {
34 return CONTAINING_RECORD(iface, Client, IAccessible_iface);
35 }
36
37 static HRESULT WINAPI Client_QueryInterface(IAccessible *iface, REFIID riid, void **ppv)
38 {
39 Client *This = impl_from_Client(iface);
40
41 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
42
43 if(IsEqualIID(riid, &IID_IAccessible) ||
44 IsEqualIID(riid, &IID_IDispatch) ||
45 IsEqualIID(riid, &IID_IUnknown)) {
46 *ppv = iface;
47 }else if(IsEqualIID(riid, &IID_IOleWindow)) {
48 *ppv = &This->IOleWindow_iface;
49 }else if(IsEqualIID(riid, &IID_IEnumVARIANT)) {
50 *ppv = &This->IEnumVARIANT_iface;
51 }else {
52 WARN("no interface: %s\n", debugstr_guid(riid));
53 *ppv = NULL;
54 return E_NOINTERFACE;
55 }
56
57 IAccessible_AddRef(iface);
58 return S_OK;
59 }
60
61 static ULONG WINAPI Client_AddRef(IAccessible *iface)
62 {
63 Client *This = impl_from_Client(iface);
64 ULONG ref = InterlockedIncrement(&This->ref);
65
66 TRACE("(%p) ref = %u\n", This, ref);
67 return ref;
68 }
69
70 static ULONG WINAPI Client_Release(IAccessible *iface)
71 {
72 Client *This = impl_from_Client(iface);
73 ULONG ref = InterlockedDecrement(&This->ref);
74
75 TRACE("(%p) ref = %u\n", This, ref);
76
77 if(!ref)
78 heap_free(This);
79 return ref;
80 }
81
82 static HRESULT WINAPI Client_GetTypeInfoCount(IAccessible *iface, UINT *pctinfo)
83 {
84 Client *This = impl_from_Client(iface);
85 FIXME("(%p)->(%p)\n", This, pctinfo);
86 return E_NOTIMPL;
87 }
88
89 static HRESULT WINAPI Client_GetTypeInfo(IAccessible *iface,
90 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
91 {
92 Client *This = impl_from_Client(iface);
93 FIXME("(%p)->(%u %x %p)\n", This, iTInfo, lcid, ppTInfo);
94 return E_NOTIMPL;
95 }
96
97 static HRESULT WINAPI Client_GetIDsOfNames(IAccessible *iface, REFIID riid,
98 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
99 {
100 Client *This = impl_from_Client(iface);
101 FIXME("(%p)->(%s %p %u %x %p)\n", This, debugstr_guid(riid),
102 rgszNames, cNames, lcid, rgDispId);
103 return E_NOTIMPL;
104 }
105
106 static HRESULT WINAPI Client_Invoke(IAccessible *iface, DISPID dispIdMember,
107 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
108 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
109 {
110 Client *This = impl_from_Client(iface);
111 FIXME("(%p)->(%x %s %x %x %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
112 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
113 return E_NOTIMPL;
114 }
115
116 static HRESULT WINAPI Client_get_accParent(IAccessible *iface, IDispatch **ppdispParent)
117 {
118 Client *This = impl_from_Client(iface);
119
120 TRACE("(%p)->(%p)\n", This, ppdispParent);
121
122 return AccessibleObjectFromWindow(This->hwnd, OBJID_WINDOW,
123 &IID_IDispatch, (void**)ppdispParent);
124 }
125
126 static HRESULT WINAPI Client_get_accChildCount(IAccessible *iface, LONG *pcountChildren)
127 {
128 Client *This = impl_from_Client(iface);
129 HWND cur;
130
131 TRACE("(%p)->(%p)\n", This, pcountChildren);
132
133 *pcountChildren = 0;
134 for(cur = GetWindow(This->hwnd, GW_CHILD); cur; cur = GetWindow(cur, GW_HWNDNEXT))
135 (*pcountChildren)++;
136
137 return S_OK;
138 }
139
140 static HRESULT WINAPI Client_get_accChild(IAccessible *iface,
141 VARIANT varChildID, IDispatch **ppdispChild)
142 {
143 Client *This = impl_from_Client(iface);
144
145 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varChildID), ppdispChild);
146
147 *ppdispChild = NULL;
148 return E_INVALIDARG;
149 }
150
151 static HRESULT WINAPI Client_get_accName(IAccessible *iface, VARIANT varID, BSTR *pszName)
152 {
153 Client *This = impl_from_Client(iface);
154 WCHAR name[1024];
155 UINT i, len;
156
157 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pszName);
158
159 *pszName = NULL;
160 if(convert_child_id(&varID) != CHILDID_SELF || !IsWindow(This->hwnd))
161 return E_INVALIDARG;
162
163 len = SendMessageW(This->hwnd, WM_GETTEXT, sizeof(name)/sizeof(WCHAR), (LPARAM)name);
164 if(!len)
165 return S_FALSE;
166
167 for(i=0; i<len; i++) {
168 if(name[i] == '&') {
169 len--;
170 memmove(name+i, name+i+1, (len-i)*sizeof(WCHAR));
171 break;
172 }
173 }
174
175 *pszName = SysAllocStringLen(name, len);
176 return *pszName ? S_OK : E_OUTOFMEMORY;
177 }
178
179 static HRESULT WINAPI Client_get_accValue(IAccessible *iface, VARIANT varID, BSTR *pszValue)
180 {
181 Client *This = impl_from_Client(iface);
182
183 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pszValue);
184
185 *pszValue = NULL;
186 if(convert_child_id(&varID) != CHILDID_SELF)
187 return E_INVALIDARG;
188 return S_FALSE;
189 }
190
191 static HRESULT WINAPI Client_get_accDescription(IAccessible *iface,
192 VARIANT varID, BSTR *pszDescription)
193 {
194 Client *This = impl_from_Client(iface);
195
196 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pszDescription);
197
198 *pszDescription = NULL;
199 if(convert_child_id(&varID) != CHILDID_SELF)
200 return E_INVALIDARG;
201 return S_FALSE;
202 }
203
204 static HRESULT WINAPI Client_get_accRole(IAccessible *iface, VARIANT varID, VARIANT *pvarRole)
205 {
206 Client *This = impl_from_Client(iface);
207
208 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pvarRole);
209
210 if(convert_child_id(&varID) != CHILDID_SELF) {
211 V_VT(pvarRole) = VT_EMPTY;
212 return E_INVALIDARG;
213 }
214
215 V_VT(pvarRole) = VT_I4;
216 V_I4(pvarRole) = ROLE_SYSTEM_CLIENT;
217 return S_OK;
218 }
219
220 static HRESULT WINAPI Client_get_accState(IAccessible *iface, VARIANT varID, VARIANT *pvarState)
221 {
222 Client *This = impl_from_Client(iface);
223 LONG style;
224
225 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pvarState);
226
227 if(convert_child_id(&varID) != CHILDID_SELF) {
228 V_VT(pvarState) = VT_EMPTY;
229 return E_INVALIDARG;
230 }
231
232 V_VT(pvarState) = VT_I4;
233 V_I4(pvarState) = 0;
234
235 style = GetWindowLongW(This->hwnd, GWL_STYLE);
236 if(style & WS_DISABLED)
237 V_I4(pvarState) |= STATE_SYSTEM_UNAVAILABLE;
238 else if(IsWindow(This->hwnd))
239 V_I4(pvarState) |= STATE_SYSTEM_FOCUSABLE;
240 if(GetFocus() == This->hwnd)
241 V_I4(pvarState) |= STATE_SYSTEM_FOCUSED;
242 if(!(style & WS_VISIBLE))
243 V_I4(pvarState) |= STATE_SYSTEM_INVISIBLE;
244 return S_OK;
245 }
246
247 static HRESULT WINAPI Client_get_accHelp(IAccessible *iface, VARIANT varID, BSTR *pszHelp)
248 {
249 Client *This = impl_from_Client(iface);
250
251 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pszHelp);
252
253 *pszHelp = NULL;
254 if(convert_child_id(&varID) != CHILDID_SELF)
255 return E_INVALIDARG;
256 return S_FALSE;
257 }
258
259 static HRESULT WINAPI Client_get_accHelpTopic(IAccessible *iface,
260 BSTR *pszHelpFile, VARIANT varID, LONG *pidTopic)
261 {
262 Client *This = impl_from_Client(iface);
263 FIXME("(%p)->(%p %s %p)\n", This, pszHelpFile, debugstr_variant(&varID), pidTopic);
264 return E_NOTIMPL;
265 }
266
267 static HRESULT WINAPI Client_get_accKeyboardShortcut(IAccessible *iface,
268 VARIANT varID, BSTR *pszKeyboardShortcut)
269 {
270 static const WCHAR shortcut_fmt[] = {'A','l','t','+','!',0};
271 Client *This = impl_from_Client(iface);
272 WCHAR name[1024];
273 UINT i, len;
274
275 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pszKeyboardShortcut);
276
277 *pszKeyboardShortcut = NULL;
278 if(convert_child_id(&varID) != CHILDID_SELF)
279 return E_INVALIDARG;
280
281 len = SendMessageW(This->hwnd, WM_GETTEXT, sizeof(name)/sizeof(WCHAR), (LPARAM)name);
282 for(i=0; i<len; i++) {
283 if(name[i] == '&')
284 break;
285 }
286 if(i+1 >= len)
287 return S_FALSE;
288
289 *pszKeyboardShortcut = SysAllocString(shortcut_fmt);
290 if(!*pszKeyboardShortcut)
291 return E_OUTOFMEMORY;
292
293 (*pszKeyboardShortcut)[4] = name[i+1];
294 return S_OK;
295 }
296
297 static HRESULT WINAPI Client_get_accFocus(IAccessible *iface, VARIANT *pvarID)
298 {
299 Client *This = impl_from_Client(iface);
300 FIXME("(%p)->(%p)\n", This, pvarID);
301 return E_NOTIMPL;
302 }
303
304 static HRESULT WINAPI Client_get_accSelection(IAccessible *iface, VARIANT *pvarID)
305 {
306 Client *This = impl_from_Client(iface);
307 FIXME("(%p)->(%p)\n", This, pvarID);
308 return E_NOTIMPL;
309 }
310
311 static HRESULT WINAPI Client_get_accDefaultAction(IAccessible *iface,
312 VARIANT varID, BSTR *pszDefaultAction)
313 {
314 Client *This = impl_from_Client(iface);
315
316 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pszDefaultAction);
317
318 *pszDefaultAction = NULL;
319 if(convert_child_id(&varID) != CHILDID_SELF)
320 return E_INVALIDARG;
321 return S_FALSE;
322 }
323
324 static HRESULT WINAPI Client_accSelect(IAccessible *iface, LONG flagsSelect, VARIANT varID)
325 {
326 Client *This = impl_from_Client(iface);
327 FIXME("(%p)->(%x %s)\n", This, flagsSelect, debugstr_variant(&varID));
328 return E_NOTIMPL;
329 }
330
331 static HRESULT WINAPI Client_accLocation(IAccessible *iface, LONG *pxLeft,
332 LONG *pyTop, LONG *pcxWidth, LONG *pcyHeight, VARIANT varID)
333 {
334 Client *This = impl_from_Client(iface);
335 RECT rect;
336 POINT pt;
337
338 TRACE("(%p)->(%p %p %p %p %s)\n", This, pxLeft, pyTop,
339 pcxWidth, pcyHeight, debugstr_variant(&varID));
340
341 *pxLeft = *pyTop = *pcxWidth = *pcyHeight = 0;
342 if(convert_child_id(&varID) != CHILDID_SELF)
343 return E_INVALIDARG;
344
345 if(!GetClientRect(This->hwnd, &rect))
346 return S_OK;
347
348 pt.x = rect.left,
349 pt.y = rect.top;
350 MapWindowPoints(This->hwnd, NULL, &pt, 1);
351 *pxLeft = pt.x;
352 *pyTop = pt.y;
353
354 pt.x = rect.right;
355 pt.y = rect.bottom;
356 MapWindowPoints(This->hwnd, NULL, &pt, 1);
357 *pcxWidth = pt.x - *pxLeft;
358 *pcyHeight = pt.y - *pyTop;
359 return S_OK;
360 }
361
362 static HRESULT WINAPI Client_accNavigate(IAccessible *iface,
363 LONG navDir, VARIANT varStart, VARIANT *pvarEnd)
364 {
365 Client *This = impl_from_Client(iface);
366 FIXME("(%p)->(%d %s %p)\n", This, navDir, debugstr_variant(&varStart), pvarEnd);
367 return E_NOTIMPL;
368 }
369
370 static HRESULT WINAPI Client_accHitTest(IAccessible *iface,
371 LONG xLeft, LONG yTop, VARIANT *pvarID)
372 {
373 Client *This = impl_from_Client(iface);
374 HWND child;
375 POINT pt;
376
377 TRACE("(%p)->(%d %d %p)\n", This, xLeft, yTop, pvarID);
378
379 V_VT(pvarID) = VT_I4;
380 V_I4(pvarID) = 0;
381
382 pt.x = xLeft;
383 pt.y = yTop;
384 if(!IsWindowVisible(This->hwnd) || !ScreenToClient(This->hwnd, &pt))
385 return S_OK;
386
387 child = ChildWindowFromPointEx(This->hwnd, pt, CWP_SKIPINVISIBLE);
388 if(!child || child==This->hwnd)
389 return S_OK;
390
391 V_VT(pvarID) = VT_DISPATCH;
392 return AccessibleObjectFromWindow(child, OBJID_WINDOW,
393 &IID_IDispatch, (void**)&V_DISPATCH(pvarID));
394 }
395
396 static HRESULT WINAPI Client_accDoDefaultAction(IAccessible *iface, VARIANT varID)
397 {
398 Client *This = impl_from_Client(iface);
399 FIXME("(%p)->(%s)\n", This, debugstr_variant(&varID));
400 return E_NOTIMPL;
401 }
402
403 static HRESULT WINAPI Client_put_accName(IAccessible *iface, VARIANT varID, BSTR pszName)
404 {
405 Client *This = impl_from_Client(iface);
406 FIXME("(%p)->(%s %s)\n", This, debugstr_variant(&varID), debugstr_w(pszName));
407 return E_NOTIMPL;
408 }
409
410 static HRESULT WINAPI Client_put_accValue(IAccessible *iface, VARIANT varID, BSTR pszValue)
411 {
412 Client *This = impl_from_Client(iface);
413 FIXME("(%p)->(%s %s)\n", This, debugstr_variant(&varID), debugstr_w(pszValue));
414 return E_NOTIMPL;
415 }
416
417 static const IAccessibleVtbl ClientVtbl = {
418 Client_QueryInterface,
419 Client_AddRef,
420 Client_Release,
421 Client_GetTypeInfoCount,
422 Client_GetTypeInfo,
423 Client_GetIDsOfNames,
424 Client_Invoke,
425 Client_get_accParent,
426 Client_get_accChildCount,
427 Client_get_accChild,
428 Client_get_accName,
429 Client_get_accValue,
430 Client_get_accDescription,
431 Client_get_accRole,
432 Client_get_accState,
433 Client_get_accHelp,
434 Client_get_accHelpTopic,
435 Client_get_accKeyboardShortcut,
436 Client_get_accFocus,
437 Client_get_accSelection,
438 Client_get_accDefaultAction,
439 Client_accSelect,
440 Client_accLocation,
441 Client_accNavigate,
442 Client_accHitTest,
443 Client_accDoDefaultAction,
444 Client_put_accName,
445 Client_put_accValue
446 };
447
448 static inline Client* impl_from_Client_OleWindow(IOleWindow *iface)
449 {
450 return CONTAINING_RECORD(iface, Client, IOleWindow_iface);
451 }
452
453 static HRESULT WINAPI Client_OleWindow_QueryInterface(IOleWindow *iface, REFIID riid, void **ppv)
454 {
455 Client *This = impl_from_Client_OleWindow(iface);
456 return IAccessible_QueryInterface(&This->IAccessible_iface, riid, ppv);
457 }
458
459 static ULONG WINAPI Client_OleWindow_AddRef(IOleWindow *iface)
460 {
461 Client *This = impl_from_Client_OleWindow(iface);
462 return IAccessible_AddRef(&This->IAccessible_iface);
463 }
464
465 static ULONG WINAPI Client_OleWindow_Release(IOleWindow *iface)
466 {
467 Client *This = impl_from_Client_OleWindow(iface);
468 return IAccessible_Release(&This->IAccessible_iface);
469 }
470
471 static HRESULT WINAPI Client_OleWindow_GetWindow(IOleWindow *iface, HWND *phwnd)
472 {
473 Client *This = impl_from_Client_OleWindow(iface);
474
475 TRACE("(%p)->(%p)\n", This, phwnd);
476
477 *phwnd = This->hwnd;
478 return S_OK;
479 }
480
481 static HRESULT WINAPI Client_OleWindow_ContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMode)
482 {
483 Client *This = impl_from_Client_OleWindow(iface);
484 FIXME("(%p)->(%x)\n", This, fEnterMode);
485 return E_NOTIMPL;
486 }
487
488 static const IOleWindowVtbl ClientOleWindowVtbl = {
489 Client_OleWindow_QueryInterface,
490 Client_OleWindow_AddRef,
491 Client_OleWindow_Release,
492 Client_OleWindow_GetWindow,
493 Client_OleWindow_ContextSensitiveHelp
494 };
495
496 static inline Client* impl_from_Client_EnumVARIANT(IEnumVARIANT *iface)
497 {
498 return CONTAINING_RECORD(iface, Client, IEnumVARIANT_iface);
499 }
500
501 static HRESULT WINAPI Client_EnumVARIANT_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **ppv)
502 {
503 Client *This = impl_from_Client_EnumVARIANT(iface);
504 return IAccessible_QueryInterface(&This->IAccessible_iface, riid, ppv);
505 }
506
507 static ULONG WINAPI Client_EnumVARIANT_AddRef(IEnumVARIANT *iface)
508 {
509 Client *This = impl_from_Client_EnumVARIANT(iface);
510 return IAccessible_AddRef(&This->IAccessible_iface);
511 }
512
513 static ULONG WINAPI Client_EnumVARIANT_Release(IEnumVARIANT *iface)
514 {
515 Client *This = impl_from_Client_EnumVARIANT(iface);
516 return IAccessible_Release(&This->IAccessible_iface);
517 }
518
519 static HRESULT WINAPI Client_EnumVARIANT_Next(IEnumVARIANT *iface,
520 ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
521 {
522 Client *This = impl_from_Client_EnumVARIANT(iface);
523 HWND cur = This->enum_pos, next;
524 ULONG fetched = 0;
525 HRESULT hr;
526
527 TRACE("(%p)->(%u %p %p)\n", This, celt, rgVar, pCeltFetched);
528
529 if(!celt) {
530 if(pCeltFetched)
531 *pCeltFetched = 0;
532 return S_OK;
533 }
534
535 if(!This->enum_pos)
536 next = GetWindow(This->hwnd, GW_CHILD);
537 else
538 next = GetWindow(This->enum_pos, GW_HWNDNEXT);
539
540 while(next) {
541 cur = next;
542
543 V_VT(rgVar+fetched) = VT_DISPATCH;
544 hr = AccessibleObjectFromWindow(cur, OBJID_WINDOW,
545 &IID_IDispatch, (void**)&V_DISPATCH(rgVar+fetched));
546 if(FAILED(hr)) {
547 V_VT(rgVar+fetched) = VT_EMPTY;
548 while(fetched > 0) {
549 VariantClear(rgVar+fetched-1);
550 fetched--;
551 }
552 if(pCeltFetched)
553 *pCeltFetched = 0;
554 return hr;
555 }
556 fetched++;
557 if(fetched == celt)
558 break;
559
560 next = GetWindow(cur, GW_HWNDNEXT);
561 }
562
563 This->enum_pos = cur;
564 if(pCeltFetched)
565 *pCeltFetched = fetched;
566 return celt == fetched ? S_OK : S_FALSE;
567 }
568
569 static HRESULT WINAPI Client_EnumVARIANT_Skip(IEnumVARIANT *iface, ULONG celt)
570 {
571 Client *This = impl_from_Client_EnumVARIANT(iface);
572 HWND next;
573
574 TRACE("(%p)->(%u)\n", This, celt);
575
576 while(celt) {
577 if(!This->enum_pos)
578 next = GetWindow(This->hwnd, GW_CHILD);
579 else
580 next = GetWindow(This->enum_pos, GW_HWNDNEXT);
581 if(!next)
582 return S_FALSE;
583
584 This->enum_pos = next;
585 celt--;
586 }
587
588 return S_OK;
589 }
590
591 static HRESULT WINAPI Client_EnumVARIANT_Reset(IEnumVARIANT *iface)
592 {
593 Client *This = impl_from_Client_EnumVARIANT(iface);
594
595 TRACE("(%p)\n", This);
596
597 This->enum_pos = 0;
598 return S_OK;
599 }
600
601 static HRESULT WINAPI Client_EnumVARIANT_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
602 {
603 Client *This = impl_from_Client_EnumVARIANT(iface);
604 FIXME("(%p)->(%p)\n", This, ppEnum);
605 return E_NOTIMPL;
606 }
607
608 static const IEnumVARIANTVtbl ClientEnumVARIANTVtbl = {
609 Client_EnumVARIANT_QueryInterface,
610 Client_EnumVARIANT_AddRef,
611 Client_EnumVARIANT_Release,
612 Client_EnumVARIANT_Next,
613 Client_EnumVARIANT_Skip,
614 Client_EnumVARIANT_Reset,
615 Client_EnumVARIANT_Clone
616 };
617
618 HRESULT create_client_object(HWND hwnd, const IID *iid, void **obj)
619 {
620 Client *client;
621 HRESULT hres;
622
623 if(!IsWindow(hwnd))
624 return E_FAIL;
625
626 client = heap_alloc_zero(sizeof(Client));
627 if(!client)
628 return E_OUTOFMEMORY;
629
630 client->IAccessible_iface.lpVtbl = &ClientVtbl;
631 client->IOleWindow_iface.lpVtbl = &ClientOleWindowVtbl;
632 client->IEnumVARIANT_iface.lpVtbl = &ClientEnumVARIANTVtbl;
633 client->ref = 1;
634 client->hwnd = hwnd;
635 client->enum_pos = 0;
636
637 hres = IAccessible_QueryInterface(&client->IAccessible_iface, iid, obj);
638 IAccessible_Release(&client->IAccessible_iface);
639 return hres;
640 }