xref: /reactos/dll/win32/ole32/ole2.c (revision 53221834)
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  */
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  */
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  */
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  */
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  */
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  */
291 static inline BOOL is_droptarget(HWND hwnd)
292 {
293     return get_droptarget_handle(hwnd) != 0;
294 }
295 
296 #ifdef __REACTOS__
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  */
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  */
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  */
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 
400 static inline DropTargetWrapper* impl_from_IDropTarget(IDropTarget* iface)
401 {
402     return CONTAINING_RECORD(iface, DropTargetWrapper, IDropTarget_iface);
403 }
404 
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 
421 static ULONG WINAPI DropTargetWrapper_AddRef(IDropTarget* iface)
422 {
423     DropTargetWrapper* This = impl_from_IDropTarget(iface);
424     return InterlockedIncrement(&This->refs);
425 }
426 
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 
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 
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 
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 
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 
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 
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 
919 static inline EnumOLEVERB *impl_from_IEnumOLEVERB(IEnumOLEVERB *iface)
920 {
921     return CONTAINING_RECORD(iface, EnumOLEVERB, IEnumOLEVERB_iface);
922 }
923 
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 
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 
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 
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 
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 
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 
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 
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  */
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  */
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  */
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  */
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  */
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  */
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  */
1411 static void OLEMenu_Initialize(void)
1412 {
1413 }
1414 
1415 /***
1416  * OLEMenu_UnInitialize()
1417  *
1418  * Releases the OLEMENU data structures.
1419  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 
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__
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 
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 
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 
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 
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  */
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  */
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 
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
2864 BSTR WINAPI PropSysAllocString(LPCOLESTR str)
2865 {
2866     return SysAllocString(str);
2867 }
2868 
2869 /***********************************************************************
2870  *           PropSysFreeString			    [OLE32.@]
2871  * NOTES
2872  *  Forward to oleaut32.
2873  */
2874 void WINAPI PropSysFreeString(LPOLESTR str)
2875 {
2876     SysFreeString(str);
2877 }
2878 
2879 /******************************************************************************
2880  * Check if a PROPVARIANT's type is valid.
2881  */
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  */
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  */
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  */
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 
3288 BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy)
3289 {
3290   FIXME("stub\n");
3291   return TRUE;
3292 }
3293