Removed old resource compiler.
[wine.git] / dlls / ole32 / ole2.c
blobfbd2cdf223279e8252ef52c7c9fe58f81d5efea4
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 <stdio.h>
12 #include <string.h>
14 #include "windef.h"
15 #include "wingdi.h"
16 #include "winuser.h"
17 #include "winerror.h"
18 #include "ole2.h"
19 #include "process.h"
20 #include "commctrl.h"
21 #include "wine/obj_clientserver.h"
22 #include "wine/wingdi16.h"
23 #include "debugtools.h"
24 #include "ole2ver.h"
25 #include "winreg.h"
27 DEFAULT_DEBUG_CHANNEL(ole)
29 /******************************************************************************
30 * These are static/global variables and internal data structures that the
31 * OLE module uses to maintain it's state.
33 typedef struct tagDropTargetNode
35 HWND hwndTarget;
36 IDropTarget* dropTarget;
37 struct tagDropTargetNode* prevDropTarget;
38 struct tagDropTargetNode* nextDropTarget;
39 } DropTargetNode;
41 typedef struct tagTrackerWindowInfo
43 IDataObject* dataObject;
44 IDropSource* dropSource;
45 DWORD dwOKEffect;
46 DWORD* pdwEffect;
47 BOOL trackingDone;
48 HRESULT returnValue;
50 BOOL escPressed;
51 HWND curDragTargetHWND;
52 IDropTarget* curDragTarget;
53 } TrackerWindowInfo;
55 typedef struct tagOleMenuDescriptor /* OleMenuDescriptor */
57 HWND hwndFrame; /* The containers frame window */
58 HWND hwndActiveObject; /* The active objects window */
59 OLEMENUGROUPWIDTHS mgw; /* OLE menu group widths for the shared menu */
60 HMENU hmenuCombined; /* The combined menu */
61 BOOL bIsServerItem; /* True if the currently open popup belongs to the server */
62 } OleMenuDescriptor;
64 typedef struct tagOleMenuHookItem /* OleMenu hook item in per thread hook list */
66 DWORD tid; /* Thread Id */
67 HANDLE hHeap; /* Heap this is allocated from */
68 HHOOK GetMsg_hHook; /* message hook for WH_GETMESSAGE */
69 HHOOK CallWndProc_hHook; /* message hook for WH_CALLWNDPROC */
70 struct tagOleMenuHookItem *next;
71 } OleMenuHookItem;
73 static OleMenuHookItem *hook_list;
76 * This is the lock count on the OLE library. It is controlled by the
77 * OLEInitialize/OLEUninitialize methods.
79 static ULONG OLE_moduleLockCount = 0;
82 * Name of our registered window class.
84 static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";
87 * This is the head of the Drop target container.
89 static DropTargetNode* targetListHead = NULL;
91 /******************************************************************************
92 * These are the prototypes of miscelaneous utility methods
94 static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue);
96 /******************************************************************************
97 * These are the prototypes of the utility methods used to manage a shared menu
99 static void OLEMenu_Initialize();
100 static void OLEMenu_UnInitialize();
101 BOOL OLEMenu_InstallHooks( DWORD tid );
102 BOOL OLEMenu_UnInstallHooks( DWORD tid );
103 OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid );
104 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
105 BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor );
106 LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam);
107 LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam);
109 /******************************************************************************
110 * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c)
112 void OLEClipbrd_UnInitialize();
113 void OLEClipbrd_Initialize();
115 /******************************************************************************
116 * These are the prototypes of the utility methods used for OLE Drag n Drop
118 static void OLEDD_Initialize();
119 static void OLEDD_UnInitialize();
120 static void OLEDD_InsertDropTarget(
121 DropTargetNode* nodeToAdd);
122 static DropTargetNode* OLEDD_ExtractDropTarget(
123 HWND hwndOfTarget);
124 static DropTargetNode* OLEDD_FindDropTarget(
125 HWND hwndOfTarget);
126 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
127 HWND hwnd,
128 UINT uMsg,
129 WPARAM wParam,
130 LPARAM lParam);
131 static void OLEDD_TrackMouseMove(
132 TrackerWindowInfo* trackerInfo,
133 POINT mousePos,
134 DWORD keyState);
135 static void OLEDD_TrackStateChange(
136 TrackerWindowInfo* trackerInfo,
137 POINT mousePos,
138 DWORD keyState);
139 static DWORD OLEDD_GetButtonState();
142 /******************************************************************************
143 * OleBuildVersion [OLE2.1]
145 DWORD WINAPI OleBuildVersion(void)
147 TRACE("Returning version %d, build %d.\n", rmm, rup);
148 return (rmm<<16)+rup;
151 /***********************************************************************
152 * OleInitialize (OLE2.2) (OLE32.108)
154 HRESULT WINAPI OleInitialize(LPVOID reserved)
156 HRESULT hr;
158 TRACE("(%p)\n", reserved);
161 * The first duty of the OleInitialize is to initialize the COM libraries.
163 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
166 * If the CoInitializeEx call failed, the OLE libraries can't be
167 * initialized.
169 if (FAILED(hr))
170 return hr;
173 * Then, it has to initialize the OLE specific modules.
174 * This includes:
175 * Clipboard
176 * Drag and Drop
177 * Object linking and Embedding
178 * In-place activation
180 if (OLE_moduleLockCount==0)
183 * Initialize the libraries.
185 TRACE("() - Initializing the OLE libraries\n");
188 * OLE Clipboard
190 OLEClipbrd_Initialize();
193 * Drag and Drop
195 OLEDD_Initialize();
198 * OLE shared menu
200 OLEMenu_Initialize();
204 * Then, we increase the lock count on the OLE module.
206 OLE_moduleLockCount++;
208 return hr;
211 /******************************************************************************
212 * CoGetCurrentProcess [COMPOBJ.34] [OLE2.2][OLE32.108]
214 * NOTES
215 * Is DWORD really the correct return type for this function?
217 DWORD WINAPI CoGetCurrentProcess(void) {
218 return (DWORD)PROCESS_Current();
221 /******************************************************************************
222 * OleUninitialize [OLE2.3] [OLE32.131]
224 void WINAPI OleUninitialize(void)
226 TRACE("()\n");
229 * Decrease the lock count on the OLE module.
231 OLE_moduleLockCount--;
234 * If we hit the bottom of the lock stack, free the libraries.
236 if (OLE_moduleLockCount==0)
239 * Actually free the libraries.
241 TRACE("() - Freeing the last reference count\n");
244 * OLE Clipboard
246 OLEClipbrd_UnInitialize();
249 * Drag and Drop
251 OLEDD_UnInitialize();
254 * OLE shared menu
256 OLEMenu_UnInitialize();
260 * Then, uninitialize the COM libraries.
262 CoUninitialize();
265 /******************************************************************************
266 * CoRegisterMessageFilter [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("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("(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("(0x%04x,%p),stub!\n",hwnd,pDropTarget);
295 return S_OK;
298 /***********************************************************************
299 * RegisterDragDrop (OLE32.139)
301 HRESULT WINAPI RegisterDragDrop(
302 HWND hwnd,
303 LPDROPTARGET pDropTarget)
305 DropTargetNode* dropTargetInfo;
307 TRACE("(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("(0x%04x),stub!\n",hwnd);
348 return S_OK;
351 /***********************************************************************
352 * RevokeDragDrop (OLE32.141)
354 HRESULT WINAPI RevokeDragDrop(
355 HWND hwnd)
357 DropTargetNode* dropTargetInfo;
359 TRACE("(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;
401 LPBYTE buffer;
402 HRESULT retVal;
404 * Initialize the out parameter.
406 *pszUserType = NULL;
409 * Build the key name we're looking for
411 WINE_StringFromCLSID((LPCLSID)clsid, xclsid);
413 strcpy(keyName, "CLSID\\");
414 strcat(keyName, xclsid);
415 strcat(keyName, "\\");
417 TRACE("(%s, %ld, %p)\n", keyName, dwFormOfType, pszUserType);
420 * Open the class id Key
422 hres = RegOpenKeyA(HKEY_CLASSES_ROOT,
423 keyName,
424 &clsidKey);
426 if (hres != ERROR_SUCCESS)
427 return REGDB_E_CLASSNOTREG;
430 * Retrieve the size of the name string.
432 cbData = 0;
434 hres = RegQueryValueExA(clsidKey,
436 NULL,
437 &dwKeyType,
438 NULL,
439 &cbData);
441 if (hres!=ERROR_SUCCESS)
443 RegCloseKey(clsidKey);
444 return REGDB_E_READREGDB;
448 * Allocate a buffer for the registry value.
450 *pszUserType = CoTaskMemAlloc(cbData*2);
452 if (*pszUserType==NULL)
454 RegCloseKey(clsidKey);
455 return E_OUTOFMEMORY;
458 buffer = HeapAlloc(GetProcessHeap(), 0, cbData);
460 if (buffer == NULL)
462 RegCloseKey(clsidKey);
463 CoTaskMemFree(*pszUserType);
464 *pszUserType=NULL;
465 return E_OUTOFMEMORY;
468 hres = RegQueryValueExA(clsidKey,
470 NULL,
471 &dwKeyType,
472 buffer,
473 &cbData);
475 RegCloseKey(clsidKey);
478 if (hres!=ERROR_SUCCESS)
480 CoTaskMemFree(*pszUserType);
481 *pszUserType=NULL;
483 retVal = REGDB_E_READREGDB;
485 else
487 lstrcpyAtoW(*pszUserType, buffer);
488 retVal = S_OK;
490 HeapFree(GetProcessHeap(), 0, buffer);
492 return retVal;
495 /***********************************************************************
496 * DoDragDrop [OLE32.65]
498 HRESULT WINAPI DoDragDrop (
499 IDataObject *pDataObject, /* ptr to the data obj */
500 IDropSource* pDropSource, /* ptr to the source obj */
501 DWORD dwOKEffect, /* effects allowed by the source */
502 DWORD *pdwEffect) /* ptr to effects of the source */
504 TrackerWindowInfo trackerInfo;
505 HWND hwndTrackWindow;
506 MSG msg;
508 TRACE("(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
511 * Setup the drag n drop tracking window.
513 trackerInfo.dataObject = pDataObject;
514 trackerInfo.dropSource = pDropSource;
515 trackerInfo.dwOKEffect = dwOKEffect;
516 trackerInfo.pdwEffect = pdwEffect;
517 trackerInfo.trackingDone = FALSE;
518 trackerInfo.escPressed = FALSE;
519 trackerInfo.curDragTargetHWND = 0;
520 trackerInfo.curDragTarget = 0;
522 hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS,
523 "TrackerWindow",
524 WS_POPUP,
525 CW_USEDEFAULT, CW_USEDEFAULT,
526 CW_USEDEFAULT, CW_USEDEFAULT,
530 (LPVOID)&trackerInfo);
532 if (hwndTrackWindow!=0)
535 * Capture the mouse input
537 SetCapture(hwndTrackWindow);
540 * Pump messages. All mouse input should go the the capture window.
542 while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )
544 if ( (msg.message >= WM_KEYFIRST) &&
545 (msg.message <= WM_KEYFIRST) )
548 * When keyboard messages are sent to windows on this thread, we
549 * want to ignore notify the drop source that the state changed.
550 * in the case of the Escape key, we also notify the drop source
551 * we give it a special meaning.
553 if ( (msg.message==WM_KEYDOWN) &&
554 (msg.wParam==VK_ESCAPE) )
556 trackerInfo.escPressed = TRUE;
560 * Notify the drop source.
562 OLEDD_TrackStateChange(&trackerInfo,
563 msg.pt,
564 OLEDD_GetButtonState());
566 else
569 * Dispatch the messages only when it's not a keyboard message.
571 DispatchMessageA(&msg);
576 * Destroy the temporary window.
578 DestroyWindow(hwndTrackWindow);
580 return trackerInfo.returnValue;
583 return E_FAIL;
586 /***********************************************************************
587 * OleQueryLinkFromData [OLE32.118]
589 HRESULT WINAPI OleQueryLinkFromData(
590 IDataObject* pSrcDataObject)
592 FIXME("(%p),stub!\n", pSrcDataObject);
593 return S_OK;
596 /***********************************************************************
597 * OleRegGetMiscStatus [OLE32.121]
599 HRESULT WINAPI OleRegGetMiscStatus(
600 REFCLSID clsid,
601 DWORD dwAspect,
602 DWORD* pdwStatus)
604 char xclsid[50];
605 char keyName[60];
606 HKEY clsidKey;
607 HKEY miscStatusKey;
608 HKEY aspectKey;
609 LONG result;
612 * Initialize the out parameter.
614 *pdwStatus = 0;
617 * Build the key name we're looking for
619 WINE_StringFromCLSID((LPCLSID)clsid, xclsid);
621 strcpy(keyName, "CLSID\\");
622 strcat(keyName, xclsid);
623 strcat(keyName, "\\");
625 TRACE("(%s, %ld, %p)\n", keyName, dwAspect, pdwStatus);
628 * Open the class id Key
630 result = RegOpenKeyA(HKEY_CLASSES_ROOT,
631 keyName,
632 &clsidKey);
634 if (result != ERROR_SUCCESS)
635 return REGDB_E_CLASSNOTREG;
638 * Get the MiscStatus
640 result = RegOpenKeyA(clsidKey,
641 "MiscStatus",
642 &miscStatusKey);
645 if (result != ERROR_SUCCESS)
647 RegCloseKey(clsidKey);
648 return REGDB_E_READREGDB;
652 * Read the default value
654 OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
657 * Open the key specific to the requested aspect.
659 sprintf(keyName, "%ld", dwAspect);
661 result = RegOpenKeyA(miscStatusKey,
662 keyName,
663 &aspectKey);
665 if (result == ERROR_SUCCESS)
667 OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
668 RegCloseKey(aspectKey);
672 * Cleanup
674 RegCloseKey(miscStatusKey);
675 RegCloseKey(clsidKey);
677 return S_OK;
680 /******************************************************************************
681 * OleSetContainedObject [OLE32.128]
683 HRESULT WINAPI OleSetContainedObject(
684 LPUNKNOWN pUnknown,
685 BOOL fContained)
687 IRunnableObject* runnable = NULL;
688 HRESULT hres;
690 TRACE("(%p,%x), stub!\n", pUnknown, fContained);
692 hres = IUnknown_QueryInterface(pUnknown,
693 &IID_IRunnableObject,
694 (void**)&runnable);
696 if (SUCCEEDED(hres))
698 hres = IRunnableObject_SetContainedObject(runnable, fContained);
700 IRunnableObject_Release(runnable);
702 return hres;
705 return S_OK;
708 /******************************************************************************
709 * OleLoad [OLE32.112]
711 HRESULT WINAPI OleLoad(
712 LPSTORAGE pStg,
713 REFIID riid,
714 LPOLECLIENTSITE pClientSite,
715 LPVOID* ppvObj)
717 IPersistStorage* persistStorage = NULL;
718 IOleObject* oleObject = NULL;
719 STATSTG storageInfo;
720 HRESULT hres;
722 TRACE("(%p,%p,%p,%p)\n", pStg, riid, pClientSite, ppvObj);
725 * TODO, Conversion ... OleDoAutoConvert
729 * Get the class ID for the object.
731 hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
734 * Now, try and create the handler for the object
736 hres = CoCreateInstance(&storageInfo.clsid,
737 NULL,
738 CLSCTX_INPROC_HANDLER,
739 &IID_IOleObject,
740 (void**)&oleObject);
743 * If that fails, as it will most times, load the default
744 * OLE handler.
746 if (FAILED(hres))
748 hres = OleCreateDefaultHandler(&storageInfo.clsid,
749 NULL,
750 &IID_IOleObject,
751 (void**)&oleObject);
755 * If we couldn't find a handler... this is bad. Abort the whole thing.
757 if (FAILED(hres))
758 return hres;
761 * Inform the new object of it's client site.
763 hres = IOleObject_SetClientSite(oleObject, pClientSite);
766 * Initialize the object with it's IPersistStorage interface.
768 hres = IOleObject_QueryInterface(oleObject,
769 &IID_IPersistStorage,
770 (void**)&persistStorage);
772 if (SUCCEEDED(hres))
774 IPersistStorage_Load(persistStorage, pStg);
776 IPersistStorage_Release(persistStorage);
777 persistStorage = NULL;
781 * Return the requested interface to the caller.
783 hres = IOleObject_QueryInterface(oleObject, riid, ppvObj);
786 * Cleanup interfaces used internally
788 IOleObject_Release(oleObject);
790 return hres;
793 /***********************************************************************
794 * OleSave [OLE32.124]
796 HRESULT WINAPI OleSave(
797 LPPERSISTSTORAGE pPS,
798 LPSTORAGE pStg,
799 BOOL fSameAsLoad)
801 HRESULT hres;
802 CLSID objectClass;
804 TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad);
807 * First, we transfer the class ID (if available)
809 hres = IPersistStorage_GetClassID(pPS, &objectClass);
811 if (SUCCEEDED(hres))
813 WriteClassStg(pStg, &objectClass);
817 * Then, we ask the object to save itself to the
818 * storage. If it is successful, we commit the storage.
820 hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad);
822 if (SUCCEEDED(hres))
824 IStorage_Commit(pStg,
825 STGC_DEFAULT);
828 return hres;
832 /**************************************************************************
833 * Internal methods to manage the shared OLE menu in response to the
834 * OLE***MenuDescriptor API
837 /***
838 * OLEMenu_Initialize()
840 * Initializes the OLEMENU data structures.
842 static void OLEMenu_Initialize()
846 /***
847 * OLEMenu_UnInitialize()
849 * Releases the OLEMENU data structures.
851 static void OLEMenu_UnInitialize()
855 /*************************************************************************
856 * OLEMenu_InstallHooks
857 * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
859 * RETURNS: TRUE if message hooks were succesfully installed
860 * FALSE on failure
862 BOOL OLEMenu_InstallHooks( DWORD tid )
864 OleMenuHookItem *pHookItem = NULL;
866 /* Create an entry for the hook table */
867 if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
868 sizeof(OleMenuHookItem)) ) )
869 return FALSE;
871 pHookItem->tid = tid;
872 pHookItem->hHeap = GetProcessHeap();
874 /* Install a thread scope message hook for WH_GETMESSAGE */
875 pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc,
876 0, GetCurrentThreadId() );
877 if ( !pHookItem->GetMsg_hHook )
878 goto CLEANUP;
880 /* Install a thread scope message hook for WH_CALLWNDPROC */
881 pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc,
882 0, GetCurrentThreadId() );
883 if ( !pHookItem->CallWndProc_hHook )
884 goto CLEANUP;
886 /* Insert the hook table entry */
887 pHookItem->next = hook_list;
888 hook_list = pHookItem;
890 return TRUE;
892 CLEANUP:
893 /* Unhook any hooks */
894 if ( pHookItem->GetMsg_hHook )
895 UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
896 if ( pHookItem->CallWndProc_hHook )
897 UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
898 /* Release the hook table entry */
899 HeapFree(pHookItem->hHeap, 0, pHookItem );
901 return FALSE;
904 /*************************************************************************
905 * OLEMenu_UnInstallHooks
906 * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
908 * RETURNS: TRUE if message hooks were succesfully installed
909 * FALSE on failure
911 BOOL OLEMenu_UnInstallHooks( DWORD tid )
913 OleMenuHookItem *pHookItem = NULL;
914 OleMenuHookItem **ppHook = &hook_list;
916 while (*ppHook)
918 if ((*ppHook)->tid == tid)
920 pHookItem = *ppHook;
921 *ppHook = pHookItem->next;
922 break;
924 ppHook = &(*ppHook)->next;
926 if (!pHookItem) return FALSE;
928 /* Uninstall the hooks installed for this thread */
929 if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
930 goto CLEANUP;
931 if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
932 goto CLEANUP;
934 /* Release the hook table entry */
935 HeapFree(pHookItem->hHeap, 0, pHookItem );
937 return TRUE;
939 CLEANUP:
940 /* Release the hook table entry */
941 if (pHookItem)
942 HeapFree(pHookItem->hHeap, 0, pHookItem );
944 return FALSE;
947 /*************************************************************************
948 * OLEMenu_IsHookInstalled
949 * Tests if OLEMenu hooks have been installed for a thread
951 * RETURNS: The pointer and index of the hook table entry for the tid
952 * NULL and -1 for the index if no hooks were installed for this thread
954 OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )
956 OleMenuHookItem *pHookItem = NULL;
958 /* Do a simple linear search for an entry whose tid matches ours.
959 * We really need a map but efficiency is not a concern here. */
960 for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next)
962 if ( tid == pHookItem->tid )
963 return pHookItem;
966 return NULL;
969 /***********************************************************************
970 * OLEMenu_FindMainMenuIndex
972 * Used by OLEMenu API to find the top level group a menu item belongs to.
973 * On success pnPos contains the index of the item in the top level menu group
975 * RETURNS: TRUE if the ID was found, FALSE on failure
977 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
979 UINT i, nItems;
981 nItems = GetMenuItemCount( hMainMenu );
983 for (i = 0; i < nItems; i++)
985 HMENU hsubmenu;
987 /* Is the current item a submenu? */
988 if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
990 /* If the handle is the same we're done */
991 if ( hsubmenu == hPopupMenu )
993 if (pnPos)
994 *pnPos = i;
995 return TRUE;
997 /* Recursively search without updating pnPos */
998 else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
1000 if (pnPos)
1001 *pnPos = i;
1002 return TRUE;
1007 return FALSE;
1010 /***********************************************************************
1011 * OLEMenu_SetIsServerMenu
1013 * Checks whether a popup menu belongs to a shared menu group which is
1014 * owned by the server, and sets the menu descriptor state accordingly.
1015 * All menu messages from these groups should be routed to the server.
1017 * RETURNS: TRUE if the popup menu is part of a server owned group
1018 * FASE if the popup menu is part of a container owned group
1020 BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
1022 UINT nPos = 0, nWidth, i;
1024 pOleMenuDescriptor->bIsServerItem = FALSE;
1026 /* Don't bother searching if the popup is the combined menu itself */
1027 if ( hmenu == pOleMenuDescriptor->hmenuCombined )
1028 return FALSE;
1030 /* Find the menu item index in the shared OLE menu that this item belongs to */
1031 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) )
1032 return FALSE;
1034 /* The group widths array has counts for the number of elements
1035 * in the groups File, Edit, Container, Object, Window, Help.
1036 * The Edit, Object & Help groups belong to the server object
1037 * and the other three belong to the container.
1038 * Loop thru the group widths and locate the group we are a member of.
1040 for ( i = 0, nWidth = 0; i < 6; i++ )
1042 nWidth += pOleMenuDescriptor->mgw.width[i];
1043 if ( nPos < nWidth )
1045 /* Odd elements are server menu widths */
1046 pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;
1047 break;
1051 return pOleMenuDescriptor->bIsServerItem;
1054 /*************************************************************************
1055 * OLEMenu_CallWndProc
1056 * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
1057 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1059 LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
1061 LPCWPSTRUCT pMsg = NULL;
1062 HOLEMENU hOleMenu = 0;
1063 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1064 OleMenuHookItem *pHookItem = NULL;
1065 WORD fuFlags;
1067 TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1069 /* Check if we're being asked to process the message */
1070 if ( HC_ACTION != code )
1071 goto NEXTHOOK;
1073 /* Retrieve the current message being dispatched from lParam */
1074 pMsg = (LPCWPSTRUCT)lParam;
1076 /* Check if the message is destined for a window we are interested in:
1077 * If the window has an OLEMenu property we may need to dispatch
1078 * the menu message to its active objects window instead. */
1080 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1081 if ( !hOleMenu )
1082 goto NEXTHOOK;
1084 /* Get the menu descriptor */
1085 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1086 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1087 goto NEXTHOOK;
1089 /* Process menu messages */
1090 switch( pMsg->message )
1092 case WM_INITMENU:
1094 /* Reset the menu descriptor state */
1095 pOleMenuDescriptor->bIsServerItem = FALSE;
1097 /* Send this message to the server as well */
1098 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1099 pMsg->message, pMsg->wParam, pMsg->lParam );
1100 goto NEXTHOOK;
1103 case WM_INITMENUPOPUP:
1105 /* Save the state for whether this is a server owned menu */
1106 OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
1107 break;
1110 case WM_MENUSELECT:
1112 fuFlags = HIWORD(pMsg->wParam); /* Get flags */
1113 if ( fuFlags & MF_SYSMENU )
1114 goto NEXTHOOK;
1116 /* Save the state for whether this is a server owned popup menu */
1117 else if ( fuFlags & MF_POPUP )
1118 OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
1120 break;
1123 case WM_DRAWITEM:
1125 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
1126 if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
1127 goto NEXTHOOK; /* Not a menu message */
1129 break;
1132 default:
1133 goto NEXTHOOK;
1136 /* If the message was for the server dispatch it accordingly */
1137 if ( pOleMenuDescriptor->bIsServerItem )
1139 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1140 pMsg->message, pMsg->wParam, pMsg->lParam );
1143 NEXTHOOK:
1144 if ( pOleMenuDescriptor )
1145 GlobalUnlock( hOleMenu );
1147 /* Lookup the hook item for the current thread */
1148 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1150 /* This should never fail!! */
1151 WARN("could not retrieve hHook for current thread!\n" );
1152 return 0;
1155 /* Pass on the message to the next hooker */
1156 return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
1159 /*************************************************************************
1160 * OLEMenu_GetMsgProc
1161 * Thread scope WH_GETMESSAGE hook proc filter function (callback)
1162 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1164 LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
1166 LPMSG pMsg = NULL;
1167 HOLEMENU hOleMenu = 0;
1168 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1169 OleMenuHookItem *pHookItem = NULL;
1170 WORD wCode;
1172 TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1174 /* Check if we're being asked to process a messages */
1175 if ( HC_ACTION != code )
1176 goto NEXTHOOK;
1178 /* Retrieve the current message being dispatched from lParam */
1179 pMsg = (LPMSG)lParam;
1181 /* Check if the message is destined for a window we are interested in:
1182 * If the window has an OLEMenu property we may need to dispatch
1183 * the menu message to its active objects window instead. */
1185 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1186 if ( !hOleMenu )
1187 goto NEXTHOOK;
1189 /* Process menu messages */
1190 switch( pMsg->message )
1192 case WM_COMMAND:
1194 wCode = HIWORD(pMsg->wParam); /* Get notification code */
1195 if ( wCode )
1196 goto NEXTHOOK; /* Not a menu message */
1197 break;
1199 default:
1200 goto NEXTHOOK;
1203 /* Get the menu descriptor */
1204 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1205 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1206 goto NEXTHOOK;
1208 /* If the message was for the server dispatch it accordingly */
1209 if ( pOleMenuDescriptor->bIsServerItem )
1211 /* Change the hWnd in the message to the active objects hWnd.
1212 * The message loop which reads this message will automatically
1213 * dispatch it to the embedded objects window. */
1214 pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
1217 NEXTHOOK:
1218 if ( pOleMenuDescriptor )
1219 GlobalUnlock( hOleMenu );
1221 /* Lookup the hook item for the current thread */
1222 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1224 /* This should never fail!! */
1225 WARN("could not retrieve hHook for current thread!\n" );
1226 return FALSE;
1229 /* Pass on the message to the next hooker */
1230 return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
1233 /***********************************************************************
1234 * OleCreateMenuDescriptor [OLE32.97]
1235 * Creates an OLE menu descriptor for OLE to use when dispatching
1236 * menu messages and commands.
1238 * PARAMS:
1239 * hmenuCombined - Handle to the objects combined menu
1240 * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group
1243 HOLEMENU WINAPI OleCreateMenuDescriptor(
1244 HMENU hmenuCombined,
1245 LPOLEMENUGROUPWIDTHS lpMenuWidths)
1247 HOLEMENU hOleMenu;
1248 OleMenuDescriptor *pOleMenuDescriptor;
1249 int i;
1251 if ( !hmenuCombined || !lpMenuWidths )
1252 return 0;
1254 /* Create an OLE menu descriptor */
1255 if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
1256 sizeof(OleMenuDescriptor) ) ) )
1257 return 0;
1259 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1260 if ( !pOleMenuDescriptor )
1261 return 0;
1263 /* Initialize menu group widths and hmenu */
1264 for ( i = 0; i < 6; i++ )
1265 pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
1267 pOleMenuDescriptor->hmenuCombined = hmenuCombined;
1268 pOleMenuDescriptor->bIsServerItem = FALSE;
1269 GlobalUnlock( hOleMenu );
1271 return hOleMenu;
1274 /***********************************************************************
1275 * OleDestroyMenuDescriptor [OLE32.99]
1276 * Destroy the shared menu descriptor
1278 HRESULT WINAPI OleDestroyMenuDescriptor(
1279 HOLEMENU hmenuDescriptor)
1281 if ( hmenuDescriptor )
1282 GlobalFree( hmenuDescriptor );
1283 return S_OK;
1286 /***********************************************************************
1287 * OleSetMenuDescriptor [OLE32.129]
1288 * Installs or removes OLE dispatching code for the containers frame window
1289 * FIXME: The lpFrame and lpActiveObject parameters are currently ignored
1290 * OLE should install context sensitive help F1 filtering for the app when
1291 * these are non null.
1293 * PARAMS:
1294 * hOleMenu Handle to composite menu descriptor
1295 * hwndFrame Handle to containers frame window
1296 * hwndActiveObject Handle to objects in-place activation window
1297 * lpFrame Pointer to IOleInPlaceFrame on containers window
1298 * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object
1300 * RETURNS:
1301 * S_OK - menu installed correctly
1302 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1304 HRESULT WINAPI OleSetMenuDescriptor(
1305 HOLEMENU hOleMenu,
1306 HWND hwndFrame,
1307 HWND hwndActiveObject,
1308 LPOLEINPLACEFRAME lpFrame,
1309 LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1311 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1313 /* Check args */
1314 if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
1315 return E_INVALIDARG;
1317 if ( lpFrame || lpActiveObject )
1319 FIXME("(%x, %x, %x, %p, %p), Context sensitive help filtering not implemented!\n",
1320 (unsigned int)hOleMenu,
1321 hwndFrame,
1322 hwndActiveObject,
1323 lpFrame,
1324 lpActiveObject);
1327 /* Set up a message hook to intercept the containers frame window messages.
1328 * The message filter is responsible for dispatching menu messages from the
1329 * shared menu which are intended for the object.
1332 if ( hOleMenu ) /* Want to install dispatching code */
1334 /* If OLEMenu hooks are already installed for this thread, fail
1335 * Note: This effectively means that OleSetMenuDescriptor cannot
1336 * be called twice in succession on the same frame window
1337 * without first calling it with a null hOleMenu to uninstall */
1338 if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) )
1339 return E_FAIL;
1341 /* Get the menu descriptor */
1342 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1343 if ( !pOleMenuDescriptor )
1344 return E_UNEXPECTED;
1346 /* Update the menu descriptor */
1347 pOleMenuDescriptor->hwndFrame = hwndFrame;
1348 pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
1350 GlobalUnlock( hOleMenu );
1351 pOleMenuDescriptor = NULL;
1353 /* Add a menu descriptor windows property to the frame window */
1354 SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu );
1356 /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
1357 if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
1358 return E_FAIL;
1360 else /* Want to uninstall dispatching code */
1362 /* Uninstall the hooks */
1363 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1364 return E_FAIL;
1366 /* Remove the menu descriptor property from the frame window */
1367 RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" );
1370 return S_OK;
1373 /***********************************************************************
1374 * ReleaseStgMedium [OLE32.140]
1376 void WINAPI ReleaseStgMedium(
1377 STGMEDIUM* pmedium)
1379 switch (pmedium->tymed)
1381 case TYMED_HGLOBAL:
1383 if ( (pmedium->pUnkForRelease==0) &&
1384 (pmedium->u.hGlobal!=0) )
1385 GlobalFree(pmedium->u.hGlobal);
1387 pmedium->u.hGlobal = 0;
1388 break;
1390 case TYMED_FILE:
1392 if (pmedium->u.lpszFileName!=0)
1394 if (pmedium->pUnkForRelease==0)
1396 DeleteFileW(pmedium->u.lpszFileName);
1399 CoTaskMemFree(pmedium->u.lpszFileName);
1402 pmedium->u.lpszFileName = 0;
1403 break;
1405 case TYMED_ISTREAM:
1407 if (pmedium->u.pstm!=0)
1409 IStream_Release(pmedium->u.pstm);
1412 pmedium->u.pstm = 0;
1413 break;
1415 case TYMED_ISTORAGE:
1417 if (pmedium->u.pstg!=0)
1419 IStorage_Release(pmedium->u.pstg);
1422 pmedium->u.pstg = 0;
1423 break;
1425 case TYMED_GDI:
1427 if ( (pmedium->pUnkForRelease==0) &&
1428 (pmedium->u.hGlobal!=0) )
1429 DeleteObject(pmedium->u.hGlobal);
1431 pmedium->u.hGlobal = 0;
1432 break;
1434 case TYMED_MFPICT:
1436 if ( (pmedium->pUnkForRelease==0) &&
1437 (pmedium->u.hMetaFilePict!=0) )
1439 DeleteMetaFile(pmedium->u.hMetaFilePict);
1440 GlobalFree(pmedium->u.hMetaFilePict);
1443 pmedium->u.hMetaFilePict = 0;
1444 break;
1446 case TYMED_ENHMF:
1448 if ( (pmedium->pUnkForRelease==0) &&
1449 (pmedium->u.hEnhMetaFile!=0) )
1451 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
1454 pmedium->u.hEnhMetaFile = 0;
1455 break;
1457 case TYMED_NULL:
1458 default:
1459 break;
1463 * After cleaning up, the unknown is released
1465 if (pmedium->pUnkForRelease!=0)
1467 IUnknown_Release(pmedium->pUnkForRelease);
1468 pmedium->pUnkForRelease = 0;
1472 /***
1473 * OLEDD_Initialize()
1475 * Initializes the OLE drag and drop data structures.
1477 static void OLEDD_Initialize()
1479 WNDCLASSA wndClass;
1481 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1482 wndClass.style = CS_GLOBALCLASS;
1483 wndClass.lpfnWndProc = (WNDPROC)OLEDD_DragTrackerWindowProc;
1484 wndClass.cbClsExtra = 0;
1485 wndClass.cbWndExtra = sizeof(TrackerWindowInfo*);
1486 wndClass.hCursor = 0;
1487 wndClass.hbrBackground = 0;
1488 wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
1490 RegisterClassA (&wndClass);
1493 /***
1494 * OLEDD_UnInitialize()
1496 * Releases the OLE drag and drop data structures.
1498 static void OLEDD_UnInitialize()
1501 * Simply empty the list.
1503 while (targetListHead!=NULL)
1505 RevokeDragDrop(targetListHead->hwndTarget);
1509 /***
1510 * OLEDD_InsertDropTarget()
1512 * Insert the target node in the tree.
1514 static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd)
1516 DropTargetNode* curNode;
1517 DropTargetNode** parentNodeLink;
1520 * Iterate the tree to find the insertion point.
1522 curNode = targetListHead;
1523 parentNodeLink = &targetListHead;
1525 while (curNode!=NULL)
1527 if (nodeToAdd->hwndTarget<curNode->hwndTarget)
1530 * If the node we want to add has a smaller HWND, go left
1532 parentNodeLink = &curNode->prevDropTarget;
1533 curNode = curNode->prevDropTarget;
1535 else if (nodeToAdd->hwndTarget>curNode->hwndTarget)
1538 * If the node we want to add has a larger HWND, go right
1540 parentNodeLink = &curNode->nextDropTarget;
1541 curNode = curNode->nextDropTarget;
1543 else
1546 * The item was found in the list. It shouldn't have been there
1548 assert(FALSE);
1549 return;
1554 * If we get here, we have found a spot for our item. The parentNodeLink
1555 * pointer points to the pointer that we have to modify.
1556 * The curNode should be NULL. We just have to establish the link and Voila!
1558 assert(curNode==NULL);
1559 assert(parentNodeLink!=NULL);
1560 assert(*parentNodeLink==NULL);
1562 *parentNodeLink=nodeToAdd;
1565 /***
1566 * OLEDD_ExtractDropTarget()
1568 * Removes the target node from the tree.
1570 static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget)
1572 DropTargetNode* curNode;
1573 DropTargetNode** parentNodeLink;
1576 * Iterate the tree to find the insertion point.
1578 curNode = targetListHead;
1579 parentNodeLink = &targetListHead;
1581 while (curNode!=NULL)
1583 if (hwndOfTarget<curNode->hwndTarget)
1586 * If the node we want to add has a smaller HWND, go left
1588 parentNodeLink = &curNode->prevDropTarget;
1589 curNode = curNode->prevDropTarget;
1591 else if (hwndOfTarget>curNode->hwndTarget)
1594 * If the node we want to add has a larger HWND, go right
1596 parentNodeLink = &curNode->nextDropTarget;
1597 curNode = curNode->nextDropTarget;
1599 else
1602 * The item was found in the list. Detach it from it's parent and
1603 * re-insert it's kids in the tree.
1605 assert(parentNodeLink!=NULL);
1606 assert(*parentNodeLink==curNode);
1609 * We arbitrately re-attach the left sub-tree to the parent.
1611 *parentNodeLink = curNode->prevDropTarget;
1614 * And we re-insert the right subtree
1616 if (curNode->nextDropTarget!=NULL)
1618 OLEDD_InsertDropTarget(curNode->nextDropTarget);
1622 * The node we found is still a valid node once we complete
1623 * the unlinking of the kids.
1625 curNode->nextDropTarget=NULL;
1626 curNode->prevDropTarget=NULL;
1628 return curNode;
1633 * If we get here, the node is not in the tree
1635 return NULL;
1638 /***
1639 * OLEDD_FindDropTarget()
1641 * Finds information about the drop target.
1643 static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
1645 DropTargetNode* curNode;
1648 * Iterate the tree to find the HWND value.
1650 curNode = targetListHead;
1652 while (curNode!=NULL)
1654 if (hwndOfTarget<curNode->hwndTarget)
1657 * If the node we want to add has a smaller HWND, go left
1659 curNode = curNode->prevDropTarget;
1661 else if (hwndOfTarget>curNode->hwndTarget)
1664 * If the node we want to add has a larger HWND, go right
1666 curNode = curNode->nextDropTarget;
1668 else
1671 * The item was found in the list.
1673 return curNode;
1678 * If we get here, the item is not in the list
1680 return NULL;
1683 /***
1684 * OLEDD_DragTrackerWindowProc()
1686 * This method is the WindowProcedure of the drag n drop tracking
1687 * window. During a drag n Drop operation, an invisible window is created
1688 * to receive the user input and act upon it. This procedure is in charge
1689 * of this behavior.
1691 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
1692 HWND hwnd,
1693 UINT uMsg,
1694 WPARAM wParam,
1695 LPARAM lParam)
1697 switch (uMsg)
1699 case WM_CREATE:
1701 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
1703 SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams);
1706 break;
1708 case WM_MOUSEMOVE:
1710 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1711 POINT mousePos;
1714 * Get the current mouse position in screen coordinates.
1716 mousePos.x = LOWORD(lParam);
1717 mousePos.y = HIWORD(lParam);
1718 ClientToScreen(hwnd, &mousePos);
1721 * Track the movement of the mouse.
1723 OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam);
1725 break;
1727 case WM_LBUTTONUP:
1728 case WM_MBUTTONUP:
1729 case WM_RBUTTONUP:
1730 case WM_LBUTTONDOWN:
1731 case WM_MBUTTONDOWN:
1732 case WM_RBUTTONDOWN:
1734 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1735 POINT mousePos;
1738 * Get the current mouse position in screen coordinates.
1740 mousePos.x = LOWORD(lParam);
1741 mousePos.y = HIWORD(lParam);
1742 ClientToScreen(hwnd, &mousePos);
1745 * Notify everyone that the button state changed
1746 * TODO: Check if the "escape" key was pressed.
1748 OLEDD_TrackStateChange(trackerInfo, mousePos, wParam);
1750 break;
1755 * This is a window proc after all. Let's call the default.
1757 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1760 /***
1761 * OLEDD_TrackMouseMove()
1763 * This method is invoked while a drag and drop operation is in effect.
1764 * it will generate the appropriate callbacks in the drop source
1765 * and drop target. It will also provide the expected feedback to
1766 * the user.
1768 * params:
1769 * trackerInfo - Pointer to the structure identifying the
1770 * drag & drop operation that is currently
1771 * active.
1772 * mousePos - Current position of the mouse in screen
1773 * coordinates.
1774 * keyState - Contains the state of the shift keys and the
1775 * mouse buttons (MK_LBUTTON and the like)
1777 static void OLEDD_TrackMouseMove(
1778 TrackerWindowInfo* trackerInfo,
1779 POINT mousePos,
1780 DWORD keyState)
1782 HWND hwndNewTarget = 0;
1783 HRESULT hr = S_OK;
1786 * Get the handle of the window under the mouse
1788 hwndNewTarget = WindowFromPoint(mousePos);
1791 * Every time, we re-initialize the effects passed to the
1792 * IDropTarget to the effects allowed by the source.
1794 *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
1797 * If we are hovering over the same target as before, send the
1798 * DragOver notification
1800 if ( (trackerInfo->curDragTarget != 0) &&
1801 (trackerInfo->curDragTargetHWND==hwndNewTarget) )
1803 POINTL mousePosParam;
1806 * The documentation tells me that the coordinate should be in the target
1807 * window's coordinate space. However, the tests I made tell me the
1808 * coordinates should be in screen coordinates.
1810 mousePosParam.x = mousePos.x;
1811 mousePosParam.y = mousePos.y;
1813 IDropTarget_DragOver(trackerInfo->curDragTarget,
1814 keyState,
1815 mousePosParam,
1816 trackerInfo->pdwEffect);
1818 else
1820 DropTargetNode* newDropTargetNode = 0;
1823 * If we changed window, we have to notify our old target and check for
1824 * the new one.
1826 if (trackerInfo->curDragTarget!=0)
1828 IDropTarget_DragLeave(trackerInfo->curDragTarget);
1832 * Make sure we're hovering over a window.
1834 if (hwndNewTarget!=0)
1837 * Find-out if there is a drag target under the mouse
1839 newDropTargetNode = OLEDD_FindDropTarget(hwndNewTarget);
1841 trackerInfo->curDragTargetHWND = hwndNewTarget;
1842 trackerInfo->curDragTarget = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
1845 * If there is, notify it that we just dragged-in
1847 if (trackerInfo->curDragTarget!=0)
1849 POINTL mousePosParam;
1852 * The documentation tells me that the coordinate should be in the target
1853 * window's coordinate space. However, the tests I made tell me the
1854 * coordinates should be in screen coordinates.
1856 mousePosParam.x = mousePos.x;
1857 mousePosParam.y = mousePos.y;
1859 IDropTarget_DragEnter(trackerInfo->curDragTarget,
1860 trackerInfo->dataObject,
1861 keyState,
1862 mousePosParam,
1863 trackerInfo->pdwEffect);
1866 else
1869 * The mouse is not over a window so we don't track anything.
1871 trackerInfo->curDragTargetHWND = 0;
1872 trackerInfo->curDragTarget = 0;
1877 * Now that we have done that, we have to tell the source to give
1878 * us feedback on the work being done by the target. If we don't
1879 * have a target, simulate no effect.
1881 if (trackerInfo->curDragTarget==0)
1883 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
1886 hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
1887 *trackerInfo->pdwEffect);
1890 * When we ask for feedback from the drop source, sometimes it will
1891 * do all the necessary work and sometimes it will not handle it
1892 * when that's the case, we must display the standard drag and drop
1893 * cursors.
1895 if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
1897 if ( (*trackerInfo->pdwEffect & DROPEFFECT_MOVE) ||
1898 (*trackerInfo->pdwEffect & DROPEFFECT_COPY) ||
1899 (*trackerInfo->pdwEffect & DROPEFFECT_LINK) )
1901 SetCursor(LoadCursorA(0, IDC_SIZEALLA));
1903 else
1905 SetCursor(LoadCursorA(0, IDC_NOA));
1910 /***
1911 * OLEDD_TrackStateChange()
1913 * This method is invoked while a drag and drop operation is in effect.
1914 * It is used to notify the drop target/drop source callbacks when
1915 * the state of the keyboard or mouse button change.
1917 * params:
1918 * trackerInfo - Pointer to the structure identifying the
1919 * drag & drop operation that is currently
1920 * active.
1921 * mousePos - Current position of the mouse in screen
1922 * coordinates.
1923 * keyState - Contains the state of the shift keys and the
1924 * mouse buttons (MK_LBUTTON and the like)
1926 static void OLEDD_TrackStateChange(
1927 TrackerWindowInfo* trackerInfo,
1928 POINT mousePos,
1929 DWORD keyState)
1932 * Ask the drop source what to do with the operation.
1934 trackerInfo->returnValue = IDropSource_QueryContinueDrag(
1935 trackerInfo->dropSource,
1936 trackerInfo->escPressed,
1937 keyState);
1940 * All the return valued will stop the operation except the S_OK
1941 * return value.
1943 if (trackerInfo->returnValue!=S_OK)
1946 * Make sure the message loop in DoDragDrop stops
1948 trackerInfo->trackingDone = TRUE;
1951 * Release the mouse in case the drop target decides to show a popup
1952 * or a menu or something.
1954 ReleaseCapture();
1957 * If we end-up over a target, drop the object in the target or
1958 * inform the target that the operation was cancelled.
1960 if (trackerInfo->curDragTarget!=0)
1962 switch (trackerInfo->returnValue)
1965 * If the source wants us to complete the operation, we tell
1966 * the drop target that we just dropped the object in it.
1968 case DRAGDROP_S_DROP:
1970 POINTL mousePosParam;
1973 * The documentation tells me that the coordinate should be
1974 * in the target window's coordinate space. However, the tests
1975 * I made tell me the coordinates should be in screen coordinates.
1977 mousePosParam.x = mousePos.x;
1978 mousePosParam.y = mousePos.y;
1980 IDropTarget_Drop(trackerInfo->curDragTarget,
1981 trackerInfo->dataObject,
1982 keyState,
1983 mousePosParam,
1984 trackerInfo->pdwEffect);
1985 break;
1988 * If the source told us that we should cancel, fool the drop
1989 * target by telling it that the mouse left it's window.
1990 * Also set the drop effect to "NONE" in case the application
1991 * ignores the result of DoDragDrop.
1993 case DRAGDROP_S_CANCEL:
1994 IDropTarget_DragLeave(trackerInfo->curDragTarget);
1995 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
1996 break;
2002 /***
2003 * OLEDD_GetButtonState()
2005 * This method will use the current state of the keyboard to build
2006 * a button state mask equivalent to the one passed in the
2007 * WM_MOUSEMOVE wParam.
2009 static DWORD OLEDD_GetButtonState()
2011 BYTE keyboardState[256];
2012 DWORD keyMask = 0;
2014 GetKeyboardState(keyboardState);
2016 if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
2017 keyMask |= MK_SHIFT;
2019 if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
2020 keyMask |= MK_CONTROL;
2022 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
2023 keyMask |= MK_LBUTTON;
2025 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
2026 keyMask |= MK_RBUTTON;
2028 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
2029 keyMask |= MK_MBUTTON;
2031 return keyMask;
2034 /***
2035 * OLEDD_GetButtonState()
2037 * This method will read the default value of the registry key in
2038 * parameter and extract a DWORD value from it. The registry key value
2039 * can be in a string key or a DWORD key.
2041 * params:
2042 * regKey - Key to read the default value from
2043 * pdwValue - Pointer to the location where the DWORD
2044 * value is returned. This value is not modified
2045 * if the value is not found.
2048 static void OLEUTL_ReadRegistryDWORDValue(
2049 HKEY regKey,
2050 DWORD* pdwValue)
2052 char buffer[20];
2053 DWORD dwKeyType;
2054 DWORD cbData = 20;
2055 LONG lres;
2057 lres = RegQueryValueExA(regKey,
2059 NULL,
2060 &dwKeyType,
2061 (LPBYTE)buffer,
2062 &cbData);
2064 if (lres==ERROR_SUCCESS)
2066 switch (dwKeyType)
2068 case REG_DWORD:
2069 *pdwValue = *(DWORD*)buffer;
2070 break;
2071 case REG_EXPAND_SZ:
2072 case REG_MULTI_SZ:
2073 case REG_SZ:
2074 *pdwValue = (DWORD)strtoul(buffer, NULL, 10);
2075 break;
2080 /******************************************************************************
2081 * OleMetaFilePictFromIconAndLabel
2083 * Returns a global memory handle to a metafile which contains the icon and
2084 * label given.
2085 * I guess the result of that should look somehow like desktop icons.
2086 * If no hIcon is given, we load the icon via lpszSourceFile and iIconIndex.
2087 * This code might be wrong at some places.
2089 HGLOBAL16 WINAPI OleMetaFilePictFromIconAndLabel16(
2090 HICON16 hIcon,
2091 LPCOLESTR16 lpszLabel,
2092 LPCOLESTR16 lpszSourceFile,
2093 UINT16 iIconIndex
2095 METAFILEPICT16 *mf;
2096 HGLOBAL16 hmf;
2097 HDC16 hdc;
2099 FIXME("(%04x, '%s', '%s', %d): incorrect metrics, please try to correct them !\n\n\n", hIcon, lpszLabel, lpszSourceFile, iIconIndex);
2101 if (!hIcon) {
2102 if (lpszSourceFile) {
2103 HINSTANCE16 hInstance = LoadLibrary16(lpszSourceFile);
2105 /* load the icon at index from lpszSourceFile */
2106 hIcon = (HICON16)LoadIconA(hInstance, (LPCSTR)(DWORD)iIconIndex);
2107 FreeLibrary16(hInstance);
2108 } else
2109 return (HGLOBAL)NULL;
2112 hdc = CreateMetaFile16(NULL);
2113 DrawIcon(hdc, 0, 0, hIcon); /* FIXME */
2114 TextOut16(hdc, 0, 0, lpszLabel, 1); /* FIXME */
2115 hmf = GlobalAlloc16(0, sizeof(METAFILEPICT16));
2116 mf = (METAFILEPICT16 *)GlobalLock16(hmf);
2117 mf->mm = MM_ANISOTROPIC;
2118 mf->xExt = 20; /* FIXME: bogus */
2119 mf->yExt = 20; /* dito */
2120 mf->hMF = CloseMetaFile16(hdc);
2121 return hmf;