Implemented the OLE Drag and Drop target registration mechanism and
[wine] / ole / ole2.c
1 /*
2  *      OLE2 library
3  *
4  *      Copyright 1995  Martin von Loewis
5  *      Copyright 1999  Francis Beaudet
6  */
7
8 #include <assert.h>
9
10 #include "windows.h"
11 #include "winerror.h"
12 #include "ole2.h"
13 #include "process.h"
14 #include "debug.h"
15 #include "objbase.h"
16 #include "objidl.h"
17 #include "wine/obj_base.h"
18 #include "wine/obj_clientserver.h"
19 #include "wine/obj_storage.h"
20 #include "wine/obj_moniker.h"
21
22 /******************************************************************************
23  * These are static/global variables and internal data structures that the 
24  * OLE module uses to maintain it's state.
25  */
26 typedef struct tagDropTargetNode
27 {
28   HWND32          hwndTarget;
29   IDropTarget*    dropTarget;
30   struct tagDropTargetNode* prevDropTarget;
31   struct tagDropTargetNode* nextDropTarget;
32 } DropTargetNode;
33
34 typedef struct tagTrackerWindowInfo
35 {
36   IDataObject* dataObject;
37   IDropSource* dropSource;
38   DWORD        dwOKEffect;
39   DWORD*       pdwEffect;
40   BOOL32       trackingDone;
41   HRESULT      returnValue;
42
43   BOOL32       escPressed;
44   HWND32       curDragTargetHWND;
45   IDropTarget* curDragTarget;
46 } TrackerWindowInfo;
47
48 /*
49  * This is the lock count on the OLE library. It is controlled by the
50  * OLEInitialize/OLEUninitialize methods.
51  */
52 static ULONG OLE_moduleLockCount = 0;
53
54 /*
55  * Name of our registered window class.
56  */
57 static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";
58
59 /*
60  * This is the head of the Drop target container.
61  */
62 static DropTargetNode* targetListHead = NULL;
63
64 /******************************************************************************
65  * These are the prototypes of the utility methods used for OLE Drag n Drop
66  */
67 static void            OLEDD_Initialize();
68 static void            OLEDD_UnInitialize();
69 static void            OLEDD_InsertDropTarget(
70                          DropTargetNode* nodeToAdd);
71 static DropTargetNode* OLEDD_ExtractDropTarget(
72                          HWND32 hwndOfTarget);
73 static DropTargetNode* OLEDD_FindDropTarget(
74                          HWND32 hwndOfTarget);
75 static LRESULT WINAPI  OLEDD_DragTrackerWindowProc(
76                          HWND32   hwnd, 
77                          UINT32   uMsg,
78                          WPARAM32 wParam, 
79                          LPARAM   lParam);
80 static void OLEDD_TrackMouseMove(
81                          TrackerWindowInfo* trackerInfo,
82                          POINT32            mousePos,
83                          DWORD              keyState);
84 static void OLEDD_TrackStateChange(
85                          TrackerWindowInfo* trackerInfo,
86                          POINT32            mousePos,
87                          DWORD              keyState);
88 static DWORD OLEDD_GetButtonState();
89
90
91 /******************************************************************************
92  *              OleBuildVersion [OLE2.1]
93  */
94 DWORD WINAPI OleBuildVersion(void)
95 {
96     TRACE(ole,"(void)\n");
97     return (rmm<<16)+rup;
98 }
99
100 /***********************************************************************
101  *           OleInitialize       (OLE2.2) (OLE32.108)
102  */
103 HRESULT WINAPI OleInitialize(LPVOID reserved)
104 {
105   HRESULT hr;
106
107   TRACE(ole, "(%p)\n", reserved);
108
109   /*
110    * The first duty of the OleInitialize is to initialize the COM libraries.
111    */
112   hr = CoInitializeEx32(NULL, COINIT_APARTMENTTHREADED);
113
114   /*
115    * If the CoInitializeEx call failed, the OLE libraries can't be 
116    * initialized.
117    */
118   if (FAILED(hr))
119     return hr;    
120
121   /*
122    * Then, it has to initialize the OLE specific modules.
123    * This includes:
124    *     Clipboard
125    *     Drag and Drop
126    *     Object linking and Embedding
127    *     In-place activation
128    */
129   if (OLE_moduleLockCount==0)
130 {
131     /* 
132      * Initialize the libraries.
133      */
134     TRACE(ole, "() - Initializing the OLE libraries\n");
135
136     /*
137      * Drag and Drop
138      */
139     OLEDD_Initialize();
140 }
141
142   /*
143    * Then, we increase the lock count on the OLE module.
144    */
145   OLE_moduleLockCount++;  
146
147   return hr;
148 }
149
150 /******************************************************************************
151  *              CoGetCurrentProcess     [COMPOBJ.34] [OLE2.2][OLE32.108]
152  *
153  * NOTES
154  *   Is DWORD really the correct return type for this function?
155  */
156 DWORD WINAPI CoGetCurrentProcess(void) {
157         return (DWORD)PROCESS_Current();
158 }
159
160 /******************************************************************************
161  *              OleUninitialize [OLE2.3] [OLE32.131]
162  */
163 void WINAPI OleUninitialize(void)
164 {
165   TRACE(ole, "()\n");
166
167   /*
168    * Decrease the lock count on the OLE module.
169    */
170   OLE_moduleLockCount--;
171
172   /*
173    * If we hit the bottom of the lock stack, free the libraries.
174    */
175   if (OLE_moduleLockCount==0)
176   {
177     /*
178      * Actually free the libraries.
179      */
180     TRACE(ole, "() - Freeing the last reference count\n");
181
182     /*
183      * Drag and Drop
184      */
185     OLEDD_UnInitialize();
186   }
187   
188   /*
189    * Then, uninitialize the COM libraries.
190    */
191   CoUninitialize32();
192 }
193
194 /***********************************************************************
195  *           OleFlushClipboard   [OLE2.76]
196  */
197 HRESULT WINAPI OleFlushClipboard(void)
198 {
199     return S_OK;
200 }
201
202 /***********************************************************************
203  *           OleSetClipboard     [OLE32.127]
204  */
205 HRESULT WINAPI OleSetClipboard(LPVOID pDataObj)
206 {
207     FIXME(ole,"(%p), stub!\n", pDataObj);
208     return S_OK;
209 }
210
211 /******************************************************************************
212  *              CoRegisterMessageFilter32       [OLE32.38]
213  */
214 HRESULT WINAPI CoRegisterMessageFilter32(
215     LPMESSAGEFILTER lpMessageFilter,    /* Pointer to interface */
216     LPMESSAGEFILTER *lplpMessageFilter  /* Indirect pointer to prior instance if non-NULL */
217 ) {
218     FIXME(ole,"stub\n");
219     if (lplpMessageFilter) {
220         *lplpMessageFilter = NULL;
221     }
222     return S_OK;
223 }
224
225 /******************************************************************************
226  *              OleInitializeWOW        [OLE32.109]
227  */
228 HRESULT WINAPI OleInitializeWOW(DWORD x) {
229         FIXME(ole,"(0x%08lx),stub!\n",x);
230         return 0;
231 }
232
233 /***********************************************************************
234  *           RegisterDragDrop16 (OLE2.35)
235  */
236 HRESULT WINAPI RegisterDragDrop16(
237         HWND16 hwnd,
238         LPDROPTARGET pDropTarget
239 ) {
240         FIXME(ole,"(0x%04x,%p),stub!\n",hwnd,pDropTarget);
241         return S_OK;
242 }
243
244 /***********************************************************************
245  *           RegisterDragDrop32 (OLE32.139)
246  */
247 HRESULT WINAPI RegisterDragDrop32(
248         HWND32 hwnd,
249         LPDROPTARGET pDropTarget) 
250 {
251   DropTargetNode* dropTargetInfo;
252
253   TRACE(ole,"(0x%x,%p)\n", hwnd, pDropTarget);
254
255   /*
256    * First, check if the window is already registered.
257    */
258   dropTargetInfo = OLEDD_FindDropTarget(hwnd);
259
260   if (dropTargetInfo!=NULL)
261     return DRAGDROP_E_ALREADYREGISTERED;
262
263   /*
264    * If it's not there, we can add it. We first create a node for it.
265    */
266   dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));
267
268   if (dropTargetInfo==NULL)
269     return E_OUTOFMEMORY;
270
271   dropTargetInfo->hwndTarget     = hwnd;
272   dropTargetInfo->prevDropTarget = NULL;
273   dropTargetInfo->nextDropTarget = NULL;
274
275   /*
276    * Don't forget that this is an interface pointer, need to nail it down since
277    * we keep a copy of it.
278    */
279   dropTargetInfo->dropTarget  = pDropTarget;
280   IDropTarget_AddRef(dropTargetInfo->dropTarget);
281   
282   OLEDD_InsertDropTarget(dropTargetInfo);
283
284         return S_OK;
285 }
286
287 /***********************************************************************
288  *           RevokeDragDrop16 (OLE2.36)
289  */
290 HRESULT WINAPI RevokeDragDrop16(
291         HWND16 hwnd
292 ) {
293         FIXME(ole,"(0x%04x),stub!\n",hwnd);
294         return S_OK;
295 }
296
297 /***********************************************************************
298  *           RevokeDragDrop32 (OLE32.141)
299  */
300 HRESULT WINAPI RevokeDragDrop32(
301         HWND32 hwnd)
302 {
303   DropTargetNode* dropTargetInfo;
304
305   TRACE(ole,"(0x%x)\n", hwnd);
306
307   /*
308    * First, check if the window is already registered.
309    */
310   dropTargetInfo = OLEDD_ExtractDropTarget(hwnd);
311
312   /*
313    * If it ain't in there, it's an error.
314    */
315   if (dropTargetInfo==NULL)
316     return DRAGDROP_E_NOTREGISTERED;
317
318   /*
319    * If it's in there, clean-up it's used memory and
320    * references
321    */
322   IDropTarget_Release(dropTargetInfo->dropTarget);
323   HeapFree(GetProcessHeap(), 0, dropTargetInfo);  
324
325         return S_OK;
326 }
327
328 /***********************************************************************
329  *           OleRegGetUserType (OLE32.122)
330  */
331 HRESULT WINAPI OleRegGetUserType32( 
332         REFCLSID clsid, 
333         DWORD dwFormOfType,
334         LPOLESTR32* pszUserType)
335 {
336         FIXME(ole,",stub!\n");
337         return S_OK;
338 }
339
340 /***********************************************************************
341  * DoDragDrop32 [OLE32.65]
342  */
343 HRESULT WINAPI DoDragDrop32 (
344   IDataObject *pDataObject,  /* ptr to the data obj           */
345   IDropSource* pDropSource,  /* ptr to the source obj         */
346   DWORD       dwOKEffect,    /* effects allowed by the source */
347   DWORD       *pdwEffect)    /* ptr to effects of the source  */
348 {
349   TrackerWindowInfo trackerInfo;
350   HWND32            hwndTrackWindow;
351   MSG32             msg;
352
353   TRACE(ole,"(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
354
355   /*
356    * Setup the drag n drop tracking window.
357    */
358   trackerInfo.dataObject        = pDataObject;
359   trackerInfo.dropSource        = pDropSource;
360   trackerInfo.dwOKEffect        = dwOKEffect;
361   trackerInfo.pdwEffect         = pdwEffect;
362   trackerInfo.trackingDone      = FALSE;
363   trackerInfo.escPressed        = FALSE;
364   trackerInfo.curDragTargetHWND = 0;
365   trackerInfo.curDragTarget     = 0;
366
367   hwndTrackWindow = CreateWindow32A(OLEDD_DRAGTRACKERCLASS,
368                                     "TrackerWindow",
369                                     WS_POPUP,
370                                     CW_USEDEFAULT32, CW_USEDEFAULT32,
371                                     CW_USEDEFAULT32, CW_USEDEFAULT32,
372                                     0,
373                                     0,
374                                     0,
375                                     (LPVOID)&trackerInfo);
376
377   if (hwndTrackWindow!=0)
378   {
379     /*
380      * Capture the mouse input
381      */
382     SetCapture32(hwndTrackWindow);
383
384     /*
385      * Pump messages. All mouse input should go the the capture window.
386      */
387     while (!trackerInfo.trackingDone && GetMessage32A(&msg, 0, 0, 0) )
388     {
389       if ( (msg.message >= WM_KEYFIRST) && 
390            (msg.message <= WM_KEYFIRST) )
391       {
392         /*
393          * When keyboard messages are sent to windows on this thread, we
394          * want to ignore notify the drop source that the state changed.
395          * in the case of the Escape key, we also notify the drop source
396          * we give it a special meaning.
397          */
398         if ( (msg.message==WM_KEYDOWN) &&
399              (msg.wParam==VK_ESCAPE) )
400         {
401           trackerInfo.escPressed = TRUE;
402         }
403
404         /*
405          * Notify the drop source.
406          */       
407         OLEDD_TrackStateChange(&trackerInfo,
408                                msg.pt,
409                                OLEDD_GetButtonState());
410       }
411       else
412       {
413         /*
414          * Dispatch the messages only when it's not a keyboard message.
415          */
416         DispatchMessage32A(&msg);
417       }
418     }
419
420     /*
421      * Destroy the temporary window.
422      */
423     DestroyWindow32(hwndTrackWindow);
424
425     return trackerInfo.returnValue;
426   }
427
428   return E_FAIL;
429 }
430
431 /***********************************************************************
432  * OleQueryLinkFromData32 [OLE32.118]
433  */
434 HRESULT WINAPI OleQueryLinkFromData32(
435   IDataObject* pSrcDataObject)
436 {
437   FIXME(ole,"(%p),stub!\n", pSrcDataObject);
438   return S_OK;
439 }
440
441 /***********************************************************************
442  * OleRegGetMiscStatus32 [OLE32.121]
443  */
444 HRESULT WINAPI OleRegGetMiscStatus32(
445   REFCLSID clsid,
446   DWORD    dwAspect,
447   DWORD*   pdwStatus)
448 {
449   FIXME(ole,"(),stub!\n");
450   return REGDB_E_CLASSNOTREG;
451 }
452
453 /***********************************************************************
454  * OleGetClipboard32 [OLE32.105]
455  */
456 HRESULT WINAPI OleGetClipboard32(
457   IDataObject** ppDataObj)
458 {
459   FIXME(ole,"(%p),stub!\n", ppDataObj);
460
461   if (ppDataObj)
462     *ppDataObj=0;
463
464   return E_FAIL;
465 }
466
467 /***
468  * OLEDD_Initialize()
469  *
470  * Initializes the OLE drag and drop data structures.
471  */
472 static void OLEDD_Initialize()
473 {
474     WNDCLASS32A wndClass;
475
476     ZeroMemory (&wndClass, sizeof(WNDCLASS32A));
477     wndClass.style         = CS_GLOBALCLASS;
478     wndClass.lpfnWndProc   = (WNDPROC32)OLEDD_DragTrackerWindowProc;
479     wndClass.cbClsExtra    = 0;
480     wndClass.cbWndExtra    = sizeof(TrackerWindowInfo*);
481     wndClass.hCursor       = 0;
482     wndClass.hbrBackground = 0;
483     wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
484  
485     RegisterClass32A (&wndClass);
486 }
487
488 /***
489  * OLEDD_UnInitialize()
490  *
491  * Releases the OLE drag and drop data structures.
492  */
493 static void OLEDD_UnInitialize()
494 {
495   /*
496    * Simply empty the list.
497    */
498   while (targetListHead!=NULL)
499   {
500     RevokeDragDrop32(targetListHead->hwndTarget);
501   }
502 }
503
504 /***
505  * OLEDD_InsertDropTarget()
506  *
507  * Insert the target node in the tree.
508  */
509 static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd)
510 {
511   DropTargetNode*  curNode;
512   DropTargetNode** parentNodeLink;
513
514   /*
515    * Iterate the tree to find the insertion point.
516    */
517   curNode        = targetListHead;
518   parentNodeLink = &targetListHead;
519
520   while (curNode!=NULL)
521   {
522     if (nodeToAdd->hwndTarget<curNode->hwndTarget)
523     {
524       /*
525        * If the node we want to add has a smaller HWND, go left
526        */
527       parentNodeLink = &curNode->prevDropTarget;
528       curNode        =  curNode->prevDropTarget;
529     }
530     else if (nodeToAdd->hwndTarget>curNode->hwndTarget)
531     {
532       /*
533        * If the node we want to add has a larger HWND, go right
534        */
535       parentNodeLink = &curNode->nextDropTarget;
536       curNode        =  curNode->nextDropTarget;
537     }
538     else
539     {
540       /*
541        * The item was found in the list. It shouldn't have been there
542        */
543       assert(FALSE);
544       return;
545     }
546   }
547
548   /*
549    * If we get here, we have found a spot for our item. The parentNodeLink
550    * pointer points to the pointer that we have to modify. 
551    * The curNode should be NULL. We just have to establish the link and Voila!
552    */
553   assert(curNode==NULL);
554   assert(parentNodeLink!=NULL);
555   assert(*parentNodeLink==NULL);
556
557   *parentNodeLink=nodeToAdd;
558 }
559
560 /***
561  * OLEDD_ExtractDropTarget()
562  *
563  * Removes the target node from the tree.
564  */
565 static DropTargetNode* OLEDD_ExtractDropTarget(HWND32 hwndOfTarget)
566 {
567   DropTargetNode*  curNode;
568   DropTargetNode** parentNodeLink;
569
570   /*
571    * Iterate the tree to find the insertion point.
572    */
573   curNode        = targetListHead;
574   parentNodeLink = &targetListHead;
575
576   while (curNode!=NULL)
577   {
578     if (hwndOfTarget<curNode->hwndTarget)
579     {
580       /*
581        * If the node we want to add has a smaller HWND, go left
582        */
583       parentNodeLink = &curNode->prevDropTarget;
584       curNode        =  curNode->prevDropTarget;
585     }
586     else if (hwndOfTarget>curNode->hwndTarget)
587     {
588       /*
589        * If the node we want to add has a larger HWND, go right
590        */
591       parentNodeLink = &curNode->nextDropTarget;
592       curNode        =  curNode->nextDropTarget;
593     }
594     else
595     {
596       /*
597        * The item was found in the list. Detach it from it's parent and 
598        * re-insert it's kids in the tree.
599        */
600       assert(parentNodeLink!=NULL);
601       assert(*parentNodeLink==curNode);
602
603       /*
604        * We arbitrately re-attach the left sub-tree to the parent.
605        */
606       *parentNodeLink = curNode->prevDropTarget;
607
608       /*
609        * And we re-insert the right subtree
610        */
611       if (curNode->nextDropTarget!=NULL)
612       {
613         OLEDD_InsertDropTarget(curNode->nextDropTarget);
614       }
615
616       /*
617        * The node we found is still a valid node once we complete
618        * the unlinking of the kids.
619        */
620       curNode->nextDropTarget=NULL;
621       curNode->prevDropTarget=NULL;
622
623       return curNode;
624     }
625   }
626
627   /*
628    * If we get here, the node is not in the tree
629    */
630   return NULL;
631 }
632
633 /***
634  * OLEDD_FindDropTarget()
635  *
636  * Finds information about the drop target.
637  */
638 static DropTargetNode* OLEDD_FindDropTarget(HWND32 hwndOfTarget)
639 {
640   DropTargetNode*  curNode;
641
642   /*
643    * Iterate the tree to find the HWND value.
644    */
645   curNode        = targetListHead;
646
647   while (curNode!=NULL)
648   {
649     if (hwndOfTarget<curNode->hwndTarget)
650     {
651       /*
652        * If the node we want to add has a smaller HWND, go left
653        */
654       curNode =  curNode->prevDropTarget;
655     }
656     else if (hwndOfTarget>curNode->hwndTarget)
657     {
658       /*
659        * If the node we want to add has a larger HWND, go right
660        */
661       curNode =  curNode->nextDropTarget;
662     }
663     else
664     {
665       /*
666        * The item was found in the list.
667        */
668       return curNode;
669     }
670   }
671
672   /*
673    * If we get here, the item is not in the list
674    */
675   return NULL;
676 }
677
678 /***
679  * OLEDD_DragTrackerWindowProc()
680  *
681  * This method is the WindowProcedure of the drag n drop tracking
682  * window. During a drag n Drop operation, an invisible window is created
683  * to receive the user input and act upon it. This procedure is in charge
684  * of this behavior.
685  */
686 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
687                          HWND32   hwnd, 
688                          UINT32   uMsg,
689                          WPARAM32 wParam, 
690                          LPARAM   lParam)
691 {
692   switch (uMsg)
693   {
694     case WM_CREATE:
695     {
696       LPCREATESTRUCT32A createStruct = (LPCREATESTRUCT32A)lParam;
697
698       SetWindowLong32A(hwnd, 0, (LONG)createStruct->lpCreateParams); 
699
700       
701       break;
702     }
703     case WM_MOUSEMOVE:
704     {
705       TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLong32A(hwnd, 0);
706       POINT32            mousePos;
707
708       /*
709        * Get the current mouse position in screen coordinates.
710        */
711       mousePos.x = LOWORD(lParam);
712       mousePos.y = HIWORD(lParam);
713       ClientToScreen32(hwnd, &mousePos);
714
715       /*
716        * Track the movement of the mouse.
717        */
718       OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam);
719
720       break;
721     }
722     case WM_LBUTTONUP:
723     case WM_MBUTTONUP:
724     case WM_RBUTTONUP:
725     case WM_LBUTTONDOWN:
726     case WM_MBUTTONDOWN:
727     case WM_RBUTTONDOWN:
728     {
729       TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLong32A(hwnd, 0);
730       POINT32            mousePos;
731
732       /*
733        * Get the current mouse position in screen coordinates.
734        */
735       mousePos.x = LOWORD(lParam);
736       mousePos.y = HIWORD(lParam);
737       ClientToScreen32(hwnd, &mousePos);
738
739       /*
740        * Notify everyone that the button state changed
741        * TODO: Check if the "escape" key was pressed.
742        */
743       OLEDD_TrackStateChange(trackerInfo, mousePos, wParam);
744
745       break;
746     }
747   }
748
749   /*
750    * This is a window proc after all. Let's call the default.
751    */
752   return DefWindowProc32A (hwnd, uMsg, wParam, lParam);
753 }
754
755 /***
756  * OLEDD_TrackMouseMove()
757  *
758  * This method is invoked while a drag and drop operation is in effect.
759  * it will generate the appropriate callbacks in the drop source
760  * and drop target. It will also provide the expected feedback to
761  * the user.
762  *
763  * params:
764  *    trackerInfo - Pointer to the structure identifying the
765  *                  drag & drop operation that is currently
766  *                  active.
767  *    mousePos    - Current position of the mouse in screen
768  *                  coordinates.
769  *    keyState    - Contains the state of the shift keys and the
770  *                  mouse buttons (MK_LBUTTON and the like)
771  */
772 static void OLEDD_TrackMouseMove(
773   TrackerWindowInfo* trackerInfo,
774   POINT32            mousePos,
775   DWORD              keyState)
776 {
777   HWND32   hwndNewTarget = 0;
778   HRESULT  hr = S_OK;
779
780   /*
781    * Get the handle of the window under the mouse
782    */
783   hwndNewTarget = WindowFromPoint32(mousePos);
784
785   /*
786    * If we are hovering over the same target as before, send the
787    * DragOver notification
788    */
789   if ( (trackerInfo->curDragTarget != 0) && 
790        (trackerInfo->curDragTargetHWND==hwndNewTarget) )
791   {
792     POINTL  mousePosParam;
793     
794     /*
795      * The documentation tells me that the coordinate should be in the target
796      * window's coordinate space. However, the tests I made tell me the
797      * coordinates should be in screen coordinates.
798      */
799     mousePosParam.x = mousePos.x;
800     mousePosParam.y = mousePos.y;
801     
802     IDropTarget_DragOver(trackerInfo->curDragTarget,
803                          keyState,
804                          mousePosParam,
805                          trackerInfo->pdwEffect);
806   }
807   else
808 {
809     DropTargetNode* newDropTargetNode = 0;
810     
811     /*
812      * If we changed window, we have to notify our old target and check for
813      * the new one.
814      */
815     if (trackerInfo->curDragTarget!=0)
816     {
817       IDropTarget_DragLeave(trackerInfo->curDragTarget);
818     }
819     
820     /*
821      * Make sure we're hovering over a window.
822      */
823     if (hwndNewTarget!=0)
824     {
825       /*
826        * Find-out if there is a drag target under the mouse
827        */
828       newDropTargetNode = OLEDD_FindDropTarget(hwndNewTarget);
829       
830       trackerInfo->curDragTargetHWND = hwndNewTarget;
831       trackerInfo->curDragTarget     = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
832       
833       /*
834        * If there is, notify it that we just dragged-in
835        */
836       if (trackerInfo->curDragTarget!=0)
837       {
838         POINTL  mousePosParam;
839         
840         /*
841          * The documentation tells me that the coordinate should be in the target
842          * window's coordinate space. However, the tests I made tell me the
843          * coordinates should be in screen coordinates.
844          */
845         mousePosParam.x = mousePos.x;
846         mousePosParam.y = mousePos.y;
847         
848         IDropTarget_DragEnter(trackerInfo->curDragTarget,
849                               trackerInfo->dataObject,
850                               keyState,
851                               mousePosParam,
852                               trackerInfo->pdwEffect);
853       }
854     }
855     else
856     {
857       /*
858        * The mouse is not over a window so we don't track anything.
859        */
860       trackerInfo->curDragTargetHWND = 0;
861       trackerInfo->curDragTarget     = 0;
862     }
863   }
864
865   /*
866    * Now that we have done that, we have to tell the source to give 
867    * us feedback on the work being done by the target.  If we don't 
868    * have a target, simulate no effect.
869    */
870   if (trackerInfo->curDragTarget==0)
871   {
872     *trackerInfo->pdwEffect = DROPEFFECT_NONE;
873   }
874
875   hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
876                                 *trackerInfo->pdwEffect);
877
878   /*
879    * When we ask for feedback from the drop source, sometimes it will
880    * do all the necessary work and sometimes it will not handle it
881    * when that's the case, we must display the standard drag and drop
882    * cursors.
883    */
884   if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
885   {
886     if ( (*trackerInfo->pdwEffect & DROPEFFECT_MOVE) ||
887          (*trackerInfo->pdwEffect & DROPEFFECT_COPY) ||
888          (*trackerInfo->pdwEffect & DROPEFFECT_LINK) )
889     {
890       SetCursor32(LoadCursor32A(0, IDC_SIZEALL32A));
891     }
892     else
893     {
894       SetCursor32(LoadCursor32A(0, IDC_NO32A));
895     }
896   }  
897 }
898
899 /***
900  * OLEDD_TrackStateChange()
901  *
902  * This method is invoked while a drag and drop operation is in effect.
903  * It is used to notify the drop target/drop source callbacks when
904  * the state of the keyboard or mouse button change.
905  *
906  * params:
907  *    trackerInfo - Pointer to the structure identifying the
908  *                  drag & drop operation that is currently
909  *                  active.
910  *    mousePos    - Current position of the mouse in screen
911  *                  coordinates.
912  *    keyState    - Contains the state of the shift keys and the
913  *                  mouse buttons (MK_LBUTTON and the like)
914  */
915 static void OLEDD_TrackStateChange(
916   TrackerWindowInfo* trackerInfo,
917   POINT32            mousePos,
918   DWORD              keyState)
919 {
920   /*
921    * Ask the drop source what to do with the operation.
922    */
923   trackerInfo->returnValue = IDropSource_QueryContinueDrag(
924                                trackerInfo->dropSource,
925                                trackerInfo->escPressed, 
926                                keyState);
927   
928   /*
929    * All the return valued will stop the operation except the S_OK
930    * return value.
931    */
932   if (trackerInfo->returnValue!=S_OK)
933   {
934     /*
935      * Make sure the message loop in DoDragDrop stops
936      */
937     trackerInfo->trackingDone = TRUE;
938
939     /*
940      * Release the mouse in case the drop target decides to show a popup 
941      * or a menu or something.
942      */
943     ReleaseCapture();
944     
945     /*
946      * If we end-up over a target, drop the object in the target or 
947      * inform the target that the operation was cancelled.
948      */
949     if (trackerInfo->curDragTarget!=0)
950     {
951       switch (trackerInfo->returnValue)
952       {
953         /*
954          * If the source wants us to complete the operation, we tell 
955          * the drop target that we just dropped the object in it.
956          */
957         case DRAGDROP_S_DROP:
958         {
959           POINTL  mousePosParam;
960         
961           /*
962            * The documentation tells me that the coordinate should be 
963            * in the target window's coordinate space. However, the tests
964            * I made tell me the coordinates should be in screen coordinates.
965            */
966           mousePosParam.x = mousePos.x;
967           mousePosParam.y = mousePos.y;
968           
969           IDropTarget_Drop(trackerInfo->curDragTarget,
970                            trackerInfo->dataObject,
971                            keyState,
972                            mousePosParam,
973                            trackerInfo->pdwEffect);
974           break;
975         }
976         /*
977          * If the source told us that we should cancel, fool the drop 
978          * target by telling it that the mouse left it's window.
979          */
980         case DRAGDROP_S_CANCEL:
981           IDropTarget_DragLeave(trackerInfo->curDragTarget);
982           break;
983       }
984     }
985   }
986 }
987
988 /***
989  * OLEDD_GetButtonState()
990  *
991  * This method will use the current state of the keyboard to build
992  * a button state mask equivalent to the one passed in the
993  * WM_MOUSEMOVE wParam.
994  */
995 static DWORD OLEDD_GetButtonState()
996 {
997   BYTE  keyboardState[256];
998   DWORD keyMask = 0;
999
1000   GetKeyboardState(keyboardState);
1001
1002   if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
1003     keyMask |= MK_SHIFT;
1004
1005   if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
1006     keyMask |= MK_CONTROL;
1007
1008   if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
1009     keyMask |= MK_LBUTTON;
1010
1011   if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
1012     keyMask |= MK_RBUTTON;
1013
1014   if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
1015     keyMask |= MK_MBUTTON;
1016
1017   return keyMask;
1018 }
1019
1020