comctl32/tests: Use CRT allocation functions.
[wine.git] / dlls / oleacc / main.c
blobb2096d5d557b7cb59a5a390e95008f0d71d963e3
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 "initguid.h"
24 #include "oleacc_private.h"
25 #include "resource.h"
27 #include "wine/debug.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(oleacc);
31 static const WCHAR lresult_atom_prefix[] = {'w','i','n','e','_','o','l','e','a','c','c',':'};
33 #define NAVDIR_INTERNAL_HWND 10
34 DEFINE_GUID(SID_AccFromDAWrapper, 0x33f139ee, 0xe509, 0x47f7, 0xbf,0x39, 0x83,0x76,0x44,0xf7,0x45,0x76);
36 extern HRESULT WINAPI OLEACC_DllGetClassObject(REFCLSID, REFIID, void**);
37 extern BOOL WINAPI OLEACC_DllMain(HINSTANCE, DWORD, void*);
38 extern HRESULT WINAPI OLEACC_DllRegisterServer(void);
39 extern HRESULT WINAPI OLEACC_DllUnregisterServer(void);
41 static HINSTANCE oleacc_handle = 0;
43 int convert_child_id(VARIANT *v)
45 switch(V_VT(v)) {
46 case VT_I4:
47 return V_I4(v);
48 default:
49 FIXME("unhandled child ID variant type: %d\n", V_VT(v));
50 return -1;
54 const struct win_class_data* find_class_data(HWND hwnd, const struct win_class_data *classes)
56 WCHAR class_name[64];
57 int i, idx;
59 if(!RealGetWindowClassW(hwnd, class_name, ARRAY_SIZE(class_name)))
60 return NULL;
61 TRACE("got window class: %s\n", debugstr_w(class_name));
63 for(i=0; classes[i].name; i++) {
64 if(!wcsicmp(class_name, classes[i].name)) {
65 if(classes[i].stub)
66 FIXME("unhandled window class: %s\n", debugstr_w(class_name));
67 return &classes[i];
71 idx = SendMessageW(hwnd, WM_GETOBJECT, 0, OBJID_QUERYCLASSNAMEIDX);
72 if(idx) {
73 for(i=0; classes[i].name; i++) {
74 if(idx == classes[i].idx) {
75 if(classes[i].stub)
76 FIXME("unhandled window class: %s\n", debugstr_w(class_name));
77 return &classes[i];
81 WARN("unhandled class name idx: %x\n", idx);
84 return NULL;
87 HRESULT WINAPI CreateStdAccessibleObject( HWND hwnd, LONG idObject,
88 REFIID riidInterface, void** ppvObject )
90 TRACE("%p %ld %s %p\n", hwnd, idObject,
91 debugstr_guid( riidInterface ), ppvObject );
93 switch(idObject) {
94 case OBJID_CLIENT:
95 return create_client_object(hwnd, riidInterface, ppvObject);
96 case OBJID_WINDOW:
97 return create_window_object(hwnd, riidInterface, ppvObject);
98 default:
99 FIXME("unhandled object id: %ld\n", idObject);
100 return E_NOTIMPL;
104 HRESULT WINAPI ObjectFromLresult( LRESULT result, REFIID riid, WPARAM wParam, void **ppObject )
106 WCHAR atom_str[ARRAY_SIZE(lresult_atom_prefix)+3*8+3];
107 HANDLE server_proc, server_mapping, mapping;
108 DWORD proc_id, size;
109 IStream *stream;
110 HGLOBAL data;
111 void *view;
112 HRESULT hr;
113 WCHAR *p;
115 TRACE("%Id %s %Id %p\n", result, debugstr_guid(riid), wParam, ppObject );
117 if(wParam)
118 FIXME("unsupported wParam = %Ix\n", wParam);
120 if(!ppObject)
121 return E_INVALIDARG;
122 *ppObject = NULL;
124 if(result != (ATOM)result)
125 return E_FAIL;
127 if(!GlobalGetAtomNameW(result, atom_str, ARRAY_SIZE(atom_str)))
128 return E_FAIL;
129 if(memcmp(atom_str, lresult_atom_prefix, sizeof(lresult_atom_prefix)))
130 return E_FAIL;
131 p = atom_str + ARRAY_SIZE(lresult_atom_prefix);
132 proc_id = wcstoul(p, &p, 16);
133 if(*p != ':')
134 return E_FAIL;
135 server_mapping = ULongToHandle( wcstoul(p+1, &p, 16) );
136 if(*p != ':')
137 return E_FAIL;
138 size = wcstoul(p+1, &p, 16);
139 if(*p != 0)
140 return E_FAIL;
142 server_proc = OpenProcess(PROCESS_DUP_HANDLE, FALSE, proc_id);
143 if(!server_proc)
144 return E_FAIL;
146 if(!DuplicateHandle(server_proc, server_mapping, GetCurrentProcess(), &mapping,
147 0, FALSE, DUPLICATE_CLOSE_SOURCE|DUPLICATE_SAME_ACCESS))
148 return E_FAIL;
149 CloseHandle(server_proc);
150 GlobalDeleteAtom(result);
152 view = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
153 CloseHandle(mapping);
154 if(!view)
155 return E_FAIL;
157 data = GlobalAlloc(GMEM_FIXED, size);
158 if(!data) {
159 UnmapViewOfFile(view);
160 return E_OUTOFMEMORY;
162 memcpy(data, view, size);
163 UnmapViewOfFile(view);
165 hr = CreateStreamOnHGlobal(data, TRUE, &stream);
166 if(FAILED(hr)) {
167 GlobalFree(data);
168 return hr;
171 hr = CoUnmarshalInterface(stream, riid, ppObject);
172 IStream_Release(stream);
173 return hr;
176 LRESULT WINAPI LresultFromObject( REFIID riid, WPARAM wParam, LPUNKNOWN pAcc )
178 static const LARGE_INTEGER seek_zero = {{0}};
180 WCHAR atom_str[ARRAY_SIZE(lresult_atom_prefix)+3*8+3];
181 IStream *stream;
182 HANDLE mapping;
183 STATSTG stat;
184 HRESULT hr;
185 ATOM atom;
186 void *view;
188 TRACE("%s %Id %p\n", debugstr_guid(riid), wParam, pAcc);
190 if(wParam)
191 FIXME("unsupported wParam = %Ix\n", wParam);
193 if(!pAcc)
194 return E_INVALIDARG;
196 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
197 if(FAILED(hr))
198 return hr;
200 hr = CoMarshalInterface(stream, riid, pAcc, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL);
201 if(FAILED(hr)) {
202 IStream_Release(stream);
203 return hr;
206 hr = IStream_Seek(stream, seek_zero, STREAM_SEEK_SET, NULL);
207 if(FAILED(hr)) {
208 IStream_Release(stream);
209 return hr;
212 hr = IStream_Stat(stream, &stat, STATFLAG_NONAME);
213 if(FAILED(hr)) {
214 CoReleaseMarshalData(stream);
215 IStream_Release(stream);
216 return hr;
217 }else if(stat.cbSize.u.HighPart) {
218 FIXME("stream size to big\n");
219 CoReleaseMarshalData(stream);
220 IStream_Release(stream);
221 return E_NOTIMPL;
224 mapping = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
225 stat.cbSize.u.HighPart, stat.cbSize.u.LowPart, NULL);
226 if(!mapping) {
227 CoReleaseMarshalData(stream);
228 IStream_Release(stream);
229 return hr;
232 view = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0);
233 if(!view) {
234 CloseHandle(mapping);
235 CoReleaseMarshalData(stream);
236 IStream_Release(stream);
237 return E_FAIL;
240 hr = IStream_Read(stream, view, stat.cbSize.u.LowPart, NULL);
241 UnmapViewOfFile(view);
242 if(FAILED(hr)) {
243 CloseHandle(mapping);
244 hr = IStream_Seek(stream, seek_zero, STREAM_SEEK_SET, NULL);
245 if(SUCCEEDED(hr))
246 CoReleaseMarshalData(stream);
247 IStream_Release(stream);
248 return hr;
252 memcpy(atom_str, lresult_atom_prefix, sizeof(lresult_atom_prefix));
253 swprintf(atom_str+ARRAY_SIZE(lresult_atom_prefix), 3*8 + 3, L"%08x:%08x:%08x", GetCurrentProcessId(),
254 HandleToUlong(mapping), stat.cbSize.u.LowPart);
255 atom = GlobalAddAtomW(atom_str);
256 if(!atom) {
257 CloseHandle(mapping);
258 hr = IStream_Seek(stream, seek_zero, STREAM_SEEK_SET, NULL);
259 if(SUCCEEDED(hr))
260 CoReleaseMarshalData(stream);
261 IStream_Release(stream);
262 return E_FAIL;
265 IStream_Release(stream);
266 return atom;
269 static void variant_init_i4( VARIANT *v, int val )
271 V_VT(v) = VT_I4;
272 V_I4(v) = val;
275 HRESULT WINAPI AccessibleObjectFromPoint( POINT point, IAccessible** acc, VARIANT* child_id )
277 IAccessible *cur;
278 HRESULT hr;
279 VARIANT v;
280 HWND hwnd;
282 TRACE("{%ld,%ld} %p %p\n", point.x, point.y, acc, child_id);
284 if (!acc || !child_id)
285 return E_INVALIDARG;
287 *acc = NULL;
288 V_VT(child_id) = VT_EMPTY;
290 hwnd = WindowFromPoint(point);
291 if (!hwnd)
292 return E_FAIL;
293 hwnd = GetAncestor(hwnd, GA_ROOT);
295 hr = AccessibleObjectFromWindow(hwnd, OBJID_WINDOW, &IID_IAccessible, (void **)&cur);
296 if (FAILED(hr))
297 return hr;
298 if (!cur)
299 return E_FAIL;
301 V_VT(&v) = VT_EMPTY;
302 while (1)
304 hr = IAccessible_accHitTest(cur, point.x, point.y, &v);
305 if (FAILED(hr))
307 IAccessible_Release(cur);
308 return hr;
311 if (V_VT(&v) == VT_I4)
313 *acc = cur;
314 variant_init_i4(child_id, V_I4(&v));
315 return S_OK;
317 else if (V_VT(&v) == VT_DISPATCH)
319 IAccessible_Release(cur);
321 hr = IDispatch_QueryInterface(V_DISPATCH(&v), &IID_IAccessible, (void**)&cur);
322 VariantClear(&v);
323 if (FAILED(hr))
324 return hr;
325 if (!cur)
326 return E_FAIL;
328 else
330 VariantClear(&v);
331 IAccessible_Release(cur);
332 FIXME("unhandled variant type: %d\n", V_VT(&v));
333 return E_NOTIMPL;
337 return S_OK;
340 HRESULT WINAPI AccessibleObjectFromEvent( HWND hwnd, DWORD object_id, DWORD child_id,
341 IAccessible **acc_out, VARIANT *child_id_out )
343 VARIANT child_id_variant;
344 IAccessible *acc = NULL;
345 IDispatch *child = NULL;
346 HRESULT hr;
348 TRACE("%p %ld %ld %p %p\n", hwnd, object_id, child_id, acc_out, child_id_out);
350 if (!acc_out)
351 return E_INVALIDARG;
352 *acc_out = NULL;
353 VariantInit(child_id_out);
355 hr = AccessibleObjectFromWindow(hwnd, object_id, &IID_IAccessible, (void **)&acc);
356 if (FAILED(hr))
357 return hr;
359 variant_init_i4(&child_id_variant, child_id);
360 hr = IAccessible_get_accChild(acc, child_id_variant, &child);
361 if (FAILED(hr))
362 TRACE("get_accChild failed with %#lx!\n", hr);
364 if (SUCCEEDED(hr) && child)
366 IAccessible_Release(acc);
367 hr = IDispatch_QueryInterface(child, &IID_IAccessible, (void **)&acc);
368 IDispatch_Release(child);
369 if (FAILED(hr))
370 return hr;
372 variant_init_i4(&child_id_variant, CHILDID_SELF);
375 *acc_out = acc;
376 *child_id_out = child_id_variant;
378 return S_OK;
381 HRESULT WINAPI AccessibleObjectFromWindow( HWND hwnd, DWORD dwObjectID,
382 REFIID riid, void** ppvObject )
384 TRACE("%p %ld %s %p\n", hwnd, dwObjectID,
385 debugstr_guid( riid ), ppvObject );
387 if(!ppvObject)
388 return E_INVALIDARG;
389 *ppvObject = NULL;
391 if(IsWindow(hwnd)) {
392 LRESULT lres;
394 lres = SendMessageW(hwnd, WM_GETOBJECT, 0xffffffff, dwObjectID);
395 if(FAILED(lres))
396 return lres;
397 else if(lres)
398 return ObjectFromLresult(lres, riid, 0, ppvObject);
401 return CreateStdAccessibleObject(hwnd, dwObjectID, riid, ppvObject);
404 HRESULT WINAPI WindowFromAccessibleObject(IAccessible *acc, HWND *phwnd)
406 IServiceProvider *sp;
407 IAccessible *acc2;
408 IDispatch *parent;
409 IOleWindow *ow;
410 VARIANT v, cid;
411 HRESULT hres;
413 TRACE("%p %p\n", acc, phwnd);
415 hres = IAccessible_QueryInterface(acc, &IID_IOleWindow, (void**)&ow);
416 if(SUCCEEDED(hres)) {
417 hres = IOleWindow_GetWindow(ow, phwnd);
418 IOleWindow_Release(ow);
419 if(SUCCEEDED(hres) && *phwnd)
420 return S_OK;
423 VariantInit(&v);
424 variant_init_i4(&cid, CHILDID_SELF);
425 hres = IAccessible_accNavigate(acc, NAVDIR_INTERNAL_HWND, cid, &v);
426 if(SUCCEEDED(hres)) {
427 if(hres == S_OK && V_VT(&v) == VT_I4 && V_I4(&v)) {
428 *phwnd = LongToHandle(V_I4(&v));
429 return S_OK;
431 /* native leaks v here */
432 VariantClear(&v);
435 hres = IAccessible_QueryInterface(acc, &IID_IServiceProvider, (void**)&sp);
436 if(SUCCEEDED(hres)) {
437 hres = IServiceProvider_QueryService(sp, &SID_AccFromDAWrapper,
438 &IID_IAccessible, (void**)&acc2);
439 IServiceProvider_Release(sp);
441 if(FAILED(hres)) {
442 acc2 = acc;
443 IAccessible_AddRef(acc2);
446 while(1) {
447 hres = IAccessible_QueryInterface(acc2, &IID_IOleWindow, (void**)&ow);
448 if(SUCCEEDED(hres)) {
449 hres = IOleWindow_GetWindow(ow, phwnd);
450 IOleWindow_Release(ow);
451 if(SUCCEEDED(hres)) {
452 IAccessible_Release(acc2);
453 return hres;
457 hres = IAccessible_get_accParent(acc, &parent);
458 IAccessible_Release(acc2);
459 if(FAILED(hres))
460 return hres;
461 if(!parent) {
462 *phwnd = NULL;
463 return hres;
466 hres = IDispatch_QueryInterface(parent, &IID_IAccessible, (void**)&acc2);
467 IDispatch_Release(parent);
468 if(FAILED(hres))
469 return hres;
470 acc = acc2;
474 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
475 LPVOID lpvReserved)
477 TRACE("%p, %ld, %p\n", hinstDLL, fdwReason, lpvReserved);
479 switch (fdwReason)
481 case DLL_PROCESS_ATTACH:
482 oleacc_handle = hinstDLL;
483 DisableThreadLibraryCalls(hinstDLL);
484 break;
487 return OLEACC_DllMain(hinstDLL, fdwReason, lpvReserved);
490 HRESULT WINAPI DllRegisterServer(void)
492 return OLEACC_DllRegisterServer();
495 HRESULT WINAPI DllUnregisterServer(void)
497 return OLEACC_DllUnregisterServer();
500 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, void **ppv)
502 if(IsEqualGUID(&CLSID_CAccPropServices, rclsid)) {
503 TRACE("(CLSID_CAccPropServices %s %p)\n", debugstr_guid(iid), ppv);
504 return get_accpropservices_factory(iid, ppv);
507 if(IsEqualGUID(&CLSID_PSFactoryBuffer, rclsid)) {
508 TRACE("(CLSID_PSFactoryBuffer %s %p)\n", debugstr_guid(iid), ppv);
509 return OLEACC_DllGetClassObject(rclsid, iid, ppv);
512 FIXME("%s %s %p: stub\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv);
513 return E_NOTIMPL;
516 void WINAPI GetOleaccVersionInfo(DWORD* pVersion, DWORD* pBuild)
518 *pVersion = MAKELONG(0,7); /* Windows 7 version of oleacc: 7.0.0.0 */
519 *pBuild = MAKELONG(0,0);
522 HANDLE WINAPI GetProcessHandleFromHwnd(HWND hwnd)
524 DWORD proc_id;
526 TRACE("%p\n", hwnd);
528 if(!GetWindowThreadProcessId(hwnd, &proc_id))
529 return NULL;
530 return OpenProcess(PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION |
531 PROCESS_VM_READ | PROCESS_VM_WRITE | SYNCHRONIZE, TRUE, proc_id);
534 UINT WINAPI GetRoleTextW(DWORD role, LPWSTR lpRole, UINT rolemax)
536 INT ret;
537 WCHAR *resptr;
539 TRACE("%lu %p %u\n", role, lpRole, rolemax);
541 /* return role text length */
542 if(!lpRole)
543 return LoadStringW(oleacc_handle, role, (LPWSTR)&resptr, 0);
545 ret = LoadStringW(oleacc_handle, role, lpRole, rolemax);
546 if(!(ret > 0)){
547 if(rolemax > 0) lpRole[0] = '\0';
548 return 0;
551 return ret;
554 UINT WINAPI GetRoleTextA(DWORD role, LPSTR lpRole, UINT rolemax)
556 UINT length;
557 WCHAR *roletextW;
559 TRACE("%lu %p %u\n", role, lpRole, rolemax);
561 if(lpRole && !rolemax)
562 return 0;
564 length = GetRoleTextW(role, NULL, 0);
565 if(!length) {
566 if(lpRole && rolemax)
567 lpRole[0] = 0;
568 return 0;
571 roletextW = HeapAlloc(GetProcessHeap(), 0, (length + 1)*sizeof(WCHAR));
572 if(!roletextW)
573 return 0;
575 GetRoleTextW(role, roletextW, length + 1);
577 length = WideCharToMultiByte( CP_ACP, 0, roletextW, -1, NULL, 0, NULL, NULL );
579 if(!lpRole){
580 HeapFree(GetProcessHeap(), 0, roletextW);
581 return length - 1;
584 if(rolemax < length) {
585 HeapFree(GetProcessHeap(), 0, roletextW);
586 lpRole[0] = 0;
587 return 0;
590 WideCharToMultiByte( CP_ACP, 0, roletextW, -1, lpRole, rolemax, NULL, NULL );
592 if(rolemax < length){
593 lpRole[rolemax-1] = '\0';
594 length = rolemax;
597 HeapFree(GetProcessHeap(), 0, roletextW);
599 return length - 1;
602 UINT WINAPI GetStateTextW(DWORD state_bit, WCHAR *state_str, UINT state_str_len)
604 DWORD state_id;
606 TRACE("%lx %p %u\n", state_bit, state_str, state_str_len);
608 if(state_bit & ~(STATE_SYSTEM_VALID | STATE_SYSTEM_HASPOPUP)) {
609 if(state_str && state_str_len)
610 state_str[0] = 0;
611 return 0;
614 state_id = IDS_STATE_NORMAL;
615 while(state_bit) {
616 state_id++;
617 state_bit /= 2;
620 if(state_str) {
621 UINT ret = LoadStringW(oleacc_handle, state_id, state_str, state_str_len);
622 if(!ret && state_str_len)
623 state_str[0] = 0;
624 return ret;
625 }else {
626 WCHAR *tmp;
627 return LoadStringW(oleacc_handle, state_id, (WCHAR*)&tmp, 0);
632 UINT WINAPI GetStateTextA(DWORD state_bit, CHAR *state_str, UINT state_str_len)
634 DWORD state_id;
636 TRACE("%lx %p %u\n", state_bit, state_str, state_str_len);
638 if(state_str && !state_str_len)
639 return 0;
641 if(state_bit & ~(STATE_SYSTEM_VALID | STATE_SYSTEM_HASPOPUP)) {
642 if(state_str && state_str_len)
643 state_str[0] = 0;
644 return 0;
647 state_id = IDS_STATE_NORMAL;
648 while(state_bit) {
649 state_id++;
650 state_bit /= 2;
653 if(state_str) {
654 UINT ret = LoadStringA(oleacc_handle, state_id, state_str, state_str_len);
655 if(!ret && state_str_len)
656 state_str[0] = 0;
657 return ret;
658 }else {
659 CHAR tmp[256];
660 return LoadStringA(oleacc_handle, state_id, tmp, sizeof(tmp));
664 HRESULT WINAPI AccessibleChildren(IAccessible *container,
665 LONG start, LONG count, VARIANT *children, LONG *children_cnt)
667 IEnumVARIANT *ev;
668 LONG i, child_no;
669 HRESULT hr;
671 TRACE("%p %ld %ld %p %p\n", container, start, count, children, children_cnt);
673 if(!container || !children || !children_cnt)
674 return E_INVALIDARG;
676 for(i=0; i<count; i++)
677 VariantInit(children+i);
679 hr = IAccessible_QueryInterface(container, &IID_IEnumVARIANT, (void**)&ev);
680 if(SUCCEEDED(hr)) {
681 hr = IEnumVARIANT_Reset(ev);
682 if(SUCCEEDED(hr))
683 hr = IEnumVARIANT_Skip(ev, start);
684 if(SUCCEEDED(hr))
685 hr = IEnumVARIANT_Next(ev, count, children, (ULONG*)children_cnt);
686 IEnumVARIANT_Release(ev);
687 return hr;
690 hr = IAccessible_get_accChildCount(container, &child_no);
691 if(FAILED(hr))
692 return hr;
694 for(i=0; i<count && start+i+1<=child_no; i++) {
695 IDispatch *disp;
697 V_VT(children+i) = VT_I4;
698 V_I4(children+i) = start+i+1;
700 hr = IAccessible_get_accChild(container, children[i], &disp);
701 if(SUCCEEDED(hr) && disp) {
702 V_VT(children+i) = VT_DISPATCH;
703 V_DISPATCH(children+i) = disp;
707 *children_cnt = i;
708 return i==count ? S_OK : S_FALSE;