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