Added support for WODM_BREAKLOOP message.
[wine.git] / dlls / ole32 / ole2.c
blob7fe9f423dc41f13418fae61dae199d19951f8be2
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 <string.h>
13 #include "winuser.h"
14 #include "winerror.h"
15 #include "ole2.h"
16 #include "process.h"
17 #include "commctrl.h"
18 #include "wine/obj_clientserver.h"
19 #include "wine/wingdi16.h"
20 #include "debugtools.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 OLE Clipboard initialization methods (in clipboard.c)
111 void OLEClipbrd_UnInitialize();
112 void OLEClipbrd_Initialize();
114 /******************************************************************************
115 * These are the prototypes of the utility methods used for OLE Drag n Drop
117 static void OLEDD_Initialize();
118 static void OLEDD_UnInitialize();
119 static void OLEDD_InsertDropTarget(
120 DropTargetNode* nodeToAdd);
121 static DropTargetNode* OLEDD_ExtractDropTarget(
122 HWND hwndOfTarget);
123 static DropTargetNode* OLEDD_FindDropTarget(
124 HWND hwndOfTarget);
125 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
126 HWND hwnd,
127 UINT uMsg,
128 WPARAM wParam,
129 LPARAM lParam);
130 static void OLEDD_TrackMouseMove(
131 TrackerWindowInfo* trackerInfo,
132 POINT mousePos,
133 DWORD keyState);
134 static void OLEDD_TrackStateChange(
135 TrackerWindowInfo* trackerInfo,
136 POINT mousePos,
137 DWORD keyState);
138 static DWORD OLEDD_GetButtonState();
141 /******************************************************************************
142 * OleBuildVersion [OLE2.1]
144 DWORD WINAPI OleBuildVersion(void)
146 TRACE("Returning version %d, build %d.\n", rmm, rup);
147 return (rmm<<16)+rup;
150 /***********************************************************************
151 * OleInitialize (OLE2.2) (OLE32.108)
153 HRESULT WINAPI OleInitialize(LPVOID reserved)
155 HRESULT hr;
157 TRACE("(%p)\n", reserved);
160 * The first duty of the OleInitialize is to initialize the COM libraries.
162 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
165 * If the CoInitializeEx call failed, the OLE libraries can't be
166 * initialized.
168 if (FAILED(hr))
169 return hr;
172 * Then, it has to initialize the OLE specific modules.
173 * This includes:
174 * Clipboard
175 * Drag and Drop
176 * Object linking and Embedding
177 * In-place activation
179 if (OLE_moduleLockCount==0)
182 * Initialize the libraries.
184 TRACE("() - Initializing the OLE libraries\n");
187 * OLE Clipboard
189 OLEClipbrd_Initialize();
192 * Drag and Drop
194 OLEDD_Initialize();
197 * OLE shared menu
199 OLEMenu_Initialize();
203 * Then, we increase the lock count on the OLE module.
205 OLE_moduleLockCount++;
207 return hr;
210 /******************************************************************************
211 * CoGetCurrentProcess [COMPOBJ.34] [OLE2.2][OLE32.108]
213 * NOTES
214 * Is DWORD really the correct return type for this function?
216 DWORD WINAPI CoGetCurrentProcess(void) {
217 return (DWORD)PROCESS_Current();
220 /******************************************************************************
221 * OleUninitialize [OLE2.3] [OLE32.131]
223 void WINAPI OleUninitialize(void)
225 TRACE("()\n");
228 * Decrease the lock count on the OLE module.
230 OLE_moduleLockCount--;
233 * If we hit the bottom of the lock stack, free the libraries.
235 if (OLE_moduleLockCount==0)
238 * Actually free the libraries.
240 TRACE("() - Freeing the last reference count\n");
243 * OLE Clipboard
245 OLEClipbrd_UnInitialize();
248 * Drag and Drop
250 OLEDD_UnInitialize();
253 * OLE shared menu
255 OLEMenu_UnInitialize();
259 * Then, uninitialize the COM libraries.
261 CoUninitialize();
264 /******************************************************************************
265 * CoRegisterMessageFilter32 [OLE32.38]
267 HRESULT WINAPI CoRegisterMessageFilter(
268 LPMESSAGEFILTER lpMessageFilter, /* Pointer to interface */
269 LPMESSAGEFILTER *lplpMessageFilter /* Indirect pointer to prior instance if non-NULL */
271 FIXME("stub\n");
272 if (lplpMessageFilter) {
273 *lplpMessageFilter = NULL;
275 return S_OK;
278 /******************************************************************************
279 * OleInitializeWOW [OLE32.109]
281 HRESULT WINAPI OleInitializeWOW(DWORD x) {
282 FIXME("(0x%08lx),stub!\n",x);
283 return 0;
286 /***********************************************************************
287 * RegisterDragDrop16 (OLE2.35)
289 HRESULT WINAPI RegisterDragDrop16(
290 HWND16 hwnd,
291 LPDROPTARGET pDropTarget
293 FIXME("(0x%04x,%p),stub!\n",hwnd,pDropTarget);
294 return S_OK;
297 /***********************************************************************
298 * RegisterDragDrop32 (OLE32.139)
300 HRESULT WINAPI RegisterDragDrop(
301 HWND hwnd,
302 LPDROPTARGET pDropTarget)
304 DropTargetNode* dropTargetInfo;
306 TRACE("(0x%x,%p)\n", hwnd, pDropTarget);
309 * First, check if the window is already registered.
311 dropTargetInfo = OLEDD_FindDropTarget(hwnd);
313 if (dropTargetInfo!=NULL)
314 return DRAGDROP_E_ALREADYREGISTERED;
317 * If it's not there, we can add it. We first create a node for it.
319 dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));
321 if (dropTargetInfo==NULL)
322 return E_OUTOFMEMORY;
324 dropTargetInfo->hwndTarget = hwnd;
325 dropTargetInfo->prevDropTarget = NULL;
326 dropTargetInfo->nextDropTarget = NULL;
329 * Don't forget that this is an interface pointer, need to nail it down since
330 * we keep a copy of it.
332 dropTargetInfo->dropTarget = pDropTarget;
333 IDropTarget_AddRef(dropTargetInfo->dropTarget);
335 OLEDD_InsertDropTarget(dropTargetInfo);
337 return S_OK;
340 /***********************************************************************
341 * RevokeDragDrop16 (OLE2.36)
343 HRESULT WINAPI RevokeDragDrop16(
344 HWND16 hwnd
346 FIXME("(0x%04x),stub!\n",hwnd);
347 return S_OK;
350 /***********************************************************************
351 * RevokeDragDrop32 (OLE32.141)
353 HRESULT WINAPI RevokeDragDrop(
354 HWND hwnd)
356 DropTargetNode* dropTargetInfo;
358 TRACE("(0x%x)\n", hwnd);
361 * First, check if the window is already registered.
363 dropTargetInfo = OLEDD_ExtractDropTarget(hwnd);
366 * If it ain't in there, it's an error.
368 if (dropTargetInfo==NULL)
369 return DRAGDROP_E_NOTREGISTERED;
372 * If it's in there, clean-up it's used memory and
373 * references
375 IDropTarget_Release(dropTargetInfo->dropTarget);
376 HeapFree(GetProcessHeap(), 0, dropTargetInfo);
378 return S_OK;
381 /***********************************************************************
382 * OleRegGetUserType (OLE32.122)
384 * This implementation of OleRegGetUserType ignores the dwFormOfType
385 * parameter and always returns the full name of the object. This is
386 * not too bad since this is the case for many objects because of the
387 * way they are registered.
389 HRESULT WINAPI OleRegGetUserType(
390 REFCLSID clsid,
391 DWORD dwFormOfType,
392 LPOLESTR* pszUserType)
394 char xclsid[50];
395 char keyName[60];
396 DWORD dwKeyType;
397 DWORD cbData;
398 HKEY clsidKey;
399 LONG hres;
402 * Initialize the out parameter.
404 *pszUserType = NULL;
407 * Build the key name we're looking for
409 WINE_StringFromCLSID((LPCLSID)clsid, xclsid);
411 strcpy(keyName, "CLSID\\");
412 strcat(keyName, xclsid);
413 strcat(keyName, "\\");
415 TRACE("(%s, %ld, %p)\n", keyName, dwFormOfType, pszUserType);
418 * Open the class id Key
420 hres = RegOpenKeyA(HKEY_CLASSES_ROOT,
421 keyName,
422 &clsidKey);
424 if (hres != ERROR_SUCCESS)
425 return REGDB_E_CLASSNOTREG;
428 * Retrieve the size of the name string.
430 cbData = 0;
432 hres = RegQueryValueExA(clsidKey,
434 NULL,
435 &dwKeyType,
436 NULL,
437 &cbData);
439 if (hres!=ERROR_SUCCESS)
441 RegCloseKey(clsidKey);
442 return REGDB_E_READREGDB;
446 * Allocate a buffer for the registry value.
448 *pszUserType = CoTaskMemAlloc(cbData);
450 if (*pszUserType==NULL)
452 RegCloseKey(clsidKey);
453 return E_OUTOFMEMORY;
456 hres = RegQueryValueExA(HKEY_CLASSES_ROOT,
458 NULL,
459 &dwKeyType,
460 (LPBYTE)*pszUserType,
461 &cbData);
463 RegCloseKey(clsidKey);
465 if (hres!=ERROR_SUCCESS)
467 CoTaskMemFree(*pszUserType);
468 *pszUserType=NULL;
470 return REGDB_E_READREGDB;
473 return S_OK;
476 /***********************************************************************
477 * DoDragDrop32 [OLE32.65]
479 HRESULT WINAPI DoDragDrop (
480 IDataObject *pDataObject, /* ptr to the data obj */
481 IDropSource* pDropSource, /* ptr to the source obj */
482 DWORD dwOKEffect, /* effects allowed by the source */
483 DWORD *pdwEffect) /* ptr to effects of the source */
485 TrackerWindowInfo trackerInfo;
486 HWND hwndTrackWindow;
487 MSG msg;
489 TRACE("(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
492 * Setup the drag n drop tracking window.
494 trackerInfo.dataObject = pDataObject;
495 trackerInfo.dropSource = pDropSource;
496 trackerInfo.dwOKEffect = dwOKEffect;
497 trackerInfo.pdwEffect = pdwEffect;
498 trackerInfo.trackingDone = FALSE;
499 trackerInfo.escPressed = FALSE;
500 trackerInfo.curDragTargetHWND = 0;
501 trackerInfo.curDragTarget = 0;
503 hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS,
504 "TrackerWindow",
505 WS_POPUP,
506 CW_USEDEFAULT, CW_USEDEFAULT,
507 CW_USEDEFAULT, CW_USEDEFAULT,
511 (LPVOID)&trackerInfo);
513 if (hwndTrackWindow!=0)
516 * Capture the mouse input
518 SetCapture(hwndTrackWindow);
521 * Pump messages. All mouse input should go the the capture window.
523 while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )
525 if ( (msg.message >= WM_KEYFIRST) &&
526 (msg.message <= WM_KEYFIRST) )
529 * When keyboard messages are sent to windows on this thread, we
530 * want to ignore notify the drop source that the state changed.
531 * in the case of the Escape key, we also notify the drop source
532 * we give it a special meaning.
534 if ( (msg.message==WM_KEYDOWN) &&
535 (msg.wParam==VK_ESCAPE) )
537 trackerInfo.escPressed = TRUE;
541 * Notify the drop source.
543 OLEDD_TrackStateChange(&trackerInfo,
544 msg.pt,
545 OLEDD_GetButtonState());
547 else
550 * Dispatch the messages only when it's not a keyboard message.
552 DispatchMessageA(&msg);
557 * Destroy the temporary window.
559 DestroyWindow(hwndTrackWindow);
561 return trackerInfo.returnValue;
564 return E_FAIL;
567 /***********************************************************************
568 * OleQueryLinkFromData32 [OLE32.118]
570 HRESULT WINAPI OleQueryLinkFromData(
571 IDataObject* pSrcDataObject)
573 FIXME("(%p),stub!\n", pSrcDataObject);
574 return S_OK;
577 /***********************************************************************
578 * OleRegGetMiscStatus [OLE32.121]
580 HRESULT WINAPI OleRegGetMiscStatus(
581 REFCLSID clsid,
582 DWORD dwAspect,
583 DWORD* pdwStatus)
585 char xclsid[50];
586 char keyName[60];
587 HKEY clsidKey;
588 HKEY miscStatusKey;
589 HKEY aspectKey;
590 LONG result;
593 * Initialize the out parameter.
595 *pdwStatus = 0;
598 * Build the key name we're looking for
600 WINE_StringFromCLSID((LPCLSID)clsid, xclsid);
602 strcpy(keyName, "CLSID\\");
603 strcat(keyName, xclsid);
604 strcat(keyName, "\\");
606 TRACE("(%s, %ld, %p)\n", keyName, dwAspect, pdwStatus);
609 * Open the class id Key
611 result = RegOpenKeyA(HKEY_CLASSES_ROOT,
612 keyName,
613 &clsidKey);
615 if (result != ERROR_SUCCESS)
616 return REGDB_E_CLASSNOTREG;
619 * Get the MiscStatus
621 result = RegOpenKeyA(clsidKey,
622 "MiscStatus",
623 &miscStatusKey);
626 if (result != ERROR_SUCCESS)
628 RegCloseKey(clsidKey);
629 return REGDB_E_READREGDB;
633 * Read the default value
635 OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
638 * Open the key specific to the requested aspect.
640 sprintf(keyName, "%ld", dwAspect);
642 result = RegOpenKeyA(miscStatusKey,
643 keyName,
644 &aspectKey);
646 if (result == ERROR_SUCCESS)
648 OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
649 RegCloseKey(aspectKey);
653 * Cleanup
655 RegCloseKey(miscStatusKey);
656 RegCloseKey(clsidKey);
658 return S_OK;
661 /******************************************************************************
662 * OleSetContainedObject [OLE32.128]
664 HRESULT WINAPI OleSetContainedObject(
665 LPUNKNOWN pUnknown,
666 BOOL fContained)
668 IRunnableObject* runnable = NULL;
669 HRESULT hres;
671 TRACE("(%p,%x), stub!\n", pUnknown, fContained);
673 hres = IUnknown_QueryInterface(pUnknown,
674 &IID_IRunnableObject,
675 (void**)&runnable);
677 if (SUCCEEDED(hres))
679 hres = IRunnableObject_SetContainedObject(runnable, fContained);
681 IRunnableObject_Release(runnable);
683 return hres;
686 return S_OK;
689 /******************************************************************************
690 * OleLoad [OLE32.112]
692 HRESULT WINAPI OleLoad(
693 LPSTORAGE pStg,
694 REFIID riid,
695 LPOLECLIENTSITE pClientSite,
696 LPVOID* ppvObj)
698 IPersistStorage* persistStorage = NULL;
699 IOleObject* oleObject = NULL;
700 STATSTG storageInfo;
701 HRESULT hres;
703 TRACE("(%p,%p,%p,%p)\n", pStg, riid, pClientSite, ppvObj);
706 * TODO, Conversion ... OleDoAutoConvert
710 * Get the class ID for the object.
712 hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
715 * Now, try and create the handler for the object
717 hres = CoCreateInstance(&storageInfo.clsid,
718 NULL,
719 CLSCTX_INPROC_HANDLER,
720 &IID_IOleObject,
721 (void**)&oleObject);
724 * If that fails, as it will most times, load the default
725 * OLE handler.
727 if (FAILED(hres))
729 hres = OleCreateDefaultHandler(&storageInfo.clsid,
730 NULL,
731 &IID_IOleObject,
732 (void**)&oleObject);
736 * If we couldn't find a handler... this is bad. Abort the whole thing.
738 if (FAILED(hres))
739 return hres;
742 * Inform the new object of it's client site.
744 hres = IOleObject_SetClientSite(oleObject, pClientSite);
747 * Initialize the object with it's IPersistStorage interface.
749 hres = IOleObject_QueryInterface(oleObject,
750 &IID_IPersistStorage,
751 (void**)&persistStorage);
753 if (SUCCEEDED(hres))
755 IPersistStorage_Load(persistStorage, pStg);
757 IPersistStorage_Release(persistStorage);
758 persistStorage = NULL;
762 * Return the requested interface to the caller.
764 hres = IOleObject_QueryInterface(oleObject, riid, ppvObj);
767 * Cleanup interfaces used internally
769 IOleObject_Release(oleObject);
771 return hres;
774 /***********************************************************************
775 * OleSave [OLE32.124]
777 HRESULT WINAPI OleSave(
778 LPPERSISTSTORAGE pPS,
779 LPSTORAGE pStg,
780 BOOL fSameAsLoad)
782 HRESULT hres;
783 CLSID objectClass;
785 TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad);
788 * First, we transfer the class ID (if available)
790 hres = IPersistStorage_GetClassID(pPS, &objectClass);
792 if (SUCCEEDED(hres))
794 WriteClassStg(pStg, &objectClass);
798 * Then, we ask the object to save itself to the
799 * storage. If it is successful, we commit the storage.
801 hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad);
803 if (SUCCEEDED(hres))
805 IStorage_Commit(pStg,
806 STGC_DEFAULT);
809 return hres;
813 /**************************************************************************
814 * Internal methods to manage the shared OLE menu in response to the
815 * OLE***MenuDescriptor API
818 /***
819 * OLEMenu_Initialize()
821 * Initializes the OLEMENU data structures.
823 static void OLEMenu_Initialize()
825 /* Create a dynamic pointer array to store the hook handles */
826 if ( !OLEMenu_MsgHookDPA )
827 OLEMenu_MsgHookDPA = DPA_CreateEx( 2, GetProcessHeap() );
830 /***
831 * OLEMenu_UnInitialize()
833 * Releases the OLEMENU data structures.
835 static void OLEMenu_UnInitialize()
837 /* Release the hook table */
838 if ( OLEMenu_MsgHookDPA )
839 DPA_Destroy( OLEMenu_MsgHookDPA );
841 OLEMenu_MsgHookDPA = NULL;
844 /*************************************************************************
845 * OLEMenu_InstallHooks
846 * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
848 * RETURNS: TRUE if message hooks were succesfully installed
849 * FALSE on failure
851 BOOL OLEMenu_InstallHooks( DWORD tid )
853 OleMenuHookItem *pHookItem = NULL;
855 if ( !OLEMenu_MsgHookDPA ) /* No hook table? Create one */
857 /* Create a dynamic pointer array to store the hook handles */
858 if ( !(OLEMenu_MsgHookDPA = DPA_CreateEx( 2, GetProcessHeap() )) )
859 return FALSE;
862 /* Create an entry for the hook table */
863 if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
864 sizeof(OleMenuHookItem)) ) )
865 return FALSE;
867 pHookItem->tid = tid;
868 pHookItem->hHeap = GetProcessHeap();
870 /* Install a thread scope message hook for WH_GETMESSAGE */
871 pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc,
872 0, GetCurrentThreadId() );
873 if ( !pHookItem->GetMsg_hHook )
874 goto CLEANUP;
876 /* Install a thread scope message hook for WH_CALLWNDPROC */
877 pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc,
878 0, GetCurrentThreadId() );
879 if ( !pHookItem->CallWndProc_hHook )
880 goto CLEANUP;
882 /* Insert the hook table entry */
883 if ( -1 == DPA_InsertPtr( OLEMenu_MsgHookDPA, 0, pHookItem ) )
884 goto CLEANUP;
886 return TRUE;
888 CLEANUP:
889 /* Unhook any hooks */
890 if ( pHookItem->GetMsg_hHook )
891 UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
892 if ( pHookItem->CallWndProc_hHook )
893 UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
894 /* Release the hook table entry */
895 HeapFree(pHookItem->hHeap, 0, pHookItem );
897 return FALSE;
900 /*************************************************************************
901 * OLEMenu_UnInstallHooks
902 * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
904 * RETURNS: TRUE if message hooks were succesfully installed
905 * FALSE on failure
907 BOOL OLEMenu_UnInstallHooks( DWORD tid )
909 INT ixHook;
910 OleMenuHookItem *pHookItem = NULL;
912 if ( !OLEMenu_MsgHookDPA ) /* No hooks set */
913 return TRUE;
915 /* Lookup the hHook index for this tid */
916 if ( !OLEMenu_IsHookInstalled( tid , &ixHook ) )
917 return TRUE;
919 /* Remove the hook entry from the table(the pointer itself is not deleted) */
920 if ( !( pHookItem = DPA_DeletePtr(OLEMenu_MsgHookDPA, ixHook) ) )
921 return FALSE;
923 /* Uninstall the hooks installed for this thread */
924 if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
925 goto CLEANUP;
926 if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
927 goto CLEANUP;
929 /* Release the hook table entry */
930 HeapFree(pHookItem->hHeap, 0, pHookItem );
932 return TRUE;
934 CLEANUP:
935 /* Release the hook table entry */
936 if (pHookItem)
937 HeapFree(pHookItem->hHeap, 0, pHookItem );
939 return FALSE;
942 /*************************************************************************
943 * OLEMenu_IsHookInstalled
944 * Tests if OLEMenu hooks have been installed for a thread
946 * RETURNS: The pointer and index of the hook table entry for the tid
947 * NULL and -1 for the index if no hooks were installed for this thread
949 OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid, INT *pixHook )
951 INT ixHook;
952 OleMenuHookItem *pHookItem = NULL;
954 if ( pixHook )
955 *pixHook = -1;
957 if ( !OLEMenu_MsgHookDPA ) /* No hooks set */
958 return NULL;
960 /* Do a simple linear search for an entry whose tid matches ours.
961 * We really need a map but efficiency is not a concern here. */
962 for( ixHook = 0; ; ixHook++ )
964 /* Retrieve the hook entry */
965 if ( !( pHookItem = DPA_GetPtr(OLEMenu_MsgHookDPA, ixHook) ) )
966 return NULL;
968 if ( tid == pHookItem->tid )
970 if ( pixHook )
971 *pixHook = ixHook;
972 return pHookItem;
976 return NULL;
979 /***********************************************************************
980 * OLEMenu_FindMainMenuIndex
982 * Used by OLEMenu API to find the top level group a menu item belongs to.
983 * On success pnPos contains the index of the item in the top level menu group
985 * RETURNS: TRUE if the ID was found, FALSE on failure
987 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
989 UINT i, nItems;
991 nItems = GetMenuItemCount( hMainMenu );
993 for (i = 0; i < nItems; i++)
995 HMENU hsubmenu;
997 /* Is the current item a submenu? */
998 if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
1000 /* If the handle is the same we're done */
1001 if ( hsubmenu == hPopupMenu )
1003 if (pnPos)
1004 *pnPos = i;
1005 return TRUE;
1007 /* Recursively search without updating pnPos */
1008 else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
1010 if (pnPos)
1011 *pnPos = i;
1012 return TRUE;
1017 return FALSE;
1020 /***********************************************************************
1021 * OLEMenu_SetIsServerMenu
1023 * Checks whether a popup menu belongs to a shared menu group which is
1024 * owned by the server, and sets the menu descriptor state accordingly.
1025 * All menu messages from these groups should be routed to the server.
1027 * RETURNS: TRUE if the popup menu is part of a server owned group
1028 * FASE if the popup menu is part of a container owned group
1030 BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
1032 UINT nPos = 0, nWidth, i;
1034 pOleMenuDescriptor->bIsServerItem = FALSE;
1036 /* Don't bother searching if the popup is the combined menu itself */
1037 if ( hmenu == pOleMenuDescriptor->hmenuCombined )
1038 return FALSE;
1040 /* Find the menu item index in the shared OLE menu that this item belongs to */
1041 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) )
1042 return FALSE;
1044 /* The group widths array has counts for the number of elements
1045 * in the groups File, Edit, Container, Object, Window, Help.
1046 * The Edit, Object & Help groups belong to the server object
1047 * and the other three belong to the container.
1048 * Loop thru the group widths and locate the group we are a member of.
1050 for ( i = 0, nWidth = 0; i < 6; i++ )
1052 nWidth += pOleMenuDescriptor->mgw.width[i];
1053 if ( nPos < nWidth )
1055 /* Odd elements are server menu widths */
1056 pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;
1057 break;
1061 return pOleMenuDescriptor->bIsServerItem;
1064 /*************************************************************************
1065 * OLEMenu_CallWndProc
1066 * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
1067 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1069 LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
1071 LPCWPSTRUCT pMsg = NULL;
1072 HOLEMENU hOleMenu = 0;
1073 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1074 OleMenuHookItem *pHookItem = NULL;
1075 WORD fuFlags;
1077 TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1079 /* Check if we're being asked to process the message */
1080 if ( HC_ACTION != code )
1081 goto NEXTHOOK;
1083 /* Retrieve the current message being dispatched from lParam */
1084 pMsg = (LPCWPSTRUCT)lParam;
1086 /* Check if the message is destined for a window we are interested in:
1087 * If the window has an OLEMenu property we may need to dispatch
1088 * the menu message to its active objects window instead. */
1090 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1091 if ( !hOleMenu )
1092 goto NEXTHOOK;
1094 /* Get the menu descriptor */
1095 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1096 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1097 goto NEXTHOOK;
1099 /* Process menu messages */
1100 switch( pMsg->message )
1102 case WM_INITMENU:
1104 /* Reset the menu descriptor state */
1105 pOleMenuDescriptor->bIsServerItem = FALSE;
1107 /* Send this message to the server as well */
1108 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1109 pMsg->message, pMsg->wParam, pMsg->lParam );
1110 goto NEXTHOOK;
1113 case WM_INITMENUPOPUP:
1115 /* Save the state for whether this is a server owned menu */
1116 OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
1117 break;
1120 case WM_MENUSELECT:
1122 fuFlags = HIWORD(pMsg->wParam); /* Get flags */
1123 if ( fuFlags & MF_SYSMENU )
1124 goto NEXTHOOK;
1126 /* Save the state for whether this is a server owned popup menu */
1127 else if ( fuFlags & MF_POPUP )
1128 OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
1130 break;
1133 case WM_DRAWITEM:
1135 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
1136 if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
1137 goto NEXTHOOK; /* Not a menu message */
1139 break;
1142 default:
1143 goto NEXTHOOK;
1146 /* If the message was for the server dispatch it accordingly */
1147 if ( pOleMenuDescriptor->bIsServerItem )
1149 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1150 pMsg->message, pMsg->wParam, pMsg->lParam );
1153 NEXTHOOK:
1154 if ( pOleMenuDescriptor )
1155 GlobalUnlock( hOleMenu );
1157 /* Lookup the hook item for the current thread */
1158 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId(), NULL ) ) )
1160 /* This should never fail!! */
1161 WARN("could not retrieve hHook for current thread!\n" );
1162 return 0;
1165 /* Pass on the message to the next hooker */
1166 return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
1169 /*************************************************************************
1170 * OLEMenu_GetMsgProc
1171 * Thread scope WH_GETMESSAGE hook proc filter function (callback)
1172 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1174 LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
1176 LPMSG pMsg = NULL;
1177 HOLEMENU hOleMenu = 0;
1178 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1179 OleMenuHookItem *pHookItem = NULL;
1180 WORD wCode;
1182 TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1184 /* Check if we're being asked to process a messages */
1185 if ( HC_ACTION != code )
1186 goto NEXTHOOK;
1188 /* Retrieve the current message being dispatched from lParam */
1189 pMsg = (LPMSG)lParam;
1191 /* Check if the message is destined for a window we are interested in:
1192 * If the window has an OLEMenu property we may need to dispatch
1193 * the menu message to its active objects window instead. */
1195 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1196 if ( !hOleMenu )
1197 goto NEXTHOOK;
1199 /* Process menu messages */
1200 switch( pMsg->message )
1202 case WM_COMMAND:
1204 wCode = HIWORD(pMsg->wParam); /* Get notification code */
1205 if ( wCode )
1206 goto NEXTHOOK; /* Not a menu message */
1207 break;
1209 default:
1210 goto NEXTHOOK;
1213 /* Get the menu descriptor */
1214 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1215 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1216 goto NEXTHOOK;
1218 /* If the message was for the server dispatch it accordingly */
1219 if ( pOleMenuDescriptor->bIsServerItem )
1221 /* Change the hWnd in the message to the active objects hWnd.
1222 * The message loop which reads this message will automatically
1223 * dispatch it to the embedded objects window. */
1224 pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
1227 NEXTHOOK:
1228 if ( pOleMenuDescriptor )
1229 GlobalUnlock( hOleMenu );
1231 /* Lookup the hook item for the current thread */
1232 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId(), NULL ) ) )
1234 /* This should never fail!! */
1235 WARN("could not retrieve hHook for current thread!\n" );
1236 return FALSE;
1239 /* Pass on the message to the next hooker */
1240 return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
1243 /***********************************************************************
1244 * OleCreateMenuDescriptor [OLE32.97]
1245 * Creates an OLE menu descriptor for OLE to use when dispatching
1246 * menu messages and commands.
1248 * PARAMS:
1249 * hmenuCombined - Handle to the objects combined menu
1250 * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group
1253 HOLEMENU WINAPI OleCreateMenuDescriptor(
1254 HMENU hmenuCombined,
1255 LPOLEMENUGROUPWIDTHS lpMenuWidths)
1257 HOLEMENU hOleMenu;
1258 OleMenuDescriptor *pOleMenuDescriptor;
1259 int i;
1261 if ( !hmenuCombined || !lpMenuWidths )
1262 return 0;
1264 /* Create an OLE menu descriptor */
1265 if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
1266 sizeof(OleMenuDescriptor) ) ) )
1267 return 0;
1269 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1270 if ( !pOleMenuDescriptor )
1271 return 0;
1273 /* Initialize menu group widths and hmenu */
1274 for ( i = 0; i < 6; i++ )
1275 pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
1277 pOleMenuDescriptor->hmenuCombined = hmenuCombined;
1278 pOleMenuDescriptor->bIsServerItem = FALSE;
1279 GlobalUnlock( hOleMenu );
1281 return hOleMenu;
1284 /***********************************************************************
1285 * OleDestroyMenuDescriptor [OLE32.99]
1286 * Destroy the shared menu descriptor
1288 HRESULT WINAPI OleDestroyMenuDescriptor(
1289 HOLEMENU hmenuDescriptor)
1291 if ( hmenuDescriptor )
1292 GlobalFree( hmenuDescriptor );
1293 return S_OK;
1296 /***********************************************************************
1297 * OleSetMenuDescriptor [OLE32.129]
1298 * Installs or removes OLE dispatching code for the containers frame window
1299 * FIXME: The lpFrame and lpActiveObject parameters are currently ignored
1300 * OLE should install context sensitive help F1 filtering for the app when
1301 * these are non null.
1303 * PARAMS:
1304 * hOleMenu Handle to composite menu descriptor
1305 * hwndFrame Handle to containers frame window
1306 * hwndActiveObject Handle to objects in-place activation window
1307 * lpFrame Pointer to IOleInPlaceFrame on containers window
1308 * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object
1310 * RETURNS:
1311 * S_OK - menu installed correctly
1312 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1314 HRESULT WINAPI OleSetMenuDescriptor(
1315 HOLEMENU hOleMenu,
1316 HWND hwndFrame,
1317 HWND hwndActiveObject,
1318 LPOLEINPLACEFRAME lpFrame,
1319 LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1321 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1323 /* Check args */
1324 if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
1325 return E_INVALIDARG;
1327 if ( lpFrame || lpActiveObject )
1329 FIXME("(%x, %x, %x, %p, %p), Context sensitive help filtering not implemented!\n",
1330 (unsigned int)hOleMenu,
1331 hwndFrame,
1332 hwndActiveObject,
1333 lpFrame,
1334 lpActiveObject);
1337 /* Set up a message hook to intercept the containers frame window messages.
1338 * The message filter is responsible for dispatching menu messages from the
1339 * shared menu which are intended for the object.
1342 if ( hOleMenu ) /* Want to install dispatching code */
1344 /* If OLEMenu hooks are already installed for this thread, fail
1345 * Note: This effectively means that OleSetMenuDescriptor cannot
1346 * be called twice in succession on the same frame window
1347 * without first calling it with a null hOleMenu to uninstall */
1348 if ( OLEMenu_IsHookInstalled( GetCurrentThreadId(), NULL ) )
1349 return E_FAIL;
1351 /* Get the menu descriptor */
1352 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1353 if ( !pOleMenuDescriptor )
1354 return E_UNEXPECTED;
1356 /* Update the menu descriptor */
1357 pOleMenuDescriptor->hwndFrame = hwndFrame;
1358 pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
1360 GlobalUnlock( hOleMenu );
1361 pOleMenuDescriptor = NULL;
1363 /* Add a menu descriptor windows property to the frame window */
1364 SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu );
1366 /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
1367 if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
1368 return E_FAIL;
1370 else /* Want to uninstall dispatching code */
1372 /* Uninstall the hooks */
1373 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1374 return E_FAIL;
1376 /* Remove the menu descriptor property from the frame window */
1377 RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" );
1380 return S_OK;
1383 /***********************************************************************
1384 * ReleaseStgMedium [OLE32.140]
1386 void WINAPI ReleaseStgMedium(
1387 STGMEDIUM* pmedium)
1389 switch (pmedium->tymed)
1391 case TYMED_HGLOBAL:
1393 if ( (pmedium->pUnkForRelease==0) &&
1394 (pmedium->u.hGlobal!=0) )
1395 GlobalFree(pmedium->u.hGlobal);
1397 pmedium->u.hGlobal = 0;
1398 break;
1400 case TYMED_FILE:
1402 if (pmedium->u.lpszFileName!=0)
1404 if (pmedium->pUnkForRelease==0)
1406 DeleteFileW(pmedium->u.lpszFileName);
1409 CoTaskMemFree(pmedium->u.lpszFileName);
1412 pmedium->u.lpszFileName = 0;
1413 break;
1415 case TYMED_ISTREAM:
1417 if (pmedium->u.pstm!=0)
1419 IStream_Release(pmedium->u.pstm);
1422 pmedium->u.pstm = 0;
1423 break;
1425 case TYMED_ISTORAGE:
1427 if (pmedium->u.pstg!=0)
1429 IStorage_Release(pmedium->u.pstg);
1432 pmedium->u.pstg = 0;
1433 break;
1435 case TYMED_GDI:
1437 if ( (pmedium->pUnkForRelease==0) &&
1438 (pmedium->u.hGlobal!=0) )
1439 DeleteObject(pmedium->u.hGlobal);
1441 pmedium->u.hGlobal = 0;
1442 break;
1444 case TYMED_MFPICT:
1446 if ( (pmedium->pUnkForRelease==0) &&
1447 (pmedium->u.hMetaFilePict!=0) )
1449 DeleteMetaFile(pmedium->u.hMetaFilePict);
1450 GlobalFree(pmedium->u.hMetaFilePict);
1453 pmedium->u.hMetaFilePict = 0;
1454 break;
1456 case TYMED_ENHMF:
1458 if ( (pmedium->pUnkForRelease==0) &&
1459 (pmedium->u.hEnhMetaFile!=0) )
1461 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
1464 pmedium->u.hEnhMetaFile = 0;
1465 break;
1467 case TYMED_NULL:
1468 default:
1469 break;
1473 * After cleaning up, the unknown is released
1475 if (pmedium->pUnkForRelease!=0)
1477 IUnknown_Release(pmedium->pUnkForRelease);
1478 pmedium->pUnkForRelease = 0;
1482 /***
1483 * OLEDD_Initialize()
1485 * Initializes the OLE drag and drop data structures.
1487 static void OLEDD_Initialize()
1489 WNDCLASSA wndClass;
1491 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1492 wndClass.style = CS_GLOBALCLASS;
1493 wndClass.lpfnWndProc = (WNDPROC)OLEDD_DragTrackerWindowProc;
1494 wndClass.cbClsExtra = 0;
1495 wndClass.cbWndExtra = sizeof(TrackerWindowInfo*);
1496 wndClass.hCursor = 0;
1497 wndClass.hbrBackground = 0;
1498 wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
1500 RegisterClassA (&wndClass);
1503 /***
1504 * OLEDD_UnInitialize()
1506 * Releases the OLE drag and drop data structures.
1508 static void OLEDD_UnInitialize()
1511 * Simply empty the list.
1513 while (targetListHead!=NULL)
1515 RevokeDragDrop(targetListHead->hwndTarget);
1519 /***
1520 * OLEDD_InsertDropTarget()
1522 * Insert the target node in the tree.
1524 static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd)
1526 DropTargetNode* curNode;
1527 DropTargetNode** parentNodeLink;
1530 * Iterate the tree to find the insertion point.
1532 curNode = targetListHead;
1533 parentNodeLink = &targetListHead;
1535 while (curNode!=NULL)
1537 if (nodeToAdd->hwndTarget<curNode->hwndTarget)
1540 * If the node we want to add has a smaller HWND, go left
1542 parentNodeLink = &curNode->prevDropTarget;
1543 curNode = curNode->prevDropTarget;
1545 else if (nodeToAdd->hwndTarget>curNode->hwndTarget)
1548 * If the node we want to add has a larger HWND, go right
1550 parentNodeLink = &curNode->nextDropTarget;
1551 curNode = curNode->nextDropTarget;
1553 else
1556 * The item was found in the list. It shouldn't have been there
1558 assert(FALSE);
1559 return;
1564 * If we get here, we have found a spot for our item. The parentNodeLink
1565 * pointer points to the pointer that we have to modify.
1566 * The curNode should be NULL. We just have to establish the link and Voila!
1568 assert(curNode==NULL);
1569 assert(parentNodeLink!=NULL);
1570 assert(*parentNodeLink==NULL);
1572 *parentNodeLink=nodeToAdd;
1575 /***
1576 * OLEDD_ExtractDropTarget()
1578 * Removes the target node from the tree.
1580 static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget)
1582 DropTargetNode* curNode;
1583 DropTargetNode** parentNodeLink;
1586 * Iterate the tree to find the insertion point.
1588 curNode = targetListHead;
1589 parentNodeLink = &targetListHead;
1591 while (curNode!=NULL)
1593 if (hwndOfTarget<curNode->hwndTarget)
1596 * If the node we want to add has a smaller HWND, go left
1598 parentNodeLink = &curNode->prevDropTarget;
1599 curNode = curNode->prevDropTarget;
1601 else if (hwndOfTarget>curNode->hwndTarget)
1604 * If the node we want to add has a larger HWND, go right
1606 parentNodeLink = &curNode->nextDropTarget;
1607 curNode = curNode->nextDropTarget;
1609 else
1612 * The item was found in the list. Detach it from it's parent and
1613 * re-insert it's kids in the tree.
1615 assert(parentNodeLink!=NULL);
1616 assert(*parentNodeLink==curNode);
1619 * We arbitrately re-attach the left sub-tree to the parent.
1621 *parentNodeLink = curNode->prevDropTarget;
1624 * And we re-insert the right subtree
1626 if (curNode->nextDropTarget!=NULL)
1628 OLEDD_InsertDropTarget(curNode->nextDropTarget);
1632 * The node we found is still a valid node once we complete
1633 * the unlinking of the kids.
1635 curNode->nextDropTarget=NULL;
1636 curNode->prevDropTarget=NULL;
1638 return curNode;
1643 * If we get here, the node is not in the tree
1645 return NULL;
1648 /***
1649 * OLEDD_FindDropTarget()
1651 * Finds information about the drop target.
1653 static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
1655 DropTargetNode* curNode;
1658 * Iterate the tree to find the HWND value.
1660 curNode = targetListHead;
1662 while (curNode!=NULL)
1664 if (hwndOfTarget<curNode->hwndTarget)
1667 * If the node we want to add has a smaller HWND, go left
1669 curNode = curNode->prevDropTarget;
1671 else if (hwndOfTarget>curNode->hwndTarget)
1674 * If the node we want to add has a larger HWND, go right
1676 curNode = curNode->nextDropTarget;
1678 else
1681 * The item was found in the list.
1683 return curNode;
1688 * If we get here, the item is not in the list
1690 return NULL;
1693 /***
1694 * OLEDD_DragTrackerWindowProc()
1696 * This method is the WindowProcedure of the drag n drop tracking
1697 * window. During a drag n Drop operation, an invisible window is created
1698 * to receive the user input and act upon it. This procedure is in charge
1699 * of this behavior.
1701 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
1702 HWND hwnd,
1703 UINT uMsg,
1704 WPARAM wParam,
1705 LPARAM lParam)
1707 switch (uMsg)
1709 case WM_CREATE:
1711 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
1713 SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams);
1716 break;
1718 case WM_MOUSEMOVE:
1720 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1721 POINT mousePos;
1724 * Get the current mouse position in screen coordinates.
1726 mousePos.x = LOWORD(lParam);
1727 mousePos.y = HIWORD(lParam);
1728 ClientToScreen(hwnd, &mousePos);
1731 * Track the movement of the mouse.
1733 OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam);
1735 break;
1737 case WM_LBUTTONUP:
1738 case WM_MBUTTONUP:
1739 case WM_RBUTTONUP:
1740 case WM_LBUTTONDOWN:
1741 case WM_MBUTTONDOWN:
1742 case WM_RBUTTONDOWN:
1744 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1745 POINT mousePos;
1748 * Get the current mouse position in screen coordinates.
1750 mousePos.x = LOWORD(lParam);
1751 mousePos.y = HIWORD(lParam);
1752 ClientToScreen(hwnd, &mousePos);
1755 * Notify everyone that the button state changed
1756 * TODO: Check if the "escape" key was pressed.
1758 OLEDD_TrackStateChange(trackerInfo, mousePos, wParam);
1760 break;
1765 * This is a window proc after all. Let's call the default.
1767 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1770 /***
1771 * OLEDD_TrackMouseMove()
1773 * This method is invoked while a drag and drop operation is in effect.
1774 * it will generate the appropriate callbacks in the drop source
1775 * and drop target. It will also provide the expected feedback to
1776 * the user.
1778 * params:
1779 * trackerInfo - Pointer to the structure identifying the
1780 * drag & drop operation that is currently
1781 * active.
1782 * mousePos - Current position of the mouse in screen
1783 * coordinates.
1784 * keyState - Contains the state of the shift keys and the
1785 * mouse buttons (MK_LBUTTON and the like)
1787 static void OLEDD_TrackMouseMove(
1788 TrackerWindowInfo* trackerInfo,
1789 POINT mousePos,
1790 DWORD keyState)
1792 HWND hwndNewTarget = 0;
1793 HRESULT hr = S_OK;
1796 * Get the handle of the window under the mouse
1798 hwndNewTarget = WindowFromPoint(mousePos);
1801 * Every time, we re-initialize the effects passed to the
1802 * IDropTarget to the effects allowed by the source.
1804 *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
1807 * If we are hovering over the same target as before, send the
1808 * DragOver notification
1810 if ( (trackerInfo->curDragTarget != 0) &&
1811 (trackerInfo->curDragTargetHWND==hwndNewTarget) )
1813 POINTL mousePosParam;
1816 * The documentation tells me that the coordinate should be in the target
1817 * window's coordinate space. However, the tests I made tell me the
1818 * coordinates should be in screen coordinates.
1820 mousePosParam.x = mousePos.x;
1821 mousePosParam.y = mousePos.y;
1823 IDropTarget_DragOver(trackerInfo->curDragTarget,
1824 keyState,
1825 mousePosParam,
1826 trackerInfo->pdwEffect);
1828 else
1830 DropTargetNode* newDropTargetNode = 0;
1833 * If we changed window, we have to notify our old target and check for
1834 * the new one.
1836 if (trackerInfo->curDragTarget!=0)
1838 IDropTarget_DragLeave(trackerInfo->curDragTarget);
1842 * Make sure we're hovering over a window.
1844 if (hwndNewTarget!=0)
1847 * Find-out if there is a drag target under the mouse
1849 newDropTargetNode = OLEDD_FindDropTarget(hwndNewTarget);
1851 trackerInfo->curDragTargetHWND = hwndNewTarget;
1852 trackerInfo->curDragTarget = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
1855 * If there is, notify it that we just dragged-in
1857 if (trackerInfo->curDragTarget!=0)
1859 POINTL mousePosParam;
1862 * The documentation tells me that the coordinate should be in the target
1863 * window's coordinate space. However, the tests I made tell me the
1864 * coordinates should be in screen coordinates.
1866 mousePosParam.x = mousePos.x;
1867 mousePosParam.y = mousePos.y;
1869 IDropTarget_DragEnter(trackerInfo->curDragTarget,
1870 trackerInfo->dataObject,
1871 keyState,
1872 mousePosParam,
1873 trackerInfo->pdwEffect);
1876 else
1879 * The mouse is not over a window so we don't track anything.
1881 trackerInfo->curDragTargetHWND = 0;
1882 trackerInfo->curDragTarget = 0;
1887 * Now that we have done that, we have to tell the source to give
1888 * us feedback on the work being done by the target. If we don't
1889 * have a target, simulate no effect.
1891 if (trackerInfo->curDragTarget==0)
1893 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
1896 hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
1897 *trackerInfo->pdwEffect);
1900 * When we ask for feedback from the drop source, sometimes it will
1901 * do all the necessary work and sometimes it will not handle it
1902 * when that's the case, we must display the standard drag and drop
1903 * cursors.
1905 if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
1907 if ( (*trackerInfo->pdwEffect & DROPEFFECT_MOVE) ||
1908 (*trackerInfo->pdwEffect & DROPEFFECT_COPY) ||
1909 (*trackerInfo->pdwEffect & DROPEFFECT_LINK) )
1911 SetCursor(LoadCursorA(0, IDC_SIZEALLA));
1913 else
1915 SetCursor(LoadCursorA(0, IDC_NOA));
1920 /***
1921 * OLEDD_TrackStateChange()
1923 * This method is invoked while a drag and drop operation is in effect.
1924 * It is used to notify the drop target/drop source callbacks when
1925 * the state of the keyboard or mouse button change.
1927 * params:
1928 * trackerInfo - Pointer to the structure identifying the
1929 * drag & drop operation that is currently
1930 * active.
1931 * mousePos - Current position of the mouse in screen
1932 * coordinates.
1933 * keyState - Contains the state of the shift keys and the
1934 * mouse buttons (MK_LBUTTON and the like)
1936 static void OLEDD_TrackStateChange(
1937 TrackerWindowInfo* trackerInfo,
1938 POINT mousePos,
1939 DWORD keyState)
1942 * Ask the drop source what to do with the operation.
1944 trackerInfo->returnValue = IDropSource_QueryContinueDrag(
1945 trackerInfo->dropSource,
1946 trackerInfo->escPressed,
1947 keyState);
1950 * All the return valued will stop the operation except the S_OK
1951 * return value.
1953 if (trackerInfo->returnValue!=S_OK)
1956 * Make sure the message loop in DoDragDrop stops
1958 trackerInfo->trackingDone = TRUE;
1961 * Release the mouse in case the drop target decides to show a popup
1962 * or a menu or something.
1964 ReleaseCapture();
1967 * If we end-up over a target, drop the object in the target or
1968 * inform the target that the operation was cancelled.
1970 if (trackerInfo->curDragTarget!=0)
1972 switch (trackerInfo->returnValue)
1975 * If the source wants us to complete the operation, we tell
1976 * the drop target that we just dropped the object in it.
1978 case DRAGDROP_S_DROP:
1980 POINTL mousePosParam;
1983 * The documentation tells me that the coordinate should be
1984 * in the target window's coordinate space. However, the tests
1985 * I made tell me the coordinates should be in screen coordinates.
1987 mousePosParam.x = mousePos.x;
1988 mousePosParam.y = mousePos.y;
1990 IDropTarget_Drop(trackerInfo->curDragTarget,
1991 trackerInfo->dataObject,
1992 keyState,
1993 mousePosParam,
1994 trackerInfo->pdwEffect);
1995 break;
1998 * If the source told us that we should cancel, fool the drop
1999 * target by telling it that the mouse left it's window.
2000 * Also set the drop effect to "NONE" in case the application
2001 * ignores the result of DoDragDrop.
2003 case DRAGDROP_S_CANCEL:
2004 IDropTarget_DragLeave(trackerInfo->curDragTarget);
2005 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2006 break;
2012 /***
2013 * OLEDD_GetButtonState()
2015 * This method will use the current state of the keyboard to build
2016 * a button state mask equivalent to the one passed in the
2017 * WM_MOUSEMOVE wParam.
2019 static DWORD OLEDD_GetButtonState()
2021 BYTE keyboardState[256];
2022 DWORD keyMask = 0;
2024 GetKeyboardState(keyboardState);
2026 if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
2027 keyMask |= MK_SHIFT;
2029 if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
2030 keyMask |= MK_CONTROL;
2032 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
2033 keyMask |= MK_LBUTTON;
2035 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
2036 keyMask |= MK_RBUTTON;
2038 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
2039 keyMask |= MK_MBUTTON;
2041 return keyMask;
2044 /***
2045 * OLEDD_GetButtonState()
2047 * This method will read the default value of the registry key in
2048 * parameter and extract a DWORD value from it. The registry key value
2049 * can be in a string key or a DWORD key.
2051 * params:
2052 * regKey - Key to read the default value from
2053 * pdwValue - Pointer to the location where the DWORD
2054 * value is returned. This value is not modified
2055 * if the value is not found.
2058 static void OLEUTL_ReadRegistryDWORDValue(
2059 HKEY regKey,
2060 DWORD* pdwValue)
2062 char buffer[20];
2063 DWORD dwKeyType;
2064 DWORD cbData = 20;
2065 LONG lres;
2067 lres = RegQueryValueExA(regKey,
2069 NULL,
2070 &dwKeyType,
2071 (LPBYTE)buffer,
2072 &cbData);
2074 if (lres==ERROR_SUCCESS)
2076 switch (dwKeyType)
2078 case REG_DWORD:
2079 *pdwValue = *(DWORD*)buffer;
2080 break;
2081 case REG_EXPAND_SZ:
2082 case REG_MULTI_SZ:
2083 case REG_SZ:
2084 *pdwValue = (DWORD)strtoul(buffer, NULL, 10);
2085 break;
2090 /******************************************************************************
2091 * OleMetaFilePictFromIconAndLabel
2093 * Returns a global memory handle to a metafile which contains the icon and
2094 * label given.
2095 * I guess the result of that should look somehow like desktop icons.
2096 * If no hIcon is given, we load the icon via lpszSourceFile and iIconIndex.
2097 * This code might be wrong at some places.
2099 HGLOBAL16 WINAPI OleMetaFilePictFromIconAndLabel16(
2100 HICON16 hIcon,
2101 LPCOLESTR16 lpszLabel,
2102 LPCOLESTR16 lpszSourceFile,
2103 UINT16 iIconIndex
2105 METAFILEPICT16 *mf;
2106 HGLOBAL16 hmf;
2107 HDC16 hdc;
2109 FIXME("(%04x, '%s', '%s', %d): incorrect metrics, please try to correct them !\n\n\n", hIcon, lpszLabel, lpszSourceFile, iIconIndex);
2111 if (!hIcon) {
2112 if (lpszSourceFile) {
2113 HINSTANCE16 hInstance = LoadLibrary16(lpszSourceFile);
2115 /* load the icon at index from lpszSourceFile */
2116 hIcon = (HICON16)LoadIconA(hInstance, (LPCSTR)(DWORD)iIconIndex);
2117 FreeLibrary16(hInstance);
2118 } else
2119 return (HGLOBAL)NULL;
2122 hdc = CreateMetaFile16(NULL);
2123 DrawIcon(hdc, 0, 0, hIcon); /* FIXME */
2124 TextOut16(hdc, 0, 0, lpszLabel, 1); /* FIXME */
2125 hmf = GlobalAlloc16(0, sizeof(METAFILEPICT16));
2126 mf = (METAFILEPICT16 *)GlobalLock16(hmf);
2127 mf->mm = MM_ANISOTROPIC;
2128 mf->xExt = 20; /* FIXME: bogus */
2129 mf->yExt = 20; /* dito */
2130 mf->hMF = CloseMetaFile16(hdc);
2131 return hmf;