gdi32: Improve EMF DC cleanup when CloseEnhMetafile is not called.
[wine.git] / dlls / oleacc / client.c
blob8a8fd3d240d9f90b44175eb5b659bbcbaf250712
1 /*
2 * Copyright 2014 Piotr Caban for CodeWeavers
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.
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.
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
19 #define COBJMACROS
21 #include <assert.h>
22 #include "oleacc_private.h"
23 #include "commctrl.h"
25 #include "wine/debug.h"
26 #include "wine/heap.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(oleacc);
30 typedef struct win_class_vtbl win_class_vtbl;
31 typedef struct {
32 IAccessible IAccessible_iface;
33 IOleWindow IOleWindow_iface;
34 IEnumVARIANT IEnumVARIANT_iface;
35 IServiceProvider IServiceProvider_iface;
37 LONG ref;
39 HWND hwnd;
40 HWND enum_pos;
41 INT role;
43 const win_class_vtbl *vtbl;
44 } Client;
46 struct win_class_vtbl {
47 void (*init)(Client*);
48 HRESULT (*get_state)(Client*, VARIANT, VARIANT*);
49 HRESULT (*get_name)(Client*, VARIANT, BSTR*);
50 HRESULT (*get_kbd_shortcut)(Client*, VARIANT, BSTR*);
51 HRESULT (*get_value)(Client*, VARIANT, BSTR*);
52 HRESULT (*put_value)(Client*, VARIANT, BSTR);
55 static HRESULT win_get_name(HWND hwnd, BSTR *name)
57 WCHAR buf[1024];
58 UINT i, len;
60 len = SendMessageW(hwnd, WM_GETTEXT, ARRAY_SIZE(buf), (LPARAM)buf);
61 if(!len)
62 return S_FALSE;
64 for(i=0; i<len; i++) {
65 if(buf[i] == '&') {
66 len--;
67 memmove(buf+i, buf+i+1, (len-i)*sizeof(WCHAR));
68 break;
72 *name = SysAllocStringLen(buf, len);
73 return *name ? S_OK : E_OUTOFMEMORY;
76 static HRESULT win_get_kbd_shortcut(HWND hwnd, BSTR *shortcut)
78 WCHAR buf[1024];
79 UINT i, len;
81 len = SendMessageW(hwnd, WM_GETTEXT, ARRAY_SIZE(buf), (LPARAM)buf);
82 if(!len)
83 return S_FALSE;
85 for(i=0; i<len; i++) {
86 if(buf[i] == '&')
87 break;
89 if(i+1 >= len)
90 return S_FALSE;
92 *shortcut = SysAllocString(L"Alt+!");
93 if(!*shortcut)
94 return E_OUTOFMEMORY;
95 (*shortcut)[4] = buf[i+1];
96 return S_OK;
99 static inline Client* impl_from_Client(IAccessible *iface)
101 return CONTAINING_RECORD(iface, Client, IAccessible_iface);
104 static HRESULT WINAPI Client_QueryInterface(IAccessible *iface, REFIID riid, void **ppv)
106 Client *This = impl_from_Client(iface);
108 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
110 if(IsEqualIID(riid, &IID_IAccessible) ||
111 IsEqualIID(riid, &IID_IDispatch) ||
112 IsEqualIID(riid, &IID_IUnknown)) {
113 *ppv = iface;
114 }else if(IsEqualIID(riid, &IID_IOleWindow)) {
115 *ppv = &This->IOleWindow_iface;
116 }else if(IsEqualIID(riid, &IID_IEnumVARIANT)) {
117 *ppv = &This->IEnumVARIANT_iface;
118 }else if(IsEqualIID(riid, &IID_IServiceProvider)) {
119 *ppv = &This->IServiceProvider_iface;
120 }else {
121 WARN("no interface: %s\n", debugstr_guid(riid));
122 *ppv = NULL;
123 return E_NOINTERFACE;
126 IAccessible_AddRef(iface);
127 return S_OK;
130 static ULONG WINAPI Client_AddRef(IAccessible *iface)
132 Client *This = impl_from_Client(iface);
133 ULONG ref = InterlockedIncrement(&This->ref);
135 TRACE("(%p) ref = %lu\n", This, ref);
136 return ref;
139 static ULONG WINAPI Client_Release(IAccessible *iface)
141 Client *This = impl_from_Client(iface);
142 ULONG ref = InterlockedDecrement(&This->ref);
144 TRACE("(%p) ref = %lu\n", This, ref);
146 if(!ref)
147 heap_free(This);
148 return ref;
151 static HRESULT WINAPI Client_GetTypeInfoCount(IAccessible *iface, UINT *pctinfo)
153 Client *This = impl_from_Client(iface);
154 FIXME("(%p)->(%p)\n", This, pctinfo);
155 return E_NOTIMPL;
158 static HRESULT WINAPI Client_GetTypeInfo(IAccessible *iface,
159 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
161 Client *This = impl_from_Client(iface);
162 FIXME("(%p)->(%u %lx %p)\n", This, iTInfo, lcid, ppTInfo);
163 return E_NOTIMPL;
166 static HRESULT WINAPI Client_GetIDsOfNames(IAccessible *iface, REFIID riid,
167 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
169 Client *This = impl_from_Client(iface);
170 FIXME("(%p)->(%s %p %u %lx %p)\n", This, debugstr_guid(riid),
171 rgszNames, cNames, lcid, rgDispId);
172 return E_NOTIMPL;
175 static HRESULT WINAPI Client_Invoke(IAccessible *iface, DISPID dispIdMember,
176 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
177 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
179 Client *This = impl_from_Client(iface);
180 FIXME("(%p)->(%lx %s %lx %x %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
181 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
182 return E_NOTIMPL;
185 static HRESULT WINAPI Client_get_accParent(IAccessible *iface, IDispatch **ppdispParent)
187 Client *This = impl_from_Client(iface);
189 TRACE("(%p)->(%p)\n", This, ppdispParent);
191 return AccessibleObjectFromWindow(This->hwnd, OBJID_WINDOW,
192 &IID_IDispatch, (void**)ppdispParent);
195 static HRESULT WINAPI Client_get_accChildCount(IAccessible *iface, LONG *pcountChildren)
197 Client *This = impl_from_Client(iface);
198 HWND cur;
200 TRACE("(%p)->(%p)\n", This, pcountChildren);
202 *pcountChildren = 0;
203 for(cur = GetWindow(This->hwnd, GW_CHILD); cur; cur = GetWindow(cur, GW_HWNDNEXT))
204 (*pcountChildren)++;
206 return S_OK;
209 static HRESULT WINAPI Client_get_accChild(IAccessible *iface,
210 VARIANT varChildID, IDispatch **ppdispChild)
212 Client *This = impl_from_Client(iface);
214 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varChildID), ppdispChild);
216 *ppdispChild = NULL;
217 return E_INVALIDARG;
220 static HRESULT WINAPI Client_get_accName(IAccessible *iface, VARIANT id, BSTR *name)
222 Client *This = impl_from_Client(iface);
224 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&id), name);
226 *name = NULL;
227 if(This->vtbl && This->vtbl->get_name)
228 return This->vtbl->get_name(This, id, name);
230 if(convert_child_id(&id) != CHILDID_SELF || !IsWindow(This->hwnd))
231 return E_INVALIDARG;
233 return win_get_name(This->hwnd, name);
236 static HRESULT WINAPI Client_get_accValue(IAccessible *iface, VARIANT id, BSTR *value)
238 Client *This = impl_from_Client(iface);
240 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&id), value);
242 *value = NULL;
243 if(This->vtbl && This->vtbl->get_value)
244 return This->vtbl->get_value(This, id, value);
246 if(convert_child_id(&id) != CHILDID_SELF)
247 return E_INVALIDARG;
248 return S_FALSE;
251 static HRESULT WINAPI Client_get_accDescription(IAccessible *iface,
252 VARIANT varID, BSTR *pszDescription)
254 Client *This = impl_from_Client(iface);
256 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pszDescription);
258 *pszDescription = NULL;
259 if(convert_child_id(&varID) != CHILDID_SELF)
260 return E_INVALIDARG;
261 return S_FALSE;
264 static HRESULT WINAPI Client_get_accRole(IAccessible *iface, VARIANT varID, VARIANT *pvarRole)
266 Client *This = impl_from_Client(iface);
268 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pvarRole);
270 if(convert_child_id(&varID) != CHILDID_SELF) {
271 V_VT(pvarRole) = VT_EMPTY;
272 return E_INVALIDARG;
275 V_VT(pvarRole) = VT_I4;
276 V_I4(pvarRole) = This->role;
277 return S_OK;
280 static HRESULT client_get_state(Client *client, VARIANT id, VARIANT *state)
282 GUITHREADINFO info;
283 LONG style;
285 if(convert_child_id(&id) != CHILDID_SELF) {
286 V_VT(state) = VT_EMPTY;
287 return E_INVALIDARG;
290 V_VT(state) = VT_I4;
291 V_I4(state) = 0;
293 style = GetWindowLongW(client->hwnd, GWL_STYLE);
294 if(style & WS_DISABLED)
295 V_I4(state) |= STATE_SYSTEM_UNAVAILABLE;
296 else if(IsWindow(client->hwnd))
297 V_I4(state) |= STATE_SYSTEM_FOCUSABLE;
299 info.cbSize = sizeof(info);
300 if(GetGUIThreadInfo(0, &info) && info.hwndFocus == client->hwnd)
301 V_I4(state) |= STATE_SYSTEM_FOCUSED;
302 if(!(style & WS_VISIBLE))
303 V_I4(state) |= STATE_SYSTEM_INVISIBLE;
304 return S_OK;
307 static HRESULT WINAPI Client_get_accState(IAccessible *iface, VARIANT id, VARIANT *state)
309 Client *This = impl_from_Client(iface);
311 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&id), state);
313 if(This->vtbl && This->vtbl->get_state)
314 return This->vtbl->get_state(This, id, state);
315 return client_get_state(This, id, state);
318 static HRESULT WINAPI Client_get_accHelp(IAccessible *iface, VARIANT varID, BSTR *pszHelp)
320 Client *This = impl_from_Client(iface);
322 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pszHelp);
324 *pszHelp = NULL;
325 if(convert_child_id(&varID) != CHILDID_SELF)
326 return E_INVALIDARG;
327 return S_FALSE;
330 static HRESULT WINAPI Client_get_accHelpTopic(IAccessible *iface,
331 BSTR *pszHelpFile, VARIANT varID, LONG *pidTopic)
333 Client *This = impl_from_Client(iface);
334 FIXME("(%p)->(%p %s %p)\n", This, pszHelpFile, debugstr_variant(&varID), pidTopic);
335 return E_NOTIMPL;
338 static HRESULT WINAPI Client_get_accKeyboardShortcut(IAccessible *iface,
339 VARIANT id, BSTR *shortcut)
341 Client *This = impl_from_Client(iface);
343 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&id), shortcut);
345 *shortcut = NULL;
346 if(This->vtbl && This->vtbl->get_kbd_shortcut)
347 return This->vtbl->get_kbd_shortcut(This, id, shortcut);
349 if(convert_child_id(&id) != CHILDID_SELF)
350 return E_INVALIDARG;
352 return win_get_kbd_shortcut(This->hwnd, shortcut);
355 static HRESULT WINAPI Client_get_accFocus(IAccessible *iface, VARIANT *focus)
357 Client *This = impl_from_Client(iface);
358 GUITHREADINFO info;
360 TRACE("(%p)->(%p)\n", This, focus);
362 V_VT(focus) = VT_EMPTY;
363 info.cbSize = sizeof(info);
364 if(GetGUIThreadInfo(0, &info) && info.hwndFocus) {
365 if(info.hwndFocus == This->hwnd) {
366 V_VT(focus) = VT_I4;
367 V_I4(focus) = CHILDID_SELF;
369 else if(IsChild(This->hwnd, info.hwndFocus)) {
370 IDispatch *disp;
371 HRESULT hr;
373 hr = AccessibleObjectFromWindow(info.hwndFocus, OBJID_WINDOW,
374 &IID_IDispatch, (void**)&disp);
375 if(FAILED(hr))
376 return hr;
377 if(!disp)
378 return E_FAIL;
380 V_VT(focus) = VT_DISPATCH;
381 V_DISPATCH(focus) = disp;
385 return S_OK;
388 static HRESULT WINAPI Client_get_accSelection(IAccessible *iface, VARIANT *pvarID)
390 Client *This = impl_from_Client(iface);
391 FIXME("(%p)->(%p)\n", This, pvarID);
392 return E_NOTIMPL;
395 static HRESULT WINAPI Client_get_accDefaultAction(IAccessible *iface,
396 VARIANT varID, BSTR *pszDefaultAction)
398 Client *This = impl_from_Client(iface);
400 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pszDefaultAction);
402 *pszDefaultAction = NULL;
403 if(convert_child_id(&varID) != CHILDID_SELF)
404 return E_INVALIDARG;
405 return S_FALSE;
408 static HRESULT WINAPI Client_accSelect(IAccessible *iface, LONG flagsSelect, VARIANT varID)
410 Client *This = impl_from_Client(iface);
411 FIXME("(%p)->(%lx %s)\n", This, flagsSelect, debugstr_variant(&varID));
412 return E_NOTIMPL;
415 static HRESULT WINAPI Client_accLocation(IAccessible *iface, LONG *pxLeft,
416 LONG *pyTop, LONG *pcxWidth, LONG *pcyHeight, VARIANT varID)
418 Client *This = impl_from_Client(iface);
419 RECT rect;
420 POINT pt;
422 TRACE("(%p)->(%p %p %p %p %s)\n", This, pxLeft, pyTop,
423 pcxWidth, pcyHeight, debugstr_variant(&varID));
425 *pxLeft = *pyTop = *pcxWidth = *pcyHeight = 0;
426 if(convert_child_id(&varID) != CHILDID_SELF)
427 return E_INVALIDARG;
429 if(!GetClientRect(This->hwnd, &rect))
430 return S_OK;
432 pt.x = rect.left;
433 pt.y = rect.top;
434 MapWindowPoints(This->hwnd, NULL, &pt, 1);
435 *pxLeft = pt.x;
436 *pyTop = pt.y;
438 pt.x = rect.right;
439 pt.y = rect.bottom;
440 MapWindowPoints(This->hwnd, NULL, &pt, 1);
441 *pcxWidth = pt.x - *pxLeft;
442 *pcyHeight = pt.y - *pyTop;
443 return S_OK;
446 static HRESULT WINAPI Client_accNavigate(IAccessible *iface,
447 LONG navDir, VARIANT varStart, VARIANT *pvarEnd)
449 Client *This = impl_from_Client(iface);
450 FIXME("(%p)->(%ld %s %p)\n", This, navDir, debugstr_variant(&varStart), pvarEnd);
451 return E_NOTIMPL;
454 static HRESULT WINAPI Client_accHitTest(IAccessible *iface,
455 LONG xLeft, LONG yTop, VARIANT *pvarID)
457 Client *This = impl_from_Client(iface);
458 HWND child;
459 POINT pt;
461 TRACE("(%p)->(%ld %ld %p)\n", This, xLeft, yTop, pvarID);
463 V_VT(pvarID) = VT_I4;
464 V_I4(pvarID) = 0;
466 pt.x = xLeft;
467 pt.y = yTop;
468 if(!IsWindowVisible(This->hwnd) || !ScreenToClient(This->hwnd, &pt))
469 return S_OK;
471 child = ChildWindowFromPointEx(This->hwnd, pt, CWP_SKIPINVISIBLE);
472 if(!child || child==This->hwnd)
473 return S_OK;
475 V_VT(pvarID) = VT_DISPATCH;
476 return AccessibleObjectFromWindow(child, OBJID_WINDOW,
477 &IID_IDispatch, (void**)&V_DISPATCH(pvarID));
480 static HRESULT WINAPI Client_accDoDefaultAction(IAccessible *iface, VARIANT varID)
482 Client *This = impl_from_Client(iface);
483 FIXME("(%p)->(%s)\n", This, debugstr_variant(&varID));
484 return E_NOTIMPL;
487 static HRESULT WINAPI Client_put_accName(IAccessible *iface, VARIANT varID, BSTR pszName)
489 Client *This = impl_from_Client(iface);
490 FIXME("(%p)->(%s %s)\n", This, debugstr_variant(&varID), debugstr_w(pszName));
491 return E_NOTIMPL;
494 static HRESULT WINAPI Client_put_accValue(IAccessible *iface, VARIANT id, BSTR value)
496 Client *This = impl_from_Client(iface);
498 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&id), value);
500 if(This->vtbl && This->vtbl->put_value)
501 return This->vtbl->put_value(This, id, value);
503 if(convert_child_id(&id) != CHILDID_SELF)
504 return E_INVALIDARG;
505 return S_FALSE;
508 static const IAccessibleVtbl ClientVtbl = {
509 Client_QueryInterface,
510 Client_AddRef,
511 Client_Release,
512 Client_GetTypeInfoCount,
513 Client_GetTypeInfo,
514 Client_GetIDsOfNames,
515 Client_Invoke,
516 Client_get_accParent,
517 Client_get_accChildCount,
518 Client_get_accChild,
519 Client_get_accName,
520 Client_get_accValue,
521 Client_get_accDescription,
522 Client_get_accRole,
523 Client_get_accState,
524 Client_get_accHelp,
525 Client_get_accHelpTopic,
526 Client_get_accKeyboardShortcut,
527 Client_get_accFocus,
528 Client_get_accSelection,
529 Client_get_accDefaultAction,
530 Client_accSelect,
531 Client_accLocation,
532 Client_accNavigate,
533 Client_accHitTest,
534 Client_accDoDefaultAction,
535 Client_put_accName,
536 Client_put_accValue
539 static inline Client* impl_from_Client_OleWindow(IOleWindow *iface)
541 return CONTAINING_RECORD(iface, Client, IOleWindow_iface);
544 static HRESULT WINAPI Client_OleWindow_QueryInterface(IOleWindow *iface, REFIID riid, void **ppv)
546 Client *This = impl_from_Client_OleWindow(iface);
547 return IAccessible_QueryInterface(&This->IAccessible_iface, riid, ppv);
550 static ULONG WINAPI Client_OleWindow_AddRef(IOleWindow *iface)
552 Client *This = impl_from_Client_OleWindow(iface);
553 return IAccessible_AddRef(&This->IAccessible_iface);
556 static ULONG WINAPI Client_OleWindow_Release(IOleWindow *iface)
558 Client *This = impl_from_Client_OleWindow(iface);
559 return IAccessible_Release(&This->IAccessible_iface);
562 static HRESULT WINAPI Client_OleWindow_GetWindow(IOleWindow *iface, HWND *phwnd)
564 Client *This = impl_from_Client_OleWindow(iface);
566 TRACE("(%p)->(%p)\n", This, phwnd);
568 *phwnd = This->hwnd;
569 return S_OK;
572 static HRESULT WINAPI Client_OleWindow_ContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMode)
574 Client *This = impl_from_Client_OleWindow(iface);
575 FIXME("(%p)->(%x)\n", This, fEnterMode);
576 return E_NOTIMPL;
579 static const IOleWindowVtbl ClientOleWindowVtbl = {
580 Client_OleWindow_QueryInterface,
581 Client_OleWindow_AddRef,
582 Client_OleWindow_Release,
583 Client_OleWindow_GetWindow,
584 Client_OleWindow_ContextSensitiveHelp
587 static inline Client* impl_from_Client_EnumVARIANT(IEnumVARIANT *iface)
589 return CONTAINING_RECORD(iface, Client, IEnumVARIANT_iface);
592 static HRESULT WINAPI Client_EnumVARIANT_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **ppv)
594 Client *This = impl_from_Client_EnumVARIANT(iface);
595 return IAccessible_QueryInterface(&This->IAccessible_iface, riid, ppv);
598 static ULONG WINAPI Client_EnumVARIANT_AddRef(IEnumVARIANT *iface)
600 Client *This = impl_from_Client_EnumVARIANT(iface);
601 return IAccessible_AddRef(&This->IAccessible_iface);
604 static ULONG WINAPI Client_EnumVARIANT_Release(IEnumVARIANT *iface)
606 Client *This = impl_from_Client_EnumVARIANT(iface);
607 return IAccessible_Release(&This->IAccessible_iface);
610 static HRESULT WINAPI Client_EnumVARIANT_Next(IEnumVARIANT *iface,
611 ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
613 Client *This = impl_from_Client_EnumVARIANT(iface);
614 HWND cur = This->enum_pos, next;
615 ULONG fetched = 0;
616 HRESULT hr;
618 TRACE("(%p)->(%lu %p %p)\n", This, celt, rgVar, pCeltFetched);
620 if(!celt) {
621 if(pCeltFetched)
622 *pCeltFetched = 0;
623 return S_OK;
626 if(!This->enum_pos)
627 next = GetWindow(This->hwnd, GW_CHILD);
628 else
629 next = GetWindow(This->enum_pos, GW_HWNDNEXT);
631 while(next) {
632 cur = next;
634 V_VT(rgVar+fetched) = VT_DISPATCH;
635 hr = AccessibleObjectFromWindow(cur, OBJID_WINDOW,
636 &IID_IDispatch, (void**)&V_DISPATCH(rgVar+fetched));
637 if(FAILED(hr)) {
638 V_VT(rgVar+fetched) = VT_EMPTY;
639 while(fetched > 0) {
640 VariantClear(rgVar+fetched-1);
641 fetched--;
643 if(pCeltFetched)
644 *pCeltFetched = 0;
645 return hr;
647 fetched++;
648 if(fetched == celt)
649 break;
651 next = GetWindow(cur, GW_HWNDNEXT);
654 This->enum_pos = cur;
655 if(pCeltFetched)
656 *pCeltFetched = fetched;
657 return celt == fetched ? S_OK : S_FALSE;
660 static HRESULT WINAPI Client_EnumVARIANT_Skip(IEnumVARIANT *iface, ULONG celt)
662 Client *This = impl_from_Client_EnumVARIANT(iface);
663 HWND next;
665 TRACE("(%p)->(%lu)\n", This, celt);
667 while(celt) {
668 if(!This->enum_pos)
669 next = GetWindow(This->hwnd, GW_CHILD);
670 else
671 next = GetWindow(This->enum_pos, GW_HWNDNEXT);
672 if(!next)
673 return S_FALSE;
675 This->enum_pos = next;
676 celt--;
679 return S_OK;
682 static HRESULT WINAPI Client_EnumVARIANT_Reset(IEnumVARIANT *iface)
684 Client *This = impl_from_Client_EnumVARIANT(iface);
686 TRACE("(%p)\n", This);
688 This->enum_pos = 0;
689 return S_OK;
692 static HRESULT WINAPI Client_EnumVARIANT_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
694 Client *This = impl_from_Client_EnumVARIANT(iface);
695 FIXME("(%p)->(%p)\n", This, ppEnum);
696 return E_NOTIMPL;
699 static const IEnumVARIANTVtbl ClientEnumVARIANTVtbl = {
700 Client_EnumVARIANT_QueryInterface,
701 Client_EnumVARIANT_AddRef,
702 Client_EnumVARIANT_Release,
703 Client_EnumVARIANT_Next,
704 Client_EnumVARIANT_Skip,
705 Client_EnumVARIANT_Reset,
706 Client_EnumVARIANT_Clone
709 static inline Client* impl_from_Client_ServiceProvider(IServiceProvider *iface)
711 return CONTAINING_RECORD(iface, Client, IServiceProvider_iface);
714 static HRESULT WINAPI Client_ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
716 Client *This = impl_from_Client_ServiceProvider(iface);
717 return IAccessible_QueryInterface(&This->IAccessible_iface, riid, ppv);
720 static ULONG WINAPI Client_ServiceProvider_AddRef(IServiceProvider *iface)
722 Client *This = impl_from_Client_ServiceProvider(iface);
723 return IAccessible_AddRef(&This->IAccessible_iface);
726 static ULONG WINAPI Client_ServiceProvider_Release(IServiceProvider *iface)
728 Client *This = impl_from_Client_ServiceProvider(iface);
729 return IAccessible_Release(&This->IAccessible_iface);
732 static HRESULT WINAPI Client_ServiceProvider_QueryService(IServiceProvider *iface, REFGUID guid_service,
733 REFIID riid, void **ppv)
735 Client *This = impl_from_Client_ServiceProvider(iface);
737 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid_service), debugstr_guid(riid), ppv);
739 *ppv = NULL;
740 if (IsEqualIID(guid_service, &IIS_IsOleaccProxy))
741 return IAccessible_QueryInterface(&This->IAccessible_iface, riid, ppv);
743 return E_INVALIDARG;
746 static const IServiceProviderVtbl ClientServiceProviderVtbl = {
747 Client_ServiceProvider_QueryInterface,
748 Client_ServiceProvider_AddRef,
749 Client_ServiceProvider_Release,
750 Client_ServiceProvider_QueryService
753 static void edit_init(Client *client)
755 client->role = ROLE_SYSTEM_TEXT;
758 static HRESULT edit_get_state(Client *client, VARIANT id, VARIANT *state)
760 HRESULT hres;
761 LONG style;
763 hres = client_get_state(client, id, state);
764 if(FAILED(hres))
765 return hres;
767 assert(V_VT(state) == VT_I4);
769 style = GetWindowLongW(client->hwnd, GWL_STYLE);
770 if(style & ES_READONLY)
771 V_I4(state) |= STATE_SYSTEM_READONLY;
772 if(style & ES_PASSWORD)
773 V_I4(state) |= STATE_SYSTEM_PROTECTED;
774 return S_OK;
778 * Edit control objects have their name property defined by the first static
779 * text control preceding them in the order of window creation. If one is not
780 * found, the edit has no name property. In the case of the keyboard shortcut
781 * property, the first preceding visible static text control is used.
783 static HWND edit_find_label(HWND hwnd, BOOL visible)
785 HWND cur;
787 for(cur = hwnd; cur; cur = GetWindow(cur, GW_HWNDPREV)) {
788 WCHAR class_name[64];
790 if(!RealGetWindowClassW(cur, class_name, ARRAY_SIZE(class_name)))
791 continue;
793 if(!wcsicmp(class_name, WC_STATICW)) {
794 if(visible && !(GetWindowLongW(cur, GWL_STYLE) & WS_VISIBLE))
795 continue;
796 else
797 break;
801 return cur;
804 static HRESULT edit_get_name(Client *client, VARIANT id, BSTR *name)
806 HWND label;
808 if(convert_child_id(&id) != CHILDID_SELF || !IsWindow(client->hwnd))
809 return E_INVALIDARG;
811 label = edit_find_label(client->hwnd, FALSE);
812 if(!label)
813 return S_FALSE;
815 return win_get_name(label, name);
818 static HRESULT edit_get_kbd_shortcut(Client *client, VARIANT id, BSTR *shortcut)
820 HWND label;
822 if(convert_child_id(&id) != CHILDID_SELF)
823 return E_INVALIDARG;
825 label = edit_find_label(client->hwnd, TRUE);
826 if(!label)
827 return S_FALSE;
829 return win_get_kbd_shortcut(label, shortcut);
832 static HRESULT edit_get_value(Client *client, VARIANT id, BSTR *value_out)
834 WCHAR *buf;
835 UINT len;
837 if(convert_child_id(&id) != CHILDID_SELF)
838 return E_INVALIDARG;
840 if(GetWindowLongW(client->hwnd, GWL_STYLE) & ES_PASSWORD)
841 return E_ACCESSDENIED;
843 len = SendMessageW(client->hwnd, WM_GETTEXTLENGTH, 0, 0);
844 buf = heap_alloc_zero((len + 1) * sizeof(*buf));
845 if(!buf)
846 return E_OUTOFMEMORY;
848 SendMessageW(client->hwnd, WM_GETTEXT, len + 1, (LPARAM)buf);
849 *value_out = SysAllocString(buf);
850 heap_free(buf);
851 return S_OK;
854 static HRESULT edit_put_value(Client *client, VARIANT id, BSTR value)
856 if(convert_child_id(&id) != CHILDID_SELF || !IsWindow(client->hwnd))
857 return E_INVALIDARG;
859 SendMessageW(client->hwnd, WM_SETTEXT, 0, (LPARAM)value);
860 return S_OK;
863 static const win_class_vtbl edit_vtbl = {
864 edit_init,
865 edit_get_state,
866 edit_get_name,
867 edit_get_kbd_shortcut,
868 edit_get_value,
869 edit_put_value,
872 static const struct win_class_data classes[] = {
873 {WC_LISTBOXW, 0x10000, TRUE},
874 {L"#32768", 0x10001, TRUE}, /* menu */
875 {WC_BUTTONW, 0x10002, TRUE},
876 {WC_STATICW, 0x10003, TRUE},
877 {WC_EDITW, 0x10004, FALSE, &edit_vtbl},
878 {WC_COMBOBOXW, 0x10005, TRUE},
879 {L"#32770", 0x10006, TRUE}, /* dialog */
880 {L"#32771", 0x10007, TRUE}, /* winswitcher */
881 {L"MDIClient", 0x10008, TRUE},
882 {L"#32769", 0x10009, TRUE}, /* desktop */
883 {WC_SCROLLBARW, 0x1000a, TRUE},
884 {STATUSCLASSNAMEW, 0x1000b, TRUE},
885 {TOOLBARCLASSNAMEW, 0x1000c, TRUE},
886 {PROGRESS_CLASSW, 0x1000d, TRUE},
887 {ANIMATE_CLASSW, 0x1000e, TRUE},
888 {WC_TABCONTROLW, 0x1000f, TRUE},
889 {HOTKEY_CLASSW, 0x10010, TRUE},
890 {WC_HEADERW, 0x10011, TRUE},
891 {TRACKBAR_CLASSW, 0x10012, TRUE},
892 {WC_LISTVIEWW, 0x10013, TRUE},
893 {UPDOWN_CLASSW, 0x10016, TRUE},
894 {TOOLTIPS_CLASSW, 0x10018, TRUE},
895 {WC_TREEVIEWW, 0x10019, TRUE},
896 {DATETIMEPICK_CLASSW, 0, TRUE},
897 {WC_IPADDRESSW, 0, TRUE},
898 {L"RICHEDIT", 0x1001c, TRUE},
899 {L"RichEdit20A", 0, TRUE},
900 {L"RichEdit20W", 0, TRUE},
901 {NULL}
904 HRESULT create_client_object(HWND hwnd, const IID *iid, void **obj)
906 const struct win_class_data *data;
907 Client *client;
908 HRESULT hres = S_OK;
910 if(!IsWindow(hwnd))
911 return E_FAIL;
913 client = heap_alloc_zero(sizeof(Client));
914 if(!client)
915 return E_OUTOFMEMORY;
917 data = find_class_data(hwnd, classes);
919 client->IAccessible_iface.lpVtbl = &ClientVtbl;
920 client->IOleWindow_iface.lpVtbl = &ClientOleWindowVtbl;
921 client->IEnumVARIANT_iface.lpVtbl = &ClientEnumVARIANTVtbl;
922 client->IServiceProvider_iface.lpVtbl = &ClientServiceProviderVtbl;
923 client->ref = 1;
924 client->hwnd = hwnd;
925 client->enum_pos = 0;
926 client->role = ROLE_SYSTEM_CLIENT;
928 if(data)
929 client->vtbl = data->vtbl;
930 if(client->vtbl && client->vtbl->init)
931 client->vtbl->init(client);
933 hres = IAccessible_QueryInterface(&client->IAccessible_iface, iid, obj);
934 IAccessible_Release(&client->IAccessible_iface);
935 return hres;