4 * Copyright 1995 Martin von Loewis
5 * Copyright 1999 Francis Beaudet
6 * Copyright 1999 Noel Borthwick
17 #include "wine/obj_clientserver.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
30 IDropTarget* dropTarget;
31 struct tagDropTargetNode* prevDropTarget;
32 struct tagDropTargetNode* nextDropTarget;
35 typedef struct tagTrackerWindowInfo
37 IDataObject* dataObject;
38 IDropSource* dropSource;
45 HWND curDragTargetHWND;
46 IDropTarget* curDragTarget;
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 */
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 */
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(
109 static DropTargetNode* OLEDD_FindDropTarget(
111 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
116 static void OLEDD_TrackMouseMove(
117 TrackerWindowInfo* trackerInfo,
120 static void OLEDD_TrackStateChange(
121 TrackerWindowInfo* trackerInfo,
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)
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
158 * Then, it has to initialize the OLE specific modules.
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");
180 OLEMenu_Initialize();
184 * Then, we increase the lock count on the OLE module.
186 OLE_moduleLockCount++;
191 /******************************************************************************
192 * CoGetCurrentProcess [COMPOBJ.34] [OLE2.2][OLE32.108]
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)
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");
226 OLEDD_UnInitialize();
231 OLEMenu_UnInitialize();
235 * Then, uninitialize the COM libraries.
240 /***********************************************************************
241 * OleFlushClipboard [OLE2.76]
243 HRESULT WINAPI OleFlushClipboard16(void)
248 /***********************************************************************
249 * OleSetClipboard [OLE32.127]
251 HRESULT WINAPI OleSetClipboard(LPVOID pDataObj)
253 FIXME(ole,"(%p), stub!\n", pDataObj);
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 */
265 if (lplpMessageFilter) {
266 *lplpMessageFilter = NULL;
271 /******************************************************************************
272 * OleInitializeWOW [OLE32.109]
274 HRESULT WINAPI OleInitializeWOW(DWORD x) {
275 FIXME(ole,"(0x%08lx),stub!\n",x);
279 /***********************************************************************
280 * RegisterDragDrop16 (OLE2.35)
282 HRESULT WINAPI RegisterDragDrop16(
284 LPDROPTARGET pDropTarget
286 FIXME(ole,"(0x%04x,%p),stub!\n",hwnd,pDropTarget);
290 /***********************************************************************
291 * RegisterDragDrop32 (OLE32.139)
293 HRESULT WINAPI RegisterDragDrop(
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);
333 /***********************************************************************
334 * RevokeDragDrop16 (OLE2.36)
336 HRESULT WINAPI RevokeDragDrop16(
339 FIXME(ole,"(0x%04x),stub!\n",hwnd);
343 /***********************************************************************
344 * RevokeDragDrop32 (OLE32.141)
346 HRESULT WINAPI RevokeDragDrop(
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
368 IDropTarget_Release(dropTargetInfo->dropTarget);
369 HeapFree(GetProcessHeap(), 0, dropTargetInfo);
374 /***********************************************************************
375 * OleRegGetUserType (OLE32.122)
377 HRESULT WINAPI OleRegGetUserType(
380 LPOLESTR* pszUserType)
382 FIXME(ole,",stub!\n");
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;
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,
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,
455 OLEDD_GetButtonState());
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;
477 /***********************************************************************
478 * OleQueryLinkFromData32 [OLE32.118]
480 HRESULT WINAPI OleQueryLinkFromData(
481 IDataObject* pSrcDataObject)
483 FIXME(ole,"(%p),stub!\n", pSrcDataObject);
487 /***********************************************************************
488 * OleRegGetMiscStatus [OLE32.121]
490 HRESULT WINAPI OleRegGetMiscStatus(
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);
514 /**************************************************************************
515 * Internal methods to manage the shared OLE menu in response to the
516 * OLE***MenuDescriptor API
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() );
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
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() )) )
563 /* Create an entry for the hook table */
564 if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
565 sizeof(OleMenuHookItem)) ) )
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 )
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 )
583 /* Insert the hook table entry */
584 if ( -1 == DPA_InsertPtr( OLEMenu_MsgHookDPA, 0, pHookItem ) )
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 );
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
608 BOOL OLEMenu_UnInstallHooks( DWORD tid )
611 OleMenuHookItem *pHookItem = NULL;
613 if ( !OLEMenu_MsgHookDPA ) /* No hooks set */
616 /* Lookup the hHook index for this tid */
617 if ( !OLEMenu_IsHookInstalled( tid , &ixHook ) )
620 /* Remove the hook entry from the table(the pointer itself is not deleted) */
621 if ( !( pHookItem = DPA_DeletePtr(OLEMenu_MsgHookDPA, ixHook) ) )
624 /* Uninstall the hooks installed for this thread */
625 if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
627 if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
630 /* Release the hook table entry */
631 HeapFree(pHookItem->hHeap, 0, pHookItem );
636 /* Release the hook table entry */
638 HeapFree(pHookItem->hHeap, 0, pHookItem );
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 )
653 OleMenuHookItem *pHookItem = NULL;
658 if ( !OLEMenu_MsgHookDPA ) /* No hooks set */
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) ) )
669 if ( tid == pHookItem->tid )
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 )
692 nItems = GetMenuItemCount( hMainMenu );
694 for (i = 0; i < nItems; i++)
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 )
708 /* Recursively search without updating pnPos */
709 else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
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 )
741 /* Find the menu item index in the shared OLE menu that this item belongs to */
742 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) )
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];
756 /* Odd elements are server menu widths */
757 pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;
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;
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 )
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" );
795 /* Get the menu descriptor */
796 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
797 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
800 /* Process menu messages */
801 switch( pMsg->message )
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 );
814 case WM_INITMENUPOPUP:
816 /* Save the state for whether this is a server owned menu */
817 OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
823 fuFlags = HIWORD(pMsg->wParam); /* Get flags */
824 if ( fuFlags & MF_SYSMENU )
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 );
836 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
837 if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
838 goto NEXTHOOK; /* Not a menu message */
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 );
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" );
866 /* Pass on the message to the next hooker */
867 return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
870 /*************************************************************************
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)
878 HOLEMENU hOleMenu = 0;
879 OleMenuDescriptor *pOleMenuDescriptor = NULL;
880 OleMenuHookItem *pHookItem = NULL;
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 )
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" );
900 /* Process menu messages */
901 switch( pMsg->message )
905 wCode = HIWORD(pMsg->wParam); /* Get notification code */
907 goto NEXTHOOK; /* Not a menu message */
914 /* Get the menu descriptor */
915 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
916 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
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;
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" );
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.
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(
956 LPOLEMENUGROUPWIDTHS lpMenuWidths)
959 OleMenuDescriptor *pOleMenuDescriptor;
962 if ( !hmenuCombined || !lpMenuWidths )
965 /* Create an OLE menu descriptor */
966 if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
967 sizeof(OleMenuDescriptor) ) ) )
970 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
971 if ( !pOleMenuDescriptor )
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 );
985 /***********************************************************************
986 * OleDestroyMenuDescriptor [OLE32.99]
987 * Destroy the shared menu descriptor
989 HRESULT WINAPI OleDestroyMenuDescriptor(
990 HOLEMENU hmenuDescriptor)
992 if ( hmenuDescriptor )
993 GlobalFree( hmenuDescriptor );
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.
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
1012 * S_OK - menu installed correctly
1013 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1015 HRESULT WINAPI OleSetMenuDescriptor(
1018 HWND hwndActiveObject,
1019 LPOLEINPLACEFRAME lpFrame,
1020 LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1022 OleMenuDescriptor *pOleMenuDescriptor = NULL;
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,
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 ) )
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() ) )
1071 else /* Want to uninstall dispatching code */
1073 /* Uninstall the hooks */
1074 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1077 /* Remove the menu descriptor property from the frame window */
1078 RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" );
1084 /***********************************************************************
1085 * ReleaseStgMedium [OLE32.140]
1087 void WINAPI ReleaseStgMedium(
1090 switch (pmedium->tymed)
1094 if ( (pmedium->pUnkForRelease==0) &&
1095 (pmedium->u.hGlobal!=0) )
1096 GlobalFree(pmedium->u.hGlobal);
1098 pmedium->u.hGlobal = 0;
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;
1118 if (pmedium->u.pstm!=0)
1120 IStream_Release(pmedium->u.pstm);
1123 pmedium->u.pstm = 0;
1126 case TYMED_ISTORAGE:
1128 if (pmedium->u.pstg!=0)
1130 IStorage_Release(pmedium->u.pstg);
1133 pmedium->u.pstg = 0;
1138 if ( (pmedium->pUnkForRelease==0) &&
1139 (pmedium->u.hGlobal!=0) )
1140 DeleteObject(pmedium->u.hGlobal);
1142 pmedium->u.hGlobal = 0;
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;
1159 if ( (pmedium->pUnkForRelease==0) &&
1160 (pmedium->u.hEnhMetaFile!=0) )
1162 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
1165 pmedium->u.hEnhMetaFile = 0;
1174 * After cleaning up, the unknown is released
1176 if (pmedium->pUnkForRelease!=0)
1178 IUnknown_Release(pmedium->pUnkForRelease);
1179 pmedium->pUnkForRelease = 0;
1184 * OLEDD_Initialize()
1186 * Initializes the OLE drag and drop data structures.
1188 static void OLEDD_Initialize()
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);
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);
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;
1257 * The item was found in the list. It shouldn't have been there
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;
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;
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;
1344 * If we get here, the node is not in the tree
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;
1382 * The item was found in the list.
1389 * If we get here, the item is not in the list
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
1402 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
1412 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
1414 SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams);
1421 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
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);
1441 case WM_LBUTTONDOWN:
1442 case WM_MBUTTONDOWN:
1443 case WM_RBUTTONDOWN:
1445 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
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);
1466 * This is a window proc after all. Let's call the default.
1468 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
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
1480 * trackerInfo - Pointer to the structure identifying the
1481 * drag & drop operation that is currently
1483 * mousePos - Current position of the mouse in screen
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,
1493 HWND hwndNewTarget = 0;
1497 * Get the handle of the window under the mouse
1499 hwndNewTarget = WindowFromPoint(mousePos);
1502 * Every time, we re-initialize the effects passed to the
1503 * IDropTarget to the effects allowed by the source.
1505 *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
1508 * If we are hovering over the same target as before, send the
1509 * DragOver notification
1511 if ( (trackerInfo->curDragTarget != 0) &&
1512 (trackerInfo->curDragTargetHWND==hwndNewTarget) )
1514 POINTL mousePosParam;
1517 * The documentation tells me that the coordinate should be in the target
1518 * window's coordinate space. However, the tests I made tell me the
1519 * coordinates should be in screen coordinates.
1521 mousePosParam.x = mousePos.x;
1522 mousePosParam.y = mousePos.y;
1524 IDropTarget_DragOver(trackerInfo->curDragTarget,
1527 trackerInfo->pdwEffect);
1531 DropTargetNode* newDropTargetNode = 0;
1534 * If we changed window, we have to notify our old target and check for
1537 if (trackerInfo->curDragTarget!=0)
1539 IDropTarget_DragLeave(trackerInfo->curDragTarget);
1543 * Make sure we're hovering over a window.
1545 if (hwndNewTarget!=0)
1548 * Find-out if there is a drag target under the mouse
1550 newDropTargetNode = OLEDD_FindDropTarget(hwndNewTarget);
1552 trackerInfo->curDragTargetHWND = hwndNewTarget;
1553 trackerInfo->curDragTarget = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
1556 * If there is, notify it that we just dragged-in
1558 if (trackerInfo->curDragTarget!=0)
1560 POINTL mousePosParam;
1563 * The documentation tells me that the coordinate should be in the target
1564 * window's coordinate space. However, the tests I made tell me the
1565 * coordinates should be in screen coordinates.
1567 mousePosParam.x = mousePos.x;
1568 mousePosParam.y = mousePos.y;
1570 IDropTarget_DragEnter(trackerInfo->curDragTarget,
1571 trackerInfo->dataObject,
1574 trackerInfo->pdwEffect);
1580 * The mouse is not over a window so we don't track anything.
1582 trackerInfo->curDragTargetHWND = 0;
1583 trackerInfo->curDragTarget = 0;
1588 * Now that we have done that, we have to tell the source to give
1589 * us feedback on the work being done by the target. If we don't
1590 * have a target, simulate no effect.
1592 if (trackerInfo->curDragTarget==0)
1594 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
1597 hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
1598 *trackerInfo->pdwEffect);
1601 * When we ask for feedback from the drop source, sometimes it will
1602 * do all the necessary work and sometimes it will not handle it
1603 * when that's the case, we must display the standard drag and drop
1606 if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
1608 if ( (*trackerInfo->pdwEffect & DROPEFFECT_MOVE) ||
1609 (*trackerInfo->pdwEffect & DROPEFFECT_COPY) ||
1610 (*trackerInfo->pdwEffect & DROPEFFECT_LINK) )
1612 SetCursor(LoadCursorA(0, IDC_SIZEALLA));
1616 SetCursor(LoadCursorA(0, IDC_NOA));
1622 * OLEDD_TrackStateChange()
1624 * This method is invoked while a drag and drop operation is in effect.
1625 * It is used to notify the drop target/drop source callbacks when
1626 * the state of the keyboard or mouse button change.
1629 * trackerInfo - Pointer to the structure identifying the
1630 * drag & drop operation that is currently
1632 * mousePos - Current position of the mouse in screen
1634 * keyState - Contains the state of the shift keys and the
1635 * mouse buttons (MK_LBUTTON and the like)
1637 static void OLEDD_TrackStateChange(
1638 TrackerWindowInfo* trackerInfo,
1643 * Ask the drop source what to do with the operation.
1645 trackerInfo->returnValue = IDropSource_QueryContinueDrag(
1646 trackerInfo->dropSource,
1647 trackerInfo->escPressed,
1651 * All the return valued will stop the operation except the S_OK
1654 if (trackerInfo->returnValue!=S_OK)
1657 * Make sure the message loop in DoDragDrop stops
1659 trackerInfo->trackingDone = TRUE;
1662 * Release the mouse in case the drop target decides to show a popup
1663 * or a menu or something.
1668 * If we end-up over a target, drop the object in the target or
1669 * inform the target that the operation was cancelled.
1671 if (trackerInfo->curDragTarget!=0)
1673 switch (trackerInfo->returnValue)
1676 * If the source wants us to complete the operation, we tell
1677 * the drop target that we just dropped the object in it.
1679 case DRAGDROP_S_DROP:
1681 POINTL mousePosParam;
1684 * The documentation tells me that the coordinate should be
1685 * in the target window's coordinate space. However, the tests
1686 * I made tell me the coordinates should be in screen coordinates.
1688 mousePosParam.x = mousePos.x;
1689 mousePosParam.y = mousePos.y;
1691 IDropTarget_Drop(trackerInfo->curDragTarget,
1692 trackerInfo->dataObject,
1695 trackerInfo->pdwEffect);
1699 * If the source told us that we should cancel, fool the drop
1700 * target by telling it that the mouse left it's window.
1702 case DRAGDROP_S_CANCEL:
1703 IDropTarget_DragLeave(trackerInfo->curDragTarget);
1711 * OLEDD_GetButtonState()
1713 * This method will use the current state of the keyboard to build
1714 * a button state mask equivalent to the one passed in the
1715 * WM_MOUSEMOVE wParam.
1717 static DWORD OLEDD_GetButtonState()
1719 BYTE keyboardState[256];
1722 GetKeyboardState(keyboardState);
1724 if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
1725 keyMask |= MK_SHIFT;
1727 if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
1728 keyMask |= MK_CONTROL;
1730 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
1731 keyMask |= MK_LBUTTON;
1733 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
1734 keyMask |= MK_RBUTTON;
1736 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
1737 keyMask |= MK_MBUTTON;