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