oleacc: Modify output buffer on incorrect role in GetRoleTextA.
[wine.git] / dlls / oleacc / main.c
blob36349917d98abfba9045ad14ac5ebce24fb168ee
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"
28 #include "initguid.h"
29 #include "oleacc_private.h"
30 #include "resource.h"
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(oleacc);
37 static const WCHAR lresult_atom_prefix[] = {'w','i','n','e','_','o','l','e','a','c','c',':'};
39 static HINSTANCE oleacc_handle = 0;
41 const char *debugstr_variant(const VARIANT *v)
43 if(!v)
44 return "(null)";
46 if(V_ISBYREF(v))
47 return wine_dbg_sprintf("{V_BYREF -> %s}", debugstr_variant(V_BYREF(v)));
49 switch(V_VT(v)) {
50 case VT_EMPTY:
51 return "{VT_EMPTY}";
52 case VT_NULL:
53 return "{VT_NULL}";
54 case VT_I2:
55 return wine_dbg_sprintf("{VT_I2: %d}", V_I2(v));
56 case VT_I4:
57 return wine_dbg_sprintf("{VT_I4: %d}", V_I4(v));
58 case VT_UI4:
59 return wine_dbg_sprintf("{VT_UI4: %u}", V_UI4(v));
60 case VT_R8:
61 return wine_dbg_sprintf("{VT_R8: %lf}", V_R8(v));
62 case VT_BSTR:
63 return wine_dbg_sprintf("{VT_BSTR: %s}", debugstr_w(V_BSTR(v)));
64 case VT_DISPATCH:
65 return wine_dbg_sprintf("{VT_DISPATCH: %p}", V_DISPATCH(v));
66 case VT_BOOL:
67 return wine_dbg_sprintf("{VT_BOOL: %x}", V_BOOL(v));
68 default:
69 return wine_dbg_sprintf("{vt %d}", V_VT(v));
73 int convert_child_id(VARIANT *v)
75 switch(V_VT(v)) {
76 case VT_I4:
77 return V_I4(v);
78 default:
79 FIXME("unhandled child ID variant type: %d\n", V_VT(v));
80 return -1;
84 HRESULT WINAPI CreateStdAccessibleObject( HWND hwnd, LONG idObject,
85 REFIID riidInterface, void** ppvObject )
87 WCHAR class_name[64];
89 TRACE("%p %d %s %p\n", hwnd, idObject,
90 debugstr_guid( riidInterface ), ppvObject );
91 if(GetClassNameW(hwnd, class_name, sizeof(class_name)/sizeof(WCHAR)))
92 FIXME("unhandled window class: %s\n", debugstr_w(class_name));
94 switch(idObject) {
95 case OBJID_CLIENT:
96 return create_client_object(hwnd, riidInterface, ppvObject);
97 case OBJID_WINDOW:
98 return create_window_object(hwnd, riidInterface, ppvObject);
99 default:
100 FIXME("unhandled object id: %d\n", idObject);
101 return E_NOTIMPL;
105 HRESULT WINAPI ObjectFromLresult( LRESULT result, REFIID riid, WPARAM wParam, void **ppObject )
107 WCHAR atom_str[sizeof(lresult_atom_prefix)/sizeof(WCHAR)+3*8+3];
108 HANDLE server_proc, server_mapping, mapping;
109 DWORD proc_id, size;
110 IStream *stream;
111 HGLOBAL data;
112 void *view;
113 HRESULT hr;
114 WCHAR *p;
116 TRACE("%ld %s %ld %p\n", result, debugstr_guid(riid), wParam, ppObject );
118 if(wParam)
119 FIXME("unsupported wParam = %lx\n", wParam);
121 if(!ppObject)
122 return E_INVALIDARG;
123 *ppObject = NULL;
125 if(result != (ATOM)result)
126 return E_FAIL;
128 if(!GlobalGetAtomNameW(result, atom_str, sizeof(atom_str)/sizeof(WCHAR)))
129 return E_FAIL;
130 if(memcmp(atom_str, lresult_atom_prefix, sizeof(lresult_atom_prefix)))
131 return E_FAIL;
132 p = atom_str + sizeof(lresult_atom_prefix)/sizeof(WCHAR);
133 proc_id = strtoulW(p, &p, 16);
134 if(*p != ':')
135 return E_FAIL;
136 server_mapping = ULongToHandle( strtoulW(p+1, &p, 16) );
137 if(*p != ':')
138 return E_FAIL;
139 size = strtoulW(p+1, &p, 16);
140 if(*p != 0)
141 return E_FAIL;
143 server_proc = OpenProcess(PROCESS_DUP_HANDLE, FALSE, proc_id);
144 if(!server_proc)
145 return E_FAIL;
147 if(!DuplicateHandle(server_proc, server_mapping, GetCurrentProcess(), &mapping,
148 0, FALSE, DUPLICATE_CLOSE_SOURCE|DUPLICATE_SAME_ACCESS))
149 return E_FAIL;
150 CloseHandle(server_proc);
151 GlobalDeleteAtom(result);
153 view = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
154 CloseHandle(mapping);
155 if(!view)
156 return E_FAIL;
158 data = GlobalAlloc(GMEM_FIXED, size);
159 memcpy(data, view, size);
160 UnmapViewOfFile(view);
161 if(!data)
162 return E_OUTOFMEMORY;
164 hr = CreateStreamOnHGlobal(data, TRUE, &stream);
165 if(FAILED(hr)) {
166 GlobalFree(data);
167 return hr;
170 hr = CoUnmarshalInterface(stream, riid, ppObject);
171 IStream_Release(stream);
172 return hr;
175 LRESULT WINAPI LresultFromObject( REFIID riid, WPARAM wParam, LPUNKNOWN pAcc )
177 static const WCHAR atom_fmt[] = {'%','0','8','x',':','%','0','8','x',':','%','0','8','x',0};
178 static const LARGE_INTEGER seek_zero = {{0}};
180 WCHAR atom_str[sizeof(lresult_atom_prefix)/sizeof(WCHAR)+3*8+3];
181 IStream *stream;
182 HANDLE mapping;
183 STATSTG stat;
184 HRESULT hr;
185 ATOM atom;
186 void *view;
188 TRACE("%s %ld %p\n", debugstr_guid(riid), wParam, pAcc);
190 if(wParam)
191 FIXME("unsupported wParam = %lx\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 sprintfW(atom_str+sizeof(lresult_atom_prefix)/sizeof(WCHAR),
254 atom_fmt, GetCurrentProcessId(), 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 HRESULT WINAPI AccessibleObjectFromPoint( POINT ptScreen, IAccessible** ppacc, VARIANT* pvarChild )
271 FIXME("{%d,%d} %p %p: stub\n", ptScreen.x, ptScreen.y, ppacc, pvarChild );
272 return E_NOTIMPL;
275 HRESULT WINAPI AccessibleObjectFromWindow( HWND hwnd, DWORD dwObjectID,
276 REFIID riid, void** ppvObject )
278 TRACE("%p %d %s %p\n", hwnd, dwObjectID,
279 debugstr_guid( riid ), ppvObject );
281 if(!ppvObject)
282 return E_INVALIDARG;
283 *ppvObject = NULL;
285 if(IsWindow(hwnd)) {
286 LRESULT lres;
288 lres = SendMessageW(hwnd, WM_GETOBJECT, 0xffffffff, dwObjectID);
289 if(FAILED(lres))
290 return lres;
291 else if(lres)
292 return ObjectFromLresult(lres, riid, 0, ppvObject);
295 return CreateStdAccessibleObject(hwnd, dwObjectID, riid, ppvObject);
298 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
299 LPVOID lpvReserved)
301 TRACE("%p, %d, %p\n", hinstDLL, fdwReason, lpvReserved);
303 switch (fdwReason)
305 case DLL_PROCESS_ATTACH:
306 oleacc_handle = hinstDLL;
307 DisableThreadLibraryCalls(hinstDLL);
308 break;
310 return TRUE;
313 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, void **ppv)
315 FIXME("%s %s %p: stub\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv);
316 return E_NOTIMPL;
319 HRESULT WINAPI DllRegisterServer(void)
321 FIXME("\n");
322 return S_OK;
325 HRESULT WINAPI DllUnregisterServer(void)
327 FIXME("\n");
328 return S_OK;
331 void WINAPI GetOleaccVersionInfo(DWORD* pVersion, DWORD* pBuild)
333 *pVersion = MAKELONG(0,7); /* Windows 7 version of oleacc: 7.0.0.0 */
334 *pBuild = MAKELONG(0,0);
337 HANDLE WINAPI GetProcessHandleFromHwnd(HWND hwnd)
339 DWORD proc_id;
341 TRACE("%p\n", hwnd);
343 if(!GetWindowThreadProcessId(hwnd, &proc_id))
344 return NULL;
345 return OpenProcess(PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION |
346 PROCESS_VM_READ | PROCESS_VM_WRITE | SYNCHRONIZE, TRUE, proc_id);
349 UINT WINAPI GetRoleTextW(DWORD role, LPWSTR lpRole, UINT rolemax)
351 INT ret;
352 WCHAR *resptr;
354 TRACE("%u %p %u\n", role, lpRole, rolemax);
356 /* return role text length */
357 if(!lpRole)
358 return LoadStringW(oleacc_handle, role, (LPWSTR)&resptr, 0);
360 ret = LoadStringW(oleacc_handle, role, lpRole, rolemax);
361 if(!(ret > 0)){
362 if(rolemax > 0) lpRole[0] = '\0';
363 return 0;
366 return ret;
369 UINT WINAPI GetRoleTextA(DWORD role, LPSTR lpRole, UINT rolemax)
371 UINT length;
372 WCHAR *roletextW;
374 TRACE("%u %p %u\n", role, lpRole, rolemax);
376 if(lpRole && !rolemax)
377 return 0;
379 length = GetRoleTextW(role, NULL, 0);
380 if(!length) {
381 if(lpRole && rolemax)
382 lpRole[0] = 0;
383 return 0;
386 roletextW = HeapAlloc(GetProcessHeap(), 0, (length + 1)*sizeof(WCHAR));
387 if(!roletextW)
388 return 0;
390 GetRoleTextW(role, roletextW, length + 1);
392 length = WideCharToMultiByte( CP_ACP, 0, roletextW, -1, NULL, 0, NULL, NULL );
394 if(!lpRole){
395 HeapFree(GetProcessHeap(), 0, roletextW);
396 return length - 1;
399 WideCharToMultiByte( CP_ACP, 0, roletextW, -1, lpRole, rolemax, NULL, NULL );
401 if(rolemax < length){
402 lpRole[rolemax-1] = '\0';
403 length = rolemax;
406 HeapFree(GetProcessHeap(), 0, roletextW);
408 return length - 1;
411 UINT WINAPI GetStateTextW(DWORD state_bit, WCHAR *state_str, UINT state_str_len)
413 DWORD state_id;
415 TRACE("%x %p %u\n", state_bit, state_str, state_str_len);
417 if(state_bit & ~(STATE_SYSTEM_VALID | STATE_SYSTEM_HASPOPUP)) {
418 if(state_str && state_str_len)
419 state_str[0] = 0;
420 return 0;
423 state_id = IDS_STATE_NORMAL;
424 while(state_bit) {
425 state_id++;
426 state_bit /= 2;
429 if(state_str) {
430 UINT ret = LoadStringW(oleacc_handle, state_id, state_str, state_str_len);
431 if(!ret && state_str_len)
432 state_str[0] = 0;
433 return ret;
434 }else {
435 WCHAR *tmp;
436 return LoadStringW(oleacc_handle, state_id, (WCHAR*)&tmp, 0);
441 UINT WINAPI GetStateTextA(DWORD state_bit, CHAR *state_str, UINT state_str_len)
443 DWORD state_id;
445 TRACE("%x %p %u\n", state_bit, state_str, state_str_len);
447 if(state_str && !state_str_len)
448 return 0;
450 if(state_bit & ~(STATE_SYSTEM_VALID | STATE_SYSTEM_HASPOPUP)) {
451 if(state_str && state_str_len)
452 state_str[0] = 0;
453 return 0;
456 state_id = IDS_STATE_NORMAL;
457 while(state_bit) {
458 state_id++;
459 state_bit /= 2;
462 if(state_str) {
463 UINT ret = LoadStringA(oleacc_handle, state_id, state_str, state_str_len);
464 if(!ret && state_str_len)
465 state_str[0] = 0;
466 return ret;
467 }else {
468 CHAR tmp[256];
469 return LoadStringA(oleacc_handle, state_id, tmp, sizeof(tmp));