| /* | |
| * OLE2 library | |
| * | |
| * Copyright 1995 Martin von Loewis | |
| * Copyright 1999 Francis Beaudet | |
| */ | |
| #include <assert.h> | |
| #include "windows.h" | |
| #include "winerror.h" | |
| #include "ole2.h" | |
| #include "process.h" | |
| #include "debug.h" | |
| #include "objbase.h" | |
| #include "objidl.h" | |
| #include "wine/obj_base.h" | |
| #include "wine/obj_clientserver.h" | |
| #include "wine/obj_storage.h" | |
| #include "wine/obj_moniker.h" | |
| /****************************************************************************** | |
| * These are static/global variables and internal data structures that the | |
| * OLE module uses to maintain it's state. | |
| */ | |
| typedef struct tagDropTargetNode | |
| { | |
| HWND32 hwndTarget; | |
| IDropTarget* dropTarget; | |
| struct tagDropTargetNode* prevDropTarget; | |
| struct tagDropTargetNode* nextDropTarget; | |
| } DropTargetNode; | |
| typedef struct tagTrackerWindowInfo | |
| { | |
| IDataObject* dataObject; | |
| IDropSource* dropSource; | |
| DWORD dwOKEffect; | |
| DWORD* pdwEffect; | |
| BOOL32 trackingDone; | |
| HRESULT returnValue; | |
| BOOL32 escPressed; | |
| HWND32 curDragTargetHWND; | |
| IDropTarget* curDragTarget; | |
| } TrackerWindowInfo; | |
| /* | |
| * This is the lock count on the OLE library. It is controlled by the | |
| * OLEInitialize/OLEUninitialize methods. | |
| */ | |
| static ULONG OLE_moduleLockCount = 0; | |
| /* | |
| * Name of our registered window class. | |
| */ | |
| static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32"; | |
| /* | |
| * This is the head of the Drop target container. | |
| */ | |
| static DropTargetNode* targetListHead = NULL; | |
| /****************************************************************************** | |
| * These are the prototypes of the utility methods used for OLE Drag n Drop | |
| */ | |
| static void OLEDD_Initialize(); | |
| static void OLEDD_UnInitialize(); | |
| static void OLEDD_InsertDropTarget( | |
| DropTargetNode* nodeToAdd); | |
| static DropTargetNode* OLEDD_ExtractDropTarget( | |
| HWND32 hwndOfTarget); | |
| static DropTargetNode* OLEDD_FindDropTarget( | |
| HWND32 hwndOfTarget); | |
| static LRESULT WINAPI OLEDD_DragTrackerWindowProc( | |
| HWND32 hwnd, | |
| UINT32 uMsg, | |
| WPARAM32 wParam, | |
| LPARAM lParam); | |
| static void OLEDD_TrackMouseMove( | |
| TrackerWindowInfo* trackerInfo, | |
| POINT32 mousePos, | |
| DWORD keyState); | |
| static void OLEDD_TrackStateChange( | |
| TrackerWindowInfo* trackerInfo, | |
| POINT32 mousePos, | |
| DWORD keyState); | |
| static DWORD OLEDD_GetButtonState(); | |
| /****************************************************************************** | |
| * OleBuildVersion [OLE2.1] | |
| */ | |
| DWORD WINAPI OleBuildVersion(void) | |
| { | |
| TRACE(ole,"(void)\n"); | |
| return (rmm<<16)+rup; | |
| } | |
| /*********************************************************************** | |
| * OleInitialize (OLE2.2) (OLE32.108) | |
| */ | |
| HRESULT WINAPI OleInitialize(LPVOID reserved) | |
| { | |
| HRESULT hr; | |
| TRACE(ole, "(%p)\n", reserved); | |
| /* | |
| * The first duty of the OleInitialize is to initialize the COM libraries. | |
| */ | |
| hr = CoInitializeEx32(NULL, COINIT_APARTMENTTHREADED); | |
| /* | |
| * If the CoInitializeEx call failed, the OLE libraries can't be | |
| * initialized. | |
| */ | |
| if (FAILED(hr)) | |
| return hr; | |
| /* | |
| * Then, it has to initialize the OLE specific modules. | |
| * This includes: | |
| * Clipboard | |
| * Drag and Drop | |
| * Object linking and Embedding | |
| * In-place activation | |
| */ | |
| if (OLE_moduleLockCount==0) | |
| { | |
| /* | |
| * Initialize the libraries. | |
| */ | |
| TRACE(ole, "() - Initializing the OLE libraries\n"); | |
| /* | |
| * Drag and Drop | |
| */ | |
| OLEDD_Initialize(); | |
| } | |
| /* | |
| * Then, we increase the lock count on the OLE module. | |
| */ | |
| OLE_moduleLockCount++; | |
| return hr; | |
| } | |
| /****************************************************************************** | |
| * CoGetCurrentProcess [COMPOBJ.34] [OLE2.2][OLE32.108] | |
| * | |
| * NOTES | |
| * Is DWORD really the correct return type for this function? | |
| */ | |
| DWORD WINAPI CoGetCurrentProcess(void) { | |
| return (DWORD)PROCESS_Current(); | |
| } | |
| /****************************************************************************** | |
| * OleUninitialize [OLE2.3] [OLE32.131] | |
| */ | |
| void WINAPI OleUninitialize(void) | |
| { | |
| TRACE(ole, "()\n"); | |
| /* | |
| * Decrease the lock count on the OLE module. | |
| */ | |
| OLE_moduleLockCount--; | |
| /* | |
| * If we hit the bottom of the lock stack, free the libraries. | |
| */ | |
| if (OLE_moduleLockCount==0) | |
| { | |
| /* | |
| * Actually free the libraries. | |
| */ | |
| TRACE(ole, "() - Freeing the last reference count\n"); | |
| /* | |
| * Drag and Drop | |
| */ | |
| OLEDD_UnInitialize(); | |
| } | |
| /* | |
| * Then, uninitialize the COM libraries. | |
| */ | |
| CoUninitialize32(); | |
| } | |
| /*********************************************************************** | |
| * OleFlushClipboard [OLE2.76] | |
| */ | |
| HRESULT WINAPI OleFlushClipboard(void) | |
| { | |
| return S_OK; | |
| } | |
| /*********************************************************************** | |
| * OleSetClipboard [OLE32.127] | |
| */ | |
| HRESULT WINAPI OleSetClipboard(LPVOID pDataObj) | |
| { | |
| FIXME(ole,"(%p), stub!\n", pDataObj); | |
| return S_OK; | |
| } | |
| /****************************************************************************** | |
| * CoRegisterMessageFilter32 [OLE32.38] | |
| */ | |
| HRESULT WINAPI CoRegisterMessageFilter32( | |
| LPMESSAGEFILTER lpMessageFilter, /* Pointer to interface */ | |
| LPMESSAGEFILTER *lplpMessageFilter /* Indirect pointer to prior instance if non-NULL */ | |
| ) { | |
| FIXME(ole,"stub\n"); | |
| if (lplpMessageFilter) { | |
| *lplpMessageFilter = NULL; | |
| } | |
| return S_OK; | |
| } | |
| /****************************************************************************** | |
| * OleInitializeWOW [OLE32.109] | |
| */ | |
| HRESULT WINAPI OleInitializeWOW(DWORD x) { | |
| FIXME(ole,"(0x%08lx),stub!\n",x); | |
| return 0; | |
| } | |
| /*********************************************************************** | |
| * RegisterDragDrop16 (OLE2.35) | |
| */ | |
| HRESULT WINAPI RegisterDragDrop16( | |
| HWND16 hwnd, | |
| LPDROPTARGET pDropTarget | |
| ) { | |
| FIXME(ole,"(0x%04x,%p),stub!\n",hwnd,pDropTarget); | |
| return S_OK; | |
| } | |
| /*********************************************************************** | |
| * RegisterDragDrop32 (OLE32.139) | |
| */ | |
| HRESULT WINAPI RegisterDragDrop32( | |
| HWND32 hwnd, | |
| LPDROPTARGET pDropTarget) | |
| { | |
| DropTargetNode* dropTargetInfo; | |
| TRACE(ole,"(0x%x,%p)\n", hwnd, pDropTarget); | |
| /* | |
| * First, check if the window is already registered. | |
| */ | |
| dropTargetInfo = OLEDD_FindDropTarget(hwnd); | |
| if (dropTargetInfo!=NULL) | |
| return DRAGDROP_E_ALREADYREGISTERED; | |
| /* | |
| * If it's not there, we can add it. We first create a node for it. | |
| */ | |
| dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode)); | |
| if (dropTargetInfo==NULL) | |
| return E_OUTOFMEMORY; | |
| dropTargetInfo->hwndTarget = hwnd; | |
| dropTargetInfo->prevDropTarget = NULL; | |
| dropTargetInfo->nextDropTarget = NULL; | |
| /* | |
| * Don't forget that this is an interface pointer, need to nail it down since | |
| * we keep a copy of it. | |
| */ | |
| dropTargetInfo->dropTarget = pDropTarget; | |
| IDropTarget_AddRef(dropTargetInfo->dropTarget); | |
| OLEDD_InsertDropTarget(dropTargetInfo); | |
| return S_OK; | |
| } | |
| /*********************************************************************** | |
| * RevokeDragDrop16 (OLE2.36) | |
| */ | |
| HRESULT WINAPI RevokeDragDrop16( | |
| HWND16 hwnd | |
| ) { | |
| FIXME(ole,"(0x%04x),stub!\n",hwnd); | |
| return S_OK; | |
| } | |
| /*********************************************************************** | |
| * RevokeDragDrop32 (OLE32.141) | |
| */ | |
| HRESULT WINAPI RevokeDragDrop32( | |
| HWND32 hwnd) | |
| { | |
| DropTargetNode* dropTargetInfo; | |
| TRACE(ole,"(0x%x)\n", hwnd); | |
| /* | |
| * First, check if the window is already registered. | |
| */ | |
| dropTargetInfo = OLEDD_ExtractDropTarget(hwnd); | |
| /* | |
| * If it ain't in there, it's an error. | |
| */ | |
| if (dropTargetInfo==NULL) | |
| return DRAGDROP_E_NOTREGISTERED; | |
| /* | |
| * If it's in there, clean-up it's used memory and | |
| * references | |
| */ | |
| IDropTarget_Release(dropTargetInfo->dropTarget); | |
| HeapFree(GetProcessHeap(), 0, dropTargetInfo); | |
| return S_OK; | |
| } | |
| /*********************************************************************** | |
| * OleRegGetUserType (OLE32.122) | |
| */ | |
| HRESULT WINAPI OleRegGetUserType32( | |
| REFCLSID clsid, | |
| DWORD dwFormOfType, | |
| LPOLESTR32* pszUserType) | |
| { | |
| FIXME(ole,",stub!\n"); | |
| return S_OK; | |
| } | |
| /*********************************************************************** | |
| * DoDragDrop32 [OLE32.65] | |
| */ | |
| HRESULT WINAPI DoDragDrop32 ( | |
| IDataObject *pDataObject, /* ptr to the data obj */ | |
| IDropSource* pDropSource, /* ptr to the source obj */ | |
| DWORD dwOKEffect, /* effects allowed by the source */ | |
| DWORD *pdwEffect) /* ptr to effects of the source */ | |
| { | |
| TrackerWindowInfo trackerInfo; | |
| HWND32 hwndTrackWindow; | |
| MSG32 msg; | |
| TRACE(ole,"(DataObject %p, DropSource %p)\n", pDataObject, pDropSource); | |
| /* | |
| * Setup the drag n drop tracking window. | |
| */ | |
| trackerInfo.dataObject = pDataObject; | |
| trackerInfo.dropSource = pDropSource; | |
| trackerInfo.dwOKEffect = dwOKEffect; | |
| trackerInfo.pdwEffect = pdwEffect; | |
| trackerInfo.trackingDone = FALSE; | |
| trackerInfo.escPressed = FALSE; | |
| trackerInfo.curDragTargetHWND = 0; | |
| trackerInfo.curDragTarget = 0; | |
| hwndTrackWindow = CreateWindow32A(OLEDD_DRAGTRACKERCLASS, | |
| "TrackerWindow", | |
| WS_POPUP, | |
| CW_USEDEFAULT32, CW_USEDEFAULT32, | |
| CW_USEDEFAULT32, CW_USEDEFAULT32, | |
| 0, | |
| 0, | |
| 0, | |
| (LPVOID)&trackerInfo); | |
| if (hwndTrackWindow!=0) | |
| { | |
| /* | |
| * Capture the mouse input | |
| */ | |
| SetCapture32(hwndTrackWindow); | |
| /* | |
| * Pump messages. All mouse input should go the the capture window. | |
| */ | |
| while (!trackerInfo.trackingDone && GetMessage32A(&msg, 0, 0, 0) ) | |
| { | |
| if ( (msg.message >= WM_KEYFIRST) && | |
| (msg.message <= WM_KEYFIRST) ) | |
| { | |
| /* | |
| * When keyboard messages are sent to windows on this thread, we | |
| * want to ignore notify the drop source that the state changed. | |
| * in the case of the Escape key, we also notify the drop source | |
| * we give it a special meaning. | |
| */ | |
| if ( (msg.message==WM_KEYDOWN) && | |
| (msg.wParam==VK_ESCAPE) ) | |
| { | |
| trackerInfo.escPressed = TRUE; | |
| } | |
| /* | |
| * Notify the drop source. | |
| */ | |
| OLEDD_TrackStateChange(&trackerInfo, | |
| msg.pt, | |
| OLEDD_GetButtonState()); | |
| } | |
| else | |
| { | |
| /* | |
| * Dispatch the messages only when it's not a keyboard message. | |
| */ | |
| DispatchMessage32A(&msg); | |
| } | |
| } | |
| /* | |
| * Destroy the temporary window. | |
| */ | |
| DestroyWindow32(hwndTrackWindow); | |
| return trackerInfo.returnValue; | |
| } | |
| return E_FAIL; | |
| } | |
| /*********************************************************************** | |
| * OleQueryLinkFromData32 [OLE32.118] | |
| */ | |
| HRESULT WINAPI OleQueryLinkFromData32( | |
| IDataObject* pSrcDataObject) | |
| { | |
| FIXME(ole,"(%p),stub!\n", pSrcDataObject); | |
| return S_OK; | |
| } | |
| /*********************************************************************** | |
| * OleRegGetMiscStatus32 [OLE32.121] | |
| */ | |
| HRESULT WINAPI OleRegGetMiscStatus32( | |
| REFCLSID clsid, | |
| DWORD dwAspect, | |
| DWORD* pdwStatus) | |
| { | |
| FIXME(ole,"(),stub!\n"); | |
| return REGDB_E_CLASSNOTREG; | |
| } | |
| /*********************************************************************** | |
| * OleGetClipboard32 [OLE32.105] | |
| */ | |
| HRESULT WINAPI OleGetClipboard32( | |
| IDataObject** ppDataObj) | |
| { | |
| FIXME(ole,"(%p),stub!\n", ppDataObj); | |
| if (ppDataObj) | |
| *ppDataObj=0; | |
| return E_FAIL; | |
| } | |
| /*** | |
| * OLEDD_Initialize() | |
| * | |
| * Initializes the OLE drag and drop data structures. | |
| */ | |
| static void OLEDD_Initialize() | |
| { | |
| WNDCLASS32A wndClass; | |
| ZeroMemory (&wndClass, sizeof(WNDCLASS32A)); | |
| wndClass.style = CS_GLOBALCLASS; | |
| wndClass.lpfnWndProc = (WNDPROC32)OLEDD_DragTrackerWindowProc; | |
| wndClass.cbClsExtra = 0; | |
| wndClass.cbWndExtra = sizeof(TrackerWindowInfo*); | |
| wndClass.hCursor = 0; | |
| wndClass.hbrBackground = 0; | |
| wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS; | |
| RegisterClass32A (&wndClass); | |
| } | |
| /*** | |
| * OLEDD_UnInitialize() | |
| * | |
| * Releases the OLE drag and drop data structures. | |
| */ | |
| static void OLEDD_UnInitialize() | |
| { | |
| /* | |
| * Simply empty the list. | |
| */ | |
| while (targetListHead!=NULL) | |
| { | |
| RevokeDragDrop32(targetListHead->hwndTarget); | |
| } | |
| } | |
| /*** | |
| * OLEDD_InsertDropTarget() | |
| * | |
| * Insert the target node in the tree. | |
| */ | |
| static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd) | |
| { | |
| DropTargetNode* curNode; | |
| DropTargetNode** parentNodeLink; | |
| /* | |
| * Iterate the tree to find the insertion point. | |
| */ | |
| curNode = targetListHead; | |
| parentNodeLink = &targetListHead; | |
| while (curNode!=NULL) | |
| { | |
| if (nodeToAdd->hwndTarget<curNode->hwndTarget) | |
| { | |
| /* | |
| * If the node we want to add has a smaller HWND, go left | |
| */ | |
| parentNodeLink = &curNode->prevDropTarget; | |
| curNode = curNode->prevDropTarget; | |
| } | |
| else if (nodeToAdd->hwndTarget>curNode->hwndTarget) | |
| { | |
| /* | |
| * If the node we want to add has a larger HWND, go right | |
| */ | |
| parentNodeLink = &curNode->nextDropTarget; | |
| curNode = curNode->nextDropTarget; | |
| } | |
| else | |
| { | |
| /* | |
| * The item was found in the list. It shouldn't have been there | |
| */ | |
| assert(FALSE); | |
| return; | |
| } | |
| } | |
| /* | |
| * If we get here, we have found a spot for our item. The parentNodeLink | |
| * pointer points to the pointer that we have to modify. | |
| * The curNode should be NULL. We just have to establish the link and Voila! | |
| */ | |
| assert(curNode==NULL); | |
| assert(parentNodeLink!=NULL); | |
| assert(*parentNodeLink==NULL); | |
| *parentNodeLink=nodeToAdd; | |
| } | |
| /*** | |
| * OLEDD_ExtractDropTarget() | |
| * | |
| * Removes the target node from the tree. | |
| */ | |
| static DropTargetNode* OLEDD_ExtractDropTarget(HWND32 hwndOfTarget) | |
| { | |
| DropTargetNode* curNode; | |
| DropTargetNode** parentNodeLink; | |
| /* | |
| * Iterate the tree to find the insertion point. | |
| */ | |
| curNode = targetListHead; | |
| parentNodeLink = &targetListHead; | |
| while (curNode!=NULL) | |
| { | |
| if (hwndOfTarget<curNode->hwndTarget) | |
| { | |
| /* | |
| * If the node we want to add has a smaller HWND, go left | |
| */ | |
| parentNodeLink = &curNode->prevDropTarget; | |
| curNode = curNode->prevDropTarget; | |
| } | |
| else if (hwndOfTarget>curNode->hwndTarget) | |
| { | |
| /* | |
| * If the node we want to add has a larger HWND, go right | |
| */ | |
| parentNodeLink = &curNode->nextDropTarget; | |
| curNode = curNode->nextDropTarget; | |
| } | |
| else | |
| { | |
| /* | |
| * The item was found in the list. Detach it from it's parent and | |
| * re-insert it's kids in the tree. | |
| */ | |
| assert(parentNodeLink!=NULL); | |
| assert(*parentNodeLink==curNode); | |
| /* | |
| * We arbitrately re-attach the left sub-tree to the parent. | |
| */ | |
| *parentNodeLink = curNode->prevDropTarget; | |
| /* | |
| * And we re-insert the right subtree | |
| */ | |
| if (curNode->nextDropTarget!=NULL) | |
| { | |
| OLEDD_InsertDropTarget(curNode->nextDropTarget); | |
| } | |
| /* | |
| * The node we found is still a valid node once we complete | |
| * the unlinking of the kids. | |
| */ | |
| curNode->nextDropTarget=NULL; | |
| curNode->prevDropTarget=NULL; | |
| return curNode; | |
| } | |
| } | |
| /* | |
| * If we get here, the node is not in the tree | |
| */ | |
| return NULL; | |
| } | |
| /*** | |
| * OLEDD_FindDropTarget() | |
| * | |
| * Finds information about the drop target. | |
| */ | |
| static DropTargetNode* OLEDD_FindDropTarget(HWND32 hwndOfTarget) | |
| { | |
| DropTargetNode* curNode; | |
| /* | |
| * Iterate the tree to find the HWND value. | |
| */ | |
| curNode = targetListHead; | |
| while (curNode!=NULL) | |
| { | |
| if (hwndOfTarget<curNode->hwndTarget) | |
| { | |
| /* | |
| * If the node we want to add has a smaller HWND, go left | |
| */ | |
| curNode = curNode->prevDropTarget; | |
| } | |
| else if (hwndOfTarget>curNode->hwndTarget) | |
| { | |
| /* | |
| * If the node we want to add has a larger HWND, go right | |
| */ | |
| curNode = curNode->nextDropTarget; | |
| } | |
| else | |
| { | |
| /* | |
| * The item was found in the list. | |
| */ | |
| return curNode; | |
| } | |
| } | |
| /* | |
| * If we get here, the item is not in the list | |
| */ | |
| return NULL; | |
| } | |
| /*** | |
| * OLEDD_DragTrackerWindowProc() | |
| * | |
| * This method is the WindowProcedure of the drag n drop tracking | |
| * window. During a drag n Drop operation, an invisible window is created | |
| * to receive the user input and act upon it. This procedure is in charge | |
| * of this behavior. | |
| */ | |
| static LRESULT WINAPI OLEDD_DragTrackerWindowProc( | |
| HWND32 hwnd, | |
| UINT32 uMsg, | |
| WPARAM32 wParam, | |
| LPARAM lParam) | |
| { | |
| switch (uMsg) | |
| { | |
| case WM_CREATE: | |
| { | |
| LPCREATESTRUCT32A createStruct = (LPCREATESTRUCT32A)lParam; | |
| SetWindowLong32A(hwnd, 0, (LONG)createStruct->lpCreateParams); | |
| break; | |
| } | |
| case WM_MOUSEMOVE: | |
| { | |
| TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLong32A(hwnd, 0); | |
| POINT32 mousePos; | |
| /* | |
| * Get the current mouse position in screen coordinates. | |
| */ | |
| mousePos.x = LOWORD(lParam); | |
| mousePos.y = HIWORD(lParam); | |
| ClientToScreen32(hwnd, &mousePos); | |
| /* | |
| * Track the movement of the mouse. | |
| */ | |
| OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam); | |
| break; | |
| } | |
| case WM_LBUTTONUP: | |
| case WM_MBUTTONUP: | |
| case WM_RBUTTONUP: | |
| case WM_LBUTTONDOWN: | |
| case WM_MBUTTONDOWN: | |
| case WM_RBUTTONDOWN: | |
| { | |
| TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLong32A(hwnd, 0); | |
| POINT32 mousePos; | |
| /* | |
| * Get the current mouse position in screen coordinates. | |
| */ | |
| mousePos.x = LOWORD(lParam); | |
| mousePos.y = HIWORD(lParam); | |
| ClientToScreen32(hwnd, &mousePos); | |
| /* | |
| * Notify everyone that the button state changed | |
| * TODO: Check if the "escape" key was pressed. | |
| */ | |
| OLEDD_TrackStateChange(trackerInfo, mousePos, wParam); | |
| break; | |
| } | |
| } | |
| /* | |
| * This is a window proc after all. Let's call the default. | |
| */ | |
| return DefWindowProc32A (hwnd, uMsg, wParam, lParam); | |
| } | |
| /*** | |
| * OLEDD_TrackMouseMove() | |
| * | |
| * This method is invoked while a drag and drop operation is in effect. | |
| * it will generate the appropriate callbacks in the drop source | |
| * and drop target. It will also provide the expected feedback to | |
| * the user. | |
| * | |
| * params: | |
| * trackerInfo - Pointer to the structure identifying the | |
| * drag & drop operation that is currently | |
| * active. | |
| * mousePos - Current position of the mouse in screen | |
| * coordinates. | |
| * keyState - Contains the state of the shift keys and the | |
| * mouse buttons (MK_LBUTTON and the like) | |
| */ | |
| static void OLEDD_TrackMouseMove( | |
| TrackerWindowInfo* trackerInfo, | |
| POINT32 mousePos, | |
| DWORD keyState) | |
| { | |
| HWND32 hwndNewTarget = 0; | |
| HRESULT hr = S_OK; | |
| /* | |
| * Get the handle of the window under the mouse | |
| */ | |
| hwndNewTarget = WindowFromPoint32(mousePos); | |
| /* | |
| * If we are hovering over the same target as before, send the | |
| * DragOver notification | |
| */ | |
| if ( (trackerInfo->curDragTarget != 0) && | |
| (trackerInfo->curDragTargetHWND==hwndNewTarget) ) | |
| { | |
| POINTL mousePosParam; | |
| /* | |
| * The documentation tells me that the coordinate should be in the target | |
| * window's coordinate space. However, the tests I made tell me the | |
| * coordinates should be in screen coordinates. | |
| */ | |
| mousePosParam.x = mousePos.x; | |
| mousePosParam.y = mousePos.y; | |
| IDropTarget_DragOver(trackerInfo->curDragTarget, | |
| keyState, | |
| mousePosParam, | |
| trackerInfo->pdwEffect); | |
| } | |
| else | |
| { | |
| DropTargetNode* newDropTargetNode = 0; | |
| /* | |
| * If we changed window, we have to notify our old target and check for | |
| * the new one. | |
| */ | |
| if (trackerInfo->curDragTarget!=0) | |
| { | |
| IDropTarget_DragLeave(trackerInfo->curDragTarget); | |
| } | |
| /* | |
| * Make sure we're hovering over a window. | |
| */ | |
| if (hwndNewTarget!=0) | |
| { | |
| /* | |
| * Find-out if there is a drag target under the mouse | |
| */ | |
| newDropTargetNode = OLEDD_FindDropTarget(hwndNewTarget); | |
| trackerInfo->curDragTargetHWND = hwndNewTarget; | |
| trackerInfo->curDragTarget = newDropTargetNode ? newDropTargetNode->dropTarget : 0; | |
| /* | |
| * If there is, notify it that we just dragged-in | |
| */ | |
| if (trackerInfo->curDragTarget!=0) | |
| { | |
| POINTL mousePosParam; | |
| /* | |
| * The documentation tells me that the coordinate should be in the target | |
| * window's coordinate space. However, the tests I made tell me the | |
| * coordinates should be in screen coordinates. | |
| */ | |
| mousePosParam.x = mousePos.x; | |
| mousePosParam.y = mousePos.y; | |
| IDropTarget_DragEnter(trackerInfo->curDragTarget, | |
| trackerInfo->dataObject, | |
| keyState, | |
| mousePosParam, | |
| trackerInfo->pdwEffect); | |
| } | |
| } | |
| else | |
| { | |
| /* | |
| * The mouse is not over a window so we don't track anything. | |
| */ | |
| trackerInfo->curDragTargetHWND = 0; | |
| trackerInfo->curDragTarget = 0; | |
| } | |
| } | |
| /* | |
| * Now that we have done that, we have to tell the source to give | |
| * us feedback on the work being done by the target. If we don't | |
| * have a target, simulate no effect. | |
| */ | |
| if (trackerInfo->curDragTarget==0) | |
| { | |
| *trackerInfo->pdwEffect = DROPEFFECT_NONE; | |
| } | |
| hr = IDropSource_GiveFeedback(trackerInfo->dropSource, | |
| *trackerInfo->pdwEffect); | |
| /* | |
| * When we ask for feedback from the drop source, sometimes it will | |
| * do all the necessary work and sometimes it will not handle it | |
| * when that's the case, we must display the standard drag and drop | |
| * cursors. | |
| */ | |
| if (hr==DRAGDROP_S_USEDEFAULTCURSORS) | |
| { | |
| if ( (*trackerInfo->pdwEffect & DROPEFFECT_MOVE) || | |
| (*trackerInfo->pdwEffect & DROPEFFECT_COPY) || | |
| (*trackerInfo->pdwEffect & DROPEFFECT_LINK) ) | |
| { | |
| SetCursor32(LoadCursor32A(0, IDC_SIZEALL32A)); | |
| } | |
| else | |
| { | |
| SetCursor32(LoadCursor32A(0, IDC_NO32A)); | |
| } | |
| } | |
| } | |
| /*** | |
| * OLEDD_TrackStateChange() | |
| * | |
| * This method is invoked while a drag and drop operation is in effect. | |
| * It is used to notify the drop target/drop source callbacks when | |
| * the state of the keyboard or mouse button change. | |
| * | |
| * params: | |
| * trackerInfo - Pointer to the structure identifying the | |
| * drag & drop operation that is currently | |
| * active. | |
| * mousePos - Current position of the mouse in screen | |
| * coordinates. | |
| * keyState - Contains the state of the shift keys and the | |
| * mouse buttons (MK_LBUTTON and the like) | |
| */ | |
| static void OLEDD_TrackStateChange( | |
| TrackerWindowInfo* trackerInfo, | |
| POINT32 mousePos, | |
| DWORD keyState) | |
| { | |
| /* | |
| * Ask the drop source what to do with the operation. | |
| */ | |
| trackerInfo->returnValue = IDropSource_QueryContinueDrag( | |
| trackerInfo->dropSource, | |
| trackerInfo->escPressed, | |
| keyState); | |
| /* | |
| * All the return valued will stop the operation except the S_OK | |
| * return value. | |
| */ | |
| if (trackerInfo->returnValue!=S_OK) | |
| { | |
| /* | |
| * Make sure the message loop in DoDragDrop stops | |
| */ | |
| trackerInfo->trackingDone = TRUE; | |
| /* | |
| * Release the mouse in case the drop target decides to show a popup | |
| * or a menu or something. | |
| */ | |
| ReleaseCapture(); | |
| /* | |
| * If we end-up over a target, drop the object in the target or | |
| * inform the target that the operation was cancelled. | |
| */ | |
| if (trackerInfo->curDragTarget!=0) | |
| { | |
| switch (trackerInfo->returnValue) | |
| { | |
| /* | |
| * If the source wants us to complete the operation, we tell | |
| * the drop target that we just dropped the object in it. | |
| */ | |
| case DRAGDROP_S_DROP: | |
| { | |
| POINTL mousePosParam; | |
| /* | |
| * The documentation tells me that the coordinate should be | |
| * in the target window's coordinate space. However, the tests | |
| * I made tell me the coordinates should be in screen coordinates. | |
| */ | |
| mousePosParam.x = mousePos.x; | |
| mousePosParam.y = mousePos.y; | |
| IDropTarget_Drop(trackerInfo->curDragTarget, | |
| trackerInfo->dataObject, | |
| keyState, | |
| mousePosParam, | |
| trackerInfo->pdwEffect); | |
| break; | |
| } | |
| /* | |
| * If the source told us that we should cancel, fool the drop | |
| * target by telling it that the mouse left it's window. | |
| */ | |
| case DRAGDROP_S_CANCEL: | |
| IDropTarget_DragLeave(trackerInfo->curDragTarget); | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| /*** | |
| * OLEDD_GetButtonState() | |
| * | |
| * This method will use the current state of the keyboard to build | |
| * a button state mask equivalent to the one passed in the | |
| * WM_MOUSEMOVE wParam. | |
| */ | |
| static DWORD OLEDD_GetButtonState() | |
| { | |
| BYTE keyboardState[256]; | |
| DWORD keyMask = 0; | |
| GetKeyboardState(keyboardState); | |
| if ( (keyboardState[VK_SHIFT] & 0x80) !=0) | |
| keyMask |= MK_SHIFT; | |
| if ( (keyboardState[VK_CONTROL] & 0x80) !=0) | |
| keyMask |= MK_CONTROL; | |
| if ( (keyboardState[VK_LBUTTON] & 0x80) !=0) | |
| keyMask |= MK_LBUTTON; | |
| if ( (keyboardState[VK_RBUTTON] & 0x80) !=0) | |
| keyMask |= MK_RBUTTON; | |
| if ( (keyboardState[VK_MBUTTON] & 0x80) !=0) | |
| keyMask |= MK_MBUTTON; | |
| return keyMask; | |
| } | |