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 * 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
,
1521 trackerInfo
->pdwEffect
);
1525 DropTargetNode
* newDropTargetNode
= 0;
1528 * If we changed window, we have to notify our old target and check for
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
,
1568 trackerInfo
->pdwEffect
);
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
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
));
1610 SetCursor(LoadCursorA(0, IDC_NOA
));
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.
1623 * trackerInfo - Pointer to the structure identifying the
1624 * drag & drop operation that is currently
1626 * mousePos - Current position of the mouse in screen
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
,
1637 * Ask the drop source what to do with the operation.
1639 trackerInfo
->returnValue
= IDropSource_QueryContinueDrag(
1640 trackerInfo
->dropSource
,
1641 trackerInfo
->escPressed
,
1645 * All the return valued will stop the operation except the S_OK
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.
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
,
1689 trackerInfo
->pdwEffect
);
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
);
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];
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
;