1 /*
2 * OLE2 library
3 *
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1999 Francis Beaudet
6 * Copyright 1999 Noel Borthwick
7 * Copyright 1999, 2000 Marcus Meissner
8 * Copyright 2005 Juan Lang
9 * Copyright 2011 Adam Martinson for CodeWeavers
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <string.h>
31
32 #define COBJMACROS
33 #define NONAMELESSUNION
34
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winerror.h"
38 #include "wingdi.h"
39 #include "winuser.h"
40 #include "winnls.h"
41 #include "winreg.h"
42 #include "ole2.h"
43 #include "ole2ver.h"
44
45 #include "compobj_private.h"
46 #include "olestd.h"
47 #include "wine/list.h"
48
49 #include "wine/debug.h"
50
51 WINE_DEFAULT_DEBUG_CHANNEL(ole);
52 WINE_DECLARE_DEBUG_CHANNEL(accel);
53
54 /******************************************************************************
55 * These are static/global variables and internal data structures that the
56 * OLE module uses to maintain its state.
57 */
58 typedef struct tagTrackerWindowInfo
59 {
60 IDataObject* dataObject;
61 IDropSource* dropSource;
62 DWORD dwOKEffect;
63 DWORD* pdwEffect;
64 BOOL trackingDone;
65 HRESULT returnValue;
66
67 BOOL escPressed;
68 HWND curTargetHWND; /* window the mouse is hovering over */
69 IDropTarget* curDragTarget;
70 #ifdef __REACTOS__
71 HWND accepterHWND;
72 #endif
73 POINTL curMousePos; /* current position of the mouse in screen coordinates */
74 DWORD dwKeyState; /* current state of the shift and ctrl keys and the mouse buttons */
75 } TrackerWindowInfo;
76
77 typedef struct tagOleMenuDescriptor /* OleMenuDescriptor */
78 {
79 HWND hwndFrame; /* The containers frame window */
80 HWND hwndActiveObject; /* The active objects window */
81 OLEMENUGROUPWIDTHS mgw; /* OLE menu group widths for the shared menu */
82 HMENU hmenuCombined; /* The combined menu */
83 BOOL bIsServerItem; /* True if the currently open popup belongs to the server */
84 } OleMenuDescriptor;
85
86 typedef struct tagOleMenuHookItem /* OleMenu hook item in per thread hook list */
87 {
88 DWORD tid; /* Thread Id */
89 HANDLE hHeap; /* Heap this is allocated from */
90 HHOOK GetMsg_hHook; /* message hook for WH_GETMESSAGE */
91 HHOOK CallWndProc_hHook; /* message hook for WH_CALLWNDPROC */
92 struct tagOleMenuHookItem *next;
93 } OleMenuHookItem;
94
95 static OleMenuHookItem *hook_list;
96
97 /*
98 * This is the lock count on the OLE library. It is controlled by the
99 * OLEInitialize/OLEUninitialize methods.
100 */
101 static LONG OLE_moduleLockCount = 0;
102
103 /*
104 * Name of our registered window class.
105 */
106 static const WCHAR OLEDD_DRAGTRACKERCLASS[] =
107 {'W','i','n','e','D','r','a','g','D','r','o','p','T','r','a','c','k','e','r','3','2',0};
108
109 /*
110 * Name of menu descriptor property.
111 */
112 static const WCHAR prop_olemenuW[] =
113 {'P','R','O','P','_','O','L','E','M','e','n','u','D','e','s','c','r','i','p','t','o','r',0};
114
115 /* property to store IDropTarget pointer */
116 static const WCHAR prop_oledroptarget[] =
117 {'O','l','e','D','r','o','p','T','a','r','g','e','t','I','n','t','e','r','f','a','c','e',0};
118
119 /* property to store Marshalled IDropTarget pointer */
120 static const WCHAR prop_marshalleddroptarget[] =
121 {'W','i','n','e','M','a','r','s','h','a','l','l','e','d','D','r','o','p','T','a','r','g','e','t',0};
122
123 static const WCHAR emptyW[] = { 0 };
124
125 /******************************************************************************
126 * These are the prototypes of miscellaneous utility methods
127 */
128 static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue);
129
130 /******************************************************************************
131 * These are the prototypes of the utility methods used to manage a shared menu
132 */
133 static void OLEMenu_Initialize(void);
134 static void OLEMenu_UnInitialize(void);
135 static BOOL OLEMenu_InstallHooks( DWORD tid );
136 static BOOL OLEMenu_UnInstallHooks( DWORD tid );
137 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid );
138 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
139 static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor );
140 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam);
141 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam);
142
143 /******************************************************************************
144 * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c)
145 */
146 extern void OLEClipbrd_UnInitialize(void);
147 extern void OLEClipbrd_Initialize(void);
148
149 /******************************************************************************
150 * These are the prototypes of the utility methods used for OLE Drag n Drop
151 */
152 static void OLEDD_Initialize(void);
153 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
154 static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo);
155 static DWORD OLEDD_GetButtonState(void);
156
157 /******************************************************************************
158 * OleBuildVersion [OLE32.@]
159 */
OleBuildVersion(void)160 DWORD WINAPI OleBuildVersion(void)
161 {
162 TRACE("Returning version %d, build %d.\n", rmm, rup);
163 return (rmm<<16)+rup;
164 }
165
166 /***********************************************************************
167 * OleInitialize (OLE32.@)
168 */
OleInitialize(LPVOID reserved)169 HRESULT WINAPI DECLSPEC_HOTPATCH OleInitialize(LPVOID reserved)
170 {
171 HRESULT hr;
172
173 TRACE("(%p)\n", reserved);
174
175 /*
176 * The first duty of the OleInitialize is to initialize the COM libraries.
177 */
178 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
179
180 /*
181 * If the CoInitializeEx call failed, the OLE libraries can't be
182 * initialized.
183 */
184 if (FAILED(hr))
185 return hr;
186
187 if (!COM_CurrentInfo()->ole_inits)
188 hr = S_OK;
189 else
190 hr = S_FALSE;
191
192 /*
193 * Then, it has to initialize the OLE specific modules.
194 * This includes:
195 * Clipboard
196 * Drag and Drop
197 * Object linking and Embedding
198 * In-place activation
199 */
200 if (!COM_CurrentInfo()->ole_inits++ &&
201 InterlockedIncrement(&OLE_moduleLockCount) == 1)
202 {
203 /*
204 * Initialize the libraries.
205 */
206 TRACE("() - Initializing the OLE libraries\n");
207
208 /*
209 * OLE Clipboard
210 */
211 OLEClipbrd_Initialize();
212
213 /*
214 * Drag and Drop
215 */
216 OLEDD_Initialize();
217
218 /*
219 * OLE shared menu
220 */
221 OLEMenu_Initialize();
222 }
223
224 return hr;
225 }
226
227 /******************************************************************************
228 * OleUninitialize [OLE32.@]
229 */
OleUninitialize(void)230 void WINAPI DECLSPEC_HOTPATCH OleUninitialize(void)
231 {
232 TRACE("()\n");
233
234 if (COM_CurrentInfo()->ole_inits == 0)
235 {
236 WARN("ole_inits is already 0\n");
237 return ;
238 }
239 /*
240 * If we hit the bottom of the lock stack, free the libraries.
241 */
242 if (!--COM_CurrentInfo()->ole_inits && !InterlockedDecrement(&OLE_moduleLockCount))
243 {
244 /*
245 * Actually free the libraries.
246 */
247 TRACE("() - Freeing the last reference count\n");
248
249 /*
250 * OLE Clipboard
251 */
252 OLEClipbrd_UnInitialize();
253
254 /*
255 * OLE shared menu
256 */
257 OLEMenu_UnInitialize();
258 }
259
260 /*
261 * Then, uninitialize the COM libraries.
262 */
263 CoUninitialize();
264 }
265
266 /******************************************************************************
267 * OleInitializeWOW [OLE32.@]
268 */
OleInitializeWOW(DWORD x,DWORD y)269 HRESULT WINAPI OleInitializeWOW(DWORD x, DWORD y) {
270 FIXME("(0x%08x, 0x%08x),stub!\n",x, y);
271 return 0;
272 }
273
274 /*************************************************************
275 * get_droptarget_handle
276 *
277 * Retrieve a handle to the map containing the marshalled IDropTarget.
278 * This handle belongs to the process that called RegisterDragDrop.
279 * See get_droptarget_local_handle().
280 */
get_droptarget_handle(HWND hwnd)281 static inline HANDLE get_droptarget_handle(HWND hwnd)
282 {
283 return GetPropW(hwnd, prop_marshalleddroptarget);
284 }
285
286 /*************************************************************
287 * is_droptarget
288 *
289 * Is the window a droptarget.
290 */
is_droptarget(HWND hwnd)291 static inline BOOL is_droptarget(HWND hwnd)
292 {
293 return get_droptarget_handle(hwnd) != 0;
294 }
295
296 #ifdef __REACTOS__
is_acceptfiles(HWND hwnd)297 static inline BOOL is_acceptfiles(HWND hwnd)
298 {
299 return !!(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_ACCEPTFILES);
300 }
301 #endif
302 /*************************************************************
303 * get_droptarget_local_handle
304 *
305 * Retrieve a handle to the map containing the marshalled IDropTarget.
306 * The handle should be closed when finished with.
307 */
get_droptarget_local_handle(HWND hwnd)308 static HANDLE get_droptarget_local_handle(HWND hwnd)
309 {
310 HANDLE handle, local_handle = 0;
311
312 handle = get_droptarget_handle(hwnd);
313
314 if(handle)
315 {
316 DWORD pid;
317 HANDLE process;
318
319 GetWindowThreadProcessId(hwnd, &pid);
320 process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid);
321 if(process)
322 {
323 DuplicateHandle(process, handle, GetCurrentProcess(), &local_handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
324 CloseHandle(process);
325 }
326 }
327 return local_handle;
328 }
329
330 /***********************************************************************
331 * create_map_from_stream
332 *
333 * Helper for RegisterDragDrop. Creates a file mapping object
334 * with the contents of the provided stream. The stream must
335 * be a global memory backed stream.
336 */
create_map_from_stream(IStream * stream,HANDLE * map)337 static HRESULT create_map_from_stream(IStream *stream, HANDLE *map)
338 {
339 HGLOBAL hmem;
340 DWORD size;
341 HRESULT hr;
342 void *data;
343
344 hr = GetHGlobalFromStream(stream, &hmem);
345 if(FAILED(hr)) return hr;
346
347 size = GlobalSize(hmem);
348 *map = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, NULL);
349 if(!*map) return E_OUTOFMEMORY;
350
351 data = MapViewOfFile(*map, FILE_MAP_WRITE, 0, 0, size);
352 memcpy(data, GlobalLock(hmem), size);
353 GlobalUnlock(hmem);
354 UnmapViewOfFile(data);
355 return S_OK;
356 }
357
358 /***********************************************************************
359 * create_stream_from_map
360 *
361 * Creates a stream from the provided map.
362 */
create_stream_from_map(HANDLE map,IStream ** stream)363 static HRESULT create_stream_from_map(HANDLE map, IStream **stream)
364 {
365 HRESULT hr = E_OUTOFMEMORY;
366 HGLOBAL hmem;
367 void *data;
368 MEMORY_BASIC_INFORMATION info;
369
370 data = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
371 if(!data) return hr;
372
373 VirtualQuery(data, &info, sizeof(info));
374 TRACE("size %d\n", (int)info.RegionSize);
375
376 hmem = GlobalAlloc(GMEM_MOVEABLE, info.RegionSize);
377 if(hmem)
378 {
379 memcpy(GlobalLock(hmem), data, info.RegionSize);
380 GlobalUnlock(hmem);
381 hr = CreateStreamOnHGlobal(hmem, TRUE, stream);
382 }
383 UnmapViewOfFile(data);
384 return hr;
385 }
386
387 /* This is to work around apps which break COM rules by not implementing
388 * IDropTarget::QueryInterface(). Windows doesn't expose this because it
389 * doesn't call CoMarshallInterface() in RegisterDragDrop().
390 * The wrapper is only used internally, and only exists for the life of
391 * the marshal. We don't want to hold a ref on the app provided target
392 * as some apps destroy this prior to CoUninitialize without calling
393 * RevokeDragDrop. The only (long-term) ref is held by the window prop. */
394 typedef struct {
395 IDropTarget IDropTarget_iface;
396 HWND hwnd;
397 LONG refs;
398 } DropTargetWrapper;
399
impl_from_IDropTarget(IDropTarget * iface)400 static inline DropTargetWrapper* impl_from_IDropTarget(IDropTarget* iface)
401 {
402 return CONTAINING_RECORD(iface, DropTargetWrapper, IDropTarget_iface);
403 }
404
DropTargetWrapper_QueryInterface(IDropTarget * iface,REFIID riid,void ** ppvObject)405 static HRESULT WINAPI DropTargetWrapper_QueryInterface(IDropTarget* iface,
406 REFIID riid,
407 void** ppvObject)
408 {
409 DropTargetWrapper* This = impl_from_IDropTarget(iface);
410 if (IsEqualIID(riid, &IID_IUnknown) ||
411 IsEqualIID(riid, &IID_IDropTarget))
412 {
413 IDropTarget_AddRef(&This->IDropTarget_iface);
414 *ppvObject = &This->IDropTarget_iface;
415 return S_OK;
416 }
417 *ppvObject = NULL;
418 return E_NOINTERFACE;
419 }
420
DropTargetWrapper_AddRef(IDropTarget * iface)421 static ULONG WINAPI DropTargetWrapper_AddRef(IDropTarget* iface)
422 {
423 DropTargetWrapper* This = impl_from_IDropTarget(iface);
424 return InterlockedIncrement(&This->refs);
425 }
426
DropTargetWrapper_Release(IDropTarget * iface)427 static ULONG WINAPI DropTargetWrapper_Release(IDropTarget* iface)
428 {
429 DropTargetWrapper* This = impl_from_IDropTarget(iface);
430 ULONG refs = InterlockedDecrement(&This->refs);
431 if (!refs) HeapFree(GetProcessHeap(), 0, This);
432 return refs;
433 }
434
get_target_from_wrapper(IDropTarget * wrapper,IDropTarget ** target)435 static inline HRESULT get_target_from_wrapper( IDropTarget *wrapper, IDropTarget **target )
436 {
437 DropTargetWrapper* This = impl_from_IDropTarget( wrapper );
438 *target = GetPropW( This->hwnd, prop_oledroptarget );
439 if (!*target) return DRAGDROP_E_NOTREGISTERED;
440 IDropTarget_AddRef( *target );
441 return S_OK;
442 }
443
DropTargetWrapper_DragEnter(IDropTarget * iface,IDataObject * pDataObj,DWORD grfKeyState,POINTL pt,DWORD * pdwEffect)444 static HRESULT WINAPI DropTargetWrapper_DragEnter(IDropTarget* iface,
445 IDataObject* pDataObj,
446 DWORD grfKeyState,
447 POINTL pt,
448 DWORD* pdwEffect)
449 {
450 IDropTarget *target;
451 HRESULT r = get_target_from_wrapper( iface, &target );
452
453 if (SUCCEEDED( r ))
454 {
455 r = IDropTarget_DragEnter( target, pDataObj, grfKeyState, pt, pdwEffect );
456 IDropTarget_Release( target );
457 }
458 return r;
459 }
460
DropTargetWrapper_DragOver(IDropTarget * iface,DWORD grfKeyState,POINTL pt,DWORD * pdwEffect)461 static HRESULT WINAPI DropTargetWrapper_DragOver(IDropTarget* iface,
462 DWORD grfKeyState,
463 POINTL pt,
464 DWORD* pdwEffect)
465 {
466 IDropTarget *target;
467 HRESULT r = get_target_from_wrapper( iface, &target );
468
469 if (SUCCEEDED( r ))
470 {
471 r = IDropTarget_DragOver( target, grfKeyState, pt, pdwEffect );
472 IDropTarget_Release( target );
473 }
474 return r;
475 }
476
DropTargetWrapper_DragLeave(IDropTarget * iface)477 static HRESULT WINAPI DropTargetWrapper_DragLeave(IDropTarget* iface)
478 {
479 IDropTarget *target;
480 HRESULT r = get_target_from_wrapper( iface, &target );
481
482 if (SUCCEEDED( r ))
483 {
484 r = IDropTarget_DragLeave( target );
485 IDropTarget_Release( target );
486 }
487 return r;
488 }
489
DropTargetWrapper_Drop(IDropTarget * iface,IDataObject * pDataObj,DWORD grfKeyState,POINTL pt,DWORD * pdwEffect)490 static HRESULT WINAPI DropTargetWrapper_Drop(IDropTarget* iface,
491 IDataObject* pDataObj,
492 DWORD grfKeyState,
493 POINTL pt,
494 DWORD* pdwEffect)
495 {
496 IDropTarget *target;
497 HRESULT r = get_target_from_wrapper( iface, &target );
498
499 if (SUCCEEDED( r ))
500 {
501 r = IDropTarget_Drop( target, pDataObj, grfKeyState, pt, pdwEffect );
502 IDropTarget_Release( target );
503 }
504 return r;
505 }
506
507 static const IDropTargetVtbl DropTargetWrapperVTbl =
508 {
509 DropTargetWrapper_QueryInterface,
510 DropTargetWrapper_AddRef,
511 DropTargetWrapper_Release,
512 DropTargetWrapper_DragEnter,
513 DropTargetWrapper_DragOver,
514 DropTargetWrapper_DragLeave,
515 DropTargetWrapper_Drop
516 };
517
WrapDropTarget(HWND hwnd)518 static IDropTarget* WrapDropTarget( HWND hwnd )
519 {
520 DropTargetWrapper* This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
521
522 if (This)
523 {
524 This->IDropTarget_iface.lpVtbl = &DropTargetWrapperVTbl;
525 This->hwnd = hwnd;
526 This->refs = 1;
527 }
528 return &This->IDropTarget_iface;
529 }
530
531 /***********************************************************************
532 * get_droptarget_pointer
533 *
534 * Retrieves the marshalled IDropTarget from the window.
535 */
get_droptarget_pointer(HWND hwnd)536 static IDropTarget* get_droptarget_pointer(HWND hwnd)
537 {
538 IDropTarget *droptarget = NULL;
539 HANDLE map;
540 IStream *stream;
541
542 map = get_droptarget_local_handle(hwnd);
543 if(!map) return NULL;
544
545 if(SUCCEEDED(create_stream_from_map(map, &stream)))
546 {
547 CoUnmarshalInterface(stream, &IID_IDropTarget, (void**)&droptarget);
548 IStream_Release(stream);
549 }
550 CloseHandle(map);
551 return droptarget;
552 }
553
554 /***********************************************************************
555 * RegisterDragDrop (OLE32.@)
556 */
RegisterDragDrop(HWND hwnd,LPDROPTARGET pDropTarget)557 HRESULT WINAPI RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget)
558 {
559 DWORD pid = 0;
560 HRESULT hr;
561 IStream *stream;
562 HANDLE map;
563 IDropTarget *wrapper;
564
565 TRACE("(%p,%p)\n", hwnd, pDropTarget);
566
567 if (!COM_CurrentApt())
568 {
569 ERR("COM not initialized\n");
570 return E_OUTOFMEMORY;
571 }
572
573 if (!pDropTarget)
574 return E_INVALIDARG;
575
576 if (!IsWindow(hwnd))
577 {
578 ERR("invalid hwnd %p\n", hwnd);
579 return DRAGDROP_E_INVALIDHWND;
580 }
581
582 /* block register for other processes windows */
583 GetWindowThreadProcessId(hwnd, &pid);
584 if (pid != GetCurrentProcessId())
585 {
586 FIXME("register for another process windows is disabled\n");
587 return DRAGDROP_E_INVALIDHWND;
588 }
589
590 /* check if the window is already registered */
591 if (is_droptarget(hwnd))
592 return DRAGDROP_E_ALREADYREGISTERED;
593
594 /*
595 * Marshal the drop target pointer into a shared memory map and
596 * store the map's handle in a Wine specific window prop. We also
597 * store the drop target pointer itself in the
598 * "OleDropTargetInterface" prop for compatibility with Windows.
599 */
600
601 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
602 if(FAILED(hr)) return hr;
603
604 /* IDropTarget::QueryInterface() shouldn't be called, some (broken) apps depend on this. */
605 wrapper = WrapDropTarget( hwnd );
606 if(!wrapper)
607 {
608 IStream_Release(stream);
609 return E_OUTOFMEMORY;
610 }
611 hr = CoMarshalInterface(stream, &IID_IDropTarget, (IUnknown*)wrapper, MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
612 IDropTarget_Release(wrapper);
613
614 if(SUCCEEDED(hr))
615 {
616 hr = create_map_from_stream(stream, &map);
617 if(SUCCEEDED(hr))
618 {
619 IDropTarget_AddRef(pDropTarget);
620 SetPropW(hwnd, prop_oledroptarget, pDropTarget);
621 SetPropW(hwnd, prop_marshalleddroptarget, map);
622 }
623 else
624 {
625 LARGE_INTEGER zero;
626 zero.QuadPart = 0;
627 IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
628 CoReleaseMarshalData(stream);
629 }
630 }
631 IStream_Release(stream);
632
633 return hr;
634 }
635
636 /***********************************************************************
637 * RevokeDragDrop (OLE32.@)
638 */
RevokeDragDrop(HWND hwnd)639 HRESULT WINAPI RevokeDragDrop(HWND hwnd)
640 {
641 HANDLE map;
642 IStream *stream;
643 IDropTarget *drop_target;
644 HRESULT hr;
645
646 TRACE("(%p)\n", hwnd);
647
648 if (!IsWindow(hwnd))
649 {
650 ERR("invalid hwnd %p\n", hwnd);
651 return DRAGDROP_E_INVALIDHWND;
652 }
653
654 /* no registration data */
655 if (!(map = get_droptarget_handle(hwnd)))
656 return DRAGDROP_E_NOTREGISTERED;
657
658 drop_target = GetPropW(hwnd, prop_oledroptarget);
659 if(drop_target) IDropTarget_Release(drop_target);
660
661 RemovePropW(hwnd, prop_oledroptarget);
662 RemovePropW(hwnd, prop_marshalleddroptarget);
663
664 hr = create_stream_from_map(map, &stream);
665 if(SUCCEEDED(hr))
666 {
667 CoReleaseMarshalData(stream);
668 IStream_Release(stream);
669 }
670 CloseHandle(map);
671
672 return hr;
673 }
674
675 /***********************************************************************
676 * OleRegGetUserType (OLE32.@)
677 */
OleRegGetUserType(REFCLSID clsid,DWORD form,LPOLESTR * usertype)678 HRESULT WINAPI OleRegGetUserType(REFCLSID clsid, DWORD form, LPOLESTR *usertype)
679 {
680 static const WCHAR auxusertypeW[] = {'A','u','x','U','s','e','r','T','y','p','e','\\','%','d',0};
681 DWORD valuetype, valuelen;
682 WCHAR auxkeynameW[16];
683 HKEY usertypekey;
684 HRESULT hres;
685 LONG ret;
686
687 TRACE("(%s, %u, %p)\n", debugstr_guid(clsid), form, usertype);
688
689 if (!usertype)
690 return E_INVALIDARG;
691
692 *usertype = NULL;
693
694 /* Return immediately if it's not registered. */
695 hres = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &usertypekey);
696 if (FAILED(hres))
697 return hres;
698
699 valuelen = 0;
700
701 /* Try additional types if requested. If they don't exist fall back to USERCLASSTYPE_FULL. */
702 if (form != USERCLASSTYPE_FULL)
703 {
704 HKEY auxkey;
705
706 swprintf(auxkeynameW, auxusertypeW, form);
707 if (COM_OpenKeyForCLSID(clsid, auxkeynameW, KEY_READ, &auxkey) == S_OK)
708 {
709 if (!RegQueryValueExW(auxkey, emptyW, NULL, &valuetype, NULL, &valuelen) && valuelen)
710 {
711 RegCloseKey(usertypekey);
712 usertypekey = auxkey;
713 }
714 else
715 RegCloseKey(auxkey);
716 }
717 }
718
719 valuelen = 0;
720 if (RegQueryValueExW(usertypekey, emptyW, NULL, &valuetype, NULL, &valuelen))
721 {
722 RegCloseKey(usertypekey);
723 return REGDB_E_READREGDB;
724 }
725
726 *usertype = CoTaskMemAlloc(valuelen);
727 if (!*usertype)
728 {
729 RegCloseKey(usertypekey);
730 return E_OUTOFMEMORY;
731 }
732
733 ret = RegQueryValueExW(usertypekey,
734 emptyW,
735 NULL,
736 &valuetype,
737 (LPBYTE)*usertype,
738 &valuelen);
739 RegCloseKey(usertypekey);
740 if (ret != ERROR_SUCCESS)
741 {
742 CoTaskMemFree(*usertype);
743 *usertype = NULL;
744 return REGDB_E_READREGDB;
745 }
746
747 return S_OK;
748 }
749
750 /***********************************************************************
751 * DoDragDrop [OLE32.@]
752 */
DoDragDrop(IDataObject * pDataObject,IDropSource * pDropSource,DWORD dwOKEffect,DWORD * pdwEffect)753 HRESULT WINAPI DoDragDrop (
754 IDataObject *pDataObject, /* [in] ptr to the data obj */
755 IDropSource* pDropSource, /* [in] ptr to the source obj */
756 DWORD dwOKEffect, /* [in] effects allowed by the source */
757 DWORD *pdwEffect) /* [out] ptr to effects of the source */
758 {
759 static const WCHAR trackerW[] = {'T','r','a','c','k','e','r','W','i','n','d','o','w',0};
760 TrackerWindowInfo trackerInfo;
761 HWND hwndTrackWindow;
762 MSG msg;
763
764 TRACE("(%p, %p, %08x, %p)\n", pDataObject, pDropSource, dwOKEffect, pdwEffect);
765
766 if (!pDataObject || !pDropSource || !pdwEffect)
767 return E_INVALIDARG;
768
769 /*
770 * Setup the drag n drop tracking window.
771 */
772
773 trackerInfo.dataObject = pDataObject;
774 trackerInfo.dropSource = pDropSource;
775 trackerInfo.dwOKEffect = dwOKEffect;
776 trackerInfo.pdwEffect = pdwEffect;
777 trackerInfo.trackingDone = FALSE;
778 trackerInfo.escPressed = FALSE;
779 trackerInfo.curTargetHWND = 0;
780 trackerInfo.curDragTarget = 0;
781 #ifdef __REACTOS__
782 trackerInfo.accepterHWND = NULL;
783 #endif
784
785 hwndTrackWindow = CreateWindowW(OLEDD_DRAGTRACKERCLASS, trackerW,
786 WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
787 CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0,
788 &trackerInfo);
789
790 if (hwndTrackWindow)
791 {
792 /*
793 * Capture the mouse input
794 */
795 SetCapture(hwndTrackWindow);
796
797 msg.message = 0;
798
799 /*
800 * Pump messages. All mouse input should go to the capture window.
801 */
802 while (!trackerInfo.trackingDone && GetMessageW(&msg, 0, 0, 0) )
803 {
804 trackerInfo.curMousePos.x = msg.pt.x;
805 trackerInfo.curMousePos.y = msg.pt.y;
806 trackerInfo.dwKeyState = OLEDD_GetButtonState();
807
808 if ( (msg.message >= WM_KEYFIRST) &&
809 (msg.message <= WM_KEYLAST) )
810 {
811 /*
812 * When keyboard messages are sent to windows on this thread, we
813 * want to ignore notify the drop source that the state changed.
814 * in the case of the Escape key, we also notify the drop source
815 * we give it a special meaning.
816 */
817 if ( (msg.message==WM_KEYDOWN) &&
818 (msg.wParam==VK_ESCAPE) )
819 {
820 trackerInfo.escPressed = TRUE;
821 }
822
823 /*
824 * Notify the drop source.
825 */
826 OLEDD_TrackStateChange(&trackerInfo);
827 }
828 else
829 {
830 /*
831 * Dispatch the messages only when it's not a keyboard message.
832 */
833 DispatchMessageW(&msg);
834 }
835 }
836
837 /* re-post the quit message to outer message loop */
838 if (msg.message == WM_QUIT)
839 PostQuitMessage(msg.wParam);
840 /*
841 * Destroy the temporary window.
842 */
843 DestroyWindow(hwndTrackWindow);
844
845 return trackerInfo.returnValue;
846 }
847
848 return E_FAIL;
849 }
850
851 /***********************************************************************
852 * OleQueryLinkFromData [OLE32.@]
853 */
OleQueryLinkFromData(IDataObject * pSrcDataObject)854 HRESULT WINAPI OleQueryLinkFromData(
855 IDataObject* pSrcDataObject)
856 {
857 FIXME("(%p),stub!\n", pSrcDataObject);
858 return S_FALSE;
859 }
860
861 /***********************************************************************
862 * OleRegGetMiscStatus [OLE32.@]
863 */
OleRegGetMiscStatus(REFCLSID clsid,DWORD dwAspect,DWORD * pdwStatus)864 HRESULT WINAPI OleRegGetMiscStatus(
865 REFCLSID clsid,
866 DWORD dwAspect,
867 DWORD* pdwStatus)
868 {
869 static const WCHAR miscstatusW[] = {'M','i','s','c','S','t','a','t','u','s',0};
870 static const WCHAR dfmtW[] = {'%','d',0};
871 WCHAR keyName[16];
872 HKEY miscStatusKey;
873 HKEY aspectKey;
874 LONG result;
875 HRESULT hr;
876
877 TRACE("(%s, %d, %p)\n", debugstr_guid(clsid), dwAspect, pdwStatus);
878
879 if (!pdwStatus) return E_INVALIDARG;
880
881 *pdwStatus = 0;
882
883 if (actctx_get_miscstatus(clsid, dwAspect, pdwStatus)) return S_OK;
884
885 hr = COM_OpenKeyForCLSID(clsid, miscstatusW, KEY_READ, &miscStatusKey);
886 if (FAILED(hr))
887 /* missing key is not a failure */
888 return hr == REGDB_E_KEYMISSING ? S_OK : hr;
889
890 OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
891
892 /*
893 * Open the key specific to the requested aspect.
894 */
895 swprintf(keyName, dfmtW, dwAspect);
896
897 result = open_classes_key(miscStatusKey, keyName, KEY_READ, &aspectKey);
898 if (result == ERROR_SUCCESS)
899 {
900 OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
901 RegCloseKey(aspectKey);
902 }
903
904 RegCloseKey(miscStatusKey);
905 return S_OK;
906 }
907
908 static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum);
909
910 typedef struct
911 {
912 IEnumOLEVERB IEnumOLEVERB_iface;
913 LONG ref;
914
915 HKEY hkeyVerb;
916 ULONG index;
917 } EnumOLEVERB;
918
impl_from_IEnumOLEVERB(IEnumOLEVERB * iface)919 static inline EnumOLEVERB *impl_from_IEnumOLEVERB(IEnumOLEVERB *iface)
920 {
921 return CONTAINING_RECORD(iface, EnumOLEVERB, IEnumOLEVERB_iface);
922 }
923
EnumOLEVERB_QueryInterface(IEnumOLEVERB * iface,REFIID riid,void ** ppv)924 static HRESULT WINAPI EnumOLEVERB_QueryInterface(
925 IEnumOLEVERB *iface, REFIID riid, void **ppv)
926 {
927 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
928 if (IsEqualIID(riid, &IID_IUnknown) ||
929 IsEqualIID(riid, &IID_IEnumOLEVERB))
930 {
931 IEnumOLEVERB_AddRef(iface);
932 *ppv = iface;
933 return S_OK;
934 }
935 return E_NOINTERFACE;
936 }
937
EnumOLEVERB_AddRef(IEnumOLEVERB * iface)938 static ULONG WINAPI EnumOLEVERB_AddRef(
939 IEnumOLEVERB *iface)
940 {
941 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
942 TRACE("()\n");
943 return InterlockedIncrement(&This->ref);
944 }
945
EnumOLEVERB_Release(IEnumOLEVERB * iface)946 static ULONG WINAPI EnumOLEVERB_Release(
947 IEnumOLEVERB *iface)
948 {
949 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
950 LONG refs = InterlockedDecrement(&This->ref);
951 TRACE("()\n");
952 if (!refs)
953 {
954 RegCloseKey(This->hkeyVerb);
955 HeapFree(GetProcessHeap(), 0, This);
956 }
957 return refs;
958 }
959
EnumOLEVERB_Next(IEnumOLEVERB * iface,ULONG celt,LPOLEVERB rgelt,ULONG * pceltFetched)960 static HRESULT WINAPI EnumOLEVERB_Next(
961 IEnumOLEVERB *iface, ULONG celt, LPOLEVERB rgelt,
962 ULONG *pceltFetched)
963 {
964 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
965 HRESULT hr = S_OK;
966
967 TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched);
968
969 if (pceltFetched)
970 *pceltFetched = 0;
971
972 for (; celt; celt--, rgelt++)
973 {
974 WCHAR wszSubKey[20];
975 LONG cbData;
976 LPWSTR pwszOLEVERB;
977 LPWSTR pwszMenuFlags;
978 LPWSTR pwszAttribs;
979 LONG res = RegEnumKeyW(This->hkeyVerb, This->index, wszSubKey, ARRAY_SIZE(wszSubKey));
980 if (res == ERROR_NO_MORE_ITEMS)
981 {
982 hr = S_FALSE;
983 break;
984 }
985 else if (res != ERROR_SUCCESS)
986 {
987 ERR("RegEnumKeyW failed with error %d\n", res);
988 hr = REGDB_E_READREGDB;
989 break;
990 }
991 res = RegQueryValueW(This->hkeyVerb, wszSubKey, NULL, &cbData);
992 if (res != ERROR_SUCCESS)
993 {
994 ERR("RegQueryValueW failed with error %d\n", res);
995 hr = REGDB_E_READREGDB;
996 break;
997 }
998 pwszOLEVERB = CoTaskMemAlloc(cbData);
999 if (!pwszOLEVERB)
1000 {
1001 hr = E_OUTOFMEMORY;
1002 break;
1003 }
1004 res = RegQueryValueW(This->hkeyVerb, wszSubKey, pwszOLEVERB, &cbData);
1005 if (res != ERROR_SUCCESS)
1006 {
1007 ERR("RegQueryValueW failed with error %d\n", res);
1008 hr = REGDB_E_READREGDB;
1009 CoTaskMemFree(pwszOLEVERB);
1010 break;
1011 }
1012
1013 TRACE("verb string: %s\n", debugstr_w(pwszOLEVERB));
1014 pwszMenuFlags = wcschr(pwszOLEVERB, ',');
1015 if (!pwszMenuFlags)
1016 {
1017 hr = OLEOBJ_E_INVALIDVERB;
1018 CoTaskMemFree(pwszOLEVERB);
1019 break;
1020 }
1021 /* nul terminate the name string and advance to first character */
1022 *pwszMenuFlags = '\0';
1023 pwszMenuFlags++;
1024 pwszAttribs = wcschr(pwszMenuFlags, ',');
1025 if (!pwszAttribs)
1026 {
1027 hr = OLEOBJ_E_INVALIDVERB;
1028 CoTaskMemFree(pwszOLEVERB);
1029 break;
1030 }
1031 /* nul terminate the menu string and advance to first character */
1032 *pwszAttribs = '\0';
1033 pwszAttribs++;
1034
1035 /* fill out structure for this verb */
1036 rgelt->lVerb = wcstol(wszSubKey, NULL, 10);
1037 rgelt->lpszVerbName = pwszOLEVERB; /* user should free */
1038 rgelt->fuFlags = wcstol(pwszMenuFlags, NULL, 10);
1039 rgelt->grfAttribs = wcstol(pwszAttribs, NULL, 10);
1040
1041 if (pceltFetched)
1042 (*pceltFetched)++;
1043 This->index++;
1044 }
1045 return hr;
1046 }
1047
EnumOLEVERB_Skip(IEnumOLEVERB * iface,ULONG celt)1048 static HRESULT WINAPI EnumOLEVERB_Skip(
1049 IEnumOLEVERB *iface, ULONG celt)
1050 {
1051 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
1052
1053 TRACE("(%d)\n", celt);
1054
1055 This->index += celt;
1056 return S_OK;
1057 }
1058
EnumOLEVERB_Reset(IEnumOLEVERB * iface)1059 static HRESULT WINAPI EnumOLEVERB_Reset(
1060 IEnumOLEVERB *iface)
1061 {
1062 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
1063
1064 TRACE("()\n");
1065
1066 This->index = 0;
1067 return S_OK;
1068 }
1069
EnumOLEVERB_Clone(IEnumOLEVERB * iface,IEnumOLEVERB ** ppenum)1070 static HRESULT WINAPI EnumOLEVERB_Clone(
1071 IEnumOLEVERB *iface,
1072 IEnumOLEVERB **ppenum)
1073 {
1074 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
1075 HKEY hkeyVerb;
1076 TRACE("(%p)\n", ppenum);
1077 if (!DuplicateHandle(GetCurrentProcess(), This->hkeyVerb, GetCurrentProcess(), (HANDLE *)&hkeyVerb, 0, FALSE, DUPLICATE_SAME_ACCESS))
1078 return HRESULT_FROM_WIN32(GetLastError());
1079 return EnumOLEVERB_Construct(hkeyVerb, This->index, ppenum);
1080 }
1081
1082 static const IEnumOLEVERBVtbl EnumOLEVERB_VTable =
1083 {
1084 EnumOLEVERB_QueryInterface,
1085 EnumOLEVERB_AddRef,
1086 EnumOLEVERB_Release,
1087 EnumOLEVERB_Next,
1088 EnumOLEVERB_Skip,
1089 EnumOLEVERB_Reset,
1090 EnumOLEVERB_Clone
1091 };
1092
EnumOLEVERB_Construct(HKEY hkeyVerb,ULONG index,IEnumOLEVERB ** ppenum)1093 static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum)
1094 {
1095 EnumOLEVERB *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1096 if (!This)
1097 {
1098 RegCloseKey(hkeyVerb);
1099 return E_OUTOFMEMORY;
1100 }
1101 This->IEnumOLEVERB_iface.lpVtbl = &EnumOLEVERB_VTable;
1102 This->ref = 1;
1103 This->index = index;
1104 This->hkeyVerb = hkeyVerb;
1105 *ppenum = &This->IEnumOLEVERB_iface;
1106 return S_OK;
1107 }
1108
1109 /***********************************************************************
1110 * OleRegEnumVerbs [OLE32.@]
1111 *
1112 * Enumerates verbs associated with a class stored in the registry.
1113 *
1114 * PARAMS
1115 * clsid [I] Class ID to enumerate the verbs for.
1116 * ppenum [O] Enumerator.
1117 *
1118 * RETURNS
1119 * S_OK: Success.
1120 * REGDB_E_CLASSNOTREG: The specified class does not have a key in the registry.
1121 * REGDB_E_READREGDB: The class key could not be opened for some other reason.
1122 * OLE_E_REGDB_KEY: The Verb subkey for the class is not present.
1123 * OLEOBJ_E_NOVERBS: The Verb subkey for the class is empty.
1124 */
OleRegEnumVerbs(REFCLSID clsid,LPENUMOLEVERB * ppenum)1125 HRESULT WINAPI OleRegEnumVerbs (REFCLSID clsid, LPENUMOLEVERB* ppenum)
1126 {
1127 LONG res;
1128 HKEY hkeyVerb;
1129 DWORD dwSubKeys;
1130 static const WCHAR wszVerb[] = {'V','e','r','b',0};
1131
1132 TRACE("(%s, %p)\n", debugstr_guid(clsid), ppenum);
1133
1134 res = COM_OpenKeyForCLSID(clsid, wszVerb, KEY_READ, &hkeyVerb);
1135 if (FAILED(res))
1136 {
1137 if (res == REGDB_E_CLASSNOTREG)
1138 ERR("CLSID %s not registered\n", debugstr_guid(clsid));
1139 else if (res == REGDB_E_KEYMISSING)
1140 ERR("no Verbs key for class %s\n", debugstr_guid(clsid));
1141 else
1142 ERR("failed to open Verbs key for CLSID %s with error %d\n",
1143 debugstr_guid(clsid), res);
1144 return res;
1145 }
1146
1147 res = RegQueryInfoKeyW(hkeyVerb, NULL, NULL, NULL, &dwSubKeys, NULL,
1148 NULL, NULL, NULL, NULL, NULL, NULL);
1149 if (res != ERROR_SUCCESS)
1150 {
1151 ERR("failed to get subkey count with error %d\n", GetLastError());
1152 return REGDB_E_READREGDB;
1153 }
1154
1155 if (!dwSubKeys)
1156 {
1157 WARN("class %s has no verbs\n", debugstr_guid(clsid));
1158 RegCloseKey(hkeyVerb);
1159 return OLEOBJ_E_NOVERBS;
1160 }
1161
1162 return EnumOLEVERB_Construct(hkeyVerb, 0, ppenum);
1163 }
1164
1165 /******************************************************************************
1166 * OleSetContainedObject [OLE32.@]
1167 */
OleSetContainedObject(LPUNKNOWN pUnknown,BOOL fContained)1168 HRESULT WINAPI OleSetContainedObject(
1169 LPUNKNOWN pUnknown,
1170 BOOL fContained)
1171 {
1172 IRunnableObject* runnable = NULL;
1173 HRESULT hres;
1174
1175 TRACE("(%p,%x)\n", pUnknown, fContained);
1176
1177 hres = IUnknown_QueryInterface(pUnknown,
1178 &IID_IRunnableObject,
1179 (void**)&runnable);
1180
1181 if (SUCCEEDED(hres))
1182 {
1183 hres = IRunnableObject_SetContainedObject(runnable, fContained);
1184
1185 IRunnableObject_Release(runnable);
1186
1187 return hres;
1188 }
1189
1190 return S_OK;
1191 }
1192
1193 /******************************************************************************
1194 * OleRun [OLE32.@]
1195 *
1196 * Set the OLE object to the running state.
1197 *
1198 * PARAMS
1199 * pUnknown [I] OLE object to run.
1200 *
1201 * RETURNS
1202 * Success: S_OK.
1203 * Failure: Any HRESULT code.
1204 */
OleRun(LPUNKNOWN pUnknown)1205 HRESULT WINAPI DECLSPEC_HOTPATCH OleRun(LPUNKNOWN pUnknown)
1206 {
1207 IRunnableObject *runable;
1208 HRESULT hres;
1209
1210 TRACE("(%p)\n", pUnknown);
1211
1212 hres = IUnknown_QueryInterface(pUnknown, &IID_IRunnableObject, (void**)&runable);
1213 if (FAILED(hres))
1214 return S_OK; /* Appears to return no error. */
1215
1216 hres = IRunnableObject_Run(runable, NULL);
1217 IRunnableObject_Release(runable);
1218 return hres;
1219 }
1220
1221 /******************************************************************************
1222 * OleLoad [OLE32.@]
1223 */
OleLoad(LPSTORAGE pStg,REFIID riid,LPOLECLIENTSITE pClientSite,LPVOID * ppvObj)1224 HRESULT WINAPI OleLoad(
1225 LPSTORAGE pStg,
1226 REFIID riid,
1227 LPOLECLIENTSITE pClientSite,
1228 LPVOID* ppvObj)
1229 {
1230 IPersistStorage* persistStorage = NULL;
1231 IUnknown* pUnk;
1232 IOleObject* pOleObject = NULL;
1233 STATSTG storageInfo;
1234 HRESULT hres;
1235
1236 TRACE("(%p, %s, %p, %p)\n", pStg, debugstr_guid(riid), pClientSite, ppvObj);
1237
1238 *ppvObj = NULL;
1239
1240 /*
1241 * TODO, Conversion ... OleDoAutoConvert
1242 */
1243
1244 /*
1245 * Get the class ID for the object.
1246 */
1247 hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
1248 if (FAILED(hres))
1249 return hres;
1250
1251 /*
1252 * Now, try and create the handler for the object
1253 */
1254 hres = CoCreateInstance(&storageInfo.clsid,
1255 NULL,
1256 CLSCTX_INPROC_HANDLER|CLSCTX_INPROC_SERVER,
1257 riid,
1258 (void**)&pUnk);
1259
1260 /*
1261 * If that fails, as it will most times, load the default
1262 * OLE handler.
1263 */
1264 if (FAILED(hres))
1265 {
1266 hres = OleCreateDefaultHandler(&storageInfo.clsid,
1267 NULL,
1268 riid,
1269 (void**)&pUnk);
1270 }
1271
1272 /*
1273 * If we couldn't find a handler... this is bad. Abort the whole thing.
1274 */
1275 if (FAILED(hres))
1276 return hres;
1277
1278 if (pClientSite)
1279 {
1280 hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (void **)&pOleObject);
1281 if (SUCCEEDED(hres))
1282 {
1283 DWORD dwStatus;
1284 hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
1285 }
1286 }
1287
1288 /*
1289 * Initialize the object with its IPersistStorage interface.
1290 */
1291 hres = IUnknown_QueryInterface(pUnk, &IID_IPersistStorage, (void**)&persistStorage);
1292 if (SUCCEEDED(hres))
1293 {
1294 hres = IPersistStorage_Load(persistStorage, pStg);
1295
1296 IPersistStorage_Release(persistStorage);
1297 persistStorage = NULL;
1298 }
1299
1300 if (SUCCEEDED(hres) && pClientSite)
1301 /*
1302 * Inform the new object of its client site.
1303 */
1304 hres = IOleObject_SetClientSite(pOleObject, pClientSite);
1305
1306 /*
1307 * Cleanup interfaces used internally
1308 */
1309 if (pOleObject)
1310 IOleObject_Release(pOleObject);
1311
1312 if (SUCCEEDED(hres))
1313 {
1314 IOleLink *pOleLink;
1315 HRESULT hres1;
1316 hres1 = IUnknown_QueryInterface(pUnk, &IID_IOleLink, (void **)&pOleLink);
1317 if (SUCCEEDED(hres1))
1318 {
1319 FIXME("handle OLE link\n");
1320 IOleLink_Release(pOleLink);
1321 }
1322 }
1323
1324 if (FAILED(hres))
1325 {
1326 IUnknown_Release(pUnk);
1327 pUnk = NULL;
1328 }
1329
1330 *ppvObj = pUnk;
1331
1332 return hres;
1333 }
1334
1335 /***********************************************************************
1336 * OleSave [OLE32.@]
1337 */
OleSave(LPPERSISTSTORAGE pPS,LPSTORAGE pStg,BOOL fSameAsLoad)1338 HRESULT WINAPI OleSave(
1339 LPPERSISTSTORAGE pPS,
1340 LPSTORAGE pStg,
1341 BOOL fSameAsLoad)
1342 {
1343 HRESULT hres;
1344 CLSID objectClass;
1345
1346 TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad);
1347
1348 /*
1349 * First, we transfer the class ID (if available)
1350 */
1351 hres = IPersistStorage_GetClassID(pPS, &objectClass);
1352
1353 if (SUCCEEDED(hres))
1354 {
1355 WriteClassStg(pStg, &objectClass);
1356 }
1357
1358 /*
1359 * Then, we ask the object to save itself to the
1360 * storage. If it is successful, we commit the storage.
1361 */
1362 hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad);
1363
1364 if (SUCCEEDED(hres))
1365 {
1366 IStorage_Commit(pStg,
1367 STGC_DEFAULT);
1368 }
1369
1370 return hres;
1371 }
1372
1373
1374 /******************************************************************************
1375 * OleLockRunning [OLE32.@]
1376 */
OleLockRunning(LPUNKNOWN pUnknown,BOOL fLock,BOOL fLastUnlockCloses)1377 HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses)
1378 {
1379 IRunnableObject* runnable = NULL;
1380 HRESULT hres;
1381
1382 TRACE("(%p,%x,%x)\n", pUnknown, fLock, fLastUnlockCloses);
1383
1384 hres = IUnknown_QueryInterface(pUnknown,
1385 &IID_IRunnableObject,
1386 (void**)&runnable);
1387
1388 if (SUCCEEDED(hres))
1389 {
1390 hres = IRunnableObject_LockRunning(runnable, fLock, fLastUnlockCloses);
1391
1392 IRunnableObject_Release(runnable);
1393
1394 return hres;
1395 }
1396
1397 return S_OK;
1398 }
1399
1400
1401 /**************************************************************************
1402 * Internal methods to manage the shared OLE menu in response to the
1403 * OLE***MenuDescriptor API
1404 */
1405
1406 /***
1407 * OLEMenu_Initialize()
1408 *
1409 * Initializes the OLEMENU data structures.
1410 */
OLEMenu_Initialize(void)1411 static void OLEMenu_Initialize(void)
1412 {
1413 }
1414
1415 /***
1416 * OLEMenu_UnInitialize()
1417 *
1418 * Releases the OLEMENU data structures.
1419 */
OLEMenu_UnInitialize(void)1420 static void OLEMenu_UnInitialize(void)
1421 {
1422 }
1423
1424 /*************************************************************************
1425 * OLEMenu_InstallHooks
1426 * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
1427 *
1428 * RETURNS: TRUE if message hooks were successfully installed
1429 * FALSE on failure
1430 */
OLEMenu_InstallHooks(DWORD tid)1431 static BOOL OLEMenu_InstallHooks( DWORD tid )
1432 {
1433 OleMenuHookItem *pHookItem;
1434
1435 /* Create an entry for the hook table */
1436 if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
1437 sizeof(OleMenuHookItem)) ) )
1438 return FALSE;
1439
1440 pHookItem->tid = tid;
1441 pHookItem->hHeap = GetProcessHeap();
1442 pHookItem->CallWndProc_hHook = NULL;
1443
1444 /* Install a thread scope message hook for WH_GETMESSAGE */
1445 pHookItem->GetMsg_hHook = SetWindowsHookExW( WH_GETMESSAGE, OLEMenu_GetMsgProc,
1446 0, GetCurrentThreadId() );
1447 if ( !pHookItem->GetMsg_hHook )
1448 goto CLEANUP;
1449
1450 /* Install a thread scope message hook for WH_CALLWNDPROC */
1451 pHookItem->CallWndProc_hHook = SetWindowsHookExW( WH_CALLWNDPROC, OLEMenu_CallWndProc,
1452 0, GetCurrentThreadId() );
1453 if ( !pHookItem->CallWndProc_hHook )
1454 goto CLEANUP;
1455
1456 /* Insert the hook table entry */
1457 pHookItem->next = hook_list;
1458 hook_list = pHookItem;
1459
1460 return TRUE;
1461
1462 CLEANUP:
1463 /* Unhook any hooks */
1464 if ( pHookItem->GetMsg_hHook )
1465 UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
1466 if ( pHookItem->CallWndProc_hHook )
1467 UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
1468 /* Release the hook table entry */
1469 HeapFree(pHookItem->hHeap, 0, pHookItem );
1470
1471 return FALSE;
1472 }
1473
1474 /*************************************************************************
1475 * OLEMenu_UnInstallHooks
1476 * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
1477 *
1478 * RETURNS: TRUE if message hooks were successfully installed
1479 * FALSE on failure
1480 */
OLEMenu_UnInstallHooks(DWORD tid)1481 static BOOL OLEMenu_UnInstallHooks( DWORD tid )
1482 {
1483 OleMenuHookItem *pHookItem = NULL;
1484 OleMenuHookItem **ppHook = &hook_list;
1485
1486 while (*ppHook)
1487 {
1488 if ((*ppHook)->tid == tid)
1489 {
1490 pHookItem = *ppHook;
1491 *ppHook = pHookItem->next;
1492 break;
1493 }
1494 ppHook = &(*ppHook)->next;
1495 }
1496 if (!pHookItem) return FALSE;
1497
1498 /* Uninstall the hooks installed for this thread */
1499 if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
1500 goto CLEANUP;
1501 if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
1502 goto CLEANUP;
1503
1504 /* Release the hook table entry */
1505 HeapFree(pHookItem->hHeap, 0, pHookItem );
1506
1507 return TRUE;
1508
1509 CLEANUP:
1510 /* Release the hook table entry */
1511 HeapFree(pHookItem->hHeap, 0, pHookItem );
1512
1513 return FALSE;
1514 }
1515
1516 /*************************************************************************
1517 * OLEMenu_IsHookInstalled
1518 * Tests if OLEMenu hooks have been installed for a thread
1519 *
1520 * RETURNS: The pointer and index of the hook table entry for the tid
1521 * NULL and -1 for the index if no hooks were installed for this thread
1522 */
OLEMenu_IsHookInstalled(DWORD tid)1523 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )
1524 {
1525 OleMenuHookItem *pHookItem;
1526
1527 /* Do a simple linear search for an entry whose tid matches ours.
1528 * We really need a map but efficiency is not a concern here. */
1529 for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next)
1530 {
1531 if ( tid == pHookItem->tid )
1532 return pHookItem;
1533 }
1534
1535 return NULL;
1536 }
1537
1538 /***********************************************************************
1539 * OLEMenu_FindMainMenuIndex
1540 *
1541 * Used by OLEMenu API to find the top level group a menu item belongs to.
1542 * On success pnPos contains the index of the item in the top level menu group
1543 *
1544 * RETURNS: TRUE if the ID was found, FALSE on failure
1545 */
OLEMenu_FindMainMenuIndex(HMENU hMainMenu,HMENU hPopupMenu,UINT * pnPos)1546 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
1547 {
1548 INT i, nItems;
1549
1550 nItems = GetMenuItemCount( hMainMenu );
1551
1552 for (i = 0; i < nItems; i++)
1553 {
1554 HMENU hsubmenu;
1555
1556 /* Is the current item a submenu? */
1557 if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
1558 {
1559 /* If the handle is the same we're done */
1560 if ( hsubmenu == hPopupMenu )
1561 {
1562 if (pnPos)
1563 *pnPos = i;
1564 return TRUE;
1565 }
1566 /* Recursively search without updating pnPos */
1567 else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
1568 {
1569 if (pnPos)
1570 *pnPos = i;
1571 return TRUE;
1572 }
1573 }
1574 }
1575
1576 return FALSE;
1577 }
1578
1579 /***********************************************************************
1580 * OLEMenu_SetIsServerMenu
1581 *
1582 * Checks whether a popup menu belongs to a shared menu group which is
1583 * owned by the server, and sets the menu descriptor state accordingly.
1584 * All menu messages from these groups should be routed to the server.
1585 *
1586 * RETURNS: TRUE if the popup menu is part of a server owned group
1587 * FALSE if the popup menu is part of a container owned group
1588 */
OLEMenu_SetIsServerMenu(HMENU hmenu,OleMenuDescriptor * pOleMenuDescriptor)1589 static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
1590 {
1591 UINT nPos = 0, nWidth, i;
1592
1593 pOleMenuDescriptor->bIsServerItem = FALSE;
1594
1595 /* Don't bother searching if the popup is the combined menu itself */
1596 if ( hmenu == pOleMenuDescriptor->hmenuCombined )
1597 return FALSE;
1598
1599 /* Find the menu item index in the shared OLE menu that this item belongs to */
1600 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) )
1601 return FALSE;
1602
1603 /* The group widths array has counts for the number of elements
1604 * in the groups File, Edit, Container, Object, Window, Help.
1605 * The Edit, Object & Help groups belong to the server object
1606 * and the other three belong to the container.
1607 * Loop through the group widths and locate the group we are a member of.
1608 */
1609 for ( i = 0, nWidth = 0; i < 6; i++ )
1610 {
1611 nWidth += pOleMenuDescriptor->mgw.width[i];
1612 if ( nPos < nWidth )
1613 {
1614 /* Odd elements are server menu widths */
1615 pOleMenuDescriptor->bIsServerItem = i%2;
1616 break;
1617 }
1618 }
1619
1620 return pOleMenuDescriptor->bIsServerItem;
1621 }
1622
1623 /*************************************************************************
1624 * OLEMenu_CallWndProc
1625 * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
1626 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1627 */
OLEMenu_CallWndProc(INT code,WPARAM wParam,LPARAM lParam)1628 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
1629 {
1630 LPCWPSTRUCT pMsg;
1631 HOLEMENU hOleMenu = 0;
1632 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1633 OleMenuHookItem *pHookItem = NULL;
1634 WORD fuFlags;
1635
1636 TRACE("%i, %04lx, %08lx\n", code, wParam, lParam );
1637
1638 /* Check if we're being asked to process the message */
1639 if ( HC_ACTION != code )
1640 goto NEXTHOOK;
1641
1642 /* Retrieve the current message being dispatched from lParam */
1643 pMsg = (LPCWPSTRUCT)lParam;
1644
1645 /* Check if the message is destined for a window we are interested in:
1646 * If the window has an OLEMenu property we may need to dispatch
1647 * the menu message to its active objects window instead. */
1648
1649 hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW );
1650 if ( !hOleMenu )
1651 goto NEXTHOOK;
1652
1653 /* Get the menu descriptor */
1654 pOleMenuDescriptor = GlobalLock( hOleMenu );
1655 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1656 goto NEXTHOOK;
1657
1658 /* Process menu messages */
1659 switch( pMsg->message )
1660 {
1661 case WM_INITMENU:
1662 {
1663 /* Reset the menu descriptor state */
1664 pOleMenuDescriptor->bIsServerItem = FALSE;
1665
1666 /* Send this message to the server as well */
1667 SendMessageW( pOleMenuDescriptor->hwndActiveObject,
1668 pMsg->message, pMsg->wParam, pMsg->lParam );
1669 goto NEXTHOOK;
1670 }
1671
1672 case WM_INITMENUPOPUP:
1673 {
1674 /* Save the state for whether this is a server owned menu */
1675 OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
1676 break;
1677 }
1678
1679 case WM_MENUSELECT:
1680 {
1681 fuFlags = HIWORD(pMsg->wParam); /* Get flags */
1682 if ( fuFlags & MF_SYSMENU )
1683 goto NEXTHOOK;
1684
1685 /* Save the state for whether this is a server owned popup menu */
1686 else if ( fuFlags & MF_POPUP )
1687 OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
1688
1689 break;
1690 }
1691
1692 case WM_DRAWITEM:
1693 {
1694 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
1695 if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
1696 goto NEXTHOOK; /* Not a menu message */
1697
1698 break;
1699 }
1700
1701 default:
1702 goto NEXTHOOK;
1703 }
1704
1705 /* If the message was for the server dispatch it accordingly */
1706 if ( pOleMenuDescriptor->bIsServerItem )
1707 {
1708 SendMessageW( pOleMenuDescriptor->hwndActiveObject,
1709 pMsg->message, pMsg->wParam, pMsg->lParam );
1710 }
1711
1712 NEXTHOOK:
1713 if ( pOleMenuDescriptor )
1714 GlobalUnlock( hOleMenu );
1715
1716 /* Lookup the hook item for the current thread */
1717 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1718 {
1719 /* This should never fail!! */
1720 WARN("could not retrieve hHook for current thread!\n" );
1721 return 0;
1722 }
1723
1724 /* Pass on the message to the next hooker */
1725 return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
1726 }
1727
1728 /*************************************************************************
1729 * OLEMenu_GetMsgProc
1730 * Thread scope WH_GETMESSAGE hook proc filter function (callback)
1731 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1732 */
OLEMenu_GetMsgProc(INT code,WPARAM wParam,LPARAM lParam)1733 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
1734 {
1735 LPMSG pMsg;
1736 HOLEMENU hOleMenu = 0;
1737 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1738 OleMenuHookItem *pHookItem = NULL;
1739 WORD wCode;
1740
1741 TRACE("%i, %04lx, %08lx\n", code, wParam, lParam );
1742
1743 /* Check if we're being asked to process a messages */
1744 if ( HC_ACTION != code )
1745 goto NEXTHOOK;
1746
1747 /* Retrieve the current message being dispatched from lParam */
1748 pMsg = (LPMSG)lParam;
1749
1750 /* Check if the message is destined for a window we are interested in:
1751 * If the window has an OLEMenu property we may need to dispatch
1752 * the menu message to its active objects window instead. */
1753
1754 hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW );
1755 if ( !hOleMenu )
1756 goto NEXTHOOK;
1757
1758 /* Process menu messages */
1759 switch( pMsg->message )
1760 {
1761 case WM_COMMAND:
1762 {
1763 wCode = HIWORD(pMsg->wParam); /* Get notification code */
1764 if ( wCode )
1765 goto NEXTHOOK; /* Not a menu message */
1766 break;
1767 }
1768 default:
1769 goto NEXTHOOK;
1770 }
1771
1772 /* Get the menu descriptor */
1773 pOleMenuDescriptor = GlobalLock( hOleMenu );
1774 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1775 goto NEXTHOOK;
1776
1777 /* If the message was for the server dispatch it accordingly */
1778 if ( pOleMenuDescriptor->bIsServerItem )
1779 {
1780 /* Change the hWnd in the message to the active objects hWnd.
1781 * The message loop which reads this message will automatically
1782 * dispatch it to the embedded objects window. */
1783 pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
1784 }
1785
1786 NEXTHOOK:
1787 if ( pOleMenuDescriptor )
1788 GlobalUnlock( hOleMenu );
1789
1790 /* Lookup the hook item for the current thread */
1791 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1792 {
1793 /* This should never fail!! */
1794 WARN("could not retrieve hHook for current thread!\n" );
1795 return FALSE;
1796 }
1797
1798 /* Pass on the message to the next hooker */
1799 return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
1800 }
1801
1802 /***********************************************************************
1803 * OleCreateMenuDescriptor [OLE32.@]
1804 * Creates an OLE menu descriptor for OLE to use when dispatching
1805 * menu messages and commands.
1806 *
1807 * PARAMS:
1808 * hmenuCombined - Handle to the objects combined menu
1809 * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group
1810 *
1811 */
OleCreateMenuDescriptor(HMENU hmenuCombined,LPOLEMENUGROUPWIDTHS lpMenuWidths)1812 HOLEMENU WINAPI OleCreateMenuDescriptor(
1813 HMENU hmenuCombined,
1814 LPOLEMENUGROUPWIDTHS lpMenuWidths)
1815 {
1816 HOLEMENU hOleMenu;
1817 OleMenuDescriptor *pOleMenuDescriptor;
1818 int i;
1819
1820 if ( !hmenuCombined || !lpMenuWidths )
1821 return 0;
1822
1823 /* Create an OLE menu descriptor */
1824 if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
1825 sizeof(OleMenuDescriptor) ) ) )
1826 return 0;
1827
1828 pOleMenuDescriptor = GlobalLock( hOleMenu );
1829 if ( !pOleMenuDescriptor )
1830 return 0;
1831
1832 /* Initialize menu group widths and hmenu */
1833 for ( i = 0; i < 6; i++ )
1834 pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
1835
1836 pOleMenuDescriptor->hmenuCombined = hmenuCombined;
1837 pOleMenuDescriptor->bIsServerItem = FALSE;
1838 GlobalUnlock( hOleMenu );
1839
1840 return hOleMenu;
1841 }
1842
1843 /***********************************************************************
1844 * OleDestroyMenuDescriptor [OLE32.@]
1845 * Destroy the shared menu descriptor
1846 */
OleDestroyMenuDescriptor(HOLEMENU hmenuDescriptor)1847 HRESULT WINAPI OleDestroyMenuDescriptor(
1848 HOLEMENU hmenuDescriptor)
1849 {
1850 if ( hmenuDescriptor )
1851 GlobalFree( hmenuDescriptor );
1852 return S_OK;
1853 }
1854
1855 /***********************************************************************
1856 * OleSetMenuDescriptor [OLE32.@]
1857 * Installs or removes OLE dispatching code for the containers frame window.
1858 *
1859 * PARAMS
1860 * hOleMenu Handle to composite menu descriptor
1861 * hwndFrame Handle to containers frame window
1862 * hwndActiveObject Handle to objects in-place activation window
1863 * lpFrame Pointer to IOleInPlaceFrame on containers window
1864 * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object
1865 *
1866 * RETURNS
1867 * S_OK - menu installed correctly
1868 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1869 *
1870 * FIXME
1871 * The lpFrame and lpActiveObject parameters are currently ignored
1872 * OLE should install context sensitive help F1 filtering for the app when
1873 * these are non null.
1874 */
OleSetMenuDescriptor(HOLEMENU hOleMenu,HWND hwndFrame,HWND hwndActiveObject,LPOLEINPLACEFRAME lpFrame,LPOLEINPLACEACTIVEOBJECT lpActiveObject)1875 HRESULT WINAPI OleSetMenuDescriptor(
1876 HOLEMENU hOleMenu,
1877 HWND hwndFrame,
1878 HWND hwndActiveObject,
1879 LPOLEINPLACEFRAME lpFrame,
1880 LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1881 {
1882 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1883
1884 /* Check args */
1885 if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
1886 return E_INVALIDARG;
1887
1888 if ( lpFrame || lpActiveObject )
1889 {
1890 FIXME("(%p, %p, %p, %p, %p), Context sensitive help filtering not implemented!\n",
1891 hOleMenu,
1892 hwndFrame,
1893 hwndActiveObject,
1894 lpFrame,
1895 lpActiveObject);
1896 }
1897
1898 /* Set up a message hook to intercept the containers frame window messages.
1899 * The message filter is responsible for dispatching menu messages from the
1900 * shared menu which are intended for the object.
1901 */
1902
1903 if ( hOleMenu ) /* Want to install dispatching code */
1904 {
1905 /* If OLEMenu hooks are already installed for this thread, fail
1906 * Note: This effectively means that OleSetMenuDescriptor cannot
1907 * be called twice in succession on the same frame window
1908 * without first calling it with a null hOleMenu to uninstall
1909 */
1910 if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) )
1911 return E_FAIL;
1912
1913 /* Get the menu descriptor */
1914 pOleMenuDescriptor = GlobalLock( hOleMenu );
1915 if ( !pOleMenuDescriptor )
1916 return E_UNEXPECTED;
1917
1918 /* Update the menu descriptor */
1919 pOleMenuDescriptor->hwndFrame = hwndFrame;
1920 pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
1921
1922 GlobalUnlock( hOleMenu );
1923 pOleMenuDescriptor = NULL;
1924
1925 /* Add a menu descriptor windows property to the frame window */
1926 SetPropW( hwndFrame, prop_olemenuW, hOleMenu );
1927
1928 /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
1929 if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
1930 return E_FAIL;
1931 }
1932 else /* Want to uninstall dispatching code */
1933 {
1934 /* Uninstall the hooks */
1935 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1936 return E_FAIL;
1937
1938 /* Remove the menu descriptor property from the frame window */
1939 RemovePropW( hwndFrame, prop_olemenuW );
1940 }
1941
1942 return S_OK;
1943 }
1944
1945 /******************************************************************************
1946 * IsAccelerator [OLE32.@]
1947 * Mostly copied from controls/menu.c TranslateAccelerator implementation
1948 */
IsAccelerator(HACCEL hAccel,int cAccelEntries,LPMSG lpMsg,WORD * lpwCmd)1949 BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd)
1950 {
1951 LPACCEL lpAccelTbl;
1952 int i;
1953
1954 if(!lpMsg) return FALSE;
1955 if (!hAccel)
1956 {
1957 WARN_(accel)("NULL accel handle\n");
1958 return FALSE;
1959 }
1960 if((lpMsg->message != WM_KEYDOWN &&
1961 lpMsg->message != WM_SYSKEYDOWN &&
1962 lpMsg->message != WM_SYSCHAR &&
1963 lpMsg->message != WM_CHAR)) return FALSE;
1964 lpAccelTbl = HeapAlloc(GetProcessHeap(), 0, cAccelEntries * sizeof(ACCEL));
1965 if (NULL == lpAccelTbl)
1966 {
1967 return FALSE;
1968 }
1969 if (CopyAcceleratorTableW(hAccel, lpAccelTbl, cAccelEntries) != cAccelEntries)
1970 {
1971 WARN_(accel)("CopyAcceleratorTableW failed\n");
1972 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1973 return FALSE;
1974 }
1975
1976 TRACE_(accel)("hAccel=%p, cAccelEntries=%d,"
1977 "msg->hwnd=%p, msg->message=%04x, wParam=%08lx, lParam=%08lx\n",
1978 hAccel, cAccelEntries,
1979 lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);
1980 for(i = 0; i < cAccelEntries; i++)
1981 {
1982 if(lpAccelTbl[i].key != lpMsg->wParam)
1983 continue;
1984
1985 if(lpMsg->message == WM_CHAR)
1986 {
1987 if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY))
1988 {
1989 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", LOWORD(lpMsg->wParam) & 0xff);
1990 goto found;
1991 }
1992 }
1993 else
1994 {
1995 if(lpAccelTbl[i].fVirt & FVIRTKEY)
1996 {
1997 INT mask = 0;
1998 TRACE_(accel)("found accel for virt_key %04lx (scan %04x)\n",
1999 lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff);
2000 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
2001 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
2002 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
2003 if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
2004 TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n");
2005 }
2006 else
2007 {
2008 if(!(lpMsg->lParam & 0x01000000)) /* no special_key */
2009 {
2010 if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000))
2011 { /* ^^ ALT pressed */
2012 TRACE_(accel)("found accel for Alt-%c\n", LOWORD(lpMsg->wParam) & 0xff);
2013 goto found;
2014 }
2015 }
2016 }
2017 }
2018 }
2019
2020 WARN_(accel)("couldn't translate accelerator key\n");
2021 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
2022 return FALSE;
2023
2024 found:
2025 if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd;
2026 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
2027 return TRUE;
2028 }
2029
2030 /***********************************************************************
2031 * ReleaseStgMedium [OLE32.@]
2032 */
ReleaseStgMedium(STGMEDIUM * pmedium)2033 void WINAPI ReleaseStgMedium(
2034 STGMEDIUM* pmedium)
2035 {
2036 switch (pmedium->tymed)
2037 {
2038 case TYMED_HGLOBAL:
2039 {
2040 if ( (pmedium->pUnkForRelease==0) &&
2041 (pmedium->u.hGlobal!=0) )
2042 GlobalFree(pmedium->u.hGlobal);
2043 break;
2044 }
2045 case TYMED_FILE:
2046 {
2047 if (pmedium->u.lpszFileName!=0)
2048 {
2049 if (pmedium->pUnkForRelease==0)
2050 {
2051 DeleteFileW(pmedium->u.lpszFileName);
2052 }
2053
2054 CoTaskMemFree(pmedium->u.lpszFileName);
2055 }
2056 break;
2057 }
2058 case TYMED_ISTREAM:
2059 {
2060 if (pmedium->u.pstm!=0)
2061 {
2062 IStream_Release(pmedium->u.pstm);
2063 }
2064 break;
2065 }
2066 case TYMED_ISTORAGE:
2067 {
2068 if (pmedium->u.pstg!=0)
2069 {
2070 IStorage_Release(pmedium->u.pstg);
2071 }
2072 break;
2073 }
2074 case TYMED_GDI:
2075 {
2076 if ( (pmedium->pUnkForRelease==0) &&
2077 (pmedium->u.hBitmap!=0) )
2078 DeleteObject(pmedium->u.hBitmap);
2079 break;
2080 }
2081 case TYMED_MFPICT:
2082 {
2083 if ( (pmedium->pUnkForRelease==0) &&
2084 (pmedium->u.hMetaFilePict!=0) )
2085 {
2086 LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hMetaFilePict);
2087 DeleteMetaFile(pMP->hMF);
2088 GlobalUnlock(pmedium->u.hMetaFilePict);
2089 GlobalFree(pmedium->u.hMetaFilePict);
2090 }
2091 break;
2092 }
2093 case TYMED_ENHMF:
2094 {
2095 if ( (pmedium->pUnkForRelease==0) &&
2096 (pmedium->u.hEnhMetaFile!=0) )
2097 {
2098 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
2099 }
2100 break;
2101 }
2102 case TYMED_NULL:
2103 default:
2104 break;
2105 }
2106 pmedium->tymed=TYMED_NULL;
2107
2108 /*
2109 * After cleaning up, the unknown is released
2110 */
2111 if (pmedium->pUnkForRelease!=0)
2112 {
2113 IUnknown_Release(pmedium->pUnkForRelease);
2114 pmedium->pUnkForRelease = 0;
2115 }
2116 }
2117
2118 /***
2119 * OLEDD_Initialize()
2120 *
2121 * Initializes the OLE drag and drop data structures.
2122 */
OLEDD_Initialize(void)2123 static void OLEDD_Initialize(void)
2124 {
2125 WNDCLASSW wndClass;
2126
2127 ZeroMemory (&wndClass, sizeof(WNDCLASSW));
2128 wndClass.style = CS_GLOBALCLASS;
2129 wndClass.lpfnWndProc = OLEDD_DragTrackerWindowProc;
2130 wndClass.cbClsExtra = 0;
2131 wndClass.cbWndExtra = sizeof(TrackerWindowInfo*);
2132 wndClass.hCursor = 0;
2133 wndClass.hbrBackground = 0;
2134 wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
2135
2136 RegisterClassW (&wndClass);
2137 }
2138
2139 /***
2140 * OLEDD_DragTrackerWindowProc()
2141 *
2142 * This method is the WindowProcedure of the drag n drop tracking
2143 * window. During a drag n Drop operation, an invisible window is created
2144 * to receive the user input and act upon it. This procedure is in charge
2145 * of this behavior.
2146 */
2147
2148 #define DRAG_TIMER_ID 1
2149
OLEDD_DragTrackerWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)2150 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
2151 HWND hwnd,
2152 UINT uMsg,
2153 WPARAM wParam,
2154 LPARAM lParam)
2155 {
2156 switch (uMsg)
2157 {
2158 case WM_CREATE:
2159 {
2160 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
2161
2162 SetWindowLongPtrW(hwnd, 0, (LONG_PTR)createStruct->lpCreateParams);
2163 SetTimer(hwnd, DRAG_TIMER_ID, 50, NULL);
2164
2165 break;
2166 }
2167 case WM_TIMER:
2168 case WM_MOUSEMOVE:
2169 case WM_LBUTTONUP:
2170 case WM_MBUTTONUP:
2171 case WM_RBUTTONUP:
2172 case WM_LBUTTONDOWN:
2173 case WM_MBUTTONDOWN:
2174 case WM_RBUTTONDOWN:
2175 {
2176 TrackerWindowInfo *trackerInfo = (TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0);
2177 if (trackerInfo->trackingDone) break;
2178 OLEDD_TrackStateChange(trackerInfo);
2179 break;
2180 }
2181 case WM_DESTROY:
2182 {
2183 KillTimer(hwnd, DRAG_TIMER_ID);
2184 break;
2185 }
2186 }
2187
2188 /*
2189 * This is a window proc after all. Let's call the default.
2190 */
2191 return DefWindowProcW (hwnd, uMsg, wParam, lParam);
2192 }
2193
2194 #ifdef __REACTOS__
DefaultDragEnter(HWND hwndTarget,IDataObject * pDataObj,DWORD grfKeyState,POINTL pt,DWORD * pdwEffect)2195 static HRESULT WINAPI DefaultDragEnter(HWND hwndTarget,
2196 IDataObject* pDataObj,
2197 DWORD grfKeyState,
2198 POINTL pt,
2199 DWORD* pdwEffect)
2200 {
2201 HRESULT hr;
2202 FORMATETC fme;
2203
2204 ZeroMemory(&fme, sizeof(fme));
2205 fme.cfFormat = CF_HDROP;
2206 fme.ptd = NULL;
2207 fme.dwAspect = DVASPECT_CONTENT;
2208 fme.lindex = -1;
2209 fme.tymed = TYMED_HGLOBAL;
2210 hr = pDataObj->lpVtbl->QueryGetData(pDataObj, &fme);
2211
2212 *pdwEffect = SUCCEEDED(hr) ? DROPEFFECT_COPY : DROPEFFECT_NONE;
2213
2214 if (*pdwEffect == DROPEFFECT_NONE)
2215 return DRAGDROP_S_CANCEL;
2216
2217 return S_OK;
2218 }
2219
DefaultDrop(HWND hwndAccepter,IDataObject * pDataObj,DWORD grfKeyState,POINTL pt,DWORD * pdwEffect)2220 static HRESULT WINAPI DefaultDrop(HWND hwndAccepter,
2221 IDataObject* pDataObj,
2222 DWORD grfKeyState,
2223 POINTL pt,
2224 DWORD* pdwEffect)
2225 {
2226 FORMATETC fme;
2227 STGMEDIUM stgm;
2228 HRESULT hr;
2229 HGLOBAL hGlobal = NULL;
2230
2231 ZeroMemory(&fme, sizeof(fme));
2232 fme.cfFormat = CF_HDROP;
2233 fme.ptd = NULL;
2234 fme.dwAspect = DVASPECT_CONTENT;
2235 fme.lindex = -1;
2236 fme.tymed = TYMED_HGLOBAL;
2237 hr = pDataObj->lpVtbl->QueryGetData(pDataObj, &fme);
2238 if (FAILED(hr))
2239 return hr;
2240
2241 ZeroMemory(&stgm, sizeof(stgm));
2242 hr = pDataObj->lpVtbl->GetData(pDataObj, &fme, &stgm);
2243 if (SUCCEEDED(hr))
2244 {
2245 hGlobal = stgm.DUMMYUNIONNAME.hGlobal;
2246 if (hGlobal)
2247 {
2248 if (IsWindowUnicode(hwndAccepter))
2249 PostMessageW(hwndAccepter, WM_DROPFILES, (WPARAM)hGlobal, 0);
2250 else
2251 PostMessageA(hwndAccepter, WM_DROPFILES, (WPARAM)hGlobal, 0);
2252 }
2253 ReleaseStgMedium(&stgm);
2254 }
2255
2256 return hr;
2257 }
2258 #endif
2259
drag_enter(TrackerWindowInfo * info,HWND new_target)2260 static void drag_enter( TrackerWindowInfo *info, HWND new_target )
2261 {
2262 HRESULT hr;
2263 #ifdef __REACTOS__
2264 DWORD dwEffect = *info->pdwEffect;
2265 #endif
2266
2267 info->curTargetHWND = new_target;
2268
2269 #ifdef __REACTOS__
2270 info->accepterHWND = NULL;
2271 while (new_target && !is_droptarget( new_target ))
2272 {
2273 if (is_acceptfiles(new_target))
2274 {
2275 dwEffect = info->dwOKEffect;
2276 hr = DefaultDragEnter(new_target, info->dataObject,
2277 info->dwKeyState, info->curMousePos,
2278 &dwEffect);
2279 dwEffect &= info->dwOKEffect;
2280
2281 if (hr == S_OK)
2282 {
2283 info->accepterHWND = new_target;
2284 info->curDragTarget = NULL;
2285 *info->pdwEffect = dwEffect;
2286 return;
2287 }
2288 }
2289 new_target = GetParent( new_target );
2290 }
2291 #else
2292 while (new_target && !is_droptarget( new_target ))
2293 new_target = GetParent( new_target );
2294 #endif
2295
2296 info->curDragTarget = get_droptarget_pointer( new_target );
2297
2298 if (info->curDragTarget)
2299 {
2300 *info->pdwEffect = info->dwOKEffect;
2301 hr = IDropTarget_DragEnter( info->curDragTarget, info->dataObject,
2302 info->dwKeyState, info->curMousePos,
2303 info->pdwEffect );
2304 *info->pdwEffect &= info->dwOKEffect;
2305
2306 /* failed DragEnter() means invalid target */
2307 if (hr != S_OK)
2308 {
2309 IDropTarget_Release( info->curDragTarget );
2310 info->curDragTarget = NULL;
2311 info->curTargetHWND = NULL;
2312 #ifdef __REACTOS__
2313 info->accepterHWND = NULL;
2314 #endif
2315 }
2316 }
2317 }
2318
drag_end(TrackerWindowInfo * info)2319 static void drag_end( TrackerWindowInfo *info )
2320 {
2321 HRESULT hr;
2322
2323 info->trackingDone = TRUE;
2324 ReleaseCapture();
2325
2326 if (info->curDragTarget)
2327 {
2328 if (info->returnValue == DRAGDROP_S_DROP &&
2329 *info->pdwEffect != DROPEFFECT_NONE)
2330 {
2331 *info->pdwEffect = info->dwOKEffect;
2332 hr = IDropTarget_Drop( info->curDragTarget, info->dataObject, info->dwKeyState,
2333 info->curMousePos, info->pdwEffect );
2334 *info->pdwEffect &= info->dwOKEffect;
2335
2336 if (FAILED( hr ))
2337 info->returnValue = hr;
2338 }
2339 else
2340 {
2341 IDropTarget_DragLeave( info->curDragTarget );
2342 *info->pdwEffect = DROPEFFECT_NONE;
2343 }
2344 IDropTarget_Release( info->curDragTarget );
2345 info->curDragTarget = NULL;
2346 }
2347 #ifdef __REACTOS__
2348 else if (info->accepterHWND)
2349 {
2350 if (info->returnValue == DRAGDROP_S_DROP &&
2351 *info->pdwEffect != DROPEFFECT_NONE)
2352 {
2353 *info->pdwEffect = info->dwOKEffect;
2354 hr = DefaultDrop(info->accepterHWND, info->dataObject, info->dwKeyState,
2355 info->curMousePos, info->pdwEffect);
2356 *info->pdwEffect &= info->dwOKEffect;
2357
2358 if (FAILED( hr ))
2359 info->returnValue = hr;
2360 }
2361 else
2362 {
2363 *info->pdwEffect = DROPEFFECT_NONE;
2364 }
2365 info->accepterHWND = NULL;
2366 }
2367 #endif
2368 else
2369 *info->pdwEffect = DROPEFFECT_NONE;
2370 }
2371
give_feedback(TrackerWindowInfo * info)2372 static HRESULT give_feedback( TrackerWindowInfo *info )
2373 {
2374 HRESULT hr;
2375 int res;
2376 HCURSOR cur;
2377
2378 #ifdef __REACTOS__
2379 if (info->curDragTarget == NULL && info->accepterHWND == NULL)
2380 *info->pdwEffect = DROPEFFECT_NONE;
2381 #else
2382 if (info->curDragTarget == NULL)
2383 *info->pdwEffect = DROPEFFECT_NONE;
2384 #endif
2385
2386 hr = IDropSource_GiveFeedback( info->dropSource, *info->pdwEffect );
2387
2388 if (hr == DRAGDROP_S_USEDEFAULTCURSORS)
2389 {
2390 if (*info->pdwEffect & DROPEFFECT_MOVE)
2391 res = CURSOR_MOVE;
2392 else if (*info->pdwEffect & DROPEFFECT_COPY)
2393 res = CURSOR_COPY;
2394 else if (*info->pdwEffect & DROPEFFECT_LINK)
2395 res = CURSOR_LINK;
2396 else
2397 res = CURSOR_NODROP;
2398
2399 cur = LoadCursorW( hProxyDll, MAKEINTRESOURCEW( res ) );
2400 SetCursor( cur );
2401 }
2402
2403 return hr;
2404 }
2405
2406 /***
2407 * OLEDD_TrackStateChange()
2408 *
2409 * This method is invoked while a drag and drop operation is in effect.
2410 *
2411 * params:
2412 * trackerInfo - Pointer to the structure identifying the
2413 * drag & drop operation that is currently
2414 * active.
2415 */
OLEDD_TrackStateChange(TrackerWindowInfo * trackerInfo)2416 static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo)
2417 {
2418 HWND hwndNewTarget = 0;
2419 POINT pt;
2420
2421 /*
2422 * Get the handle of the window under the mouse
2423 */
2424 pt.x = trackerInfo->curMousePos.x;
2425 pt.y = trackerInfo->curMousePos.y;
2426 hwndNewTarget = WindowFromPoint(pt);
2427
2428 trackerInfo->returnValue = IDropSource_QueryContinueDrag(trackerInfo->dropSource,
2429 trackerInfo->escPressed,
2430 trackerInfo->dwKeyState);
2431
2432 if (trackerInfo->curTargetHWND != hwndNewTarget &&
2433 (trackerInfo->returnValue == S_OK ||
2434 trackerInfo->returnValue == DRAGDROP_S_DROP))
2435 {
2436 if (trackerInfo->curDragTarget)
2437 {
2438 IDropTarget_DragLeave(trackerInfo->curDragTarget);
2439 IDropTarget_Release(trackerInfo->curDragTarget);
2440 trackerInfo->curDragTarget = NULL;
2441 trackerInfo->curTargetHWND = NULL;
2442 }
2443 #ifdef __REACTOS__
2444 trackerInfo->accepterHWND = NULL;
2445 #endif
2446
2447 if (hwndNewTarget)
2448 drag_enter( trackerInfo, hwndNewTarget );
2449
2450 give_feedback( trackerInfo );
2451
2452 }
2453
2454 if (trackerInfo->returnValue == S_OK)
2455 {
2456 if (trackerInfo->curDragTarget)
2457 {
2458 *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
2459 IDropTarget_DragOver(trackerInfo->curDragTarget,
2460 trackerInfo->dwKeyState,
2461 trackerInfo->curMousePos,
2462 trackerInfo->pdwEffect);
2463 *trackerInfo->pdwEffect &= trackerInfo->dwOKEffect;
2464 }
2465 #ifdef __REACTOS__
2466 else if (trackerInfo->accepterHWND)
2467 {
2468 *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
2469 }
2470 #endif
2471 give_feedback( trackerInfo );
2472 }
2473 else
2474 drag_end( trackerInfo );
2475 }
2476
2477 /***
2478 * OLEDD_GetButtonState()
2479 *
2480 * This method will use the current state of the keyboard to build
2481 * a button state mask equivalent to the one passed in the
2482 * WM_MOUSEMOVE wParam.
2483 */
OLEDD_GetButtonState(void)2484 static DWORD OLEDD_GetButtonState(void)
2485 {
2486 BYTE keyboardState[256];
2487 DWORD keyMask = 0;
2488
2489 GetKeyboardState(keyboardState);
2490
2491 if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
2492 keyMask |= MK_SHIFT;
2493
2494 if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
2495 keyMask |= MK_CONTROL;
2496
2497 if ( (keyboardState[VK_MENU] & 0x80) !=0)
2498 keyMask |= MK_ALT;
2499
2500 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
2501 keyMask |= MK_LBUTTON;
2502
2503 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
2504 keyMask |= MK_RBUTTON;
2505
2506 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
2507 keyMask |= MK_MBUTTON;
2508
2509 return keyMask;
2510 }
2511
2512 /***
2513 * OLEDD_GetButtonState()
2514 *
2515 * This method will read the default value of the registry key in
2516 * parameter and extract a DWORD value from it. The registry key value
2517 * can be in a string key or a DWORD key.
2518 *
2519 * params:
2520 * regKey - Key to read the default value from
2521 * pdwValue - Pointer to the location where the DWORD
2522 * value is returned. This value is not modified
2523 * if the value is not found.
2524 */
2525
OLEUTL_ReadRegistryDWORDValue(HKEY regKey,DWORD * pdwValue)2526 static void OLEUTL_ReadRegistryDWORDValue(
2527 HKEY regKey,
2528 DWORD* pdwValue)
2529 {
2530 WCHAR buffer[20];
2531 DWORD cbData = sizeof(buffer);
2532 DWORD dwKeyType;
2533 LONG lres;
2534
2535 lres = RegQueryValueExW(regKey,
2536 emptyW,
2537 NULL,
2538 &dwKeyType,
2539 (LPBYTE)buffer,
2540 &cbData);
2541
2542 if (lres==ERROR_SUCCESS)
2543 {
2544 switch (dwKeyType)
2545 {
2546 case REG_DWORD:
2547 *pdwValue = *(DWORD*)buffer;
2548 break;
2549 case REG_EXPAND_SZ:
2550 case REG_MULTI_SZ:
2551 case REG_SZ:
2552 *pdwValue = wcstoul(buffer, NULL, 10);
2553 break;
2554 }
2555 }
2556 }
2557
2558 /******************************************************************************
2559 * OleDraw (OLE32.@)
2560 *
2561 * The operation of this function is documented literally in the WinAPI
2562 * documentation to involve a QueryInterface for the IViewObject interface,
2563 * followed by a call to IViewObject::Draw.
2564 */
OleDraw(IUnknown * pUnk,DWORD dwAspect,HDC hdcDraw,LPCRECT rect)2565 HRESULT WINAPI OleDraw(
2566 IUnknown *pUnk,
2567 DWORD dwAspect,
2568 HDC hdcDraw,
2569 LPCRECT rect)
2570 {
2571 HRESULT hres;
2572 IViewObject *viewobject;
2573
2574 if (!pUnk) return E_INVALIDARG;
2575
2576 hres = IUnknown_QueryInterface(pUnk,
2577 &IID_IViewObject,
2578 (void**)&viewobject);
2579 if (SUCCEEDED(hres))
2580 {
2581 hres = IViewObject_Draw(viewobject, dwAspect, -1, 0, 0, 0, hdcDraw, (RECTL*)rect, 0, 0, 0);
2582 IViewObject_Release(viewobject);
2583 return hres;
2584 }
2585 else
2586 return DV_E_NOIVIEWOBJECT;
2587 }
2588
2589 /***********************************************************************
2590 * OleTranslateAccelerator [OLE32.@]
2591 */
OleTranslateAccelerator(LPOLEINPLACEFRAME lpFrame,LPOLEINPLACEFRAMEINFO lpFrameInfo,LPMSG lpmsg)2592 HRESULT WINAPI OleTranslateAccelerator (LPOLEINPLACEFRAME lpFrame,
2593 LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpmsg)
2594 {
2595 WORD wID;
2596
2597 TRACE("(%p,%p,%p)\n", lpFrame, lpFrameInfo, lpmsg);
2598
2599 if (IsAccelerator(lpFrameInfo->haccel,lpFrameInfo->cAccelEntries,lpmsg,&wID))
2600 return IOleInPlaceFrame_TranslateAccelerator(lpFrame,lpmsg,wID);
2601
2602 return S_FALSE;
2603 }
2604
2605 /******************************************************************************
2606 * OleCreate [OLE32.@]
2607 *
2608 */
OleCreate(REFCLSID rclsid,REFIID riid,DWORD renderopt,LPFORMATETC pFormatEtc,LPOLECLIENTSITE pClientSite,LPSTORAGE pStg,LPVOID * ppvObj)2609 HRESULT WINAPI OleCreate(
2610 REFCLSID rclsid,
2611 REFIID riid,
2612 DWORD renderopt,
2613 LPFORMATETC pFormatEtc,
2614 LPOLECLIENTSITE pClientSite,
2615 LPSTORAGE pStg,
2616 LPVOID* ppvObj)
2617 {
2618 HRESULT hres;
2619 IUnknown * pUnk = NULL;
2620 IOleObject *pOleObject = NULL;
2621
2622 TRACE("(%s, %s, %d, %p, %p, %p, %p)\n", debugstr_guid(rclsid),
2623 debugstr_guid(riid), renderopt, pFormatEtc, pClientSite, pStg, ppvObj);
2624
2625 hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, riid, (LPVOID*)&pUnk);
2626
2627 if (SUCCEEDED(hres))
2628 hres = IStorage_SetClass(pStg, rclsid);
2629
2630 if (pClientSite && SUCCEEDED(hres))
2631 {
2632 hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (LPVOID*)&pOleObject);
2633 if (SUCCEEDED(hres))
2634 {
2635 DWORD dwStatus;
2636 IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
2637 }
2638 }
2639
2640 if (SUCCEEDED(hres))
2641 {
2642 IPersistStorage * pPS;
2643 if (SUCCEEDED((hres = IUnknown_QueryInterface(pUnk, &IID_IPersistStorage, (LPVOID*)&pPS))))
2644 {
2645 TRACE("trying to set stg %p\n", pStg);
2646 hres = IPersistStorage_InitNew(pPS, pStg);
2647 TRACE("-- result 0x%08x\n", hres);
2648 IPersistStorage_Release(pPS);
2649 }
2650 }
2651
2652 if (pClientSite && SUCCEEDED(hres))
2653 {
2654 TRACE("trying to set clientsite %p\n", pClientSite);
2655 hres = IOleObject_SetClientSite(pOleObject, pClientSite);
2656 TRACE("-- result 0x%08x\n", hres);
2657 }
2658
2659 if (pOleObject)
2660 IOleObject_Release(pOleObject);
2661
2662 if (((renderopt == OLERENDER_DRAW) || (renderopt == OLERENDER_FORMAT)) &&
2663 SUCCEEDED(hres))
2664 {
2665 hres = OleRun(pUnk);
2666 if (SUCCEEDED(hres))
2667 {
2668 IOleCache *pOleCache;
2669
2670 if (SUCCEEDED(IUnknown_QueryInterface(pUnk, &IID_IOleCache, (void **)&pOleCache)))
2671 {
2672 DWORD dwConnection;
2673 if (renderopt == OLERENDER_DRAW && !pFormatEtc) {
2674 FORMATETC pfe;
2675 pfe.cfFormat = 0;
2676 pfe.ptd = NULL;
2677 pfe.dwAspect = DVASPECT_CONTENT;
2678 pfe.lindex = -1;
2679 pfe.tymed = TYMED_NULL;
2680 hres = IOleCache_Cache(pOleCache, &pfe, ADVF_PRIMEFIRST, &dwConnection);
2681 }
2682 else
2683 hres = IOleCache_Cache(pOleCache, pFormatEtc, ADVF_PRIMEFIRST, &dwConnection);
2684 IOleCache_Release(pOleCache);
2685 }
2686 }
2687 }
2688
2689 if (FAILED(hres) && pUnk)
2690 {
2691 IUnknown_Release(pUnk);
2692 pUnk = NULL;
2693 }
2694
2695 *ppvObj = pUnk;
2696
2697 TRACE("-- %p\n", pUnk);
2698 return hres;
2699 }
2700
2701 /******************************************************************************
2702 * OleGetAutoConvert [OLE32.@]
2703 */
OleGetAutoConvert(REFCLSID clsidOld,LPCLSID pClsidNew)2704 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2705 {
2706 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2707 HKEY hkey = NULL;
2708 WCHAR buf[CHARS_IN_GUID];
2709 LONG len;
2710 HRESULT res = S_OK;
2711
2712 res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey);
2713 if (FAILED(res))
2714 goto done;
2715
2716 len = sizeof(buf);
2717 if (RegQueryValueW(hkey, NULL, buf, &len))
2718 {
2719 res = REGDB_E_KEYMISSING;
2720 goto done;
2721 }
2722 res = CLSIDFromString(buf, pClsidNew);
2723 done:
2724 if (hkey) RegCloseKey(hkey);
2725 return res;
2726 }
2727
2728 /******************************************************************************
2729 * OleSetAutoConvert [OLE32.@]
2730 */
OleSetAutoConvert(REFCLSID clsidOld,REFCLSID clsidNew)2731 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
2732 {
2733 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2734 HKEY hkey = NULL;
2735 WCHAR szClsidNew[CHARS_IN_GUID];
2736 HRESULT res = S_OK;
2737
2738 TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
2739
2740 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2741 if (FAILED(res))
2742 goto done;
2743 StringFromGUID2(clsidNew, szClsidNew, CHARS_IN_GUID);
2744 if (RegSetValueW(hkey, wszAutoConvertTo, REG_SZ, szClsidNew, (lstrlenW(szClsidNew)+1) * sizeof(WCHAR)))
2745 {
2746 res = REGDB_E_WRITEREGDB;
2747 goto done;
2748 }
2749
2750 done:
2751 if (hkey) RegCloseKey(hkey);
2752 return res;
2753 }
2754
2755 /******************************************************************************
2756 * OleDoAutoConvert [OLE32.@]
2757 */
OleDoAutoConvert(LPSTORAGE pStg,LPCLSID pClsidNew)2758 HRESULT WINAPI OleDoAutoConvert(LPSTORAGE pStg, LPCLSID pClsidNew)
2759 {
2760 WCHAR *user_type_old, *user_type_new;
2761 CLIPFORMAT cf;
2762 STATSTG stat;
2763 CLSID clsid;
2764 HRESULT hr;
2765
2766 TRACE("(%p, %p)\n", pStg, pClsidNew);
2767
2768 *pClsidNew = CLSID_NULL;
2769 if(!pStg)
2770 return E_INVALIDARG;
2771 hr = IStorage_Stat(pStg, &stat, STATFLAG_NONAME);
2772 if(FAILED(hr))
2773 return hr;
2774
2775 *pClsidNew = stat.clsid;
2776 hr = OleGetAutoConvert(&stat.clsid, &clsid);
2777 if(FAILED(hr))
2778 return hr;
2779
2780 hr = IStorage_SetClass(pStg, &clsid);
2781 if(FAILED(hr))
2782 return hr;
2783
2784 hr = ReadFmtUserTypeStg(pStg, &cf, &user_type_old);
2785 if(FAILED(hr)) {
2786 cf = 0;
2787 user_type_new = NULL;
2788 }
2789
2790 hr = OleRegGetUserType(&clsid, USERCLASSTYPE_FULL, &user_type_new);
2791 if(FAILED(hr))
2792 user_type_new = NULL;
2793
2794 hr = WriteFmtUserTypeStg(pStg, cf, user_type_new);
2795 CoTaskMemFree(user_type_new);
2796 if(FAILED(hr))
2797 {
2798 CoTaskMemFree(user_type_old);
2799 IStorage_SetClass(pStg, &stat.clsid);
2800 return hr;
2801 }
2802
2803 hr = SetConvertStg(pStg, TRUE);
2804 if(FAILED(hr))
2805 {
2806 WriteFmtUserTypeStg(pStg, cf, user_type_old);
2807 IStorage_SetClass(pStg, &stat.clsid);
2808 }
2809 else
2810 *pClsidNew = clsid;
2811 CoTaskMemFree(user_type_old);
2812 return hr;
2813 }
2814
2815 /******************************************************************************
2816 * OleIsRunning [OLE32.@]
2817 */
OleIsRunning(LPOLEOBJECT object)2818 BOOL WINAPI OleIsRunning(LPOLEOBJECT object)
2819 {
2820 IRunnableObject *pRunnable;
2821 HRESULT hr;
2822 BOOL running;
2823
2824 TRACE("(%p)\n", object);
2825
2826 if (!object) return FALSE;
2827
2828 hr = IOleObject_QueryInterface(object, &IID_IRunnableObject, (void **)&pRunnable);
2829 if (FAILED(hr))
2830 return TRUE;
2831 running = IRunnableObject_IsRunning(pRunnable);
2832 IRunnableObject_Release(pRunnable);
2833 return running;
2834 }
2835
2836 /***********************************************************************
2837 * OleNoteObjectVisible [OLE32.@]
2838 */
OleNoteObjectVisible(LPUNKNOWN pUnknown,BOOL bVisible)2839 HRESULT WINAPI OleNoteObjectVisible(LPUNKNOWN pUnknown, BOOL bVisible)
2840 {
2841 TRACE("(%p, %s)\n", pUnknown, bVisible ? "TRUE" : "FALSE");
2842 return CoLockObjectExternal(pUnknown, bVisible, TRUE);
2843 }
2844
2845
2846 /***********************************************************************
2847 * OLE_FreeClipDataArray [internal]
2848 *
2849 * NOTES:
2850 * frees the data associated with an array of CLIPDATAs
2851 */
OLE_FreeClipDataArray(ULONG count,CLIPDATA * pClipDataArray)2852 static void OLE_FreeClipDataArray(ULONG count, CLIPDATA * pClipDataArray)
2853 {
2854 ULONG i;
2855 for (i = 0; i < count; i++)
2856 CoTaskMemFree(pClipDataArray[i].pClipData);
2857 }
2858
2859 /***********************************************************************
2860 * PropSysAllocString [OLE32.@]
2861 * NOTES
2862 * Forward to oleaut32.
2863 */
PropSysAllocString(LPCOLESTR str)2864 BSTR WINAPI PropSysAllocString(LPCOLESTR str)
2865 {
2866 return SysAllocString(str);
2867 }
2868
2869 /***********************************************************************
2870 * PropSysFreeString [OLE32.@]
2871 * NOTES
2872 * Forward to oleaut32.
2873 */
PropSysFreeString(LPOLESTR str)2874 void WINAPI PropSysFreeString(LPOLESTR str)
2875 {
2876 SysFreeString(str);
2877 }
2878
2879 /******************************************************************************
2880 * Check if a PROPVARIANT's type is valid.
2881 */
PROPVARIANT_ValidateType(VARTYPE vt)2882 static inline HRESULT PROPVARIANT_ValidateType(VARTYPE vt)
2883 {
2884 switch (vt)
2885 {
2886 case VT_EMPTY:
2887 case VT_NULL:
2888 case VT_I1:
2889 case VT_I2:
2890 case VT_I4:
2891 case VT_I8:
2892 case VT_R4:
2893 case VT_R8:
2894 case VT_CY:
2895 case VT_DATE:
2896 case VT_BSTR:
2897 case VT_ERROR:
2898 case VT_BOOL:
2899 case VT_DECIMAL:
2900 case VT_UI1:
2901 case VT_UI2:
2902 case VT_UI4:
2903 case VT_UI8:
2904 case VT_INT:
2905 case VT_UINT:
2906 case VT_LPSTR:
2907 case VT_LPWSTR:
2908 case VT_FILETIME:
2909 case VT_BLOB:
2910 case VT_DISPATCH:
2911 case VT_UNKNOWN:
2912 case VT_STREAM:
2913 case VT_STORAGE:
2914 case VT_STREAMED_OBJECT:
2915 case VT_STORED_OBJECT:
2916 case VT_BLOB_OBJECT:
2917 case VT_CF:
2918 case VT_CLSID:
2919 case VT_I1|VT_VECTOR:
2920 case VT_I2|VT_VECTOR:
2921 case VT_I4|VT_VECTOR:
2922 case VT_I8|VT_VECTOR:
2923 case VT_R4|VT_VECTOR:
2924 case VT_R8|VT_VECTOR:
2925 case VT_CY|VT_VECTOR:
2926 case VT_DATE|VT_VECTOR:
2927 case VT_BSTR|VT_VECTOR:
2928 case VT_ERROR|VT_VECTOR:
2929 case VT_BOOL|VT_VECTOR:
2930 case VT_VARIANT|VT_VECTOR:
2931 case VT_UI1|VT_VECTOR:
2932 case VT_UI2|VT_VECTOR:
2933 case VT_UI4|VT_VECTOR:
2934 case VT_UI8|VT_VECTOR:
2935 case VT_LPSTR|VT_VECTOR:
2936 case VT_LPWSTR|VT_VECTOR:
2937 case VT_FILETIME|VT_VECTOR:
2938 case VT_CF|VT_VECTOR:
2939 case VT_CLSID|VT_VECTOR:
2940 case VT_ARRAY|VT_I1:
2941 case VT_ARRAY|VT_UI1:
2942 case VT_ARRAY|VT_I2:
2943 case VT_ARRAY|VT_UI2:
2944 case VT_ARRAY|VT_I4:
2945 case VT_ARRAY|VT_UI4:
2946 case VT_ARRAY|VT_INT:
2947 case VT_ARRAY|VT_UINT:
2948 case VT_ARRAY|VT_R4:
2949 case VT_ARRAY|VT_R8:
2950 case VT_ARRAY|VT_CY:
2951 case VT_ARRAY|VT_DATE:
2952 case VT_ARRAY|VT_BSTR:
2953 case VT_ARRAY|VT_BOOL:
2954 case VT_ARRAY|VT_DECIMAL:
2955 case VT_ARRAY|VT_DISPATCH:
2956 case VT_ARRAY|VT_UNKNOWN:
2957 case VT_ARRAY|VT_ERROR:
2958 case VT_ARRAY|VT_VARIANT:
2959 return S_OK;
2960 }
2961 WARN("Bad type %d\n", vt);
2962 return STG_E_INVALIDPARAMETER;
2963 }
2964
2965 /***********************************************************************
2966 * PropVariantClear [OLE32.@]
2967 */
PropVariantClear(PROPVARIANT * pvar)2968 HRESULT WINAPI PropVariantClear(PROPVARIANT * pvar) /* [in/out] */
2969 {
2970 HRESULT hr;
2971
2972 TRACE("(%p)\n", pvar);
2973
2974 if (!pvar)
2975 return S_OK;
2976
2977 hr = PROPVARIANT_ValidateType(pvar->vt);
2978 if (FAILED(hr))
2979 {
2980 memset(pvar, 0, sizeof(*pvar));
2981 return hr;
2982 }
2983
2984 switch(pvar->vt)
2985 {
2986 case VT_EMPTY:
2987 case VT_NULL:
2988 case VT_I1:
2989 case VT_I2:
2990 case VT_I4:
2991 case VT_I8:
2992 case VT_R4:
2993 case VT_R8:
2994 case VT_CY:
2995 case VT_DATE:
2996 case VT_ERROR:
2997 case VT_BOOL:
2998 case VT_DECIMAL:
2999 case VT_UI1:
3000 case VT_UI2:
3001 case VT_UI4:
3002 case VT_UI8:
3003 case VT_INT:
3004 case VT_UINT:
3005 case VT_FILETIME:
3006 break;
3007 case VT_DISPATCH:
3008 case VT_UNKNOWN:
3009 case VT_STREAM:
3010 case VT_STREAMED_OBJECT:
3011 case VT_STORAGE:
3012 case VT_STORED_OBJECT:
3013 if (pvar->u.pStream)
3014 IStream_Release(pvar->u.pStream);
3015 break;
3016 case VT_CLSID:
3017 case VT_LPSTR:
3018 case VT_LPWSTR:
3019 /* pick an arbitrary typed pointer - we don't care about the type
3020 * as we are just freeing it */
3021 CoTaskMemFree(pvar->u.puuid);
3022 break;
3023 case VT_BLOB:
3024 case VT_BLOB_OBJECT:
3025 CoTaskMemFree(pvar->u.blob.pBlobData);
3026 break;
3027 case VT_BSTR:
3028 PropSysFreeString(pvar->u.bstrVal);
3029 break;
3030 case VT_CF:
3031 if (pvar->u.pclipdata)
3032 {
3033 OLE_FreeClipDataArray(1, pvar->u.pclipdata);
3034 CoTaskMemFree(pvar->u.pclipdata);
3035 }
3036 break;
3037 default:
3038 if (pvar->vt & VT_VECTOR)
3039 {
3040 ULONG i;
3041
3042 switch (pvar->vt & ~VT_VECTOR)
3043 {
3044 case VT_VARIANT:
3045 FreePropVariantArray(pvar->u.capropvar.cElems, pvar->u.capropvar.pElems);
3046 break;
3047 case VT_CF:
3048 OLE_FreeClipDataArray(pvar->u.caclipdata.cElems, pvar->u.caclipdata.pElems);
3049 break;
3050 case VT_BSTR:
3051 for (i = 0; i < pvar->u.cabstr.cElems; i++)
3052 PropSysFreeString(pvar->u.cabstr.pElems[i]);
3053 break;
3054 case VT_LPSTR:
3055 for (i = 0; i < pvar->u.calpstr.cElems; i++)
3056 CoTaskMemFree(pvar->u.calpstr.pElems[i]);
3057 break;
3058 case VT_LPWSTR:
3059 for (i = 0; i < pvar->u.calpwstr.cElems; i++)
3060 CoTaskMemFree(pvar->u.calpwstr.pElems[i]);
3061 break;
3062 }
3063 if (pvar->vt & ~VT_VECTOR)
3064 {
3065 /* pick an arbitrary VT_VECTOR structure - they all have the same
3066 * memory layout */
3067 CoTaskMemFree(pvar->u.capropvar.pElems);
3068 }
3069 }
3070 else if (pvar->vt & VT_ARRAY)
3071 hr = SafeArrayDestroy(pvar->u.parray);
3072 else
3073 {
3074 WARN("Invalid/unsupported type %d\n", pvar->vt);
3075 hr = STG_E_INVALIDPARAMETER;
3076 }
3077 }
3078
3079 memset(pvar, 0, sizeof(*pvar));
3080 return hr;
3081 }
3082
3083 /***********************************************************************
3084 * PropVariantCopy [OLE32.@]
3085 */
PropVariantCopy(PROPVARIANT * pvarDest,const PROPVARIANT * pvarSrc)3086 HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, /* [out] */
3087 const PROPVARIANT *pvarSrc) /* [in] */
3088 {
3089 ULONG len;
3090 HRESULT hr;
3091
3092 TRACE("(%p, %p vt %04x)\n", pvarDest, pvarSrc, pvarSrc->vt);
3093
3094 hr = PROPVARIANT_ValidateType(pvarSrc->vt);
3095 if (FAILED(hr))
3096 return DISP_E_BADVARTYPE;
3097
3098 /* this will deal with most cases */
3099 *pvarDest = *pvarSrc;
3100
3101 switch(pvarSrc->vt)
3102 {
3103 case VT_EMPTY:
3104 case VT_NULL:
3105 case VT_I1:
3106 case VT_UI1:
3107 case VT_I2:
3108 case VT_UI2:
3109 case VT_BOOL:
3110 case VT_DECIMAL:
3111 case VT_I4:
3112 case VT_UI4:
3113 case VT_R4:
3114 case VT_ERROR:
3115 case VT_I8:
3116 case VT_UI8:
3117 case VT_INT:
3118 case VT_UINT:
3119 case VT_R8:
3120 case VT_CY:
3121 case VT_DATE:
3122 case VT_FILETIME:
3123 break;
3124 case VT_DISPATCH:
3125 case VT_UNKNOWN:
3126 case VT_STREAM:
3127 case VT_STREAMED_OBJECT:
3128 case VT_STORAGE:
3129 case VT_STORED_OBJECT:
3130 if (pvarDest->u.pStream)
3131 IStream_AddRef(pvarDest->u.pStream);
3132 break;
3133 case VT_CLSID:
3134 pvarDest->u.puuid = CoTaskMemAlloc(sizeof(CLSID));
3135 *pvarDest->u.puuid = *pvarSrc->u.puuid;
3136 break;
3137 case VT_LPSTR:
3138 if (pvarSrc->u.pszVal)
3139 {
3140 len = strlen(pvarSrc->u.pszVal);
3141 pvarDest->u.pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR));
3142 CopyMemory(pvarDest->u.pszVal, pvarSrc->u.pszVal, (len+1)*sizeof(CHAR));
3143 }
3144 break;
3145 case VT_LPWSTR:
3146 if (pvarSrc->u.pwszVal)
3147 {
3148 len = lstrlenW(pvarSrc->u.pwszVal);
3149 pvarDest->u.pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
3150 CopyMemory(pvarDest->u.pwszVal, pvarSrc->u.pwszVal, (len+1)*sizeof(WCHAR));
3151 }
3152 break;
3153 case VT_BLOB:
3154 case VT_BLOB_OBJECT:
3155 if (pvarSrc->u.blob.pBlobData)
3156 {
3157 len = pvarSrc->u.blob.cbSize;
3158 pvarDest->u.blob.pBlobData = CoTaskMemAlloc(len);
3159 CopyMemory(pvarDest->u.blob.pBlobData, pvarSrc->u.blob.pBlobData, len);
3160 }
3161 break;
3162 case VT_BSTR:
3163 pvarDest->u.bstrVal = PropSysAllocString(pvarSrc->u.bstrVal);
3164 break;
3165 case VT_CF:
3166 if (pvarSrc->u.pclipdata)
3167 {
3168 len = pvarSrc->u.pclipdata->cbSize - sizeof(pvarSrc->u.pclipdata->ulClipFmt);
3169 pvarDest->u.pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA));
3170 pvarDest->u.pclipdata->cbSize = pvarSrc->u.pclipdata->cbSize;
3171 pvarDest->u.pclipdata->ulClipFmt = pvarSrc->u.pclipdata->ulClipFmt;
3172 pvarDest->u.pclipdata->pClipData = CoTaskMemAlloc(len);
3173 CopyMemory(pvarDest->u.pclipdata->pClipData, pvarSrc->u.pclipdata->pClipData, len);
3174 }
3175 break;
3176 default:
3177 if (pvarSrc->vt & VT_VECTOR)
3178 {
3179 int elemSize;
3180 ULONG i;
3181
3182 switch(pvarSrc->vt & ~VT_VECTOR)
3183 {
3184 case VT_I1: elemSize = sizeof(pvarSrc->u.cVal); break;
3185 case VT_UI1: elemSize = sizeof(pvarSrc->u.bVal); break;
3186 case VT_I2: elemSize = sizeof(pvarSrc->u.iVal); break;
3187 case VT_UI2: elemSize = sizeof(pvarSrc->u.uiVal); break;
3188 case VT_BOOL: elemSize = sizeof(pvarSrc->u.boolVal); break;
3189 case VT_I4: elemSize = sizeof(pvarSrc->u.lVal); break;
3190 case VT_UI4: elemSize = sizeof(pvarSrc->u.ulVal); break;
3191 case VT_R4: elemSize = sizeof(pvarSrc->u.fltVal); break;
3192 case VT_R8: elemSize = sizeof(pvarSrc->u.dblVal); break;
3193 case VT_ERROR: elemSize = sizeof(pvarSrc->u.scode); break;
3194 case VT_I8: elemSize = sizeof(pvarSrc->u.hVal); break;
3195 case VT_UI8: elemSize = sizeof(pvarSrc->u.uhVal); break;
3196 case VT_CY: elemSize = sizeof(pvarSrc->u.cyVal); break;
3197 case VT_DATE: elemSize = sizeof(pvarSrc->u.date); break;
3198 case VT_FILETIME: elemSize = sizeof(pvarSrc->u.filetime); break;
3199 case VT_CLSID: elemSize = sizeof(*pvarSrc->u.puuid); break;
3200 case VT_CF: elemSize = sizeof(*pvarSrc->u.pclipdata); break;
3201 case VT_BSTR: elemSize = sizeof(pvarSrc->u.bstrVal); break;
3202 case VT_LPSTR: elemSize = sizeof(pvarSrc->u.pszVal); break;
3203 case VT_LPWSTR: elemSize = sizeof(pvarSrc->u.pwszVal); break;
3204 case VT_VARIANT: elemSize = sizeof(*pvarSrc->u.pvarVal); break;
3205
3206 default:
3207 FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR);
3208 return E_INVALIDARG;
3209 }
3210 len = pvarSrc->u.capropvar.cElems;
3211 pvarDest->u.capropvar.pElems = len ? CoTaskMemAlloc(len * elemSize) : NULL;
3212 if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT))
3213 {
3214 for (i = 0; i < len; i++)
3215 PropVariantCopy(&pvarDest->u.capropvar.pElems[i], &pvarSrc->u.capropvar.pElems[i]);
3216 }
3217 else if (pvarSrc->vt == (VT_VECTOR | VT_CF))
3218 {
3219 FIXME("Copy clipformats\n");
3220 }
3221 else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR))
3222 {
3223 for (i = 0; i < len; i++)
3224 pvarDest->u.cabstr.pElems[i] = PropSysAllocString(pvarSrc->u.cabstr.pElems[i]);
3225 }
3226 else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
3227 {
3228 size_t strLen;
3229 for (i = 0; i < len; i++)
3230 {
3231 strLen = lstrlenA(pvarSrc->u.calpstr.pElems[i]) + 1;
3232 pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
3233 memcpy(pvarDest->u.calpstr.pElems[i],
3234 pvarSrc->u.calpstr.pElems[i], strLen);
3235 }
3236 }
3237 else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR))
3238 {
3239 size_t strLen;
3240 for (i = 0; i < len; i++)
3241 {
3242 strLen = (lstrlenW(pvarSrc->u.calpwstr.pElems[i]) + 1) *
3243 sizeof(WCHAR);
3244 pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
3245 memcpy(pvarDest->u.calpstr.pElems[i],
3246 pvarSrc->u.calpstr.pElems[i], strLen);
3247 }
3248 }
3249 else
3250 CopyMemory(pvarDest->u.capropvar.pElems, pvarSrc->u.capropvar.pElems, len * elemSize);
3251 }
3252 else if (pvarSrc->vt & VT_ARRAY)
3253 {
3254 pvarDest->u.uhVal.QuadPart = 0;
3255 return SafeArrayCopy(pvarSrc->u.parray, &pvarDest->u.parray);
3256 }
3257 else
3258 WARN("Invalid/unsupported type %d\n", pvarSrc->vt);
3259 }
3260
3261 return S_OK;
3262 }
3263
3264 /***********************************************************************
3265 * FreePropVariantArray [OLE32.@]
3266 */
FreePropVariantArray(ULONG cVariants,PROPVARIANT * rgvars)3267 HRESULT WINAPI FreePropVariantArray(ULONG cVariants, /* [in] */
3268 PROPVARIANT *rgvars) /* [in/out] */
3269 {
3270 ULONG i;
3271
3272 TRACE("(%u, %p)\n", cVariants, rgvars);
3273
3274 if (!rgvars)
3275 return E_INVALIDARG;
3276
3277 for(i = 0; i < cVariants; i++)
3278 PropVariantClear(&rgvars[i]);
3279
3280 return S_OK;
3281 }
3282
3283 /******************************************************************************
3284 * DllDebugObjectRPCHook (OLE32.@)
3285 * turns on and off internal debugging, pointer is only used on macintosh
3286 */
3287
DllDebugObjectRPCHook(BOOL b,void * dummy)3288 BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy)
3289 {
3290 FIXME("stub\n");
3291 return TRUE;
3292 }
3293