4 * Copyright 1995 Martin von Loewis
5 * Copyright 1999 Francis Beaudet
6 * Copyright 1999 Noel Borthwick
17 #include "wine/obj_clientserver.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
28 IDropTarget
* dropTarget
;
29 struct tagDropTargetNode
* prevDropTarget
;
30 struct tagDropTargetNode
* nextDropTarget
;
33 typedef struct tagTrackerWindowInfo
35 IDataObject
* dataObject
;
36 IDropSource
* dropSource
;
43 HWND curDragTargetHWND
;
44 IDropTarget
* curDragTarget
;
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 */
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 */
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(
107 static DropTargetNode
* OLEDD_FindDropTarget(
109 static LRESULT WINAPI
OLEDD_DragTrackerWindowProc(
114 static void OLEDD_TrackMouseMove(
115 TrackerWindowInfo
* trackerInfo
,
118 static void OLEDD_TrackStateChange(
119 TrackerWindowInfo
* trackerInfo
,
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
)
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
156 * Then, it has to initialize the OLE specific modules.
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");
178 OLEMenu_Initialize();
182 * Then, we increase the lock count on the OLE module.
184 OLE_moduleLockCount
++;
189 /******************************************************************************
190 * CoGetCurrentProcess [COMPOBJ.34] [OLE2.2][OLE32.108]
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)
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");
224 OLEDD_UnInitialize();
229 OLEMenu_UnInitialize();
233 * Then, uninitialize the COM libraries.
238 /***********************************************************************
239 * OleFlushClipboard [OLE2.76]
241 HRESULT WINAPI
OleFlushClipboard16(void)
246 /***********************************************************************
247 * OleSetClipboard [OLE32.127]
249 HRESULT WINAPI
OleSetClipboard(LPVOID pDataObj
)
251 FIXME(ole
,"(%p), stub!\n", pDataObj
);
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 */
263 if (lplpMessageFilter
) {
264 *lplpMessageFilter
= NULL
;
269 /******************************************************************************
270 * OleInitializeWOW [OLE32.109]
272 HRESULT WINAPI
OleInitializeWOW(DWORD x
) {
273 FIXME(ole
,"(0x%08lx),stub!\n",x
);
277 /***********************************************************************
278 * RegisterDragDrop16 (OLE2.35)
280 HRESULT WINAPI
RegisterDragDrop16(
282 LPDROPTARGET pDropTarget
284 FIXME(ole
,"(0x%04x,%p),stub!\n",hwnd
,pDropTarget
);
288 /***********************************************************************
289 * RegisterDragDrop32 (OLE32.139)
291 HRESULT WINAPI
RegisterDragDrop(
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
);
331 /***********************************************************************
332 * RevokeDragDrop16 (OLE2.36)
334 HRESULT WINAPI
RevokeDragDrop16(
337 FIXME(ole
,"(0x%04x),stub!\n",hwnd
);
341 /***********************************************************************
342 * RevokeDragDrop32 (OLE32.141)
344 HRESULT WINAPI
RevokeDragDrop(
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
366 IDropTarget_Release(dropTargetInfo
->dropTarget
);
367 HeapFree(GetProcessHeap(), 0, dropTargetInfo
);
372 /***********************************************************************
373 * OleRegGetUserType (OLE32.122)
375 HRESULT WINAPI
OleRegGetUserType(
378 LPOLESTR
* pszUserType
)
380 FIXME(ole
,",stub!\n");
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
;
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
,
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
,
453 OLEDD_GetButtonState());
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
;
475 /***********************************************************************
476 * OleQueryLinkFromData32 [OLE32.118]
478 HRESULT WINAPI
OleQueryLinkFromData(
479 IDataObject
* pSrcDataObject
)
481 FIXME(ole
,"(%p),stub!\n", pSrcDataObject
);
485 /***********************************************************************
486 * OleRegGetMiscStatus [OLE32.121]
488 HRESULT WINAPI
OleRegGetMiscStatus(
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
);
512 /**************************************************************************
513 * Internal methods to manage the shared OLE menu in response to the
514 * OLE***MenuDescriptor API
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() );
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
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() )) )
561 /* Create an entry for the hook table */
562 if ( !(pHookItem
= HeapAlloc(GetProcessHeap(), 0,
563 sizeof(OleMenuHookItem
)) ) )
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
)
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
)
581 /* Insert the hook table entry */
582 if ( -1 == DPA_InsertPtr( OLEMenu_MsgHookDPA
, 0, pHookItem
) )
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
);
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
606 BOOL
OLEMenu_UnInstallHooks( DWORD tid
)
609 OleMenuHookItem
*pHookItem
= NULL
;
611 if ( !OLEMenu_MsgHookDPA
) /* No hooks set */
614 /* Lookup the hHook index for this tid */
615 if ( !OLEMenu_IsHookInstalled( tid
, &ixHook
) )
618 /* Remove the hook entry from the table(the pointer itself is not deleted) */
619 if ( !( pHookItem
= DPA_DeletePtr(OLEMenu_MsgHookDPA
, ixHook
) ) )
622 /* Uninstall the hooks installed for this thread */
623 if ( !UnhookWindowsHookEx( pHookItem
->GetMsg_hHook
) )
625 if ( !UnhookWindowsHookEx( pHookItem
->CallWndProc_hHook
) )
628 /* Release the hook table entry */
629 HeapFree(pHookItem
->hHeap
, 0, pHookItem
);
634 /* Release the hook table entry */
636 HeapFree(pHookItem
->hHeap
, 0, pHookItem
);
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
)
651 OleMenuHookItem
*pHookItem
= NULL
;
656 if ( !OLEMenu_MsgHookDPA
) /* No hooks set */
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
) ) )
667 if ( tid
== pHookItem
->tid
)
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
)
690 nItems
= GetMenuItemCount( hMainMenu
);
692 for (i
= 0; i
< nItems
; i
++)
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
)
706 /* Recursively search without updating pnPos */
707 else if ( OLEMenu_FindMainMenuIndex( hsubmenu
, hPopupMenu
, NULL
) )
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
)
739 /* Find the menu item index in the shared OLE menu that this item belongs to */
740 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor
->hmenuCombined
, hmenu
, &nPos
) )
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
];
754 /* Odd elements are server menu widths */
755 pOleMenuDescriptor
->bIsServerItem
= (i
%2) ? TRUE
: FALSE
;
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
;
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
)
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" );
793 /* Get the menu descriptor */
794 pOleMenuDescriptor
= (OleMenuDescriptor
*) GlobalLock( hOleMenu
);
795 if ( !pOleMenuDescriptor
) /* Bad descriptor! */
798 /* Process menu messages */
799 switch( pMsg
->message
)
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
);
812 case WM_INITMENUPOPUP
:
814 /* Save the state for whether this is a server owned menu */
815 OLEMenu_SetIsServerMenu( (HMENU
)pMsg
->wParam
, pOleMenuDescriptor
);
821 fuFlags
= HIWORD(pMsg
->wParam
); /* Get flags */
822 if ( fuFlags
& MF_SYSMENU
)
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
);
834 LPDRAWITEMSTRUCT lpdis
= (LPDRAWITEMSTRUCT
) pMsg
->lParam
;
835 if ( pMsg
->wParam
!= 0 || lpdis
->CtlType
!= ODT_MENU
)
836 goto NEXTHOOK
; /* Not a menu message */
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
);
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" );
864 /* Pass on the message to the next hooker */
865 return CallNextHookEx( pHookItem
->CallWndProc_hHook
, code
, wParam
, lParam
);
868 /*************************************************************************
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
)
876 HOLEMENU hOleMenu
= 0;
877 OleMenuDescriptor
*pOleMenuDescriptor
= NULL
;
878 OleMenuHookItem
*pHookItem
= NULL
;
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
)
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" );
898 /* Process menu messages */
899 switch( pMsg
->message
)
903 wCode
= HIWORD(pMsg
->wParam
); /* Get notification code */
905 goto NEXTHOOK
; /* Not a menu message */
912 /* Get the menu descriptor */
913 pOleMenuDescriptor
= (OleMenuDescriptor
*) GlobalLock( hOleMenu
);
914 if ( !pOleMenuDescriptor
) /* Bad descriptor! */
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
;
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" );
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.
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(
954 LPOLEMENUGROUPWIDTHS lpMenuWidths
)
957 OleMenuDescriptor
*pOleMenuDescriptor
;
960 if ( !hmenuCombined
|| !lpMenuWidths
)
963 /* Create an OLE menu descriptor */
964 if ( !(hOleMenu
= GlobalAlloc(GMEM_MOVEABLE
| GMEM_ZEROINIT
,
965 sizeof(OleMenuDescriptor
) ) ) )
968 pOleMenuDescriptor
= (OleMenuDescriptor
*) GlobalLock( hOleMenu
);
969 if ( !pOleMenuDescriptor
)
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
);
983 /***********************************************************************
984 * OleDestroyMenuDescriptor [OLE32.99]
985 * Destroy the shared menu descriptor
987 HRESULT WINAPI
OleDestroyMenuDescriptor(
988 HOLEMENU hmenuDescriptor
)
990 if ( hmenuDescriptor
)
991 GlobalFree( hmenuDescriptor
);
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.
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
1010 * S_OK - menu installed correctly
1011 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1013 HRESULT WINAPI
OleSetMenuDescriptor(
1016 HWND hwndActiveObject
,
1017 LPOLEINPLACEFRAME lpFrame
,
1018 LPOLEINPLACEACTIVEOBJECT lpActiveObject
)
1020 OleMenuDescriptor
*pOleMenuDescriptor
= NULL
;
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
,
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
) )
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() ) )
1069 else /* Want to uninstall dispatching code */
1071 /* Uninstall the hooks */
1072 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1075 /* Remove the menu descriptor property from the frame window */
1076 RemovePropA( hwndFrame
, "PROP_OLEMenuDescriptor" );
1082 /***********************************************************************
1083 * ReleaseStgMedium [OLE32.140]
1085 void WINAPI
ReleaseStgMedium(
1088 switch (pmedium
->tymed
)
1092 if ( (pmedium
->pUnkForRelease
==0) &&
1093 (pmedium
->u
.hGlobal
!=0) )
1094 GlobalFree(pmedium
->u
.hGlobal
);
1096 pmedium
->u
.hGlobal
= 0;
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;
1116 if (pmedium
->u
.pstm
!=0)
1118 IStream_Release(pmedium
->u
.pstm
);
1121 pmedium
->u
.pstm
= 0;
1124 case TYMED_ISTORAGE
:
1126 if (pmedium
->u
.pstg
!=0)
1128 IStorage_Release(pmedium
->u
.pstg
);
1131 pmedium
->u
.pstg
= 0;
1136 if ( (pmedium
->pUnkForRelease
==0) &&
1137 (pmedium
->u
.hGlobal
!=0) )
1138 DeleteObject(pmedium
->u
.hGlobal
);
1140 pmedium
->u
.hGlobal
= 0;
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;
1157 if ( (pmedium
->pUnkForRelease
==0) &&
1158 (pmedium
->u
.hEnhMetaFile
!=0) )
1160 DeleteEnhMetaFile(pmedium
->u
.hEnhMetaFile
);
1163 pmedium
->u
.hEnhMetaFile
= 0;
1172 * After cleaning up, the unknown is released
1174 if (pmedium
->pUnkForRelease
!=0)
1176 IUnknown_Release(pmedium
->pUnkForRelease
);
1177 pmedium
->pUnkForRelease
= 0;
1182 * OLEDD_Initialize()
1184 * Initializes the OLE drag and drop data structures.
1186 static void OLEDD_Initialize()
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
);
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
);
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
;
1255 * The item was found in the list. It shouldn't have been there
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
;
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
;
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
;
1342 * If we get here, the node is not in the tree
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
;
1380 * The item was found in the list.
1387 * If we get here, the item is not in the list
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
1400 static LRESULT WINAPI
OLEDD_DragTrackerWindowProc(
1410 LPCREATESTRUCTA createStruct
= (LPCREATESTRUCTA
)lParam
;
1412 SetWindowLongA(hwnd
, 0, (LONG
)createStruct
->lpCreateParams
);
1419 TrackerWindowInfo
* trackerInfo
= (TrackerWindowInfo
*)GetWindowLongA(hwnd
, 0);
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
);
1439 case WM_LBUTTONDOWN
:
1440 case WM_MBUTTONDOWN
:
1441 case WM_RBUTTONDOWN
:
1443 TrackerWindowInfo
* trackerInfo
= (TrackerWindowInfo
*)GetWindowLongA(hwnd
, 0);
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
);
1464 * This is a window proc after all. Let's call the default.
1466 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
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
1478 * trackerInfo - Pointer to the structure identifying the
1479 * drag & drop operation that is currently
1481 * mousePos - Current position of the mouse in screen
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
,
1491 HWND hwndNewTarget
= 0;
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
,
1519 trackerInfo
->pdwEffect
);
1523 DropTargetNode
* newDropTargetNode
= 0;
1526 * If we changed window, we have to notify our old target and check for
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
,
1566 trackerInfo
->pdwEffect
);
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
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
));
1608 SetCursor(LoadCursorA(0, IDC_NOA
));
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.
1621 * trackerInfo - Pointer to the structure identifying the
1622 * drag & drop operation that is currently
1624 * mousePos - Current position of the mouse in screen
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
,
1635 * Ask the drop source what to do with the operation.
1637 trackerInfo
->returnValue
= IDropSource_QueryContinueDrag(
1638 trackerInfo
->dropSource
,
1639 trackerInfo
->escPressed
,
1643 * All the return valued will stop the operation except the S_OK
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.
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
,
1687 trackerInfo
->pdwEffect
);
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
);
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];
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
;