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
31 #include "oleacc_private.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 extern HRESULT WINAPI
OLEACC_DllGetClassObject(REFCLSID
, REFIID
, void**) DECLSPEC_HIDDEN
;
53 extern BOOL WINAPI
OLEACC_DllMain(HINSTANCE
, DWORD
, void*) DECLSPEC_HIDDEN
;
54 extern HRESULT WINAPI
OLEACC_DllRegisterServer(void) DECLSPEC_HIDDEN
;
55 extern HRESULT WINAPI
OLEACC_DllUnregisterServer(void) DECLSPEC_HIDDEN
;
60 accessible_create create_client
;
61 accessible_create create_window
;
62 } builtin_classes
[] = {
63 {WC_LISTBOXW
, 0x10000, NULL
, NULL
},
64 {menuW
, 0x10001, NULL
, NULL
},
65 {WC_BUTTONW
, 0x10002, NULL
, NULL
},
66 {WC_STATICW
, 0x10003, NULL
, NULL
},
67 {WC_EDITW
, 0x10004, NULL
, NULL
},
68 {WC_COMBOBOXW
, 0x10005, NULL
, NULL
},
69 {dialogW
, 0x10006, NULL
, NULL
},
70 {winswitchW
, 0x10007, NULL
, NULL
},
71 {mdi_clientW
, 0x10008, NULL
, NULL
},
72 {desktopW
, 0x10009, NULL
, NULL
},
73 {WC_SCROLLBARW
, 0x1000a, NULL
, NULL
},
74 {STATUSCLASSNAMEW
, 0x1000b, NULL
, NULL
},
75 {TOOLBARCLASSNAMEW
, 0x1000c, NULL
, NULL
},
76 {PROGRESS_CLASSW
, 0x1000d, NULL
, NULL
},
77 {ANIMATE_CLASSW
, 0x1000e, NULL
, NULL
},
78 {WC_TABCONTROLW
, 0x1000f, NULL
, NULL
},
79 {HOTKEY_CLASSW
, 0x10010, NULL
, NULL
},
80 {WC_HEADERW
, 0x10011, NULL
, NULL
},
81 {TRACKBAR_CLASSW
, 0x10012, NULL
, NULL
},
82 {WC_LISTVIEWW
, 0x10013, NULL
, NULL
},
83 {UPDOWN_CLASSW
, 0x10016, NULL
, NULL
},
84 {TOOLTIPS_CLASSW
, 0x10018, NULL
, NULL
},
85 {WC_TREEVIEWW
, 0x10019, NULL
, NULL
},
86 {MONTHCAL_CLASSW
, 0, NULL
, NULL
},
87 {DATETIMEPICK_CLASSW
, 0, NULL
, NULL
},
88 {WC_IPADDRESSW
, 0, NULL
, NULL
},
89 {richeditW
, 0x1001c, NULL
, NULL
},
90 {richedit20aW
, 0, NULL
, NULL
},
91 {richedit20wW
, 0, NULL
, NULL
},
94 static HINSTANCE oleacc_handle
= 0;
96 int convert_child_id(VARIANT
*v
)
102 FIXME("unhandled child ID variant type: %d\n", V_VT(v
));
107 static accessible_create
get_builtin_accessible_obj(HWND hwnd
, LONG objid
)
109 WCHAR class_name
[64];
112 if(!RealGetWindowClassW(hwnd
, class_name
, sizeof(class_name
)/sizeof(WCHAR
)))
114 TRACE("got window class: %s\n", debugstr_w(class_name
));
116 for(i
=0; i
<sizeof(builtin_classes
)/sizeof(builtin_classes
[0]); i
++) {
117 if(!strcmpiW(class_name
, builtin_classes
[i
].name
)) {
118 accessible_create ret
;
120 ret
= (objid
==OBJID_CLIENT
?
121 builtin_classes
[i
].create_client
:
122 builtin_classes
[i
].create_window
);
124 FIXME("unhandled window class: %s\n", debugstr_w(class_name
));
129 idx
= SendMessageW(hwnd
, WM_GETOBJECT
, 0, OBJID_QUERYCLASSNAMEIDX
);
131 for(i
=0; i
<sizeof(builtin_classes
)/sizeof(builtin_classes
[0]); i
++) {
132 if(idx
== builtin_classes
[i
].idx
) {
133 accessible_create ret
;
135 ret
= (objid
==OBJID_CLIENT
?
136 builtin_classes
[i
].create_client
:
137 builtin_classes
[i
].create_window
);
139 FIXME("unhandled class name idx: %x\n", idx
);
144 WARN("unhandled class name idx: %x\n", idx
);
150 HRESULT WINAPI
CreateStdAccessibleObject( HWND hwnd
, LONG idObject
,
151 REFIID riidInterface
, void** ppvObject
)
153 accessible_create create
;
155 TRACE("%p %d %s %p\n", hwnd
, idObject
,
156 debugstr_guid( riidInterface
), ppvObject
);
160 create
= get_builtin_accessible_obj(hwnd
, idObject
);
161 if(create
) return create(hwnd
, riidInterface
, ppvObject
);
162 return create_client_object(hwnd
, riidInterface
, ppvObject
);
164 create
= get_builtin_accessible_obj(hwnd
, idObject
);
165 if(create
) return create(hwnd
, riidInterface
, ppvObject
);
166 return create_window_object(hwnd
, riidInterface
, ppvObject
);
168 FIXME("unhandled object id: %d\n", idObject
);
173 HRESULT WINAPI
ObjectFromLresult( LRESULT result
, REFIID riid
, WPARAM wParam
, void **ppObject
)
175 WCHAR atom_str
[sizeof(lresult_atom_prefix
)/sizeof(WCHAR
)+3*8+3];
176 HANDLE server_proc
, server_mapping
, mapping
;
184 TRACE("%ld %s %ld %p\n", result
, debugstr_guid(riid
), wParam
, ppObject
);
187 FIXME("unsupported wParam = %lx\n", wParam
);
193 if(result
!= (ATOM
)result
)
196 if(!GlobalGetAtomNameW(result
, atom_str
, sizeof(atom_str
)/sizeof(WCHAR
)))
198 if(memcmp(atom_str
, lresult_atom_prefix
, sizeof(lresult_atom_prefix
)))
200 p
= atom_str
+ sizeof(lresult_atom_prefix
)/sizeof(WCHAR
);
201 proc_id
= strtoulW(p
, &p
, 16);
204 server_mapping
= ULongToHandle( strtoulW(p
+1, &p
, 16) );
207 size
= strtoulW(p
+1, &p
, 16);
211 server_proc
= OpenProcess(PROCESS_DUP_HANDLE
, FALSE
, proc_id
);
215 if(!DuplicateHandle(server_proc
, server_mapping
, GetCurrentProcess(), &mapping
,
216 0, FALSE
, DUPLICATE_CLOSE_SOURCE
|DUPLICATE_SAME_ACCESS
))
218 CloseHandle(server_proc
);
219 GlobalDeleteAtom(result
);
221 view
= MapViewOfFile(mapping
, FILE_MAP_READ
, 0, 0, 0);
222 CloseHandle(mapping
);
226 data
= GlobalAlloc(GMEM_FIXED
, size
);
228 UnmapViewOfFile(view
);
229 return E_OUTOFMEMORY
;
231 memcpy(data
, view
, size
);
232 UnmapViewOfFile(view
);
234 hr
= CreateStreamOnHGlobal(data
, TRUE
, &stream
);
240 hr
= CoUnmarshalInterface(stream
, riid
, ppObject
);
241 IStream_Release(stream
);
245 LRESULT WINAPI
LresultFromObject( REFIID riid
, WPARAM wParam
, LPUNKNOWN pAcc
)
247 static const WCHAR atom_fmt
[] = {'%','0','8','x',':','%','0','8','x',':','%','0','8','x',0};
248 static const LARGE_INTEGER seek_zero
= {{0}};
250 WCHAR atom_str
[sizeof(lresult_atom_prefix
)/sizeof(WCHAR
)+3*8+3];
258 TRACE("%s %ld %p\n", debugstr_guid(riid
), wParam
, pAcc
);
261 FIXME("unsupported wParam = %lx\n", wParam
);
266 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stream
);
270 hr
= CoMarshalInterface(stream
, riid
, pAcc
, MSHCTX_LOCAL
, NULL
, MSHLFLAGS_NORMAL
);
272 IStream_Release(stream
);
276 hr
= IStream_Seek(stream
, seek_zero
, STREAM_SEEK_SET
, NULL
);
278 IStream_Release(stream
);
282 hr
= IStream_Stat(stream
, &stat
, STATFLAG_NONAME
);
284 CoReleaseMarshalData(stream
);
285 IStream_Release(stream
);
287 }else if(stat
.cbSize
.u
.HighPart
) {
288 FIXME("stream size to big\n");
289 CoReleaseMarshalData(stream
);
290 IStream_Release(stream
);
294 mapping
= CreateFileMappingW(INVALID_HANDLE_VALUE
, NULL
, PAGE_READWRITE
,
295 stat
.cbSize
.u
.HighPart
, stat
.cbSize
.u
.LowPart
, NULL
);
297 CoReleaseMarshalData(stream
);
298 IStream_Release(stream
);
302 view
= MapViewOfFile(mapping
, FILE_MAP_WRITE
, 0, 0, 0);
304 CloseHandle(mapping
);
305 CoReleaseMarshalData(stream
);
306 IStream_Release(stream
);
310 hr
= IStream_Read(stream
, view
, stat
.cbSize
.u
.LowPart
, NULL
);
311 UnmapViewOfFile(view
);
313 CloseHandle(mapping
);
314 hr
= IStream_Seek(stream
, seek_zero
, STREAM_SEEK_SET
, NULL
);
316 CoReleaseMarshalData(stream
);
317 IStream_Release(stream
);
322 memcpy(atom_str
, lresult_atom_prefix
, sizeof(lresult_atom_prefix
));
323 sprintfW(atom_str
+sizeof(lresult_atom_prefix
)/sizeof(WCHAR
),
324 atom_fmt
, GetCurrentProcessId(), HandleToUlong(mapping
), stat
.cbSize
.u
.LowPart
);
325 atom
= GlobalAddAtomW(atom_str
);
327 CloseHandle(mapping
);
328 hr
= IStream_Seek(stream
, seek_zero
, STREAM_SEEK_SET
, NULL
);
330 CoReleaseMarshalData(stream
);
331 IStream_Release(stream
);
335 IStream_Release(stream
);
339 HRESULT WINAPI
AccessibleObjectFromPoint( POINT ptScreen
, IAccessible
** ppacc
, VARIANT
* pvarChild
)
341 FIXME("{%d,%d} %p %p: stub\n", ptScreen
.x
, ptScreen
.y
, ppacc
, pvarChild
);
345 HRESULT WINAPI
AccessibleObjectFromWindow( HWND hwnd
, DWORD dwObjectID
,
346 REFIID riid
, void** ppvObject
)
348 TRACE("%p %d %s %p\n", hwnd
, dwObjectID
,
349 debugstr_guid( riid
), ppvObject
);
358 lres
= SendMessageW(hwnd
, WM_GETOBJECT
, 0xffffffff, dwObjectID
);
362 return ObjectFromLresult(lres
, riid
, 0, ppvObject
);
365 return CreateStdAccessibleObject(hwnd
, dwObjectID
, riid
, ppvObject
);
368 HRESULT WINAPI
WindowFromAccessibleObject(IAccessible
*acc
, HWND
*phwnd
)
374 TRACE("%p %p\n", acc
, phwnd
);
376 IAccessible_AddRef(acc
);
378 hres
= IAccessible_QueryInterface(acc
, &IID_IOleWindow
, (void**)&ow
);
379 if(SUCCEEDED(hres
)) {
380 hres
= IOleWindow_GetWindow(ow
, phwnd
);
381 IOleWindow_Release(ow
);
382 IAccessible_Release(acc
);
386 hres
= IAccessible_get_accParent(acc
, &parent
);
387 IAccessible_Release(acc
);
390 if(hres
!=S_OK
|| !parent
) {
395 hres
= IDispatch_QueryInterface(parent
, &IID_IAccessible
, (void**)&acc
);
396 IDispatch_Release(parent
);
402 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
,
405 TRACE("%p, %d, %p\n", hinstDLL
, fdwReason
, lpvReserved
);
409 case DLL_PROCESS_ATTACH
:
410 oleacc_handle
= hinstDLL
;
411 DisableThreadLibraryCalls(hinstDLL
);
415 return OLEACC_DllMain(hinstDLL
, fdwReason
, lpvReserved
);
418 HRESULT WINAPI
DllRegisterServer(void)
420 return OLEACC_DllRegisterServer();
423 HRESULT WINAPI
DllUnregisterServer(void)
425 return OLEACC_DllUnregisterServer();
428 HRESULT WINAPI
DllGetClassObject(REFCLSID rclsid
, REFIID iid
, void **ppv
)
430 if(IsEqualGUID(&CLSID_CAccPropServices
, rclsid
)) {
431 TRACE("(CLSID_CAccPropServices %s %p)\n", debugstr_guid(iid
), ppv
);
432 return get_accpropservices_factory(iid
, ppv
);
435 if(IsEqualGUID(&CLSID_PSFactoryBuffer
, rclsid
)) {
436 TRACE("(CLSID_PSFactoryBuffer %s %p)\n", debugstr_guid(iid
), ppv
);
437 return OLEACC_DllGetClassObject(rclsid
, iid
, ppv
);
440 FIXME("%s %s %p: stub\n", debugstr_guid(rclsid
), debugstr_guid(iid
), ppv
);
444 void WINAPI
GetOleaccVersionInfo(DWORD
* pVersion
, DWORD
* pBuild
)
446 *pVersion
= MAKELONG(0,7); /* Windows 7 version of oleacc: 7.0.0.0 */
447 *pBuild
= MAKELONG(0,0);
450 HANDLE WINAPI
GetProcessHandleFromHwnd(HWND hwnd
)
456 if(!GetWindowThreadProcessId(hwnd
, &proc_id
))
458 return OpenProcess(PROCESS_DUP_HANDLE
| PROCESS_VM_OPERATION
|
459 PROCESS_VM_READ
| PROCESS_VM_WRITE
| SYNCHRONIZE
, TRUE
, proc_id
);
462 UINT WINAPI
GetRoleTextW(DWORD role
, LPWSTR lpRole
, UINT rolemax
)
467 TRACE("%u %p %u\n", role
, lpRole
, rolemax
);
469 /* return role text length */
471 return LoadStringW(oleacc_handle
, role
, (LPWSTR
)&resptr
, 0);
473 ret
= LoadStringW(oleacc_handle
, role
, lpRole
, rolemax
);
475 if(rolemax
> 0) lpRole
[0] = '\0';
482 UINT WINAPI
GetRoleTextA(DWORD role
, LPSTR lpRole
, UINT rolemax
)
487 TRACE("%u %p %u\n", role
, lpRole
, rolemax
);
489 if(lpRole
&& !rolemax
)
492 length
= GetRoleTextW(role
, NULL
, 0);
494 if(lpRole
&& rolemax
)
499 roletextW
= HeapAlloc(GetProcessHeap(), 0, (length
+ 1)*sizeof(WCHAR
));
503 GetRoleTextW(role
, roletextW
, length
+ 1);
505 length
= WideCharToMultiByte( CP_ACP
, 0, roletextW
, -1, NULL
, 0, NULL
, NULL
);
508 HeapFree(GetProcessHeap(), 0, roletextW
);
512 if(rolemax
< length
) {
513 HeapFree(GetProcessHeap(), 0, roletextW
);
518 WideCharToMultiByte( CP_ACP
, 0, roletextW
, -1, lpRole
, rolemax
, NULL
, NULL
);
520 if(rolemax
< length
){
521 lpRole
[rolemax
-1] = '\0';
525 HeapFree(GetProcessHeap(), 0, roletextW
);
530 UINT WINAPI
GetStateTextW(DWORD state_bit
, WCHAR
*state_str
, UINT state_str_len
)
534 TRACE("%x %p %u\n", state_bit
, state_str
, state_str_len
);
536 if(state_bit
& ~(STATE_SYSTEM_VALID
| STATE_SYSTEM_HASPOPUP
)) {
537 if(state_str
&& state_str_len
)
542 state_id
= IDS_STATE_NORMAL
;
549 UINT ret
= LoadStringW(oleacc_handle
, state_id
, state_str
, state_str_len
);
550 if(!ret
&& state_str_len
)
555 return LoadStringW(oleacc_handle
, state_id
, (WCHAR
*)&tmp
, 0);
560 UINT WINAPI
GetStateTextA(DWORD state_bit
, CHAR
*state_str
, UINT state_str_len
)
564 TRACE("%x %p %u\n", state_bit
, state_str
, state_str_len
);
566 if(state_str
&& !state_str_len
)
569 if(state_bit
& ~(STATE_SYSTEM_VALID
| STATE_SYSTEM_HASPOPUP
)) {
570 if(state_str
&& state_str_len
)
575 state_id
= IDS_STATE_NORMAL
;
582 UINT ret
= LoadStringA(oleacc_handle
, state_id
, state_str
, state_str_len
);
583 if(!ret
&& state_str_len
)
588 return LoadStringA(oleacc_handle
, state_id
, tmp
, sizeof(tmp
));
592 HRESULT WINAPI
AccessibleChildren(IAccessible
*container
,
593 LONG start
, LONG count
, VARIANT
*children
, LONG
*children_cnt
)
599 TRACE("%p %d %d %p %p\n", container
, start
, count
, children
, children_cnt
);
601 if(!container
|| !children
|| !children_cnt
)
604 for(i
=0; i
<count
; i
++)
605 VariantInit(children
+i
);
607 hr
= IAccessible_QueryInterface(container
, &IID_IEnumVARIANT
, (void**)&ev
);
609 hr
= IEnumVARIANT_Reset(ev
);
611 hr
= IEnumVARIANT_Skip(ev
, start
);
613 hr
= IEnumVARIANT_Next(ev
, count
, children
, (ULONG
*)children_cnt
);
614 IEnumVARIANT_Release(ev
);
618 hr
= IAccessible_get_accChildCount(container
, &child_no
);
622 for(i
=0; i
<count
&& start
+i
+1<=child_no
; i
++) {
625 V_VT(children
+i
) = VT_I4
;
626 V_I4(children
+i
) = start
+i
+1;
628 hr
= IAccessible_get_accChild(container
, children
[i
], &disp
);
629 if(SUCCEEDED(hr
) && disp
) {
630 V_VT(children
+i
) = VT_DISPATCH
;
631 V_DISPATCH(children
+i
) = disp
;
636 return i
==count
? S_OK
: S_FALSE
;