Check file sharing permissions based on the file inode instead of the
[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     LPACCEL lpAccelTbl;
1423     int i;
1424
1425     if(!lpMsg) return FALSE;
1426     if (!hAccel)
1427     {
1428         WARN_(accel)("NULL accel handle\n");
1429         return FALSE;
1430     }
1431     if((lpMsg->message != WM_KEYDOWN &&
1432         lpMsg->message != WM_KEYUP &&
1433         lpMsg->message != WM_SYSKEYDOWN &&
1434         lpMsg->message != WM_SYSKEYUP &&
1435         lpMsg->message != WM_CHAR)) return FALSE;
1436     lpAccelTbl = HeapAlloc(GetProcessHeap(), 0, cAccelEntries * sizeof(ACCEL));
1437     if (NULL == lpAccelTbl)
1438     {
1439         return FALSE;
1440     }
1441     if (CopyAcceleratorTableW(hAccel, lpAccelTbl, cAccelEntries) != cAccelEntries)
1442     {
1443         WARN_(accel)("CopyAcceleratorTableW failed\n");
1444         HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1445         return FALSE;
1446     }
1447
1448     TRACE_(accel)("hAccel=%p, cAccelEntries=%d,"
1449                 "msg->hwnd=%p, msg->message=%04x, wParam=%08x, lParam=%08lx\n",
1450                 hAccel, cAccelEntries,
1451                 lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);
1452     for(i = 0; i < cAccelEntries; i++)
1453     {
1454         if(lpAccelTbl[i].key != lpMsg->wParam)
1455             continue;
1456
1457         if(lpMsg->message == WM_CHAR)
1458         {
1459             if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY))
1460             {
1461                 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", lpMsg->wParam & 0xff);
1462                 goto found;
1463             }
1464         }
1465         else
1466         {
1467             if(lpAccelTbl[i].fVirt & FVIRTKEY)
1468             {
1469                 INT mask = 0;
1470                 TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
1471                                 lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff);
1472                 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
1473                 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
1474                 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
1475                 if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
1476                 TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n");
1477             }
1478             else
1479             {
1480                 if(!(lpMsg->lParam & 0x01000000))  /* no special_key */
1481                 {
1482                     if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000))
1483                     {                                                  /* ^^ ALT pressed */
1484                         TRACE_(accel)("found accel for Alt-%c\n", lpMsg->wParam & 0xff);
1485                         goto found;
1486                     }
1487                 }
1488             }
1489         }
1490     }
1491
1492     WARN_(accel)("couldn't translate accelerator key\n");
1493     HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1494     return FALSE;
1495
1496 found:
1497     if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd;
1498     HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1499     return TRUE;
1500 }
1501
1502 /***********************************************************************
1503  * ReleaseStgMedium [OLE32.@]
1504  */
1505 void WINAPI ReleaseStgMedium(
1506   STGMEDIUM* pmedium)
1507 {
1508   switch (pmedium->tymed)
1509   {
1510     case TYMED_HGLOBAL:
1511     {
1512       if ( (pmedium->pUnkForRelease==0) &&
1513            (pmedium->u.hGlobal!=0) )
1514         GlobalFree(pmedium->u.hGlobal);
1515       break;
1516     }
1517     case TYMED_FILE:
1518     {
1519       if (pmedium->u.lpszFileName!=0)
1520       {
1521         if (pmedium->pUnkForRelease==0)
1522         {
1523           DeleteFileW(pmedium->u.lpszFileName);
1524         }
1525
1526         CoTaskMemFree(pmedium->u.lpszFileName);
1527       }
1528       break;
1529     }
1530     case TYMED_ISTREAM:
1531     {
1532       if (pmedium->u.pstm!=0)
1533       {
1534         IStream_Release(pmedium->u.pstm);
1535       }
1536       break;
1537     }
1538     case TYMED_ISTORAGE:
1539     {
1540       if (pmedium->u.pstg!=0)
1541       {
1542         IStorage_Release(pmedium->u.pstg);
1543       }
1544       break;
1545     }
1546     case TYMED_GDI:
1547     {
1548       if ( (pmedium->pUnkForRelease==0) &&
1549            (pmedium->u.hBitmap!=0) )
1550         DeleteObject(pmedium->u.hBitmap);
1551       break;
1552     }
1553     case TYMED_MFPICT:
1554     {
1555       if ( (pmedium->pUnkForRelease==0) &&
1556            (pmedium->u.hMetaFilePict!=0) )
1557       {
1558         LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hMetaFilePict);
1559         DeleteMetaFile(pMP->hMF);
1560         GlobalUnlock(pmedium->u.hMetaFilePict);
1561         GlobalFree(pmedium->u.hMetaFilePict);
1562       }
1563       break;
1564     }
1565     case TYMED_ENHMF:
1566     {
1567       if ( (pmedium->pUnkForRelease==0) &&
1568            (pmedium->u.hEnhMetaFile!=0) )
1569       {
1570         DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
1571       }
1572       break;
1573     }
1574     case TYMED_NULL:
1575     default:
1576       break;
1577   }
1578   pmedium->tymed=TYMED_NULL;
1579
1580   /*
1581    * After cleaning up, the unknown is released
1582    */
1583   if (pmedium->pUnkForRelease!=0)
1584   {
1585     IUnknown_Release(pmedium->pUnkForRelease);
1586     pmedium->pUnkForRelease = 0;
1587   }
1588 }
1589
1590 /***
1591  * OLEDD_Initialize()
1592  *
1593  * Initializes the OLE drag and drop data structures.
1594  */
1595 static void OLEDD_Initialize()
1596 {
1597     WNDCLASSA wndClass;
1598
1599     ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1600     wndClass.style         = CS_GLOBALCLASS;
1601     wndClass.lpfnWndProc   = (WNDPROC)OLEDD_DragTrackerWindowProc;
1602     wndClass.cbClsExtra    = 0;
1603     wndClass.cbWndExtra    = sizeof(TrackerWindowInfo*);
1604     wndClass.hCursor       = 0;
1605     wndClass.hbrBackground = 0;
1606     wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
1607
1608     RegisterClassA (&wndClass);
1609 }
1610
1611 /***
1612  * OLEDD_UnInitialize()
1613  *
1614  * Releases the OLE drag and drop data structures.
1615  */
1616 static void OLEDD_UnInitialize()
1617 {
1618   /*
1619    * Simply empty the list.
1620    */
1621   while (targetListHead!=NULL)
1622   {
1623     RevokeDragDrop(targetListHead->hwndTarget);
1624   }
1625 }
1626
1627 /***
1628  * OLEDD_InsertDropTarget()
1629  *
1630  * Insert the target node in the tree.
1631  */
1632 static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd)
1633 {
1634   DropTargetNode*  curNode;
1635   DropTargetNode** parentNodeLink;
1636
1637   /*
1638    * Iterate the tree to find the insertion point.
1639    */
1640   curNode        = targetListHead;
1641   parentNodeLink = &targetListHead;
1642
1643   while (curNode!=NULL)
1644   {
1645     if (nodeToAdd->hwndTarget<curNode->hwndTarget)
1646     {
1647       /*
1648        * If the node we want to add has a smaller HWND, go left
1649        */
1650       parentNodeLink = &curNode->prevDropTarget;
1651       curNode        =  curNode->prevDropTarget;
1652     }
1653     else if (nodeToAdd->hwndTarget>curNode->hwndTarget)
1654     {
1655       /*
1656        * If the node we want to add has a larger HWND, go right
1657        */
1658       parentNodeLink = &curNode->nextDropTarget;
1659       curNode        =  curNode->nextDropTarget;
1660     }
1661     else
1662     {
1663       /*
1664        * The item was found in the list. It shouldn't have been there
1665        */
1666       assert(FALSE);
1667       return;
1668     }
1669   }
1670
1671   /*
1672    * If we get here, we have found a spot for our item. The parentNodeLink
1673    * pointer points to the pointer that we have to modify.
1674    * The curNode should be NULL. We just have to establish the link and Voila!
1675    */
1676   assert(curNode==NULL);
1677   assert(parentNodeLink!=NULL);
1678   assert(*parentNodeLink==NULL);
1679
1680   *parentNodeLink=nodeToAdd;
1681 }
1682
1683 /***
1684  * OLEDD_ExtractDropTarget()
1685  *
1686  * Removes the target node from the tree.
1687  */
1688 static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget)
1689 {
1690   DropTargetNode*  curNode;
1691   DropTargetNode** parentNodeLink;
1692
1693   /*
1694    * Iterate the tree to find the insertion point.
1695    */
1696   curNode        = targetListHead;
1697   parentNodeLink = &targetListHead;
1698
1699   while (curNode!=NULL)
1700   {
1701     if (hwndOfTarget<curNode->hwndTarget)
1702     {
1703       /*
1704        * If the node we want to add has a smaller HWND, go left
1705        */
1706       parentNodeLink = &curNode->prevDropTarget;
1707       curNode        =  curNode->prevDropTarget;
1708     }
1709     else if (hwndOfTarget>curNode->hwndTarget)
1710     {
1711       /*
1712        * If the node we want to add has a larger HWND, go right
1713        */
1714       parentNodeLink = &curNode->nextDropTarget;
1715       curNode        =  curNode->nextDropTarget;
1716     }
1717     else
1718     {
1719       /*
1720        * The item was found in the list. Detach it from it's parent and
1721        * re-insert it's kids in the tree.
1722        */
1723       assert(parentNodeLink!=NULL);
1724       assert(*parentNodeLink==curNode);
1725
1726       /*
1727        * We arbitrately re-attach the left sub-tree to the parent.
1728        */
1729       *parentNodeLink = curNode->prevDropTarget;
1730
1731       /*
1732        * And we re-insert the right subtree
1733        */
1734       if (curNode->nextDropTarget!=NULL)
1735       {
1736         OLEDD_InsertDropTarget(curNode->nextDropTarget);
1737       }
1738
1739       /*
1740        * The node we found is still a valid node once we complete
1741        * the unlinking of the kids.
1742        */
1743       curNode->nextDropTarget=NULL;
1744       curNode->prevDropTarget=NULL;
1745
1746       return curNode;
1747     }
1748   }
1749
1750   /*
1751    * If we get here, the node is not in the tree
1752    */
1753   return NULL;
1754 }
1755
1756 /***
1757  * OLEDD_FindDropTarget()
1758  *
1759  * Finds information about the drop target.
1760  */
1761 static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
1762 {
1763   DropTargetNode*  curNode;
1764
1765   /*
1766    * Iterate the tree to find the HWND value.
1767    */
1768   curNode        = targetListHead;
1769
1770   while (curNode!=NULL)
1771   {
1772     if (hwndOfTarget<curNode->hwndTarget)
1773     {
1774       /*
1775        * If the node we want to add has a smaller HWND, go left
1776        */
1777       curNode =  curNode->prevDropTarget;
1778     }
1779     else if (hwndOfTarget>curNode->hwndTarget)
1780     {
1781       /*
1782        * If the node we want to add has a larger HWND, go right
1783        */
1784       curNode =  curNode->nextDropTarget;
1785     }
1786     else
1787     {
1788       /*
1789        * The item was found in the list.
1790        */
1791       return curNode;
1792     }
1793   }
1794
1795   /*
1796    * If we get here, the item is not in the list
1797    */
1798   return NULL;
1799 }
1800
1801 /***
1802  * OLEDD_DragTrackerWindowProc()
1803  *
1804  * This method is the WindowProcedure of the drag n drop tracking
1805  * window. During a drag n Drop operation, an invisible window is created
1806  * to receive the user input and act upon it. This procedure is in charge
1807  * of this behavior.
1808  */
1809 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
1810                          HWND   hwnd,
1811                          UINT   uMsg,
1812                          WPARAM wParam,
1813                          LPARAM   lParam)
1814 {
1815   switch (uMsg)
1816   {
1817     case WM_CREATE:
1818     {
1819       LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
1820
1821       SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams);
1822
1823
1824       break;
1825     }
1826     case WM_MOUSEMOVE:
1827     {
1828       TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1829       POINT            mousePos;
1830
1831       /*
1832        * Get the current mouse position in screen coordinates.
1833        */
1834       mousePos.x = LOWORD(lParam);
1835       mousePos.y = HIWORD(lParam);
1836       ClientToScreen(hwnd, &mousePos);
1837
1838       /*
1839        * Track the movement of the mouse.
1840        */
1841       OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam);
1842
1843       break;
1844     }
1845     case WM_LBUTTONUP:
1846     case WM_MBUTTONUP:
1847     case WM_RBUTTONUP:
1848     case WM_LBUTTONDOWN:
1849     case WM_MBUTTONDOWN:
1850     case WM_RBUTTONDOWN:
1851     {
1852       TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1853       POINT            mousePos;
1854
1855       /*
1856        * Get the current mouse position in screen coordinates.
1857        */
1858       mousePos.x = LOWORD(lParam);
1859       mousePos.y = HIWORD(lParam);
1860       ClientToScreen(hwnd, &mousePos);
1861
1862       /*
1863        * Notify everyone that the button state changed
1864        * TODO: Check if the "escape" key was pressed.
1865        */
1866       OLEDD_TrackStateChange(trackerInfo, mousePos, wParam);
1867
1868       break;
1869     }
1870   }
1871
1872   /*
1873    * This is a window proc after all. Let's call the default.
1874    */
1875   return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1876 }
1877
1878 /***
1879  * OLEDD_TrackMouseMove()
1880  *
1881  * This method is invoked while a drag and drop operation is in effect.
1882  * it will generate the appropriate callbacks in the drop source
1883  * and drop target. It will also provide the expected feedback to
1884  * the user.
1885  *
1886  * params:
1887  *    trackerInfo - Pointer to the structure identifying the
1888  *                  drag & drop operation that is currently
1889  *                  active.
1890  *    mousePos    - Current position of the mouse in screen
1891  *                  coordinates.
1892  *    keyState    - Contains the state of the shift keys and the
1893  *                  mouse buttons (MK_LBUTTON and the like)
1894  */
1895 static void OLEDD_TrackMouseMove(
1896   TrackerWindowInfo* trackerInfo,
1897   POINT            mousePos,
1898   DWORD              keyState)
1899 {
1900   HWND   hwndNewTarget = 0;
1901   HRESULT  hr = S_OK;
1902
1903   /*
1904    * Get the handle of the window under the mouse
1905    */
1906   hwndNewTarget = WindowFromPoint(mousePos);
1907
1908   /*
1909    * Every time, we re-initialize the effects passed to the
1910    * IDropTarget to the effects allowed by the source.
1911    */
1912   *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
1913
1914   /*
1915    * If we are hovering over the same target as before, send the
1916    * DragOver notification
1917    */
1918   if ( (trackerInfo->curDragTarget != 0) &&
1919        (trackerInfo->curTargetHWND == hwndNewTarget) )
1920   {
1921     POINTL  mousePosParam;
1922
1923     /*
1924      * The documentation tells me that the coordinate should be in the target
1925      * window's coordinate space. However, the tests I made tell me the
1926      * coordinates should be in screen coordinates.
1927      */
1928     mousePosParam.x = mousePos.x;
1929     mousePosParam.y = mousePos.y;
1930
1931     IDropTarget_DragOver(trackerInfo->curDragTarget,
1932                          keyState,
1933                          mousePosParam,
1934                          trackerInfo->pdwEffect);
1935   }
1936   else
1937   {
1938     DropTargetNode* newDropTargetNode = 0;
1939
1940     /*
1941      * If we changed window, we have to notify our old target and check for
1942      * the new one.
1943      */
1944     if (trackerInfo->curDragTarget!=0)
1945     {
1946       IDropTarget_DragLeave(trackerInfo->curDragTarget);
1947     }
1948
1949     /*
1950      * Make sure we're hovering over a window.
1951      */
1952     if (hwndNewTarget!=0)
1953     {
1954       /*
1955        * Find-out if there is a drag target under the mouse
1956        */
1957       HWND nexttar = hwndNewTarget;
1958       trackerInfo->curTargetHWND = hwndNewTarget;
1959
1960       do {
1961         newDropTargetNode = OLEDD_FindDropTarget(nexttar);
1962       } while (!newDropTargetNode && (nexttar = GetParent(nexttar)) != 0);
1963       if(nexttar) hwndNewTarget = nexttar;
1964
1965       trackerInfo->curDragTargetHWND = hwndNewTarget;
1966       trackerInfo->curDragTarget     = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
1967
1968       /*
1969        * If there is, notify it that we just dragged-in
1970        */
1971       if (trackerInfo->curDragTarget!=0)
1972       {
1973         POINTL  mousePosParam;
1974
1975         /*
1976          * The documentation tells me that the coordinate should be in the target
1977          * window's coordinate space. However, the tests I made tell me the
1978          * coordinates should be in screen coordinates.
1979          */
1980         mousePosParam.x = mousePos.x;
1981         mousePosParam.y = mousePos.y;
1982
1983         IDropTarget_DragEnter(trackerInfo->curDragTarget,
1984                               trackerInfo->dataObject,
1985                               keyState,
1986                               mousePosParam,
1987                               trackerInfo->pdwEffect);
1988       }
1989     }
1990     else
1991     {
1992       /*
1993        * The mouse is not over a window so we don't track anything.
1994        */
1995       trackerInfo->curDragTargetHWND = 0;
1996       trackerInfo->curTargetHWND     = 0;
1997       trackerInfo->curDragTarget     = 0;
1998     }
1999   }
2000
2001   /*
2002    * Now that we have done that, we have to tell the source to give
2003    * us feedback on the work being done by the target.  If we don't
2004    * have a target, simulate no effect.
2005    */
2006   if (trackerInfo->curDragTarget==0)
2007   {
2008     *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2009   }
2010
2011   hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
2012                                 *trackerInfo->pdwEffect);
2013
2014   /*
2015    * When we ask for feedback from the drop source, sometimes it will
2016    * do all the necessary work and sometimes it will not handle it
2017    * when that's the case, we must display the standard drag and drop
2018    * cursors.
2019    */
2020   if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
2021   {
2022     if (*trackerInfo->pdwEffect & DROPEFFECT_MOVE)
2023     {
2024       SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(1)));
2025     }
2026     else if (*trackerInfo->pdwEffect & DROPEFFECT_COPY)
2027     {
2028       SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(2)));
2029     }
2030     else if (*trackerInfo->pdwEffect & DROPEFFECT_LINK)
2031     {
2032       SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(3)));
2033     }
2034     else
2035     {
2036       SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(0)));
2037     }
2038   }
2039 }
2040
2041 /***
2042  * OLEDD_TrackStateChange()
2043  *
2044  * This method is invoked while a drag and drop operation is in effect.
2045  * It is used to notify the drop target/drop source callbacks when
2046  * the state of the keyboard or mouse button change.
2047  *
2048  * params:
2049  *    trackerInfo - Pointer to the structure identifying the
2050  *                  drag & drop operation that is currently
2051  *                  active.
2052  *    mousePos    - Current position of the mouse in screen
2053  *                  coordinates.
2054  *    keyState    - Contains the state of the shift keys and the
2055  *                  mouse buttons (MK_LBUTTON and the like)
2056  */
2057 static void OLEDD_TrackStateChange(
2058   TrackerWindowInfo* trackerInfo,
2059   POINT            mousePos,
2060   DWORD              keyState)
2061 {
2062   /*
2063    * Ask the drop source what to do with the operation.
2064    */
2065   trackerInfo->returnValue = IDropSource_QueryContinueDrag(
2066                                trackerInfo->dropSource,
2067                                trackerInfo->escPressed,
2068                                keyState);
2069
2070   /*
2071    * All the return valued will stop the operation except the S_OK
2072    * return value.
2073    */
2074   if (trackerInfo->returnValue!=S_OK)
2075   {
2076     /*
2077      * Make sure the message loop in DoDragDrop stops
2078      */
2079     trackerInfo->trackingDone = TRUE;
2080
2081     /*
2082      * Release the mouse in case the drop target decides to show a popup
2083      * or a menu or something.
2084      */
2085     ReleaseCapture();
2086
2087     /*
2088      * If we end-up over a target, drop the object in the target or
2089      * inform the target that the operation was cancelled.
2090      */
2091     if (trackerInfo->curDragTarget!=0)
2092     {
2093       switch (trackerInfo->returnValue)
2094       {
2095         /*
2096          * If the source wants us to complete the operation, we tell
2097          * the drop target that we just dropped the object in it.
2098          */
2099         case DRAGDROP_S_DROP:
2100         {
2101           POINTL  mousePosParam;
2102
2103           /*
2104            * The documentation tells me that the coordinate should be
2105            * in the target window's coordinate space. However, the tests
2106            * I made tell me the coordinates should be in screen coordinates.
2107            */
2108           mousePosParam.x = mousePos.x;
2109           mousePosParam.y = mousePos.y;
2110
2111           IDropTarget_Drop(trackerInfo->curDragTarget,
2112                            trackerInfo->dataObject,
2113                            keyState,
2114                            mousePosParam,
2115                            trackerInfo->pdwEffect);
2116           break;
2117         }
2118         /*
2119          * If the source told us that we should cancel, fool the drop
2120          * target by telling it that the mouse left it's window.
2121          * Also set the drop effect to "NONE" in case the application
2122          * ignores the result of DoDragDrop.
2123          */
2124         case DRAGDROP_S_CANCEL:
2125           IDropTarget_DragLeave(trackerInfo->curDragTarget);
2126           *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2127           break;
2128       }
2129     }
2130   }
2131 }
2132
2133 /***
2134  * OLEDD_GetButtonState()
2135  *
2136  * This method will use the current state of the keyboard to build
2137  * a button state mask equivalent to the one passed in the
2138  * WM_MOUSEMOVE wParam.
2139  */
2140 static DWORD OLEDD_GetButtonState()
2141 {
2142   BYTE  keyboardState[256];
2143   DWORD keyMask = 0;
2144
2145   GetKeyboardState(keyboardState);
2146
2147   if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
2148     keyMask |= MK_SHIFT;
2149
2150   if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
2151     keyMask |= MK_CONTROL;
2152
2153   if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
2154     keyMask |= MK_LBUTTON;
2155
2156   if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
2157     keyMask |= MK_RBUTTON;
2158
2159   if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
2160     keyMask |= MK_MBUTTON;
2161
2162   return keyMask;
2163 }
2164
2165 /***
2166  * OLEDD_GetButtonState()
2167  *
2168  * This method will read the default value of the registry key in
2169  * parameter and extract a DWORD value from it. The registry key value
2170  * can be in a string key or a DWORD key.
2171  *
2172  * params:
2173  *     regKey   - Key to read the default value from
2174  *     pdwValue - Pointer to the location where the DWORD
2175  *                value is returned. This value is not modified
2176  *                if the value is not found.
2177  */
2178
2179 static void OLEUTL_ReadRegistryDWORDValue(
2180   HKEY   regKey,
2181   DWORD* pdwValue)
2182 {
2183   char  buffer[20];
2184   DWORD dwKeyType;
2185   DWORD cbData = 20;
2186   LONG  lres;
2187
2188   lres = RegQueryValueExA(regKey,
2189                           "",
2190                           NULL,
2191                           &dwKeyType,
2192                           (LPBYTE)buffer,
2193                           &cbData);
2194
2195   if (lres==ERROR_SUCCESS)
2196   {
2197     switch (dwKeyType)
2198     {
2199       case REG_DWORD:
2200         *pdwValue = *(DWORD*)buffer;
2201         break;
2202       case REG_EXPAND_SZ:
2203       case REG_MULTI_SZ:
2204       case REG_SZ:
2205         *pdwValue = (DWORD)strtoul(buffer, NULL, 10);
2206         break;
2207     }
2208   }
2209 }
2210
2211 /******************************************************************************
2212  * OleDraw (OLE32.@)
2213  *
2214  * The operation of this function is documented literally in the WinAPI
2215  * documentation to involve a QueryInterface for the IViewObject interface,
2216  * followed by a call to IViewObject::Draw.
2217  */
2218 HRESULT WINAPI OleDraw(
2219         IUnknown *pUnk,
2220         DWORD dwAspect,
2221         HDC hdcDraw,
2222         LPCRECT lprcBounds)
2223 {
2224   HRESULT hres;
2225   IViewObject *viewobject;
2226
2227   hres = IUnknown_QueryInterface(pUnk,
2228                                  &IID_IViewObject,
2229                                  (void**)&viewobject);
2230
2231   if (SUCCEEDED(hres))
2232   {
2233     RECTL rectl;
2234
2235     rectl.left = lprcBounds->left;
2236     rectl.right = lprcBounds->right;
2237     rectl.top = lprcBounds->top;
2238     rectl.bottom = lprcBounds->bottom;
2239     hres = IViewObject_Draw(viewobject, dwAspect, -1, 0, 0, 0, hdcDraw, &rectl, 0, 0, 0);
2240
2241     IViewObject_Release(viewobject);
2242     return hres;
2243   }
2244   else
2245   {
2246     return DV_E_NOIVIEWOBJECT;
2247   }
2248 }
2249
2250 /***********************************************************************
2251  *             OleTranslateAccelerator [OLE32.@]
2252  */
2253 HRESULT WINAPI OleTranslateAccelerator (LPOLEINPLACEFRAME lpFrame,
2254                    LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpmsg)
2255 {
2256     WORD wID;
2257
2258     TRACE("(%p,%p,%p)\n", lpFrame, lpFrameInfo, lpmsg);
2259
2260     if (IsAccelerator(lpFrameInfo->haccel,lpFrameInfo->cAccelEntries,lpmsg,&wID))
2261         return IOleInPlaceFrame_TranslateAccelerator(lpFrame,lpmsg,wID);
2262
2263     return S_FALSE;
2264 }
2265
2266 /******************************************************************************
2267  *              OleCreate        [OLE32.@]
2268  *
2269  */
2270 HRESULT WINAPI OleCreate(
2271         REFCLSID rclsid,
2272         REFIID riid,
2273         DWORD renderopt,
2274         LPFORMATETC pFormatEtc,
2275         LPOLECLIENTSITE pClientSite,
2276         LPSTORAGE pStg,
2277         LPVOID* ppvObj)
2278 {
2279     HRESULT hres, hres1;
2280     IUnknown * pUnk = NULL;
2281
2282     FIXME("\n\t%s\n\t%s semi-stub!\n", debugstr_guid(rclsid), debugstr_guid(riid));
2283
2284     if (SUCCEEDED((hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER|CLSCTX_LOCAL_SERVER , riid, (LPVOID*)&pUnk))))
2285     {
2286         if (pClientSite)
2287         {
2288             IOleObject * pOE;
2289             IPersistStorage * pPS;
2290             if (SUCCEEDED((hres = IUnknown_QueryInterface( pUnk, &IID_IOleObject, (LPVOID*)&pOE))))
2291             {
2292                 TRACE("trying to set clientsite %p\n", pClientSite);
2293                 hres1 = IOleObject_SetClientSite(pOE, pClientSite);
2294                 TRACE("-- result 0x%08lx\n", hres1);
2295                 IOleObject_Release(pOE);
2296             }
2297             if (SUCCEEDED((hres = IUnknown_QueryInterface( pUnk, &IID_IPersistStorage, (LPVOID*)&pPS))))
2298             {
2299                 TRACE("trying to set stg %p\n", pStg);
2300                 hres1 = IPersistStorage_InitNew(pPS, pStg);
2301                 TRACE("-- result 0x%08lx\n", hres1);
2302                 IPersistStorage_Release(pPS);
2303             }
2304         }
2305     }
2306
2307     *ppvObj = pUnk;
2308
2309     TRACE("-- %p \n", pUnk);
2310     return hres;
2311 }
2312
2313 /***********************************************************************
2314  *           OLE_FreeClipDataArray   [internal]
2315  *
2316  * NOTES:
2317  *  frees the data associated with an array of CLIPDATAs
2318  */
2319 static void OLE_FreeClipDataArray(ULONG count, CLIPDATA * pClipDataArray)
2320 {
2321     ULONG i;
2322     for (i = 0; i < count; i++)
2323         if (pClipDataArray[i].pClipData)
2324             CoTaskMemFree(pClipDataArray[i].pClipData);
2325 }
2326
2327 HRESULT WINAPI FreePropVariantArray(ULONG,PROPVARIANT*);
2328
2329 /***********************************************************************
2330  *           PropVariantClear                       [OLE32.@]
2331  */
2332 HRESULT WINAPI PropVariantClear(PROPVARIANT * pvar) /* [in/out] */
2333 {
2334     TRACE("(%p)\n", pvar);
2335
2336     if (!pvar)
2337         return S_OK;
2338
2339     switch(pvar->vt)
2340     {
2341     case VT_STREAM:
2342     case VT_STREAMED_OBJECT:
2343     case VT_STORAGE:
2344     case VT_STORED_OBJECT:
2345         IUnknown_Release((LPUNKNOWN)pvar->u.pStream);
2346         break;
2347     case VT_CLSID:
2348     case VT_LPSTR:
2349     case VT_LPWSTR:
2350         /* pick an arbitary typed pointer - we don't care about the type
2351          * as we are just freeing it */
2352         CoTaskMemFree(pvar->u.puuid);
2353         break;
2354     case VT_BLOB:
2355     case VT_BLOB_OBJECT:
2356         CoTaskMemFree(pvar->u.blob.pBlobData);
2357         break;
2358     case VT_BSTR:
2359         FIXME("Need to load OLEAUT32 for SysFreeString\n");
2360         /* SysFreeString(pvar->u.bstrVal); */
2361         break;
2362    case VT_CF:
2363         if (pvar->u.pclipdata)
2364         {
2365             OLE_FreeClipDataArray(1, pvar->u.pclipdata);
2366             CoTaskMemFree(pvar->u.pclipdata);
2367         }
2368         break;
2369     default:
2370         if (pvar->vt & VT_ARRAY)
2371         {
2372             FIXME("Need to call SafeArrayDestroy\n");
2373             /* SafeArrayDestroy(pvar->u.caub); */
2374         }
2375         switch (pvar->vt & VT_VECTOR)
2376         {
2377         case VT_VARIANT:
2378             FreePropVariantArray(pvar->u.capropvar.cElems, pvar->u.capropvar.pElems);
2379             break;
2380         case VT_CF:
2381             OLE_FreeClipDataArray(pvar->u.caclipdata.cElems, pvar->u.caclipdata.pElems);
2382             break;
2383         case VT_BSTR:
2384         case VT_LPSTR:
2385         case VT_LPWSTR:
2386             FIXME("Freeing of vector sub-type not supported yet\n");
2387         }
2388         if (pvar->vt & VT_VECTOR)
2389         {
2390             /* pick an arbitary VT_VECTOR structure - they all have the same
2391              * memory layout */
2392             CoTaskMemFree(pvar->u.capropvar.pElems);
2393         }
2394     }
2395
2396     ZeroMemory(pvar, sizeof(*pvar));
2397
2398     return S_OK;
2399 }
2400
2401 /***********************************************************************
2402  *           PropVariantCopy                        [OLE32.@]
2403  */
2404 HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest,      /* [out] */
2405                                const PROPVARIANT *pvarSrc) /* [in] */
2406 {
2407     ULONG len;
2408     TRACE("(%p, %p): stub:\n", pvarDest, pvarSrc);
2409
2410     /* this will deal with most cases */
2411     CopyMemory(pvarDest, pvarSrc, sizeof(*pvarDest));
2412
2413     switch(pvarSrc->vt)
2414     {
2415     case VT_STREAM:
2416     case VT_STREAMED_OBJECT:
2417     case VT_STORAGE:
2418     case VT_STORED_OBJECT:
2419         IUnknown_AddRef((LPUNKNOWN)pvarDest->u.pStream);
2420         break;
2421     case VT_CLSID:
2422         pvarDest->u.puuid = CoTaskMemAlloc(sizeof(CLSID));
2423         CopyMemory(pvarDest->u.puuid, pvarSrc->u.puuid, sizeof(CLSID));
2424         break;
2425     case VT_LPSTR:
2426         len = strlen(pvarSrc->u.pszVal);
2427         pvarDest->u.pszVal = CoTaskMemAlloc(len);
2428         CopyMemory(pvarDest->u.pszVal, pvarSrc->u.pszVal, len);
2429         break;
2430     case VT_LPWSTR:
2431         len = lstrlenW(pvarSrc->u.pwszVal);
2432         pvarDest->u.pwszVal = CoTaskMemAlloc(len);
2433         CopyMemory(pvarDest->u.pwszVal, pvarSrc->u.pwszVal, len);
2434         break;
2435     case VT_BLOB:
2436     case VT_BLOB_OBJECT:
2437         if (pvarSrc->u.blob.pBlobData)
2438         {
2439             len = pvarSrc->u.blob.cbSize;
2440             pvarDest->u.blob.pBlobData = CoTaskMemAlloc(len);
2441             CopyMemory(pvarDest->u.blob.pBlobData, pvarSrc->u.blob.pBlobData, len);
2442         }
2443         break;
2444     case VT_BSTR:
2445         FIXME("Need to copy BSTR\n");
2446         break;
2447     case VT_CF:
2448         if (pvarSrc->u.pclipdata)
2449         {
2450             len = pvarSrc->u.pclipdata->cbSize - sizeof(pvarSrc->u.pclipdata->ulClipFmt);
2451             CoTaskMemAlloc(len);
2452             CopyMemory(pvarDest->u.pclipdata->pClipData, pvarSrc->u.pclipdata->pClipData, len);
2453         }
2454         break;
2455     default:
2456         if (pvarSrc->vt & VT_ARRAY)
2457         {
2458             FIXME("Need to call SafeArrayCopy\n");
2459             /* SafeArrayCopy(...); */
2460         }
2461         if (pvarSrc->vt & VT_VECTOR)
2462         {
2463             int elemSize;
2464             switch(pvarSrc->vt & VT_VECTOR)
2465             {
2466             case VT_I1:       elemSize = sizeof(pvarSrc->u.cVal); break;
2467             case VT_UI1:      elemSize = sizeof(pvarSrc->u.bVal); break;
2468             case VT_I2:       elemSize = sizeof(pvarSrc->u.iVal); break;
2469             case VT_UI2:      elemSize = sizeof(pvarSrc->u.uiVal); break;
2470             case VT_BOOL:     elemSize = sizeof(pvarSrc->u.boolVal); break;
2471             case VT_I4:       elemSize = sizeof(pvarSrc->u.lVal); break;
2472             case VT_UI4:      elemSize = sizeof(pvarSrc->u.ulVal); break;
2473             case VT_R4:       elemSize = sizeof(pvarSrc->u.fltVal); break;
2474             case VT_R8:       elemSize = sizeof(pvarSrc->u.dblVal); break;
2475             case VT_ERROR:    elemSize = sizeof(pvarSrc->u.scode); break;
2476             case VT_I8:       elemSize = sizeof(pvarSrc->u.hVal); break;
2477             case VT_UI8:      elemSize = sizeof(pvarSrc->u.uhVal); break;
2478             case VT_CY:       elemSize = sizeof(pvarSrc->u.cyVal); break;
2479             case VT_DATE:     elemSize = sizeof(pvarSrc->u.date); break;
2480             case VT_FILETIME: elemSize = sizeof(pvarSrc->u.filetime); break;
2481             case VT_CLSID:    elemSize = sizeof(*pvarSrc->u.puuid); break;
2482             case VT_CF:       elemSize = sizeof(*pvarSrc->u.pclipdata); break;
2483
2484             case VT_BSTR:
2485             case VT_LPSTR:
2486             case VT_LPWSTR:
2487             case VT_VARIANT:
2488             default:
2489                 FIXME("Invalid element type: %ul\n", pvarSrc->vt & VT_VECTOR);
2490                 return E_INVALIDARG;
2491             }
2492             len = pvarSrc->u.capropvar.cElems;
2493             pvarDest->u.capropvar.pElems = CoTaskMemAlloc(len * elemSize);
2494             if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT))
2495             {
2496                 ULONG i;
2497                 for (i = 0; i < len; i++)
2498                     PropVariantCopy(&pvarDest->u.capropvar.pElems[i], &pvarSrc->u.capropvar.pElems[i]);
2499             }
2500             else if (pvarSrc->vt == (VT_VECTOR | VT_CF))
2501             {
2502                 FIXME("Copy clipformats\n");
2503             }
2504             else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR))
2505             {
2506                 FIXME("Copy BSTRs\n");
2507             }
2508             else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
2509             {
2510                 FIXME("Copy LPSTRs\n");
2511             }
2512             else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
2513             {
2514                 FIXME("Copy LPWSTRs\n");
2515             }
2516             else
2517                 CopyMemory(pvarDest->u.capropvar.pElems, pvarSrc->u.capropvar.pElems, len * elemSize);
2518         }
2519     }
2520
2521     return S_OK;
2522 }
2523
2524 /***********************************************************************
2525  *           FreePropVariantArray                           [OLE32.@]
2526  */
2527 HRESULT WINAPI FreePropVariantArray(ULONG cVariants, /* [in] */
2528                                     PROPVARIANT *rgvars)    /* [in/out] */
2529 {
2530     ULONG i;
2531
2532     TRACE("(%lu, %p)\n", cVariants, rgvars);
2533
2534     for(i = 0; i < cVariants; i++)
2535         PropVariantClear(&rgvars[i]);
2536
2537     return S_OK;
2538 }
2539
2540 /******************************************************************************
2541  * DllDebugObjectRPCHook (OLE32.@)
2542  * turns on and off internal debugging,  pointer is only used on macintosh
2543  */
2544
2545 BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy)
2546 {
2547   FIXME("stub\n");
2548   return TRUE;
2549 }