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