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