ole32: Allocate the StorageImpl in StorageImpl_Construct.
[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 char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";
114
115 /*
116  * This is the head of the Drop target container.
117  */
118 static struct list targetListHead = LIST_INIT(targetListHead);
119
120 /******************************************************************************
121  * These are the prototypes of miscellaneous utility methods
122  */
123 static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue);
124
125 /******************************************************************************
126  * These are the prototypes of the utility methods used to manage a shared menu
127  */
128 static void OLEMenu_Initialize(void);
129 static void OLEMenu_UnInitialize(void);
130 static BOOL OLEMenu_InstallHooks( DWORD tid );
131 static BOOL OLEMenu_UnInstallHooks( DWORD tid );
132 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid );
133 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
134 static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor );
135 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam);
136 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam);
137
138 /******************************************************************************
139  * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c)
140  */
141 extern void OLEClipbrd_UnInitialize(void);
142 extern void OLEClipbrd_Initialize(void);
143
144 /******************************************************************************
145  * These are the prototypes of the utility methods used for OLE Drag n Drop
146  */
147 static void            OLEDD_Initialize(void);
148 static DropTargetNode* OLEDD_FindDropTarget(
149                          HWND hwndOfTarget);
150 static void            OLEDD_FreeDropTarget(DropTargetNode*, BOOL);
151 static LRESULT WINAPI  OLEDD_DragTrackerWindowProc(
152                          HWND   hwnd,
153                          UINT   uMsg,
154                          WPARAM wParam,
155                          LPARAM   lParam);
156 static void OLEDD_TrackMouseMove(
157                          TrackerWindowInfo* trackerInfo);
158 static void OLEDD_TrackStateChange(
159                          TrackerWindowInfo* trackerInfo);
160 static DWORD OLEDD_GetButtonState(void);
161
162
163 /******************************************************************************
164  *              OleBuildVersion [OLE32.@]
165  */
166 DWORD WINAPI OleBuildVersion(void)
167 {
168     TRACE("Returning version %d, build %d.\n", rmm, rup);
169     return (rmm<<16)+rup;
170 }
171
172 /***********************************************************************
173  *           OleInitialize       (OLE32.@)
174  */
175 HRESULT WINAPI OleInitialize(LPVOID reserved)
176 {
177   HRESULT hr;
178
179   TRACE("(%p)\n", reserved);
180
181   /*
182    * The first duty of the OleInitialize is to initialize the COM libraries.
183    */
184   hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
185
186   /*
187    * If the CoInitializeEx call failed, the OLE libraries can't be
188    * initialized.
189    */
190   if (FAILED(hr))
191     return hr;
192
193   if (!COM_CurrentInfo()->ole_inits)
194     hr = S_OK;
195
196   /*
197    * Then, it has to initialize the OLE specific modules.
198    * This includes:
199    *     Clipboard
200    *     Drag and Drop
201    *     Object linking and Embedding
202    *     In-place activation
203    */
204   if (!COM_CurrentInfo()->ole_inits++ &&
205       InterlockedIncrement(&OLE_moduleLockCount) == 1)
206   {
207     /*
208      * Initialize the libraries.
209      */
210     TRACE("() - Initializing the OLE libraries\n");
211
212     /*
213      * OLE Clipboard
214      */
215     OLEClipbrd_Initialize();
216
217     /*
218      * Drag and Drop
219      */
220     OLEDD_Initialize();
221
222     /*
223      * OLE shared menu
224      */
225     OLEMenu_Initialize();
226   }
227
228   return hr;
229 }
230
231 /******************************************************************************
232  *              OleUninitialize [OLE32.@]
233  */
234 void WINAPI OleUninitialize(void)
235 {
236   TRACE("()\n");
237
238   /*
239    * If we hit the bottom of the lock stack, free the libraries.
240    */
241   if (!--COM_CurrentInfo()->ole_inits && !InterlockedDecrement(&OLE_moduleLockCount))
242   {
243     /*
244      * Actually free the libraries.
245      */
246     TRACE("() - Freeing the last reference count\n");
247
248     /*
249      * OLE Clipboard
250      */
251     OLEClipbrd_UnInitialize();
252
253     /*
254      * OLE shared menu
255      */
256     OLEMenu_UnInitialize();
257   }
258
259   /*
260    * Then, uninitialize the COM libraries.
261    */
262   CoUninitialize();
263 }
264
265 /******************************************************************************
266  *              OleInitializeWOW        [OLE32.@]
267  */
268 HRESULT WINAPI OleInitializeWOW(DWORD x, DWORD y) {
269         FIXME("(0x%08x, 0x%08x),stub!\n",x, y);
270         return 0;
271 }
272
273 /***********************************************************************
274  *           RegisterDragDrop (OLE32.@)
275  */
276 HRESULT WINAPI RegisterDragDrop(
277         HWND hwnd,
278         LPDROPTARGET pDropTarget)
279 {
280   DropTargetNode* dropTargetInfo;
281
282   TRACE("(%p,%p)\n", hwnd, pDropTarget);
283
284   if (!COM_CurrentApt())
285   {
286     ERR("COM not initialized\n");
287     return E_OUTOFMEMORY;
288   }
289
290   if (!pDropTarget)
291     return E_INVALIDARG;
292
293   if (!IsWindow(hwnd))
294   {
295     ERR("invalid hwnd %p\n", hwnd);
296     return DRAGDROP_E_INVALIDHWND;
297   }
298
299   /*
300    * First, check if the window is already registered.
301    */
302   dropTargetInfo = OLEDD_FindDropTarget(hwnd);
303
304   if (dropTargetInfo!=NULL)
305     return DRAGDROP_E_ALREADYREGISTERED;
306
307   /*
308    * If it's not there, we can add it. We first create a node for it.
309    */
310   dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));
311
312   if (dropTargetInfo==NULL)
313     return E_OUTOFMEMORY;
314
315   dropTargetInfo->hwndTarget     = hwnd;
316
317   /*
318    * Don't forget that this is an interface pointer, need to nail it down since
319    * we keep a copy of it.
320    */
321   IDropTarget_AddRef(pDropTarget);
322   dropTargetInfo->dropTarget  = pDropTarget;
323
324   list_add_tail(&targetListHead, &dropTargetInfo->entry);
325
326   return S_OK;
327 }
328
329 /***********************************************************************
330  *           RevokeDragDrop (OLE32.@)
331  */
332 HRESULT WINAPI RevokeDragDrop(
333         HWND hwnd)
334 {
335   DropTargetNode* dropTargetInfo;
336
337   TRACE("(%p)\n", hwnd);
338
339   if (!IsWindow(hwnd))
340   {
341     ERR("invalid hwnd %p\n", hwnd);
342     return DRAGDROP_E_INVALIDHWND;
343   }
344
345   /*
346    * First, check if the window is already registered.
347    */
348   dropTargetInfo = OLEDD_FindDropTarget(hwnd);
349
350   /*
351    * If it ain't in there, it's an error.
352    */
353   if (dropTargetInfo==NULL)
354     return DRAGDROP_E_NOTREGISTERED;
355
356   OLEDD_FreeDropTarget(dropTargetInfo, TRUE);
357
358   return S_OK;
359 }
360
361 /***********************************************************************
362  *           OleRegGetUserType (OLE32.@)
363  *
364  * This implementation of OleRegGetUserType ignores the dwFormOfType
365  * parameter and always returns the full name of the object. This is
366  * not too bad since this is the case for many objects because of the
367  * way they are registered.
368  */
369 HRESULT WINAPI OleRegGetUserType(
370         REFCLSID clsid,
371         DWORD dwFormOfType,
372         LPOLESTR* pszUserType)
373 {
374   char    keyName[60];
375   DWORD   dwKeyType;
376   DWORD   cbData;
377   HKEY    clsidKey;
378   LONG    hres;
379   LPSTR   buffer;
380   HRESULT retVal;
381   /*
382    * Initialize the out parameter.
383    */
384   *pszUserType = NULL;
385
386   /*
387    * Build the key name we're looking for
388    */
389   sprintf( keyName, "CLSID\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
390            clsid->Data1, clsid->Data2, clsid->Data3,
391            clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
392            clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
393
394   TRACE("(%s, %d, %p)\n", keyName, dwFormOfType, pszUserType);
395
396   /*
397    * Open the class id Key
398    */
399   hres = RegOpenKeyA(HKEY_CLASSES_ROOT,
400                      keyName,
401                      &clsidKey);
402
403   if (hres != ERROR_SUCCESS)
404     return REGDB_E_CLASSNOTREG;
405
406   /*
407    * Retrieve the size of the name string.
408    */
409   cbData = 0;
410
411   hres = RegQueryValueExA(clsidKey,
412                           "",
413                           NULL,
414                           &dwKeyType,
415                           NULL,
416                           &cbData);
417
418   if (hres!=ERROR_SUCCESS)
419   {
420     RegCloseKey(clsidKey);
421     return REGDB_E_READREGDB;
422   }
423
424   /*
425    * Allocate a buffer for the registry value.
426    */
427   *pszUserType = CoTaskMemAlloc(cbData*2);
428
429   if (*pszUserType==NULL)
430   {
431     RegCloseKey(clsidKey);
432     return E_OUTOFMEMORY;
433   }
434
435   buffer = HeapAlloc(GetProcessHeap(), 0, cbData);
436
437   if (buffer == NULL)
438   {
439     RegCloseKey(clsidKey);
440     CoTaskMemFree(*pszUserType);
441     *pszUserType=NULL;
442     return E_OUTOFMEMORY;
443   }
444
445   hres = RegQueryValueExA(clsidKey,
446                           "",
447                           NULL,
448                           &dwKeyType,
449                           (LPBYTE) buffer,
450                           &cbData);
451
452   RegCloseKey(clsidKey);
453
454
455   if (hres!=ERROR_SUCCESS)
456   {
457     CoTaskMemFree(*pszUserType);
458     *pszUserType=NULL;
459
460     retVal = REGDB_E_READREGDB;
461   }
462   else
463   {
464     MultiByteToWideChar( CP_ACP, 0, buffer, -1, *pszUserType, cbData /*FIXME*/ );
465     retVal = S_OK;
466   }
467   HeapFree(GetProcessHeap(), 0, buffer);
468
469   return retVal;
470 }
471
472 /***********************************************************************
473  * DoDragDrop [OLE32.@]
474  */
475 HRESULT WINAPI DoDragDrop (
476   IDataObject *pDataObject,  /* [in] ptr to the data obj           */
477   IDropSource* pDropSource,  /* [in] ptr to the source obj         */
478   DWORD       dwOKEffect,    /* [in] effects allowed by the source */
479   DWORD       *pdwEffect)    /* [out] ptr to effects of the source */
480 {
481   TrackerWindowInfo trackerInfo;
482   HWND            hwndTrackWindow;
483   MSG             msg;
484
485   TRACE("(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
486
487   /*
488    * Setup the drag n drop tracking window.
489    */
490   if (!IsValidInterface((LPUNKNOWN)pDropSource))
491       return E_INVALIDARG;
492
493   trackerInfo.dataObject        = pDataObject;
494   trackerInfo.dropSource        = pDropSource;
495   trackerInfo.dwOKEffect        = dwOKEffect;
496   trackerInfo.pdwEffect         = pdwEffect;
497   trackerInfo.trackingDone      = FALSE;
498   trackerInfo.escPressed        = FALSE;
499   trackerInfo.curDragTargetHWND = 0;
500   trackerInfo.curTargetHWND     = 0;
501   trackerInfo.curDragTarget     = 0;
502
503   hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS, "TrackerWindow",
504                                   WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
505                                   CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0,
506                                   &trackerInfo);
507
508   if (hwndTrackWindow!=0)
509   {
510     /*
511      * Capture the mouse input
512      */
513     SetCapture(hwndTrackWindow);
514
515     msg.message = 0;
516
517     /*
518      * Pump messages. All mouse input should go to the capture window.
519      */
520     while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )
521     {
522       trackerInfo.curMousePos.x = msg.pt.x;
523       trackerInfo.curMousePos.y = msg.pt.y;
524       trackerInfo.dwKeyState = OLEDD_GetButtonState();
525             
526       if ( (msg.message >= WM_KEYFIRST) &&
527            (msg.message <= WM_KEYLAST) )
528       {
529         /*
530          * When keyboard messages are sent to windows on this thread, we
531          * want to ignore notify the drop source that the state changed.
532          * in the case of the Escape key, we also notify the drop source
533          * we give it a special meaning.
534          */
535         if ( (msg.message==WM_KEYDOWN) &&
536              (msg.wParam==VK_ESCAPE) )
537         {
538           trackerInfo.escPressed = TRUE;
539         }
540
541         /*
542          * Notify the drop source.
543          */
544         OLEDD_TrackStateChange(&trackerInfo);
545       }
546       else
547       {
548         /*
549          * Dispatch the messages only when it's not a keyboard message.
550          */
551         DispatchMessageA(&msg);
552       }
553     }
554
555     /* re-post the quit message to outer message loop */
556     if (msg.message == WM_QUIT)
557         PostQuitMessage(msg.wParam);
558     /*
559      * Destroy the temporary window.
560      */
561     DestroyWindow(hwndTrackWindow);
562
563     return trackerInfo.returnValue;
564   }
565
566   return E_FAIL;
567 }
568
569 /***********************************************************************
570  * OleQueryLinkFromData [OLE32.@]
571  */
572 HRESULT WINAPI OleQueryLinkFromData(
573   IDataObject* pSrcDataObject)
574 {
575   FIXME("(%p),stub!\n", pSrcDataObject);
576   return S_FALSE;
577 }
578
579 /***********************************************************************
580  * OleRegGetMiscStatus [OLE32.@]
581  */
582 HRESULT WINAPI OleRegGetMiscStatus(
583   REFCLSID clsid,
584   DWORD    dwAspect,
585   DWORD*   pdwStatus)
586 {
587   char    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   sprintf( keyName, "CLSID\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
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", keyName, dwAspect, pdwStatus);
607
608   /*
609    * Open the class id Key
610    */
611   result = RegOpenKeyA(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 = RegOpenKeyA(clsidKey,
622                        "MiscStatus",
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   sprintf(keyName, "%d", dwAspect);
641
642   result = RegOpenKeyA(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 = NULL;
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
1193   /* Install a thread scope message hook for WH_GETMESSAGE */
1194   pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc,
1195                                                0, GetCurrentThreadId() );
1196   if ( !pHookItem->GetMsg_hHook )
1197     goto CLEANUP;
1198
1199   /* Install a thread scope message hook for WH_CALLWNDPROC */
1200   pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc,
1201                                                     0, GetCurrentThreadId() );
1202   if ( !pHookItem->CallWndProc_hHook )
1203     goto CLEANUP;
1204
1205   /* Insert the hook table entry */
1206   pHookItem->next = hook_list;
1207   hook_list = pHookItem;
1208
1209   return TRUE;
1210
1211 CLEANUP:
1212   /* Unhook any hooks */
1213   if ( pHookItem->GetMsg_hHook )
1214     UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
1215   if ( pHookItem->CallWndProc_hHook )
1216     UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
1217   /* Release the hook table entry */
1218   HeapFree(pHookItem->hHeap, 0, pHookItem );
1219
1220   return FALSE;
1221 }
1222
1223 /*************************************************************************
1224  * OLEMenu_UnInstallHooks
1225  * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
1226  *
1227  * RETURNS: TRUE if message hooks were successfully installed
1228  *          FALSE on failure
1229  */
1230 static BOOL OLEMenu_UnInstallHooks( DWORD tid )
1231 {
1232   OleMenuHookItem *pHookItem = NULL;
1233   OleMenuHookItem **ppHook = &hook_list;
1234
1235   while (*ppHook)
1236   {
1237       if ((*ppHook)->tid == tid)
1238       {
1239           pHookItem = *ppHook;
1240           *ppHook = pHookItem->next;
1241           break;
1242       }
1243       ppHook = &(*ppHook)->next;
1244   }
1245   if (!pHookItem) return FALSE;
1246
1247   /* Uninstall the hooks installed for this thread */
1248   if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
1249     goto CLEANUP;
1250   if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
1251     goto CLEANUP;
1252
1253   /* Release the hook table entry */
1254   HeapFree(pHookItem->hHeap, 0, pHookItem );
1255
1256   return TRUE;
1257
1258 CLEANUP:
1259   /* Release the hook table entry */
1260   HeapFree(pHookItem->hHeap, 0, pHookItem );
1261
1262   return FALSE;
1263 }
1264
1265 /*************************************************************************
1266  * OLEMenu_IsHookInstalled
1267  * Tests if OLEMenu hooks have been installed for a thread
1268  *
1269  * RETURNS: The pointer and index of the hook table entry for the tid
1270  *          NULL and -1 for the index if no hooks were installed for this thread
1271  */
1272 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )
1273 {
1274   OleMenuHookItem *pHookItem = NULL;
1275
1276   /* Do a simple linear search for an entry whose tid matches ours.
1277    * We really need a map but efficiency is not a concern here. */
1278   for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next)
1279   {
1280     if ( tid == pHookItem->tid )
1281       return pHookItem;
1282   }
1283
1284   return NULL;
1285 }
1286
1287 /***********************************************************************
1288  *           OLEMenu_FindMainMenuIndex
1289  *
1290  * Used by OLEMenu API to find the top level group a menu item belongs to.
1291  * On success pnPos contains the index of the item in the top level menu group
1292  *
1293  * RETURNS: TRUE if the ID was found, FALSE on failure
1294  */
1295 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
1296 {
1297   INT i, nItems;
1298
1299   nItems = GetMenuItemCount( hMainMenu );
1300
1301   for (i = 0; i < nItems; i++)
1302   {
1303     HMENU hsubmenu;
1304
1305     /*  Is the current item a submenu? */
1306     if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
1307     {
1308       /* If the handle is the same we're done */
1309       if ( hsubmenu == hPopupMenu )
1310       {
1311         if (pnPos)
1312           *pnPos = i;
1313         return TRUE;
1314       }
1315       /* Recursively search without updating pnPos */
1316       else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
1317       {
1318         if (pnPos)
1319           *pnPos = i;
1320         return TRUE;
1321       }
1322     }
1323   }
1324
1325   return FALSE;
1326 }
1327
1328 /***********************************************************************
1329  *           OLEMenu_SetIsServerMenu
1330  *
1331  * Checks whether a popup menu belongs to a shared menu group which is
1332  * owned by the server, and sets the menu descriptor state accordingly.
1333  * All menu messages from these groups should be routed to the server.
1334  *
1335  * RETURNS: TRUE if the popup menu is part of a server owned group
1336  *          FALSE if the popup menu is part of a container owned group
1337  */
1338 static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
1339 {
1340   UINT nPos = 0, nWidth, i;
1341
1342   pOleMenuDescriptor->bIsServerItem = FALSE;
1343
1344   /* Don't bother searching if the popup is the combined menu itself */
1345   if ( hmenu == pOleMenuDescriptor->hmenuCombined )
1346     return FALSE;
1347
1348   /* Find the menu item index in the shared OLE menu that this item belongs to */
1349   if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu,  &nPos ) )
1350     return FALSE;
1351
1352   /* The group widths array has counts for the number of elements
1353    * in the groups File, Edit, Container, Object, Window, Help.
1354    * The Edit, Object & Help groups belong to the server object
1355    * and the other three belong to the container.
1356    * Loop through the group widths and locate the group we are a member of.
1357    */
1358   for ( i = 0, nWidth = 0; i < 6; i++ )
1359   {
1360     nWidth += pOleMenuDescriptor->mgw.width[i];
1361     if ( nPos < nWidth )
1362     {
1363       /* Odd elements are server menu widths */
1364       pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;
1365       break;
1366     }
1367   }
1368
1369   return pOleMenuDescriptor->bIsServerItem;
1370 }
1371
1372 /*************************************************************************
1373  * OLEMenu_CallWndProc
1374  * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
1375  * This is invoked from a message hook installed in OleSetMenuDescriptor.
1376  */
1377 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
1378 {
1379   LPCWPSTRUCT pMsg = NULL;
1380   HOLEMENU hOleMenu = 0;
1381   OleMenuDescriptor *pOleMenuDescriptor = NULL;
1382   OleMenuHookItem *pHookItem = NULL;
1383   WORD fuFlags;
1384
1385   TRACE("%i, %04lx, %08lx\n", code, wParam, lParam );
1386
1387   /* Check if we're being asked to process the message */
1388   if ( HC_ACTION != code )
1389     goto NEXTHOOK;
1390
1391   /* Retrieve the current message being dispatched from lParam */
1392   pMsg = (LPCWPSTRUCT)lParam;
1393
1394   /* Check if the message is destined for a window we are interested in:
1395    * If the window has an OLEMenu property we may need to dispatch
1396    * the menu message to its active objects window instead. */
1397
1398   hOleMenu = GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1399   if ( !hOleMenu )
1400     goto NEXTHOOK;
1401
1402   /* Get the menu descriptor */
1403   pOleMenuDescriptor = GlobalLock( hOleMenu );
1404   if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1405     goto NEXTHOOK;
1406
1407   /* Process menu messages */
1408   switch( pMsg->message )
1409   {
1410     case WM_INITMENU:
1411     {
1412       /* Reset the menu descriptor state */
1413       pOleMenuDescriptor->bIsServerItem = FALSE;
1414
1415       /* Send this message to the server as well */
1416       SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1417                   pMsg->message, pMsg->wParam, pMsg->lParam );
1418       goto NEXTHOOK;
1419     }
1420
1421     case WM_INITMENUPOPUP:
1422     {
1423       /* Save the state for whether this is a server owned menu */
1424       OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
1425       break;
1426     }
1427
1428     case WM_MENUSELECT:
1429     {
1430       fuFlags = HIWORD(pMsg->wParam);  /* Get flags */
1431       if ( fuFlags & MF_SYSMENU )
1432          goto NEXTHOOK;
1433
1434       /* Save the state for whether this is a server owned popup menu */
1435       else if ( fuFlags & MF_POPUP )
1436         OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
1437
1438       break;
1439     }
1440
1441     case WM_DRAWITEM:
1442     {
1443       LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
1444       if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
1445         goto NEXTHOOK;  /* Not a menu message */
1446
1447       break;
1448     }
1449
1450     default:
1451       goto NEXTHOOK;
1452   }
1453
1454   /* If the message was for the server dispatch it accordingly */
1455   if ( pOleMenuDescriptor->bIsServerItem )
1456   {
1457     SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1458                   pMsg->message, pMsg->wParam, pMsg->lParam );
1459   }
1460
1461 NEXTHOOK:
1462   if ( pOleMenuDescriptor )
1463     GlobalUnlock( hOleMenu );
1464
1465   /* Lookup the hook item for the current thread */
1466   if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1467   {
1468     /* This should never fail!! */
1469     WARN("could not retrieve hHook for current thread!\n" );
1470     return 0;
1471   }
1472
1473   /* Pass on the message to the next hooker */
1474   return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
1475 }
1476
1477 /*************************************************************************
1478  * OLEMenu_GetMsgProc
1479  * Thread scope WH_GETMESSAGE hook proc filter function (callback)
1480  * This is invoked from a message hook installed in OleSetMenuDescriptor.
1481  */
1482 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
1483 {
1484   LPMSG pMsg = NULL;
1485   HOLEMENU hOleMenu = 0;
1486   OleMenuDescriptor *pOleMenuDescriptor = NULL;
1487   OleMenuHookItem *pHookItem = NULL;
1488   WORD wCode;
1489
1490   TRACE("%i, %04lx, %08lx\n", code, wParam, lParam );
1491
1492   /* Check if we're being asked to process a  messages */
1493   if ( HC_ACTION != code )
1494     goto NEXTHOOK;
1495
1496   /* Retrieve the current message being dispatched from lParam */
1497   pMsg = (LPMSG)lParam;
1498
1499   /* Check if the message is destined for a window we are interested in:
1500    * If the window has an OLEMenu property we may need to dispatch
1501    * the menu message to its active objects window instead. */
1502
1503   hOleMenu = GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1504   if ( !hOleMenu )
1505     goto NEXTHOOK;
1506
1507   /* Process menu messages */
1508   switch( pMsg->message )
1509   {
1510     case WM_COMMAND:
1511     {
1512       wCode = HIWORD(pMsg->wParam);  /* Get notification code */
1513       if ( wCode )
1514         goto NEXTHOOK;  /* Not a menu message */
1515       break;
1516     }
1517     default:
1518       goto NEXTHOOK;
1519   }
1520
1521   /* Get the menu descriptor */
1522   pOleMenuDescriptor = GlobalLock( hOleMenu );
1523   if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1524     goto NEXTHOOK;
1525
1526   /* If the message was for the server dispatch it accordingly */
1527   if ( pOleMenuDescriptor->bIsServerItem )
1528   {
1529     /* Change the hWnd in the message to the active objects hWnd.
1530      * The message loop which reads this message will automatically
1531      * dispatch it to the embedded objects window. */
1532     pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
1533   }
1534
1535 NEXTHOOK:
1536   if ( pOleMenuDescriptor )
1537     GlobalUnlock( hOleMenu );
1538
1539   /* Lookup the hook item for the current thread */
1540   if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1541   {
1542     /* This should never fail!! */
1543     WARN("could not retrieve hHook for current thread!\n" );
1544     return FALSE;
1545   }
1546
1547   /* Pass on the message to the next hooker */
1548   return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
1549 }
1550
1551 /***********************************************************************
1552  * OleCreateMenuDescriptor [OLE32.@]
1553  * Creates an OLE menu descriptor for OLE to use when dispatching
1554  * menu messages and commands.
1555  *
1556  * PARAMS:
1557  *    hmenuCombined  -  Handle to the objects combined menu
1558  *    lpMenuWidths   -  Pointer to array of 6 LONG's indicating menus per group
1559  *
1560  */
1561 HOLEMENU WINAPI OleCreateMenuDescriptor(
1562   HMENU                hmenuCombined,
1563   LPOLEMENUGROUPWIDTHS lpMenuWidths)
1564 {
1565   HOLEMENU hOleMenu;
1566   OleMenuDescriptor *pOleMenuDescriptor;
1567   int i;
1568
1569   if ( !hmenuCombined || !lpMenuWidths )
1570     return 0;
1571
1572   /* Create an OLE menu descriptor */
1573   if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
1574                                 sizeof(OleMenuDescriptor) ) ) )
1575   return 0;
1576
1577   pOleMenuDescriptor = GlobalLock( hOleMenu );
1578   if ( !pOleMenuDescriptor )
1579     return 0;
1580
1581   /* Initialize menu group widths and hmenu */
1582   for ( i = 0; i < 6; i++ )
1583     pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
1584
1585   pOleMenuDescriptor->hmenuCombined = hmenuCombined;
1586   pOleMenuDescriptor->bIsServerItem = FALSE;
1587   GlobalUnlock( hOleMenu );
1588
1589   return hOleMenu;
1590 }
1591
1592 /***********************************************************************
1593  * OleDestroyMenuDescriptor [OLE32.@]
1594  * Destroy the shared menu descriptor
1595  */
1596 HRESULT WINAPI OleDestroyMenuDescriptor(
1597   HOLEMENU hmenuDescriptor)
1598 {
1599   if ( hmenuDescriptor )
1600     GlobalFree( hmenuDescriptor );
1601         return S_OK;
1602 }
1603
1604 /***********************************************************************
1605  * OleSetMenuDescriptor [OLE32.@]
1606  * Installs or removes OLE dispatching code for the containers frame window.
1607  *
1608  * PARAMS
1609  *     hOleMenu         Handle to composite menu descriptor
1610  *     hwndFrame        Handle to containers frame window
1611  *     hwndActiveObject Handle to objects in-place activation window
1612  *     lpFrame          Pointer to IOleInPlaceFrame on containers window
1613  *     lpActiveObject   Pointer to IOleInPlaceActiveObject on active in-place object
1614  *
1615  * RETURNS
1616  *      S_OK                               - menu installed correctly
1617  *      E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1618  *
1619  * FIXME
1620  *      The lpFrame and lpActiveObject parameters are currently ignored
1621  *      OLE should install context sensitive help F1 filtering for the app when
1622  *      these are non null.
1623  */
1624 HRESULT WINAPI OleSetMenuDescriptor(
1625   HOLEMENU               hOleMenu,
1626   HWND                   hwndFrame,
1627   HWND                   hwndActiveObject,
1628   LPOLEINPLACEFRAME        lpFrame,
1629   LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1630 {
1631   OleMenuDescriptor *pOleMenuDescriptor = NULL;
1632
1633   /* Check args */
1634   if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
1635     return E_INVALIDARG;
1636
1637   if ( lpFrame || lpActiveObject )
1638   {
1639      FIXME("(%p, %p, %p, %p, %p), Context sensitive help filtering not implemented!\n",
1640         hOleMenu,
1641         hwndFrame,
1642         hwndActiveObject,
1643         lpFrame,
1644         lpActiveObject);
1645   }
1646
1647   /* Set up a message hook to intercept the containers frame window messages.
1648    * The message filter is responsible for dispatching menu messages from the
1649    * shared menu which are intended for the object.
1650    */
1651
1652   if ( hOleMenu )  /* Want to install dispatching code */
1653   {
1654     /* If OLEMenu hooks are already installed for this thread, fail
1655      * Note: This effectively means that OleSetMenuDescriptor cannot
1656      * be called twice in succession on the same frame window
1657      * without first calling it with a null hOleMenu to uninstall */
1658     if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) )
1659   return E_FAIL;
1660
1661     /* Get the menu descriptor */
1662     pOleMenuDescriptor = GlobalLock( hOleMenu );
1663     if ( !pOleMenuDescriptor )
1664       return E_UNEXPECTED;
1665
1666     /* Update the menu descriptor */
1667     pOleMenuDescriptor->hwndFrame = hwndFrame;
1668     pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
1669
1670     GlobalUnlock( hOleMenu );
1671     pOleMenuDescriptor = NULL;
1672
1673     /* Add a menu descriptor windows property to the frame window */
1674     SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu );
1675
1676     /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
1677     if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
1678       return E_FAIL;
1679   }
1680   else  /* Want to uninstall dispatching code */
1681   {
1682     /* Uninstall the hooks */
1683     if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1684       return E_FAIL;
1685
1686     /* Remove the menu descriptor property from the frame window */
1687     RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" );
1688   }
1689
1690   return S_OK;
1691 }
1692
1693 /******************************************************************************
1694  *              IsAccelerator        [OLE32.@]
1695  * Mostly copied from controls/menu.c TranslateAccelerator implementation
1696  */
1697 BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd)
1698 {
1699     LPACCEL lpAccelTbl;
1700     int i;
1701
1702     if(!lpMsg) return FALSE;
1703     if (!hAccel)
1704     {
1705         WARN_(accel)("NULL accel handle\n");
1706         return FALSE;
1707     }
1708     if((lpMsg->message != WM_KEYDOWN &&
1709         lpMsg->message != WM_SYSKEYDOWN &&
1710         lpMsg->message != WM_SYSCHAR &&
1711         lpMsg->message != WM_CHAR)) return FALSE;
1712     lpAccelTbl = HeapAlloc(GetProcessHeap(), 0, cAccelEntries * sizeof(ACCEL));
1713     if (NULL == lpAccelTbl)
1714     {
1715         return FALSE;
1716     }
1717     if (CopyAcceleratorTableW(hAccel, lpAccelTbl, cAccelEntries) != cAccelEntries)
1718     {
1719         WARN_(accel)("CopyAcceleratorTableW failed\n");
1720         HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1721         return FALSE;
1722     }
1723
1724     TRACE_(accel)("hAccel=%p, cAccelEntries=%d,"
1725                 "msg->hwnd=%p, msg->message=%04x, wParam=%08lx, lParam=%08lx\n",
1726                 hAccel, cAccelEntries,
1727                 lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);
1728     for(i = 0; i < cAccelEntries; i++)
1729     {
1730         if(lpAccelTbl[i].key != lpMsg->wParam)
1731             continue;
1732
1733         if(lpMsg->message == WM_CHAR)
1734         {
1735             if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY))
1736             {
1737                 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", LOWORD(lpMsg->wParam) & 0xff);
1738                 goto found;
1739             }
1740         }
1741         else
1742         {
1743             if(lpAccelTbl[i].fVirt & FVIRTKEY)
1744             {
1745                 INT mask = 0;
1746                 TRACE_(accel)("found accel for virt_key %04lx (scan %04x)\n",
1747                                 lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff);
1748                 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
1749                 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
1750                 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
1751                 if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
1752                 TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n");
1753             }
1754             else
1755             {
1756                 if(!(lpMsg->lParam & 0x01000000))  /* no special_key */
1757                 {
1758                     if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000))
1759                     {                                                  /* ^^ ALT pressed */
1760                         TRACE_(accel)("found accel for Alt-%c\n", LOWORD(lpMsg->wParam) & 0xff);
1761                         goto found;
1762                     }
1763                 }
1764             }
1765         }
1766     }
1767
1768     WARN_(accel)("couldn't translate accelerator key\n");
1769     HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1770     return FALSE;
1771
1772 found:
1773     if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd;
1774     HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1775     return TRUE;
1776 }
1777
1778 /***********************************************************************
1779  * ReleaseStgMedium [OLE32.@]
1780  */
1781 void WINAPI ReleaseStgMedium(
1782   STGMEDIUM* pmedium)
1783 {
1784   switch (pmedium->tymed)
1785   {
1786     case TYMED_HGLOBAL:
1787     {
1788       if ( (pmedium->pUnkForRelease==0) &&
1789            (pmedium->u.hGlobal!=0) )
1790         GlobalFree(pmedium->u.hGlobal);
1791       break;
1792     }
1793     case TYMED_FILE:
1794     {
1795       if (pmedium->u.lpszFileName!=0)
1796       {
1797         if (pmedium->pUnkForRelease==0)
1798         {
1799           DeleteFileW(pmedium->u.lpszFileName);
1800         }
1801
1802         CoTaskMemFree(pmedium->u.lpszFileName);
1803       }
1804       break;
1805     }
1806     case TYMED_ISTREAM:
1807     {
1808       if (pmedium->u.pstm!=0)
1809       {
1810         IStream_Release(pmedium->u.pstm);
1811       }
1812       break;
1813     }
1814     case TYMED_ISTORAGE:
1815     {
1816       if (pmedium->u.pstg!=0)
1817       {
1818         IStorage_Release(pmedium->u.pstg);
1819       }
1820       break;
1821     }
1822     case TYMED_GDI:
1823     {
1824       if ( (pmedium->pUnkForRelease==0) &&
1825            (pmedium->u.hBitmap!=0) )
1826         DeleteObject(pmedium->u.hBitmap);
1827       break;
1828     }
1829     case TYMED_MFPICT:
1830     {
1831       if ( (pmedium->pUnkForRelease==0) &&
1832            (pmedium->u.hMetaFilePict!=0) )
1833       {
1834         LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hMetaFilePict);
1835         DeleteMetaFile(pMP->hMF);
1836         GlobalUnlock(pmedium->u.hMetaFilePict);
1837         GlobalFree(pmedium->u.hMetaFilePict);
1838       }
1839       break;
1840     }
1841     case TYMED_ENHMF:
1842     {
1843       if ( (pmedium->pUnkForRelease==0) &&
1844            (pmedium->u.hEnhMetaFile!=0) )
1845       {
1846         DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
1847       }
1848       break;
1849     }
1850     case TYMED_NULL:
1851     default:
1852       break;
1853   }
1854   pmedium->tymed=TYMED_NULL;
1855
1856   /*
1857    * After cleaning up, the unknown is released
1858    */
1859   if (pmedium->pUnkForRelease!=0)
1860   {
1861     IUnknown_Release(pmedium->pUnkForRelease);
1862     pmedium->pUnkForRelease = 0;
1863   }
1864 }
1865
1866 /***
1867  * OLEDD_Initialize()
1868  *
1869  * Initializes the OLE drag and drop data structures.
1870  */
1871 static void OLEDD_Initialize(void)
1872 {
1873     WNDCLASSA wndClass;
1874
1875     ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1876     wndClass.style         = CS_GLOBALCLASS;
1877     wndClass.lpfnWndProc   = OLEDD_DragTrackerWindowProc;
1878     wndClass.cbClsExtra    = 0;
1879     wndClass.cbWndExtra    = sizeof(TrackerWindowInfo*);
1880     wndClass.hCursor       = 0;
1881     wndClass.hbrBackground = 0;
1882     wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
1883
1884     RegisterClassA (&wndClass);
1885 }
1886
1887 /***
1888  * OLEDD_FreeDropTarget()
1889  *
1890  * Frees the drag and drop data structure
1891  */
1892 static void OLEDD_FreeDropTarget(DropTargetNode *dropTargetInfo, BOOL release_drop_target)
1893 {
1894   list_remove(&dropTargetInfo->entry);
1895   if (release_drop_target) IDropTarget_Release(dropTargetInfo->dropTarget);
1896   HeapFree(GetProcessHeap(), 0, dropTargetInfo);
1897 }
1898
1899 /***
1900  * OLEDD_UnInitialize()
1901  *
1902  * Releases the OLE drag and drop data structures.
1903  */
1904 void OLEDD_UnInitialize(void)
1905 {
1906   /*
1907    * Simply empty the list.
1908    */
1909   while (!list_empty(&targetListHead))
1910   {
1911     DropTargetNode* curNode = LIST_ENTRY(list_head(&targetListHead), DropTargetNode, entry);
1912     OLEDD_FreeDropTarget(curNode, FALSE);
1913   }
1914 }
1915
1916 /***
1917  * OLEDD_FindDropTarget()
1918  *
1919  * Finds information about the drop target.
1920  */
1921 static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
1922 {
1923   DropTargetNode*  curNode;
1924
1925   /*
1926    * Iterate the list to find the HWND value.
1927    */
1928   LIST_FOR_EACH_ENTRY(curNode, &targetListHead, DropTargetNode, entry)
1929     if (hwndOfTarget==curNode->hwndTarget)
1930       return curNode;
1931
1932   /*
1933    * If we get here, the item is not in the list
1934    */
1935   return NULL;
1936 }
1937
1938 /***
1939  * OLEDD_DragTrackerWindowProc()
1940  *
1941  * This method is the WindowProcedure of the drag n drop tracking
1942  * window. During a drag n Drop operation, an invisible window is created
1943  * to receive the user input and act upon it. This procedure is in charge
1944  * of this behavior.
1945  */
1946
1947 #define DRAG_TIMER_ID 1
1948
1949 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
1950                          HWND   hwnd,
1951                          UINT   uMsg,
1952                          WPARAM wParam,
1953                          LPARAM   lParam)
1954 {
1955   switch (uMsg)
1956   {
1957     case WM_CREATE:
1958     {
1959       LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
1960
1961       SetWindowLongPtrA(hwnd, 0, (LONG_PTR)createStruct->lpCreateParams);
1962       SetTimer(hwnd, DRAG_TIMER_ID, 50, NULL);
1963
1964       break;
1965     }
1966     case WM_TIMER:
1967     case WM_MOUSEMOVE:
1968     {
1969       OLEDD_TrackMouseMove((TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0));
1970       break;
1971     }
1972     case WM_LBUTTONUP:
1973     case WM_MBUTTONUP:
1974     case WM_RBUTTONUP:
1975     case WM_LBUTTONDOWN:
1976     case WM_MBUTTONDOWN:
1977     case WM_RBUTTONDOWN:
1978     {
1979       OLEDD_TrackStateChange((TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0));
1980       break;
1981     }
1982     case WM_DESTROY:
1983     {
1984       KillTimer(hwnd, DRAG_TIMER_ID);
1985       break;
1986     }
1987   }
1988
1989   /*
1990    * This is a window proc after all. Let's call the default.
1991    */
1992   return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1993 }
1994
1995 /***
1996  * OLEDD_TrackMouseMove()
1997  *
1998  * This method is invoked while a drag and drop operation is in effect.
1999  * it will generate the appropriate callbacks in the drop source
2000  * and drop target. It will also provide the expected feedback to
2001  * the user.
2002  *
2003  * params:
2004  *    trackerInfo - Pointer to the structure identifying the
2005  *                  drag & drop operation that is currently
2006  *                  active.
2007  */
2008 static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo)
2009 {
2010   HWND   hwndNewTarget = 0;
2011   HRESULT  hr = S_OK;
2012   POINT pt;
2013
2014   /*
2015    * Get the handle of the window under the mouse
2016    */
2017   pt.x = trackerInfo->curMousePos.x;
2018   pt.y = trackerInfo->curMousePos.y;
2019   hwndNewTarget = WindowFromPoint(pt);
2020
2021   /*
2022    * Every time, we re-initialize the effects passed to the
2023    * IDropTarget to the effects allowed by the source.
2024    */
2025   *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
2026
2027   /*
2028    * If we are hovering over the same target as before, send the
2029    * DragOver notification
2030    */
2031   if ( (trackerInfo->curDragTarget != 0) &&
2032        (trackerInfo->curTargetHWND == hwndNewTarget) )
2033   {
2034     IDropTarget_DragOver(trackerInfo->curDragTarget,
2035                          trackerInfo->dwKeyState,
2036                          trackerInfo->curMousePos,
2037                          trackerInfo->pdwEffect);
2038   }
2039   else
2040   {
2041     DropTargetNode* newDropTargetNode = 0;
2042
2043     /*
2044      * If we changed window, we have to notify our old target and check for
2045      * the new one.
2046      */
2047     if (trackerInfo->curDragTarget!=0)
2048     {
2049       IDropTarget_DragLeave(trackerInfo->curDragTarget);
2050     }
2051
2052     /*
2053      * Make sure we're hovering over a window.
2054      */
2055     if (hwndNewTarget!=0)
2056     {
2057       /*
2058        * Find-out if there is a drag target under the mouse
2059        */
2060       HWND nexttar = hwndNewTarget;
2061       trackerInfo->curTargetHWND = hwndNewTarget;
2062
2063       do {
2064         newDropTargetNode = OLEDD_FindDropTarget(nexttar);
2065       } while (!newDropTargetNode && (nexttar = GetParent(nexttar)) != 0);
2066       if(nexttar) hwndNewTarget = nexttar;
2067
2068       trackerInfo->curDragTargetHWND = hwndNewTarget;
2069       trackerInfo->curDragTarget     = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
2070
2071       /*
2072        * If there is, notify it that we just dragged-in
2073        */
2074       if (trackerInfo->curDragTarget!=0)
2075       {
2076         IDropTarget_DragEnter(trackerInfo->curDragTarget,
2077                               trackerInfo->dataObject,
2078                               trackerInfo->dwKeyState,
2079                               trackerInfo->curMousePos,
2080                               trackerInfo->pdwEffect);
2081       }
2082     }
2083     else
2084     {
2085       /*
2086        * The mouse is not over a window so we don't track anything.
2087        */
2088       trackerInfo->curDragTargetHWND = 0;
2089       trackerInfo->curTargetHWND     = 0;
2090       trackerInfo->curDragTarget     = 0;
2091     }
2092   }
2093
2094   /*
2095    * Now that we have done that, we have to tell the source to give
2096    * us feedback on the work being done by the target.  If we don't
2097    * have a target, simulate no effect.
2098    */
2099   if (trackerInfo->curDragTarget==0)
2100   {
2101     *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2102   }
2103
2104   hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
2105                                 *trackerInfo->pdwEffect);
2106
2107   /*
2108    * When we ask for feedback from the drop source, sometimes it will
2109    * do all the necessary work and sometimes it will not handle it
2110    * when that's the case, we must display the standard drag and drop
2111    * cursors.
2112    */
2113   if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
2114   {
2115     if (*trackerInfo->pdwEffect & DROPEFFECT_MOVE)
2116     {
2117       SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(1)));
2118     }
2119     else if (*trackerInfo->pdwEffect & DROPEFFECT_COPY)
2120     {
2121       SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(2)));
2122     }
2123     else if (*trackerInfo->pdwEffect & DROPEFFECT_LINK)
2124     {
2125       SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(3)));
2126     }
2127     else
2128     {
2129       SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(0)));
2130     }
2131   }
2132 }
2133
2134 /***
2135  * OLEDD_TrackStateChange()
2136  *
2137  * This method is invoked while a drag and drop operation is in effect.
2138  * It is used to notify the drop target/drop source callbacks when
2139  * the state of the keyboard or mouse button change.
2140  *
2141  * params:
2142  *    trackerInfo - Pointer to the structure identifying the
2143  *                  drag & drop operation that is currently
2144  *                  active.
2145  */
2146 static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo)
2147 {
2148   /*
2149    * Ask the drop source what to do with the operation.
2150    */
2151   trackerInfo->returnValue = IDropSource_QueryContinueDrag(
2152                                trackerInfo->dropSource,
2153                                trackerInfo->escPressed,
2154                                trackerInfo->dwKeyState);
2155
2156   /*
2157    * All the return valued will stop the operation except the S_OK
2158    * return value.
2159    */
2160   if (trackerInfo->returnValue!=S_OK)
2161   {
2162     /*
2163      * Make sure the message loop in DoDragDrop stops
2164      */
2165     trackerInfo->trackingDone = TRUE;
2166
2167     /*
2168      * Release the mouse in case the drop target decides to show a popup
2169      * or a menu or something.
2170      */
2171     ReleaseCapture();
2172
2173     /*
2174      * If we end-up over a target, drop the object in the target or
2175      * inform the target that the operation was cancelled.
2176      */
2177     if (trackerInfo->curDragTarget!=0)
2178     {
2179       switch (trackerInfo->returnValue)
2180       {
2181         /*
2182          * If the source wants us to complete the operation, we tell
2183          * the drop target that we just dropped the object in it.
2184          */
2185         case DRAGDROP_S_DROP:
2186         {
2187           IDropTarget_Drop(trackerInfo->curDragTarget,
2188                            trackerInfo->dataObject,
2189                            trackerInfo->dwKeyState,
2190                            trackerInfo->curMousePos,
2191                            trackerInfo->pdwEffect);
2192           break;
2193         }
2194         /*
2195          * If the source told us that we should cancel, fool the drop
2196          * target by telling it that the mouse left it's window.
2197          * Also set the drop effect to "NONE" in case the application
2198          * ignores the result of DoDragDrop.
2199          */
2200         case DRAGDROP_S_CANCEL:
2201           IDropTarget_DragLeave(trackerInfo->curDragTarget);
2202           *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2203           break;
2204       }
2205     }
2206   }
2207 }
2208
2209 /***
2210  * OLEDD_GetButtonState()
2211  *
2212  * This method will use the current state of the keyboard to build
2213  * a button state mask equivalent to the one passed in the
2214  * WM_MOUSEMOVE wParam.
2215  */
2216 static DWORD OLEDD_GetButtonState(void)
2217 {
2218   BYTE  keyboardState[256];
2219   DWORD keyMask = 0;
2220
2221   GetKeyboardState(keyboardState);
2222
2223   if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
2224     keyMask |= MK_SHIFT;
2225
2226   if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
2227     keyMask |= MK_CONTROL;
2228
2229   if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
2230     keyMask |= MK_LBUTTON;
2231
2232   if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
2233     keyMask |= MK_RBUTTON;
2234
2235   if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
2236     keyMask |= MK_MBUTTON;
2237
2238   return keyMask;
2239 }
2240
2241 /***
2242  * OLEDD_GetButtonState()
2243  *
2244  * This method will read the default value of the registry key in
2245  * parameter and extract a DWORD value from it. The registry key value
2246  * can be in a string key or a DWORD key.
2247  *
2248  * params:
2249  *     regKey   - Key to read the default value from
2250  *     pdwValue - Pointer to the location where the DWORD
2251  *                value is returned. This value is not modified
2252  *                if the value is not found.
2253  */
2254
2255 static void OLEUTL_ReadRegistryDWORDValue(
2256   HKEY   regKey,
2257   DWORD* pdwValue)
2258 {
2259   char  buffer[20];
2260   DWORD dwKeyType;
2261   DWORD cbData = 20;
2262   LONG  lres;
2263
2264   lres = RegQueryValueExA(regKey,
2265                           "",
2266                           NULL,
2267                           &dwKeyType,
2268                           (LPBYTE)buffer,
2269                           &cbData);
2270
2271   if (lres==ERROR_SUCCESS)
2272   {
2273     switch (dwKeyType)
2274     {
2275       case REG_DWORD:
2276         *pdwValue = *(DWORD*)buffer;
2277         break;
2278       case REG_EXPAND_SZ:
2279       case REG_MULTI_SZ:
2280       case REG_SZ:
2281         *pdwValue = (DWORD)strtoul(buffer, NULL, 10);
2282         break;
2283     }
2284   }
2285 }
2286
2287 /******************************************************************************
2288  * OleDraw (OLE32.@)
2289  *
2290  * The operation of this function is documented literally in the WinAPI
2291  * documentation to involve a QueryInterface for the IViewObject interface,
2292  * followed by a call to IViewObject::Draw.
2293  */
2294 HRESULT WINAPI OleDraw(
2295         IUnknown *pUnk,
2296         DWORD dwAspect,
2297         HDC hdcDraw,
2298         LPCRECT lprcBounds)
2299 {
2300   HRESULT hres;
2301   IViewObject *viewobject;
2302
2303   hres = IUnknown_QueryInterface(pUnk,
2304                                  &IID_IViewObject,
2305                                  (void**)&viewobject);
2306
2307   if (SUCCEEDED(hres))
2308   {
2309     RECTL rectl;
2310
2311     rectl.left = lprcBounds->left;
2312     rectl.right = lprcBounds->right;
2313     rectl.top = lprcBounds->top;
2314     rectl.bottom = lprcBounds->bottom;
2315     hres = IViewObject_Draw(viewobject, dwAspect, -1, 0, 0, 0, hdcDraw, &rectl, 0, 0, 0);
2316
2317     IViewObject_Release(viewobject);
2318     return hres;
2319   }
2320   else
2321   {
2322     return DV_E_NOIVIEWOBJECT;
2323   }
2324 }
2325
2326 /***********************************************************************
2327  *             OleTranslateAccelerator [OLE32.@]
2328  */
2329 HRESULT WINAPI OleTranslateAccelerator (LPOLEINPLACEFRAME lpFrame,
2330                    LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpmsg)
2331 {
2332     WORD wID;
2333
2334     TRACE("(%p,%p,%p)\n", lpFrame, lpFrameInfo, lpmsg);
2335
2336     if (IsAccelerator(lpFrameInfo->haccel,lpFrameInfo->cAccelEntries,lpmsg,&wID))
2337         return IOleInPlaceFrame_TranslateAccelerator(lpFrame,lpmsg,wID);
2338
2339     return S_FALSE;
2340 }
2341
2342 /******************************************************************************
2343  *              OleCreate        [OLE32.@]
2344  *
2345  */
2346 HRESULT WINAPI OleCreate(
2347         REFCLSID rclsid,
2348         REFIID riid,
2349         DWORD renderopt,
2350         LPFORMATETC pFormatEtc,
2351         LPOLECLIENTSITE pClientSite,
2352         LPSTORAGE pStg,
2353         LPVOID* ppvObj)
2354 {
2355     HRESULT hres;
2356     IUnknown * pUnk = NULL;
2357     IOleObject *pOleObject = NULL;
2358
2359     TRACE("(%s, %s, %d, %p, %p, %p, %p)\n", debugstr_guid(rclsid),
2360         debugstr_guid(riid), renderopt, pFormatEtc, pClientSite, pStg, ppvObj);
2361
2362     hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, riid, (LPVOID*)&pUnk);
2363
2364     if (SUCCEEDED(hres))
2365         hres = IStorage_SetClass(pStg, rclsid);
2366
2367     if (pClientSite && SUCCEEDED(hres))
2368     {
2369         hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (LPVOID*)&pOleObject);
2370         if (SUCCEEDED(hres))
2371         {
2372             DWORD dwStatus;
2373             hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
2374         }
2375     }
2376
2377     if (SUCCEEDED(hres))
2378     {
2379         IPersistStorage * pPS;
2380         if (SUCCEEDED((hres = IUnknown_QueryInterface(pUnk, &IID_IPersistStorage, (LPVOID*)&pPS))))
2381         {
2382             TRACE("trying to set stg %p\n", pStg);
2383             hres = IPersistStorage_InitNew(pPS, pStg);
2384             TRACE("-- result 0x%08x\n", hres);
2385             IPersistStorage_Release(pPS);
2386         }
2387     }
2388
2389     if (pClientSite && SUCCEEDED(hres))
2390     {
2391         TRACE("trying to set clientsite %p\n", pClientSite);
2392         hres = IOleObject_SetClientSite(pOleObject, pClientSite);
2393         TRACE("-- result 0x%08x\n", hres);
2394     }
2395
2396     if (pOleObject)
2397         IOleObject_Release(pOleObject);
2398
2399     if (((renderopt == OLERENDER_DRAW) || (renderopt == OLERENDER_FORMAT)) &&
2400         SUCCEEDED(hres))
2401     {
2402         IRunnableObject *pRunnable;
2403         IOleCache *pOleCache;
2404         HRESULT hres2;
2405
2406         hres2 = IUnknown_QueryInterface(pUnk, &IID_IRunnableObject, (void **)&pRunnable);
2407         if (SUCCEEDED(hres2))
2408         {
2409             hres = IRunnableObject_Run(pRunnable, NULL);
2410             IRunnableObject_Release(pRunnable);
2411         }
2412
2413         if (SUCCEEDED(hres))
2414         {
2415             hres2 = IUnknown_QueryInterface(pUnk, &IID_IOleCache, (void **)&pOleCache);
2416             if (SUCCEEDED(hres2))
2417             {
2418                 DWORD dwConnection;
2419                 hres = IOleCache_Cache(pOleCache, pFormatEtc, ADVF_PRIMEFIRST, &dwConnection);
2420                 IOleCache_Release(pOleCache);
2421             }
2422         }
2423     }
2424
2425     if (FAILED(hres) && pUnk)
2426     {
2427         IUnknown_Release(pUnk);
2428         pUnk = NULL;
2429     }
2430
2431     *ppvObj = pUnk;
2432
2433     TRACE("-- %p\n", pUnk);
2434     return hres;
2435 }
2436
2437 /******************************************************************************
2438  *              OleGetAutoConvert        [OLE32.@]
2439  */
2440 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2441 {
2442     static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2443     HKEY hkey = NULL;
2444     WCHAR buf[CHARS_IN_GUID];
2445     LONG len;
2446     HRESULT res = S_OK;
2447
2448     res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey);
2449     if (FAILED(res))
2450         goto done;
2451
2452     len = sizeof(buf);
2453     if (RegQueryValueW(hkey, NULL, buf, &len))
2454     {
2455         res = REGDB_E_KEYMISSING;
2456         goto done;
2457     }
2458     res = CLSIDFromString(buf, pClsidNew);
2459 done:
2460     if (hkey) RegCloseKey(hkey);
2461     return res;
2462 }
2463
2464 /******************************************************************************
2465  *              OleSetAutoConvert        [OLE32.@]
2466  */
2467 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
2468 {
2469     static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2470     HKEY hkey = NULL;
2471     WCHAR szClsidNew[CHARS_IN_GUID];
2472     HRESULT res = S_OK;
2473
2474     TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
2475     
2476     res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2477     if (FAILED(res))
2478         goto done;
2479     StringFromGUID2(clsidNew, szClsidNew, CHARS_IN_GUID);
2480     if (RegSetValueW(hkey, wszAutoConvertTo, REG_SZ, szClsidNew, (strlenW(szClsidNew)+1) * sizeof(WCHAR)))
2481     {
2482         res = REGDB_E_WRITEREGDB;
2483         goto done;
2484     }
2485
2486 done:
2487     if (hkey) RegCloseKey(hkey);
2488     return res;
2489 }
2490
2491 /******************************************************************************
2492  *              OleDoAutoConvert        [OLE32.@]
2493  */
2494 HRESULT WINAPI OleDoAutoConvert(LPSTORAGE pStg, LPCLSID pClsidNew)
2495 {
2496     FIXME("(%p,%p) : stub\n",pStg,pClsidNew);
2497     return E_NOTIMPL;
2498 }
2499
2500 /******************************************************************************
2501  *              OleIsRunning        [OLE32.@]
2502  */
2503 BOOL WINAPI OleIsRunning(LPOLEOBJECT pObject)
2504 {
2505     IRunnableObject *pRunnable;
2506     HRESULT hr;
2507     BOOL running;
2508
2509     TRACE("(%p)\n", pObject);
2510
2511     hr = IOleObject_QueryInterface(pObject, &IID_IRunnableObject, (void **)&pRunnable);
2512     if (FAILED(hr))
2513         return TRUE;
2514     running = IRunnableObject_IsRunning(pRunnable);
2515     IRunnableObject_Release(pRunnable);
2516     return running;
2517 }
2518
2519 /***********************************************************************
2520  *           OleNoteObjectVisible                           [OLE32.@]
2521  */
2522 HRESULT WINAPI OleNoteObjectVisible(LPUNKNOWN pUnknown, BOOL bVisible)
2523 {
2524     TRACE("(%p, %s)\n", pUnknown, bVisible ? "TRUE" : "FALSE");
2525     return CoLockObjectExternal(pUnknown, bVisible, TRUE);
2526 }
2527
2528
2529 /***********************************************************************
2530  *           OLE_FreeClipDataArray   [internal]
2531  *
2532  * NOTES:
2533  *  frees the data associated with an array of CLIPDATAs
2534  */
2535 static void OLE_FreeClipDataArray(ULONG count, CLIPDATA * pClipDataArray)
2536 {
2537     ULONG i;
2538     for (i = 0; i < count; i++)
2539         if (pClipDataArray[i].pClipData)
2540             CoTaskMemFree(pClipDataArray[i].pClipData);
2541 }
2542
2543 /***********************************************************************
2544  *           PropSysAllocString                     [OLE32.@]
2545  * NOTES:
2546  *  Basically a copy of SysAllocStringLen.
2547  */
2548 BSTR WINAPI PropSysAllocString(LPCOLESTR str)
2549 {
2550     DWORD  bufferSize;
2551     DWORD* newBuffer;
2552     WCHAR* stringBuffer;
2553     int len;
2554
2555     if (!str) return 0;
2556
2557     len = lstrlenW(str);
2558     /*
2559      * Find the length of the buffer passed-in, in bytes.
2560      */
2561     bufferSize = len * sizeof (WCHAR);
2562
2563     /*
2564      * Allocate a new buffer to hold the string.
2565      * Don't forget to keep an empty spot at the beginning of the
2566      * buffer for the character count and an extra character at the
2567      * end for the NULL.
2568      */
2569     newBuffer = HeapAlloc(GetProcessHeap(), 0,
2570                           bufferSize + sizeof(WCHAR) + sizeof(DWORD));
2571
2572     /*
2573      * If the memory allocation failed, return a null pointer.
2574      */
2575     if (newBuffer==0)
2576       return 0;
2577
2578     /*
2579      * Copy the length of the string in the placeholder.
2580      */
2581     *newBuffer = bufferSize;
2582
2583     /*
2584      * Skip the byte count.
2585      */
2586     newBuffer++;
2587
2588     memcpy(newBuffer, str, bufferSize);
2589
2590     /*
2591      * Make sure that there is a nul character at the end of the
2592      * string.
2593      */
2594     stringBuffer = (WCHAR*)newBuffer;
2595     stringBuffer[len] = '\0';
2596
2597     return stringBuffer;
2598 }
2599
2600 /***********************************************************************
2601  *           PropSysFreeString                      [OLE32.@]
2602  * NOTES
2603  *  Copy of SysFreeString.
2604  */
2605 void WINAPI PropSysFreeString(LPOLESTR str)
2606 {
2607     DWORD* bufferPointer;
2608
2609     /* NULL is a valid parameter */
2610     if(!str) return;
2611
2612     /*
2613      * We have to be careful when we free a BSTR pointer, it points to
2614      * the beginning of the string but it skips the byte count contained
2615      * before the string.
2616      */
2617     bufferPointer = (DWORD*)str;
2618
2619     bufferPointer--;
2620
2621     /*
2622      * Free the memory from its "real" origin.
2623      */
2624     HeapFree(GetProcessHeap(), 0, bufferPointer);
2625 }
2626
2627 /******************************************************************************
2628  * Check if a PROPVARIANT's type is valid.
2629  */
2630 static inline HRESULT PROPVARIANT_ValidateType(VARTYPE vt)
2631 {
2632     switch (vt)
2633     {
2634     case VT_EMPTY:
2635     case VT_NULL:
2636     case VT_I2:
2637     case VT_I4:
2638     case VT_R4:
2639     case VT_R8:
2640     case VT_CY:
2641     case VT_DATE:
2642     case VT_BSTR:
2643     case VT_ERROR:
2644     case VT_BOOL:
2645     case VT_DECIMAL:
2646     case VT_UI1:
2647     case VT_UI2:
2648     case VT_UI4:
2649     case VT_I8:
2650     case VT_UI8:
2651     case VT_LPSTR:
2652     case VT_LPWSTR:
2653     case VT_FILETIME:
2654     case VT_BLOB:
2655     case VT_STREAM:
2656     case VT_STORAGE:
2657     case VT_STREAMED_OBJECT:
2658     case VT_STORED_OBJECT:
2659     case VT_BLOB_OBJECT:
2660     case VT_CF:
2661     case VT_CLSID:
2662     case VT_I2|VT_VECTOR:
2663     case VT_I4|VT_VECTOR:
2664     case VT_R4|VT_VECTOR:
2665     case VT_R8|VT_VECTOR:
2666     case VT_CY|VT_VECTOR:
2667     case VT_DATE|VT_VECTOR:
2668     case VT_BSTR|VT_VECTOR:
2669     case VT_ERROR|VT_VECTOR:
2670     case VT_BOOL|VT_VECTOR:
2671     case VT_VARIANT|VT_VECTOR:
2672     case VT_UI1|VT_VECTOR:
2673     case VT_UI2|VT_VECTOR:
2674     case VT_UI4|VT_VECTOR:
2675     case VT_I8|VT_VECTOR:
2676     case VT_UI8|VT_VECTOR:
2677     case VT_LPSTR|VT_VECTOR:
2678     case VT_LPWSTR|VT_VECTOR:
2679     case VT_FILETIME|VT_VECTOR:
2680     case VT_CF|VT_VECTOR:
2681     case VT_CLSID|VT_VECTOR:
2682         return S_OK;
2683     }
2684     WARN("Bad type %d\n", vt);
2685     return STG_E_INVALIDPARAMETER;
2686 }
2687
2688 /***********************************************************************
2689  *           PropVariantClear                       [OLE32.@]
2690  */
2691 HRESULT WINAPI PropVariantClear(PROPVARIANT * pvar) /* [in/out] */
2692 {
2693     HRESULT hr;
2694
2695     TRACE("(%p)\n", pvar);
2696
2697     if (!pvar)
2698         return S_OK;
2699
2700     hr = PROPVARIANT_ValidateType(pvar->vt);
2701     if (FAILED(hr))
2702         return hr;
2703
2704     switch(pvar->vt)
2705     {
2706     case VT_EMPTY:
2707     case VT_NULL:
2708     case VT_I2:
2709     case VT_I4:
2710     case VT_R4:
2711     case VT_R8:
2712     case VT_CY:
2713     case VT_DATE:
2714     case VT_ERROR:
2715     case VT_BOOL:
2716     case VT_DECIMAL:
2717     case VT_UI1:
2718     case VT_UI2:
2719     case VT_UI4:
2720     case VT_I8:
2721     case VT_UI8:
2722     case VT_FILETIME:
2723         break;
2724     case VT_STREAM:
2725     case VT_STREAMED_OBJECT:
2726     case VT_STORAGE:
2727     case VT_STORED_OBJECT:
2728         if (pvar->u.pStream)
2729             IUnknown_Release(pvar->u.pStream);
2730         break;
2731     case VT_CLSID:
2732     case VT_LPSTR:
2733     case VT_LPWSTR:
2734         /* pick an arbitrary typed pointer - we don't care about the type
2735          * as we are just freeing it */
2736         CoTaskMemFree(pvar->u.puuid);
2737         break;
2738     case VT_BLOB:
2739     case VT_BLOB_OBJECT:
2740         CoTaskMemFree(pvar->u.blob.pBlobData);
2741         break;
2742     case VT_BSTR:
2743         if (pvar->u.bstrVal)
2744             PropSysFreeString(pvar->u.bstrVal);
2745         break;
2746     case VT_CF:
2747         if (pvar->u.pclipdata)
2748         {
2749             OLE_FreeClipDataArray(1, pvar->u.pclipdata);
2750             CoTaskMemFree(pvar->u.pclipdata);
2751         }
2752         break;
2753     default:
2754         if (pvar->vt & VT_VECTOR)
2755         {
2756             ULONG i;
2757
2758             switch (pvar->vt & ~VT_VECTOR)
2759             {
2760             case VT_VARIANT:
2761                 FreePropVariantArray(pvar->u.capropvar.cElems, pvar->u.capropvar.pElems);
2762                 break;
2763             case VT_CF:
2764                 OLE_FreeClipDataArray(pvar->u.caclipdata.cElems, pvar->u.caclipdata.pElems);
2765                 break;
2766             case VT_BSTR:
2767                 for (i = 0; i < pvar->u.cabstr.cElems; i++)
2768                     PropSysFreeString(pvar->u.cabstr.pElems[i]);
2769                 break;
2770             case VT_LPSTR:
2771                 for (i = 0; i < pvar->u.calpstr.cElems; i++)
2772                     CoTaskMemFree(pvar->u.calpstr.pElems[i]);
2773                 break;
2774             case VT_LPWSTR:
2775                 for (i = 0; i < pvar->u.calpwstr.cElems; i++)
2776                     CoTaskMemFree(pvar->u.calpwstr.pElems[i]);
2777                 break;
2778             }
2779             if (pvar->vt & ~VT_VECTOR)
2780             {
2781                 /* pick an arbitrary VT_VECTOR structure - they all have the same
2782                  * memory layout */
2783                 CoTaskMemFree(pvar->u.capropvar.pElems);
2784             }
2785         }
2786         else
2787             WARN("Invalid/unsupported type %d\n", pvar->vt);
2788     }
2789
2790     ZeroMemory(pvar, sizeof(*pvar));
2791
2792     return S_OK;
2793 }
2794
2795 /***********************************************************************
2796  *           PropVariantCopy                        [OLE32.@]
2797  */
2798 HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest,      /* [out] */
2799                                const PROPVARIANT *pvarSrc) /* [in] */
2800 {
2801     ULONG len;
2802     HRESULT hr;
2803
2804     TRACE("(%p, %p vt %04x)\n", pvarDest, pvarSrc, pvarSrc->vt);
2805
2806     hr = PROPVARIANT_ValidateType(pvarSrc->vt);
2807     if (FAILED(hr))
2808         return hr;
2809
2810     /* this will deal with most cases */
2811     *pvarDest = *pvarSrc;
2812
2813     switch(pvarSrc->vt)
2814     {
2815     case VT_EMPTY:
2816     case VT_NULL:
2817     case VT_I1:
2818     case VT_UI1:
2819     case VT_I2:
2820     case VT_UI2:
2821     case VT_BOOL:
2822     case VT_DECIMAL:
2823     case VT_I4:
2824     case VT_UI4:
2825     case VT_R4:
2826     case VT_ERROR:
2827     case VT_I8:
2828     case VT_UI8:
2829     case VT_R8:
2830     case VT_CY:
2831     case VT_DATE:
2832     case VT_FILETIME:
2833         break;
2834     case VT_STREAM:
2835     case VT_STREAMED_OBJECT:
2836     case VT_STORAGE:
2837     case VT_STORED_OBJECT:
2838         IUnknown_AddRef((LPUNKNOWN)pvarDest->u.pStream);
2839         break;
2840     case VT_CLSID:
2841         pvarDest->u.puuid = CoTaskMemAlloc(sizeof(CLSID));
2842         *pvarDest->u.puuid = *pvarSrc->u.puuid;
2843         break;
2844     case VT_LPSTR:
2845         len = strlen(pvarSrc->u.pszVal);
2846         pvarDest->u.pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR));
2847         CopyMemory(pvarDest->u.pszVal, pvarSrc->u.pszVal, (len+1)*sizeof(CHAR));
2848         break;
2849     case VT_LPWSTR:
2850         len = lstrlenW(pvarSrc->u.pwszVal);
2851         pvarDest->u.pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
2852         CopyMemory(pvarDest->u.pwszVal, pvarSrc->u.pwszVal, (len+1)*sizeof(WCHAR));
2853         break;
2854     case VT_BLOB:
2855     case VT_BLOB_OBJECT:
2856         if (pvarSrc->u.blob.pBlobData)
2857         {
2858             len = pvarSrc->u.blob.cbSize;
2859             pvarDest->u.blob.pBlobData = CoTaskMemAlloc(len);
2860             CopyMemory(pvarDest->u.blob.pBlobData, pvarSrc->u.blob.pBlobData, len);
2861         }
2862         break;
2863     case VT_BSTR:
2864         pvarDest->u.bstrVal = PropSysAllocString(pvarSrc->u.bstrVal);
2865         break;
2866     case VT_CF:
2867         if (pvarSrc->u.pclipdata)
2868         {
2869             len = pvarSrc->u.pclipdata->cbSize - sizeof(pvarSrc->u.pclipdata->ulClipFmt);
2870             pvarDest->u.pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA));
2871             pvarDest->u.pclipdata->cbSize = pvarSrc->u.pclipdata->cbSize;
2872             pvarDest->u.pclipdata->ulClipFmt = pvarSrc->u.pclipdata->ulClipFmt;
2873             pvarDest->u.pclipdata->pClipData = CoTaskMemAlloc(len);
2874             CopyMemory(pvarDest->u.pclipdata->pClipData, pvarSrc->u.pclipdata->pClipData, len);
2875         }
2876         break;
2877     default:
2878         if (pvarSrc->vt & VT_VECTOR)
2879         {
2880             int elemSize;
2881             ULONG i;
2882
2883             switch(pvarSrc->vt & ~VT_VECTOR)
2884             {
2885             case VT_I1:       elemSize = sizeof(pvarSrc->u.cVal); break;
2886             case VT_UI1:      elemSize = sizeof(pvarSrc->u.bVal); break;
2887             case VT_I2:       elemSize = sizeof(pvarSrc->u.iVal); break;
2888             case VT_UI2:      elemSize = sizeof(pvarSrc->u.uiVal); break;
2889             case VT_BOOL:     elemSize = sizeof(pvarSrc->u.boolVal); break;
2890             case VT_I4:       elemSize = sizeof(pvarSrc->u.lVal); break;
2891             case VT_UI4:      elemSize = sizeof(pvarSrc->u.ulVal); break;
2892             case VT_R4:       elemSize = sizeof(pvarSrc->u.fltVal); break;
2893             case VT_R8:       elemSize = sizeof(pvarSrc->u.dblVal); break;
2894             case VT_ERROR:    elemSize = sizeof(pvarSrc->u.scode); break;
2895             case VT_I8:       elemSize = sizeof(pvarSrc->u.hVal); break;
2896             case VT_UI8:      elemSize = sizeof(pvarSrc->u.uhVal); break;
2897             case VT_CY:       elemSize = sizeof(pvarSrc->u.cyVal); break;
2898             case VT_DATE:     elemSize = sizeof(pvarSrc->u.date); break;
2899             case VT_FILETIME: elemSize = sizeof(pvarSrc->u.filetime); break;
2900             case VT_CLSID:    elemSize = sizeof(*pvarSrc->u.puuid); break;
2901             case VT_CF:       elemSize = sizeof(*pvarSrc->u.pclipdata); break;
2902             case VT_BSTR:     elemSize = sizeof(pvarSrc->u.bstrVal); break;
2903             case VT_LPSTR:    elemSize = sizeof(pvarSrc->u.pszVal); break;
2904             case VT_LPWSTR:   elemSize = sizeof(pvarSrc->u.pwszVal); break;
2905             case VT_VARIANT:  elemSize = sizeof(*pvarSrc->u.pvarVal); break;
2906
2907             default:
2908                 FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR);
2909                 return E_INVALIDARG;
2910             }
2911             len = pvarSrc->u.capropvar.cElems;
2912             pvarDest->u.capropvar.pElems = CoTaskMemAlloc(len * elemSize);
2913             if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT))
2914             {
2915                 for (i = 0; i < len; i++)
2916                     PropVariantCopy(&pvarDest->u.capropvar.pElems[i], &pvarSrc->u.capropvar.pElems[i]);
2917             }
2918             else if (pvarSrc->vt == (VT_VECTOR | VT_CF))
2919             {
2920                 FIXME("Copy clipformats\n");
2921             }
2922             else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR))
2923             {
2924                 for (i = 0; i < len; i++)
2925                     pvarDest->u.cabstr.pElems[i] = PropSysAllocString(pvarSrc->u.cabstr.pElems[i]);
2926             }
2927             else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
2928             {
2929                 size_t strLen;
2930                 for (i = 0; i < len; i++)
2931                 {
2932                     strLen = lstrlenA(pvarSrc->u.calpstr.pElems[i]) + 1;
2933                     pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
2934                     memcpy(pvarDest->u.calpstr.pElems[i],
2935                      pvarSrc->u.calpstr.pElems[i], strLen);
2936                 }
2937             }
2938             else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR))
2939             {
2940                 size_t strLen;
2941                 for (i = 0; i < len; i++)
2942                 {
2943                     strLen = (lstrlenW(pvarSrc->u.calpwstr.pElems[i]) + 1) *
2944                      sizeof(WCHAR);
2945                     pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
2946                     memcpy(pvarDest->u.calpstr.pElems[i],
2947                      pvarSrc->u.calpstr.pElems[i], strLen);
2948                 }
2949             }
2950             else
2951                 CopyMemory(pvarDest->u.capropvar.pElems, pvarSrc->u.capropvar.pElems, len * elemSize);
2952         }
2953         else
2954             WARN("Invalid/unsupported type %d\n", pvarSrc->vt);
2955     }
2956
2957     return S_OK;
2958 }
2959
2960 /***********************************************************************
2961  *           FreePropVariantArray                           [OLE32.@]
2962  */
2963 HRESULT WINAPI FreePropVariantArray(ULONG cVariants, /* [in] */
2964                                     PROPVARIANT *rgvars)    /* [in/out] */
2965 {
2966     ULONG i;
2967
2968     TRACE("(%u, %p)\n", cVariants, rgvars);
2969
2970     if (!rgvars)
2971         return E_INVALIDARG;
2972
2973     for(i = 0; i < cVariants; i++)
2974         PropVariantClear(&rgvars[i]);
2975
2976     return S_OK;
2977 }
2978
2979 /******************************************************************************
2980  * DllDebugObjectRPCHook (OLE32.@)
2981  * turns on and off internal debugging,  pointer is only used on macintosh
2982  */
2983
2984 BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy)
2985 {
2986   FIXME("stub\n");
2987   return TRUE;
2988 }