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
24 #include "oleacc_private.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
)
49 FIXME("unhandled child ID variant type: %d\n", V_VT(v
));
54 const struct win_class_data
* find_class_data(HWND hwnd
, const struct win_class_data
*classes
)
59 if(!RealGetWindowClassW(hwnd
, class_name
, ARRAY_SIZE(class_name
)))
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
)) {
66 FIXME("unhandled window class: %s\n", debugstr_w(class_name
));
71 idx
= SendMessageW(hwnd
, WM_GETOBJECT
, 0, OBJID_QUERYCLASSNAMEIDX
);
73 for(i
=0; classes
[i
].name
; i
++) {
74 if(idx
== classes
[i
].idx
) {
76 FIXME("unhandled window class: %s\n", debugstr_w(class_name
));
81 WARN("unhandled class name idx: %x\n", idx
);
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
);
95 return create_client_object(hwnd
, riidInterface
, ppvObject
);
97 return create_window_object(hwnd
, riidInterface
, ppvObject
);
99 FIXME("unhandled object id: %ld\n", idObject
);
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
;
115 TRACE("%Id %s %Id %p\n", result
, debugstr_guid(riid
), wParam
, ppObject
);
118 FIXME("unsupported wParam = %Ix\n", wParam
);
124 if(result
!= (ATOM
)result
)
127 if(!GlobalGetAtomNameW(result
, atom_str
, ARRAY_SIZE(atom_str
)))
129 if(memcmp(atom_str
, lresult_atom_prefix
, sizeof(lresult_atom_prefix
)))
131 p
= atom_str
+ ARRAY_SIZE(lresult_atom_prefix
);
132 proc_id
= wcstoul(p
, &p
, 16);
135 server_mapping
= ULongToHandle( wcstoul(p
+1, &p
, 16) );
138 size
= wcstoul(p
+1, &p
, 16);
142 server_proc
= OpenProcess(PROCESS_DUP_HANDLE
, FALSE
, proc_id
);
146 if(!DuplicateHandle(server_proc
, server_mapping
, GetCurrentProcess(), &mapping
,
147 0, FALSE
, DUPLICATE_CLOSE_SOURCE
|DUPLICATE_SAME_ACCESS
))
149 CloseHandle(server_proc
);
150 GlobalDeleteAtom(result
);
152 view
= MapViewOfFile(mapping
, FILE_MAP_READ
, 0, 0, 0);
153 CloseHandle(mapping
);
157 data
= GlobalAlloc(GMEM_FIXED
, size
);
159 UnmapViewOfFile(view
);
160 return E_OUTOFMEMORY
;
162 memcpy(data
, view
, size
);
163 UnmapViewOfFile(view
);
165 hr
= CreateStreamOnHGlobal(data
, TRUE
, &stream
);
171 hr
= CoUnmarshalInterface(stream
, riid
, ppObject
);
172 IStream_Release(stream
);
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];
188 TRACE("%s %Id %p\n", debugstr_guid(riid
), wParam
, pAcc
);
191 FIXME("unsupported wParam = %Ix\n", wParam
);
196 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stream
);
200 hr
= CoMarshalInterface(stream
, riid
, pAcc
, MSHCTX_LOCAL
, NULL
, MSHLFLAGS_NORMAL
);
202 IStream_Release(stream
);
206 hr
= IStream_Seek(stream
, seek_zero
, STREAM_SEEK_SET
, NULL
);
208 IStream_Release(stream
);
212 hr
= IStream_Stat(stream
, &stat
, STATFLAG_NONAME
);
214 CoReleaseMarshalData(stream
);
215 IStream_Release(stream
);
217 }else if(stat
.cbSize
.u
.HighPart
) {
218 FIXME("stream size to big\n");
219 CoReleaseMarshalData(stream
);
220 IStream_Release(stream
);
224 mapping
= CreateFileMappingW(INVALID_HANDLE_VALUE
, NULL
, PAGE_READWRITE
,
225 stat
.cbSize
.u
.HighPart
, stat
.cbSize
.u
.LowPart
, NULL
);
227 CoReleaseMarshalData(stream
);
228 IStream_Release(stream
);
232 view
= MapViewOfFile(mapping
, FILE_MAP_WRITE
, 0, 0, 0);
234 CloseHandle(mapping
);
235 CoReleaseMarshalData(stream
);
236 IStream_Release(stream
);
240 hr
= IStream_Read(stream
, view
, stat
.cbSize
.u
.LowPart
, NULL
);
241 UnmapViewOfFile(view
);
243 CloseHandle(mapping
);
244 hr
= IStream_Seek(stream
, seek_zero
, STREAM_SEEK_SET
, NULL
);
246 CoReleaseMarshalData(stream
);
247 IStream_Release(stream
);
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
);
257 CloseHandle(mapping
);
258 hr
= IStream_Seek(stream
, seek_zero
, STREAM_SEEK_SET
, NULL
);
260 CoReleaseMarshalData(stream
);
261 IStream_Release(stream
);
265 IStream_Release(stream
);
269 static void variant_init_i4( VARIANT
*v
, int val
)
275 HRESULT WINAPI
AccessibleObjectFromPoint( POINT point
, IAccessible
** acc
, VARIANT
* child_id
)
282 TRACE("{%ld,%ld} %p %p\n", point
.x
, point
.y
, acc
, child_id
);
284 if (!acc
|| !child_id
)
288 V_VT(child_id
) = VT_EMPTY
;
290 hwnd
= WindowFromPoint(point
);
293 hwnd
= GetAncestor(hwnd
, GA_ROOT
);
295 hr
= AccessibleObjectFromWindow(hwnd
, OBJID_WINDOW
, &IID_IAccessible
, (void **)&cur
);
304 hr
= IAccessible_accHitTest(cur
, point
.x
, point
.y
, &v
);
307 IAccessible_Release(cur
);
311 if (V_VT(&v
) == VT_I4
)
314 variant_init_i4(child_id
, V_I4(&v
));
317 else if (V_VT(&v
) == VT_DISPATCH
)
319 IAccessible_Release(cur
);
321 hr
= IDispatch_QueryInterface(V_DISPATCH(&v
), &IID_IAccessible
, (void**)&cur
);
331 IAccessible_Release(cur
);
332 FIXME("unhandled variant type: %d\n", V_VT(&v
));
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
;
348 TRACE("%p %ld %ld %p %p\n", hwnd
, object_id
, child_id
, acc_out
, child_id_out
);
353 VariantInit(child_id_out
);
355 hr
= AccessibleObjectFromWindow(hwnd
, object_id
, &IID_IAccessible
, (void **)&acc
);
359 variant_init_i4(&child_id_variant
, child_id
);
360 hr
= IAccessible_get_accChild(acc
, child_id_variant
, &child
);
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
);
372 variant_init_i4(&child_id_variant
, CHILDID_SELF
);
376 *child_id_out
= child_id_variant
;
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
);
394 lres
= SendMessageW(hwnd
, WM_GETOBJECT
, 0xffffffff, dwObjectID
);
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
;
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
)
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
));
431 /* native leaks v here */
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
);
443 IAccessible_AddRef(acc2
);
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
);
457 hres
= IAccessible_get_accParent(acc
, &parent
);
458 IAccessible_Release(acc2
);
466 hres
= IDispatch_QueryInterface(parent
, &IID_IAccessible
, (void**)&acc2
);
467 IDispatch_Release(parent
);
474 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
,
477 TRACE("%p, %ld, %p\n", hinstDLL
, fdwReason
, lpvReserved
);
481 case DLL_PROCESS_ATTACH
:
482 oleacc_handle
= hinstDLL
;
483 DisableThreadLibraryCalls(hinstDLL
);
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
);
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
)
528 if(!GetWindowThreadProcessId(hwnd
, &proc_id
))
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
)
539 TRACE("%lu %p %u\n", role
, lpRole
, rolemax
);
541 /* return role text length */
543 return LoadStringW(oleacc_handle
, role
, (LPWSTR
)&resptr
, 0);
545 ret
= LoadStringW(oleacc_handle
, role
, lpRole
, rolemax
);
547 if(rolemax
> 0) lpRole
[0] = '\0';
554 UINT WINAPI
GetRoleTextA(DWORD role
, LPSTR lpRole
, UINT rolemax
)
559 TRACE("%lu %p %u\n", role
, lpRole
, rolemax
);
561 if(lpRole
&& !rolemax
)
564 length
= GetRoleTextW(role
, NULL
, 0);
566 if(lpRole
&& rolemax
)
571 roletextW
= HeapAlloc(GetProcessHeap(), 0, (length
+ 1)*sizeof(WCHAR
));
575 GetRoleTextW(role
, roletextW
, length
+ 1);
577 length
= WideCharToMultiByte( CP_ACP
, 0, roletextW
, -1, NULL
, 0, NULL
, NULL
);
580 HeapFree(GetProcessHeap(), 0, roletextW
);
584 if(rolemax
< length
) {
585 HeapFree(GetProcessHeap(), 0, roletextW
);
590 WideCharToMultiByte( CP_ACP
, 0, roletextW
, -1, lpRole
, rolemax
, NULL
, NULL
);
592 if(rolemax
< length
){
593 lpRole
[rolemax
-1] = '\0';
597 HeapFree(GetProcessHeap(), 0, roletextW
);
602 UINT WINAPI
GetStateTextW(DWORD state_bit
, WCHAR
*state_str
, UINT state_str_len
)
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
)
614 state_id
= IDS_STATE_NORMAL
;
621 UINT ret
= LoadStringW(oleacc_handle
, state_id
, state_str
, state_str_len
);
622 if(!ret
&& state_str_len
)
627 return LoadStringW(oleacc_handle
, state_id
, (WCHAR
*)&tmp
, 0);
632 UINT WINAPI
GetStateTextA(DWORD state_bit
, CHAR
*state_str
, UINT state_str_len
)
636 TRACE("%lx %p %u\n", state_bit
, state_str
, state_str_len
);
638 if(state_str
&& !state_str_len
)
641 if(state_bit
& ~(STATE_SYSTEM_VALID
| STATE_SYSTEM_HASPOPUP
)) {
642 if(state_str
&& state_str_len
)
647 state_id
= IDS_STATE_NORMAL
;
654 UINT ret
= LoadStringA(oleacc_handle
, state_id
, state_str
, state_str_len
);
655 if(!ret
&& state_str_len
)
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
)
671 TRACE("%p %ld %ld %p %p\n", container
, start
, count
, children
, children_cnt
);
673 if(!container
|| !children
|| !children_cnt
)
676 for(i
=0; i
<count
; i
++)
677 VariantInit(children
+i
);
679 hr
= IAccessible_QueryInterface(container
, &IID_IEnumVARIANT
, (void**)&ev
);
681 hr
= IEnumVARIANT_Reset(ev
);
683 hr
= IEnumVARIANT_Skip(ev
, start
);
685 hr
= IEnumVARIANT_Next(ev
, count
, children
, (ULONG
*)children_cnt
);
686 IEnumVARIANT_Release(ev
);
690 hr
= IAccessible_get_accChildCount(container
, &child_no
);
694 for(i
=0; i
<count
&& start
+i
+1<=child_no
; i
++) {
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
;
708 return i
==count
? S_OK
: S_FALSE
;