Implementation of the ReleaseStgMedium method.
[wine/multimedia.git] / ole / ole2.c
blob3b76ccba46194c7e5a0bf61674e95309aab49e45
1 /*
2 * OLE2 library
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1999 Francis Beaudet
6 */
8 #include <assert.h>
10 #include "winuser.h"
11 #include "winerror.h"
12 #include "ole2.h"
13 #include "process.h"
14 #include "wine/obj_clientserver.h"
15 #include "debug.h"
17 /******************************************************************************
18 * These are static/global variables and internal data structures that the
19 * OLE module uses to maintain it's state.
21 typedef struct tagDropTargetNode
23 HWND hwndTarget;
24 IDropTarget* dropTarget;
25 struct tagDropTargetNode* prevDropTarget;
26 struct tagDropTargetNode* nextDropTarget;
27 } DropTargetNode;
29 typedef struct tagTrackerWindowInfo
31 IDataObject* dataObject;
32 IDropSource* dropSource;
33 DWORD dwOKEffect;
34 DWORD* pdwEffect;
35 BOOL trackingDone;
36 HRESULT returnValue;
38 BOOL escPressed;
39 HWND curDragTargetHWND;
40 IDropTarget* curDragTarget;
41 } TrackerWindowInfo;
44 * This is the lock count on the OLE library. It is controlled by the
45 * OLEInitialize/OLEUninitialize methods.
47 static ULONG OLE_moduleLockCount = 0;
50 * Name of our registered window class.
52 static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";
55 * This is the head of the Drop target container.
57 static DropTargetNode* targetListHead = NULL;
59 /******************************************************************************
60 * These are the prototypes of the utility methods used for OLE Drag n Drop
62 static void OLEDD_Initialize();
63 static void OLEDD_UnInitialize();
64 static void OLEDD_InsertDropTarget(
65 DropTargetNode* nodeToAdd);
66 static DropTargetNode* OLEDD_ExtractDropTarget(
67 HWND hwndOfTarget);
68 static DropTargetNode* OLEDD_FindDropTarget(
69 HWND hwndOfTarget);
70 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
71 HWND hwnd,
72 UINT uMsg,
73 WPARAM wParam,
74 LPARAM lParam);
75 static void OLEDD_TrackMouseMove(
76 TrackerWindowInfo* trackerInfo,
77 POINT mousePos,
78 DWORD keyState);
79 static void OLEDD_TrackStateChange(
80 TrackerWindowInfo* trackerInfo,
81 POINT mousePos,
82 DWORD keyState);
83 static DWORD OLEDD_GetButtonState();
86 /******************************************************************************
87 * OleBuildVersion [OLE2.1]
89 DWORD WINAPI OleBuildVersion(void)
91 TRACE(ole,"(void)\n");
92 return (rmm<<16)+rup;
95 /***********************************************************************
96 * OleInitialize (OLE2.2) (OLE32.108)
98 HRESULT WINAPI OleInitialize(LPVOID reserved)
100 HRESULT hr;
102 TRACE(ole, "(%p)\n", reserved);
105 * The first duty of the OleInitialize is to initialize the COM libraries.
107 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
110 * If the CoInitializeEx call failed, the OLE libraries can't be
111 * initialized.
113 if (FAILED(hr))
114 return hr;
117 * Then, it has to initialize the OLE specific modules.
118 * This includes:
119 * Clipboard
120 * Drag and Drop
121 * Object linking and Embedding
122 * In-place activation
124 if (OLE_moduleLockCount==0)
127 * Initialize the libraries.
129 TRACE(ole, "() - Initializing the OLE libraries\n");
132 * Drag and Drop
134 OLEDD_Initialize();
138 * Then, we increase the lock count on the OLE module.
140 OLE_moduleLockCount++;
142 return hr;
145 /******************************************************************************
146 * CoGetCurrentProcess [COMPOBJ.34] [OLE2.2][OLE32.108]
148 * NOTES
149 * Is DWORD really the correct return type for this function?
151 DWORD WINAPI CoGetCurrentProcess(void) {
152 return (DWORD)PROCESS_Current();
155 /******************************************************************************
156 * OleUninitialize [OLE2.3] [OLE32.131]
158 void WINAPI OleUninitialize(void)
160 TRACE(ole, "()\n");
163 * Decrease the lock count on the OLE module.
165 OLE_moduleLockCount--;
168 * If we hit the bottom of the lock stack, free the libraries.
170 if (OLE_moduleLockCount==0)
173 * Actually free the libraries.
175 TRACE(ole, "() - Freeing the last reference count\n");
178 * Drag and Drop
180 OLEDD_UnInitialize();
184 * Then, uninitialize the COM libraries.
186 CoUninitialize();
189 /***********************************************************************
190 * OleFlushClipboard [OLE2.76]
192 HRESULT WINAPI OleFlushClipboard16(void)
194 return S_OK;
197 /***********************************************************************
198 * OleSetClipboard [OLE32.127]
200 HRESULT WINAPI OleSetClipboard(LPVOID pDataObj)
202 FIXME(ole,"(%p), stub!\n", pDataObj);
203 return S_OK;
206 /******************************************************************************
207 * CoRegisterMessageFilter32 [OLE32.38]
209 HRESULT WINAPI CoRegisterMessageFilter(
210 LPMESSAGEFILTER lpMessageFilter, /* Pointer to interface */
211 LPMESSAGEFILTER *lplpMessageFilter /* Indirect pointer to prior instance if non-NULL */
213 FIXME(ole,"stub\n");
214 if (lplpMessageFilter) {
215 *lplpMessageFilter = NULL;
217 return S_OK;
220 /******************************************************************************
221 * OleInitializeWOW [OLE32.109]
223 HRESULT WINAPI OleInitializeWOW(DWORD x) {
224 FIXME(ole,"(0x%08lx),stub!\n",x);
225 return 0;
228 /***********************************************************************
229 * RegisterDragDrop16 (OLE2.35)
231 HRESULT WINAPI RegisterDragDrop16(
232 HWND16 hwnd,
233 LPDROPTARGET pDropTarget
235 FIXME(ole,"(0x%04x,%p),stub!\n",hwnd,pDropTarget);
236 return S_OK;
239 /***********************************************************************
240 * RegisterDragDrop32 (OLE32.139)
242 HRESULT WINAPI RegisterDragDrop(
243 HWND hwnd,
244 LPDROPTARGET pDropTarget)
246 DropTargetNode* dropTargetInfo;
248 TRACE(ole,"(0x%x,%p)\n", hwnd, pDropTarget);
251 * First, check if the window is already registered.
253 dropTargetInfo = OLEDD_FindDropTarget(hwnd);
255 if (dropTargetInfo!=NULL)
256 return DRAGDROP_E_ALREADYREGISTERED;
259 * If it's not there, we can add it. We first create a node for it.
261 dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));
263 if (dropTargetInfo==NULL)
264 return E_OUTOFMEMORY;
266 dropTargetInfo->hwndTarget = hwnd;
267 dropTargetInfo->prevDropTarget = NULL;
268 dropTargetInfo->nextDropTarget = NULL;
271 * Don't forget that this is an interface pointer, need to nail it down since
272 * we keep a copy of it.
274 dropTargetInfo->dropTarget = pDropTarget;
275 IDropTarget_AddRef(dropTargetInfo->dropTarget);
277 OLEDD_InsertDropTarget(dropTargetInfo);
279 return S_OK;
282 /***********************************************************************
283 * RevokeDragDrop16 (OLE2.36)
285 HRESULT WINAPI RevokeDragDrop16(
286 HWND16 hwnd
288 FIXME(ole,"(0x%04x),stub!\n",hwnd);
289 return S_OK;
292 /***********************************************************************
293 * RevokeDragDrop32 (OLE32.141)
295 HRESULT WINAPI RevokeDragDrop(
296 HWND hwnd)
298 DropTargetNode* dropTargetInfo;
300 TRACE(ole,"(0x%x)\n", hwnd);
303 * First, check if the window is already registered.
305 dropTargetInfo = OLEDD_ExtractDropTarget(hwnd);
308 * If it ain't in there, it's an error.
310 if (dropTargetInfo==NULL)
311 return DRAGDROP_E_NOTREGISTERED;
314 * If it's in there, clean-up it's used memory and
315 * references
317 IDropTarget_Release(dropTargetInfo->dropTarget);
318 HeapFree(GetProcessHeap(), 0, dropTargetInfo);
320 return S_OK;
323 /***********************************************************************
324 * OleRegGetUserType (OLE32.122)
326 HRESULT WINAPI OleRegGetUserType(
327 REFCLSID clsid,
328 DWORD dwFormOfType,
329 LPOLESTR* pszUserType)
331 FIXME(ole,",stub!\n");
332 return S_OK;
335 /***********************************************************************
336 * DoDragDrop32 [OLE32.65]
338 HRESULT WINAPI DoDragDrop (
339 IDataObject *pDataObject, /* ptr to the data obj */
340 IDropSource* pDropSource, /* ptr to the source obj */
341 DWORD dwOKEffect, /* effects allowed by the source */
342 DWORD *pdwEffect) /* ptr to effects of the source */
344 TrackerWindowInfo trackerInfo;
345 HWND hwndTrackWindow;
346 MSG msg;
348 TRACE(ole,"(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
351 * Setup the drag n drop tracking window.
353 trackerInfo.dataObject = pDataObject;
354 trackerInfo.dropSource = pDropSource;
355 trackerInfo.dwOKEffect = dwOKEffect;
356 trackerInfo.pdwEffect = pdwEffect;
357 trackerInfo.trackingDone = FALSE;
358 trackerInfo.escPressed = FALSE;
359 trackerInfo.curDragTargetHWND = 0;
360 trackerInfo.curDragTarget = 0;
362 hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS,
363 "TrackerWindow",
364 WS_POPUP,
365 CW_USEDEFAULT, CW_USEDEFAULT,
366 CW_USEDEFAULT, CW_USEDEFAULT,
370 (LPVOID)&trackerInfo);
372 if (hwndTrackWindow!=0)
375 * Capture the mouse input
377 SetCapture(hwndTrackWindow);
380 * Pump messages. All mouse input should go the the capture window.
382 while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )
384 if ( (msg.message >= WM_KEYFIRST) &&
385 (msg.message <= WM_KEYFIRST) )
388 * When keyboard messages are sent to windows on this thread, we
389 * want to ignore notify the drop source that the state changed.
390 * in the case of the Escape key, we also notify the drop source
391 * we give it a special meaning.
393 if ( (msg.message==WM_KEYDOWN) &&
394 (msg.wParam==VK_ESCAPE) )
396 trackerInfo.escPressed = TRUE;
400 * Notify the drop source.
402 OLEDD_TrackStateChange(&trackerInfo,
403 msg.pt,
404 OLEDD_GetButtonState());
406 else
409 * Dispatch the messages only when it's not a keyboard message.
411 DispatchMessageA(&msg);
416 * Destroy the temporary window.
418 DestroyWindow(hwndTrackWindow);
420 return trackerInfo.returnValue;
423 return E_FAIL;
426 /***********************************************************************
427 * OleQueryLinkFromData32 [OLE32.118]
429 HRESULT WINAPI OleQueryLinkFromData32(
430 IDataObject* pSrcDataObject)
432 FIXME(ole,"(%p),stub!\n", pSrcDataObject);
433 return S_OK;
436 /***********************************************************************
437 * OleRegGetMiscStatus32 [OLE32.121]
439 HRESULT WINAPI OleRegGetMiscStatus32(
440 REFCLSID clsid,
441 DWORD dwAspect,
442 DWORD* pdwStatus)
444 FIXME(ole,"(),stub!\n");
445 return REGDB_E_CLASSNOTREG;
448 /***********************************************************************
449 * OleGetClipboard32 [OLE32.105]
451 HRESULT WINAPI OleGetClipboard32(
452 IDataObject** ppDataObj)
454 FIXME(ole,"(%p),stub!\n", ppDataObj);
456 if (ppDataObj)
457 *ppDataObj=0;
459 return E_FAIL;
462 /***********************************************************************
463 * OleCreateMenuDescriptor [OLE32.97]
465 HOLEMENU WINAPI OleCreateMenuDescriptor(
466 HMENU hmenuCombined,
467 LPOLEMENUGROUPWIDTHS lpMenuWidths)
469 FIXME(ole,"(%x,%p),stub!\n", hmenuCombined, lpMenuWidths);
471 return NULL;
474 /***********************************************************************
475 * OleDestroyMenuDescriptor [OLE32.99]
477 void WINAPI OleDestroyMenuDescriptor(
478 HOLEMENU hmenuDescriptor)
480 FIXME(ole,"(%x),stub!\n", (unsigned int)hmenuDescriptor);
483 /***********************************************************************
484 * OleSetMenuDescriptor [OLE32.129]
486 HRESULT WINAPI OleSetMenuDescriptor(
487 HOLEMENU hmenuDescriptor,
488 HWND hwndFrame,
489 HWND hwndActiveObject,
490 LPOLEINPLACEFRAME lpFrame,
491 LPOLEINPLACEACTIVEOBJECT lpActiveObject)
493 FIXME(ole,"(%x, %x, %x, %p, %p),stub!\n",
494 (unsigned int)hmenuDescriptor,
495 hwndFrame,
496 hwndActiveObject,
497 lpFrame,
498 lpActiveObject);
500 return E_FAIL;
503 /***********************************************************************
504 * ReleaseStgMedium [OLE32.140]
506 void WINAPI ReleaseStgMedium(
507 STGMEDIUM* pmedium)
509 switch (pmedium->tymed)
511 case TYMED_HGLOBAL:
513 if ( (pmedium->pUnkForRelease==0) &&
514 (pmedium->u.hGlobal!=0) )
515 GlobalFree(pmedium->u.hGlobal);
517 pmedium->u.hGlobal = 0;
518 break;
520 case TYMED_FILE:
522 if (pmedium->u.lpszFileName!=0)
524 if (pmedium->pUnkForRelease==0)
526 DeleteFileW(pmedium->u.lpszFileName);
529 CoTaskMemFree(pmedium->u.lpszFileName);
532 pmedium->u.lpszFileName = 0;
533 break;
535 case TYMED_ISTREAM:
537 if (pmedium->u.pstm!=0)
539 IStream_Release(pmedium->u.pstm);
542 pmedium->u.pstm = 0;
543 break;
545 case TYMED_ISTORAGE:
547 if (pmedium->u.pstg!=0)
549 IStorage_Release(pmedium->u.pstg);
552 pmedium->u.pstg = 0;
553 break;
555 case TYMED_GDI:
557 if ( (pmedium->pUnkForRelease==0) &&
558 (pmedium->u.hGlobal!=0) )
559 DeleteObject(pmedium->u.hGlobal);
561 pmedium->u.hGlobal = 0;
562 break;
564 case TYMED_MFPICT:
566 if ( (pmedium->pUnkForRelease==0) &&
567 (pmedium->u.hMetaFilePict!=0) )
569 DeleteMetaFile(pmedium->u.hMetaFilePict);
570 GlobalFree(pmedium->u.hMetaFilePict);
573 pmedium->u.hMetaFilePict = 0;
574 break;
576 case TYMED_ENHMF:
578 if ( (pmedium->pUnkForRelease==0) &&
579 (pmedium->u.hEnhMetaFile!=0) )
581 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
584 pmedium->u.hEnhMetaFile = 0;
585 break;
587 case TYMED_NULL:
588 default:
589 break;
593 * After cleaning up, the unknown is released
595 if (pmedium->pUnkForRelease!=0)
597 IUnknown_Release(pmedium->pUnkForRelease);
598 pmedium->pUnkForRelease = 0;
602 /***
603 * OLEDD_Initialize()
605 * Initializes the OLE drag and drop data structures.
607 static void OLEDD_Initialize()
609 WNDCLASSA wndClass;
611 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
612 wndClass.style = CS_GLOBALCLASS;
613 wndClass.lpfnWndProc = (WNDPROC)OLEDD_DragTrackerWindowProc;
614 wndClass.cbClsExtra = 0;
615 wndClass.cbWndExtra = sizeof(TrackerWindowInfo*);
616 wndClass.hCursor = 0;
617 wndClass.hbrBackground = 0;
618 wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
620 RegisterClassA (&wndClass);
623 /***
624 * OLEDD_UnInitialize()
626 * Releases the OLE drag and drop data structures.
628 static void OLEDD_UnInitialize()
631 * Simply empty the list.
633 while (targetListHead!=NULL)
635 RevokeDragDrop(targetListHead->hwndTarget);
639 /***
640 * OLEDD_InsertDropTarget()
642 * Insert the target node in the tree.
644 static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd)
646 DropTargetNode* curNode;
647 DropTargetNode** parentNodeLink;
650 * Iterate the tree to find the insertion point.
652 curNode = targetListHead;
653 parentNodeLink = &targetListHead;
655 while (curNode!=NULL)
657 if (nodeToAdd->hwndTarget<curNode->hwndTarget)
660 * If the node we want to add has a smaller HWND, go left
662 parentNodeLink = &curNode->prevDropTarget;
663 curNode = curNode->prevDropTarget;
665 else if (nodeToAdd->hwndTarget>curNode->hwndTarget)
668 * If the node we want to add has a larger HWND, go right
670 parentNodeLink = &curNode->nextDropTarget;
671 curNode = curNode->nextDropTarget;
673 else
676 * The item was found in the list. It shouldn't have been there
678 assert(FALSE);
679 return;
684 * If we get here, we have found a spot for our item. The parentNodeLink
685 * pointer points to the pointer that we have to modify.
686 * The curNode should be NULL. We just have to establish the link and Voila!
688 assert(curNode==NULL);
689 assert(parentNodeLink!=NULL);
690 assert(*parentNodeLink==NULL);
692 *parentNodeLink=nodeToAdd;
695 /***
696 * OLEDD_ExtractDropTarget()
698 * Removes the target node from the tree.
700 static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget)
702 DropTargetNode* curNode;
703 DropTargetNode** parentNodeLink;
706 * Iterate the tree to find the insertion point.
708 curNode = targetListHead;
709 parentNodeLink = &targetListHead;
711 while (curNode!=NULL)
713 if (hwndOfTarget<curNode->hwndTarget)
716 * If the node we want to add has a smaller HWND, go left
718 parentNodeLink = &curNode->prevDropTarget;
719 curNode = curNode->prevDropTarget;
721 else if (hwndOfTarget>curNode->hwndTarget)
724 * If the node we want to add has a larger HWND, go right
726 parentNodeLink = &curNode->nextDropTarget;
727 curNode = curNode->nextDropTarget;
729 else
732 * The item was found in the list. Detach it from it's parent and
733 * re-insert it's kids in the tree.
735 assert(parentNodeLink!=NULL);
736 assert(*parentNodeLink==curNode);
739 * We arbitrately re-attach the left sub-tree to the parent.
741 *parentNodeLink = curNode->prevDropTarget;
744 * And we re-insert the right subtree
746 if (curNode->nextDropTarget!=NULL)
748 OLEDD_InsertDropTarget(curNode->nextDropTarget);
752 * The node we found is still a valid node once we complete
753 * the unlinking of the kids.
755 curNode->nextDropTarget=NULL;
756 curNode->prevDropTarget=NULL;
758 return curNode;
763 * If we get here, the node is not in the tree
765 return NULL;
768 /***
769 * OLEDD_FindDropTarget()
771 * Finds information about the drop target.
773 static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
775 DropTargetNode* curNode;
778 * Iterate the tree to find the HWND value.
780 curNode = targetListHead;
782 while (curNode!=NULL)
784 if (hwndOfTarget<curNode->hwndTarget)
787 * If the node we want to add has a smaller HWND, go left
789 curNode = curNode->prevDropTarget;
791 else if (hwndOfTarget>curNode->hwndTarget)
794 * If the node we want to add has a larger HWND, go right
796 curNode = curNode->nextDropTarget;
798 else
801 * The item was found in the list.
803 return curNode;
808 * If we get here, the item is not in the list
810 return NULL;
813 /***
814 * OLEDD_DragTrackerWindowProc()
816 * This method is the WindowProcedure of the drag n drop tracking
817 * window. During a drag n Drop operation, an invisible window is created
818 * to receive the user input and act upon it. This procedure is in charge
819 * of this behavior.
821 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
822 HWND hwnd,
823 UINT uMsg,
824 WPARAM wParam,
825 LPARAM lParam)
827 switch (uMsg)
829 case WM_CREATE:
831 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
833 SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams);
836 break;
838 case WM_MOUSEMOVE:
840 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
841 POINT mousePos;
844 * Get the current mouse position in screen coordinates.
846 mousePos.x = LOWORD(lParam);
847 mousePos.y = HIWORD(lParam);
848 ClientToScreen(hwnd, &mousePos);
851 * Track the movement of the mouse.
853 OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam);
855 break;
857 case WM_LBUTTONUP:
858 case WM_MBUTTONUP:
859 case WM_RBUTTONUP:
860 case WM_LBUTTONDOWN:
861 case WM_MBUTTONDOWN:
862 case WM_RBUTTONDOWN:
864 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
865 POINT mousePos;
868 * Get the current mouse position in screen coordinates.
870 mousePos.x = LOWORD(lParam);
871 mousePos.y = HIWORD(lParam);
872 ClientToScreen(hwnd, &mousePos);
875 * Notify everyone that the button state changed
876 * TODO: Check if the "escape" key was pressed.
878 OLEDD_TrackStateChange(trackerInfo, mousePos, wParam);
880 break;
885 * This is a window proc after all. Let's call the default.
887 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
890 /***
891 * OLEDD_TrackMouseMove()
893 * This method is invoked while a drag and drop operation is in effect.
894 * it will generate the appropriate callbacks in the drop source
895 * and drop target. It will also provide the expected feedback to
896 * the user.
898 * params:
899 * trackerInfo - Pointer to the structure identifying the
900 * drag & drop operation that is currently
901 * active.
902 * mousePos - Current position of the mouse in screen
903 * coordinates.
904 * keyState - Contains the state of the shift keys and the
905 * mouse buttons (MK_LBUTTON and the like)
907 static void OLEDD_TrackMouseMove(
908 TrackerWindowInfo* trackerInfo,
909 POINT mousePos,
910 DWORD keyState)
912 HWND hwndNewTarget = 0;
913 HRESULT hr = S_OK;
916 * Get the handle of the window under the mouse
918 hwndNewTarget = WindowFromPoint(mousePos);
921 * If we are hovering over the same target as before, send the
922 * DragOver notification
924 if ( (trackerInfo->curDragTarget != 0) &&
925 (trackerInfo->curDragTargetHWND==hwndNewTarget) )
927 POINTL mousePosParam;
930 * The documentation tells me that the coordinate should be in the target
931 * window's coordinate space. However, the tests I made tell me the
932 * coordinates should be in screen coordinates.
934 mousePosParam.x = mousePos.x;
935 mousePosParam.y = mousePos.y;
937 IDropTarget_DragOver(trackerInfo->curDragTarget,
938 keyState,
939 mousePosParam,
940 trackerInfo->pdwEffect);
942 else
944 DropTargetNode* newDropTargetNode = 0;
947 * If we changed window, we have to notify our old target and check for
948 * the new one.
950 if (trackerInfo->curDragTarget!=0)
952 IDropTarget_DragLeave(trackerInfo->curDragTarget);
956 * Make sure we're hovering over a window.
958 if (hwndNewTarget!=0)
961 * Find-out if there is a drag target under the mouse
963 newDropTargetNode = OLEDD_FindDropTarget(hwndNewTarget);
965 trackerInfo->curDragTargetHWND = hwndNewTarget;
966 trackerInfo->curDragTarget = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
969 * If there is, notify it that we just dragged-in
971 if (trackerInfo->curDragTarget!=0)
973 POINTL mousePosParam;
976 * The documentation tells me that the coordinate should be in the target
977 * window's coordinate space. However, the tests I made tell me the
978 * coordinates should be in screen coordinates.
980 mousePosParam.x = mousePos.x;
981 mousePosParam.y = mousePos.y;
983 IDropTarget_DragEnter(trackerInfo->curDragTarget,
984 trackerInfo->dataObject,
985 keyState,
986 mousePosParam,
987 trackerInfo->pdwEffect);
990 else
993 * The mouse is not over a window so we don't track anything.
995 trackerInfo->curDragTargetHWND = 0;
996 trackerInfo->curDragTarget = 0;
1001 * Now that we have done that, we have to tell the source to give
1002 * us feedback on the work being done by the target. If we don't
1003 * have a target, simulate no effect.
1005 if (trackerInfo->curDragTarget==0)
1007 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
1010 hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
1011 *trackerInfo->pdwEffect);
1014 * When we ask for feedback from the drop source, sometimes it will
1015 * do all the necessary work and sometimes it will not handle it
1016 * when that's the case, we must display the standard drag and drop
1017 * cursors.
1019 if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
1021 if ( (*trackerInfo->pdwEffect & DROPEFFECT_MOVE) ||
1022 (*trackerInfo->pdwEffect & DROPEFFECT_COPY) ||
1023 (*trackerInfo->pdwEffect & DROPEFFECT_LINK) )
1025 SetCursor(LoadCursorA(0, IDC_SIZEALLA));
1027 else
1029 SetCursor(LoadCursorA(0, IDC_NOA));
1034 /***
1035 * OLEDD_TrackStateChange()
1037 * This method is invoked while a drag and drop operation is in effect.
1038 * It is used to notify the drop target/drop source callbacks when
1039 * the state of the keyboard or mouse button change.
1041 * params:
1042 * trackerInfo - Pointer to the structure identifying the
1043 * drag & drop operation that is currently
1044 * active.
1045 * mousePos - Current position of the mouse in screen
1046 * coordinates.
1047 * keyState - Contains the state of the shift keys and the
1048 * mouse buttons (MK_LBUTTON and the like)
1050 static void OLEDD_TrackStateChange(
1051 TrackerWindowInfo* trackerInfo,
1052 POINT mousePos,
1053 DWORD keyState)
1056 * Ask the drop source what to do with the operation.
1058 trackerInfo->returnValue = IDropSource_QueryContinueDrag(
1059 trackerInfo->dropSource,
1060 trackerInfo->escPressed,
1061 keyState);
1064 * All the return valued will stop the operation except the S_OK
1065 * return value.
1067 if (trackerInfo->returnValue!=S_OK)
1070 * Make sure the message loop in DoDragDrop stops
1072 trackerInfo->trackingDone = TRUE;
1075 * Release the mouse in case the drop target decides to show a popup
1076 * or a menu or something.
1078 ReleaseCapture();
1081 * If we end-up over a target, drop the object in the target or
1082 * inform the target that the operation was cancelled.
1084 if (trackerInfo->curDragTarget!=0)
1086 switch (trackerInfo->returnValue)
1089 * If the source wants us to complete the operation, we tell
1090 * the drop target that we just dropped the object in it.
1092 case DRAGDROP_S_DROP:
1094 POINTL mousePosParam;
1097 * The documentation tells me that the coordinate should be
1098 * in the target window's coordinate space. However, the tests
1099 * I made tell me the coordinates should be in screen coordinates.
1101 mousePosParam.x = mousePos.x;
1102 mousePosParam.y = mousePos.y;
1104 IDropTarget_Drop(trackerInfo->curDragTarget,
1105 trackerInfo->dataObject,
1106 keyState,
1107 mousePosParam,
1108 trackerInfo->pdwEffect);
1109 break;
1112 * If the source told us that we should cancel, fool the drop
1113 * target by telling it that the mouse left it's window.
1115 case DRAGDROP_S_CANCEL:
1116 IDropTarget_DragLeave(trackerInfo->curDragTarget);
1117 break;
1123 /***
1124 * OLEDD_GetButtonState()
1126 * This method will use the current state of the keyboard to build
1127 * a button state mask equivalent to the one passed in the
1128 * WM_MOUSEMOVE wParam.
1130 static DWORD OLEDD_GetButtonState()
1132 BYTE keyboardState[256];
1133 DWORD keyMask = 0;
1135 GetKeyboardState(keyboardState);
1137 if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
1138 keyMask |= MK_SHIFT;
1140 if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
1141 keyMask |= MK_CONTROL;
1143 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
1144 keyMask |= MK_LBUTTON;
1146 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
1147 keyMask |= MK_RBUTTON;
1149 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
1150 keyMask |= MK_MBUTTON;
1152 return keyMask;