Added timeout to critical section waiting.
[wine/multimedia.git] / ole / ole2.c
blobb947d2ef1805840bf36f8faaab0d5982c05156f5
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 /******************************************************************************
22 * These are static/global variables and internal data structures that the
23 * OLE module uses to maintain it's state.
25 typedef struct tagDropTargetNode
27 HWND hwndTarget;
28 IDropTarget* dropTarget;
29 struct tagDropTargetNode* prevDropTarget;
30 struct tagDropTargetNode* nextDropTarget;
31 } DropTargetNode;
33 typedef struct tagTrackerWindowInfo
35 IDataObject* dataObject;
36 IDropSource* dropSource;
37 DWORD dwOKEffect;
38 DWORD* pdwEffect;
39 BOOL trackingDone;
40 HRESULT returnValue;
42 BOOL escPressed;
43 HWND curDragTargetHWND;
44 IDropTarget* curDragTarget;
45 } TrackerWindowInfo;
47 typedef struct tagOleMenuDescriptor /* OleMenuDescriptor */
49 HWND hwndFrame; /* The containers frame window */
50 HWND hwndActiveObject; /* The active objects window */
51 OLEMENUGROUPWIDTHS mgw; /* OLE menu group widths for the shared menu */
52 HMENU hmenuCombined; /* The combined menu */
53 BOOL bIsServerItem; /* True if the currently open popup belongs to the server */
54 } OleMenuDescriptor;
56 typedef struct tagOleMenuHookItem /* OleMenu hook item in per thread hook list */
58 DWORD tid; /* Thread Id */
59 HANDLE hHeap; /* Heap this is allocated from */
60 HHOOK GetMsg_hHook; /* message hook for WH_GETMESSAGE */
61 HHOOK CallWndProc_hHook; /* message hook for WH_CALLWNDPROC */
62 } OleMenuHookItem;
65 * Dynamic pointer array of per thread message hooks (maintained by OleSetMenuDescriptor)
67 static HDPA OLEMenu_MsgHookDPA = NULL;
70 * This is the lock count on the OLE library. It is controlled by the
71 * OLEInitialize/OLEUninitialize methods.
73 static ULONG OLE_moduleLockCount = 0;
76 * Name of our registered window class.
78 static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";
81 * This is the head of the Drop target container.
83 static DropTargetNode* targetListHead = NULL;
85 /******************************************************************************
86 * These are the prototypes of the utility methods used to manage a shared menu
88 static void OLEMenu_Initialize();
89 static void OLEMenu_UnInitialize();
90 BOOL OLEMenu_InstallHooks( DWORD tid );
91 BOOL OLEMenu_UnInstallHooks( DWORD tid );
92 OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid, INT *pixHook );
93 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
94 BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor );
95 LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam);
96 LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam);
98 /******************************************************************************
99 * These are the prototypes of the utility methods used for OLE Drag n Drop
101 static void OLEDD_Initialize();
102 static void OLEDD_UnInitialize();
103 static void OLEDD_InsertDropTarget(
104 DropTargetNode* nodeToAdd);
105 static DropTargetNode* OLEDD_ExtractDropTarget(
106 HWND hwndOfTarget);
107 static DropTargetNode* OLEDD_FindDropTarget(
108 HWND hwndOfTarget);
109 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
110 HWND hwnd,
111 UINT uMsg,
112 WPARAM wParam,
113 LPARAM lParam);
114 static void OLEDD_TrackMouseMove(
115 TrackerWindowInfo* trackerInfo,
116 POINT mousePos,
117 DWORD keyState);
118 static void OLEDD_TrackStateChange(
119 TrackerWindowInfo* trackerInfo,
120 POINT mousePos,
121 DWORD keyState);
122 static DWORD OLEDD_GetButtonState();
125 /******************************************************************************
126 * OleBuildVersion [OLE2.1]
128 DWORD WINAPI OleBuildVersion(void)
130 TRACE(ole,"(void)\n");
131 return (rmm<<16)+rup;
134 /***********************************************************************
135 * OleInitialize (OLE2.2) (OLE32.108)
137 HRESULT WINAPI OleInitialize(LPVOID reserved)
139 HRESULT hr;
141 TRACE(ole, "(%p)\n", reserved);
144 * The first duty of the OleInitialize is to initialize the COM libraries.
146 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
149 * If the CoInitializeEx call failed, the OLE libraries can't be
150 * initialized.
152 if (FAILED(hr))
153 return hr;
156 * Then, it has to initialize the OLE specific modules.
157 * This includes:
158 * Clipboard
159 * Drag and Drop
160 * Object linking and Embedding
161 * In-place activation
163 if (OLE_moduleLockCount==0)
166 * Initialize the libraries.
168 TRACE(ole, "() - Initializing the OLE libraries\n");
171 * Drag and Drop
173 OLEDD_Initialize();
176 * OLE shared menu
178 OLEMenu_Initialize();
182 * Then, we increase the lock count on the OLE module.
184 OLE_moduleLockCount++;
186 return hr;
189 /******************************************************************************
190 * CoGetCurrentProcess [COMPOBJ.34] [OLE2.2][OLE32.108]
192 * NOTES
193 * Is DWORD really the correct return type for this function?
195 DWORD WINAPI CoGetCurrentProcess(void) {
196 return (DWORD)PROCESS_Current();
199 /******************************************************************************
200 * OleUninitialize [OLE2.3] [OLE32.131]
202 void WINAPI OleUninitialize(void)
204 TRACE(ole, "()\n");
207 * Decrease the lock count on the OLE module.
209 OLE_moduleLockCount--;
212 * If we hit the bottom of the lock stack, free the libraries.
214 if (OLE_moduleLockCount==0)
217 * Actually free the libraries.
219 TRACE(ole, "() - Freeing the last reference count\n");
222 * Drag and Drop
224 OLEDD_UnInitialize();
227 * OLE shared menu
229 OLEMenu_UnInitialize();
233 * Then, uninitialize the COM libraries.
235 CoUninitialize();
238 /***********************************************************************
239 * OleFlushClipboard [OLE2.76]
241 HRESULT WINAPI OleFlushClipboard16(void)
243 return S_OK;
246 /***********************************************************************
247 * OleSetClipboard [OLE32.127]
249 HRESULT WINAPI OleSetClipboard(LPVOID pDataObj)
251 FIXME(ole,"(%p), stub!\n", pDataObj);
252 return S_OK;
255 /******************************************************************************
256 * CoRegisterMessageFilter32 [OLE32.38]
258 HRESULT WINAPI CoRegisterMessageFilter(
259 LPMESSAGEFILTER lpMessageFilter, /* Pointer to interface */
260 LPMESSAGEFILTER *lplpMessageFilter /* Indirect pointer to prior instance if non-NULL */
262 FIXME(ole,"stub\n");
263 if (lplpMessageFilter) {
264 *lplpMessageFilter = NULL;
266 return S_OK;
269 /******************************************************************************
270 * OleInitializeWOW [OLE32.109]
272 HRESULT WINAPI OleInitializeWOW(DWORD x) {
273 FIXME(ole,"(0x%08lx),stub!\n",x);
274 return 0;
277 /***********************************************************************
278 * RegisterDragDrop16 (OLE2.35)
280 HRESULT WINAPI RegisterDragDrop16(
281 HWND16 hwnd,
282 LPDROPTARGET pDropTarget
284 FIXME(ole,"(0x%04x,%p),stub!\n",hwnd,pDropTarget);
285 return S_OK;
288 /***********************************************************************
289 * RegisterDragDrop32 (OLE32.139)
291 HRESULT WINAPI RegisterDragDrop(
292 HWND hwnd,
293 LPDROPTARGET pDropTarget)
295 DropTargetNode* dropTargetInfo;
297 TRACE(ole,"(0x%x,%p)\n", hwnd, pDropTarget);
300 * First, check if the window is already registered.
302 dropTargetInfo = OLEDD_FindDropTarget(hwnd);
304 if (dropTargetInfo!=NULL)
305 return DRAGDROP_E_ALREADYREGISTERED;
308 * If it's not there, we can add it. We first create a node for it.
310 dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));
312 if (dropTargetInfo==NULL)
313 return E_OUTOFMEMORY;
315 dropTargetInfo->hwndTarget = hwnd;
316 dropTargetInfo->prevDropTarget = NULL;
317 dropTargetInfo->nextDropTarget = NULL;
320 * Don't forget that this is an interface pointer, need to nail it down since
321 * we keep a copy of it.
323 dropTargetInfo->dropTarget = pDropTarget;
324 IDropTarget_AddRef(dropTargetInfo->dropTarget);
326 OLEDD_InsertDropTarget(dropTargetInfo);
328 return S_OK;
331 /***********************************************************************
332 * RevokeDragDrop16 (OLE2.36)
334 HRESULT WINAPI RevokeDragDrop16(
335 HWND16 hwnd
337 FIXME(ole,"(0x%04x),stub!\n",hwnd);
338 return S_OK;
341 /***********************************************************************
342 * RevokeDragDrop32 (OLE32.141)
344 HRESULT WINAPI RevokeDragDrop(
345 HWND hwnd)
347 DropTargetNode* dropTargetInfo;
349 TRACE(ole,"(0x%x)\n", hwnd);
352 * First, check if the window is already registered.
354 dropTargetInfo = OLEDD_ExtractDropTarget(hwnd);
357 * If it ain't in there, it's an error.
359 if (dropTargetInfo==NULL)
360 return DRAGDROP_E_NOTREGISTERED;
363 * If it's in there, clean-up it's used memory and
364 * references
366 IDropTarget_Release(dropTargetInfo->dropTarget);
367 HeapFree(GetProcessHeap(), 0, dropTargetInfo);
369 return S_OK;
372 /***********************************************************************
373 * OleRegGetUserType (OLE32.122)
375 HRESULT WINAPI OleRegGetUserType(
376 REFCLSID clsid,
377 DWORD dwFormOfType,
378 LPOLESTR* pszUserType)
380 FIXME(ole,",stub!\n");
381 return S_OK;
384 /***********************************************************************
385 * DoDragDrop32 [OLE32.65]
387 HRESULT WINAPI DoDragDrop (
388 IDataObject *pDataObject, /* ptr to the data obj */
389 IDropSource* pDropSource, /* ptr to the source obj */
390 DWORD dwOKEffect, /* effects allowed by the source */
391 DWORD *pdwEffect) /* ptr to effects of the source */
393 TrackerWindowInfo trackerInfo;
394 HWND hwndTrackWindow;
395 MSG msg;
397 TRACE(ole,"(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
400 * Setup the drag n drop tracking window.
402 trackerInfo.dataObject = pDataObject;
403 trackerInfo.dropSource = pDropSource;
404 trackerInfo.dwOKEffect = dwOKEffect;
405 trackerInfo.pdwEffect = pdwEffect;
406 trackerInfo.trackingDone = FALSE;
407 trackerInfo.escPressed = FALSE;
408 trackerInfo.curDragTargetHWND = 0;
409 trackerInfo.curDragTarget = 0;
411 hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS,
412 "TrackerWindow",
413 WS_POPUP,
414 CW_USEDEFAULT, CW_USEDEFAULT,
415 CW_USEDEFAULT, CW_USEDEFAULT,
419 (LPVOID)&trackerInfo);
421 if (hwndTrackWindow!=0)
424 * Capture the mouse input
426 SetCapture(hwndTrackWindow);
429 * Pump messages. All mouse input should go the the capture window.
431 while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )
433 if ( (msg.message >= WM_KEYFIRST) &&
434 (msg.message <= WM_KEYFIRST) )
437 * When keyboard messages are sent to windows on this thread, we
438 * want to ignore notify the drop source that the state changed.
439 * in the case of the Escape key, we also notify the drop source
440 * we give it a special meaning.
442 if ( (msg.message==WM_KEYDOWN) &&
443 (msg.wParam==VK_ESCAPE) )
445 trackerInfo.escPressed = TRUE;
449 * Notify the drop source.
451 OLEDD_TrackStateChange(&trackerInfo,
452 msg.pt,
453 OLEDD_GetButtonState());
455 else
458 * Dispatch the messages only when it's not a keyboard message.
460 DispatchMessageA(&msg);
465 * Destroy the temporary window.
467 DestroyWindow(hwndTrackWindow);
469 return trackerInfo.returnValue;
472 return E_FAIL;
475 /***********************************************************************
476 * OleQueryLinkFromData32 [OLE32.118]
478 HRESULT WINAPI OleQueryLinkFromData(
479 IDataObject* pSrcDataObject)
481 FIXME(ole,"(%p),stub!\n", pSrcDataObject);
482 return S_OK;
485 /***********************************************************************
486 * OleRegGetMiscStatus [OLE32.121]
488 HRESULT WINAPI OleRegGetMiscStatus(
489 REFCLSID clsid,
490 DWORD dwAspect,
491 DWORD* pdwStatus)
493 FIXME(ole,"(),stub!\n");
494 return REGDB_E_CLASSNOTREG;
497 /***********************************************************************
498 * OleGetClipboard32 [OLE32.105]
500 HRESULT WINAPI OleGetClipboard(
501 IDataObject** ppDataObj)
503 FIXME(ole,"(%p),stub!\n", ppDataObj);
505 if (ppDataObj)
506 *ppDataObj=0;
508 return E_FAIL;
512 /**************************************************************************
513 * Internal methods to manage the shared OLE menu in response to the
514 * OLE***MenuDescriptor API
517 /***
518 * OLEMenu_Initialize()
520 * Initializes the OLEMENU data structures.
522 static void OLEMenu_Initialize()
524 /* Create a dynamic pointer array to store the hook handles */
525 if ( !OLEMenu_MsgHookDPA )
526 OLEMenu_MsgHookDPA = DPA_CreateEx( 2, GetProcessHeap() );
529 /***
530 * OLEMenu_UnInitialize()
532 * Releases the OLEMENU data structures.
534 static void OLEMenu_UnInitialize()
536 /* Release the hook table */
537 if ( OLEMenu_MsgHookDPA )
538 DPA_Destroy( OLEMenu_MsgHookDPA );
540 OLEMenu_MsgHookDPA = NULL;
543 /*************************************************************************
544 * OLEMenu_InstallHooks
545 * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
547 * RETURNS: TRUE if message hooks were succesfully installed
548 * FALSE on failure
550 BOOL OLEMenu_InstallHooks( DWORD tid )
552 OleMenuHookItem *pHookItem = NULL;
554 if ( !OLEMenu_MsgHookDPA ) /* No hook table? Create one */
556 /* Create a dynamic pointer array to store the hook handles */
557 if ( !(OLEMenu_MsgHookDPA = DPA_CreateEx( 2, GetProcessHeap() )) )
558 return FALSE;
561 /* Create an entry for the hook table */
562 if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
563 sizeof(OleMenuHookItem)) ) )
564 return FALSE;
566 pHookItem->tid = tid;
567 pHookItem->hHeap = GetProcessHeap();
569 /* Install a thread scope message hook for WH_GETMESSAGE */
570 pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc,
571 0, GetCurrentThreadId() );
572 if ( !pHookItem->GetMsg_hHook )
573 goto CLEANUP;
575 /* Install a thread scope message hook for WH_CALLWNDPROC */
576 pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc,
577 0, GetCurrentThreadId() );
578 if ( !pHookItem->CallWndProc_hHook )
579 goto CLEANUP;
581 /* Insert the hook table entry */
582 if ( -1 == DPA_InsertPtr( OLEMenu_MsgHookDPA, 0, pHookItem ) )
583 goto CLEANUP;
585 return TRUE;
587 CLEANUP:
588 /* Unhook any hooks */
589 if ( pHookItem->GetMsg_hHook )
590 UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
591 if ( pHookItem->CallWndProc_hHook )
592 UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
593 /* Release the hook table entry */
594 HeapFree(pHookItem->hHeap, 0, pHookItem );
596 return FALSE;
599 /*************************************************************************
600 * OLEMenu_UnInstallHooks
601 * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
603 * RETURNS: TRUE if message hooks were succesfully installed
604 * FALSE on failure
606 BOOL OLEMenu_UnInstallHooks( DWORD tid )
608 INT ixHook;
609 OleMenuHookItem *pHookItem = NULL;
611 if ( !OLEMenu_MsgHookDPA ) /* No hooks set */
612 return TRUE;
614 /* Lookup the hHook index for this tid */
615 if ( !OLEMenu_IsHookInstalled( tid , &ixHook ) )
616 return TRUE;
618 /* Remove the hook entry from the table(the pointer itself is not deleted) */
619 if ( !( pHookItem = DPA_DeletePtr(OLEMenu_MsgHookDPA, ixHook) ) )
620 return FALSE;
622 /* Uninstall the hooks installed for this thread */
623 if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
624 goto CLEANUP;
625 if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
626 goto CLEANUP;
628 /* Release the hook table entry */
629 HeapFree(pHookItem->hHeap, 0, pHookItem );
631 return TRUE;
633 CLEANUP:
634 /* Release the hook table entry */
635 if (pHookItem)
636 HeapFree(pHookItem->hHeap, 0, pHookItem );
638 return FALSE;
641 /*************************************************************************
642 * OLEMenu_IsHookInstalled
643 * Tests if OLEMenu hooks have been installed for a thread
645 * RETURNS: The pointer and index of the hook table entry for the tid
646 * NULL and -1 for the index if no hooks were installed for this thread
648 OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid, INT *pixHook )
650 INT ixHook;
651 OleMenuHookItem *pHookItem = NULL;
653 if ( pixHook )
654 *pixHook = -1;
656 if ( !OLEMenu_MsgHookDPA ) /* No hooks set */
657 return NULL;
659 /* Do a simple linear search for an entry whose tid matches ours.
660 * We really need a map but efficiency is not a concern here. */
661 for( ixHook = 0; ; ixHook++ )
663 /* Retrieve the hook entry */
664 if ( !( pHookItem = DPA_GetPtr(OLEMenu_MsgHookDPA, ixHook) ) )
665 return NULL;
667 if ( tid == pHookItem->tid )
669 if ( pixHook )
670 *pixHook = ixHook;
671 return pHookItem;
675 return NULL;
678 /***********************************************************************
679 * OLEMenu_FindMainMenuIndex
681 * Used by OLEMenu API to find the top level group a menu item belongs to.
682 * On success pnPos contains the index of the item in the top level menu group
684 * RETURNS: TRUE if the ID was found, FALSE on failure
686 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
688 UINT i, nItems;
690 nItems = GetMenuItemCount( hMainMenu );
692 for (i = 0; i < nItems; i++)
694 HMENU hsubmenu;
696 /* Is the current item a submenu? */
697 if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
699 /* If the handle is the same we're done */
700 if ( hsubmenu == hPopupMenu )
702 if (pnPos)
703 *pnPos = i;
704 return TRUE;
706 /* Recursively search without updating pnPos */
707 else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
709 if (pnPos)
710 *pnPos = i;
711 return TRUE;
716 return FALSE;
719 /***********************************************************************
720 * OLEMenu_SetIsServerMenu
722 * Checks whether a popup menu belongs to a shared menu group which is
723 * owned by the server, and sets the menu descriptor state accordingly.
724 * All menu messages from these groups should be routed to the server.
726 * RETURNS: TRUE if the popup menu is part of a server owned group
727 * FASE if the popup menu is part of a container owned group
729 BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
731 UINT nPos = 0, nWidth, i;
733 pOleMenuDescriptor->bIsServerItem = FALSE;
735 /* Don't bother searching if the popup is the combined menu itself */
736 if ( hmenu == pOleMenuDescriptor->hmenuCombined )
737 return FALSE;
739 /* Find the menu item index in the shared OLE menu that this item belongs to */
740 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) )
741 return FALSE;
743 /* The group widths array has counts for the number of elements
744 * in the groups File, Edit, Container, Object, Window, Help.
745 * The Edit, Object & Help groups belong to the server object
746 * and the other three belong to the container.
747 * Loop thru the group widths and locate the group we are a member of.
749 for ( i = 0, nWidth = 0; i < 6; i++ )
751 nWidth += pOleMenuDescriptor->mgw.width[i];
752 if ( nPos < nWidth )
754 /* Odd elements are server menu widths */
755 pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;
756 break;
760 return pOleMenuDescriptor->bIsServerItem;
763 /*************************************************************************
764 * OLEMenu_CallWndProc
765 * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
766 * This is invoked from a message hook installed in OleSetMenuDescriptor.
768 LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
770 LPCWPSTRUCT pMsg = NULL;
771 HOLEMENU hOleMenu = 0;
772 OleMenuDescriptor *pOleMenuDescriptor = NULL;
773 OleMenuHookItem *pHookItem = NULL;
774 WORD fuFlags;
776 TRACE(ole,"%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
778 /* Check if we're being asked to process the message */
779 if ( HC_ACTION != code )
780 goto NEXTHOOK;
782 /* Retrieve the current message being dispatched from lParam */
783 pMsg = (LPCWPSTRUCT)lParam;
785 /* Check if the message is destined for a window we are interested in:
786 * If the window has an OLEMenu property we may need to dispatch
787 * the menu message to its active objects window instead. */
789 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
790 if ( !hOleMenu )
791 goto NEXTHOOK;
793 /* Get the menu descriptor */
794 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
795 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
796 goto NEXTHOOK;
798 /* Process menu messages */
799 switch( pMsg->message )
801 case WM_INITMENU:
803 /* Reset the menu descriptor state */
804 pOleMenuDescriptor->bIsServerItem = FALSE;
806 /* Send this message to the server as well */
807 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
808 pMsg->message, pMsg->wParam, pMsg->lParam );
809 goto NEXTHOOK;
812 case WM_INITMENUPOPUP:
814 /* Save the state for whether this is a server owned menu */
815 OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
816 break;
819 case WM_MENUSELECT:
821 fuFlags = HIWORD(pMsg->wParam); /* Get flags */
822 if ( fuFlags & MF_SYSMENU )
823 goto NEXTHOOK;
825 /* Save the state for whether this is a server owned popup menu */
826 else if ( fuFlags & MF_POPUP )
827 OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
829 break;
832 case WM_DRAWITEM:
834 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
835 if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
836 goto NEXTHOOK; /* Not a menu message */
838 break;
841 default:
842 goto NEXTHOOK;
845 /* If the message was for the server dispatch it accordingly */
846 if ( pOleMenuDescriptor->bIsServerItem )
848 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
849 pMsg->message, pMsg->wParam, pMsg->lParam );
852 NEXTHOOK:
853 if ( pOleMenuDescriptor )
854 GlobalUnlock( hOleMenu );
856 /* Lookup the hook item for the current thread */
857 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId(), NULL ) ) )
859 /* This should never fail!! */
860 WARN(ole, "could not retrieve hHook for current thread!\n" );
861 return 0;
864 /* Pass on the message to the next hooker */
865 return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
868 /*************************************************************************
869 * OLEMenu_GetMsgProc
870 * Thread scope WH_GETMESSAGE hook proc filter function (callback)
871 * This is invoked from a message hook installed in OleSetMenuDescriptor.
873 LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
875 LPMSG pMsg = NULL;
876 HOLEMENU hOleMenu = 0;
877 OleMenuDescriptor *pOleMenuDescriptor = NULL;
878 OleMenuHookItem *pHookItem = NULL;
879 WORD wCode;
881 TRACE(ole,"%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
883 /* Check if we're being asked to process a messages */
884 if ( HC_ACTION != code )
885 goto NEXTHOOK;
887 /* Retrieve the current message being dispatched from lParam */
888 pMsg = (LPMSG)lParam;
890 /* Check if the message is destined for a window we are interested in:
891 * If the window has an OLEMenu property we may need to dispatch
892 * the menu message to its active objects window instead. */
894 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
895 if ( !hOleMenu )
896 goto NEXTHOOK;
898 /* Process menu messages */
899 switch( pMsg->message )
901 case WM_COMMAND:
903 wCode = HIWORD(pMsg->wParam); /* Get notification code */
904 if ( wCode )
905 goto NEXTHOOK; /* Not a menu message */
906 break;
908 default:
909 goto NEXTHOOK;
912 /* Get the menu descriptor */
913 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
914 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
915 goto NEXTHOOK;
917 /* If the message was for the server dispatch it accordingly */
918 if ( pOleMenuDescriptor->bIsServerItem )
920 /* Change the hWnd in the message to the active objects hWnd.
921 * The message loop which reads this message will automatically
922 * dispatch it to the embedded objects window. */
923 pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
926 NEXTHOOK:
927 if ( pOleMenuDescriptor )
928 GlobalUnlock( hOleMenu );
930 /* Lookup the hook item for the current thread */
931 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId(), NULL ) ) )
933 /* This should never fail!! */
934 WARN(ole, "could not retrieve hHook for current thread!\n" );
935 return FALSE;
938 /* Pass on the message to the next hooker */
939 return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
942 /***********************************************************************
943 * OleCreateMenuDescriptor [OLE32.97]
944 * Creates an OLE menu descriptor for OLE to use when dispatching
945 * menu messages and commands.
947 * PARAMS:
948 * hmenuCombined - Handle to the objects combined menu
949 * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group
952 HOLEMENU WINAPI OleCreateMenuDescriptor(
953 HMENU hmenuCombined,
954 LPOLEMENUGROUPWIDTHS lpMenuWidths)
956 HOLEMENU hOleMenu;
957 OleMenuDescriptor *pOleMenuDescriptor;
958 int i;
960 if ( !hmenuCombined || !lpMenuWidths )
961 return 0;
963 /* Create an OLE menu descriptor */
964 if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
965 sizeof(OleMenuDescriptor) ) ) )
966 return 0;
968 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
969 if ( !pOleMenuDescriptor )
970 return 0;
972 /* Initialize menu group widths and hmenu */
973 for ( i = 0; i < 6; i++ )
974 pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
976 pOleMenuDescriptor->hmenuCombined = hmenuCombined;
977 pOleMenuDescriptor->bIsServerItem = FALSE;
978 GlobalUnlock( hOleMenu );
980 return hOleMenu;
983 /***********************************************************************
984 * OleDestroyMenuDescriptor [OLE32.99]
985 * Destroy the shared menu descriptor
987 HRESULT WINAPI OleDestroyMenuDescriptor(
988 HOLEMENU hmenuDescriptor)
990 if ( hmenuDescriptor )
991 GlobalFree( hmenuDescriptor );
992 return S_OK;
995 /***********************************************************************
996 * OleSetMenuDescriptor [OLE32.129]
997 * Installs or removes OLE dispatching code for the containers frame window
998 * FIXME: The lpFrame and lpActiveObject parameters are currently ignored
999 * OLE should install context sensitive help F1 filtering for the app when
1000 * these are non null.
1002 * PARAMS:
1003 * hOleMenu Handle to composite menu descriptor
1004 * hwndFrame Handle to containers frame window
1005 * hwndActiveObject Handle to objects in-place activation window
1006 * lpFrame Pointer to IOleInPlaceFrame on containers window
1007 * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object
1009 * RETURNS:
1010 * S_OK - menu installed correctly
1011 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1013 HRESULT WINAPI OleSetMenuDescriptor(
1014 HOLEMENU hOleMenu,
1015 HWND hwndFrame,
1016 HWND hwndActiveObject,
1017 LPOLEINPLACEFRAME lpFrame,
1018 LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1020 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1022 /* Check args */
1023 if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
1024 return E_INVALIDARG;
1026 if ( lpFrame || lpActiveObject )
1028 FIXME(ole,"(%x, %x, %x, %p, %p), Context sensitive help filtering not implemented!\n",
1029 (unsigned int)hOleMenu,
1030 hwndFrame,
1031 hwndActiveObject,
1032 lpFrame,
1033 lpActiveObject);
1036 /* Set up a message hook to intercept the containers frame window messages.
1037 * The message filter is responsible for dispatching menu messages from the
1038 * shared menu which are intended for the object.
1041 if ( hOleMenu ) /* Want to install dispatching code */
1043 /* If OLEMenu hooks are already installed for this thread, fail
1044 * Note: This effectively means that OleSetMenuDescriptor cannot
1045 * be called twice in succession on the same frame window
1046 * without first calling it with a null hOleMenu to uninstall */
1047 if ( OLEMenu_IsHookInstalled( GetCurrentThreadId(), NULL ) )
1048 return E_FAIL;
1050 /* Get the menu descriptor */
1051 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1052 if ( !pOleMenuDescriptor )
1053 return E_UNEXPECTED;
1055 /* Update the menu descriptor */
1056 pOleMenuDescriptor->hwndFrame = hwndFrame;
1057 pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
1059 GlobalUnlock( hOleMenu );
1060 pOleMenuDescriptor = NULL;
1062 /* Add a menu descriptor windows property to the frame window */
1063 SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu );
1065 /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
1066 if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
1067 return E_FAIL;
1069 else /* Want to uninstall dispatching code */
1071 /* Uninstall the hooks */
1072 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1073 return E_FAIL;
1075 /* Remove the menu descriptor property from the frame window */
1076 RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" );
1079 return S_OK;
1082 /***********************************************************************
1083 * ReleaseStgMedium [OLE32.140]
1085 void WINAPI ReleaseStgMedium(
1086 STGMEDIUM* pmedium)
1088 switch (pmedium->tymed)
1090 case TYMED_HGLOBAL:
1092 if ( (pmedium->pUnkForRelease==0) &&
1093 (pmedium->u.hGlobal!=0) )
1094 GlobalFree(pmedium->u.hGlobal);
1096 pmedium->u.hGlobal = 0;
1097 break;
1099 case TYMED_FILE:
1101 if (pmedium->u.lpszFileName!=0)
1103 if (pmedium->pUnkForRelease==0)
1105 DeleteFileW(pmedium->u.lpszFileName);
1108 CoTaskMemFree(pmedium->u.lpszFileName);
1111 pmedium->u.lpszFileName = 0;
1112 break;
1114 case TYMED_ISTREAM:
1116 if (pmedium->u.pstm!=0)
1118 IStream_Release(pmedium->u.pstm);
1121 pmedium->u.pstm = 0;
1122 break;
1124 case TYMED_ISTORAGE:
1126 if (pmedium->u.pstg!=0)
1128 IStorage_Release(pmedium->u.pstg);
1131 pmedium->u.pstg = 0;
1132 break;
1134 case TYMED_GDI:
1136 if ( (pmedium->pUnkForRelease==0) &&
1137 (pmedium->u.hGlobal!=0) )
1138 DeleteObject(pmedium->u.hGlobal);
1140 pmedium->u.hGlobal = 0;
1141 break;
1143 case TYMED_MFPICT:
1145 if ( (pmedium->pUnkForRelease==0) &&
1146 (pmedium->u.hMetaFilePict!=0) )
1148 DeleteMetaFile(pmedium->u.hMetaFilePict);
1149 GlobalFree(pmedium->u.hMetaFilePict);
1152 pmedium->u.hMetaFilePict = 0;
1153 break;
1155 case TYMED_ENHMF:
1157 if ( (pmedium->pUnkForRelease==0) &&
1158 (pmedium->u.hEnhMetaFile!=0) )
1160 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
1163 pmedium->u.hEnhMetaFile = 0;
1164 break;
1166 case TYMED_NULL:
1167 default:
1168 break;
1172 * After cleaning up, the unknown is released
1174 if (pmedium->pUnkForRelease!=0)
1176 IUnknown_Release(pmedium->pUnkForRelease);
1177 pmedium->pUnkForRelease = 0;
1181 /***
1182 * OLEDD_Initialize()
1184 * Initializes the OLE drag and drop data structures.
1186 static void OLEDD_Initialize()
1188 WNDCLASSA wndClass;
1190 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1191 wndClass.style = CS_GLOBALCLASS;
1192 wndClass.lpfnWndProc = (WNDPROC)OLEDD_DragTrackerWindowProc;
1193 wndClass.cbClsExtra = 0;
1194 wndClass.cbWndExtra = sizeof(TrackerWindowInfo*);
1195 wndClass.hCursor = 0;
1196 wndClass.hbrBackground = 0;
1197 wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
1199 RegisterClassA (&wndClass);
1202 /***
1203 * OLEDD_UnInitialize()
1205 * Releases the OLE drag and drop data structures.
1207 static void OLEDD_UnInitialize()
1210 * Simply empty the list.
1212 while (targetListHead!=NULL)
1214 RevokeDragDrop(targetListHead->hwndTarget);
1218 /***
1219 * OLEDD_InsertDropTarget()
1221 * Insert the target node in the tree.
1223 static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd)
1225 DropTargetNode* curNode;
1226 DropTargetNode** parentNodeLink;
1229 * Iterate the tree to find the insertion point.
1231 curNode = targetListHead;
1232 parentNodeLink = &targetListHead;
1234 while (curNode!=NULL)
1236 if (nodeToAdd->hwndTarget<curNode->hwndTarget)
1239 * If the node we want to add has a smaller HWND, go left
1241 parentNodeLink = &curNode->prevDropTarget;
1242 curNode = curNode->prevDropTarget;
1244 else if (nodeToAdd->hwndTarget>curNode->hwndTarget)
1247 * If the node we want to add has a larger HWND, go right
1249 parentNodeLink = &curNode->nextDropTarget;
1250 curNode = curNode->nextDropTarget;
1252 else
1255 * The item was found in the list. It shouldn't have been there
1257 assert(FALSE);
1258 return;
1263 * If we get here, we have found a spot for our item. The parentNodeLink
1264 * pointer points to the pointer that we have to modify.
1265 * The curNode should be NULL. We just have to establish the link and Voila!
1267 assert(curNode==NULL);
1268 assert(parentNodeLink!=NULL);
1269 assert(*parentNodeLink==NULL);
1271 *parentNodeLink=nodeToAdd;
1274 /***
1275 * OLEDD_ExtractDropTarget()
1277 * Removes the target node from the tree.
1279 static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget)
1281 DropTargetNode* curNode;
1282 DropTargetNode** parentNodeLink;
1285 * Iterate the tree to find the insertion point.
1287 curNode = targetListHead;
1288 parentNodeLink = &targetListHead;
1290 while (curNode!=NULL)
1292 if (hwndOfTarget<curNode->hwndTarget)
1295 * If the node we want to add has a smaller HWND, go left
1297 parentNodeLink = &curNode->prevDropTarget;
1298 curNode = curNode->prevDropTarget;
1300 else if (hwndOfTarget>curNode->hwndTarget)
1303 * If the node we want to add has a larger HWND, go right
1305 parentNodeLink = &curNode->nextDropTarget;
1306 curNode = curNode->nextDropTarget;
1308 else
1311 * The item was found in the list. Detach it from it's parent and
1312 * re-insert it's kids in the tree.
1314 assert(parentNodeLink!=NULL);
1315 assert(*parentNodeLink==curNode);
1318 * We arbitrately re-attach the left sub-tree to the parent.
1320 *parentNodeLink = curNode->prevDropTarget;
1323 * And we re-insert the right subtree
1325 if (curNode->nextDropTarget!=NULL)
1327 OLEDD_InsertDropTarget(curNode->nextDropTarget);
1331 * The node we found is still a valid node once we complete
1332 * the unlinking of the kids.
1334 curNode->nextDropTarget=NULL;
1335 curNode->prevDropTarget=NULL;
1337 return curNode;
1342 * If we get here, the node is not in the tree
1344 return NULL;
1347 /***
1348 * OLEDD_FindDropTarget()
1350 * Finds information about the drop target.
1352 static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
1354 DropTargetNode* curNode;
1357 * Iterate the tree to find the HWND value.
1359 curNode = targetListHead;
1361 while (curNode!=NULL)
1363 if (hwndOfTarget<curNode->hwndTarget)
1366 * If the node we want to add has a smaller HWND, go left
1368 curNode = curNode->prevDropTarget;
1370 else if (hwndOfTarget>curNode->hwndTarget)
1373 * If the node we want to add has a larger HWND, go right
1375 curNode = curNode->nextDropTarget;
1377 else
1380 * The item was found in the list.
1382 return curNode;
1387 * If we get here, the item is not in the list
1389 return NULL;
1392 /***
1393 * OLEDD_DragTrackerWindowProc()
1395 * This method is the WindowProcedure of the drag n drop tracking
1396 * window. During a drag n Drop operation, an invisible window is created
1397 * to receive the user input and act upon it. This procedure is in charge
1398 * of this behavior.
1400 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
1401 HWND hwnd,
1402 UINT uMsg,
1403 WPARAM wParam,
1404 LPARAM lParam)
1406 switch (uMsg)
1408 case WM_CREATE:
1410 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
1412 SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams);
1415 break;
1417 case WM_MOUSEMOVE:
1419 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1420 POINT mousePos;
1423 * Get the current mouse position in screen coordinates.
1425 mousePos.x = LOWORD(lParam);
1426 mousePos.y = HIWORD(lParam);
1427 ClientToScreen(hwnd, &mousePos);
1430 * Track the movement of the mouse.
1432 OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam);
1434 break;
1436 case WM_LBUTTONUP:
1437 case WM_MBUTTONUP:
1438 case WM_RBUTTONUP:
1439 case WM_LBUTTONDOWN:
1440 case WM_MBUTTONDOWN:
1441 case WM_RBUTTONDOWN:
1443 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1444 POINT mousePos;
1447 * Get the current mouse position in screen coordinates.
1449 mousePos.x = LOWORD(lParam);
1450 mousePos.y = HIWORD(lParam);
1451 ClientToScreen(hwnd, &mousePos);
1454 * Notify everyone that the button state changed
1455 * TODO: Check if the "escape" key was pressed.
1457 OLEDD_TrackStateChange(trackerInfo, mousePos, wParam);
1459 break;
1464 * This is a window proc after all. Let's call the default.
1466 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1469 /***
1470 * OLEDD_TrackMouseMove()
1472 * This method is invoked while a drag and drop operation is in effect.
1473 * it will generate the appropriate callbacks in the drop source
1474 * and drop target. It will also provide the expected feedback to
1475 * the user.
1477 * params:
1478 * trackerInfo - Pointer to the structure identifying the
1479 * drag & drop operation that is currently
1480 * active.
1481 * mousePos - Current position of the mouse in screen
1482 * coordinates.
1483 * keyState - Contains the state of the shift keys and the
1484 * mouse buttons (MK_LBUTTON and the like)
1486 static void OLEDD_TrackMouseMove(
1487 TrackerWindowInfo* trackerInfo,
1488 POINT mousePos,
1489 DWORD keyState)
1491 HWND hwndNewTarget = 0;
1492 HRESULT hr = S_OK;
1495 * Get the handle of the window under the mouse
1497 hwndNewTarget = WindowFromPoint(mousePos);
1500 * If we are hovering over the same target as before, send the
1501 * DragOver notification
1503 if ( (trackerInfo->curDragTarget != 0) &&
1504 (trackerInfo->curDragTargetHWND==hwndNewTarget) )
1506 POINTL mousePosParam;
1509 * The documentation tells me that the coordinate should be in the target
1510 * window's coordinate space. However, the tests I made tell me the
1511 * coordinates should be in screen coordinates.
1513 mousePosParam.x = mousePos.x;
1514 mousePosParam.y = mousePos.y;
1516 IDropTarget_DragOver(trackerInfo->curDragTarget,
1517 keyState,
1518 mousePosParam,
1519 trackerInfo->pdwEffect);
1521 else
1523 DropTargetNode* newDropTargetNode = 0;
1526 * If we changed window, we have to notify our old target and check for
1527 * the new one.
1529 if (trackerInfo->curDragTarget!=0)
1531 IDropTarget_DragLeave(trackerInfo->curDragTarget);
1535 * Make sure we're hovering over a window.
1537 if (hwndNewTarget!=0)
1540 * Find-out if there is a drag target under the mouse
1542 newDropTargetNode = OLEDD_FindDropTarget(hwndNewTarget);
1544 trackerInfo->curDragTargetHWND = hwndNewTarget;
1545 trackerInfo->curDragTarget = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
1548 * If there is, notify it that we just dragged-in
1550 if (trackerInfo->curDragTarget!=0)
1552 POINTL mousePosParam;
1555 * The documentation tells me that the coordinate should be in the target
1556 * window's coordinate space. However, the tests I made tell me the
1557 * coordinates should be in screen coordinates.
1559 mousePosParam.x = mousePos.x;
1560 mousePosParam.y = mousePos.y;
1562 IDropTarget_DragEnter(trackerInfo->curDragTarget,
1563 trackerInfo->dataObject,
1564 keyState,
1565 mousePosParam,
1566 trackerInfo->pdwEffect);
1569 else
1572 * The mouse is not over a window so we don't track anything.
1574 trackerInfo->curDragTargetHWND = 0;
1575 trackerInfo->curDragTarget = 0;
1580 * Now that we have done that, we have to tell the source to give
1581 * us feedback on the work being done by the target. If we don't
1582 * have a target, simulate no effect.
1584 if (trackerInfo->curDragTarget==0)
1586 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
1589 hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
1590 *trackerInfo->pdwEffect);
1593 * When we ask for feedback from the drop source, sometimes it will
1594 * do all the necessary work and sometimes it will not handle it
1595 * when that's the case, we must display the standard drag and drop
1596 * cursors.
1598 if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
1600 if ( (*trackerInfo->pdwEffect & DROPEFFECT_MOVE) ||
1601 (*trackerInfo->pdwEffect & DROPEFFECT_COPY) ||
1602 (*trackerInfo->pdwEffect & DROPEFFECT_LINK) )
1604 SetCursor(LoadCursorA(0, IDC_SIZEALLA));
1606 else
1608 SetCursor(LoadCursorA(0, IDC_NOA));
1613 /***
1614 * OLEDD_TrackStateChange()
1616 * This method is invoked while a drag and drop operation is in effect.
1617 * It is used to notify the drop target/drop source callbacks when
1618 * the state of the keyboard or mouse button change.
1620 * params:
1621 * trackerInfo - Pointer to the structure identifying the
1622 * drag & drop operation that is currently
1623 * active.
1624 * mousePos - Current position of the mouse in screen
1625 * coordinates.
1626 * keyState - Contains the state of the shift keys and the
1627 * mouse buttons (MK_LBUTTON and the like)
1629 static void OLEDD_TrackStateChange(
1630 TrackerWindowInfo* trackerInfo,
1631 POINT mousePos,
1632 DWORD keyState)
1635 * Ask the drop source what to do with the operation.
1637 trackerInfo->returnValue = IDropSource_QueryContinueDrag(
1638 trackerInfo->dropSource,
1639 trackerInfo->escPressed,
1640 keyState);
1643 * All the return valued will stop the operation except the S_OK
1644 * return value.
1646 if (trackerInfo->returnValue!=S_OK)
1649 * Make sure the message loop in DoDragDrop stops
1651 trackerInfo->trackingDone = TRUE;
1654 * Release the mouse in case the drop target decides to show a popup
1655 * or a menu or something.
1657 ReleaseCapture();
1660 * If we end-up over a target, drop the object in the target or
1661 * inform the target that the operation was cancelled.
1663 if (trackerInfo->curDragTarget!=0)
1665 switch (trackerInfo->returnValue)
1668 * If the source wants us to complete the operation, we tell
1669 * the drop target that we just dropped the object in it.
1671 case DRAGDROP_S_DROP:
1673 POINTL mousePosParam;
1676 * The documentation tells me that the coordinate should be
1677 * in the target window's coordinate space. However, the tests
1678 * I made tell me the coordinates should be in screen coordinates.
1680 mousePosParam.x = mousePos.x;
1681 mousePosParam.y = mousePos.y;
1683 IDropTarget_Drop(trackerInfo->curDragTarget,
1684 trackerInfo->dataObject,
1685 keyState,
1686 mousePosParam,
1687 trackerInfo->pdwEffect);
1688 break;
1691 * If the source told us that we should cancel, fool the drop
1692 * target by telling it that the mouse left it's window.
1694 case DRAGDROP_S_CANCEL:
1695 IDropTarget_DragLeave(trackerInfo->curDragTarget);
1696 break;
1702 /***
1703 * OLEDD_GetButtonState()
1705 * This method will use the current state of the keyboard to build
1706 * a button state mask equivalent to the one passed in the
1707 * WM_MOUSEMOVE wParam.
1709 static DWORD OLEDD_GetButtonState()
1711 BYTE keyboardState[256];
1712 DWORD keyMask = 0;
1714 GetKeyboardState(keyboardState);
1716 if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
1717 keyMask |= MK_SHIFT;
1719 if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
1720 keyMask |= MK_CONTROL;
1722 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
1723 keyMask |= MK_LBUTTON;
1725 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
1726 keyMask |= MK_RBUTTON;
1728 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
1729 keyMask |= MK_MBUTTON;
1731 return keyMask;