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