Stop winelib programs on fault instead of endless faultlooping.
[wine.git] / ole / ole2.c
blobcb052ad107488c2e05b19e7ed36695a37c3a07bd
1 /*
2 * OLE2 library
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1999 Francis Beaudet
6 * Copyright 1999 Noel Borthwick
7 */
9 #include <assert.h>
10 #include <stdlib.h>
11 #include <strings.h>
13 #include "winuser.h"
14 #include "winerror.h"
15 #include "ole2.h"
16 #include "process.h"
17 #include "hook.h"
18 #include "commctrl.h"
19 #include "wine/obj_clientserver.h"
20 #include "debug.h"
21 #include "ole2ver.h"
22 #include "winreg.h"
24 DEFAULT_DEBUG_CHANNEL(ole)
26 /******************************************************************************
27 * These are static/global variables and internal data structures that the
28 * OLE module uses to maintain it's state.
30 typedef struct tagDropTargetNode
32 HWND hwndTarget;
33 IDropTarget* dropTarget;
34 struct tagDropTargetNode* prevDropTarget;
35 struct tagDropTargetNode* nextDropTarget;
36 } DropTargetNode;
38 typedef struct tagTrackerWindowInfo
40 IDataObject* dataObject;
41 IDropSource* dropSource;
42 DWORD dwOKEffect;
43 DWORD* pdwEffect;
44 BOOL trackingDone;
45 HRESULT returnValue;
47 BOOL escPressed;
48 HWND curDragTargetHWND;
49 IDropTarget* curDragTarget;
50 } TrackerWindowInfo;
52 typedef struct tagOleMenuDescriptor /* OleMenuDescriptor */
54 HWND hwndFrame; /* The containers frame window */
55 HWND hwndActiveObject; /* The active objects window */
56 OLEMENUGROUPWIDTHS mgw; /* OLE menu group widths for the shared menu */
57 HMENU hmenuCombined; /* The combined menu */
58 BOOL bIsServerItem; /* True if the currently open popup belongs to the server */
59 } OleMenuDescriptor;
61 typedef struct tagOleMenuHookItem /* OleMenu hook item in per thread hook list */
63 DWORD tid; /* Thread Id */
64 HANDLE hHeap; /* Heap this is allocated from */
65 HHOOK GetMsg_hHook; /* message hook for WH_GETMESSAGE */
66 HHOOK CallWndProc_hHook; /* message hook for WH_CALLWNDPROC */
67 } OleMenuHookItem;
70 * Dynamic pointer array of per thread message hooks (maintained by OleSetMenuDescriptor)
72 static HDPA OLEMenu_MsgHookDPA = NULL;
75 * This is the lock count on the OLE library. It is controlled by the
76 * OLEInitialize/OLEUninitialize methods.
78 static ULONG OLE_moduleLockCount = 0;
81 * Name of our registered window class.
83 static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";
86 * This is the head of the Drop target container.
88 static DropTargetNode* targetListHead = NULL;
90 /******************************************************************************
91 * These are the prototypes of miscelaneous utility methods
93 static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue);
95 /******************************************************************************
96 * These are the prototypes of the utility methods used to manage a shared menu
98 static void OLEMenu_Initialize();
99 static void OLEMenu_UnInitialize();
100 BOOL OLEMenu_InstallHooks( DWORD tid );
101 BOOL OLEMenu_UnInstallHooks( DWORD tid );
102 OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid, INT *pixHook );
103 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
104 BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor );
105 LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam);
106 LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam);
108 /******************************************************************************
109 * These are the prototypes of the utility methods used for OLE Drag n Drop
111 static void OLEDD_Initialize();
112 static void OLEDD_UnInitialize();
113 static void OLEDD_InsertDropTarget(
114 DropTargetNode* nodeToAdd);
115 static DropTargetNode* OLEDD_ExtractDropTarget(
116 HWND hwndOfTarget);
117 static DropTargetNode* OLEDD_FindDropTarget(
118 HWND hwndOfTarget);
119 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
120 HWND hwnd,
121 UINT uMsg,
122 WPARAM wParam,
123 LPARAM lParam);
124 static void OLEDD_TrackMouseMove(
125 TrackerWindowInfo* trackerInfo,
126 POINT mousePos,
127 DWORD keyState);
128 static void OLEDD_TrackStateChange(
129 TrackerWindowInfo* trackerInfo,
130 POINT mousePos,
131 DWORD keyState);
132 static DWORD OLEDD_GetButtonState();
135 /******************************************************************************
136 * OleBuildVersion [OLE2.1]
138 DWORD WINAPI OleBuildVersion(void)
140 TRACE(ole,"(void)\n");
141 return (rmm<<16)+rup;
144 /***********************************************************************
145 * OleInitialize (OLE2.2) (OLE32.108)
147 HRESULT WINAPI OleInitialize(LPVOID reserved)
149 HRESULT hr;
151 TRACE(ole, "(%p)\n", reserved);
154 * The first duty of the OleInitialize is to initialize the COM libraries.
156 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
159 * If the CoInitializeEx call failed, the OLE libraries can't be
160 * initialized.
162 if (FAILED(hr))
163 return hr;
166 * Then, it has to initialize the OLE specific modules.
167 * This includes:
168 * Clipboard
169 * Drag and Drop
170 * Object linking and Embedding
171 * In-place activation
173 if (OLE_moduleLockCount==0)
176 * Initialize the libraries.
178 TRACE(ole, "() - Initializing the OLE libraries\n");
181 * Drag and Drop
183 OLEDD_Initialize();
186 * OLE shared menu
188 OLEMenu_Initialize();
192 * Then, we increase the lock count on the OLE module.
194 OLE_moduleLockCount++;
196 return hr;
199 /******************************************************************************
200 * CoGetCurrentProcess [COMPOBJ.34] [OLE2.2][OLE32.108]
202 * NOTES
203 * Is DWORD really the correct return type for this function?
205 DWORD WINAPI CoGetCurrentProcess(void) {
206 return (DWORD)PROCESS_Current();
209 /******************************************************************************
210 * OleUninitialize [OLE2.3] [OLE32.131]
212 void WINAPI OleUninitialize(void)
214 TRACE(ole, "()\n");
217 * Decrease the lock count on the OLE module.
219 OLE_moduleLockCount--;
222 * If we hit the bottom of the lock stack, free the libraries.
224 if (OLE_moduleLockCount==0)
227 * Actually free the libraries.
229 TRACE(ole, "() - Freeing the last reference count\n");
232 * Drag and Drop
234 OLEDD_UnInitialize();
237 * OLE shared menu
239 OLEMenu_UnInitialize();
243 * Then, uninitialize the COM libraries.
245 CoUninitialize();
248 /***********************************************************************
249 * OleFlushClipboard [OLE2.76]
251 HRESULT WINAPI OleFlushClipboard16(void)
253 return S_OK;
256 /***********************************************************************
257 * OleSetClipboard [OLE32.127]
259 HRESULT WINAPI OleSetClipboard(LPVOID pDataObj)
261 FIXME(ole,"(%p), stub!\n", pDataObj);
262 return S_OK;
265 /******************************************************************************
266 * CoRegisterMessageFilter32 [OLE32.38]
268 HRESULT WINAPI CoRegisterMessageFilter(
269 LPMESSAGEFILTER lpMessageFilter, /* Pointer to interface */
270 LPMESSAGEFILTER *lplpMessageFilter /* Indirect pointer to prior instance if non-NULL */
272 FIXME(ole,"stub\n");
273 if (lplpMessageFilter) {
274 *lplpMessageFilter = NULL;
276 return S_OK;
279 /******************************************************************************
280 * OleInitializeWOW [OLE32.109]
282 HRESULT WINAPI OleInitializeWOW(DWORD x) {
283 FIXME(ole,"(0x%08lx),stub!\n",x);
284 return 0;
287 /***********************************************************************
288 * RegisterDragDrop16 (OLE2.35)
290 HRESULT WINAPI RegisterDragDrop16(
291 HWND16 hwnd,
292 LPDROPTARGET pDropTarget
294 FIXME(ole,"(0x%04x,%p),stub!\n",hwnd,pDropTarget);
295 return S_OK;
298 /***********************************************************************
299 * RegisterDragDrop32 (OLE32.139)
301 HRESULT WINAPI RegisterDragDrop(
302 HWND hwnd,
303 LPDROPTARGET pDropTarget)
305 DropTargetNode* dropTargetInfo;
307 TRACE(ole,"(0x%x,%p)\n", hwnd, pDropTarget);
310 * First, check if the window is already registered.
312 dropTargetInfo = OLEDD_FindDropTarget(hwnd);
314 if (dropTargetInfo!=NULL)
315 return DRAGDROP_E_ALREADYREGISTERED;
318 * If it's not there, we can add it. We first create a node for it.
320 dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));
322 if (dropTargetInfo==NULL)
323 return E_OUTOFMEMORY;
325 dropTargetInfo->hwndTarget = hwnd;
326 dropTargetInfo->prevDropTarget = NULL;
327 dropTargetInfo->nextDropTarget = NULL;
330 * Don't forget that this is an interface pointer, need to nail it down since
331 * we keep a copy of it.
333 dropTargetInfo->dropTarget = pDropTarget;
334 IDropTarget_AddRef(dropTargetInfo->dropTarget);
336 OLEDD_InsertDropTarget(dropTargetInfo);
338 return S_OK;
341 /***********************************************************************
342 * RevokeDragDrop16 (OLE2.36)
344 HRESULT WINAPI RevokeDragDrop16(
345 HWND16 hwnd
347 FIXME(ole,"(0x%04x),stub!\n",hwnd);
348 return S_OK;
351 /***********************************************************************
352 * RevokeDragDrop32 (OLE32.141)
354 HRESULT WINAPI RevokeDragDrop(
355 HWND hwnd)
357 DropTargetNode* dropTargetInfo;
359 TRACE(ole,"(0x%x)\n", hwnd);
362 * First, check if the window is already registered.
364 dropTargetInfo = OLEDD_ExtractDropTarget(hwnd);
367 * If it ain't in there, it's an error.
369 if (dropTargetInfo==NULL)
370 return DRAGDROP_E_NOTREGISTERED;
373 * If it's in there, clean-up it's used memory and
374 * references
376 IDropTarget_Release(dropTargetInfo->dropTarget);
377 HeapFree(GetProcessHeap(), 0, dropTargetInfo);
379 return S_OK;
382 /***********************************************************************
383 * OleRegGetUserType (OLE32.122)
385 * This implementation of OleRegGetUserType ignores the dwFormOfType
386 * parameter and always returns the full name of the object. This is
387 * not too bad since this is the case for many objects because of the
388 * way they are registered.
390 HRESULT WINAPI OleRegGetUserType(
391 REFCLSID clsid,
392 DWORD dwFormOfType,
393 LPOLESTR* pszUserType)
395 char xclsid[50];
396 char keyName[60];
397 DWORD dwKeyType;
398 DWORD cbData;
399 HKEY clsidKey;
400 LONG hres;
403 * Initialize the out parameter.
405 *pszUserType = NULL;
408 * Build the key name we're looking for
410 WINE_StringFromCLSID((LPCLSID)clsid, xclsid);
412 strcpy(keyName, "CLSID\\");
413 strcat(keyName, xclsid);
414 strcat(keyName, "\\");
416 TRACE(ole,"(%s, %ld, %p)\n", keyName, dwFormOfType, pszUserType);
419 * Open the class id Key
421 hres = RegOpenKeyA(HKEY_CLASSES_ROOT,
422 keyName,
423 &clsidKey);
425 if (hres != ERROR_SUCCESS)
426 return REGDB_E_CLASSNOTREG;
429 * Retrieve the size of the name string.
431 cbData = 0;
433 hres = RegQueryValueExA(clsidKey,
435 NULL,
436 &dwKeyType,
437 NULL,
438 &cbData);
440 if (hres!=ERROR_SUCCESS)
442 RegCloseKey(clsidKey);
443 return REGDB_E_READREGDB;
447 * Allocate a buffer for the registry value.
449 *pszUserType = CoTaskMemAlloc(cbData);
451 if (*pszUserType==NULL)
453 RegCloseKey(clsidKey);
454 return E_OUTOFMEMORY;
457 hres = RegQueryValueExA(HKEY_CLASSES_ROOT,
459 NULL,
460 &dwKeyType,
461 (LPBYTE)*pszUserType,
462 &cbData);
464 RegCloseKey(clsidKey);
466 if (hres!=ERROR_SUCCESS)
468 CoTaskMemFree(*pszUserType);
469 *pszUserType=NULL;
471 return REGDB_E_READREGDB;
474 return S_OK;
477 /***********************************************************************
478 * DoDragDrop32 [OLE32.65]
480 HRESULT WINAPI DoDragDrop (
481 IDataObject *pDataObject, /* ptr to the data obj */
482 IDropSource* pDropSource, /* ptr to the source obj */
483 DWORD dwOKEffect, /* effects allowed by the source */
484 DWORD *pdwEffect) /* ptr to effects of the source */
486 TrackerWindowInfo trackerInfo;
487 HWND hwndTrackWindow;
488 MSG msg;
490 TRACE(ole,"(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
493 * Setup the drag n drop tracking window.
495 trackerInfo.dataObject = pDataObject;
496 trackerInfo.dropSource = pDropSource;
497 trackerInfo.dwOKEffect = dwOKEffect;
498 trackerInfo.pdwEffect = pdwEffect;
499 trackerInfo.trackingDone = FALSE;
500 trackerInfo.escPressed = FALSE;
501 trackerInfo.curDragTargetHWND = 0;
502 trackerInfo.curDragTarget = 0;
504 hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS,
505 "TrackerWindow",
506 WS_POPUP,
507 CW_USEDEFAULT, CW_USEDEFAULT,
508 CW_USEDEFAULT, CW_USEDEFAULT,
512 (LPVOID)&trackerInfo);
514 if (hwndTrackWindow!=0)
517 * Capture the mouse input
519 SetCapture(hwndTrackWindow);
522 * Pump messages. All mouse input should go the the capture window.
524 while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )
526 if ( (msg.message >= WM_KEYFIRST) &&
527 (msg.message <= WM_KEYFIRST) )
530 * When keyboard messages are sent to windows on this thread, we
531 * want to ignore notify the drop source that the state changed.
532 * in the case of the Escape key, we also notify the drop source
533 * we give it a special meaning.
535 if ( (msg.message==WM_KEYDOWN) &&
536 (msg.wParam==VK_ESCAPE) )
538 trackerInfo.escPressed = TRUE;
542 * Notify the drop source.
544 OLEDD_TrackStateChange(&trackerInfo,
545 msg.pt,
546 OLEDD_GetButtonState());
548 else
551 * Dispatch the messages only when it's not a keyboard message.
553 DispatchMessageA(&msg);
558 * Destroy the temporary window.
560 DestroyWindow(hwndTrackWindow);
562 return trackerInfo.returnValue;
565 return E_FAIL;
568 /***********************************************************************
569 * OleQueryLinkFromData32 [OLE32.118]
571 HRESULT WINAPI OleQueryLinkFromData(
572 IDataObject* pSrcDataObject)
574 FIXME(ole,"(%p),stub!\n", pSrcDataObject);
575 return S_OK;
578 /***********************************************************************
579 * OleRegGetMiscStatus [OLE32.121]
581 HRESULT WINAPI OleRegGetMiscStatus(
582 REFCLSID clsid,
583 DWORD dwAspect,
584 DWORD* pdwStatus)
586 char xclsid[50];
587 char keyName[60];
588 HKEY clsidKey;
589 HKEY miscStatusKey;
590 HKEY aspectKey;
591 LONG result;
594 * Initialize the out parameter.
596 *pdwStatus = 0;
599 * Build the key name we're looking for
601 WINE_StringFromCLSID((LPCLSID)clsid, xclsid);
603 strcpy(keyName, "CLSID\\");
604 strcat(keyName, xclsid);
605 strcat(keyName, "\\");
607 TRACE(ole,"(%s, %ld, %p)\n", keyName, dwAspect, pdwStatus);
610 * Open the class id Key
612 result = RegOpenKeyA(HKEY_CLASSES_ROOT,
613 keyName,
614 &clsidKey);
616 if (result != ERROR_SUCCESS)
617 return REGDB_E_CLASSNOTREG;
620 * Get the MiscStatus
622 result = RegOpenKeyA(clsidKey,
623 "MiscStatus",
624 &miscStatusKey);
627 if (result != ERROR_SUCCESS)
629 RegCloseKey(clsidKey);
630 return REGDB_E_READREGDB;
634 * Read the default value
636 OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
639 * Open the key specific to the requested aspect.
641 sprintf(keyName, "%ld", dwAspect);
643 result = RegOpenKeyA(miscStatusKey,
644 keyName,
645 &aspectKey);
647 if (result == ERROR_SUCCESS)
649 OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
650 RegCloseKey(aspectKey);
654 * Cleanup
656 RegCloseKey(miscStatusKey);
657 RegCloseKey(clsidKey);
659 return S_OK;
662 /******************************************************************************
663 * OleSetContainedObject [OLE32.128]
665 HRESULT WINAPI OleSetContainedObject(
666 LPUNKNOWN pUnknown,
667 BOOL fContained)
669 IRunnableObject* runnable = NULL;
670 HRESULT hres;
672 TRACE(ole,"(%p,%x), stub!\n", pUnknown, fContained);
674 hres = IUnknown_QueryInterface(pUnknown,
675 &IID_IRunnableObject,
676 (void**)&runnable);
678 if (SUCCEEDED(hres))
680 hres = IRunnableObject_SetContainedObject(runnable, fContained);
682 IRunnableObject_Release(runnable);
684 return hres;
687 return S_OK;
690 /******************************************************************************
691 * OleLoad [OLE32.112]
693 HRESULT WINAPI OleLoad(
694 LPSTORAGE pStg,
695 REFIID riid,
696 LPOLECLIENTSITE pClientSite,
697 LPVOID* ppvObj)
699 IPersistStorage* persistStorage = NULL;
700 IOleObject* oleObject = NULL;
701 STATSTG storageInfo;
702 HRESULT hres;
704 TRACE(ole,"(%p,%p,%p,%p)\n", pStg, riid, pClientSite, ppvObj);
707 * TODO, Conversion ... OleDoAutoConvert
711 * Get the class ID for the object.
713 hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
716 * Now, try and create the handler for the object
718 hres = CoCreateInstance(&storageInfo.clsid,
719 NULL,
720 CLSCTX_INPROC_HANDLER,
721 &IID_IOleObject,
722 (void**)&oleObject);
725 * If that fails, as it will most times, load the default
726 * OLE handler.
728 if (FAILED(hres))
730 hres = OleCreateDefaultHandler(&storageInfo.clsid,
731 NULL,
732 &IID_IOleObject,
733 (void**)&oleObject);
737 * If we couldn't find a handler... this is bad. Abort the whole thing.
739 if (FAILED(hres))
740 return hres;
743 * Inform the new object of it's client site.
745 hres = IOleObject_SetClientSite(oleObject, pClientSite);
748 * Initialize the object with it's IPersistStorage interface.
750 hres = IOleObject_QueryInterface(oleObject,
751 &IID_IPersistStorage,
752 (void**)&persistStorage);
754 if (SUCCEEDED(hres))
756 IPersistStorage_Load(persistStorage, pStg);
758 IPersistStorage_Release(persistStorage);
759 persistStorage = NULL;
763 * Return the requested interface to the caller.
765 hres = IOleObject_QueryInterface(oleObject, riid, ppvObj);
768 * Cleanup interfaces used internally
770 IOleObject_Release(oleObject);
772 return hres;
775 /***********************************************************************
776 * OleGetClipboard32 [OLE32.105]
778 HRESULT WINAPI OleGetClipboard(
779 IDataObject** ppDataObj)
781 FIXME(ole,"(%p),stub!\n", ppDataObj);
783 if (ppDataObj)
784 *ppDataObj=0;
786 return E_FAIL;
790 /**************************************************************************
791 * Internal methods to manage the shared OLE menu in response to the
792 * OLE***MenuDescriptor API
795 /***
796 * OLEMenu_Initialize()
798 * Initializes the OLEMENU data structures.
800 static void OLEMenu_Initialize()
802 /* Create a dynamic pointer array to store the hook handles */
803 if ( !OLEMenu_MsgHookDPA )
804 OLEMenu_MsgHookDPA = DPA_CreateEx( 2, GetProcessHeap() );
807 /***
808 * OLEMenu_UnInitialize()
810 * Releases the OLEMENU data structures.
812 static void OLEMenu_UnInitialize()
814 /* Release the hook table */
815 if ( OLEMenu_MsgHookDPA )
816 DPA_Destroy( OLEMenu_MsgHookDPA );
818 OLEMenu_MsgHookDPA = NULL;
821 /*************************************************************************
822 * OLEMenu_InstallHooks
823 * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
825 * RETURNS: TRUE if message hooks were succesfully installed
826 * FALSE on failure
828 BOOL OLEMenu_InstallHooks( DWORD tid )
830 OleMenuHookItem *pHookItem = NULL;
832 if ( !OLEMenu_MsgHookDPA ) /* No hook table? Create one */
834 /* Create a dynamic pointer array to store the hook handles */
835 if ( !(OLEMenu_MsgHookDPA = DPA_CreateEx( 2, GetProcessHeap() )) )
836 return FALSE;
839 /* Create an entry for the hook table */
840 if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
841 sizeof(OleMenuHookItem)) ) )
842 return FALSE;
844 pHookItem->tid = tid;
845 pHookItem->hHeap = GetProcessHeap();
847 /* Install a thread scope message hook for WH_GETMESSAGE */
848 pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc,
849 0, GetCurrentThreadId() );
850 if ( !pHookItem->GetMsg_hHook )
851 goto CLEANUP;
853 /* Install a thread scope message hook for WH_CALLWNDPROC */
854 pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc,
855 0, GetCurrentThreadId() );
856 if ( !pHookItem->CallWndProc_hHook )
857 goto CLEANUP;
859 /* Insert the hook table entry */
860 if ( -1 == DPA_InsertPtr( OLEMenu_MsgHookDPA, 0, pHookItem ) )
861 goto CLEANUP;
863 return TRUE;
865 CLEANUP:
866 /* Unhook any hooks */
867 if ( pHookItem->GetMsg_hHook )
868 UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
869 if ( pHookItem->CallWndProc_hHook )
870 UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
871 /* Release the hook table entry */
872 HeapFree(pHookItem->hHeap, 0, pHookItem );
874 return FALSE;
877 /*************************************************************************
878 * OLEMenu_UnInstallHooks
879 * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
881 * RETURNS: TRUE if message hooks were succesfully installed
882 * FALSE on failure
884 BOOL OLEMenu_UnInstallHooks( DWORD tid )
886 INT ixHook;
887 OleMenuHookItem *pHookItem = NULL;
889 if ( !OLEMenu_MsgHookDPA ) /* No hooks set */
890 return TRUE;
892 /* Lookup the hHook index for this tid */
893 if ( !OLEMenu_IsHookInstalled( tid , &ixHook ) )
894 return TRUE;
896 /* Remove the hook entry from the table(the pointer itself is not deleted) */
897 if ( !( pHookItem = DPA_DeletePtr(OLEMenu_MsgHookDPA, ixHook) ) )
898 return FALSE;
900 /* Uninstall the hooks installed for this thread */
901 if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
902 goto CLEANUP;
903 if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
904 goto CLEANUP;
906 /* Release the hook table entry */
907 HeapFree(pHookItem->hHeap, 0, pHookItem );
909 return TRUE;
911 CLEANUP:
912 /* Release the hook table entry */
913 if (pHookItem)
914 HeapFree(pHookItem->hHeap, 0, pHookItem );
916 return FALSE;
919 /*************************************************************************
920 * OLEMenu_IsHookInstalled
921 * Tests if OLEMenu hooks have been installed for a thread
923 * RETURNS: The pointer and index of the hook table entry for the tid
924 * NULL and -1 for the index if no hooks were installed for this thread
926 OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid, INT *pixHook )
928 INT ixHook;
929 OleMenuHookItem *pHookItem = NULL;
931 if ( pixHook )
932 *pixHook = -1;
934 if ( !OLEMenu_MsgHookDPA ) /* No hooks set */
935 return NULL;
937 /* Do a simple linear search for an entry whose tid matches ours.
938 * We really need a map but efficiency is not a concern here. */
939 for( ixHook = 0; ; ixHook++ )
941 /* Retrieve the hook entry */
942 if ( !( pHookItem = DPA_GetPtr(OLEMenu_MsgHookDPA, ixHook) ) )
943 return NULL;
945 if ( tid == pHookItem->tid )
947 if ( pixHook )
948 *pixHook = ixHook;
949 return pHookItem;
953 return NULL;
956 /***********************************************************************
957 * OLEMenu_FindMainMenuIndex
959 * Used by OLEMenu API to find the top level group a menu item belongs to.
960 * On success pnPos contains the index of the item in the top level menu group
962 * RETURNS: TRUE if the ID was found, FALSE on failure
964 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
966 UINT i, nItems;
968 nItems = GetMenuItemCount( hMainMenu );
970 for (i = 0; i < nItems; i++)
972 HMENU hsubmenu;
974 /* Is the current item a submenu? */
975 if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
977 /* If the handle is the same we're done */
978 if ( hsubmenu == hPopupMenu )
980 if (pnPos)
981 *pnPos = i;
982 return TRUE;
984 /* Recursively search without updating pnPos */
985 else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
987 if (pnPos)
988 *pnPos = i;
989 return TRUE;
994 return FALSE;
997 /***********************************************************************
998 * OLEMenu_SetIsServerMenu
1000 * Checks whether a popup menu belongs to a shared menu group which is
1001 * owned by the server, and sets the menu descriptor state accordingly.
1002 * All menu messages from these groups should be routed to the server.
1004 * RETURNS: TRUE if the popup menu is part of a server owned group
1005 * FASE if the popup menu is part of a container owned group
1007 BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
1009 UINT nPos = 0, nWidth, i;
1011 pOleMenuDescriptor->bIsServerItem = FALSE;
1013 /* Don't bother searching if the popup is the combined menu itself */
1014 if ( hmenu == pOleMenuDescriptor->hmenuCombined )
1015 return FALSE;
1017 /* Find the menu item index in the shared OLE menu that this item belongs to */
1018 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) )
1019 return FALSE;
1021 /* The group widths array has counts for the number of elements
1022 * in the groups File, Edit, Container, Object, Window, Help.
1023 * The Edit, Object & Help groups belong to the server object
1024 * and the other three belong to the container.
1025 * Loop thru the group widths and locate the group we are a member of.
1027 for ( i = 0, nWidth = 0; i < 6; i++ )
1029 nWidth += pOleMenuDescriptor->mgw.width[i];
1030 if ( nPos < nWidth )
1032 /* Odd elements are server menu widths */
1033 pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;
1034 break;
1038 return pOleMenuDescriptor->bIsServerItem;
1041 /*************************************************************************
1042 * OLEMenu_CallWndProc
1043 * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
1044 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1046 LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
1048 LPCWPSTRUCT pMsg = NULL;
1049 HOLEMENU hOleMenu = 0;
1050 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1051 OleMenuHookItem *pHookItem = NULL;
1052 WORD fuFlags;
1054 TRACE(ole,"%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1056 /* Check if we're being asked to process the message */
1057 if ( HC_ACTION != code )
1058 goto NEXTHOOK;
1060 /* Retrieve the current message being dispatched from lParam */
1061 pMsg = (LPCWPSTRUCT)lParam;
1063 /* Check if the message is destined for a window we are interested in:
1064 * If the window has an OLEMenu property we may need to dispatch
1065 * the menu message to its active objects window instead. */
1067 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1068 if ( !hOleMenu )
1069 goto NEXTHOOK;
1071 /* Get the menu descriptor */
1072 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1073 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1074 goto NEXTHOOK;
1076 /* Process menu messages */
1077 switch( pMsg->message )
1079 case WM_INITMENU:
1081 /* Reset the menu descriptor state */
1082 pOleMenuDescriptor->bIsServerItem = FALSE;
1084 /* Send this message to the server as well */
1085 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1086 pMsg->message, pMsg->wParam, pMsg->lParam );
1087 goto NEXTHOOK;
1090 case WM_INITMENUPOPUP:
1092 /* Save the state for whether this is a server owned menu */
1093 OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
1094 break;
1097 case WM_MENUSELECT:
1099 fuFlags = HIWORD(pMsg->wParam); /* Get flags */
1100 if ( fuFlags & MF_SYSMENU )
1101 goto NEXTHOOK;
1103 /* Save the state for whether this is a server owned popup menu */
1104 else if ( fuFlags & MF_POPUP )
1105 OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
1107 break;
1110 case WM_DRAWITEM:
1112 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
1113 if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
1114 goto NEXTHOOK; /* Not a menu message */
1116 break;
1119 default:
1120 goto NEXTHOOK;
1123 /* If the message was for the server dispatch it accordingly */
1124 if ( pOleMenuDescriptor->bIsServerItem )
1126 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1127 pMsg->message, pMsg->wParam, pMsg->lParam );
1130 NEXTHOOK:
1131 if ( pOleMenuDescriptor )
1132 GlobalUnlock( hOleMenu );
1134 /* Lookup the hook item for the current thread */
1135 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId(), NULL ) ) )
1137 /* This should never fail!! */
1138 WARN(ole, "could not retrieve hHook for current thread!\n" );
1139 return 0;
1142 /* Pass on the message to the next hooker */
1143 return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
1146 /*************************************************************************
1147 * OLEMenu_GetMsgProc
1148 * Thread scope WH_GETMESSAGE hook proc filter function (callback)
1149 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1151 LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
1153 LPMSG pMsg = NULL;
1154 HOLEMENU hOleMenu = 0;
1155 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1156 OleMenuHookItem *pHookItem = NULL;
1157 WORD wCode;
1159 TRACE(ole,"%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1161 /* Check if we're being asked to process a messages */
1162 if ( HC_ACTION != code )
1163 goto NEXTHOOK;
1165 /* Retrieve the current message being dispatched from lParam */
1166 pMsg = (LPMSG)lParam;
1168 /* Check if the message is destined for a window we are interested in:
1169 * If the window has an OLEMenu property we may need to dispatch
1170 * the menu message to its active objects window instead. */
1172 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1173 if ( !hOleMenu )
1174 goto NEXTHOOK;
1176 /* Process menu messages */
1177 switch( pMsg->message )
1179 case WM_COMMAND:
1181 wCode = HIWORD(pMsg->wParam); /* Get notification code */
1182 if ( wCode )
1183 goto NEXTHOOK; /* Not a menu message */
1184 break;
1186 default:
1187 goto NEXTHOOK;
1190 /* Get the menu descriptor */
1191 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1192 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1193 goto NEXTHOOK;
1195 /* If the message was for the server dispatch it accordingly */
1196 if ( pOleMenuDescriptor->bIsServerItem )
1198 /* Change the hWnd in the message to the active objects hWnd.
1199 * The message loop which reads this message will automatically
1200 * dispatch it to the embedded objects window. */
1201 pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
1204 NEXTHOOK:
1205 if ( pOleMenuDescriptor )
1206 GlobalUnlock( hOleMenu );
1208 /* Lookup the hook item for the current thread */
1209 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId(), NULL ) ) )
1211 /* This should never fail!! */
1212 WARN(ole, "could not retrieve hHook for current thread!\n" );
1213 return FALSE;
1216 /* Pass on the message to the next hooker */
1217 return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
1220 /***********************************************************************
1221 * OleCreateMenuDescriptor [OLE32.97]
1222 * Creates an OLE menu descriptor for OLE to use when dispatching
1223 * menu messages and commands.
1225 * PARAMS:
1226 * hmenuCombined - Handle to the objects combined menu
1227 * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group
1230 HOLEMENU WINAPI OleCreateMenuDescriptor(
1231 HMENU hmenuCombined,
1232 LPOLEMENUGROUPWIDTHS lpMenuWidths)
1234 HOLEMENU hOleMenu;
1235 OleMenuDescriptor *pOleMenuDescriptor;
1236 int i;
1238 if ( !hmenuCombined || !lpMenuWidths )
1239 return 0;
1241 /* Create an OLE menu descriptor */
1242 if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
1243 sizeof(OleMenuDescriptor) ) ) )
1244 return 0;
1246 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1247 if ( !pOleMenuDescriptor )
1248 return 0;
1250 /* Initialize menu group widths and hmenu */
1251 for ( i = 0; i < 6; i++ )
1252 pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
1254 pOleMenuDescriptor->hmenuCombined = hmenuCombined;
1255 pOleMenuDescriptor->bIsServerItem = FALSE;
1256 GlobalUnlock( hOleMenu );
1258 return hOleMenu;
1261 /***********************************************************************
1262 * OleDestroyMenuDescriptor [OLE32.99]
1263 * Destroy the shared menu descriptor
1265 HRESULT WINAPI OleDestroyMenuDescriptor(
1266 HOLEMENU hmenuDescriptor)
1268 if ( hmenuDescriptor )
1269 GlobalFree( hmenuDescriptor );
1270 return S_OK;
1273 /***********************************************************************
1274 * OleSetMenuDescriptor [OLE32.129]
1275 * Installs or removes OLE dispatching code for the containers frame window
1276 * FIXME: The lpFrame and lpActiveObject parameters are currently ignored
1277 * OLE should install context sensitive help F1 filtering for the app when
1278 * these are non null.
1280 * PARAMS:
1281 * hOleMenu Handle to composite menu descriptor
1282 * hwndFrame Handle to containers frame window
1283 * hwndActiveObject Handle to objects in-place activation window
1284 * lpFrame Pointer to IOleInPlaceFrame on containers window
1285 * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object
1287 * RETURNS:
1288 * S_OK - menu installed correctly
1289 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1291 HRESULT WINAPI OleSetMenuDescriptor(
1292 HOLEMENU hOleMenu,
1293 HWND hwndFrame,
1294 HWND hwndActiveObject,
1295 LPOLEINPLACEFRAME lpFrame,
1296 LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1298 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1300 /* Check args */
1301 if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
1302 return E_INVALIDARG;
1304 if ( lpFrame || lpActiveObject )
1306 FIXME(ole,"(%x, %x, %x, %p, %p), Context sensitive help filtering not implemented!\n",
1307 (unsigned int)hOleMenu,
1308 hwndFrame,
1309 hwndActiveObject,
1310 lpFrame,
1311 lpActiveObject);
1314 /* Set up a message hook to intercept the containers frame window messages.
1315 * The message filter is responsible for dispatching menu messages from the
1316 * shared menu which are intended for the object.
1319 if ( hOleMenu ) /* Want to install dispatching code */
1321 /* If OLEMenu hooks are already installed for this thread, fail
1322 * Note: This effectively means that OleSetMenuDescriptor cannot
1323 * be called twice in succession on the same frame window
1324 * without first calling it with a null hOleMenu to uninstall */
1325 if ( OLEMenu_IsHookInstalled( GetCurrentThreadId(), NULL ) )
1326 return E_FAIL;
1328 /* Get the menu descriptor */
1329 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1330 if ( !pOleMenuDescriptor )
1331 return E_UNEXPECTED;
1333 /* Update the menu descriptor */
1334 pOleMenuDescriptor->hwndFrame = hwndFrame;
1335 pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
1337 GlobalUnlock( hOleMenu );
1338 pOleMenuDescriptor = NULL;
1340 /* Add a menu descriptor windows property to the frame window */
1341 SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu );
1343 /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
1344 if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
1345 return E_FAIL;
1347 else /* Want to uninstall dispatching code */
1349 /* Uninstall the hooks */
1350 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1351 return E_FAIL;
1353 /* Remove the menu descriptor property from the frame window */
1354 RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" );
1357 return S_OK;
1360 /***********************************************************************
1361 * ReleaseStgMedium [OLE32.140]
1363 void WINAPI ReleaseStgMedium(
1364 STGMEDIUM* pmedium)
1366 switch (pmedium->tymed)
1368 case TYMED_HGLOBAL:
1370 if ( (pmedium->pUnkForRelease==0) &&
1371 (pmedium->u.hGlobal!=0) )
1372 GlobalFree(pmedium->u.hGlobal);
1374 pmedium->u.hGlobal = 0;
1375 break;
1377 case TYMED_FILE:
1379 if (pmedium->u.lpszFileName!=0)
1381 if (pmedium->pUnkForRelease==0)
1383 DeleteFileW(pmedium->u.lpszFileName);
1386 CoTaskMemFree(pmedium->u.lpszFileName);
1389 pmedium->u.lpszFileName = 0;
1390 break;
1392 case TYMED_ISTREAM:
1394 if (pmedium->u.pstm!=0)
1396 IStream_Release(pmedium->u.pstm);
1399 pmedium->u.pstm = 0;
1400 break;
1402 case TYMED_ISTORAGE:
1404 if (pmedium->u.pstg!=0)
1406 IStorage_Release(pmedium->u.pstg);
1409 pmedium->u.pstg = 0;
1410 break;
1412 case TYMED_GDI:
1414 if ( (pmedium->pUnkForRelease==0) &&
1415 (pmedium->u.hGlobal!=0) )
1416 DeleteObject(pmedium->u.hGlobal);
1418 pmedium->u.hGlobal = 0;
1419 break;
1421 case TYMED_MFPICT:
1423 if ( (pmedium->pUnkForRelease==0) &&
1424 (pmedium->u.hMetaFilePict!=0) )
1426 DeleteMetaFile(pmedium->u.hMetaFilePict);
1427 GlobalFree(pmedium->u.hMetaFilePict);
1430 pmedium->u.hMetaFilePict = 0;
1431 break;
1433 case TYMED_ENHMF:
1435 if ( (pmedium->pUnkForRelease==0) &&
1436 (pmedium->u.hEnhMetaFile!=0) )
1438 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
1441 pmedium->u.hEnhMetaFile = 0;
1442 break;
1444 case TYMED_NULL:
1445 default:
1446 break;
1450 * After cleaning up, the unknown is released
1452 if (pmedium->pUnkForRelease!=0)
1454 IUnknown_Release(pmedium->pUnkForRelease);
1455 pmedium->pUnkForRelease = 0;
1459 /***
1460 * OLEDD_Initialize()
1462 * Initializes the OLE drag and drop data structures.
1464 static void OLEDD_Initialize()
1466 WNDCLASSA wndClass;
1468 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1469 wndClass.style = CS_GLOBALCLASS;
1470 wndClass.lpfnWndProc = (WNDPROC)OLEDD_DragTrackerWindowProc;
1471 wndClass.cbClsExtra = 0;
1472 wndClass.cbWndExtra = sizeof(TrackerWindowInfo*);
1473 wndClass.hCursor = 0;
1474 wndClass.hbrBackground = 0;
1475 wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
1477 RegisterClassA (&wndClass);
1480 /***
1481 * OLEDD_UnInitialize()
1483 * Releases the OLE drag and drop data structures.
1485 static void OLEDD_UnInitialize()
1488 * Simply empty the list.
1490 while (targetListHead!=NULL)
1492 RevokeDragDrop(targetListHead->hwndTarget);
1496 /***
1497 * OLEDD_InsertDropTarget()
1499 * Insert the target node in the tree.
1501 static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd)
1503 DropTargetNode* curNode;
1504 DropTargetNode** parentNodeLink;
1507 * Iterate the tree to find the insertion point.
1509 curNode = targetListHead;
1510 parentNodeLink = &targetListHead;
1512 while (curNode!=NULL)
1514 if (nodeToAdd->hwndTarget<curNode->hwndTarget)
1517 * If the node we want to add has a smaller HWND, go left
1519 parentNodeLink = &curNode->prevDropTarget;
1520 curNode = curNode->prevDropTarget;
1522 else if (nodeToAdd->hwndTarget>curNode->hwndTarget)
1525 * If the node we want to add has a larger HWND, go right
1527 parentNodeLink = &curNode->nextDropTarget;
1528 curNode = curNode->nextDropTarget;
1530 else
1533 * The item was found in the list. It shouldn't have been there
1535 assert(FALSE);
1536 return;
1541 * If we get here, we have found a spot for our item. The parentNodeLink
1542 * pointer points to the pointer that we have to modify.
1543 * The curNode should be NULL. We just have to establish the link and Voila!
1545 assert(curNode==NULL);
1546 assert(parentNodeLink!=NULL);
1547 assert(*parentNodeLink==NULL);
1549 *parentNodeLink=nodeToAdd;
1552 /***
1553 * OLEDD_ExtractDropTarget()
1555 * Removes the target node from the tree.
1557 static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget)
1559 DropTargetNode* curNode;
1560 DropTargetNode** parentNodeLink;
1563 * Iterate the tree to find the insertion point.
1565 curNode = targetListHead;
1566 parentNodeLink = &targetListHead;
1568 while (curNode!=NULL)
1570 if (hwndOfTarget<curNode->hwndTarget)
1573 * If the node we want to add has a smaller HWND, go left
1575 parentNodeLink = &curNode->prevDropTarget;
1576 curNode = curNode->prevDropTarget;
1578 else if (hwndOfTarget>curNode->hwndTarget)
1581 * If the node we want to add has a larger HWND, go right
1583 parentNodeLink = &curNode->nextDropTarget;
1584 curNode = curNode->nextDropTarget;
1586 else
1589 * The item was found in the list. Detach it from it's parent and
1590 * re-insert it's kids in the tree.
1592 assert(parentNodeLink!=NULL);
1593 assert(*parentNodeLink==curNode);
1596 * We arbitrately re-attach the left sub-tree to the parent.
1598 *parentNodeLink = curNode->prevDropTarget;
1601 * And we re-insert the right subtree
1603 if (curNode->nextDropTarget!=NULL)
1605 OLEDD_InsertDropTarget(curNode->nextDropTarget);
1609 * The node we found is still a valid node once we complete
1610 * the unlinking of the kids.
1612 curNode->nextDropTarget=NULL;
1613 curNode->prevDropTarget=NULL;
1615 return curNode;
1620 * If we get here, the node is not in the tree
1622 return NULL;
1625 /***
1626 * OLEDD_FindDropTarget()
1628 * Finds information about the drop target.
1630 static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
1632 DropTargetNode* curNode;
1635 * Iterate the tree to find the HWND value.
1637 curNode = targetListHead;
1639 while (curNode!=NULL)
1641 if (hwndOfTarget<curNode->hwndTarget)
1644 * If the node we want to add has a smaller HWND, go left
1646 curNode = curNode->prevDropTarget;
1648 else if (hwndOfTarget>curNode->hwndTarget)
1651 * If the node we want to add has a larger HWND, go right
1653 curNode = curNode->nextDropTarget;
1655 else
1658 * The item was found in the list.
1660 return curNode;
1665 * If we get here, the item is not in the list
1667 return NULL;
1670 /***
1671 * OLEDD_DragTrackerWindowProc()
1673 * This method is the WindowProcedure of the drag n drop tracking
1674 * window. During a drag n Drop operation, an invisible window is created
1675 * to receive the user input and act upon it. This procedure is in charge
1676 * of this behavior.
1678 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
1679 HWND hwnd,
1680 UINT uMsg,
1681 WPARAM wParam,
1682 LPARAM lParam)
1684 switch (uMsg)
1686 case WM_CREATE:
1688 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
1690 SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams);
1693 break;
1695 case WM_MOUSEMOVE:
1697 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1698 POINT mousePos;
1701 * Get the current mouse position in screen coordinates.
1703 mousePos.x = LOWORD(lParam);
1704 mousePos.y = HIWORD(lParam);
1705 ClientToScreen(hwnd, &mousePos);
1708 * Track the movement of the mouse.
1710 OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam);
1712 break;
1714 case WM_LBUTTONUP:
1715 case WM_MBUTTONUP:
1716 case WM_RBUTTONUP:
1717 case WM_LBUTTONDOWN:
1718 case WM_MBUTTONDOWN:
1719 case WM_RBUTTONDOWN:
1721 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1722 POINT mousePos;
1725 * Get the current mouse position in screen coordinates.
1727 mousePos.x = LOWORD(lParam);
1728 mousePos.y = HIWORD(lParam);
1729 ClientToScreen(hwnd, &mousePos);
1732 * Notify everyone that the button state changed
1733 * TODO: Check if the "escape" key was pressed.
1735 OLEDD_TrackStateChange(trackerInfo, mousePos, wParam);
1737 break;
1742 * This is a window proc after all. Let's call the default.
1744 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1747 /***
1748 * OLEDD_TrackMouseMove()
1750 * This method is invoked while a drag and drop operation is in effect.
1751 * it will generate the appropriate callbacks in the drop source
1752 * and drop target. It will also provide the expected feedback to
1753 * the user.
1755 * params:
1756 * trackerInfo - Pointer to the structure identifying the
1757 * drag & drop operation that is currently
1758 * active.
1759 * mousePos - Current position of the mouse in screen
1760 * coordinates.
1761 * keyState - Contains the state of the shift keys and the
1762 * mouse buttons (MK_LBUTTON and the like)
1764 static void OLEDD_TrackMouseMove(
1765 TrackerWindowInfo* trackerInfo,
1766 POINT mousePos,
1767 DWORD keyState)
1769 HWND hwndNewTarget = 0;
1770 HRESULT hr = S_OK;
1773 * Get the handle of the window under the mouse
1775 hwndNewTarget = WindowFromPoint(mousePos);
1778 * Every time, we re-initialize the effects passed to the
1779 * IDropTarget to the effects allowed by the source.
1781 *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
1784 * If we are hovering over the same target as before, send the
1785 * DragOver notification
1787 if ( (trackerInfo->curDragTarget != 0) &&
1788 (trackerInfo->curDragTargetHWND==hwndNewTarget) )
1790 POINTL mousePosParam;
1793 * The documentation tells me that the coordinate should be in the target
1794 * window's coordinate space. However, the tests I made tell me the
1795 * coordinates should be in screen coordinates.
1797 mousePosParam.x = mousePos.x;
1798 mousePosParam.y = mousePos.y;
1800 IDropTarget_DragOver(trackerInfo->curDragTarget,
1801 keyState,
1802 mousePosParam,
1803 trackerInfo->pdwEffect);
1805 else
1807 DropTargetNode* newDropTargetNode = 0;
1810 * If we changed window, we have to notify our old target and check for
1811 * the new one.
1813 if (trackerInfo->curDragTarget!=0)
1815 IDropTarget_DragLeave(trackerInfo->curDragTarget);
1819 * Make sure we're hovering over a window.
1821 if (hwndNewTarget!=0)
1824 * Find-out if there is a drag target under the mouse
1826 newDropTargetNode = OLEDD_FindDropTarget(hwndNewTarget);
1828 trackerInfo->curDragTargetHWND = hwndNewTarget;
1829 trackerInfo->curDragTarget = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
1832 * If there is, notify it that we just dragged-in
1834 if (trackerInfo->curDragTarget!=0)
1836 POINTL mousePosParam;
1839 * The documentation tells me that the coordinate should be in the target
1840 * window's coordinate space. However, the tests I made tell me the
1841 * coordinates should be in screen coordinates.
1843 mousePosParam.x = mousePos.x;
1844 mousePosParam.y = mousePos.y;
1846 IDropTarget_DragEnter(trackerInfo->curDragTarget,
1847 trackerInfo->dataObject,
1848 keyState,
1849 mousePosParam,
1850 trackerInfo->pdwEffect);
1853 else
1856 * The mouse is not over a window so we don't track anything.
1858 trackerInfo->curDragTargetHWND = 0;
1859 trackerInfo->curDragTarget = 0;
1864 * Now that we have done that, we have to tell the source to give
1865 * us feedback on the work being done by the target. If we don't
1866 * have a target, simulate no effect.
1868 if (trackerInfo->curDragTarget==0)
1870 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
1873 hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
1874 *trackerInfo->pdwEffect);
1877 * When we ask for feedback from the drop source, sometimes it will
1878 * do all the necessary work and sometimes it will not handle it
1879 * when that's the case, we must display the standard drag and drop
1880 * cursors.
1882 if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
1884 if ( (*trackerInfo->pdwEffect & DROPEFFECT_MOVE) ||
1885 (*trackerInfo->pdwEffect & DROPEFFECT_COPY) ||
1886 (*trackerInfo->pdwEffect & DROPEFFECT_LINK) )
1888 SetCursor(LoadCursorA(0, IDC_SIZEALLA));
1890 else
1892 SetCursor(LoadCursorA(0, IDC_NOA));
1897 /***
1898 * OLEDD_TrackStateChange()
1900 * This method is invoked while a drag and drop operation is in effect.
1901 * It is used to notify the drop target/drop source callbacks when
1902 * the state of the keyboard or mouse button change.
1904 * params:
1905 * trackerInfo - Pointer to the structure identifying the
1906 * drag & drop operation that is currently
1907 * active.
1908 * mousePos - Current position of the mouse in screen
1909 * coordinates.
1910 * keyState - Contains the state of the shift keys and the
1911 * mouse buttons (MK_LBUTTON and the like)
1913 static void OLEDD_TrackStateChange(
1914 TrackerWindowInfo* trackerInfo,
1915 POINT mousePos,
1916 DWORD keyState)
1919 * Ask the drop source what to do with the operation.
1921 trackerInfo->returnValue = IDropSource_QueryContinueDrag(
1922 trackerInfo->dropSource,
1923 trackerInfo->escPressed,
1924 keyState);
1927 * All the return valued will stop the operation except the S_OK
1928 * return value.
1930 if (trackerInfo->returnValue!=S_OK)
1933 * Make sure the message loop in DoDragDrop stops
1935 trackerInfo->trackingDone = TRUE;
1938 * Release the mouse in case the drop target decides to show a popup
1939 * or a menu or something.
1941 ReleaseCapture();
1944 * If we end-up over a target, drop the object in the target or
1945 * inform the target that the operation was cancelled.
1947 if (trackerInfo->curDragTarget!=0)
1949 switch (trackerInfo->returnValue)
1952 * If the source wants us to complete the operation, we tell
1953 * the drop target that we just dropped the object in it.
1955 case DRAGDROP_S_DROP:
1957 POINTL mousePosParam;
1960 * The documentation tells me that the coordinate should be
1961 * in the target window's coordinate space. However, the tests
1962 * I made tell me the coordinates should be in screen coordinates.
1964 mousePosParam.x = mousePos.x;
1965 mousePosParam.y = mousePos.y;
1967 IDropTarget_Drop(trackerInfo->curDragTarget,
1968 trackerInfo->dataObject,
1969 keyState,
1970 mousePosParam,
1971 trackerInfo->pdwEffect);
1972 break;
1975 * If the source told us that we should cancel, fool the drop
1976 * target by telling it that the mouse left it's window.
1978 case DRAGDROP_S_CANCEL:
1979 IDropTarget_DragLeave(trackerInfo->curDragTarget);
1980 break;
1986 /***
1987 * OLEDD_GetButtonState()
1989 * This method will use the current state of the keyboard to build
1990 * a button state mask equivalent to the one passed in the
1991 * WM_MOUSEMOVE wParam.
1993 static DWORD OLEDD_GetButtonState()
1995 BYTE keyboardState[256];
1996 DWORD keyMask = 0;
1998 GetKeyboardState(keyboardState);
2000 if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
2001 keyMask |= MK_SHIFT;
2003 if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
2004 keyMask |= MK_CONTROL;
2006 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
2007 keyMask |= MK_LBUTTON;
2009 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
2010 keyMask |= MK_RBUTTON;
2012 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
2013 keyMask |= MK_MBUTTON;
2015 return keyMask;
2018 /***
2019 * OLEDD_GetButtonState()
2021 * This method will read the default value of the registry key in
2022 * parameter and extract a DWORD value from it. The registry key value
2023 * can be in a string key or a DWORD key.
2025 * params:
2026 * regKey - Key to read the default value from
2027 * pdwValue - Pointer to the location where the DWORD
2028 * value is returned. This value is not modified
2029 * if the value is not found.
2032 static void OLEUTL_ReadRegistryDWORDValue(
2033 HKEY regKey,
2034 DWORD* pdwValue)
2036 char buffer[20];
2037 DWORD dwKeyType;
2038 DWORD cbData = 20;
2039 LONG lres;
2041 lres = RegQueryValueExA(regKey,
2043 NULL,
2044 &dwKeyType,
2045 (LPBYTE)buffer,
2046 &cbData);
2048 if (lres==ERROR_SUCCESS)
2050 switch (dwKeyType)
2052 case REG_DWORD:
2053 *pdwValue = *(DWORD*)buffer;
2054 break;
2055 case REG_EXPAND_SZ:
2056 case REG_MULTI_SZ:
2057 case REG_SZ:
2058 *pdwValue = (DWORD)strtoul(buffer, NULL, 10);
2059 break;