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