po: Update Japanese translation.
[wine.git] / dlls / oleacc / main.c
blobf6b66a8bcaba9af08db590922f2d2219acf93732
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/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(oleacc);
38 static const WCHAR lresult_atom_prefix[] = {'w','i','n','e','_','o','l','e','a','c','c',':'};
40 typedef HRESULT (WINAPI *accessible_create)(HWND, const IID*, void**);
42 extern HRESULT WINAPI OLEACC_DllGetClassObject(REFCLSID, REFIID, void**) DECLSPEC_HIDDEN;
43 extern BOOL WINAPI OLEACC_DllMain(HINSTANCE, DWORD, void*) DECLSPEC_HIDDEN;
44 extern HRESULT WINAPI OLEACC_DllRegisterServer(void) DECLSPEC_HIDDEN;
45 extern HRESULT WINAPI OLEACC_DllUnregisterServer(void) DECLSPEC_HIDDEN;
47 static struct {
48 const WCHAR *name;
49 DWORD idx;
50 accessible_create create_client;
51 accessible_create create_window;
52 } builtin_classes[] = {
53 {WC_LISTBOXW, 0x10000, NULL, NULL},
54 {L"#32768", 0x10001, NULL, NULL}, /* menu */
55 {WC_BUTTONW, 0x10002, NULL, NULL},
56 {WC_STATICW, 0x10003, NULL, NULL},
57 {WC_EDITW, 0x10004, NULL, NULL},
58 {WC_COMBOBOXW, 0x10005, NULL, NULL},
59 {L"#32770", 0x10006, NULL, NULL}, /* dialog */
60 {L"#32771", 0x10007, NULL, NULL}, /* winswitcher */
61 {L"MDIClient", 0x10008, NULL, NULL},
62 {L"#32769", 0x10009, NULL, NULL}, /* desktop */
63 {WC_SCROLLBARW, 0x1000a, NULL, NULL},
64 {STATUSCLASSNAMEW, 0x1000b, NULL, NULL},
65 {TOOLBARCLASSNAMEW, 0x1000c, NULL, NULL},
66 {PROGRESS_CLASSW, 0x1000d, NULL, NULL},
67 {ANIMATE_CLASSW, 0x1000e, NULL, NULL},
68 {WC_TABCONTROLW, 0x1000f, NULL, NULL},
69 {HOTKEY_CLASSW, 0x10010, NULL, NULL},
70 {WC_HEADERW, 0x10011, NULL, NULL},
71 {TRACKBAR_CLASSW, 0x10012, NULL, NULL},
72 {WC_LISTVIEWW, 0x10013, NULL, NULL},
73 {UPDOWN_CLASSW, 0x10016, NULL, NULL},
74 {TOOLTIPS_CLASSW, 0x10018, NULL, NULL},
75 {WC_TREEVIEWW, 0x10019, NULL, NULL},
76 {MONTHCAL_CLASSW, 0, NULL, NULL},
77 {DATETIMEPICK_CLASSW, 0, NULL, NULL},
78 {WC_IPADDRESSW, 0, NULL, NULL},
79 {L"RICHEDIT", 0x1001c, NULL, NULL},
80 {L"RichEdit20A", 0, NULL, NULL},
81 {L"RichEdit20W", 0, NULL, NULL},
84 static HINSTANCE oleacc_handle = 0;
86 int convert_child_id(VARIANT *v)
88 switch(V_VT(v)) {
89 case VT_I4:
90 return V_I4(v);
91 default:
92 FIXME("unhandled child ID variant type: %d\n", V_VT(v));
93 return -1;
97 static accessible_create get_builtin_accessible_obj(HWND hwnd, LONG objid)
99 WCHAR class_name[64];
100 int i, idx;
102 if(!RealGetWindowClassW(hwnd, class_name, ARRAY_SIZE(class_name)))
103 return NULL;
104 TRACE("got window class: %s\n", debugstr_w(class_name));
106 for(i=0; i<ARRAY_SIZE(builtin_classes); i++) {
107 if(!wcsicmp(class_name, builtin_classes[i].name)) {
108 accessible_create ret;
110 ret = (objid==OBJID_CLIENT ?
111 builtin_classes[i].create_client :
112 builtin_classes[i].create_window);
113 if(!ret)
114 FIXME("unhandled window class: %s\n", debugstr_w(class_name));
115 return ret;
119 idx = SendMessageW(hwnd, WM_GETOBJECT, 0, OBJID_QUERYCLASSNAMEIDX);
120 if(idx) {
121 for(i=0; i<ARRAY_SIZE(builtin_classes); i++) {
122 if(idx == builtin_classes[i].idx) {
123 accessible_create ret;
125 ret = (objid==OBJID_CLIENT ?
126 builtin_classes[i].create_client :
127 builtin_classes[i].create_window);
128 if(!ret)
129 FIXME("unhandled class name idx: %x\n", idx);
130 return ret;
134 WARN("unhandled class name idx: %x\n", idx);
137 return NULL;
140 HRESULT WINAPI CreateStdAccessibleObject( HWND hwnd, LONG idObject,
141 REFIID riidInterface, void** ppvObject )
143 accessible_create create;
145 TRACE("%p %d %s %p\n", hwnd, idObject,
146 debugstr_guid( riidInterface ), ppvObject );
148 switch(idObject) {
149 case OBJID_CLIENT:
150 create = get_builtin_accessible_obj(hwnd, idObject);
151 if(create) return create(hwnd, riidInterface, ppvObject);
152 return create_client_object(hwnd, riidInterface, ppvObject);
153 case OBJID_WINDOW:
154 create = get_builtin_accessible_obj(hwnd, idObject);
155 if(create) return create(hwnd, riidInterface, ppvObject);
156 return create_window_object(hwnd, riidInterface, ppvObject);
157 default:
158 FIXME("unhandled object id: %d\n", idObject);
159 return E_NOTIMPL;
163 HRESULT WINAPI ObjectFromLresult( LRESULT result, REFIID riid, WPARAM wParam, void **ppObject )
165 WCHAR atom_str[ARRAY_SIZE(lresult_atom_prefix)+3*8+3];
166 HANDLE server_proc, server_mapping, mapping;
167 DWORD proc_id, size;
168 IStream *stream;
169 HGLOBAL data;
170 void *view;
171 HRESULT hr;
172 WCHAR *p;
174 TRACE("%ld %s %ld %p\n", result, debugstr_guid(riid), wParam, ppObject );
176 if(wParam)
177 FIXME("unsupported wParam = %lx\n", wParam);
179 if(!ppObject)
180 return E_INVALIDARG;
181 *ppObject = NULL;
183 if(result != (ATOM)result)
184 return E_FAIL;
186 if(!GlobalGetAtomNameW(result, atom_str, ARRAY_SIZE(atom_str)))
187 return E_FAIL;
188 if(memcmp(atom_str, lresult_atom_prefix, sizeof(lresult_atom_prefix)))
189 return E_FAIL;
190 p = atom_str + ARRAY_SIZE(lresult_atom_prefix);
191 proc_id = wcstoul(p, &p, 16);
192 if(*p != ':')
193 return E_FAIL;
194 server_mapping = ULongToHandle( wcstoul(p+1, &p, 16) );
195 if(*p != ':')
196 return E_FAIL;
197 size = wcstoul(p+1, &p, 16);
198 if(*p != 0)
199 return E_FAIL;
201 server_proc = OpenProcess(PROCESS_DUP_HANDLE, FALSE, proc_id);
202 if(!server_proc)
203 return E_FAIL;
205 if(!DuplicateHandle(server_proc, server_mapping, GetCurrentProcess(), &mapping,
206 0, FALSE, DUPLICATE_CLOSE_SOURCE|DUPLICATE_SAME_ACCESS))
207 return E_FAIL;
208 CloseHandle(server_proc);
209 GlobalDeleteAtom(result);
211 view = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
212 CloseHandle(mapping);
213 if(!view)
214 return E_FAIL;
216 data = GlobalAlloc(GMEM_FIXED, size);
217 if(!data) {
218 UnmapViewOfFile(view);
219 return E_OUTOFMEMORY;
221 memcpy(data, view, size);
222 UnmapViewOfFile(view);
224 hr = CreateStreamOnHGlobal(data, TRUE, &stream);
225 if(FAILED(hr)) {
226 GlobalFree(data);
227 return hr;
230 hr = CoUnmarshalInterface(stream, riid, ppObject);
231 IStream_Release(stream);
232 return hr;
235 LRESULT WINAPI LresultFromObject( REFIID riid, WPARAM wParam, LPUNKNOWN pAcc )
237 static const LARGE_INTEGER seek_zero = {{0}};
239 WCHAR atom_str[ARRAY_SIZE(lresult_atom_prefix)+3*8+3];
240 IStream *stream;
241 HANDLE mapping;
242 STATSTG stat;
243 HRESULT hr;
244 ATOM atom;
245 void *view;
247 TRACE("%s %ld %p\n", debugstr_guid(riid), wParam, pAcc);
249 if(wParam)
250 FIXME("unsupported wParam = %lx\n", wParam);
252 if(!pAcc)
253 return E_INVALIDARG;
255 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
256 if(FAILED(hr))
257 return hr;
259 hr = CoMarshalInterface(stream, riid, pAcc, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL);
260 if(FAILED(hr)) {
261 IStream_Release(stream);
262 return hr;
265 hr = IStream_Seek(stream, seek_zero, STREAM_SEEK_SET, NULL);
266 if(FAILED(hr)) {
267 IStream_Release(stream);
268 return hr;
271 hr = IStream_Stat(stream, &stat, STATFLAG_NONAME);
272 if(FAILED(hr)) {
273 CoReleaseMarshalData(stream);
274 IStream_Release(stream);
275 return hr;
276 }else if(stat.cbSize.u.HighPart) {
277 FIXME("stream size to big\n");
278 CoReleaseMarshalData(stream);
279 IStream_Release(stream);
280 return E_NOTIMPL;
283 mapping = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
284 stat.cbSize.u.HighPart, stat.cbSize.u.LowPart, NULL);
285 if(!mapping) {
286 CoReleaseMarshalData(stream);
287 IStream_Release(stream);
288 return hr;
291 view = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0);
292 if(!view) {
293 CloseHandle(mapping);
294 CoReleaseMarshalData(stream);
295 IStream_Release(stream);
296 return E_FAIL;
299 hr = IStream_Read(stream, view, stat.cbSize.u.LowPart, NULL);
300 UnmapViewOfFile(view);
301 if(FAILED(hr)) {
302 CloseHandle(mapping);
303 hr = IStream_Seek(stream, seek_zero, STREAM_SEEK_SET, NULL);
304 if(SUCCEEDED(hr))
305 CoReleaseMarshalData(stream);
306 IStream_Release(stream);
307 return hr;
311 memcpy(atom_str, lresult_atom_prefix, sizeof(lresult_atom_prefix));
312 swprintf(atom_str+ARRAY_SIZE(lresult_atom_prefix), 3*8 + 3, L"%08x:%08x:%08x", GetCurrentProcessId(),
313 HandleToUlong(mapping), stat.cbSize.u.LowPart);
314 atom = GlobalAddAtomW(atom_str);
315 if(!atom) {
316 CloseHandle(mapping);
317 hr = IStream_Seek(stream, seek_zero, STREAM_SEEK_SET, NULL);
318 if(SUCCEEDED(hr))
319 CoReleaseMarshalData(stream);
320 IStream_Release(stream);
321 return E_FAIL;
324 IStream_Release(stream);
325 return atom;
328 HRESULT WINAPI AccessibleObjectFromPoint( POINT ptScreen, IAccessible** ppacc, VARIANT* pvarChild )
330 FIXME("{%d,%d} %p %p: stub\n", ptScreen.x, ptScreen.y, ppacc, pvarChild );
331 return E_NOTIMPL;
334 HRESULT WINAPI AccessibleObjectFromWindow( HWND hwnd, DWORD dwObjectID,
335 REFIID riid, void** ppvObject )
337 TRACE("%p %d %s %p\n", hwnd, dwObjectID,
338 debugstr_guid( riid ), ppvObject );
340 if(!ppvObject)
341 return E_INVALIDARG;
342 *ppvObject = NULL;
344 if(IsWindow(hwnd)) {
345 LRESULT lres;
347 lres = SendMessageW(hwnd, WM_GETOBJECT, 0xffffffff, dwObjectID);
348 if(FAILED(lres))
349 return lres;
350 else if(lres)
351 return ObjectFromLresult(lres, riid, 0, ppvObject);
354 return CreateStdAccessibleObject(hwnd, dwObjectID, riid, ppvObject);
357 HRESULT WINAPI WindowFromAccessibleObject(IAccessible *acc, HWND *phwnd)
359 IDispatch *parent;
360 IOleWindow *ow;
361 HRESULT hres;
363 TRACE("%p %p\n", acc, phwnd);
365 IAccessible_AddRef(acc);
366 while(1) {
367 hres = IAccessible_QueryInterface(acc, &IID_IOleWindow, (void**)&ow);
368 if(SUCCEEDED(hres)) {
369 hres = IOleWindow_GetWindow(ow, phwnd);
370 IOleWindow_Release(ow);
371 IAccessible_Release(acc);
372 return hres;
375 hres = IAccessible_get_accParent(acc, &parent);
376 IAccessible_Release(acc);
377 if(FAILED(hres))
378 return hres;
379 if(hres!=S_OK || !parent) {
380 *phwnd = NULL;
381 return hres;
384 hres = IDispatch_QueryInterface(parent, &IID_IAccessible, (void**)&acc);
385 IDispatch_Release(parent);
386 if(FAILED(hres))
387 return hres;
391 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
392 LPVOID lpvReserved)
394 TRACE("%p, %d, %p\n", hinstDLL, fdwReason, lpvReserved);
396 switch (fdwReason)
398 case DLL_PROCESS_ATTACH:
399 oleacc_handle = hinstDLL;
400 DisableThreadLibraryCalls(hinstDLL);
401 break;
404 return OLEACC_DllMain(hinstDLL, fdwReason, lpvReserved);
407 HRESULT WINAPI DllRegisterServer(void)
409 return OLEACC_DllRegisterServer();
412 HRESULT WINAPI DllUnregisterServer(void)
414 return OLEACC_DllUnregisterServer();
417 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, void **ppv)
419 if(IsEqualGUID(&CLSID_CAccPropServices, rclsid)) {
420 TRACE("(CLSID_CAccPropServices %s %p)\n", debugstr_guid(iid), ppv);
421 return get_accpropservices_factory(iid, ppv);
424 if(IsEqualGUID(&CLSID_PSFactoryBuffer, rclsid)) {
425 TRACE("(CLSID_PSFactoryBuffer %s %p)\n", debugstr_guid(iid), ppv);
426 return OLEACC_DllGetClassObject(rclsid, iid, ppv);
429 FIXME("%s %s %p: stub\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv);
430 return E_NOTIMPL;
433 void WINAPI GetOleaccVersionInfo(DWORD* pVersion, DWORD* pBuild)
435 *pVersion = MAKELONG(0,7); /* Windows 7 version of oleacc: 7.0.0.0 */
436 *pBuild = MAKELONG(0,0);
439 HANDLE WINAPI GetProcessHandleFromHwnd(HWND hwnd)
441 DWORD proc_id;
443 TRACE("%p\n", hwnd);
445 if(!GetWindowThreadProcessId(hwnd, &proc_id))
446 return NULL;
447 return OpenProcess(PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION |
448 PROCESS_VM_READ | PROCESS_VM_WRITE | SYNCHRONIZE, TRUE, proc_id);
451 UINT WINAPI GetRoleTextW(DWORD role, LPWSTR lpRole, UINT rolemax)
453 INT ret;
454 WCHAR *resptr;
456 TRACE("%u %p %u\n", role, lpRole, rolemax);
458 /* return role text length */
459 if(!lpRole)
460 return LoadStringW(oleacc_handle, role, (LPWSTR)&resptr, 0);
462 ret = LoadStringW(oleacc_handle, role, lpRole, rolemax);
463 if(!(ret > 0)){
464 if(rolemax > 0) lpRole[0] = '\0';
465 return 0;
468 return ret;
471 UINT WINAPI GetRoleTextA(DWORD role, LPSTR lpRole, UINT rolemax)
473 UINT length;
474 WCHAR *roletextW;
476 TRACE("%u %p %u\n", role, lpRole, rolemax);
478 if(lpRole && !rolemax)
479 return 0;
481 length = GetRoleTextW(role, NULL, 0);
482 if(!length) {
483 if(lpRole && rolemax)
484 lpRole[0] = 0;
485 return 0;
488 roletextW = HeapAlloc(GetProcessHeap(), 0, (length + 1)*sizeof(WCHAR));
489 if(!roletextW)
490 return 0;
492 GetRoleTextW(role, roletextW, length + 1);
494 length = WideCharToMultiByte( CP_ACP, 0, roletextW, -1, NULL, 0, NULL, NULL );
496 if(!lpRole){
497 HeapFree(GetProcessHeap(), 0, roletextW);
498 return length - 1;
501 if(rolemax < length) {
502 HeapFree(GetProcessHeap(), 0, roletextW);
503 lpRole[0] = 0;
504 return 0;
507 WideCharToMultiByte( CP_ACP, 0, roletextW, -1, lpRole, rolemax, NULL, NULL );
509 if(rolemax < length){
510 lpRole[rolemax-1] = '\0';
511 length = rolemax;
514 HeapFree(GetProcessHeap(), 0, roletextW);
516 return length - 1;
519 UINT WINAPI GetStateTextW(DWORD state_bit, WCHAR *state_str, UINT state_str_len)
521 DWORD state_id;
523 TRACE("%x %p %u\n", state_bit, state_str, state_str_len);
525 if(state_bit & ~(STATE_SYSTEM_VALID | STATE_SYSTEM_HASPOPUP)) {
526 if(state_str && state_str_len)
527 state_str[0] = 0;
528 return 0;
531 state_id = IDS_STATE_NORMAL;
532 while(state_bit) {
533 state_id++;
534 state_bit /= 2;
537 if(state_str) {
538 UINT ret = LoadStringW(oleacc_handle, state_id, state_str, state_str_len);
539 if(!ret && state_str_len)
540 state_str[0] = 0;
541 return ret;
542 }else {
543 WCHAR *tmp;
544 return LoadStringW(oleacc_handle, state_id, (WCHAR*)&tmp, 0);
549 UINT WINAPI GetStateTextA(DWORD state_bit, CHAR *state_str, UINT state_str_len)
551 DWORD state_id;
553 TRACE("%x %p %u\n", state_bit, state_str, state_str_len);
555 if(state_str && !state_str_len)
556 return 0;
558 if(state_bit & ~(STATE_SYSTEM_VALID | STATE_SYSTEM_HASPOPUP)) {
559 if(state_str && state_str_len)
560 state_str[0] = 0;
561 return 0;
564 state_id = IDS_STATE_NORMAL;
565 while(state_bit) {
566 state_id++;
567 state_bit /= 2;
570 if(state_str) {
571 UINT ret = LoadStringA(oleacc_handle, state_id, state_str, state_str_len);
572 if(!ret && state_str_len)
573 state_str[0] = 0;
574 return ret;
575 }else {
576 CHAR tmp[256];
577 return LoadStringA(oleacc_handle, state_id, tmp, sizeof(tmp));
581 HRESULT WINAPI AccessibleChildren(IAccessible *container,
582 LONG start, LONG count, VARIANT *children, LONG *children_cnt)
584 IEnumVARIANT *ev;
585 LONG i, child_no;
586 HRESULT hr;
588 TRACE("%p %d %d %p %p\n", container, start, count, children, children_cnt);
590 if(!container || !children || !children_cnt)
591 return E_INVALIDARG;
593 for(i=0; i<count; i++)
594 VariantInit(children+i);
596 hr = IAccessible_QueryInterface(container, &IID_IEnumVARIANT, (void**)&ev);
597 if(SUCCEEDED(hr)) {
598 hr = IEnumVARIANT_Reset(ev);
599 if(SUCCEEDED(hr))
600 hr = IEnumVARIANT_Skip(ev, start);
601 if(SUCCEEDED(hr))
602 hr = IEnumVARIANT_Next(ev, count, children, (ULONG*)children_cnt);
603 IEnumVARIANT_Release(ev);
604 return hr;
607 hr = IAccessible_get_accChildCount(container, &child_no);
608 if(FAILED(hr))
609 return hr;
611 for(i=0; i<count && start+i+1<=child_no; i++) {
612 IDispatch *disp;
614 V_VT(children+i) = VT_I4;
615 V_I4(children+i) = start+i+1;
617 hr = IAccessible_get_accChild(container, children[i], &disp);
618 if(SUCCEEDED(hr) && disp) {
619 V_VT(children+i) = VT_DISPATCH;
620 V_DISPATCH(children+i) = disp;
624 *children_cnt = i;
625 return i==count ? S_OK : S_FALSE;