Added mappings for a few messages.
[wine] / dlls / ole32 / ole2.c
1
2 /*
3  *      OLE2 library
4  *
5  *      Copyright 1995  Martin von Loewis
6  *      Copyright 1999  Francis Beaudet
7  *      Copyright 1999  Noel Borthwick 
8  */
9
10 #include "config.h"
11
12 #include <assert.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <string.h>
16
17 #include "commctrl.h"
18 #include "ole2.h"
19 #include "ole2ver.h"
20 #include "windef.h"
21 #include "winbase.h"
22 #include "winerror.h"
23 #include "wingdi.h"
24 #include "winuser.h"
25 #include "winreg.h"
26
27 #include "wine/obj_clientserver.h"
28 #include "wine/winbase16.h"
29 #include "wine/wingdi16.h"
30 #include "wine/winuser16.h"
31 #include "ole32_main.h"
32
33 #include "debugtools.h"
34
35 DEFAULT_DEBUG_CHANNEL(ole);
36 DECLARE_DEBUG_CHANNEL(accel);
37
38 /******************************************************************************
39  * These are static/global variables and internal data structures that the 
40  * OLE module uses to maintain it's state.
41  */
42 typedef struct tagDropTargetNode
43 {
44   HWND          hwndTarget;
45   IDropTarget*    dropTarget;
46   struct tagDropTargetNode* prevDropTarget;
47   struct tagDropTargetNode* nextDropTarget;
48 } DropTargetNode;
49
50 typedef struct tagTrackerWindowInfo
51 {
52   IDataObject* dataObject;
53   IDropSource* dropSource;
54   DWORD        dwOKEffect;
55   DWORD*       pdwEffect;
56   BOOL       trackingDone;
57   HRESULT      returnValue;
58
59   BOOL       escPressed;
60   HWND       curDragTargetHWND;
61   IDropTarget* curDragTarget;
62 } TrackerWindowInfo;
63
64 typedef struct tagOleMenuDescriptor  /* OleMenuDescriptor */
65 {
66   HWND               hwndFrame;         /* The containers frame window */
67   HWND               hwndActiveObject;  /* The active objects window */
68   OLEMENUGROUPWIDTHS mgw;               /* OLE menu group widths for the shared menu */
69   HMENU              hmenuCombined;     /* The combined menu */
70   BOOL               bIsServerItem;     /* True if the currently open popup belongs to the server */
71 } OleMenuDescriptor;
72
73 typedef struct tagOleMenuHookItem   /* OleMenu hook item in per thread hook list */
74 {
75   DWORD tid;                /* Thread Id  */
76   HANDLE hHeap;             /* Heap this is allocated from */
77   HHOOK GetMsg_hHook;       /* message hook for WH_GETMESSAGE */
78   HHOOK CallWndProc_hHook;  /* message hook for WH_CALLWNDPROC */
79   struct tagOleMenuHookItem *next;
80 } OleMenuHookItem;
81
82 static OleMenuHookItem *hook_list;
83
84 /*
85  * This is the lock count on the OLE library. It is controlled by the
86  * OLEInitialize/OLEUninitialize methods.
87  */
88 static ULONG OLE_moduleLockCount = 0;
89
90 /*
91  * Name of our registered window class.
92  */
93 static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";
94
95 /*
96  * This is the head of the Drop target container.
97  */
98 static DropTargetNode* targetListHead = NULL;
99
100 /******************************************************************************
101  * These are the prototypes of miscelaneous utility methods 
102  */
103 static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue);
104
105 /******************************************************************************
106  * These are the prototypes of the utility methods used to manage a shared menu
107  */
108 static void OLEMenu_Initialize();
109 static void OLEMenu_UnInitialize();
110 BOOL OLEMenu_InstallHooks( DWORD tid );
111 BOOL OLEMenu_UnInstallHooks( DWORD tid );
112 OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid );
113 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
114 BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor );
115 LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam);
116 LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam);
117
118 /******************************************************************************
119  * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c)
120  */
121 void OLEClipbrd_UnInitialize();
122 void OLEClipbrd_Initialize();
123
124 /******************************************************************************
125  * These are the prototypes of the utility methods used for OLE Drag n Drop
126  */
127 static void            OLEDD_Initialize();
128 static void            OLEDD_UnInitialize();
129 static void            OLEDD_InsertDropTarget(
130                          DropTargetNode* nodeToAdd);
131 static DropTargetNode* OLEDD_ExtractDropTarget(
132                          HWND hwndOfTarget);
133 static DropTargetNode* OLEDD_FindDropTarget(
134                          HWND hwndOfTarget);
135 static LRESULT WINAPI  OLEDD_DragTrackerWindowProc(
136                          HWND   hwnd, 
137                          UINT   uMsg,
138                          WPARAM wParam, 
139                          LPARAM   lParam);
140 static void OLEDD_TrackMouseMove(
141                          TrackerWindowInfo* trackerInfo,
142                          POINT            mousePos,
143                          DWORD              keyState);
144 static void OLEDD_TrackStateChange(
145                          TrackerWindowInfo* trackerInfo,
146                          POINT            mousePos,
147                          DWORD              keyState);
148 static DWORD OLEDD_GetButtonState();
149
150
151 /******************************************************************************
152  *              OleBuildVersion [OLE2.1]
153  *              OleBuildVersion [OLE32.84]
154  */
155 DWORD WINAPI OleBuildVersion(void)
156 {
157     TRACE("Returning version %d, build %d.\n", rmm, rup);
158     return (rmm<<16)+rup;
159 }
160
161 /***********************************************************************
162  *           OleInitialize       (OLE2.2)
163  *           OleInitialize       (OLE32.108)
164  */
165 HRESULT WINAPI OleInitialize(LPVOID reserved)
166 {
167   HRESULT hr;
168
169   TRACE("(%p)\n", reserved);
170
171   /*
172    * The first duty of the OleInitialize is to initialize the COM libraries.
173    */
174   hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
175
176   /*
177    * If the CoInitializeEx call failed, the OLE libraries can't be 
178    * initialized.
179    */
180   if (FAILED(hr))
181     return hr;    
182
183   /*
184    * Then, it has to initialize the OLE specific modules.
185    * This includes:
186    *     Clipboard
187    *     Drag and Drop
188    *     Object linking and Embedding
189    *     In-place activation
190    */
191   if (OLE_moduleLockCount==0)
192 {
193     /* 
194      * Initialize the libraries.
195      */
196     TRACE("() - Initializing the OLE libraries\n");
197
198     /*
199      * OLE Clipboard
200      */
201     OLEClipbrd_Initialize();
202
203     /*
204      * Drag and Drop
205      */
206     OLEDD_Initialize();
207
208     /*
209      * OLE shared menu
210      */
211     OLEMenu_Initialize();
212 }
213
214   /*
215    * Then, we increase the lock count on the OLE module.
216    */
217   OLE_moduleLockCount++;  
218
219   return hr;
220 }
221
222 /******************************************************************************
223  *              CoGetCurrentProcess     [COMPOBJ.34]
224  *              CoGetCurrentProcess     [OLE32.18]
225  *
226  * NOTES
227  *   Is DWORD really the correct return type for this function?
228  */
229 DWORD WINAPI CoGetCurrentProcess(void)
230 {
231         return GetCurrentProcessId();
232 }
233
234 /******************************************************************************
235  *              OleUninitialize [OLE2.3]
236  *              OleUninitialize [OLE32.131]
237  */
238 void WINAPI OleUninitialize(void)
239 {
240   TRACE("()\n");
241
242   /*
243    * Decrease the lock count on the OLE module.
244    */
245   OLE_moduleLockCount--;
246
247   /*
248    * If we hit the bottom of the lock stack, free the libraries.
249    */
250   if (OLE_moduleLockCount==0)
251   {
252     /*
253      * Actually free the libraries.
254      */
255     TRACE("() - Freeing the last reference count\n");
256
257     /*
258      * OLE Clipboard
259      */
260     OLEClipbrd_UnInitialize();
261
262     /*
263      * Drag and Drop
264      */
265     OLEDD_UnInitialize();
266     
267     /*
268      * OLE shared menu
269      */
270     OLEMenu_UnInitialize();
271   }
272   
273   /*
274    * Then, uninitialize the COM libraries.
275    */
276   CoUninitialize();
277 }
278
279 /******************************************************************************
280  *              CoRegisterMessageFilter [OLE32.38]
281  */
282 HRESULT WINAPI CoRegisterMessageFilter(
283     LPMESSAGEFILTER lpMessageFilter,    /* [in] Pointer to interface */
284     LPMESSAGEFILTER *lplpMessageFilter  /* [out] Indirect pointer to prior instance if non-NULL */
285 ) {
286     FIXME("stub\n");
287     if (lplpMessageFilter) {
288         *lplpMessageFilter = NULL;
289     }
290     return S_OK;
291 }
292
293 /******************************************************************************
294  *              OleInitializeWOW        [OLE32.109]
295  */
296 HRESULT WINAPI OleInitializeWOW(DWORD x) {
297         FIXME("(0x%08lx),stub!\n",x);
298         return 0;
299 }
300
301 /***********************************************************************
302  *           RegisterDragDrop (OLE2.35)
303  */
304 HRESULT WINAPI RegisterDragDrop16(
305         HWND16 hwnd,
306         LPDROPTARGET pDropTarget
307 ) {
308         FIXME("(0x%04x,%p),stub!\n",hwnd,pDropTarget);
309         return S_OK;
310 }
311
312 /***********************************************************************
313  *           RegisterDragDrop (OLE32.139)
314  */
315 HRESULT WINAPI RegisterDragDrop(
316         HWND hwnd,
317         LPDROPTARGET pDropTarget) 
318 {
319   DropTargetNode* dropTargetInfo;
320
321   TRACE("(0x%x,%p)\n", hwnd, pDropTarget);
322
323   /*
324    * First, check if the window is already registered.
325    */
326   dropTargetInfo = OLEDD_FindDropTarget(hwnd);
327
328   if (dropTargetInfo!=NULL)
329     return DRAGDROP_E_ALREADYREGISTERED;
330
331   /*
332    * If it's not there, we can add it. We first create a node for it.
333    */
334   dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));
335
336   if (dropTargetInfo==NULL)
337     return E_OUTOFMEMORY;
338
339   dropTargetInfo->hwndTarget     = hwnd;
340   dropTargetInfo->prevDropTarget = NULL;
341   dropTargetInfo->nextDropTarget = NULL;
342
343   /*
344    * Don't forget that this is an interface pointer, need to nail it down since
345    * we keep a copy of it.
346    */
347   dropTargetInfo->dropTarget  = pDropTarget;
348   IDropTarget_AddRef(dropTargetInfo->dropTarget);
349   
350   OLEDD_InsertDropTarget(dropTargetInfo);
351
352         return S_OK;
353 }
354
355 /***********************************************************************
356  *           RevokeDragDrop (OLE2.36)
357  */
358 HRESULT WINAPI RevokeDragDrop16(
359         HWND16 hwnd
360 ) {
361         FIXME("(0x%04x),stub!\n",hwnd);
362         return S_OK;
363 }
364
365 /***********************************************************************
366  *           RevokeDragDrop (OLE32.141)
367  */
368 HRESULT WINAPI RevokeDragDrop(
369         HWND hwnd)
370 {
371   DropTargetNode* dropTargetInfo;
372
373   TRACE("(0x%x)\n", hwnd);
374
375   /*
376    * First, check if the window is already registered.
377    */
378   dropTargetInfo = OLEDD_ExtractDropTarget(hwnd);
379
380   /*
381    * If it ain't in there, it's an error.
382    */
383   if (dropTargetInfo==NULL)
384     return DRAGDROP_E_NOTREGISTERED;
385
386   /*
387    * If it's in there, clean-up it's used memory and
388    * references
389    */
390   IDropTarget_Release(dropTargetInfo->dropTarget);
391   HeapFree(GetProcessHeap(), 0, dropTargetInfo);  
392
393         return S_OK;
394 }
395
396 /***********************************************************************
397  *           OleRegGetUserType (OLE32.122)
398  *
399  * This implementation of OleRegGetUserType ignores the dwFormOfType
400  * parameter and always returns the full name of the object. This is
401  * not too bad since this is the case for many objects because of the
402  * way they are registered.
403  */
404 HRESULT WINAPI OleRegGetUserType( 
405         REFCLSID clsid, 
406         DWORD dwFormOfType,
407         LPOLESTR* pszUserType)
408 {
409   char    keyName[60];
410   DWORD   dwKeyType;
411   DWORD   cbData;
412   HKEY    clsidKey;
413   LONG    hres;
414   LPBYTE  buffer;
415   HRESULT retVal;
416   /*
417    * Initialize the out parameter.
418    */
419   *pszUserType = NULL;
420
421   /*
422    * Build the key name we're looking for
423    */
424   sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
425            clsid->Data1, clsid->Data2, clsid->Data3,
426            clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
427            clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
428
429   TRACE("(%s, %ld, %p)\n", keyName, dwFormOfType, pszUserType);
430
431   /*
432    * Open the class id Key
433    */
434   hres = RegOpenKeyA(HKEY_CLASSES_ROOT,
435                      keyName,
436                      &clsidKey);
437
438   if (hres != ERROR_SUCCESS)
439     return REGDB_E_CLASSNOTREG;
440
441   /*
442    * Retrieve the size of the name string.
443    */
444   cbData = 0;
445
446   hres = RegQueryValueExA(clsidKey,
447                           "",
448                           NULL,
449                           &dwKeyType,
450                           NULL,
451                           &cbData);
452
453   if (hres!=ERROR_SUCCESS)
454   {
455     RegCloseKey(clsidKey);
456     return REGDB_E_READREGDB;
457   }
458
459   /*
460    * Allocate a buffer for the registry value.
461    */
462   *pszUserType = CoTaskMemAlloc(cbData*2);
463
464   if (*pszUserType==NULL)
465   {
466     RegCloseKey(clsidKey);
467     return E_OUTOFMEMORY;
468   }
469
470   buffer = HeapAlloc(GetProcessHeap(), 0, cbData);
471
472   if (buffer == NULL)
473   {
474     RegCloseKey(clsidKey);
475     CoTaskMemFree(*pszUserType);
476     *pszUserType=NULL;
477     return E_OUTOFMEMORY;
478   }
479
480   hres = RegQueryValueExA(clsidKey,
481                           "",
482                           NULL,
483                           &dwKeyType,
484                           buffer,
485                           &cbData);
486
487   RegCloseKey(clsidKey);
488
489   
490   if (hres!=ERROR_SUCCESS)
491   {
492     CoTaskMemFree(*pszUserType);
493     *pszUserType=NULL;
494
495     retVal = REGDB_E_READREGDB;
496   }
497   else
498   {
499     MultiByteToWideChar( CP_ACP, 0, buffer, -1, *pszUserType, cbData /*FIXME*/ );
500     retVal = S_OK;
501   }
502   HeapFree(GetProcessHeap(), 0, buffer);
503
504   return retVal;
505 }
506
507 /***********************************************************************
508  * DoDragDrop [OLE32.65]
509  */
510 HRESULT WINAPI DoDragDrop (
511   IDataObject *pDataObject,  /* [in] ptr to the data obj           */
512   IDropSource* pDropSource,  /* [in] ptr to the source obj         */
513   DWORD       dwOKEffect,    /* [in] effects allowed by the source */
514   DWORD       *pdwEffect)    /* [out] ptr to effects of the source */
515 {
516   TrackerWindowInfo trackerInfo;
517   HWND            hwndTrackWindow;
518   MSG             msg;
519
520   TRACE("(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
521
522   /*
523    * Setup the drag n drop tracking window.
524    */
525   trackerInfo.dataObject        = pDataObject;
526   trackerInfo.dropSource        = pDropSource;
527   trackerInfo.dwOKEffect        = dwOKEffect;
528   trackerInfo.pdwEffect         = pdwEffect;
529   trackerInfo.trackingDone      = FALSE;
530   trackerInfo.escPressed        = FALSE;
531   trackerInfo.curDragTargetHWND = 0;
532   trackerInfo.curDragTarget     = 0;
533
534   hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS,
535                                     "TrackerWindow",
536                                     WS_POPUP,
537                                     CW_USEDEFAULT, CW_USEDEFAULT,
538                                     CW_USEDEFAULT, CW_USEDEFAULT,
539                                     0,
540                                     0,
541                                     0,
542                                     (LPVOID)&trackerInfo);
543
544   if (hwndTrackWindow!=0)
545   {
546     /*
547      * Capture the mouse input
548      */
549     SetCapture(hwndTrackWindow);
550
551     /*
552      * Pump messages. All mouse input should go the the capture window.
553      */
554     while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )
555     {
556       if ( (msg.message >= WM_KEYFIRST) && 
557            (msg.message <= WM_KEYLAST) )
558       {
559         /*
560          * When keyboard messages are sent to windows on this thread, we
561          * want to ignore notify the drop source that the state changed.
562          * in the case of the Escape key, we also notify the drop source
563          * we give it a special meaning.
564          */
565         if ( (msg.message==WM_KEYDOWN) &&
566              (msg.wParam==VK_ESCAPE) )
567         {
568           trackerInfo.escPressed = TRUE;
569         }
570
571         /*
572          * Notify the drop source.
573          */       
574         OLEDD_TrackStateChange(&trackerInfo,
575                                msg.pt,
576                                OLEDD_GetButtonState());
577       }
578       else
579       {
580         /*
581          * Dispatch the messages only when it's not a keyboard message.
582          */
583         DispatchMessageA(&msg);
584       }
585     }
586
587     /*
588      * Destroy the temporary window.
589      */
590     DestroyWindow(hwndTrackWindow);
591
592     return trackerInfo.returnValue;
593   }
594
595   return E_FAIL;
596 }
597
598 /***********************************************************************
599  * OleQueryLinkFromData [OLE32.118]
600  */
601 HRESULT WINAPI OleQueryLinkFromData(
602   IDataObject* pSrcDataObject)
603 {
604   FIXME("(%p),stub!\n", pSrcDataObject);
605   return S_OK;
606 }
607
608 /***********************************************************************
609  * OleRegGetMiscStatus [OLE32.121]
610  */
611 HRESULT WINAPI OleRegGetMiscStatus(
612   REFCLSID clsid,
613   DWORD    dwAspect,
614   DWORD*   pdwStatus)
615 {
616   char    keyName[60];
617   HKEY    clsidKey;
618   HKEY    miscStatusKey;
619   HKEY    aspectKey;
620   LONG    result;
621
622   /*
623    * Initialize the out parameter.
624    */
625   *pdwStatus = 0;
626
627   /*
628    * Build the key name we're looking for
629    */
630   sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
631            clsid->Data1, clsid->Data2, clsid->Data3,
632            clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
633            clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
634
635   TRACE("(%s, %ld, %p)\n", keyName, dwAspect, pdwStatus);
636
637   /*
638    * Open the class id Key
639    */
640   result = RegOpenKeyA(HKEY_CLASSES_ROOT,
641                        keyName,
642                        &clsidKey);
643
644   if (result != ERROR_SUCCESS)
645     return REGDB_E_CLASSNOTREG;
646
647   /*
648    * Get the MiscStatus
649    */
650   result = RegOpenKeyA(clsidKey,
651                        "MiscStatus",
652                        &miscStatusKey);
653
654   
655   if (result != ERROR_SUCCESS)
656   {
657     RegCloseKey(clsidKey);
658     return REGDB_E_READREGDB;
659   }
660
661   /*
662    * Read the default value
663    */
664   OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
665
666   /*
667    * Open the key specific to the requested aspect.
668    */
669   sprintf(keyName, "%ld", dwAspect);
670
671   result = RegOpenKeyA(miscStatusKey,
672                        keyName,
673                        &aspectKey);
674   
675   if (result == ERROR_SUCCESS)
676   {
677     OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
678     RegCloseKey(aspectKey);
679   }
680
681   /*
682    * Cleanup
683    */
684   RegCloseKey(miscStatusKey);
685   RegCloseKey(clsidKey);
686
687   return S_OK;
688 }
689
690 /******************************************************************************
691  *              OleSetContainedObject        [OLE32.128]
692  */
693 HRESULT WINAPI OleSetContainedObject(
694   LPUNKNOWN pUnknown, 
695   BOOL      fContained)
696 {
697   IRunnableObject* runnable = NULL;
698   HRESULT          hres;
699
700   TRACE("(%p,%x), stub!\n", pUnknown, fContained);
701
702   hres = IUnknown_QueryInterface(pUnknown,
703                                  &IID_IRunnableObject,
704                                  (void**)&runnable);
705
706   if (SUCCEEDED(hres))
707   {
708     hres = IRunnableObject_SetContainedObject(runnable, fContained);
709
710     IRunnableObject_Release(runnable);
711
712     return hres;
713   }
714
715   return S_OK;
716 }
717
718 /******************************************************************************
719  *              OleLoad        [OLE32.112]
720  */
721 HRESULT WINAPI OleLoad(
722   LPSTORAGE       pStg, 
723   REFIID          riid, 
724   LPOLECLIENTSITE pClientSite, 
725   LPVOID*         ppvObj)
726 {
727   IPersistStorage* persistStorage = NULL;
728   IOleObject*      oleObject      = NULL;
729   STATSTG          storageInfo;
730   HRESULT          hres;
731
732   TRACE("(%p,%p,%p,%p)\n", pStg, riid, pClientSite, ppvObj);
733   
734   /*
735    * TODO, Conversion ... OleDoAutoConvert
736    */
737
738   /*
739    * Get the class ID for the object.
740    */
741   hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
742
743   /*
744    * Now, try and create the handler for the object
745    */
746   hres = CoCreateInstance(&storageInfo.clsid,
747                           NULL,
748                           CLSCTX_INPROC_HANDLER,
749                           &IID_IOleObject,
750                           (void**)&oleObject);
751
752   /*
753    * If that fails, as it will most times, load the default
754    * OLE handler.
755    */
756   if (FAILED(hres))
757   {
758     hres = OleCreateDefaultHandler(&storageInfo.clsid,
759                                    NULL,
760                                    &IID_IOleObject,
761                                    (void**)&oleObject);
762   }
763
764   /*
765    * If we couldn't find a handler... this is bad. Abort the whole thing.
766    */
767   if (FAILED(hres))
768     return hres;
769
770   /*
771    * Inform the new object of it's client site.
772    */
773   hres = IOleObject_SetClientSite(oleObject, pClientSite);
774
775   /*
776    * Initialize the object with it's IPersistStorage interface.
777    */
778   hres = IOleObject_QueryInterface(oleObject,
779                                    &IID_IPersistStorage,
780                                    (void**)&persistStorage);
781
782   if (SUCCEEDED(hres)) 
783   {
784     IPersistStorage_Load(persistStorage, pStg);
785
786     IPersistStorage_Release(persistStorage);
787     persistStorage = NULL;
788   }
789
790   /*
791    * Return the requested interface to the caller.
792    */
793   hres = IOleObject_QueryInterface(oleObject, riid, ppvObj);
794
795   /*
796    * Cleanup interfaces used internally
797    */
798   IOleObject_Release(oleObject);
799
800   return hres;
801 }
802
803 /***********************************************************************
804  *           OleSave     [OLE32.124]
805  */
806 HRESULT WINAPI OleSave(
807   LPPERSISTSTORAGE pPS,
808   LPSTORAGE        pStg,
809   BOOL             fSameAsLoad)
810 {
811   HRESULT hres;
812   CLSID   objectClass;
813
814   TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad);
815
816   /*
817    * First, we transfer the class ID (if available)
818    */
819   hres = IPersistStorage_GetClassID(pPS, &objectClass);
820
821   if (SUCCEEDED(hres))
822   {
823     WriteClassStg(pStg, &objectClass);
824   }
825
826   /*
827    * Then, we ask the object to save itself to the
828    * storage. If it is successful, we commit the storage.
829    */
830   hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad);
831
832   if (SUCCEEDED(hres))
833   {
834     IStorage_Commit(pStg,
835                     STGC_DEFAULT);
836   }
837   
838   return hres;
839 }
840
841
842 /******************************************************************************
843  *              OleLockRunning        [OLE32.114]
844  */
845 HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses) 
846 {
847   IRunnableObject* runnable = NULL;
848   HRESULT          hres;
849
850   TRACE("(%p,%x,%x)\n", pUnknown, fLock, fLastUnlockCloses);
851
852   hres = IUnknown_QueryInterface(pUnknown,
853                                  &IID_IRunnableObject,
854                                  (void**)&runnable);
855
856   if (SUCCEEDED(hres))
857   {
858     hres = IRunnableObject_LockRunning(runnable, fLock, fLastUnlockCloses);
859
860     IRunnableObject_Release(runnable);
861
862     return hres;
863   }
864   else
865     return E_INVALIDARG;
866 }
867
868
869 /**************************************************************************
870  * Internal methods to manage the shared OLE menu in response to the
871  * OLE***MenuDescriptor API
872  */
873
874 /***
875  * OLEMenu_Initialize()
876  *
877  * Initializes the OLEMENU data structures.
878  */
879 static void OLEMenu_Initialize()
880 {
881 }
882
883 /***
884  * OLEMenu_UnInitialize()
885  *
886  * Releases the OLEMENU data structures.
887  */
888 static void OLEMenu_UnInitialize()
889 {
890 }
891
892 /*************************************************************************
893  * OLEMenu_InstallHooks
894  * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
895  *
896  * RETURNS: TRUE if message hooks were succesfully installed
897  *          FALSE on failure
898  */
899 BOOL OLEMenu_InstallHooks( DWORD tid )
900 {
901   OleMenuHookItem *pHookItem = NULL;
902
903   /* Create an entry for the hook table */
904   if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
905                                sizeof(OleMenuHookItem)) ) )
906     return FALSE;
907
908   pHookItem->tid = tid;
909   pHookItem->hHeap = GetProcessHeap();
910   
911   /* Install a thread scope message hook for WH_GETMESSAGE */
912   pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc,
913                                                0, GetCurrentThreadId() );
914   if ( !pHookItem->GetMsg_hHook )
915     goto CLEANUP;
916
917   /* Install a thread scope message hook for WH_CALLWNDPROC */
918   pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc,
919                                                     0, GetCurrentThreadId() );
920   if ( !pHookItem->CallWndProc_hHook )
921     goto CLEANUP;
922
923   /* Insert the hook table entry */
924   pHookItem->next = hook_list;
925   hook_list = pHookItem;
926   
927   return TRUE;
928   
929 CLEANUP:
930   /* Unhook any hooks */
931   if ( pHookItem->GetMsg_hHook )
932     UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
933   if ( pHookItem->CallWndProc_hHook )
934     UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
935   /* Release the hook table entry */
936   HeapFree(pHookItem->hHeap, 0, pHookItem );
937   
938   return FALSE;
939 }
940
941 /*************************************************************************
942  * OLEMenu_UnInstallHooks
943  * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
944  *
945  * RETURNS: TRUE if message hooks were succesfully installed
946  *          FALSE on failure
947  */
948 BOOL OLEMenu_UnInstallHooks( DWORD tid )
949 {
950   OleMenuHookItem *pHookItem = NULL;
951   OleMenuHookItem **ppHook = &hook_list;
952
953   while (*ppHook)
954   {
955       if ((*ppHook)->tid == tid)
956       {
957           pHookItem = *ppHook;
958           *ppHook = pHookItem->next;
959           break;
960       }
961       ppHook = &(*ppHook)->next;
962   }
963   if (!pHookItem) return FALSE;
964
965   /* Uninstall the hooks installed for this thread */
966   if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
967     goto CLEANUP;
968   if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
969     goto CLEANUP;
970
971   /* Release the hook table entry */
972   HeapFree(pHookItem->hHeap, 0, pHookItem );
973
974   return TRUE;
975
976 CLEANUP:
977   /* Release the hook table entry */
978   if (pHookItem)
979     HeapFree(pHookItem->hHeap, 0, pHookItem );
980
981   return FALSE;
982 }
983
984 /*************************************************************************
985  * OLEMenu_IsHookInstalled
986  * Tests if OLEMenu hooks have been installed for a thread
987  *
988  * RETURNS: The pointer and index of the hook table entry for the tid
989  *          NULL and -1 for the index if no hooks were installed for this thread
990  */
991 OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )
992 {
993   OleMenuHookItem *pHookItem = NULL;
994
995   /* Do a simple linear search for an entry whose tid matches ours.
996    * We really need a map but efficiency is not a concern here. */
997   for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next)
998   {
999     if ( tid == pHookItem->tid )
1000       return pHookItem;
1001   }
1002   
1003   return NULL;
1004 }
1005
1006 /***********************************************************************
1007  *           OLEMenu_FindMainMenuIndex
1008  *
1009  * Used by OLEMenu API to find the top level group a menu item belongs to.
1010  * On success pnPos contains the index of the item in the top level menu group
1011  *
1012  * RETURNS: TRUE if the ID was found, FALSE on failure
1013  */
1014 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
1015 {
1016   UINT i, nItems;
1017
1018   nItems = GetMenuItemCount( hMainMenu );
1019
1020   for (i = 0; i < nItems; i++)
1021   {
1022     HMENU hsubmenu;
1023       
1024     /*  Is the current item a submenu? */
1025     if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
1026     {
1027       /* If the handle is the same we're done */
1028       if ( hsubmenu == hPopupMenu )
1029       {
1030         if (pnPos)
1031           *pnPos = i;
1032         return TRUE;
1033       }
1034       /* Recursively search without updating pnPos */
1035       else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
1036       {
1037         if (pnPos)
1038           *pnPos = i;
1039         return TRUE;
1040       }
1041     }
1042   }
1043
1044   return FALSE;
1045 }
1046
1047 /***********************************************************************
1048  *           OLEMenu_SetIsServerMenu
1049  *
1050  * Checks whether a popup menu belongs to a shared menu group which is
1051  * owned by the server, and sets the menu descriptor state accordingly.
1052  * All menu messages from these groups should be routed to the server.
1053  *
1054  * RETURNS: TRUE if the popup menu is part of a server owned group
1055  *          FASE if the popup menu is part of a container owned group
1056  */
1057 BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
1058 {
1059   UINT nPos = 0, nWidth, i;
1060
1061   pOleMenuDescriptor->bIsServerItem = FALSE;
1062
1063   /* Don't bother searching if the popup is the combined menu itself */
1064   if ( hmenu == pOleMenuDescriptor->hmenuCombined )
1065     return FALSE;
1066
1067   /* Find the menu item index in the shared OLE menu that this item belongs to */
1068   if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu,  &nPos ) )
1069     return FALSE;
1070   
1071   /* The group widths array has counts for the number of elements
1072    * in the groups File, Edit, Container, Object, Window, Help.
1073    * The Edit, Object & Help groups belong to the server object
1074    * and the other three belong to the container.
1075    * Loop thru the group widths and locate the group we are a member of.
1076    */
1077   for ( i = 0, nWidth = 0; i < 6; i++ )
1078   {
1079     nWidth += pOleMenuDescriptor->mgw.width[i];
1080     if ( nPos < nWidth )
1081     {
1082       /* Odd elements are server menu widths */
1083       pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;
1084       break;
1085     }
1086   }
1087
1088   return pOleMenuDescriptor->bIsServerItem;
1089 }
1090
1091 /*************************************************************************
1092  * OLEMenu_CallWndProc
1093  * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
1094  * This is invoked from a message hook installed in OleSetMenuDescriptor.
1095  */
1096 LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
1097 {
1098   LPCWPSTRUCT pMsg = NULL;
1099   HOLEMENU hOleMenu = 0;
1100   OleMenuDescriptor *pOleMenuDescriptor = NULL;
1101   OleMenuHookItem *pHookItem = NULL;
1102   WORD fuFlags;
1103   
1104   TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1105
1106   /* Check if we're being asked to process the message */
1107   if ( HC_ACTION != code )
1108     goto NEXTHOOK;
1109       
1110   /* Retrieve the current message being dispatched from lParam */
1111   pMsg = (LPCWPSTRUCT)lParam;
1112
1113   /* Check if the message is destined for a window we are interested in:
1114    * If the window has an OLEMenu property we may need to dispatch
1115    * the menu message to its active objects window instead. */
1116
1117   hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1118   if ( !hOleMenu )
1119     goto NEXTHOOK;
1120
1121   /* Get the menu descriptor */
1122   pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1123   if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1124     goto NEXTHOOK;
1125
1126   /* Process menu messages */
1127   switch( pMsg->message )
1128   {
1129     case WM_INITMENU:
1130     {
1131       /* Reset the menu descriptor state */
1132       pOleMenuDescriptor->bIsServerItem = FALSE;
1133
1134       /* Send this message to the server as well */
1135       SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1136                   pMsg->message, pMsg->wParam, pMsg->lParam );
1137       goto NEXTHOOK;
1138     }
1139     
1140     case WM_INITMENUPOPUP:
1141     {
1142       /* Save the state for whether this is a server owned menu */
1143       OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
1144       break;
1145     }
1146     
1147     case WM_MENUSELECT:
1148     {
1149       fuFlags = HIWORD(pMsg->wParam);  /* Get flags */
1150       if ( fuFlags & MF_SYSMENU )
1151          goto NEXTHOOK;
1152
1153       /* Save the state for whether this is a server owned popup menu */
1154       else if ( fuFlags & MF_POPUP )
1155         OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
1156
1157       break;
1158     }
1159     
1160     case WM_DRAWITEM:
1161     {
1162       LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
1163       if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
1164         goto NEXTHOOK;  /* Not a menu message */
1165
1166       break;
1167     }
1168
1169     default:
1170       goto NEXTHOOK;
1171   }
1172
1173   /* If the message was for the server dispatch it accordingly */
1174   if ( pOleMenuDescriptor->bIsServerItem )
1175   {
1176     SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1177                   pMsg->message, pMsg->wParam, pMsg->lParam );
1178   }
1179     
1180 NEXTHOOK:
1181   if ( pOleMenuDescriptor )
1182     GlobalUnlock( hOleMenu );
1183   
1184   /* Lookup the hook item for the current thread */
1185   if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1186   {
1187     /* This should never fail!! */
1188     WARN("could not retrieve hHook for current thread!\n" );
1189     return 0;
1190   }
1191   
1192   /* Pass on the message to the next hooker */
1193   return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
1194 }
1195
1196 /*************************************************************************
1197  * OLEMenu_GetMsgProc
1198  * Thread scope WH_GETMESSAGE hook proc filter function (callback)
1199  * This is invoked from a message hook installed in OleSetMenuDescriptor.
1200  */
1201 LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
1202 {
1203   LPMSG pMsg = NULL;
1204   HOLEMENU hOleMenu = 0;
1205   OleMenuDescriptor *pOleMenuDescriptor = NULL;
1206   OleMenuHookItem *pHookItem = NULL;
1207   WORD wCode;
1208   
1209   TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1210
1211   /* Check if we're being asked to process a  messages */
1212   if ( HC_ACTION != code )
1213     goto NEXTHOOK;
1214       
1215   /* Retrieve the current message being dispatched from lParam */
1216   pMsg = (LPMSG)lParam;
1217
1218   /* Check if the message is destined for a window we are interested in:
1219    * If the window has an OLEMenu property we may need to dispatch
1220    * the menu message to its active objects window instead. */
1221
1222   hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1223   if ( !hOleMenu )
1224     goto NEXTHOOK;
1225
1226   /* Process menu messages */
1227   switch( pMsg->message )
1228   {
1229     case WM_COMMAND:
1230     {
1231       wCode = HIWORD(pMsg->wParam);  /* Get notification code */
1232       if ( wCode )
1233         goto NEXTHOOK;  /* Not a menu message */
1234       break;
1235     }
1236     default:
1237       goto NEXTHOOK;
1238   }
1239
1240   /* Get the menu descriptor */
1241   pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1242   if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1243     goto NEXTHOOK;
1244
1245   /* If the message was for the server dispatch it accordingly */
1246   if ( pOleMenuDescriptor->bIsServerItem )
1247   {
1248     /* Change the hWnd in the message to the active objects hWnd.
1249      * The message loop which reads this message will automatically
1250      * dispatch it to the embedded objects window. */
1251     pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
1252   }
1253     
1254 NEXTHOOK:
1255   if ( pOleMenuDescriptor )
1256     GlobalUnlock( hOleMenu );
1257   
1258   /* Lookup the hook item for the current thread */
1259   if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1260   {
1261     /* This should never fail!! */
1262     WARN("could not retrieve hHook for current thread!\n" );
1263     return FALSE;
1264   }
1265   
1266   /* Pass on the message to the next hooker */
1267   return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
1268 }
1269
1270 /***********************************************************************
1271  * OleCreateMenuDescriptor [OLE32.97]
1272  * Creates an OLE menu descriptor for OLE to use when dispatching
1273  * menu messages and commands.
1274  *
1275  * PARAMS:
1276  *    hmenuCombined  -  Handle to the objects combined menu
1277  *    lpMenuWidths   -  Pointer to array of 6 LONG's indicating menus per group
1278  *
1279  */
1280 HOLEMENU WINAPI OleCreateMenuDescriptor(
1281   HMENU                hmenuCombined,
1282   LPOLEMENUGROUPWIDTHS lpMenuWidths)
1283 {
1284   HOLEMENU hOleMenu;
1285   OleMenuDescriptor *pOleMenuDescriptor;
1286   int i;
1287
1288   if ( !hmenuCombined || !lpMenuWidths )
1289     return 0;
1290
1291   /* Create an OLE menu descriptor */
1292   if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
1293                                 sizeof(OleMenuDescriptor) ) ) )
1294   return 0;
1295
1296   pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1297   if ( !pOleMenuDescriptor )
1298     return 0;
1299
1300   /* Initialize menu group widths and hmenu */
1301   for ( i = 0; i < 6; i++ )
1302     pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
1303   
1304   pOleMenuDescriptor->hmenuCombined = hmenuCombined;
1305   pOleMenuDescriptor->bIsServerItem = FALSE;
1306   GlobalUnlock( hOleMenu );
1307       
1308   return hOleMenu;
1309 }
1310
1311 /***********************************************************************
1312  * OleDestroyMenuDescriptor [OLE32.99]
1313  * Destroy the shared menu descriptor
1314  */
1315 HRESULT WINAPI OleDestroyMenuDescriptor(
1316   HOLEMENU hmenuDescriptor)
1317 {
1318   if ( hmenuDescriptor )
1319     GlobalFree( hmenuDescriptor );
1320         return S_OK;
1321 }
1322
1323 /***********************************************************************
1324  * OleSetMenuDescriptor [OLE32.129]
1325  * Installs or removes OLE dispatching code for the containers frame window
1326  * FIXME: The lpFrame and lpActiveObject parameters are currently ignored
1327  * OLE should install context sensitive help F1 filtering for the app when
1328  * these are non null.
1329  * 
1330  * PARAMS:
1331  *     hOleMenu         Handle to composite menu descriptor
1332  *     hwndFrame        Handle to containers frame window
1333  *     hwndActiveObject Handle to objects in-place activation window
1334  *     lpFrame          Pointer to IOleInPlaceFrame on containers window
1335  *     lpActiveObject   Pointer to IOleInPlaceActiveObject on active in-place object
1336  *
1337  * RETURNS:
1338  *      S_OK                               - menu installed correctly
1339  *      E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1340  */
1341 HRESULT WINAPI OleSetMenuDescriptor(
1342   HOLEMENU               hOleMenu,
1343   HWND                   hwndFrame,
1344   HWND                   hwndActiveObject,
1345   LPOLEINPLACEFRAME        lpFrame,
1346   LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1347 {
1348   OleMenuDescriptor *pOleMenuDescriptor = NULL;
1349
1350   /* Check args */
1351   if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
1352     return E_INVALIDARG;
1353
1354   if ( lpFrame || lpActiveObject )
1355   {
1356      FIXME("(%x, %x, %x, %p, %p), Context sensitive help filtering not implemented!\n",
1357         (unsigned int)hOleMenu,
1358         hwndFrame,
1359         hwndActiveObject,
1360         lpFrame,
1361         lpActiveObject);
1362   }
1363
1364   /* Set up a message hook to intercept the containers frame window messages.
1365    * The message filter is responsible for dispatching menu messages from the
1366    * shared menu which are intended for the object.
1367    */
1368
1369   if ( hOleMenu )  /* Want to install dispatching code */
1370   {
1371     /* If OLEMenu hooks are already installed for this thread, fail
1372      * Note: This effectively means that OleSetMenuDescriptor cannot
1373      * be called twice in succession on the same frame window
1374      * without first calling it with a null hOleMenu to uninstall */
1375     if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) )
1376   return E_FAIL;
1377         
1378     /* Get the menu descriptor */
1379     pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1380     if ( !pOleMenuDescriptor )
1381       return E_UNEXPECTED;
1382
1383     /* Update the menu descriptor */
1384     pOleMenuDescriptor->hwndFrame = hwndFrame;
1385     pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
1386
1387     GlobalUnlock( hOleMenu );
1388     pOleMenuDescriptor = NULL;
1389     
1390     /* Add a menu descriptor windows property to the frame window */
1391     SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu );
1392
1393     /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
1394     if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
1395       return E_FAIL;
1396   }
1397   else  /* Want to uninstall dispatching code */
1398   {
1399     /* Uninstall the hooks */
1400     if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1401       return E_FAIL;
1402     
1403     /* Remove the menu descriptor property from the frame window */
1404     RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" );
1405   }
1406       
1407   return S_OK;
1408 }
1409
1410 /******************************************************************************
1411  *              IsAccelerator        [OLE32.75]
1412  * Mostly copied from controls/menu.c TranslateAccelerator implementation
1413  */
1414 BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd)
1415 {
1416     /* YES, Accel16! */
1417     LPACCEL16 lpAccelTbl;
1418     int i;
1419
1420     if(!lpMsg) return FALSE;
1421     if (!hAccel || !(lpAccelTbl = (LPACCEL16)LockResource16(hAccel)))
1422     {
1423         WARN_(accel)("invalid accel handle=%04x\n", hAccel);
1424         return FALSE;
1425     }
1426     if((lpMsg->message != WM_KEYDOWN &&
1427         lpMsg->message != WM_KEYUP &&
1428         lpMsg->message != WM_SYSKEYDOWN &&
1429         lpMsg->message != WM_SYSKEYUP &&
1430         lpMsg->message != WM_CHAR)) return FALSE;
1431
1432     TRACE_(accel)("hAccel=%04x, cAccelEntries=%d,"
1433                 "msg->hwnd=%04x, msg->message=%04x, wParam=%08x, lParam=%08lx\n",
1434                 hAccel, cAccelEntries,
1435                 lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);
1436     for(i = 0; i < cAccelEntries; i++)
1437     {
1438         if(lpAccelTbl[i].key != lpMsg->wParam)
1439             continue;
1440
1441         if(lpMsg->message == WM_CHAR)
1442         {
1443             if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY))
1444             {
1445                 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", lpMsg->wParam & 0xff);
1446                 goto found;
1447             }
1448         }
1449         else
1450         {
1451             if(lpAccelTbl[i].fVirt & FVIRTKEY)
1452             {
1453                 INT mask = 0;
1454                 TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
1455                                 lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff);
1456                 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
1457                 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
1458                 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
1459                 if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
1460                 TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n");
1461             }
1462             else
1463             {
1464                 if(!(lpMsg->lParam & 0x01000000))  /* no special_key */
1465                 {
1466                     if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000))
1467                     {                                                  /* ^^ ALT pressed */
1468                         TRACE_(accel)("found accel for Alt-%c\n", lpMsg->wParam & 0xff);
1469                         goto found;
1470                     }
1471                 }
1472             }
1473         }
1474     }   
1475
1476     WARN_(accel)("couldn't translate accelerator key\n");
1477     return FALSE;
1478
1479 found:
1480     if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd;
1481     return TRUE;
1482 }
1483
1484 /***********************************************************************
1485  * ReleaseStgMedium [OLE32.140]
1486  */
1487 void WINAPI ReleaseStgMedium(
1488   STGMEDIUM* pmedium)
1489 {
1490   switch (pmedium->tymed)
1491   {
1492     case TYMED_HGLOBAL:
1493     {
1494       if ( (pmedium->pUnkForRelease==0) && 
1495            (pmedium->u.hGlobal!=0) )
1496         GlobalFree(pmedium->u.hGlobal);
1497
1498       pmedium->u.hGlobal = 0;
1499       break;
1500     }
1501     case TYMED_FILE:
1502     {
1503       if (pmedium->u.lpszFileName!=0)
1504       {
1505         if (pmedium->pUnkForRelease==0)
1506         {
1507           DeleteFileW(pmedium->u.lpszFileName);
1508         }
1509         
1510         CoTaskMemFree(pmedium->u.lpszFileName);
1511       }
1512
1513       pmedium->u.lpszFileName = 0;
1514       break;
1515     }
1516     case TYMED_ISTREAM:
1517     {
1518       if (pmedium->u.pstm!=0)
1519       {
1520         IStream_Release(pmedium->u.pstm);
1521       }
1522
1523       pmedium->u.pstm = 0;
1524       break;
1525     }
1526     case TYMED_ISTORAGE:
1527     {
1528       if (pmedium->u.pstg!=0)
1529       {
1530         IStorage_Release(pmedium->u.pstg);
1531       }
1532
1533       pmedium->u.pstg = 0;
1534       break;
1535     }
1536     case TYMED_GDI:
1537     {
1538       if ( (pmedium->pUnkForRelease==0) && 
1539            (pmedium->u.hGlobal!=0) )
1540         DeleteObject(pmedium->u.hGlobal);
1541
1542       pmedium->u.hGlobal = 0;
1543       break;
1544     }
1545     case TYMED_MFPICT:
1546     {
1547       if ( (pmedium->pUnkForRelease==0) && 
1548            (pmedium->u.hMetaFilePict!=0) )
1549       {
1550         LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hGlobal);
1551         DeleteMetaFile(pMP->hMF);
1552         GlobalUnlock(pmedium->u.hGlobal);
1553         GlobalFree(pmedium->u.hGlobal);
1554       }
1555
1556       pmedium->u.hMetaFilePict = 0;
1557       break;
1558     }
1559     case TYMED_ENHMF:
1560     {
1561       if ( (pmedium->pUnkForRelease==0) && 
1562            (pmedium->u.hEnhMetaFile!=0) )
1563       {
1564         DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
1565       }
1566
1567       pmedium->u.hEnhMetaFile = 0;
1568       break;
1569     }
1570     case TYMED_NULL:
1571     default:
1572       break;
1573   }
1574
1575   /*
1576    * After cleaning up, the unknown is released
1577    */
1578   if (pmedium->pUnkForRelease!=0)
1579   {
1580     IUnknown_Release(pmedium->pUnkForRelease);
1581     pmedium->pUnkForRelease = 0;
1582   }
1583 }
1584
1585 /***
1586  * OLEDD_Initialize()
1587  *
1588  * Initializes the OLE drag and drop data structures.
1589  */
1590 static void OLEDD_Initialize()
1591 {
1592     WNDCLASSA wndClass;
1593
1594     ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1595     wndClass.style         = CS_GLOBALCLASS;
1596     wndClass.lpfnWndProc   = (WNDPROC)OLEDD_DragTrackerWindowProc;
1597     wndClass.cbClsExtra    = 0;
1598     wndClass.cbWndExtra    = sizeof(TrackerWindowInfo*);
1599     wndClass.hCursor       = 0;
1600     wndClass.hbrBackground = 0;
1601     wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
1602  
1603     RegisterClassA (&wndClass);
1604 }
1605
1606 /***
1607  * OLEDD_UnInitialize()
1608  *
1609  * Releases the OLE drag and drop data structures.
1610  */
1611 static void OLEDD_UnInitialize()
1612 {
1613   /*
1614    * Simply empty the list.
1615    */
1616   while (targetListHead!=NULL)
1617   {
1618     RevokeDragDrop(targetListHead->hwndTarget);
1619   }
1620 }
1621
1622 /***
1623  * OLEDD_InsertDropTarget()
1624  *
1625  * Insert the target node in the tree.
1626  */
1627 static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd)
1628 {
1629   DropTargetNode*  curNode;
1630   DropTargetNode** parentNodeLink;
1631
1632   /*
1633    * Iterate the tree to find the insertion point.
1634    */
1635   curNode        = targetListHead;
1636   parentNodeLink = &targetListHead;
1637
1638   while (curNode!=NULL)
1639   {
1640     if (nodeToAdd->hwndTarget<curNode->hwndTarget)
1641     {
1642       /*
1643        * If the node we want to add has a smaller HWND, go left
1644        */
1645       parentNodeLink = &curNode->prevDropTarget;
1646       curNode        =  curNode->prevDropTarget;
1647     }
1648     else if (nodeToAdd->hwndTarget>curNode->hwndTarget)
1649     {
1650       /*
1651        * If the node we want to add has a larger HWND, go right
1652        */
1653       parentNodeLink = &curNode->nextDropTarget;
1654       curNode        =  curNode->nextDropTarget;
1655     }
1656     else
1657     {
1658       /*
1659        * The item was found in the list. It shouldn't have been there
1660        */
1661       assert(FALSE);
1662       return;
1663     }
1664   }
1665
1666   /*
1667    * If we get here, we have found a spot for our item. The parentNodeLink
1668    * pointer points to the pointer that we have to modify. 
1669    * The curNode should be NULL. We just have to establish the link and Voila!
1670    */
1671   assert(curNode==NULL);
1672   assert(parentNodeLink!=NULL);
1673   assert(*parentNodeLink==NULL);
1674
1675   *parentNodeLink=nodeToAdd;
1676 }
1677
1678 /***
1679  * OLEDD_ExtractDropTarget()
1680  *
1681  * Removes the target node from the tree.
1682  */
1683 static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget)
1684 {
1685   DropTargetNode*  curNode;
1686   DropTargetNode** parentNodeLink;
1687
1688   /*
1689    * Iterate the tree to find the insertion point.
1690    */
1691   curNode        = targetListHead;
1692   parentNodeLink = &targetListHead;
1693
1694   while (curNode!=NULL)
1695   {
1696     if (hwndOfTarget<curNode->hwndTarget)
1697     {
1698       /*
1699        * If the node we want to add has a smaller HWND, go left
1700        */
1701       parentNodeLink = &curNode->prevDropTarget;
1702       curNode        =  curNode->prevDropTarget;
1703     }
1704     else if (hwndOfTarget>curNode->hwndTarget)
1705     {
1706       /*
1707        * If the node we want to add has a larger HWND, go right
1708        */
1709       parentNodeLink = &curNode->nextDropTarget;
1710       curNode        =  curNode->nextDropTarget;
1711     }
1712     else
1713     {
1714       /*
1715        * The item was found in the list. Detach it from it's parent and 
1716        * re-insert it's kids in the tree.
1717        */
1718       assert(parentNodeLink!=NULL);
1719       assert(*parentNodeLink==curNode);
1720
1721       /*
1722        * We arbitrately re-attach the left sub-tree to the parent.
1723        */
1724       *parentNodeLink = curNode->prevDropTarget;
1725
1726       /*
1727        * And we re-insert the right subtree
1728        */
1729       if (curNode->nextDropTarget!=NULL)
1730       {
1731         OLEDD_InsertDropTarget(curNode->nextDropTarget);
1732       }
1733
1734       /*
1735        * The node we found is still a valid node once we complete
1736        * the unlinking of the kids.
1737        */
1738       curNode->nextDropTarget=NULL;
1739       curNode->prevDropTarget=NULL;
1740
1741       return curNode;
1742     }
1743   }
1744
1745   /*
1746    * If we get here, the node is not in the tree
1747    */
1748   return NULL;
1749 }
1750
1751 /***
1752  * OLEDD_FindDropTarget()
1753  *
1754  * Finds information about the drop target.
1755  */
1756 static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
1757 {
1758   DropTargetNode*  curNode;
1759
1760   /*
1761    * Iterate the tree to find the HWND value.
1762    */
1763   curNode        = targetListHead;
1764
1765   while (curNode!=NULL)
1766   {
1767     if (hwndOfTarget<curNode->hwndTarget)
1768     {
1769       /*
1770        * If the node we want to add has a smaller HWND, go left
1771        */
1772       curNode =  curNode->prevDropTarget;
1773     }
1774     else if (hwndOfTarget>curNode->hwndTarget)
1775     {
1776       /*
1777        * If the node we want to add has a larger HWND, go right
1778        */
1779       curNode =  curNode->nextDropTarget;
1780     }
1781     else
1782     {
1783       /*
1784        * The item was found in the list.
1785        */
1786       return curNode;
1787     }
1788   }
1789
1790   /*
1791    * If we get here, the item is not in the list
1792    */
1793   return NULL;
1794 }
1795
1796 /***
1797  * OLEDD_DragTrackerWindowProc()
1798  *
1799  * This method is the WindowProcedure of the drag n drop tracking
1800  * window. During a drag n Drop operation, an invisible window is created
1801  * to receive the user input and act upon it. This procedure is in charge
1802  * of this behavior.
1803  */
1804 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
1805                          HWND   hwnd, 
1806                          UINT   uMsg,
1807                          WPARAM wParam, 
1808                          LPARAM   lParam)
1809 {
1810   switch (uMsg)
1811   {
1812     case WM_CREATE:
1813     {
1814       LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
1815
1816       SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams); 
1817
1818       
1819       break;
1820     }
1821     case WM_MOUSEMOVE:
1822     {
1823       TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1824       POINT            mousePos;
1825
1826       /*
1827        * Get the current mouse position in screen coordinates.
1828        */
1829       mousePos.x = LOWORD(lParam);
1830       mousePos.y = HIWORD(lParam);
1831       ClientToScreen(hwnd, &mousePos);
1832
1833       /*
1834        * Track the movement of the mouse.
1835        */
1836       OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam);
1837
1838       break;
1839     }
1840     case WM_LBUTTONUP:
1841     case WM_MBUTTONUP:
1842     case WM_RBUTTONUP:
1843     case WM_LBUTTONDOWN:
1844     case WM_MBUTTONDOWN:
1845     case WM_RBUTTONDOWN:
1846     {
1847       TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1848       POINT            mousePos;
1849
1850       /*
1851        * Get the current mouse position in screen coordinates.
1852        */
1853       mousePos.x = LOWORD(lParam);
1854       mousePos.y = HIWORD(lParam);
1855       ClientToScreen(hwnd, &mousePos);
1856
1857       /*
1858        * Notify everyone that the button state changed
1859        * TODO: Check if the "escape" key was pressed.
1860        */
1861       OLEDD_TrackStateChange(trackerInfo, mousePos, wParam);
1862
1863       break;
1864     }
1865   }
1866
1867   /*
1868    * This is a window proc after all. Let's call the default.
1869    */
1870   return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1871 }
1872
1873 /***
1874  * OLEDD_TrackMouseMove()
1875  *
1876  * This method is invoked while a drag and drop operation is in effect.
1877  * it will generate the appropriate callbacks in the drop source
1878  * and drop target. It will also provide the expected feedback to
1879  * the user.
1880  *
1881  * params:
1882  *    trackerInfo - Pointer to the structure identifying the
1883  *                  drag & drop operation that is currently
1884  *                  active.
1885  *    mousePos    - Current position of the mouse in screen
1886  *                  coordinates.
1887  *    keyState    - Contains the state of the shift keys and the
1888  *                  mouse buttons (MK_LBUTTON and the like)
1889  */
1890 static void OLEDD_TrackMouseMove(
1891   TrackerWindowInfo* trackerInfo,
1892   POINT            mousePos,
1893   DWORD              keyState)
1894 {
1895   HWND   hwndNewTarget = 0;
1896   HRESULT  hr = S_OK;
1897
1898   /*
1899    * Get the handle of the window under the mouse
1900    */
1901   hwndNewTarget = WindowFromPoint(mousePos);
1902
1903   /*
1904    * Every time, we re-initialize the effects passed to the
1905    * IDropTarget to the effects allowed by the source.
1906    */
1907   *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
1908
1909   /*
1910    * If we are hovering over the same target as before, send the
1911    * DragOver notification
1912    */
1913   if ( (trackerInfo->curDragTarget != 0) && 
1914        (trackerInfo->curDragTargetHWND==hwndNewTarget) )
1915   {
1916     POINTL  mousePosParam;
1917     
1918     /*
1919      * The documentation tells me that the coordinate should be in the target
1920      * window's coordinate space. However, the tests I made tell me the
1921      * coordinates should be in screen coordinates.
1922      */
1923     mousePosParam.x = mousePos.x;
1924     mousePosParam.y = mousePos.y;
1925     
1926     IDropTarget_DragOver(trackerInfo->curDragTarget,
1927                          keyState,
1928                          mousePosParam,
1929                          trackerInfo->pdwEffect);
1930   }
1931   else
1932   {
1933     DropTargetNode* newDropTargetNode = 0;
1934     
1935     /*
1936      * If we changed window, we have to notify our old target and check for
1937      * the new one.
1938      */
1939     if (trackerInfo->curDragTarget!=0)
1940     {
1941       IDropTarget_DragLeave(trackerInfo->curDragTarget);
1942     }
1943     
1944     /*
1945      * Make sure we're hovering over a window.
1946      */
1947     if (hwndNewTarget!=0)
1948     {
1949       /*
1950        * Find-out if there is a drag target under the mouse
1951        */
1952       HWND nexttar = hwndNewTarget;
1953       do {
1954         newDropTargetNode = OLEDD_FindDropTarget(nexttar);
1955       } while (!newDropTargetNode && (nexttar = GetParent(nexttar)) != 0);
1956       if(nexttar) hwndNewTarget = nexttar;
1957
1958       trackerInfo->curDragTargetHWND = hwndNewTarget;
1959       trackerInfo->curDragTarget     = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
1960       
1961       /*
1962        * If there is, notify it that we just dragged-in
1963        */
1964       if (trackerInfo->curDragTarget!=0)
1965       {
1966         POINTL  mousePosParam;
1967         
1968         /*
1969          * The documentation tells me that the coordinate should be in the target
1970          * window's coordinate space. However, the tests I made tell me the
1971          * coordinates should be in screen coordinates.
1972          */
1973         mousePosParam.x = mousePos.x;
1974         mousePosParam.y = mousePos.y;
1975         
1976         IDropTarget_DragEnter(trackerInfo->curDragTarget,
1977                               trackerInfo->dataObject,
1978                               keyState,
1979                               mousePosParam,
1980                               trackerInfo->pdwEffect);
1981       }
1982     }
1983     else
1984     {
1985       /*
1986        * The mouse is not over a window so we don't track anything.
1987        */
1988       trackerInfo->curDragTargetHWND = 0;
1989       trackerInfo->curDragTarget     = 0;
1990     }
1991   }
1992
1993   /*
1994    * Now that we have done that, we have to tell the source to give 
1995    * us feedback on the work being done by the target.  If we don't 
1996    * have a target, simulate no effect.
1997    */
1998   if (trackerInfo->curDragTarget==0)
1999   {
2000     *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2001   }
2002
2003   hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
2004                                 *trackerInfo->pdwEffect);
2005
2006   /*
2007    * When we ask for feedback from the drop source, sometimes it will
2008    * do all the necessary work and sometimes it will not handle it
2009    * when that's the case, we must display the standard drag and drop
2010    * cursors.
2011    */
2012   if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
2013   {
2014     if (*trackerInfo->pdwEffect & DROPEFFECT_MOVE)
2015     {
2016       SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(1)));
2017     }
2018     else if (*trackerInfo->pdwEffect & DROPEFFECT_COPY)
2019     {
2020       SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(2)));
2021     }
2022     else if (*trackerInfo->pdwEffect & DROPEFFECT_LINK)
2023     {
2024       SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(3)));
2025     }
2026     else
2027     {
2028       SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(0)));
2029     }
2030   }  
2031 }
2032
2033 /***
2034  * OLEDD_TrackStateChange()
2035  *
2036  * This method is invoked while a drag and drop operation is in effect.
2037  * It is used to notify the drop target/drop source callbacks when
2038  * the state of the keyboard or mouse button change.
2039  *
2040  * params:
2041  *    trackerInfo - Pointer to the structure identifying the
2042  *                  drag & drop operation that is currently
2043  *                  active.
2044  *    mousePos    - Current position of the mouse in screen
2045  *                  coordinates.
2046  *    keyState    - Contains the state of the shift keys and the
2047  *                  mouse buttons (MK_LBUTTON and the like)
2048  */
2049 static void OLEDD_TrackStateChange(
2050   TrackerWindowInfo* trackerInfo,
2051   POINT            mousePos,
2052   DWORD              keyState)
2053 {
2054   /*
2055    * Ask the drop source what to do with the operation.
2056    */
2057   trackerInfo->returnValue = IDropSource_QueryContinueDrag(
2058                                trackerInfo->dropSource,
2059                                trackerInfo->escPressed, 
2060                                keyState);
2061   
2062   /*
2063    * All the return valued will stop the operation except the S_OK
2064    * return value.
2065    */
2066   if (trackerInfo->returnValue!=S_OK)
2067   {
2068     /*
2069      * Make sure the message loop in DoDragDrop stops
2070      */
2071     trackerInfo->trackingDone = TRUE;
2072
2073     /*
2074      * Release the mouse in case the drop target decides to show a popup 
2075      * or a menu or something.
2076      */
2077     ReleaseCapture();
2078     
2079     /*
2080      * If we end-up over a target, drop the object in the target or 
2081      * inform the target that the operation was cancelled.
2082      */
2083     if (trackerInfo->curDragTarget!=0)
2084     {
2085       switch (trackerInfo->returnValue)
2086       {
2087         /*
2088          * If the source wants us to complete the operation, we tell 
2089          * the drop target that we just dropped the object in it.
2090          */
2091         case DRAGDROP_S_DROP:
2092         {
2093           POINTL  mousePosParam;
2094         
2095           /*
2096            * The documentation tells me that the coordinate should be 
2097            * in the target window's coordinate space. However, the tests
2098            * I made tell me the coordinates should be in screen coordinates.
2099            */
2100           mousePosParam.x = mousePos.x;
2101           mousePosParam.y = mousePos.y;
2102           
2103           IDropTarget_Drop(trackerInfo->curDragTarget,
2104                            trackerInfo->dataObject,
2105                            keyState,
2106                            mousePosParam,
2107                            trackerInfo->pdwEffect);
2108           break;
2109         }
2110         /*
2111          * If the source told us that we should cancel, fool the drop 
2112          * target by telling it that the mouse left it's window.
2113          * Also set the drop effect to "NONE" in case the application 
2114          * ignores the result of DoDragDrop.
2115          */
2116         case DRAGDROP_S_CANCEL:
2117           IDropTarget_DragLeave(trackerInfo->curDragTarget);
2118           *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2119           break;
2120       }
2121     }
2122   }
2123 }
2124
2125 /***
2126  * OLEDD_GetButtonState()
2127  *
2128  * This method will use the current state of the keyboard to build
2129  * a button state mask equivalent to the one passed in the
2130  * WM_MOUSEMOVE wParam.
2131  */
2132 static DWORD OLEDD_GetButtonState()
2133 {
2134   BYTE  keyboardState[256];
2135   DWORD keyMask = 0;
2136
2137   GetKeyboardState(keyboardState);
2138
2139   if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
2140     keyMask |= MK_SHIFT;
2141
2142   if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
2143     keyMask |= MK_CONTROL;
2144
2145   if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
2146     keyMask |= MK_LBUTTON;
2147
2148   if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
2149     keyMask |= MK_RBUTTON;
2150
2151   if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
2152     keyMask |= MK_MBUTTON;
2153
2154   return keyMask;
2155 }
2156
2157 /***
2158  * OLEDD_GetButtonState()
2159  *
2160  * This method will read the default value of the registry key in
2161  * parameter and extract a DWORD value from it. The registry key value
2162  * can be in a string key or a DWORD key.
2163  *
2164  * params:
2165  *     regKey   - Key to read the default value from
2166  *     pdwValue - Pointer to the location where the DWORD 
2167  *                value is returned. This value is not modified
2168  *                if the value is not found.
2169  */
2170
2171 static void OLEUTL_ReadRegistryDWORDValue(
2172   HKEY   regKey, 
2173   DWORD* pdwValue)
2174 {
2175   char  buffer[20];
2176   DWORD dwKeyType;
2177   DWORD cbData = 20;
2178   LONG  lres;
2179
2180   lres = RegQueryValueExA(regKey,
2181                           "",
2182                           NULL,
2183                           &dwKeyType,
2184                           (LPBYTE)buffer,
2185                           &cbData);
2186
2187   if (lres==ERROR_SUCCESS)
2188   {
2189     switch (dwKeyType)
2190     {
2191       case REG_DWORD:
2192         *pdwValue = *(DWORD*)buffer;
2193         break;
2194       case REG_EXPAND_SZ:
2195       case REG_MULTI_SZ:
2196       case REG_SZ:
2197         *pdwValue = (DWORD)strtoul(buffer, NULL, 10);
2198         break;
2199     }
2200   }
2201 }
2202
2203 /******************************************************************************
2204  * OleMetaFilePictFromIconAndLabel (OLE2.56)
2205  *
2206  * Returns a global memory handle to a metafile which contains the icon and
2207  * label given.
2208  * I guess the result of that should look somehow like desktop icons.
2209  * If no hIcon is given, we load the icon via lpszSourceFile and iIconIndex.
2210  * This code might be wrong at some places.
2211  */
2212 HGLOBAL16 WINAPI OleMetaFilePictFromIconAndLabel16(
2213         HICON16 hIcon,
2214         LPCOLESTR16 lpszLabel,
2215         LPCOLESTR16 lpszSourceFile,
2216         UINT16 iIconIndex
2217 ) {
2218     METAFILEPICT16 *mf;
2219     HGLOBAL16 hmf;
2220     HDC16 hdc;
2221
2222     FIXME("(%04x, '%s', '%s', %d): incorrect metrics, please try to correct them !\n\n\n", hIcon, lpszLabel, lpszSourceFile, iIconIndex);
2223
2224     if (!hIcon) {
2225         if (lpszSourceFile) {
2226             HINSTANCE16 hInstance = LoadLibrary16(lpszSourceFile);
2227
2228             /* load the icon at index from lpszSourceFile */
2229             hIcon = (HICON16)LoadIconA(hInstance, (LPCSTR)(DWORD)iIconIndex);
2230             FreeLibrary16(hInstance);
2231         } else
2232             return (HGLOBAL)NULL;
2233     }
2234
2235     hdc = CreateMetaFile16(NULL);
2236     DrawIcon(hdc, 0, 0, hIcon); /* FIXME */
2237     TextOutA(hdc, 0, 0, lpszLabel, 1); /* FIXME */
2238     hmf = GlobalAlloc16(0, sizeof(METAFILEPICT16));
2239     mf = (METAFILEPICT16 *)GlobalLock16(hmf);
2240     mf->mm = MM_ANISOTROPIC;
2241     mf->xExt = 20; /* FIXME: bogus */
2242     mf->yExt = 20; /* dito */
2243     mf->hMF = CloseMetaFile16(hdc);
2244     return hmf;
2245 }
2246
2247 /******************************************************************************
2248  * DllDebugObjectRPCHook (OLE32.62)
2249  * turns on and off internal debugging,  pointer is only used on macintosh
2250  */
2251
2252 BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy)
2253 {
2254   FIXME("stub\n");
2255   return TRUE;
2256 }
2257