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