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