Sync to trunk r65566.
[reactos.git] / dll / win32 / oleacc / main.c
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 #include "oleacc_private.h"
22
23 #include <commctrl.h>
24 #include <rpcproxy.h>
25
26 #include <wine/unicode.h>
27
28 #include "resource.h"
29
30 static const WCHAR lresult_atom_prefix[] = {'w','i','n','e','_','o','l','e','a','c','c',':'};
31
32 static const WCHAR menuW[] = {'#','3','2','7','6','8',0};
33 static const WCHAR desktopW[] = {'#','3','2','7','6','9',0};
34 static const WCHAR dialogW[] = {'#','3','2','7','7','0',0};
35 static const WCHAR winswitchW[] = {'#','3','2','7','7','1',0};
36 static const WCHAR mdi_clientW[] = {'M','D','I','C','l','i','e','n','t',0};
37 static const WCHAR richeditW[] = {'R','I','C','H','E','D','I','T',0};
38 static const WCHAR richedit20aW[] = {'R','i','c','h','E','d','i','t','2','0','A',0};
39 static const WCHAR richedit20wW[] = {'R','i','c','h','E','d','i','t','2','0','W',0};
40
41 typedef HRESULT (WINAPI *accessible_create)(HWND, const IID*, void**);
42
43 static struct {
44 const WCHAR *name;
45 DWORD idx;
46 accessible_create create_client;
47 accessible_create create_window;
48 } builtin_classes[] = {
49 {WC_LISTBOXW, 0x10000, NULL, NULL},
50 {menuW, 0x10001, NULL, NULL},
51 {WC_BUTTONW, 0x10002, NULL, NULL},
52 {WC_STATICW, 0x10003, NULL, NULL},
53 {WC_EDITW, 0x10004, NULL, NULL},
54 {WC_COMBOBOXW, 0x10005, NULL, NULL},
55 {dialogW, 0x10006, NULL, NULL},
56 {winswitchW, 0x10007, NULL, NULL},
57 {mdi_clientW, 0x10008, NULL, NULL},
58 {desktopW, 0x10009, NULL, NULL},
59 {WC_SCROLLBARW, 0x1000a, NULL, NULL},
60 {STATUSCLASSNAMEW, 0x1000b, NULL, NULL},
61 {TOOLBARCLASSNAMEW, 0x1000c, NULL, NULL},
62 {PROGRESS_CLASSW, 0x1000d, NULL, NULL},
63 {ANIMATE_CLASSW, 0x1000e, NULL, NULL},
64 {WC_TABCONTROLW, 0x1000f, NULL, NULL},
65 {HOTKEY_CLASSW, 0x10010, NULL, NULL},
66 {WC_HEADERW, 0x10011, NULL, NULL},
67 {TRACKBAR_CLASSW, 0x10012, NULL, NULL},
68 {WC_LISTVIEWW, 0x10013, NULL, NULL},
69 {UPDOWN_CLASSW, 0x10016, NULL, NULL},
70 {TOOLTIPS_CLASSW, 0x10018, NULL, NULL},
71 {WC_TREEVIEWW, 0x10019, NULL, NULL},
72 {MONTHCAL_CLASSW, 0, NULL, NULL},
73 {DATETIMEPICK_CLASSW, 0, NULL, NULL},
74 {WC_IPADDRESSW, 0, NULL, NULL},
75 {richeditW, 0x1001c, NULL, NULL},
76 {richedit20aW, 0, NULL, NULL},
77 {richedit20wW, 0, NULL, NULL},
78 };
79
80 static HINSTANCE oleacc_handle = 0;
81
82 int convert_child_id(VARIANT *v)
83 {
84 switch(V_VT(v)) {
85 case VT_I4:
86 return V_I4(v);
87 default:
88 FIXME("unhandled child ID variant type: %d\n", V_VT(v));
89 return -1;
90 }
91 }
92
93 static accessible_create get_builtin_accessible_obj(HWND hwnd, LONG objid)
94 {
95 WCHAR class_name[64];
96 int i, idx;
97
98 if(!RealGetWindowClassW(hwnd, class_name, sizeof(class_name)/sizeof(WCHAR)))
99 return NULL;
100 TRACE("got window class: %s\n", debugstr_w(class_name));
101
102 for(i=0; i<sizeof(builtin_classes)/sizeof(builtin_classes[0]); i++) {
103 if(!strcmpiW(class_name, builtin_classes[i].name)) {
104 accessible_create ret;
105
106 ret = (objid==OBJID_CLIENT ?
107 builtin_classes[i].create_client :
108 builtin_classes[i].create_window);
109 if(!ret)
110 FIXME("unhandled window class: %s\n", debugstr_w(class_name));
111 return ret;
112 }
113 }
114
115 idx = SendMessageW(hwnd, WM_GETOBJECT, 0, OBJID_QUERYCLASSNAMEIDX);
116 if(idx) {
117 for(i=0; i<sizeof(builtin_classes)/sizeof(builtin_classes[0]); i++) {
118 if(idx == builtin_classes[i].idx) {
119 accessible_create ret;
120
121 ret = (objid==OBJID_CLIENT ?
122 builtin_classes[i].create_client :
123 builtin_classes[i].create_window);
124 if(!ret)
125 FIXME("unhandled class name idx: %x\n", idx);
126 return ret;
127 }
128 }
129
130 WARN("unhandled class name idx: %x\n", idx);
131 }
132
133 return NULL;
134 }
135
136 HRESULT WINAPI CreateStdAccessibleObject( HWND hwnd, LONG idObject,
137 REFIID riidInterface, void** ppvObject )
138 {
139 accessible_create create;
140
141 TRACE("%p %d %s %p\n", hwnd, idObject,
142 debugstr_guid( riidInterface ), ppvObject );
143
144 switch(idObject) {
145 case OBJID_CLIENT:
146 create = get_builtin_accessible_obj(hwnd, idObject);
147 if(create) return create(hwnd, riidInterface, ppvObject);
148 return create_client_object(hwnd, riidInterface, ppvObject);
149 case OBJID_WINDOW:
150 create = get_builtin_accessible_obj(hwnd, idObject);
151 if(create) return create(hwnd, riidInterface, ppvObject);
152 return create_window_object(hwnd, riidInterface, ppvObject);
153 default:
154 FIXME("unhandled object id: %d\n", idObject);
155 return E_NOTIMPL;
156 }
157 }
158
159 HRESULT WINAPI ObjectFromLresult( LRESULT result, REFIID riid, WPARAM wParam, void **ppObject )
160 {
161 WCHAR atom_str[sizeof(lresult_atom_prefix)/sizeof(WCHAR)+3*8+3];
162 HANDLE server_proc, server_mapping, mapping;
163 DWORD proc_id, size;
164 IStream *stream;
165 HGLOBAL data;
166 void *view;
167 HRESULT hr;
168 WCHAR *p;
169
170 TRACE("%ld %s %ld %p\n", result, debugstr_guid(riid), wParam, ppObject );
171
172 if(wParam)
173 FIXME("unsupported wParam = %lx\n", wParam);
174
175 if(!ppObject)
176 return E_INVALIDARG;
177 *ppObject = NULL;
178
179 if(result != (ATOM)result)
180 return E_FAIL;
181
182 if(!GlobalGetAtomNameW(result, atom_str, sizeof(atom_str)/sizeof(WCHAR)))
183 return E_FAIL;
184 if(memcmp(atom_str, lresult_atom_prefix, sizeof(lresult_atom_prefix)))
185 return E_FAIL;
186 p = atom_str + sizeof(lresult_atom_prefix)/sizeof(WCHAR);
187 proc_id = strtoulW(p, &p, 16);
188 if(*p != ':')
189 return E_FAIL;
190 server_mapping = ULongToHandle( strtoulW(p+1, &p, 16) );
191 if(*p != ':')
192 return E_FAIL;
193 size = strtoulW(p+1, &p, 16);
194 if(*p != 0)
195 return E_FAIL;
196
197 server_proc = OpenProcess(PROCESS_DUP_HANDLE, FALSE, proc_id);
198 if(!server_proc)
199 return E_FAIL;
200
201 if(!DuplicateHandle(server_proc, server_mapping, GetCurrentProcess(), &mapping,
202 0, FALSE, DUPLICATE_CLOSE_SOURCE|DUPLICATE_SAME_ACCESS))
203 return E_FAIL;
204 CloseHandle(server_proc);
205 GlobalDeleteAtom(result);
206
207 view = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
208 CloseHandle(mapping);
209 if(!view)
210 return E_FAIL;
211
212 data = GlobalAlloc(GMEM_FIXED, size);
213 memcpy(data, view, size);
214 UnmapViewOfFile(view);
215 if(!data)
216 return E_OUTOFMEMORY;
217
218 hr = CreateStreamOnHGlobal(data, TRUE, &stream);
219 if(FAILED(hr)) {
220 GlobalFree(data);
221 return hr;
222 }
223
224 hr = CoUnmarshalInterface(stream, riid, ppObject);
225 IStream_Release(stream);
226 return hr;
227 }
228
229 LRESULT WINAPI LresultFromObject( REFIID riid, WPARAM wParam, LPUNKNOWN pAcc )
230 {
231 static const WCHAR atom_fmt[] = {'%','0','8','x',':','%','0','8','x',':','%','0','8','x',0};
232 static const LARGE_INTEGER seek_zero = {{0}};
233
234 WCHAR atom_str[sizeof(lresult_atom_prefix)/sizeof(WCHAR)+3*8+3];
235 IStream *stream;
236 HANDLE mapping;
237 STATSTG stat;
238 HRESULT hr;
239 ATOM atom;
240 void *view;
241
242 TRACE("%s %ld %p\n", debugstr_guid(riid), wParam, pAcc);
243
244 if(wParam)
245 FIXME("unsupported wParam = %lx\n", wParam);
246
247 if(!pAcc)
248 return E_INVALIDARG;
249
250 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
251 if(FAILED(hr))
252 return hr;
253
254 hr = CoMarshalInterface(stream, riid, pAcc, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL);
255 if(FAILED(hr)) {
256 IStream_Release(stream);
257 return hr;
258 }
259
260 hr = IStream_Seek(stream, seek_zero, STREAM_SEEK_SET, NULL);
261 if(FAILED(hr)) {
262 IStream_Release(stream);
263 return hr;
264 }
265
266 hr = IStream_Stat(stream, &stat, STATFLAG_NONAME);
267 if(FAILED(hr)) {
268 CoReleaseMarshalData(stream);
269 IStream_Release(stream);
270 return hr;
271 }else if(stat.cbSize.u.HighPart) {
272 FIXME("stream size to big\n");
273 CoReleaseMarshalData(stream);
274 IStream_Release(stream);
275 return E_NOTIMPL;
276 }
277
278 mapping = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
279 stat.cbSize.u.HighPart, stat.cbSize.u.LowPart, NULL);
280 if(!mapping) {
281 CoReleaseMarshalData(stream);
282 IStream_Release(stream);
283 return hr;
284 }
285
286 view = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0);
287 if(!view) {
288 CloseHandle(mapping);
289 CoReleaseMarshalData(stream);
290 IStream_Release(stream);
291 return E_FAIL;
292 }
293
294 hr = IStream_Read(stream, view, stat.cbSize.u.LowPart, NULL);
295 UnmapViewOfFile(view);
296 if(FAILED(hr)) {
297 CloseHandle(mapping);
298 hr = IStream_Seek(stream, seek_zero, STREAM_SEEK_SET, NULL);
299 if(SUCCEEDED(hr))
300 CoReleaseMarshalData(stream);
301 IStream_Release(stream);
302 return hr;
303
304 }
305
306 memcpy(atom_str, lresult_atom_prefix, sizeof(lresult_atom_prefix));
307 sprintfW(atom_str+sizeof(lresult_atom_prefix)/sizeof(WCHAR),
308 atom_fmt, GetCurrentProcessId(), HandleToUlong(mapping), stat.cbSize.u.LowPart);
309 atom = GlobalAddAtomW(atom_str);
310 if(!atom) {
311 CloseHandle(mapping);
312 hr = IStream_Seek(stream, seek_zero, STREAM_SEEK_SET, NULL);
313 if(SUCCEEDED(hr))
314 CoReleaseMarshalData(stream);
315 IStream_Release(stream);
316 return E_FAIL;
317 }
318
319 IStream_Release(stream);
320 return atom;
321 }
322
323 HRESULT WINAPI AccessibleObjectFromPoint( POINT ptScreen, IAccessible** ppacc, VARIANT* pvarChild )
324 {
325 FIXME("{%d,%d} %p %p: stub\n", ptScreen.x, ptScreen.y, ppacc, pvarChild );
326 return E_NOTIMPL;
327 }
328
329 HRESULT WINAPI AccessibleObjectFromWindow( HWND hwnd, DWORD dwObjectID,
330 REFIID riid, void** ppvObject )
331 {
332 TRACE("%p %d %s %p\n", hwnd, dwObjectID,
333 debugstr_guid( riid ), ppvObject );
334
335 if(!ppvObject)
336 return E_INVALIDARG;
337 *ppvObject = NULL;
338
339 if(IsWindow(hwnd)) {
340 LRESULT lres;
341
342 lres = SendMessageW(hwnd, WM_GETOBJECT, 0xffffffff, dwObjectID);
343 if(FAILED(lres))
344 return lres;
345 else if(lres)
346 return ObjectFromLresult(lres, riid, 0, ppvObject);
347 }
348
349 return CreateStdAccessibleObject(hwnd, dwObjectID, riid, ppvObject);
350 }
351
352 HRESULT WINAPI WindowFromAccessibleObject(IAccessible *acc, HWND *phwnd)
353 {
354 IDispatch *parent;
355 IOleWindow *ow;
356 HRESULT hres;
357
358 TRACE("%p %p\n", acc, phwnd);
359
360 IAccessible_AddRef(acc);
361 while(1) {
362 hres = IAccessible_QueryInterface(acc, &IID_IOleWindow, (void**)&ow);
363 if(SUCCEEDED(hres)) {
364 hres = IOleWindow_GetWindow(ow, phwnd);
365 IOleWindow_Release(ow);
366 IAccessible_Release(acc);
367 return hres;
368 }
369
370 hres = IAccessible_get_accParent(acc, &parent);
371 IAccessible_Release(acc);
372 if(FAILED(hres))
373 return hres;
374 if(hres!=S_OK || !parent) {
375 *phwnd = NULL;
376 return hres;
377 }
378
379 hres = IDispatch_QueryInterface(parent, &IID_IAccessible, (void**)&acc);
380 IDispatch_Release(parent);
381 if(FAILED(hres))
382 return hres;
383 }
384 }
385
386 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
387 LPVOID lpvReserved)
388 {
389 TRACE("%p, %d, %p\n", hinstDLL, fdwReason, lpvReserved);
390
391 switch (fdwReason)
392 {
393 case DLL_PROCESS_ATTACH:
394 oleacc_handle = hinstDLL;
395 DisableThreadLibraryCalls(hinstDLL);
396 break;
397 }
398 return TRUE;
399 }
400
401 HRESULT WINAPI DllRegisterServer(void)
402 {
403 TRACE("()\n");
404 return __wine_register_resources(oleacc_handle);
405 }
406
407 HRESULT WINAPI DllUnregisterServer(void)
408 {
409 TRACE("()\n");
410 return __wine_unregister_resources(oleacc_handle);
411 }
412
413 void WINAPI GetOleaccVersionInfo(DWORD* pVersion, DWORD* pBuild)
414 {
415 *pVersion = MAKELONG(2,4); /* Windows XP version of oleacc: 4.2.5406.0 */
416 *pBuild = MAKELONG(0,5406);
417 }
418
419 HANDLE WINAPI GetProcessHandleFromHwnd(HWND hwnd)
420 {
421 DWORD proc_id;
422
423 TRACE("%p\n", hwnd);
424
425 if(!GetWindowThreadProcessId(hwnd, &proc_id))
426 return NULL;
427 return OpenProcess(PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION |
428 PROCESS_VM_READ | PROCESS_VM_WRITE | SYNCHRONIZE, TRUE, proc_id);
429 }
430
431 UINT WINAPI GetRoleTextW(DWORD role, LPWSTR lpRole, UINT rolemax)
432 {
433 INT ret;
434 WCHAR *resptr;
435
436 TRACE("%u %p %u\n", role, lpRole, rolemax);
437
438 /* return role text length */
439 if(!lpRole)
440 return LoadStringW(oleacc_handle, role, (LPWSTR)&resptr, 0);
441
442 ret = LoadStringW(oleacc_handle, role, lpRole, rolemax);
443 if(!(ret > 0)){
444 if(rolemax > 0) lpRole[0] = '\0';
445 return 0;
446 }
447
448 return ret;
449 }
450
451 UINT WINAPI GetRoleTextA(DWORD role, LPSTR lpRole, UINT rolemax)
452 {
453 UINT length;
454 WCHAR *roletextW;
455
456 TRACE("%u %p %u\n", role, lpRole, rolemax);
457
458 if(lpRole && !rolemax)
459 return 0;
460
461 length = GetRoleTextW(role, NULL, 0);
462 if(!length) {
463 if(lpRole && rolemax)
464 lpRole[0] = 0;
465 return 0;
466 }
467
468 roletextW = HeapAlloc(GetProcessHeap(), 0, (length + 1)*sizeof(WCHAR));
469 if(!roletextW)
470 return 0;
471
472 GetRoleTextW(role, roletextW, length + 1);
473
474 length = WideCharToMultiByte( CP_ACP, 0, roletextW, -1, NULL, 0, NULL, NULL );
475
476 if(!lpRole){
477 HeapFree(GetProcessHeap(), 0, roletextW);
478 return length - 1;
479 }
480
481 if(rolemax < length) {
482 HeapFree(GetProcessHeap(), 0, roletextW);
483 lpRole[0] = 0;
484 return 0;
485 }
486
487 WideCharToMultiByte( CP_ACP, 0, roletextW, -1, lpRole, rolemax, NULL, NULL );
488
489 if(rolemax < length){
490 lpRole[rolemax-1] = '\0';
491 length = rolemax;
492 }
493
494 HeapFree(GetProcessHeap(), 0, roletextW);
495
496 return length - 1;
497 }
498
499 UINT WINAPI GetStateTextW(DWORD state_bit, WCHAR *state_str, UINT state_str_len)
500 {
501 DWORD state_id;
502
503 TRACE("%x %p %u\n", state_bit, state_str, state_str_len);
504
505 if(state_bit & ~(STATE_SYSTEM_VALID | STATE_SYSTEM_HASPOPUP)) {
506 if(state_str && state_str_len)
507 state_str[0] = 0;
508 return 0;
509 }
510
511 state_id = IDS_STATE_NORMAL;
512 while(state_bit) {
513 state_id++;
514 state_bit /= 2;
515 }
516
517 if(state_str) {
518 UINT ret = LoadStringW(oleacc_handle, state_id, state_str, state_str_len);
519 if(!ret && state_str_len)
520 state_str[0] = 0;
521 return ret;
522 }else {
523 WCHAR *tmp;
524 return LoadStringW(oleacc_handle, state_id, (WCHAR*)&tmp, 0);
525 }
526
527 }
528
529 UINT WINAPI GetStateTextA(DWORD state_bit, CHAR *state_str, UINT state_str_len)
530 {
531 DWORD state_id;
532
533 TRACE("%x %p %u\n", state_bit, state_str, state_str_len);
534
535 if(state_str && !state_str_len)
536 return 0;
537
538 if(state_bit & ~(STATE_SYSTEM_VALID | STATE_SYSTEM_HASPOPUP)) {
539 if(state_str && state_str_len)
540 state_str[0] = 0;
541 return 0;
542 }
543
544 state_id = IDS_STATE_NORMAL;
545 while(state_bit) {
546 state_id++;
547 state_bit /= 2;
548 }
549
550 if(state_str) {
551 UINT ret = LoadStringA(oleacc_handle, state_id, state_str, state_str_len);
552 if(!ret && state_str_len)
553 state_str[0] = 0;
554 return ret;
555 }else {
556 CHAR tmp[256];
557 return LoadStringA(oleacc_handle, state_id, tmp, sizeof(tmp));
558 }
559 }