oleacc: Added AccessibleChildren implementation.
[wine.git] / dlls / oleacc / main.c
blob4d9c55e992bbf156a3a50be9b393d2c1e3cfe6ce
1 /*
2 * Implementation of the OLEACC dll
4 * Copyright 2003 Mike McCormack for CodeWeavers
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.
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.
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
21 #define COBJMACROS
23 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "ole2.h"
27 #include "commctrl.h"
28 #include "rpcproxy.h"
30 #include "initguid.h"
31 #include "oleacc_private.h"
32 #include "resource.h"
34 #include "wine/unicode.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(oleacc);
39 static const WCHAR lresult_atom_prefix[] = {'w','i','n','e','_','o','l','e','a','c','c',':'};
41 static const WCHAR menuW[] = {'#','3','2','7','6','8',0};
42 static const WCHAR desktopW[] = {'#','3','2','7','6','9',0};
43 static const WCHAR dialogW[] = {'#','3','2','7','7','0',0};
44 static const WCHAR winswitchW[] = {'#','3','2','7','7','1',0};
45 static const WCHAR mdi_clientW[] = {'M','D','I','C','l','i','e','n','t',0};
46 static const WCHAR richeditW[] = {'R','I','C','H','E','D','I','T',0};
47 static const WCHAR richedit20aW[] = {'R','i','c','h','E','d','i','t','2','0','A',0};
48 static const WCHAR richedit20wW[] = {'R','i','c','h','E','d','i','t','2','0','W',0};
50 typedef HRESULT (WINAPI *accessible_create)(HWND, const IID*, void**);
52 static struct {
53 const WCHAR *name;
54 DWORD idx;
55 accessible_create create_client;
56 accessible_create create_window;
57 } builtin_classes[] = {
58 {WC_LISTBOXW, 0x10000, NULL, NULL},
59 {menuW, 0x10001, NULL, NULL},
60 {WC_BUTTONW, 0x10002, NULL, NULL},
61 {WC_STATICW, 0x10003, NULL, NULL},
62 {WC_EDITW, 0x10004, NULL, NULL},
63 {WC_COMBOBOXW, 0x10005, NULL, NULL},
64 {dialogW, 0x10006, NULL, NULL},
65 {winswitchW, 0x10007, NULL, NULL},
66 {mdi_clientW, 0x10008, NULL, NULL},
67 {desktopW, 0x10009, NULL, NULL},
68 {WC_SCROLLBARW, 0x1000a, NULL, NULL},
69 {STATUSCLASSNAMEW, 0x1000b, NULL, NULL},
70 {TOOLBARCLASSNAMEW, 0x1000c, NULL, NULL},
71 {PROGRESS_CLASSW, 0x1000d, NULL, NULL},
72 {ANIMATE_CLASSW, 0x1000e, NULL, NULL},
73 {WC_TABCONTROLW, 0x1000f, NULL, NULL},
74 {HOTKEY_CLASSW, 0x10010, NULL, NULL},
75 {WC_HEADERW, 0x10011, NULL, NULL},
76 {TRACKBAR_CLASSW, 0x10012, NULL, NULL},
77 {WC_LISTVIEWW, 0x10013, NULL, NULL},
78 {UPDOWN_CLASSW, 0x10016, NULL, NULL},
79 {TOOLTIPS_CLASSW, 0x10018, NULL, NULL},
80 {WC_TREEVIEWW, 0x10019, NULL, NULL},
81 {MONTHCAL_CLASSW, 0, NULL, NULL},
82 {DATETIMEPICK_CLASSW, 0, NULL, NULL},
83 {WC_IPADDRESSW, 0, NULL, NULL},
84 {richeditW, 0x1001c, NULL, NULL},
85 {richedit20aW, 0, NULL, NULL},
86 {richedit20wW, 0, NULL, NULL},
89 static HINSTANCE oleacc_handle = 0;
91 int convert_child_id(VARIANT *v)
93 switch(V_VT(v)) {
94 case VT_I4:
95 return V_I4(v);
96 default:
97 FIXME("unhandled child ID variant type: %d\n", V_VT(v));
98 return -1;
102 static accessible_create get_builtin_accessible_obj(HWND hwnd, LONG objid)
104 WCHAR class_name[64];
105 int i, idx;
107 if(!RealGetWindowClassW(hwnd, class_name, sizeof(class_name)/sizeof(WCHAR)))
108 return NULL;
109 TRACE("got window class: %s\n", debugstr_w(class_name));
111 for(i=0; i<sizeof(builtin_classes)/sizeof(builtin_classes[0]); i++) {
112 if(!strcmpiW(class_name, builtin_classes[i].name)) {
113 accessible_create ret;
115 ret = (objid==OBJID_CLIENT ?
116 builtin_classes[i].create_client :
117 builtin_classes[i].create_window);
118 if(!ret)
119 FIXME("unhandled window class: %s\n", debugstr_w(class_name));
120 return ret;
124 idx = SendMessageW(hwnd, WM_GETOBJECT, 0, OBJID_QUERYCLASSNAMEIDX);
125 if(idx) {
126 for(i=0; i<sizeof(builtin_classes)/sizeof(builtin_classes[0]); i++) {
127 if(idx == builtin_classes[i].idx) {
128 accessible_create ret;
130 ret = (objid==OBJID_CLIENT ?
131 builtin_classes[i].create_client :
132 builtin_classes[i].create_window);
133 if(!ret)
134 FIXME("unhandled class name idx: %x\n", idx);
135 return ret;
139 WARN("unhandled class name idx: %x\n", idx);
142 return NULL;
145 HRESULT WINAPI CreateStdAccessibleObject( HWND hwnd, LONG idObject,
146 REFIID riidInterface, void** ppvObject )
148 accessible_create create;
150 TRACE("%p %d %s %p\n", hwnd, idObject,
151 debugstr_guid( riidInterface ), ppvObject );
153 switch(idObject) {
154 case OBJID_CLIENT:
155 create = get_builtin_accessible_obj(hwnd, idObject);
156 if(create) return create(hwnd, riidInterface, ppvObject);
157 return create_client_object(hwnd, riidInterface, ppvObject);
158 case OBJID_WINDOW:
159 create = get_builtin_accessible_obj(hwnd, idObject);
160 if(create) return create(hwnd, riidInterface, ppvObject);
161 return create_window_object(hwnd, riidInterface, ppvObject);
162 default:
163 FIXME("unhandled object id: %d\n", idObject);
164 return E_NOTIMPL;
168 HRESULT WINAPI ObjectFromLresult( LRESULT result, REFIID riid, WPARAM wParam, void **ppObject )
170 WCHAR atom_str[sizeof(lresult_atom_prefix)/sizeof(WCHAR)+3*8+3];
171 HANDLE server_proc, server_mapping, mapping;
172 DWORD proc_id, size;
173 IStream *stream;
174 HGLOBAL data;
175 void *view;
176 HRESULT hr;
177 WCHAR *p;
179 TRACE("%ld %s %ld %p\n", result, debugstr_guid(riid), wParam, ppObject );
181 if(wParam)
182 FIXME("unsupported wParam = %lx\n", wParam);
184 if(!ppObject)
185 return E_INVALIDARG;
186 *ppObject = NULL;
188 if(result != (ATOM)result)
189 return E_FAIL;
191 if(!GlobalGetAtomNameW(result, atom_str, sizeof(atom_str)/sizeof(WCHAR)))
192 return E_FAIL;
193 if(memcmp(atom_str, lresult_atom_prefix, sizeof(lresult_atom_prefix)))
194 return E_FAIL;
195 p = atom_str + sizeof(lresult_atom_prefix)/sizeof(WCHAR);
196 proc_id = strtoulW(p, &p, 16);
197 if(*p != ':')
198 return E_FAIL;
199 server_mapping = ULongToHandle( strtoulW(p+1, &p, 16) );
200 if(*p != ':')
201 return E_FAIL;
202 size = strtoulW(p+1, &p, 16);
203 if(*p != 0)
204 return E_FAIL;
206 server_proc = OpenProcess(PROCESS_DUP_HANDLE, FALSE, proc_id);
207 if(!server_proc)
208 return E_FAIL;
210 if(!DuplicateHandle(server_proc, server_mapping, GetCurrentProcess(), &mapping,
211 0, FALSE, DUPLICATE_CLOSE_SOURCE|DUPLICATE_SAME_ACCESS))
212 return E_FAIL;
213 CloseHandle(server_proc);
214 GlobalDeleteAtom(result);
216 view = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
217 CloseHandle(mapping);
218 if(!view)
219 return E_FAIL;
221 data = GlobalAlloc(GMEM_FIXED, size);
222 if(!data) {
223 UnmapViewOfFile(view);
224 return E_OUTOFMEMORY;
226 memcpy(data, view, size);
227 UnmapViewOfFile(view);
229 hr = CreateStreamOnHGlobal(data, TRUE, &stream);
230 if(FAILED(hr)) {
231 GlobalFree(data);
232 return hr;
235 hr = CoUnmarshalInterface(stream, riid, ppObject);
236 IStream_Release(stream);
237 return hr;
240 LRESULT WINAPI LresultFromObject( REFIID riid, WPARAM wParam, LPUNKNOWN pAcc )
242 static const WCHAR atom_fmt[] = {'%','0','8','x',':','%','0','8','x',':','%','0','8','x',0};
243 static const LARGE_INTEGER seek_zero = {{0}};
245 WCHAR atom_str[sizeof(lresult_atom_prefix)/sizeof(WCHAR)+3*8+3];
246 IStream *stream;
247 HANDLE mapping;
248 STATSTG stat;
249 HRESULT hr;
250 ATOM atom;
251 void *view;
253 TRACE("%s %ld %p\n", debugstr_guid(riid), wParam, pAcc);
255 if(wParam)
256 FIXME("unsupported wParam = %lx\n", wParam);
258 if(!pAcc)
259 return E_INVALIDARG;
261 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
262 if(FAILED(hr))
263 return hr;
265 hr = CoMarshalInterface(stream, riid, pAcc, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL);
266 if(FAILED(hr)) {
267 IStream_Release(stream);
268 return hr;
271 hr = IStream_Seek(stream, seek_zero, STREAM_SEEK_SET, NULL);
272 if(FAILED(hr)) {
273 IStream_Release(stream);
274 return hr;
277 hr = IStream_Stat(stream, &stat, STATFLAG_NONAME);
278 if(FAILED(hr)) {
279 CoReleaseMarshalData(stream);
280 IStream_Release(stream);
281 return hr;
282 }else if(stat.cbSize.u.HighPart) {
283 FIXME("stream size to big\n");
284 CoReleaseMarshalData(stream);
285 IStream_Release(stream);
286 return E_NOTIMPL;
289 mapping = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
290 stat.cbSize.u.HighPart, stat.cbSize.u.LowPart, NULL);
291 if(!mapping) {
292 CoReleaseMarshalData(stream);
293 IStream_Release(stream);
294 return hr;
297 view = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0);
298 if(!view) {
299 CloseHandle(mapping);
300 CoReleaseMarshalData(stream);
301 IStream_Release(stream);
302 return E_FAIL;
305 hr = IStream_Read(stream, view, stat.cbSize.u.LowPart, NULL);
306 UnmapViewOfFile(view);
307 if(FAILED(hr)) {
308 CloseHandle(mapping);
309 hr = IStream_Seek(stream, seek_zero, STREAM_SEEK_SET, NULL);
310 if(SUCCEEDED(hr))
311 CoReleaseMarshalData(stream);
312 IStream_Release(stream);
313 return hr;
317 memcpy(atom_str, lresult_atom_prefix, sizeof(lresult_atom_prefix));
318 sprintfW(atom_str+sizeof(lresult_atom_prefix)/sizeof(WCHAR),
319 atom_fmt, GetCurrentProcessId(), HandleToUlong(mapping), stat.cbSize.u.LowPart);
320 atom = GlobalAddAtomW(atom_str);
321 if(!atom) {
322 CloseHandle(mapping);
323 hr = IStream_Seek(stream, seek_zero, STREAM_SEEK_SET, NULL);
324 if(SUCCEEDED(hr))
325 CoReleaseMarshalData(stream);
326 IStream_Release(stream);
327 return E_FAIL;
330 IStream_Release(stream);
331 return atom;
334 HRESULT WINAPI AccessibleObjectFromPoint( POINT ptScreen, IAccessible** ppacc, VARIANT* pvarChild )
336 FIXME("{%d,%d} %p %p: stub\n", ptScreen.x, ptScreen.y, ppacc, pvarChild );
337 return E_NOTIMPL;
340 HRESULT WINAPI AccessibleObjectFromWindow( HWND hwnd, DWORD dwObjectID,
341 REFIID riid, void** ppvObject )
343 TRACE("%p %d %s %p\n", hwnd, dwObjectID,
344 debugstr_guid( riid ), ppvObject );
346 if(!ppvObject)
347 return E_INVALIDARG;
348 *ppvObject = NULL;
350 if(IsWindow(hwnd)) {
351 LRESULT lres;
353 lres = SendMessageW(hwnd, WM_GETOBJECT, 0xffffffff, dwObjectID);
354 if(FAILED(lres))
355 return lres;
356 else if(lres)
357 return ObjectFromLresult(lres, riid, 0, ppvObject);
360 return CreateStdAccessibleObject(hwnd, dwObjectID, riid, ppvObject);
363 HRESULT WINAPI WindowFromAccessibleObject(IAccessible *acc, HWND *phwnd)
365 IDispatch *parent;
366 IOleWindow *ow;
367 HRESULT hres;
369 TRACE("%p %p\n", acc, phwnd);
371 IAccessible_AddRef(acc);
372 while(1) {
373 hres = IAccessible_QueryInterface(acc, &IID_IOleWindow, (void**)&ow);
374 if(SUCCEEDED(hres)) {
375 hres = IOleWindow_GetWindow(ow, phwnd);
376 IOleWindow_Release(ow);
377 IAccessible_Release(acc);
378 return hres;
381 hres = IAccessible_get_accParent(acc, &parent);
382 IAccessible_Release(acc);
383 if(FAILED(hres))
384 return hres;
385 if(hres!=S_OK || !parent) {
386 *phwnd = NULL;
387 return hres;
390 hres = IDispatch_QueryInterface(parent, &IID_IAccessible, (void**)&acc);
391 IDispatch_Release(parent);
392 if(FAILED(hres))
393 return hres;
397 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
398 LPVOID lpvReserved)
400 TRACE("%p, %d, %p\n", hinstDLL, fdwReason, lpvReserved);
402 switch (fdwReason)
404 case DLL_PROCESS_ATTACH:
405 oleacc_handle = hinstDLL;
406 DisableThreadLibraryCalls(hinstDLL);
407 break;
409 return TRUE;
412 HRESULT WINAPI DllRegisterServer(void)
414 TRACE("()\n");
415 return __wine_register_resources(oleacc_handle);
418 HRESULT WINAPI DllUnregisterServer(void)
420 TRACE("()\n");
421 return __wine_unregister_resources(oleacc_handle);
424 void WINAPI GetOleaccVersionInfo(DWORD* pVersion, DWORD* pBuild)
426 *pVersion = MAKELONG(0,7); /* Windows 7 version of oleacc: 7.0.0.0 */
427 *pBuild = MAKELONG(0,0);
430 HANDLE WINAPI GetProcessHandleFromHwnd(HWND hwnd)
432 DWORD proc_id;
434 TRACE("%p\n", hwnd);
436 if(!GetWindowThreadProcessId(hwnd, &proc_id))
437 return NULL;
438 return OpenProcess(PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION |
439 PROCESS_VM_READ | PROCESS_VM_WRITE | SYNCHRONIZE, TRUE, proc_id);
442 UINT WINAPI GetRoleTextW(DWORD role, LPWSTR lpRole, UINT rolemax)
444 INT ret;
445 WCHAR *resptr;
447 TRACE("%u %p %u\n", role, lpRole, rolemax);
449 /* return role text length */
450 if(!lpRole)
451 return LoadStringW(oleacc_handle, role, (LPWSTR)&resptr, 0);
453 ret = LoadStringW(oleacc_handle, role, lpRole, rolemax);
454 if(!(ret > 0)){
455 if(rolemax > 0) lpRole[0] = '\0';
456 return 0;
459 return ret;
462 UINT WINAPI GetRoleTextA(DWORD role, LPSTR lpRole, UINT rolemax)
464 UINT length;
465 WCHAR *roletextW;
467 TRACE("%u %p %u\n", role, lpRole, rolemax);
469 if(lpRole && !rolemax)
470 return 0;
472 length = GetRoleTextW(role, NULL, 0);
473 if(!length) {
474 if(lpRole && rolemax)
475 lpRole[0] = 0;
476 return 0;
479 roletextW = HeapAlloc(GetProcessHeap(), 0, (length + 1)*sizeof(WCHAR));
480 if(!roletextW)
481 return 0;
483 GetRoleTextW(role, roletextW, length + 1);
485 length = WideCharToMultiByte( CP_ACP, 0, roletextW, -1, NULL, 0, NULL, NULL );
487 if(!lpRole){
488 HeapFree(GetProcessHeap(), 0, roletextW);
489 return length - 1;
492 if(rolemax < length) {
493 HeapFree(GetProcessHeap(), 0, roletextW);
494 lpRole[0] = 0;
495 return 0;
498 WideCharToMultiByte( CP_ACP, 0, roletextW, -1, lpRole, rolemax, NULL, NULL );
500 if(rolemax < length){
501 lpRole[rolemax-1] = '\0';
502 length = rolemax;
505 HeapFree(GetProcessHeap(), 0, roletextW);
507 return length - 1;
510 UINT WINAPI GetStateTextW(DWORD state_bit, WCHAR *state_str, UINT state_str_len)
512 DWORD state_id;
514 TRACE("%x %p %u\n", state_bit, state_str, state_str_len);
516 if(state_bit & ~(STATE_SYSTEM_VALID | STATE_SYSTEM_HASPOPUP)) {
517 if(state_str && state_str_len)
518 state_str[0] = 0;
519 return 0;
522 state_id = IDS_STATE_NORMAL;
523 while(state_bit) {
524 state_id++;
525 state_bit /= 2;
528 if(state_str) {
529 UINT ret = LoadStringW(oleacc_handle, state_id, state_str, state_str_len);
530 if(!ret && state_str_len)
531 state_str[0] = 0;
532 return ret;
533 }else {
534 WCHAR *tmp;
535 return LoadStringW(oleacc_handle, state_id, (WCHAR*)&tmp, 0);
540 UINT WINAPI GetStateTextA(DWORD state_bit, CHAR *state_str, UINT state_str_len)
542 DWORD state_id;
544 TRACE("%x %p %u\n", state_bit, state_str, state_str_len);
546 if(state_str && !state_str_len)
547 return 0;
549 if(state_bit & ~(STATE_SYSTEM_VALID | STATE_SYSTEM_HASPOPUP)) {
550 if(state_str && state_str_len)
551 state_str[0] = 0;
552 return 0;
555 state_id = IDS_STATE_NORMAL;
556 while(state_bit) {
557 state_id++;
558 state_bit /= 2;
561 if(state_str) {
562 UINT ret = LoadStringA(oleacc_handle, state_id, state_str, state_str_len);
563 if(!ret && state_str_len)
564 state_str[0] = 0;
565 return ret;
566 }else {
567 CHAR tmp[256];
568 return LoadStringA(oleacc_handle, state_id, tmp, sizeof(tmp));
572 HRESULT WINAPI AccessibleChildren(IAccessible *container,
573 LONG start, LONG count, VARIANT *children, LONG *children_cnt)
575 IEnumVARIANT *ev;
576 LONG i, child_no;
577 HRESULT hr;
579 TRACE("%p %d %d %p %p\n", container, start, count, children, children_cnt);
581 if(!container || !children || !children_cnt)
582 return E_INVALIDARG;
584 for(i=0; i<count; i++)
585 VariantInit(children+i);
587 hr = IAccessible_QueryInterface(container, &IID_IEnumVARIANT, (void**)&ev);
588 if(SUCCEEDED(hr)) {
589 hr = IEnumVARIANT_Reset(ev);
590 if(SUCCEEDED(hr))
591 hr = IEnumVARIANT_Skip(ev, start);
592 if(SUCCEEDED(hr))
593 hr = IEnumVARIANT_Next(ev, count, children, (ULONG*)children_cnt);
594 IEnumVARIANT_Release(ev);
595 return hr;
598 hr = IAccessible_get_accChildCount(container, &child_no);
599 if(FAILED(hr))
600 return hr;
602 for(i=0; i<count && start+i+1<=child_no; i++) {
603 IDispatch *disp;
605 V_VT(children+i) = VT_I4;
606 V_I4(children+i) = start+i+1;
608 hr = IAccessible_get_accChild(container, children[i], &disp);
609 if(SUCCEEDED(hr) && disp) {
610 V_VT(children+i) = VT_DISPATCH;
611 V_DISPATCH(children+i) = disp;
615 *children_cnt = i;
616 return i==count ? S_OK : S_FALSE;