General tidy up of the MetaFile driver - make sure that everything
[wine.git] / ole / ole2.c
blob8533303fc715d3744c91aa8f8c7815a49cfbdc3e
1 /*
2 * OLE2 library
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1999 Francis Beaudet
6 * Copyright 1999 Noel Borthwick
7 */
9 #include <assert.h>
11 #include "winuser.h"
12 #include "winerror.h"
13 #include "ole2.h"
14 #include "process.h"
15 #include "hook.h"
16 #include "commctrl.h"
17 #include "wine/obj_clientserver.h"
18 #include "debug.h"
19 #include "ole2ver.h"
21 DEFAULT_DEBUG_CHANNEL(ole)
23 /******************************************************************************
24 * These are static/global variables and internal data structures that the
25 * OLE module uses to maintain it's state.
27 typedef struct tagDropTargetNode
29 HWND hwndTarget;
30 IDropTarget* dropTarget;
31 struct tagDropTargetNode* prevDropTarget;
32 struct tagDropTargetNode* nextDropTarget;
33 } DropTargetNode;
35 typedef struct tagTrackerWindowInfo
37 IDataObject* dataObject;
38 IDropSource* dropSource;
39 DWORD dwOKEffect;
40 DWORD* pdwEffect;
41 BOOL trackingDone;
42 HRESULT returnValue;
44 BOOL escPressed;
45 HWND curDragTargetHWND;
46 IDropTarget* curDragTarget;
47 } TrackerWindowInfo;
49 typedef struct tagOleMenuDescriptor /* OleMenuDescriptor */
51 HWND hwndFrame; /* The containers frame window */
52 HWND hwndActiveObject; /* The active objects window */
53 OLEMENUGROUPWIDTHS mgw; /* OLE menu group widths for the shared menu */
54 HMENU hmenuCombined; /* The combined menu */
55 BOOL bIsServerItem; /* True if the currently open popup belongs to the server */
56 } OleMenuDescriptor;
58 typedef struct tagOleMenuHookItem /* OleMenu hook item in per thread hook list */
60 DWORD tid; /* Thread Id */
61 HANDLE hHeap; /* Heap this is allocated from */
62 HHOOK GetMsg_hHook; /* message hook for WH_GETMESSAGE */
63 HHOOK CallWndProc_hHook; /* message hook for WH_CALLWNDPROC */
64 } OleMenuHookItem;
67 * Dynamic pointer array of per thread message hooks (maintained by OleSetMenuDescriptor)
69 static HDPA OLEMenu_MsgHookDPA = NULL;
72 * This is the lock count on the OLE library. It is controlled by the
73 * OLEInitialize/OLEUninitialize methods.
75 static ULONG OLE_moduleLockCount = 0;
78 * Name of our registered window class.
80 static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";
83 * This is the head of the Drop target container.
85 static DropTargetNode* targetListHead = NULL;
87 /******************************************************************************
88 * These are the prototypes of the utility methods used to manage a shared menu
90 static void OLEMenu_Initialize();
91 static void OLEMenu_UnInitialize();
92 BOOL OLEMenu_InstallHooks( DWORD tid );
93 BOOL OLEMenu_UnInstallHooks( DWORD tid );
94 OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid, INT *pixHook );
95 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
96 BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor );
97 LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam);
98 LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam);
100 /******************************************************************************
101 * These are the prototypes of the utility methods used for OLE Drag n Drop
103 static void OLEDD_Initialize();
104 static void OLEDD_UnInitialize();
105 static void OLEDD_InsertDropTarget(
106 DropTargetNode* nodeToAdd);
107 static DropTargetNode* OLEDD_ExtractDropTarget(
108 HWND hwndOfTarget);
109 static DropTargetNode* OLEDD_FindDropTarget(
110 HWND hwndOfTarget);
111 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
112 HWND hwnd,
113 UINT uMsg,
114 WPARAM wParam,
115 LPARAM lParam);
116 static void OLEDD_TrackMouseMove(
117 TrackerWindowInfo* trackerInfo,
118 POINT mousePos,
119 DWORD keyState);
120 static void OLEDD_TrackStateChange(
121 TrackerWindowInfo* trackerInfo,
122 POINT mousePos,
123 DWORD keyState);
124 static DWORD OLEDD_GetButtonState();
127 /******************************************************************************
128 * OleBuildVersion [OLE2.1]
130 DWORD WINAPI OleBuildVersion(void)
132 TRACE(ole,"(void)\n");
133 return (rmm<<16)+rup;
136 /***********************************************************************
137 * OleInitialize (OLE2.2) (OLE32.108)
139 HRESULT WINAPI OleInitialize(LPVOID reserved)
141 HRESULT hr;
143 TRACE(ole, "(%p)\n", reserved);
146 * The first duty of the OleInitialize is to initialize the COM libraries.
148 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
151 * If the CoInitializeEx call failed, the OLE libraries can't be
152 * initialized.
154 if (FAILED(hr))
155 return hr;
158 * Then, it has to initialize the OLE specific modules.
159 * This includes:
160 * Clipboard
161 * Drag and Drop
162 * Object linking and Embedding
163 * In-place activation
165 if (OLE_moduleLockCount==0)
168 * Initialize the libraries.
170 TRACE(ole, "() - Initializing the OLE libraries\n");
173 * Drag and Drop
175 OLEDD_Initialize();
178 * OLE shared menu
180 OLEMenu_Initialize();
184 * Then, we increase the lock count on the OLE module.
186 OLE_moduleLockCount++;
188 return hr;
191 /******************************************************************************
192 * CoGetCurrentProcess [COMPOBJ.34] [OLE2.2][OLE32.108]
194 * NOTES
195 * Is DWORD really the correct return type for this function?
197 DWORD WINAPI CoGetCurrentProcess(void) {
198 return (DWORD)PROCESS_Current();
201 /******************************************************************************
202 * OleUninitialize [OLE2.3] [OLE32.131]
204 void WINAPI OleUninitialize(void)
206 TRACE(ole, "()\n");
209 * Decrease the lock count on the OLE module.
211 OLE_moduleLockCount--;
214 * If we hit the bottom of the lock stack, free the libraries.
216 if (OLE_moduleLockCount==0)
219 * Actually free the libraries.
221 TRACE(ole, "() - Freeing the last reference count\n");
224 * Drag and Drop
226 OLEDD_UnInitialize();
229 * OLE shared menu
231 OLEMenu_UnInitialize();
235 * Then, uninitialize the COM libraries.
237 CoUninitialize();
240 /***********************************************************************
241 * OleFlushClipboard [OLE2.76]
243 HRESULT WINAPI OleFlushClipboard16(void)
245 return S_OK;
248 /***********************************************************************
249 * OleSetClipboard [OLE32.127]
251 HRESULT WINAPI OleSetClipboard(LPVOID pDataObj)
253 FIXME(ole,"(%p), stub!\n", pDataObj);
254 return S_OK;
257 /******************************************************************************
258 * CoRegisterMessageFilter32 [OLE32.38]
260 HRESULT WINAPI CoRegisterMessageFilter(
261 LPMESSAGEFILTER lpMessageFilter, /* Pointer to interface */
262 LPMESSAGEFILTER *lplpMessageFilter /* Indirect pointer to prior instance if non-NULL */
264 FIXME(ole,"stub\n");
265 if (lplpMessageFilter) {
266 *lplpMessageFilter = NULL;
268 return S_OK;
271 /******************************************************************************
272 * OleInitializeWOW [OLE32.109]
274 HRESULT WINAPI OleInitializeWOW(DWORD x) {
275 FIXME(ole,"(0x%08lx),stub!\n",x);
276 return 0;
279 /***********************************************************************
280 * RegisterDragDrop16 (OLE2.35)
282 HRESULT WINAPI RegisterDragDrop16(
283 HWND16 hwnd,
284 LPDROPTARGET pDropTarget
286 FIXME(ole,"(0x%04x,%p),stub!\n",hwnd,pDropTarget);
287 return S_OK;
290 /***********************************************************************
291 * RegisterDragDrop32 (OLE32.139)
293 HRESULT WINAPI RegisterDragDrop(
294 HWND hwnd,
295 LPDROPTARGET pDropTarget)
297 DropTargetNode* dropTargetInfo;
299 TRACE(ole,"(0x%x,%p)\n", hwnd, pDropTarget);
302 * First, check if the window is already registered.
304 dropTargetInfo = OLEDD_FindDropTarget(hwnd);
306 if (dropTargetInfo!=NULL)
307 return DRAGDROP_E_ALREADYREGISTERED;
310 * If it's not there, we can add it. We first create a node for it.
312 dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));
314 if (dropTargetInfo==NULL)
315 return E_OUTOFMEMORY;
317 dropTargetInfo->hwndTarget = hwnd;
318 dropTargetInfo->prevDropTarget = NULL;
319 dropTargetInfo->nextDropTarget = NULL;
322 * Don't forget that this is an interface pointer, need to nail it down since
323 * we keep a copy of it.
325 dropTargetInfo->dropTarget = pDropTarget;
326 IDropTarget_AddRef(dropTargetInfo->dropTarget);
328 OLEDD_InsertDropTarget(dropTargetInfo);
330 return S_OK;
333 /***********************************************************************
334 * RevokeDragDrop16 (OLE2.36)
336 HRESULT WINAPI RevokeDragDrop16(
337 HWND16 hwnd
339 FIXME(ole,"(0x%04x),stub!\n",hwnd);
340 return S_OK;
343 /***********************************************************************
344 * RevokeDragDrop32 (OLE32.141)
346 HRESULT WINAPI RevokeDragDrop(
347 HWND hwnd)
349 DropTargetNode* dropTargetInfo;
351 TRACE(ole,"(0x%x)\n", hwnd);
354 * First, check if the window is already registered.
356 dropTargetInfo = OLEDD_ExtractDropTarget(hwnd);
359 * If it ain't in there, it's an error.
361 if (dropTargetInfo==NULL)
362 return DRAGDROP_E_NOTREGISTERED;
365 * If it's in there, clean-up it's used memory and
366 * references
368 IDropTarget_Release(dropTargetInfo->dropTarget);
369 HeapFree(GetProcessHeap(), 0, dropTargetInfo);
371 return S_OK;
374 /***********************************************************************
375 * OleRegGetUserType (OLE32.122)
377 HRESULT WINAPI OleRegGetUserType(
378 REFCLSID clsid,
379 DWORD dwFormOfType,
380 LPOLESTR* pszUserType)
382 FIXME(ole,",stub!\n");
383 return S_OK;
386 /***********************************************************************
387 * DoDragDrop32 [OLE32.65]
389 HRESULT WINAPI DoDragDrop (
390 IDataObject *pDataObject, /* ptr to the data obj */
391 IDropSource* pDropSource, /* ptr to the source obj */
392 DWORD dwOKEffect, /* effects allowed by the source */
393 DWORD *pdwEffect) /* ptr to effects of the source */
395 TrackerWindowInfo trackerInfo;
396 HWND hwndTrackWindow;
397 MSG msg;
399 TRACE(ole,"(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
402 * Setup the drag n drop tracking window.
404 trackerInfo.dataObject = pDataObject;
405 trackerInfo.dropSource = pDropSource;
406 trackerInfo.dwOKEffect = dwOKEffect;
407 trackerInfo.pdwEffect = pdwEffect;
408 trackerInfo.trackingDone = FALSE;
409 trackerInfo.escPressed = FALSE;
410 trackerInfo.curDragTargetHWND = 0;
411 trackerInfo.curDragTarget = 0;
413 hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS,
414 "TrackerWindow",
415 WS_POPUP,
416 CW_USEDEFAULT, CW_USEDEFAULT,
417 CW_USEDEFAULT, CW_USEDEFAULT,
421 (LPVOID)&trackerInfo);
423 if (hwndTrackWindow!=0)
426 * Capture the mouse input
428 SetCapture(hwndTrackWindow);
431 * Pump messages. All mouse input should go the the capture window.
433 while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )
435 if ( (msg.message >= WM_KEYFIRST) &&
436 (msg.message <= WM_KEYFIRST) )
439 * When keyboard messages are sent to windows on this thread, we
440 * want to ignore notify the drop source that the state changed.
441 * in the case of the Escape key, we also notify the drop source
442 * we give it a special meaning.
444 if ( (msg.message==WM_KEYDOWN) &&
445 (msg.wParam==VK_ESCAPE) )
447 trackerInfo.escPressed = TRUE;
451 * Notify the drop source.
453 OLEDD_TrackStateChange(&trackerInfo,
454 msg.pt,
455 OLEDD_GetButtonState());
457 else
460 * Dispatch the messages only when it's not a keyboard message.
462 DispatchMessageA(&msg);
467 * Destroy the temporary window.
469 DestroyWindow(hwndTrackWindow);
471 return trackerInfo.returnValue;
474 return E_FAIL;
477 /***********************************************************************
478 * OleQueryLinkFromData32 [OLE32.118]
480 HRESULT WINAPI OleQueryLinkFromData(
481 IDataObject* pSrcDataObject)
483 FIXME(ole,"(%p),stub!\n", pSrcDataObject);
484 return S_OK;
487 /***********************************************************************
488 * OleRegGetMiscStatus [OLE32.121]
490 HRESULT WINAPI OleRegGetMiscStatus(
491 REFCLSID clsid,
492 DWORD dwAspect,
493 DWORD* pdwStatus)
495 FIXME(ole,"(),stub!\n");
496 return REGDB_E_CLASSNOTREG;
499 /***********************************************************************
500 * OleGetClipboard32 [OLE32.105]
502 HRESULT WINAPI OleGetClipboard(
503 IDataObject** ppDataObj)
505 FIXME(ole,"(%p),stub!\n", ppDataObj);
507 if (ppDataObj)
508 *ppDataObj=0;
510 return E_FAIL;
514 /**************************************************************************
515 * Internal methods to manage the shared OLE menu in response to the
516 * OLE***MenuDescriptor API
519 /***
520 * OLEMenu_Initialize()
522 * Initializes the OLEMENU data structures.
524 static void OLEMenu_Initialize()
526 /* Create a dynamic pointer array to store the hook handles */
527 if ( !OLEMenu_MsgHookDPA )
528 OLEMenu_MsgHookDPA = DPA_CreateEx( 2, GetProcessHeap() );
531 /***
532 * OLEMenu_UnInitialize()
534 * Releases the OLEMENU data structures.
536 static void OLEMenu_UnInitialize()
538 /* Release the hook table */
539 if ( OLEMenu_MsgHookDPA )
540 DPA_Destroy( OLEMenu_MsgHookDPA );
542 OLEMenu_MsgHookDPA = NULL;
545 /*************************************************************************
546 * OLEMenu_InstallHooks
547 * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
549 * RETURNS: TRUE if message hooks were succesfully installed
550 * FALSE on failure
552 BOOL OLEMenu_InstallHooks( DWORD tid )
554 OleMenuHookItem *pHookItem = NULL;
556 if ( !OLEMenu_MsgHookDPA ) /* No hook table? Create one */
558 /* Create a dynamic pointer array to store the hook handles */
559 if ( !(OLEMenu_MsgHookDPA = DPA_CreateEx( 2, GetProcessHeap() )) )
560 return FALSE;
563 /* Create an entry for the hook table */
564 if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
565 sizeof(OleMenuHookItem)) ) )
566 return FALSE;
568 pHookItem->tid = tid;
569 pHookItem->hHeap = GetProcessHeap();
571 /* Install a thread scope message hook for WH_GETMESSAGE */
572 pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc,
573 0, GetCurrentThreadId() );
574 if ( !pHookItem->GetMsg_hHook )
575 goto CLEANUP;
577 /* Install a thread scope message hook for WH_CALLWNDPROC */
578 pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc,
579 0, GetCurrentThreadId() );
580 if ( !pHookItem->CallWndProc_hHook )
581 goto CLEANUP;
583 /* Insert the hook table entry */
584 if ( -1 == DPA_InsertPtr( OLEMenu_MsgHookDPA, 0, pHookItem ) )
585 goto CLEANUP;
587 return TRUE;
589 CLEANUP:
590 /* Unhook any hooks */
591 if ( pHookItem->GetMsg_hHook )
592 UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
593 if ( pHookItem->CallWndProc_hHook )
594 UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
595 /* Release the hook table entry */
596 HeapFree(pHookItem->hHeap, 0, pHookItem );
598 return FALSE;
601 /*************************************************************************
602 * OLEMenu_UnInstallHooks
603 * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
605 * RETURNS: TRUE if message hooks were succesfully installed
606 * FALSE on failure
608 BOOL OLEMenu_UnInstallHooks( DWORD tid )
610 INT ixHook;
611 OleMenuHookItem *pHookItem = NULL;
613 if ( !OLEMenu_MsgHookDPA ) /* No hooks set */
614 return TRUE;
616 /* Lookup the hHook index for this tid */
617 if ( !OLEMenu_IsHookInstalled( tid , &ixHook ) )
618 return TRUE;
620 /* Remove the hook entry from the table(the pointer itself is not deleted) */
621 if ( !( pHookItem = DPA_DeletePtr(OLEMenu_MsgHookDPA, ixHook) ) )
622 return FALSE;
624 /* Uninstall the hooks installed for this thread */
625 if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
626 goto CLEANUP;
627 if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
628 goto CLEANUP;
630 /* Release the hook table entry */
631 HeapFree(pHookItem->hHeap, 0, pHookItem );
633 return TRUE;
635 CLEANUP:
636 /* Release the hook table entry */
637 if (pHookItem)
638 HeapFree(pHookItem->hHeap, 0, pHookItem );
640 return FALSE;
643 /*************************************************************************
644 * OLEMenu_IsHookInstalled
645 * Tests if OLEMenu hooks have been installed for a thread
647 * RETURNS: The pointer and index of the hook table entry for the tid
648 * NULL and -1 for the index if no hooks were installed for this thread
650 OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid, INT *pixHook )
652 INT ixHook;
653 OleMenuHookItem *pHookItem = NULL;
655 if ( pixHook )
656 *pixHook = -1;
658 if ( !OLEMenu_MsgHookDPA ) /* No hooks set */
659 return NULL;
661 /* Do a simple linear search for an entry whose tid matches ours.
662 * We really need a map but efficiency is not a concern here. */
663 for( ixHook = 0; ; ixHook++ )
665 /* Retrieve the hook entry */
666 if ( !( pHookItem = DPA_GetPtr(OLEMenu_MsgHookDPA, ixHook) ) )
667 return NULL;
669 if ( tid == pHookItem->tid )
671 if ( pixHook )
672 *pixHook = ixHook;
673 return pHookItem;
677 return NULL;
680 /***********************************************************************
681 * OLEMenu_FindMainMenuIndex
683 * Used by OLEMenu API to find the top level group a menu item belongs to.
684 * On success pnPos contains the index of the item in the top level menu group
686 * RETURNS: TRUE if the ID was found, FALSE on failure
688 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
690 UINT i, nItems;
692 nItems = GetMenuItemCount( hMainMenu );
694 for (i = 0; i < nItems; i++)
696 HMENU hsubmenu;
698 /* Is the current item a submenu? */
699 if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
701 /* If the handle is the same we're done */
702 if ( hsubmenu == hPopupMenu )
704 if (pnPos)
705 *pnPos = i;
706 return TRUE;
708 /* Recursively search without updating pnPos */
709 else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
711 if (pnPos)
712 *pnPos = i;
713 return TRUE;
718 return FALSE;
721 /***********************************************************************
722 * OLEMenu_SetIsServerMenu
724 * Checks whether a popup menu belongs to a shared menu group which is
725 * owned by the server, and sets the menu descriptor state accordingly.
726 * All menu messages from these groups should be routed to the server.
728 * RETURNS: TRUE if the popup menu is part of a server owned group
729 * FASE if the popup menu is part of a container owned group
731 BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
733 UINT nPos = 0, nWidth, i;
735 pOleMenuDescriptor->bIsServerItem = FALSE;
737 /* Don't bother searching if the popup is the combined menu itself */
738 if ( hmenu == pOleMenuDescriptor->hmenuCombined )
739 return FALSE;
741 /* Find the menu item index in the shared OLE menu that this item belongs to */
742 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) )
743 return FALSE;
745 /* The group widths array has counts for the number of elements
746 * in the groups File, Edit, Container, Object, Window, Help.
747 * The Edit, Object & Help groups belong to the server object
748 * and the other three belong to the container.
749 * Loop thru the group widths and locate the group we are a member of.
751 for ( i = 0, nWidth = 0; i < 6; i++ )
753 nWidth += pOleMenuDescriptor->mgw.width[i];
754 if ( nPos < nWidth )
756 /* Odd elements are server menu widths */
757 pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;
758 break;
762 return pOleMenuDescriptor->bIsServerItem;
765 /*************************************************************************
766 * OLEMenu_CallWndProc
767 * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
768 * This is invoked from a message hook installed in OleSetMenuDescriptor.
770 LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
772 LPCWPSTRUCT pMsg = NULL;
773 HOLEMENU hOleMenu = 0;
774 OleMenuDescriptor *pOleMenuDescriptor = NULL;
775 OleMenuHookItem *pHookItem = NULL;
776 WORD fuFlags;
778 TRACE(ole,"%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
780 /* Check if we're being asked to process the message */
781 if ( HC_ACTION != code )
782 goto NEXTHOOK;
784 /* Retrieve the current message being dispatched from lParam */
785 pMsg = (LPCWPSTRUCT)lParam;
787 /* Check if the message is destined for a window we are interested in:
788 * If the window has an OLEMenu property we may need to dispatch
789 * the menu message to its active objects window instead. */
791 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
792 if ( !hOleMenu )
793 goto NEXTHOOK;
795 /* Get the menu descriptor */
796 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
797 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
798 goto NEXTHOOK;
800 /* Process menu messages */
801 switch( pMsg->message )
803 case WM_INITMENU:
805 /* Reset the menu descriptor state */
806 pOleMenuDescriptor->bIsServerItem = FALSE;
808 /* Send this message to the server as well */
809 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
810 pMsg->message, pMsg->wParam, pMsg->lParam );
811 goto NEXTHOOK;
814 case WM_INITMENUPOPUP:
816 /* Save the state for whether this is a server owned menu */
817 OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
818 break;
821 case WM_MENUSELECT:
823 fuFlags = HIWORD(pMsg->wParam); /* Get flags */
824 if ( fuFlags & MF_SYSMENU )
825 goto NEXTHOOK;
827 /* Save the state for whether this is a server owned popup menu */
828 else if ( fuFlags & MF_POPUP )
829 OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
831 break;
834 case WM_DRAWITEM:
836 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
837 if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
838 goto NEXTHOOK; /* Not a menu message */
840 break;
843 default:
844 goto NEXTHOOK;
847 /* If the message was for the server dispatch it accordingly */
848 if ( pOleMenuDescriptor->bIsServerItem )
850 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
851 pMsg->message, pMsg->wParam, pMsg->lParam );
854 NEXTHOOK:
855 if ( pOleMenuDescriptor )
856 GlobalUnlock( hOleMenu );
858 /* Lookup the hook item for the current thread */
859 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId(), NULL ) ) )
861 /* This should never fail!! */
862 WARN(ole, "could not retrieve hHook for current thread!\n" );
863 return 0;
866 /* Pass on the message to the next hooker */
867 return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
870 /*************************************************************************
871 * OLEMenu_GetMsgProc
872 * Thread scope WH_GETMESSAGE hook proc filter function (callback)
873 * This is invoked from a message hook installed in OleSetMenuDescriptor.
875 LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
877 LPMSG pMsg = NULL;
878 HOLEMENU hOleMenu = 0;
879 OleMenuDescriptor *pOleMenuDescriptor = NULL;
880 OleMenuHookItem *pHookItem = NULL;
881 WORD wCode;
883 TRACE(ole,"%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
885 /* Check if we're being asked to process a messages */
886 if ( HC_ACTION != code )
887 goto NEXTHOOK;
889 /* Retrieve the current message being dispatched from lParam */
890 pMsg = (LPMSG)lParam;
892 /* Check if the message is destined for a window we are interested in:
893 * If the window has an OLEMenu property we may need to dispatch
894 * the menu message to its active objects window instead. */
896 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
897 if ( !hOleMenu )
898 goto NEXTHOOK;
900 /* Process menu messages */
901 switch( pMsg->message )
903 case WM_COMMAND:
905 wCode = HIWORD(pMsg->wParam); /* Get notification code */
906 if ( wCode )
907 goto NEXTHOOK; /* Not a menu message */
908 break;
910 default:
911 goto NEXTHOOK;
914 /* Get the menu descriptor */
915 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
916 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
917 goto NEXTHOOK;
919 /* If the message was for the server dispatch it accordingly */
920 if ( pOleMenuDescriptor->bIsServerItem )
922 /* Change the hWnd in the message to the active objects hWnd.
923 * The message loop which reads this message will automatically
924 * dispatch it to the embedded objects window. */
925 pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
928 NEXTHOOK:
929 if ( pOleMenuDescriptor )
930 GlobalUnlock( hOleMenu );
932 /* Lookup the hook item for the current thread */
933 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId(), NULL ) ) )
935 /* This should never fail!! */
936 WARN(ole, "could not retrieve hHook for current thread!\n" );
937 return FALSE;
940 /* Pass on the message to the next hooker */
941 return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
944 /***********************************************************************
945 * OleCreateMenuDescriptor [OLE32.97]
946 * Creates an OLE menu descriptor for OLE to use when dispatching
947 * menu messages and commands.
949 * PARAMS:
950 * hmenuCombined - Handle to the objects combined menu
951 * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group
954 HOLEMENU WINAPI OleCreateMenuDescriptor(
955 HMENU hmenuCombined,
956 LPOLEMENUGROUPWIDTHS lpMenuWidths)
958 HOLEMENU hOleMenu;
959 OleMenuDescriptor *pOleMenuDescriptor;
960 int i;
962 if ( !hmenuCombined || !lpMenuWidths )
963 return 0;
965 /* Create an OLE menu descriptor */
966 if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
967 sizeof(OleMenuDescriptor) ) ) )
968 return 0;
970 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
971 if ( !pOleMenuDescriptor )
972 return 0;
974 /* Initialize menu group widths and hmenu */
975 for ( i = 0; i < 6; i++ )
976 pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
978 pOleMenuDescriptor->hmenuCombined = hmenuCombined;
979 pOleMenuDescriptor->bIsServerItem = FALSE;
980 GlobalUnlock( hOleMenu );
982 return hOleMenu;
985 /***********************************************************************
986 * OleDestroyMenuDescriptor [OLE32.99]
987 * Destroy the shared menu descriptor
989 HRESULT WINAPI OleDestroyMenuDescriptor(
990 HOLEMENU hmenuDescriptor)
992 if ( hmenuDescriptor )
993 GlobalFree( hmenuDescriptor );
994 return S_OK;
997 /***********************************************************************
998 * OleSetMenuDescriptor [OLE32.129]
999 * Installs or removes OLE dispatching code for the containers frame window
1000 * FIXME: The lpFrame and lpActiveObject parameters are currently ignored
1001 * OLE should install context sensitive help F1 filtering for the app when
1002 * these are non null.
1004 * PARAMS:
1005 * hOleMenu Handle to composite menu descriptor
1006 * hwndFrame Handle to containers frame window
1007 * hwndActiveObject Handle to objects in-place activation window
1008 * lpFrame Pointer to IOleInPlaceFrame on containers window
1009 * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object
1011 * RETURNS:
1012 * S_OK - menu installed correctly
1013 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1015 HRESULT WINAPI OleSetMenuDescriptor(
1016 HOLEMENU hOleMenu,
1017 HWND hwndFrame,
1018 HWND hwndActiveObject,
1019 LPOLEINPLACEFRAME lpFrame,
1020 LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1022 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1024 /* Check args */
1025 if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
1026 return E_INVALIDARG;
1028 if ( lpFrame || lpActiveObject )
1030 FIXME(ole,"(%x, %x, %x, %p, %p), Context sensitive help filtering not implemented!\n",
1031 (unsigned int)hOleMenu,
1032 hwndFrame,
1033 hwndActiveObject,
1034 lpFrame,
1035 lpActiveObject);
1038 /* Set up a message hook to intercept the containers frame window messages.
1039 * The message filter is responsible for dispatching menu messages from the
1040 * shared menu which are intended for the object.
1043 if ( hOleMenu ) /* Want to install dispatching code */
1045 /* If OLEMenu hooks are already installed for this thread, fail
1046 * Note: This effectively means that OleSetMenuDescriptor cannot
1047 * be called twice in succession on the same frame window
1048 * without first calling it with a null hOleMenu to uninstall */
1049 if ( OLEMenu_IsHookInstalled( GetCurrentThreadId(), NULL ) )
1050 return E_FAIL;
1052 /* Get the menu descriptor */
1053 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1054 if ( !pOleMenuDescriptor )
1055 return E_UNEXPECTED;
1057 /* Update the menu descriptor */
1058 pOleMenuDescriptor->hwndFrame = hwndFrame;
1059 pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
1061 GlobalUnlock( hOleMenu );
1062 pOleMenuDescriptor = NULL;
1064 /* Add a menu descriptor windows property to the frame window */
1065 SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu );
1067 /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
1068 if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
1069 return E_FAIL;
1071 else /* Want to uninstall dispatching code */
1073 /* Uninstall the hooks */
1074 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1075 return E_FAIL;
1077 /* Remove the menu descriptor property from the frame window */
1078 RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" );
1081 return S_OK;
1084 /***********************************************************************
1085 * ReleaseStgMedium [OLE32.140]
1087 void WINAPI ReleaseStgMedium(
1088 STGMEDIUM* pmedium)
1090 switch (pmedium->tymed)
1092 case TYMED_HGLOBAL:
1094 if ( (pmedium->pUnkForRelease==0) &&
1095 (pmedium->u.hGlobal!=0) )
1096 GlobalFree(pmedium->u.hGlobal);
1098 pmedium->u.hGlobal = 0;
1099 break;
1101 case TYMED_FILE:
1103 if (pmedium->u.lpszFileName!=0)
1105 if (pmedium->pUnkForRelease==0)
1107 DeleteFileW(pmedium->u.lpszFileName);
1110 CoTaskMemFree(pmedium->u.lpszFileName);
1113 pmedium->u.lpszFileName = 0;
1114 break;
1116 case TYMED_ISTREAM:
1118 if (pmedium->u.pstm!=0)
1120 IStream_Release(pmedium->u.pstm);
1123 pmedium->u.pstm = 0;
1124 break;
1126 case TYMED_ISTORAGE:
1128 if (pmedium->u.pstg!=0)
1130 IStorage_Release(pmedium->u.pstg);
1133 pmedium->u.pstg = 0;
1134 break;
1136 case TYMED_GDI:
1138 if ( (pmedium->pUnkForRelease==0) &&
1139 (pmedium->u.hGlobal!=0) )
1140 DeleteObject(pmedium->u.hGlobal);
1142 pmedium->u.hGlobal = 0;
1143 break;
1145 case TYMED_MFPICT:
1147 if ( (pmedium->pUnkForRelease==0) &&
1148 (pmedium->u.hMetaFilePict!=0) )
1150 DeleteMetaFile(pmedium->u.hMetaFilePict);
1151 GlobalFree(pmedium->u.hMetaFilePict);
1154 pmedium->u.hMetaFilePict = 0;
1155 break;
1157 case TYMED_ENHMF:
1159 if ( (pmedium->pUnkForRelease==0) &&
1160 (pmedium->u.hEnhMetaFile!=0) )
1162 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
1165 pmedium->u.hEnhMetaFile = 0;
1166 break;
1168 case TYMED_NULL:
1169 default:
1170 break;
1174 * After cleaning up, the unknown is released
1176 if (pmedium->pUnkForRelease!=0)
1178 IUnknown_Release(pmedium->pUnkForRelease);
1179 pmedium->pUnkForRelease = 0;
1183 /***
1184 * OLEDD_Initialize()
1186 * Initializes the OLE drag and drop data structures.
1188 static void OLEDD_Initialize()
1190 WNDCLASSA wndClass;
1192 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1193 wndClass.style = CS_GLOBALCLASS;
1194 wndClass.lpfnWndProc = (WNDPROC)OLEDD_DragTrackerWindowProc;
1195 wndClass.cbClsExtra = 0;
1196 wndClass.cbWndExtra = sizeof(TrackerWindowInfo*);
1197 wndClass.hCursor = 0;
1198 wndClass.hbrBackground = 0;
1199 wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
1201 RegisterClassA (&wndClass);
1204 /***
1205 * OLEDD_UnInitialize()
1207 * Releases the OLE drag and drop data structures.
1209 static void OLEDD_UnInitialize()
1212 * Simply empty the list.
1214 while (targetListHead!=NULL)
1216 RevokeDragDrop(targetListHead->hwndTarget);
1220 /***
1221 * OLEDD_InsertDropTarget()
1223 * Insert the target node in the tree.
1225 static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd)
1227 DropTargetNode* curNode;
1228 DropTargetNode** parentNodeLink;
1231 * Iterate the tree to find the insertion point.
1233 curNode = targetListHead;
1234 parentNodeLink = &targetListHead;
1236 while (curNode!=NULL)
1238 if (nodeToAdd->hwndTarget<curNode->hwndTarget)
1241 * If the node we want to add has a smaller HWND, go left
1243 parentNodeLink = &curNode->prevDropTarget;
1244 curNode = curNode->prevDropTarget;
1246 else if (nodeToAdd->hwndTarget>curNode->hwndTarget)
1249 * If the node we want to add has a larger HWND, go right
1251 parentNodeLink = &curNode->nextDropTarget;
1252 curNode = curNode->nextDropTarget;
1254 else
1257 * The item was found in the list. It shouldn't have been there
1259 assert(FALSE);
1260 return;
1265 * If we get here, we have found a spot for our item. The parentNodeLink
1266 * pointer points to the pointer that we have to modify.
1267 * The curNode should be NULL. We just have to establish the link and Voila!
1269 assert(curNode==NULL);
1270 assert(parentNodeLink!=NULL);
1271 assert(*parentNodeLink==NULL);
1273 *parentNodeLink=nodeToAdd;
1276 /***
1277 * OLEDD_ExtractDropTarget()
1279 * Removes the target node from the tree.
1281 static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget)
1283 DropTargetNode* curNode;
1284 DropTargetNode** parentNodeLink;
1287 * Iterate the tree to find the insertion point.
1289 curNode = targetListHead;
1290 parentNodeLink = &targetListHead;
1292 while (curNode!=NULL)
1294 if (hwndOfTarget<curNode->hwndTarget)
1297 * If the node we want to add has a smaller HWND, go left
1299 parentNodeLink = &curNode->prevDropTarget;
1300 curNode = curNode->prevDropTarget;
1302 else if (hwndOfTarget>curNode->hwndTarget)
1305 * If the node we want to add has a larger HWND, go right
1307 parentNodeLink = &curNode->nextDropTarget;
1308 curNode = curNode->nextDropTarget;
1310 else
1313 * The item was found in the list. Detach it from it's parent and
1314 * re-insert it's kids in the tree.
1316 assert(parentNodeLink!=NULL);
1317 assert(*parentNodeLink==curNode);
1320 * We arbitrately re-attach the left sub-tree to the parent.
1322 *parentNodeLink = curNode->prevDropTarget;
1325 * And we re-insert the right subtree
1327 if (curNode->nextDropTarget!=NULL)
1329 OLEDD_InsertDropTarget(curNode->nextDropTarget);
1333 * The node we found is still a valid node once we complete
1334 * the unlinking of the kids.
1336 curNode->nextDropTarget=NULL;
1337 curNode->prevDropTarget=NULL;
1339 return curNode;
1344 * If we get here, the node is not in the tree
1346 return NULL;
1349 /***
1350 * OLEDD_FindDropTarget()
1352 * Finds information about the drop target.
1354 static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
1356 DropTargetNode* curNode;
1359 * Iterate the tree to find the HWND value.
1361 curNode = targetListHead;
1363 while (curNode!=NULL)
1365 if (hwndOfTarget<curNode->hwndTarget)
1368 * If the node we want to add has a smaller HWND, go left
1370 curNode = curNode->prevDropTarget;
1372 else if (hwndOfTarget>curNode->hwndTarget)
1375 * If the node we want to add has a larger HWND, go right
1377 curNode = curNode->nextDropTarget;
1379 else
1382 * The item was found in the list.
1384 return curNode;
1389 * If we get here, the item is not in the list
1391 return NULL;
1394 /***
1395 * OLEDD_DragTrackerWindowProc()
1397 * This method is the WindowProcedure of the drag n drop tracking
1398 * window. During a drag n Drop operation, an invisible window is created
1399 * to receive the user input and act upon it. This procedure is in charge
1400 * of this behavior.
1402 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
1403 HWND hwnd,
1404 UINT uMsg,
1405 WPARAM wParam,
1406 LPARAM lParam)
1408 switch (uMsg)
1410 case WM_CREATE:
1412 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
1414 SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams);
1417 break;
1419 case WM_MOUSEMOVE:
1421 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1422 POINT mousePos;
1425 * Get the current mouse position in screen coordinates.
1427 mousePos.x = LOWORD(lParam);
1428 mousePos.y = HIWORD(lParam);
1429 ClientToScreen(hwnd, &mousePos);
1432 * Track the movement of the mouse.
1434 OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam);
1436 break;
1438 case WM_LBUTTONUP:
1439 case WM_MBUTTONUP:
1440 case WM_RBUTTONUP:
1441 case WM_LBUTTONDOWN:
1442 case WM_MBUTTONDOWN:
1443 case WM_RBUTTONDOWN:
1445 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1446 POINT mousePos;
1449 * Get the current mouse position in screen coordinates.
1451 mousePos.x = LOWORD(lParam);
1452 mousePos.y = HIWORD(lParam);
1453 ClientToScreen(hwnd, &mousePos);
1456 * Notify everyone that the button state changed
1457 * TODO: Check if the "escape" key was pressed.
1459 OLEDD_TrackStateChange(trackerInfo, mousePos, wParam);
1461 break;
1466 * This is a window proc after all. Let's call the default.
1468 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1471 /***
1472 * OLEDD_TrackMouseMove()
1474 * This method is invoked while a drag and drop operation is in effect.
1475 * it will generate the appropriate callbacks in the drop source
1476 * and drop target. It will also provide the expected feedback to
1477 * the user.
1479 * params:
1480 * trackerInfo - Pointer to the structure identifying the
1481 * drag & drop operation that is currently
1482 * active.
1483 * mousePos - Current position of the mouse in screen
1484 * coordinates.
1485 * keyState - Contains the state of the shift keys and the
1486 * mouse buttons (MK_LBUTTON and the like)
1488 static void OLEDD_TrackMouseMove(
1489 TrackerWindowInfo* trackerInfo,
1490 POINT mousePos,
1491 DWORD keyState)
1493 HWND hwndNewTarget = 0;
1494 HRESULT hr = S_OK;
1497 * Get the handle of the window under the mouse
1499 hwndNewTarget = WindowFromPoint(mousePos);
1502 * If we are hovering over the same target as before, send the
1503 * DragOver notification
1505 if ( (trackerInfo->curDragTarget != 0) &&
1506 (trackerInfo->curDragTargetHWND==hwndNewTarget) )
1508 POINTL mousePosParam;
1511 * The documentation tells me that the coordinate should be in the target
1512 * window's coordinate space. However, the tests I made tell me the
1513 * coordinates should be in screen coordinates.
1515 mousePosParam.x = mousePos.x;
1516 mousePosParam.y = mousePos.y;
1518 IDropTarget_DragOver(trackerInfo->curDragTarget,
1519 keyState,
1520 mousePosParam,
1521 trackerInfo->pdwEffect);
1523 else
1525 DropTargetNode* newDropTargetNode = 0;
1528 * If we changed window, we have to notify our old target and check for
1529 * the new one.
1531 if (trackerInfo->curDragTarget!=0)
1533 IDropTarget_DragLeave(trackerInfo->curDragTarget);
1537 * Make sure we're hovering over a window.
1539 if (hwndNewTarget!=0)
1542 * Find-out if there is a drag target under the mouse
1544 newDropTargetNode = OLEDD_FindDropTarget(hwndNewTarget);
1546 trackerInfo->curDragTargetHWND = hwndNewTarget;
1547 trackerInfo->curDragTarget = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
1550 * If there is, notify it that we just dragged-in
1552 if (trackerInfo->curDragTarget!=0)
1554 POINTL mousePosParam;
1557 * The documentation tells me that the coordinate should be in the target
1558 * window's coordinate space. However, the tests I made tell me the
1559 * coordinates should be in screen coordinates.
1561 mousePosParam.x = mousePos.x;
1562 mousePosParam.y = mousePos.y;
1564 IDropTarget_DragEnter(trackerInfo->curDragTarget,
1565 trackerInfo->dataObject,
1566 keyState,
1567 mousePosParam,
1568 trackerInfo->pdwEffect);
1571 else
1574 * The mouse is not over a window so we don't track anything.
1576 trackerInfo->curDragTargetHWND = 0;
1577 trackerInfo->curDragTarget = 0;
1582 * Now that we have done that, we have to tell the source to give
1583 * us feedback on the work being done by the target. If we don't
1584 * have a target, simulate no effect.
1586 if (trackerInfo->curDragTarget==0)
1588 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
1591 hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
1592 *trackerInfo->pdwEffect);
1595 * When we ask for feedback from the drop source, sometimes it will
1596 * do all the necessary work and sometimes it will not handle it
1597 * when that's the case, we must display the standard drag and drop
1598 * cursors.
1600 if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
1602 if ( (*trackerInfo->pdwEffect & DROPEFFECT_MOVE) ||
1603 (*trackerInfo->pdwEffect & DROPEFFECT_COPY) ||
1604 (*trackerInfo->pdwEffect & DROPEFFECT_LINK) )
1606 SetCursor(LoadCursorA(0, IDC_SIZEALLA));
1608 else
1610 SetCursor(LoadCursorA(0, IDC_NOA));
1615 /***
1616 * OLEDD_TrackStateChange()
1618 * This method is invoked while a drag and drop operation is in effect.
1619 * It is used to notify the drop target/drop source callbacks when
1620 * the state of the keyboard or mouse button change.
1622 * params:
1623 * trackerInfo - Pointer to the structure identifying the
1624 * drag & drop operation that is currently
1625 * active.
1626 * mousePos - Current position of the mouse in screen
1627 * coordinates.
1628 * keyState - Contains the state of the shift keys and the
1629 * mouse buttons (MK_LBUTTON and the like)
1631 static void OLEDD_TrackStateChange(
1632 TrackerWindowInfo* trackerInfo,
1633 POINT mousePos,
1634 DWORD keyState)
1637 * Ask the drop source what to do with the operation.
1639 trackerInfo->returnValue = IDropSource_QueryContinueDrag(
1640 trackerInfo->dropSource,
1641 trackerInfo->escPressed,
1642 keyState);
1645 * All the return valued will stop the operation except the S_OK
1646 * return value.
1648 if (trackerInfo->returnValue!=S_OK)
1651 * Make sure the message loop in DoDragDrop stops
1653 trackerInfo->trackingDone = TRUE;
1656 * Release the mouse in case the drop target decides to show a popup
1657 * or a menu or something.
1659 ReleaseCapture();
1662 * If we end-up over a target, drop the object in the target or
1663 * inform the target that the operation was cancelled.
1665 if (trackerInfo->curDragTarget!=0)
1667 switch (trackerInfo->returnValue)
1670 * If the source wants us to complete the operation, we tell
1671 * the drop target that we just dropped the object in it.
1673 case DRAGDROP_S_DROP:
1675 POINTL mousePosParam;
1678 * The documentation tells me that the coordinate should be
1679 * in the target window's coordinate space. However, the tests
1680 * I made tell me the coordinates should be in screen coordinates.
1682 mousePosParam.x = mousePos.x;
1683 mousePosParam.y = mousePos.y;
1685 IDropTarget_Drop(trackerInfo->curDragTarget,
1686 trackerInfo->dataObject,
1687 keyState,
1688 mousePosParam,
1689 trackerInfo->pdwEffect);
1690 break;
1693 * If the source told us that we should cancel, fool the drop
1694 * target by telling it that the mouse left it's window.
1696 case DRAGDROP_S_CANCEL:
1697 IDropTarget_DragLeave(trackerInfo->curDragTarget);
1698 break;
1704 /***
1705 * OLEDD_GetButtonState()
1707 * This method will use the current state of the keyboard to build
1708 * a button state mask equivalent to the one passed in the
1709 * WM_MOUSEMOVE wParam.
1711 static DWORD OLEDD_GetButtonState()
1713 BYTE keyboardState[256];
1714 DWORD keyMask = 0;
1716 GetKeyboardState(keyboardState);
1718 if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
1719 keyMask |= MK_SHIFT;
1721 if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
1722 keyMask |= MK_CONTROL;
1724 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
1725 keyMask |= MK_LBUTTON;
1727 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
1728 keyMask |= MK_RBUTTON;
1730 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
1731 keyMask |= MK_MBUTTON;
1733 return keyMask;