Sync to trunk r65566.
[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
25 LONG ref;
26
27 HWND hwnd;
28 } Client;
29
30 static inline Client* impl_from_Client(IAccessible *iface)
31 {
32 return CONTAINING_RECORD(iface, Client, IAccessible_iface);
33 }
34
35 static HRESULT WINAPI Client_QueryInterface(IAccessible *iface, REFIID riid, void **ppv)
36 {
37 Client *This = impl_from_Client(iface);
38
39 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
40
41 if(IsEqualIID(riid, &IID_IAccessible) ||
42 IsEqualIID(riid, &IID_IDispatch) ||
43 IsEqualIID(riid, &IID_IUnknown)) {
44 *ppv = iface;
45 }else if(IsEqualIID(riid, &IID_IOleWindow)) {
46 *ppv = &This->IOleWindow_iface;
47 }else {
48 WARN("no interface: %s\n", debugstr_guid(riid));
49 *ppv = NULL;
50 return E_NOINTERFACE;
51 }
52
53 IAccessible_AddRef(iface);
54 return S_OK;
55 }
56
57 static ULONG WINAPI Client_AddRef(IAccessible *iface)
58 {
59 Client *This = impl_from_Client(iface);
60 ULONG ref = InterlockedIncrement(&This->ref);
61
62 TRACE("(%p) ref = %u\n", This, ref);
63 return ref;
64 }
65
66 static ULONG WINAPI Client_Release(IAccessible *iface)
67 {
68 Client *This = impl_from_Client(iface);
69 ULONG ref = InterlockedDecrement(&This->ref);
70
71 TRACE("(%p) ref = %u\n", This, ref);
72
73 if(!ref)
74 heap_free(This);
75 return ref;
76 }
77
78 static HRESULT WINAPI Client_GetTypeInfoCount(IAccessible *iface, UINT *pctinfo)
79 {
80 Client *This = impl_from_Client(iface);
81 FIXME("(%p)->(%p)\n", This, pctinfo);
82 return E_NOTIMPL;
83 }
84
85 static HRESULT WINAPI Client_GetTypeInfo(IAccessible *iface,
86 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
87 {
88 Client *This = impl_from_Client(iface);
89 FIXME("(%p)->(%u %x %p)\n", This, iTInfo, lcid, ppTInfo);
90 return E_NOTIMPL;
91 }
92
93 static HRESULT WINAPI Client_GetIDsOfNames(IAccessible *iface, REFIID riid,
94 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
95 {
96 Client *This = impl_from_Client(iface);
97 FIXME("(%p)->(%s %p %u %x %p)\n", This, debugstr_guid(riid),
98 rgszNames, cNames, lcid, rgDispId);
99 return E_NOTIMPL;
100 }
101
102 static HRESULT WINAPI Client_Invoke(IAccessible *iface, DISPID dispIdMember,
103 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
104 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
105 {
106 Client *This = impl_from_Client(iface);
107 FIXME("(%p)->(%x %s %x %x %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
108 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
109 return E_NOTIMPL;
110 }
111
112 static HRESULT WINAPI Client_get_accParent(IAccessible *iface, IDispatch **ppdispParent)
113 {
114 Client *This = impl_from_Client(iface);
115
116 TRACE("(%p)->(%p)\n", This, ppdispParent);
117
118 return AccessibleObjectFromWindow(This->hwnd, OBJID_WINDOW,
119 &IID_IDispatch, (void**)ppdispParent);
120 }
121
122 static HRESULT WINAPI Client_get_accChildCount(IAccessible *iface, LONG *pcountChildren)
123 {
124 Client *This = impl_from_Client(iface);
125 HWND cur;
126
127 TRACE("(%p)->(%p)\n", This, pcountChildren);
128
129 *pcountChildren = 0;
130 for(cur = GetWindow(This->hwnd, GW_CHILD); cur; cur = GetWindow(cur, GW_HWNDNEXT))
131 (*pcountChildren)++;
132
133 return S_OK;
134 }
135
136 static HRESULT WINAPI Client_get_accChild(IAccessible *iface,
137 VARIANT varChildID, IDispatch **ppdispChild)
138 {
139 Client *This = impl_from_Client(iface);
140 FIXME("(%p)->(%s %p)\n", This, debugstr_variant(&varChildID), ppdispChild);
141 return E_NOTIMPL;
142 }
143
144 static HRESULT WINAPI Client_get_accName(IAccessible *iface, VARIANT varID, BSTR *pszName)
145 {
146 Client *This = impl_from_Client(iface);
147 WCHAR name[1024];
148 UINT i, len;
149
150 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pszName);
151
152 *pszName = NULL;
153 if(convert_child_id(&varID) != CHILDID_SELF || !IsWindow(This->hwnd))
154 return E_INVALIDARG;
155
156 len = SendMessageW(This->hwnd, WM_GETTEXT, sizeof(name)/sizeof(WCHAR), (LPARAM)name);
157 if(!len)
158 return S_FALSE;
159
160 for(i=0; i<len; i++) {
161 if(name[i] == '&') {
162 len--;
163 memmove(name+i, name+i+1, (len-i)*sizeof(WCHAR));
164 break;
165 }
166 }
167
168 *pszName = SysAllocStringLen(name, len);
169 return *pszName ? S_OK : E_OUTOFMEMORY;
170 }
171
172 static HRESULT WINAPI Client_get_accValue(IAccessible *iface, VARIANT varID, BSTR *pszValue)
173 {
174 Client *This = impl_from_Client(iface);
175
176 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pszValue);
177
178 *pszValue = NULL;
179 if(convert_child_id(&varID) != CHILDID_SELF)
180 return E_INVALIDARG;
181 return S_FALSE;
182 }
183
184 static HRESULT WINAPI Client_get_accDescription(IAccessible *iface,
185 VARIANT varID, BSTR *pszDescription)
186 {
187 Client *This = impl_from_Client(iface);
188
189 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pszDescription);
190
191 *pszDescription = NULL;
192 if(convert_child_id(&varID) != CHILDID_SELF)
193 return E_INVALIDARG;
194 return S_FALSE;
195 }
196
197 static HRESULT WINAPI Client_get_accRole(IAccessible *iface, VARIANT varID, VARIANT *pvarRole)
198 {
199 Client *This = impl_from_Client(iface);
200
201 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pvarRole);
202
203 if(convert_child_id(&varID) != CHILDID_SELF) {
204 V_VT(pvarRole) = VT_EMPTY;
205 return E_INVALIDARG;
206 }
207
208 V_VT(pvarRole) = VT_I4;
209 V_I4(pvarRole) = ROLE_SYSTEM_CLIENT;
210 return S_OK;
211 }
212
213 static HRESULT WINAPI Client_get_accState(IAccessible *iface, VARIANT varID, VARIANT *pvarState)
214 {
215 Client *This = impl_from_Client(iface);
216 LONG style;
217
218 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pvarState);
219
220 if(convert_child_id(&varID) != CHILDID_SELF) {
221 V_VT(pvarState) = VT_EMPTY;
222 return E_INVALIDARG;
223 }
224
225 V_VT(pvarState) = VT_I4;
226 V_I4(pvarState) = 0;
227
228 style = GetWindowLongW(This->hwnd, GWL_STYLE);
229 if(style & WS_DISABLED)
230 V_I4(pvarState) |= STATE_SYSTEM_UNAVAILABLE;
231 else if(IsWindow(This->hwnd))
232 V_I4(pvarState) |= STATE_SYSTEM_FOCUSABLE;
233 if(GetFocus() == This->hwnd)
234 V_I4(pvarState) |= STATE_SYSTEM_FOCUSED;
235 if(!(style & WS_VISIBLE))
236 V_I4(pvarState) |= STATE_SYSTEM_INVISIBLE;
237 return S_OK;
238 }
239
240 static HRESULT WINAPI Client_get_accHelp(IAccessible *iface, VARIANT varID, BSTR *pszHelp)
241 {
242 Client *This = impl_from_Client(iface);
243
244 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pszHelp);
245
246 *pszHelp = NULL;
247 if(convert_child_id(&varID) != CHILDID_SELF)
248 return E_INVALIDARG;
249 return S_FALSE;
250 }
251
252 static HRESULT WINAPI Client_get_accHelpTopic(IAccessible *iface,
253 BSTR *pszHelpFile, VARIANT varID, LONG *pidTopic)
254 {
255 Client *This = impl_from_Client(iface);
256 FIXME("(%p)->(%p %s %p)\n", This, pszHelpFile, debugstr_variant(&varID), pidTopic);
257 return E_NOTIMPL;
258 }
259
260 static HRESULT WINAPI Client_get_accKeyboardShortcut(IAccessible *iface,
261 VARIANT varID, BSTR *pszKeyboardShortcut)
262 {
263 static const WCHAR shortcut_fmt[] = {'A','l','t','+','!',0};
264 Client *This = impl_from_Client(iface);
265 WCHAR name[1024];
266 UINT i, len;
267
268 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pszKeyboardShortcut);
269
270 *pszKeyboardShortcut = NULL;
271 if(convert_child_id(&varID) != CHILDID_SELF)
272 return E_INVALIDARG;
273
274 len = SendMessageW(This->hwnd, WM_GETTEXT, sizeof(name)/sizeof(WCHAR), (LPARAM)name);
275 for(i=0; i<len; i++) {
276 if(name[i] == '&')
277 break;
278 }
279 if(i+1 >= len)
280 return S_FALSE;
281
282 *pszKeyboardShortcut = SysAllocString(shortcut_fmt);
283 if(!*pszKeyboardShortcut)
284 return E_OUTOFMEMORY;
285
286 (*pszKeyboardShortcut)[4] = name[i+1];
287 return S_OK;
288 }
289
290 static HRESULT WINAPI Client_get_accFocus(IAccessible *iface, VARIANT *pvarID)
291 {
292 Client *This = impl_from_Client(iface);
293 FIXME("(%p)->(%p)\n", This, pvarID);
294 return E_NOTIMPL;
295 }
296
297 static HRESULT WINAPI Client_get_accSelection(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_accDefaultAction(IAccessible *iface,
305 VARIANT varID, BSTR *pszDefaultAction)
306 {
307 Client *This = impl_from_Client(iface);
308
309 TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pszDefaultAction);
310
311 *pszDefaultAction = NULL;
312 if(convert_child_id(&varID) != CHILDID_SELF)
313 return E_INVALIDARG;
314 return S_FALSE;
315 }
316
317 static HRESULT WINAPI Client_accSelect(IAccessible *iface, LONG flagsSelect, VARIANT varID)
318 {
319 Client *This = impl_from_Client(iface);
320 FIXME("(%p)->(%x %s)\n", This, flagsSelect, debugstr_variant(&varID));
321 return E_NOTIMPL;
322 }
323
324 static HRESULT WINAPI Client_accLocation(IAccessible *iface, LONG *pxLeft,
325 LONG *pyTop, LONG *pcxWidth, LONG *pcyHeight, VARIANT varID)
326 {
327 Client *This = impl_from_Client(iface);
328 RECT rect;
329 POINT pt;
330
331 TRACE("(%p)->(%p %p %p %p %s)\n", This, pxLeft, pyTop,
332 pcxWidth, pcyHeight, debugstr_variant(&varID));
333
334 *pxLeft = *pyTop = *pcxWidth = *pcyHeight = 0;
335 if(convert_child_id(&varID) != CHILDID_SELF)
336 return E_INVALIDARG;
337
338 if(!GetClientRect(This->hwnd, &rect))
339 return S_OK;
340
341 pt.x = rect.left,
342 pt.y = rect.top;
343 MapWindowPoints(This->hwnd, NULL, &pt, 1);
344 *pxLeft = pt.x;
345 *pyTop = pt.y;
346
347 pt.x = rect.right;
348 pt.y = rect.bottom;
349 MapWindowPoints(This->hwnd, NULL, &pt, 1);
350 *pcxWidth = pt.x - *pxLeft;
351 *pcyHeight = pt.y - *pyTop;
352 return S_OK;
353 }
354
355 static HRESULT WINAPI Client_accNavigate(IAccessible *iface,
356 LONG navDir, VARIANT varStart, VARIANT *pvarEnd)
357 {
358 Client *This = impl_from_Client(iface);
359 FIXME("(%p)->(%d %s %p)\n", This, navDir, debugstr_variant(&varStart), pvarEnd);
360 return E_NOTIMPL;
361 }
362
363 static HRESULT WINAPI Client_accHitTest(IAccessible *iface,
364 LONG xLeft, LONG yTop, VARIANT *pvarID)
365 {
366 Client *This = impl_from_Client(iface);
367 HWND child;
368 POINT pt;
369
370 TRACE("(%p)->(%d %d %p)\n", This, xLeft, yTop, pvarID);
371
372 V_VT(pvarID) = VT_I4;
373 V_I4(pvarID) = 0;
374
375 pt.x = xLeft;
376 pt.y = yTop;
377 if(!IsWindowVisible(This->hwnd) || !ScreenToClient(This->hwnd, &pt))
378 return S_OK;
379
380 child = ChildWindowFromPointEx(This->hwnd, pt, CWP_SKIPINVISIBLE);
381 if(!child || child==This->hwnd)
382 return S_OK;
383
384 V_VT(pvarID) = VT_DISPATCH;
385 return AccessibleObjectFromWindow(child, OBJID_WINDOW,
386 &IID_IDispatch, (void**)&V_DISPATCH(pvarID));
387 }
388
389 static HRESULT WINAPI Client_accDoDefaultAction(IAccessible *iface, VARIANT varID)
390 {
391 Client *This = impl_from_Client(iface);
392 FIXME("(%p)->(%s)\n", This, debugstr_variant(&varID));
393 return E_NOTIMPL;
394 }
395
396 static HRESULT WINAPI Client_put_accName(IAccessible *iface, VARIANT varID, BSTR pszName)
397 {
398 Client *This = impl_from_Client(iface);
399 FIXME("(%p)->(%s %s)\n", This, debugstr_variant(&varID), debugstr_w(pszName));
400 return E_NOTIMPL;
401 }
402
403 static HRESULT WINAPI Client_put_accValue(IAccessible *iface, VARIANT varID, BSTR pszValue)
404 {
405 Client *This = impl_from_Client(iface);
406 FIXME("(%p)->(%s %s)\n", This, debugstr_variant(&varID), debugstr_w(pszValue));
407 return E_NOTIMPL;
408 }
409
410 static const IAccessibleVtbl ClientVtbl = {
411 Client_QueryInterface,
412 Client_AddRef,
413 Client_Release,
414 Client_GetTypeInfoCount,
415 Client_GetTypeInfo,
416 Client_GetIDsOfNames,
417 Client_Invoke,
418 Client_get_accParent,
419 Client_get_accChildCount,
420 Client_get_accChild,
421 Client_get_accName,
422 Client_get_accValue,
423 Client_get_accDescription,
424 Client_get_accRole,
425 Client_get_accState,
426 Client_get_accHelp,
427 Client_get_accHelpTopic,
428 Client_get_accKeyboardShortcut,
429 Client_get_accFocus,
430 Client_get_accSelection,
431 Client_get_accDefaultAction,
432 Client_accSelect,
433 Client_accLocation,
434 Client_accNavigate,
435 Client_accHitTest,
436 Client_accDoDefaultAction,
437 Client_put_accName,
438 Client_put_accValue
439 };
440
441 static inline Client* impl_from_Client_OleWindow(IOleWindow *iface)
442 {
443 return CONTAINING_RECORD(iface, Client, IOleWindow_iface);
444 }
445
446 static HRESULT WINAPI Client_OleWindow_QueryInterface(IOleWindow *iface, REFIID riid, void **ppv)
447 {
448 Client *This = impl_from_Client_OleWindow(iface);
449 return IAccessible_QueryInterface(&This->IAccessible_iface, riid, ppv);
450 }
451
452 static ULONG WINAPI Client_OleWindow_AddRef(IOleWindow *iface)
453 {
454 Client *This = impl_from_Client_OleWindow(iface);
455 return IAccessible_AddRef(&This->IAccessible_iface);
456 }
457
458 static ULONG WINAPI Client_OleWindow_Release(IOleWindow *iface)
459 {
460 Client *This = impl_from_Client_OleWindow(iface);
461 return IAccessible_Release(&This->IAccessible_iface);
462 }
463
464 static HRESULT WINAPI Client_OleWindow_GetWindow(IOleWindow *iface, HWND *phwnd)
465 {
466 Client *This = impl_from_Client_OleWindow(iface);
467
468 TRACE("(%p)->(%p)\n", This, phwnd);
469
470 *phwnd = This->hwnd;
471 return S_OK;
472 }
473
474 static HRESULT WINAPI Client_OleWindow_ContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMode)
475 {
476 Client *This = impl_from_Client_OleWindow(iface);
477 FIXME("(%p)->(%x)\n", This, fEnterMode);
478 return E_NOTIMPL;
479 }
480
481 static const IOleWindowVtbl ClientOleWindowVtbl = {
482 Client_OleWindow_QueryInterface,
483 Client_OleWindow_AddRef,
484 Client_OleWindow_Release,
485 Client_OleWindow_GetWindow,
486 Client_OleWindow_ContextSensitiveHelp
487 };
488
489 HRESULT create_client_object(HWND hwnd, const IID *iid, void **obj)
490 {
491 Client *client;
492 HRESULT hres;
493
494 if(!IsWindow(hwnd))
495 return E_FAIL;
496
497 client = heap_alloc_zero(sizeof(Client));
498 if(!client)
499 return E_OUTOFMEMORY;
500
501 client->IAccessible_iface.lpVtbl = &ClientVtbl;
502 client->IOleWindow_iface.lpVtbl = &ClientOleWindowVtbl;
503 client->ref = 1;
504 client->hwnd = hwnd;
505
506 hres = IAccessible_QueryInterface(&client->IAccessible_iface, iid, obj);
507 IAccessible_Release(&client->IAccessible_iface);
508 return hres;
509 }