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