Fixes in the SysAllocString functions prototypes. It's mostly 'const'
[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 "winuser.h"
11 #include "winerror.h"
12 #include "ole2.h"
13 #include "process.h"
14 #include "wine/obj_clientserver.h"
15 #include "debug.h"
16
17 /******************************************************************************
18  * These are static/global variables and internal data structures that the 
19  * OLE module uses to maintain it's state.
20  */
21 typedef struct tagDropTargetNode
22 {
23   HWND          hwndTarget;
24   IDropTarget*    dropTarget;
25   struct tagDropTargetNode* prevDropTarget;
26   struct tagDropTargetNode* nextDropTarget;
27 } DropTargetNode;
28
29 typedef struct tagTrackerWindowInfo
30 {
31   IDataObject* dataObject;
32   IDropSource* dropSource;
33   DWORD        dwOKEffect;
34   DWORD*       pdwEffect;
35   BOOL       trackingDone;
36   HRESULT      returnValue;
37
38   BOOL       escPressed;
39   HWND       curDragTargetHWND;
40   IDropTarget* curDragTarget;
41 } TrackerWindowInfo;
42
43 /*
44  * This is the lock count on the OLE library. It is controlled by the
45  * OLEInitialize/OLEUninitialize methods.
46  */
47 static ULONG OLE_moduleLockCount = 0;
48
49 /*
50  * Name of our registered window class.
51  */
52 static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";
53
54 /*
55  * This is the head of the Drop target container.
56  */
57 static DropTargetNode* targetListHead = NULL;
58
59 /******************************************************************************
60  * These are the prototypes of the utility methods used for OLE Drag n Drop
61  */
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();
84
85
86 /******************************************************************************
87  *              OleBuildVersion [OLE2.1]
88  */
89 DWORD WINAPI OleBuildVersion(void)
90 {
91     TRACE(ole,"(void)\n");
92     return (rmm<<16)+rup;
93 }
94
95 /***********************************************************************
96  *           OleInitialize       (OLE2.2) (OLE32.108)
97  */
98 HRESULT WINAPI OleInitialize(LPVOID reserved)
99 {
100   HRESULT hr;
101
102   TRACE(ole, "(%p)\n", reserved);
103
104   /*
105    * The first duty of the OleInitialize is to initialize the COM libraries.
106    */
107   hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
108
109   /*
110    * If the CoInitializeEx call failed, the OLE libraries can't be 
111    * initialized.
112    */
113   if (FAILED(hr))
114     return hr;    
115
116   /*
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
123    */
124   if (OLE_moduleLockCount==0)
125 {
126     /* 
127      * Initialize the libraries.
128      */
129     TRACE(ole, "() - Initializing the OLE libraries\n");
130
131     /*
132      * Drag and Drop
133      */
134     OLEDD_Initialize();
135 }
136
137   /*
138    * Then, we increase the lock count on the OLE module.
139    */
140   OLE_moduleLockCount++;  
141
142   return hr;
143 }
144
145 /******************************************************************************
146  *              CoGetCurrentProcess     [COMPOBJ.34] [OLE2.2][OLE32.108]
147  *
148  * NOTES
149  *   Is DWORD really the correct return type for this function?
150  */
151 DWORD WINAPI CoGetCurrentProcess(void) {
152         return (DWORD)PROCESS_Current();
153 }
154
155 /******************************************************************************
156  *              OleUninitialize [OLE2.3] [OLE32.131]
157  */
158 void WINAPI OleUninitialize(void)
159 {
160   TRACE(ole, "()\n");
161
162   /*
163    * Decrease the lock count on the OLE module.
164    */
165   OLE_moduleLockCount--;
166
167   /*
168    * If we hit the bottom of the lock stack, free the libraries.
169    */
170   if (OLE_moduleLockCount==0)
171   {
172     /*
173      * Actually free the libraries.
174      */
175     TRACE(ole, "() - Freeing the last reference count\n");
176
177     /*
178      * Drag and Drop
179      */
180     OLEDD_UnInitialize();
181   }
182   
183   /*
184    * Then, uninitialize the COM libraries.
185    */
186   CoUninitialize();
187 }
188
189 /***********************************************************************
190  *           OleFlushClipboard   [OLE2.76]
191  */
192 HRESULT WINAPI OleFlushClipboard16(void)
193 {
194     return S_OK;
195 }
196
197 /***********************************************************************
198  *           OleSetClipboard     [OLE32.127]
199  */
200 HRESULT WINAPI OleSetClipboard(LPVOID pDataObj)
201 {
202     FIXME(ole,"(%p), stub!\n", pDataObj);
203     return S_OK;
204 }
205
206 /******************************************************************************
207  *              CoRegisterMessageFilter32       [OLE32.38]
208  */
209 HRESULT WINAPI CoRegisterMessageFilter(
210     LPMESSAGEFILTER lpMessageFilter,    /* Pointer to interface */
211     LPMESSAGEFILTER *lplpMessageFilter  /* Indirect pointer to prior instance if non-NULL */
212 ) {
213     FIXME(ole,"stub\n");
214     if (lplpMessageFilter) {
215         *lplpMessageFilter = NULL;
216     }
217     return S_OK;
218 }
219
220 /******************************************************************************
221  *              OleInitializeWOW        [OLE32.109]
222  */
223 HRESULT WINAPI OleInitializeWOW(DWORD x) {
224         FIXME(ole,"(0x%08lx),stub!\n",x);
225         return 0;
226 }
227
228 /***********************************************************************
229  *           RegisterDragDrop16 (OLE2.35)
230  */
231 HRESULT WINAPI RegisterDragDrop16(
232         HWND16 hwnd,
233         LPDROPTARGET pDropTarget
234 ) {
235         FIXME(ole,"(0x%04x,%p),stub!\n",hwnd,pDropTarget);
236         return S_OK;
237 }
238
239 /***********************************************************************
240  *           RegisterDragDrop32 (OLE32.139)
241  */
242 HRESULT WINAPI RegisterDragDrop(
243         HWND hwnd,
244         LPDROPTARGET pDropTarget) 
245 {
246   DropTargetNode* dropTargetInfo;
247
248   TRACE(ole,"(0x%x,%p)\n", hwnd, pDropTarget);
249
250   /*
251    * First, check if the window is already registered.
252    */
253   dropTargetInfo = OLEDD_FindDropTarget(hwnd);
254
255   if (dropTargetInfo!=NULL)
256     return DRAGDROP_E_ALREADYREGISTERED;
257
258   /*
259    * If it's not there, we can add it. We first create a node for it.
260    */
261   dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));
262
263   if (dropTargetInfo==NULL)
264     return E_OUTOFMEMORY;
265
266   dropTargetInfo->hwndTarget     = hwnd;
267   dropTargetInfo->prevDropTarget = NULL;
268   dropTargetInfo->nextDropTarget = NULL;
269
270   /*
271    * Don't forget that this is an interface pointer, need to nail it down since
272    * we keep a copy of it.
273    */
274   dropTargetInfo->dropTarget  = pDropTarget;
275   IDropTarget_AddRef(dropTargetInfo->dropTarget);
276   
277   OLEDD_InsertDropTarget(dropTargetInfo);
278
279         return S_OK;
280 }
281
282 /***********************************************************************
283  *           RevokeDragDrop16 (OLE2.36)
284  */
285 HRESULT WINAPI RevokeDragDrop16(
286         HWND16 hwnd
287 ) {
288         FIXME(ole,"(0x%04x),stub!\n",hwnd);
289         return S_OK;
290 }
291
292 /***********************************************************************
293  *           RevokeDragDrop32 (OLE32.141)
294  */
295 HRESULT WINAPI RevokeDragDrop(
296         HWND hwnd)
297 {
298   DropTargetNode* dropTargetInfo;
299
300   TRACE(ole,"(0x%x)\n", hwnd);
301
302   /*
303    * First, check if the window is already registered.
304    */
305   dropTargetInfo = OLEDD_ExtractDropTarget(hwnd);
306
307   /*
308    * If it ain't in there, it's an error.
309    */
310   if (dropTargetInfo==NULL)
311     return DRAGDROP_E_NOTREGISTERED;
312
313   /*
314    * If it's in there, clean-up it's used memory and
315    * references
316    */
317   IDropTarget_Release(dropTargetInfo->dropTarget);
318   HeapFree(GetProcessHeap(), 0, dropTargetInfo);  
319
320         return S_OK;
321 }
322
323 /***********************************************************************
324  *           OleRegGetUserType (OLE32.122)
325  */
326 HRESULT WINAPI OleRegGetUserType( 
327         REFCLSID clsid, 
328         DWORD dwFormOfType,
329         LPOLESTR* pszUserType)
330 {
331         FIXME(ole,",stub!\n");
332         return S_OK;
333 }
334
335 /***********************************************************************
336  * DoDragDrop32 [OLE32.65]
337  */
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  */
343 {
344   TrackerWindowInfo trackerInfo;
345   HWND            hwndTrackWindow;
346   MSG             msg;
347
348   TRACE(ole,"(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
349
350   /*
351    * Setup the drag n drop tracking window.
352    */
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;
361
362   hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS,
363                                     "TrackerWindow",
364                                     WS_POPUP,
365                                     CW_USEDEFAULT, CW_USEDEFAULT,
366                                     CW_USEDEFAULT, CW_USEDEFAULT,
367                                     0,
368                                     0,
369                                     0,
370                                     (LPVOID)&trackerInfo);
371
372   if (hwndTrackWindow!=0)
373   {
374     /*
375      * Capture the mouse input
376      */
377     SetCapture(hwndTrackWindow);
378
379     /*
380      * Pump messages. All mouse input should go the the capture window.
381      */
382     while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )
383     {
384       if ( (msg.message >= WM_KEYFIRST) && 
385            (msg.message <= WM_KEYFIRST) )
386       {
387         /*
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.
392          */
393         if ( (msg.message==WM_KEYDOWN) &&
394              (msg.wParam==VK_ESCAPE) )
395         {
396           trackerInfo.escPressed = TRUE;
397         }
398
399         /*
400          * Notify the drop source.
401          */       
402         OLEDD_TrackStateChange(&trackerInfo,
403                                msg.pt,
404                                OLEDD_GetButtonState());
405       }
406       else
407       {
408         /*
409          * Dispatch the messages only when it's not a keyboard message.
410          */
411         DispatchMessageA(&msg);
412       }
413     }
414
415     /*
416      * Destroy the temporary window.
417      */
418     DestroyWindow(hwndTrackWindow);
419
420     return trackerInfo.returnValue;
421   }
422
423   return E_FAIL;
424 }
425
426 /***********************************************************************
427  * OleQueryLinkFromData32 [OLE32.118]
428  */
429 HRESULT WINAPI OleQueryLinkFromData32(
430   IDataObject* pSrcDataObject)
431 {
432   FIXME(ole,"(%p),stub!\n", pSrcDataObject);
433   return S_OK;
434 }
435
436 /***********************************************************************
437  * OleRegGetMiscStatus32 [OLE32.121]
438  */
439 HRESULT WINAPI OleRegGetMiscStatus32(
440   REFCLSID clsid,
441   DWORD    dwAspect,
442   DWORD*   pdwStatus)
443 {
444   FIXME(ole,"(),stub!\n");
445   return REGDB_E_CLASSNOTREG;
446 }
447
448 /***********************************************************************
449  * OleGetClipboard32 [OLE32.105]
450  */
451 HRESULT WINAPI OleGetClipboard32(
452   IDataObject** ppDataObj)
453 {
454   FIXME(ole,"(%p),stub!\n", ppDataObj);
455
456   if (ppDataObj)
457     *ppDataObj=0;
458
459   return E_FAIL;
460 }
461
462 /***********************************************************************
463  * OleCreateMenuDescriptor [OLE32.97]
464  */
465 HOLEMENU WINAPI OleCreateMenuDescriptor(
466   HMENU                hmenuCombined,
467   LPOLEMENUGROUPWIDTHS lpMenuWidths)
468 {
469   FIXME(ole,"(%x,%p),stub!\n", hmenuCombined, lpMenuWidths);
470
471   return NULL;
472 }
473
474 /***********************************************************************
475  * OleDestroyMenuDescriptor [OLE32.99]
476  */
477 void WINAPI OleDestroyMenuDescriptor(
478   HOLEMENU hmenuDescriptor)
479 {
480   FIXME(ole,"(%x),stub!\n", (unsigned int)hmenuDescriptor);
481 }
482
483 /***********************************************************************
484  * OleSetMenuDescriptor [OLE32.129]
485  */
486 HRESULT WINAPI OleSetMenuDescriptor(
487   HOLEMENU               hmenuDescriptor,
488   HWND                   hwndFrame,
489   HWND                   hwndActiveObject,
490   LPOLEINPLACEFRAME        lpFrame,
491   LPOLEINPLACEACTIVEOBJECT lpActiveObject)
492 {
493   FIXME(ole,"(%x, %x, %x, %p, %p),stub!\n", 
494         (unsigned int)hmenuDescriptor,
495         hwndFrame,
496         hwndActiveObject,
497         lpFrame,
498         lpActiveObject);
499
500   return E_FAIL;
501 }
502
503 /***********************************************************************
504  * ReleaseStgMedium [OLE32.140]
505  */
506 void WINAPI ReleaseStgMedium(
507   STGMEDIUM* pmedium)
508 {
509   switch (pmedium->tymed)
510   {
511     case TYMED_HGLOBAL:
512     {
513       if ( (pmedium->pUnkForRelease==0) && 
514            (pmedium->u.hGlobal!=0) )
515         GlobalFree(pmedium->u.hGlobal);
516
517       pmedium->u.hGlobal = 0;
518       break;
519     }
520     case TYMED_FILE:
521     {
522       if (pmedium->u.lpszFileName!=0)
523       {
524         if (pmedium->pUnkForRelease==0)
525         {
526           DeleteFileW(pmedium->u.lpszFileName);
527         }
528         
529         CoTaskMemFree(pmedium->u.lpszFileName);
530       }
531
532       pmedium->u.lpszFileName = 0;
533       break;
534     }
535     case TYMED_ISTREAM:
536     {
537       if (pmedium->u.pstm!=0)
538       {
539         IStream_Release(pmedium->u.pstm);
540       }
541
542       pmedium->u.pstm = 0;
543       break;
544     }
545     case TYMED_ISTORAGE:
546     {
547       if (pmedium->u.pstg!=0)
548       {
549         IStorage_Release(pmedium->u.pstg);
550       }
551
552       pmedium->u.pstg = 0;
553       break;
554     }
555     case TYMED_GDI:
556     {
557       if ( (pmedium->pUnkForRelease==0) && 
558            (pmedium->u.hGlobal!=0) )
559         DeleteObject(pmedium->u.hGlobal);
560
561       pmedium->u.hGlobal = 0;
562       break;
563     }
564     case TYMED_MFPICT:
565     {
566       if ( (pmedium->pUnkForRelease==0) && 
567            (pmedium->u.hMetaFilePict!=0) )
568       {
569         DeleteMetaFile(pmedium->u.hMetaFilePict);
570         GlobalFree(pmedium->u.hMetaFilePict);
571       }
572
573       pmedium->u.hMetaFilePict = 0;
574       break;
575     }
576     case TYMED_ENHMF:
577     {
578       if ( (pmedium->pUnkForRelease==0) && 
579            (pmedium->u.hEnhMetaFile!=0) )
580       {
581         DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
582       }
583
584       pmedium->u.hEnhMetaFile = 0;
585       break;
586     }
587     case TYMED_NULL:
588     default:
589       break;
590   }
591
592   /*
593    * After cleaning up, the unknown is released
594    */
595   if (pmedium->pUnkForRelease!=0)
596   {
597     IUnknown_Release(pmedium->pUnkForRelease);
598     pmedium->pUnkForRelease = 0;
599   }
600 }
601
602 /***
603  * OLEDD_Initialize()
604  *
605  * Initializes the OLE drag and drop data structures.
606  */
607 static void OLEDD_Initialize()
608 {
609     WNDCLASSA wndClass;
610
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;
619  
620     RegisterClassA (&wndClass);
621 }
622
623 /***
624  * OLEDD_UnInitialize()
625  *
626  * Releases the OLE drag and drop data structures.
627  */
628 static void OLEDD_UnInitialize()
629 {
630   /*
631    * Simply empty the list.
632    */
633   while (targetListHead!=NULL)
634   {
635     RevokeDragDrop(targetListHead->hwndTarget);
636   }
637 }
638
639 /***
640  * OLEDD_InsertDropTarget()
641  *
642  * Insert the target node in the tree.
643  */
644 static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd)
645 {
646   DropTargetNode*  curNode;
647   DropTargetNode** parentNodeLink;
648
649   /*
650    * Iterate the tree to find the insertion point.
651    */
652   curNode        = targetListHead;
653   parentNodeLink = &targetListHead;
654
655   while (curNode!=NULL)
656   {
657     if (nodeToAdd->hwndTarget<curNode->hwndTarget)
658     {
659       /*
660        * If the node we want to add has a smaller HWND, go left
661        */
662       parentNodeLink = &curNode->prevDropTarget;
663       curNode        =  curNode->prevDropTarget;
664     }
665     else if (nodeToAdd->hwndTarget>curNode->hwndTarget)
666     {
667       /*
668        * If the node we want to add has a larger HWND, go right
669        */
670       parentNodeLink = &curNode->nextDropTarget;
671       curNode        =  curNode->nextDropTarget;
672     }
673     else
674     {
675       /*
676        * The item was found in the list. It shouldn't have been there
677        */
678       assert(FALSE);
679       return;
680     }
681   }
682
683   /*
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!
687    */
688   assert(curNode==NULL);
689   assert(parentNodeLink!=NULL);
690   assert(*parentNodeLink==NULL);
691
692   *parentNodeLink=nodeToAdd;
693 }
694
695 /***
696  * OLEDD_ExtractDropTarget()
697  *
698  * Removes the target node from the tree.
699  */
700 static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget)
701 {
702   DropTargetNode*  curNode;
703   DropTargetNode** parentNodeLink;
704
705   /*
706    * Iterate the tree to find the insertion point.
707    */
708   curNode        = targetListHead;
709   parentNodeLink = &targetListHead;
710
711   while (curNode!=NULL)
712   {
713     if (hwndOfTarget<curNode->hwndTarget)
714     {
715       /*
716        * If the node we want to add has a smaller HWND, go left
717        */
718       parentNodeLink = &curNode->prevDropTarget;
719       curNode        =  curNode->prevDropTarget;
720     }
721     else if (hwndOfTarget>curNode->hwndTarget)
722     {
723       /*
724        * If the node we want to add has a larger HWND, go right
725        */
726       parentNodeLink = &curNode->nextDropTarget;
727       curNode        =  curNode->nextDropTarget;
728     }
729     else
730     {
731       /*
732        * The item was found in the list. Detach it from it's parent and 
733        * re-insert it's kids in the tree.
734        */
735       assert(parentNodeLink!=NULL);
736       assert(*parentNodeLink==curNode);
737
738       /*
739        * We arbitrately re-attach the left sub-tree to the parent.
740        */
741       *parentNodeLink = curNode->prevDropTarget;
742
743       /*
744        * And we re-insert the right subtree
745        */
746       if (curNode->nextDropTarget!=NULL)
747       {
748         OLEDD_InsertDropTarget(curNode->nextDropTarget);
749       }
750
751       /*
752        * The node we found is still a valid node once we complete
753        * the unlinking of the kids.
754        */
755       curNode->nextDropTarget=NULL;
756       curNode->prevDropTarget=NULL;
757
758       return curNode;
759     }
760   }
761
762   /*
763    * If we get here, the node is not in the tree
764    */
765   return NULL;
766 }
767
768 /***
769  * OLEDD_FindDropTarget()
770  *
771  * Finds information about the drop target.
772  */
773 static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
774 {
775   DropTargetNode*  curNode;
776
777   /*
778    * Iterate the tree to find the HWND value.
779    */
780   curNode        = targetListHead;
781
782   while (curNode!=NULL)
783   {
784     if (hwndOfTarget<curNode->hwndTarget)
785     {
786       /*
787        * If the node we want to add has a smaller HWND, go left
788        */
789       curNode =  curNode->prevDropTarget;
790     }
791     else if (hwndOfTarget>curNode->hwndTarget)
792     {
793       /*
794        * If the node we want to add has a larger HWND, go right
795        */
796       curNode =  curNode->nextDropTarget;
797     }
798     else
799     {
800       /*
801        * The item was found in the list.
802        */
803       return curNode;
804     }
805   }
806
807   /*
808    * If we get here, the item is not in the list
809    */
810   return NULL;
811 }
812
813 /***
814  * OLEDD_DragTrackerWindowProc()
815  *
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.
820  */
821 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
822                          HWND   hwnd, 
823                          UINT   uMsg,
824                          WPARAM wParam, 
825                          LPARAM   lParam)
826 {
827   switch (uMsg)
828   {
829     case WM_CREATE:
830     {
831       LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
832
833       SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams); 
834
835       
836       break;
837     }
838     case WM_MOUSEMOVE:
839     {
840       TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
841       POINT            mousePos;
842
843       /*
844        * Get the current mouse position in screen coordinates.
845        */
846       mousePos.x = LOWORD(lParam);
847       mousePos.y = HIWORD(lParam);
848       ClientToScreen(hwnd, &mousePos);
849
850       /*
851        * Track the movement of the mouse.
852        */
853       OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam);
854
855       break;
856     }
857     case WM_LBUTTONUP:
858     case WM_MBUTTONUP:
859     case WM_RBUTTONUP:
860     case WM_LBUTTONDOWN:
861     case WM_MBUTTONDOWN:
862     case WM_RBUTTONDOWN:
863     {
864       TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
865       POINT            mousePos;
866
867       /*
868        * Get the current mouse position in screen coordinates.
869        */
870       mousePos.x = LOWORD(lParam);
871       mousePos.y = HIWORD(lParam);
872       ClientToScreen(hwnd, &mousePos);
873
874       /*
875        * Notify everyone that the button state changed
876        * TODO: Check if the "escape" key was pressed.
877        */
878       OLEDD_TrackStateChange(trackerInfo, mousePos, wParam);
879
880       break;
881     }
882   }
883
884   /*
885    * This is a window proc after all. Let's call the default.
886    */
887   return DefWindowProcA (hwnd, uMsg, wParam, lParam);
888 }
889
890 /***
891  * OLEDD_TrackMouseMove()
892  *
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.
897  *
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)
906  */
907 static void OLEDD_TrackMouseMove(
908   TrackerWindowInfo* trackerInfo,
909   POINT            mousePos,
910   DWORD              keyState)
911 {
912   HWND   hwndNewTarget = 0;
913   HRESULT  hr = S_OK;
914
915   /*
916    * Get the handle of the window under the mouse
917    */
918   hwndNewTarget = WindowFromPoint(mousePos);
919
920   /*
921    * If we are hovering over the same target as before, send the
922    * DragOver notification
923    */
924   if ( (trackerInfo->curDragTarget != 0) && 
925        (trackerInfo->curDragTargetHWND==hwndNewTarget) )
926   {
927     POINTL  mousePosParam;
928     
929     /*
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.
933      */
934     mousePosParam.x = mousePos.x;
935     mousePosParam.y = mousePos.y;
936     
937     IDropTarget_DragOver(trackerInfo->curDragTarget,
938                          keyState,
939                          mousePosParam,
940                          trackerInfo->pdwEffect);
941   }
942   else
943 {
944     DropTargetNode* newDropTargetNode = 0;
945     
946     /*
947      * If we changed window, we have to notify our old target and check for
948      * the new one.
949      */
950     if (trackerInfo->curDragTarget!=0)
951     {
952       IDropTarget_DragLeave(trackerInfo->curDragTarget);
953     }
954     
955     /*
956      * Make sure we're hovering over a window.
957      */
958     if (hwndNewTarget!=0)
959     {
960       /*
961        * Find-out if there is a drag target under the mouse
962        */
963       newDropTargetNode = OLEDD_FindDropTarget(hwndNewTarget);
964       
965       trackerInfo->curDragTargetHWND = hwndNewTarget;
966       trackerInfo->curDragTarget     = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
967       
968       /*
969        * If there is, notify it that we just dragged-in
970        */
971       if (trackerInfo->curDragTarget!=0)
972       {
973         POINTL  mousePosParam;
974         
975         /*
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.
979          */
980         mousePosParam.x = mousePos.x;
981         mousePosParam.y = mousePos.y;
982         
983         IDropTarget_DragEnter(trackerInfo->curDragTarget,
984                               trackerInfo->dataObject,
985                               keyState,
986                               mousePosParam,
987                               trackerInfo->pdwEffect);
988       }
989     }
990     else
991     {
992       /*
993        * The mouse is not over a window so we don't track anything.
994        */
995       trackerInfo->curDragTargetHWND = 0;
996       trackerInfo->curDragTarget     = 0;
997     }
998   }
999
1000   /*
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.
1004    */
1005   if (trackerInfo->curDragTarget==0)
1006   {
1007     *trackerInfo->pdwEffect = DROPEFFECT_NONE;
1008   }
1009
1010   hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
1011                                 *trackerInfo->pdwEffect);
1012
1013   /*
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.
1018    */
1019   if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
1020   {
1021     if ( (*trackerInfo->pdwEffect & DROPEFFECT_MOVE) ||
1022          (*trackerInfo->pdwEffect & DROPEFFECT_COPY) ||
1023          (*trackerInfo->pdwEffect & DROPEFFECT_LINK) )
1024     {
1025       SetCursor(LoadCursorA(0, IDC_SIZEALLA));
1026     }
1027     else
1028     {
1029       SetCursor(LoadCursorA(0, IDC_NOA));
1030     }
1031   }  
1032 }
1033
1034 /***
1035  * OLEDD_TrackStateChange()
1036  *
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.
1040  *
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)
1049  */
1050 static void OLEDD_TrackStateChange(
1051   TrackerWindowInfo* trackerInfo,
1052   POINT            mousePos,
1053   DWORD              keyState)
1054 {
1055   /*
1056    * Ask the drop source what to do with the operation.
1057    */
1058   trackerInfo->returnValue = IDropSource_QueryContinueDrag(
1059                                trackerInfo->dropSource,
1060                                trackerInfo->escPressed, 
1061                                keyState);
1062   
1063   /*
1064    * All the return valued will stop the operation except the S_OK
1065    * return value.
1066    */
1067   if (trackerInfo->returnValue!=S_OK)
1068   {
1069     /*
1070      * Make sure the message loop in DoDragDrop stops
1071      */
1072     trackerInfo->trackingDone = TRUE;
1073
1074     /*
1075      * Release the mouse in case the drop target decides to show a popup 
1076      * or a menu or something.
1077      */
1078     ReleaseCapture();
1079     
1080     /*
1081      * If we end-up over a target, drop the object in the target or 
1082      * inform the target that the operation was cancelled.
1083      */
1084     if (trackerInfo->curDragTarget!=0)
1085     {
1086       switch (trackerInfo->returnValue)
1087       {
1088         /*
1089          * If the source wants us to complete the operation, we tell 
1090          * the drop target that we just dropped the object in it.
1091          */
1092         case DRAGDROP_S_DROP:
1093         {
1094           POINTL  mousePosParam;
1095         
1096           /*
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.
1100            */
1101           mousePosParam.x = mousePos.x;
1102           mousePosParam.y = mousePos.y;
1103           
1104           IDropTarget_Drop(trackerInfo->curDragTarget,
1105                            trackerInfo->dataObject,
1106                            keyState,
1107                            mousePosParam,
1108                            trackerInfo->pdwEffect);
1109           break;
1110         }
1111         /*
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.
1114          */
1115         case DRAGDROP_S_CANCEL:
1116           IDropTarget_DragLeave(trackerInfo->curDragTarget);
1117           break;
1118       }
1119     }
1120   }
1121 }
1122
1123 /***
1124  * OLEDD_GetButtonState()
1125  *
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.
1129  */
1130 static DWORD OLEDD_GetButtonState()
1131 {
1132   BYTE  keyboardState[256];
1133   DWORD keyMask = 0;
1134
1135   GetKeyboardState(keyboardState);
1136
1137   if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
1138     keyMask |= MK_SHIFT;
1139
1140   if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
1141     keyMask |= MK_CONTROL;
1142
1143   if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
1144     keyMask |= MK_LBUTTON;
1145
1146   if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
1147     keyMask |= MK_RBUTTON;
1148
1149   if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
1150     keyMask |= MK_MBUTTON;
1151
1152   return keyMask;
1153 }
1154
1155