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