Fix InitTask() to work if DGROUP was manually resized.
[wine/gsoc_dplay.git] / ole / ole2.c
blob3d0aee0e47661b2e167e6b60129eb2026e3194a4
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 "hook.h"
18 #include "commctrl.h"
19 #include "wine/obj_clientserver.h"
20 #include "wine/wingdi16.h"
21 #include "debugtools.h"
22 #include "ole2ver.h"
23 #include "winreg.h"
25 DEFAULT_DEBUG_CHANNEL(ole)
27 /******************************************************************************
28 * These are static/global variables and internal data structures that the
29 * OLE module uses to maintain it's state.
31 typedef struct tagDropTargetNode
33 HWND hwndTarget;
34 IDropTarget* dropTarget;
35 struct tagDropTargetNode* prevDropTarget;
36 struct tagDropTargetNode* nextDropTarget;
37 } DropTargetNode;
39 typedef struct tagTrackerWindowInfo
41 IDataObject* dataObject;
42 IDropSource* dropSource;
43 DWORD dwOKEffect;
44 DWORD* pdwEffect;
45 BOOL trackingDone;
46 HRESULT returnValue;
48 BOOL escPressed;
49 HWND curDragTargetHWND;
50 IDropTarget* curDragTarget;
51 } TrackerWindowInfo;
53 typedef struct tagOleMenuDescriptor /* OleMenuDescriptor */
55 HWND hwndFrame; /* The containers frame window */
56 HWND hwndActiveObject; /* The active objects window */
57 OLEMENUGROUPWIDTHS mgw; /* OLE menu group widths for the shared menu */
58 HMENU hmenuCombined; /* The combined menu */
59 BOOL bIsServerItem; /* True if the currently open popup belongs to the server */
60 } OleMenuDescriptor;
62 typedef struct tagOleMenuHookItem /* OleMenu hook item in per thread hook list */
64 DWORD tid; /* Thread Id */
65 HANDLE hHeap; /* Heap this is allocated from */
66 HHOOK GetMsg_hHook; /* message hook for WH_GETMESSAGE */
67 HHOOK CallWndProc_hHook; /* message hook for WH_CALLWNDPROC */
68 } OleMenuHookItem;
71 * Dynamic pointer array of per thread message hooks (maintained by OleSetMenuDescriptor)
73 static HDPA OLEMenu_MsgHookDPA = NULL;
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, INT *pixHook );
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 utility methods used for OLE Drag n Drop
112 static void OLEDD_Initialize();
113 static void OLEDD_UnInitialize();
114 static void OLEDD_InsertDropTarget(
115 DropTargetNode* nodeToAdd);
116 static DropTargetNode* OLEDD_ExtractDropTarget(
117 HWND hwndOfTarget);
118 static DropTargetNode* OLEDD_FindDropTarget(
119 HWND hwndOfTarget);
120 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
121 HWND hwnd,
122 UINT uMsg,
123 WPARAM wParam,
124 LPARAM lParam);
125 static void OLEDD_TrackMouseMove(
126 TrackerWindowInfo* trackerInfo,
127 POINT mousePos,
128 DWORD keyState);
129 static void OLEDD_TrackStateChange(
130 TrackerWindowInfo* trackerInfo,
131 POINT mousePos,
132 DWORD keyState);
133 static DWORD OLEDD_GetButtonState();
136 /******************************************************************************
137 * OleBuildVersion [OLE2.1]
139 DWORD WINAPI OleBuildVersion(void)
141 TRACE("(void)\n");
142 return (rmm<<16)+rup;
145 /***********************************************************************
146 * OleInitialize (OLE2.2) (OLE32.108)
148 HRESULT WINAPI OleInitialize(LPVOID reserved)
150 HRESULT hr;
152 TRACE("(%p)\n", reserved);
155 * The first duty of the OleInitialize is to initialize the COM libraries.
157 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
160 * If the CoInitializeEx call failed, the OLE libraries can't be
161 * initialized.
163 if (FAILED(hr))
164 return hr;
167 * Then, it has to initialize the OLE specific modules.
168 * This includes:
169 * Clipboard
170 * Drag and Drop
171 * Object linking and Embedding
172 * In-place activation
174 if (OLE_moduleLockCount==0)
177 * Initialize the libraries.
179 TRACE("() - Initializing the OLE libraries\n");
182 * Drag and Drop
184 OLEDD_Initialize();
187 * OLE shared menu
189 OLEMenu_Initialize();
193 * Then, we increase the lock count on the OLE module.
195 OLE_moduleLockCount++;
197 return hr;
200 /******************************************************************************
201 * CoGetCurrentProcess [COMPOBJ.34] [OLE2.2][OLE32.108]
203 * NOTES
204 * Is DWORD really the correct return type for this function?
206 DWORD WINAPI CoGetCurrentProcess(void) {
207 return (DWORD)PROCESS_Current();
210 /******************************************************************************
211 * OleUninitialize [OLE2.3] [OLE32.131]
213 void WINAPI OleUninitialize(void)
215 TRACE("()\n");
218 * Decrease the lock count on the OLE module.
220 OLE_moduleLockCount--;
223 * If we hit the bottom of the lock stack, free the libraries.
225 if (OLE_moduleLockCount==0)
228 * Actually free the libraries.
230 TRACE("() - Freeing the last reference count\n");
233 * Drag and Drop
235 OLEDD_UnInitialize();
238 * OLE shared menu
240 OLEMenu_UnInitialize();
244 * Then, uninitialize the COM libraries.
246 CoUninitialize();
249 /***********************************************************************
250 * OleFlushClipboard [OLE2.76]
252 HRESULT WINAPI OleFlushClipboard16(void)
254 return S_OK;
257 /***********************************************************************
258 * OleSetClipboard [OLE32.127]
260 HRESULT WINAPI OleSetClipboard(LPVOID pDataObj)
262 FIXME("(%p), stub!\n", pDataObj);
263 return S_OK;
266 /******************************************************************************
267 * CoRegisterMessageFilter32 [OLE32.38]
269 HRESULT WINAPI CoRegisterMessageFilter(
270 LPMESSAGEFILTER lpMessageFilter, /* Pointer to interface */
271 LPMESSAGEFILTER *lplpMessageFilter /* Indirect pointer to prior instance if non-NULL */
273 FIXME("stub\n");
274 if (lplpMessageFilter) {
275 *lplpMessageFilter = NULL;
277 return S_OK;
280 /******************************************************************************
281 * OleInitializeWOW [OLE32.109]
283 HRESULT WINAPI OleInitializeWOW(DWORD x) {
284 FIXME("(0x%08lx),stub!\n",x);
285 return 0;
288 /***********************************************************************
289 * RegisterDragDrop16 (OLE2.35)
291 HRESULT WINAPI RegisterDragDrop16(
292 HWND16 hwnd,
293 LPDROPTARGET pDropTarget
295 FIXME("(0x%04x,%p),stub!\n",hwnd,pDropTarget);
296 return S_OK;
299 /***********************************************************************
300 * RegisterDragDrop32 (OLE32.139)
302 HRESULT WINAPI RegisterDragDrop(
303 HWND hwnd,
304 LPDROPTARGET pDropTarget)
306 DropTargetNode* dropTargetInfo;
308 TRACE("(0x%x,%p)\n", hwnd, pDropTarget);
311 * First, check if the window is already registered.
313 dropTargetInfo = OLEDD_FindDropTarget(hwnd);
315 if (dropTargetInfo!=NULL)
316 return DRAGDROP_E_ALREADYREGISTERED;
319 * If it's not there, we can add it. We first create a node for it.
321 dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));
323 if (dropTargetInfo==NULL)
324 return E_OUTOFMEMORY;
326 dropTargetInfo->hwndTarget = hwnd;
327 dropTargetInfo->prevDropTarget = NULL;
328 dropTargetInfo->nextDropTarget = NULL;
331 * Don't forget that this is an interface pointer, need to nail it down since
332 * we keep a copy of it.
334 dropTargetInfo->dropTarget = pDropTarget;
335 IDropTarget_AddRef(dropTargetInfo->dropTarget);
337 OLEDD_InsertDropTarget(dropTargetInfo);
339 return S_OK;
342 /***********************************************************************
343 * RevokeDragDrop16 (OLE2.36)
345 HRESULT WINAPI RevokeDragDrop16(
346 HWND16 hwnd
348 FIXME("(0x%04x),stub!\n",hwnd);
349 return S_OK;
352 /***********************************************************************
353 * RevokeDragDrop32 (OLE32.141)
355 HRESULT WINAPI RevokeDragDrop(
356 HWND hwnd)
358 DropTargetNode* dropTargetInfo;
360 TRACE("(0x%x)\n", hwnd);
363 * First, check if the window is already registered.
365 dropTargetInfo = OLEDD_ExtractDropTarget(hwnd);
368 * If it ain't in there, it's an error.
370 if (dropTargetInfo==NULL)
371 return DRAGDROP_E_NOTREGISTERED;
374 * If it's in there, clean-up it's used memory and
375 * references
377 IDropTarget_Release(dropTargetInfo->dropTarget);
378 HeapFree(GetProcessHeap(), 0, dropTargetInfo);
380 return S_OK;
383 /***********************************************************************
384 * OleRegGetUserType (OLE32.122)
386 * This implementation of OleRegGetUserType ignores the dwFormOfType
387 * parameter and always returns the full name of the object. This is
388 * not too bad since this is the case for many objects because of the
389 * way they are registered.
391 HRESULT WINAPI OleRegGetUserType(
392 REFCLSID clsid,
393 DWORD dwFormOfType,
394 LPOLESTR* pszUserType)
396 char xclsid[50];
397 char keyName[60];
398 DWORD dwKeyType;
399 DWORD cbData;
400 HKEY clsidKey;
401 LONG hres;
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);
452 if (*pszUserType==NULL)
454 RegCloseKey(clsidKey);
455 return E_OUTOFMEMORY;
458 hres = RegQueryValueExA(HKEY_CLASSES_ROOT,
460 NULL,
461 &dwKeyType,
462 (LPBYTE)*pszUserType,
463 &cbData);
465 RegCloseKey(clsidKey);
467 if (hres!=ERROR_SUCCESS)
469 CoTaskMemFree(*pszUserType);
470 *pszUserType=NULL;
472 return REGDB_E_READREGDB;
475 return S_OK;
478 /***********************************************************************
479 * DoDragDrop32 [OLE32.65]
481 HRESULT WINAPI DoDragDrop (
482 IDataObject *pDataObject, /* ptr to the data obj */
483 IDropSource* pDropSource, /* ptr to the source obj */
484 DWORD dwOKEffect, /* effects allowed by the source */
485 DWORD *pdwEffect) /* ptr to effects of the source */
487 TrackerWindowInfo trackerInfo;
488 HWND hwndTrackWindow;
489 MSG msg;
491 TRACE("(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
494 * Setup the drag n drop tracking window.
496 trackerInfo.dataObject = pDataObject;
497 trackerInfo.dropSource = pDropSource;
498 trackerInfo.dwOKEffect = dwOKEffect;
499 trackerInfo.pdwEffect = pdwEffect;
500 trackerInfo.trackingDone = FALSE;
501 trackerInfo.escPressed = FALSE;
502 trackerInfo.curDragTargetHWND = 0;
503 trackerInfo.curDragTarget = 0;
505 hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS,
506 "TrackerWindow",
507 WS_POPUP,
508 CW_USEDEFAULT, CW_USEDEFAULT,
509 CW_USEDEFAULT, CW_USEDEFAULT,
513 (LPVOID)&trackerInfo);
515 if (hwndTrackWindow!=0)
518 * Capture the mouse input
520 SetCapture(hwndTrackWindow);
523 * Pump messages. All mouse input should go the the capture window.
525 while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )
527 if ( (msg.message >= WM_KEYFIRST) &&
528 (msg.message <= WM_KEYFIRST) )
531 * When keyboard messages are sent to windows on this thread, we
532 * want to ignore notify the drop source that the state changed.
533 * in the case of the Escape key, we also notify the drop source
534 * we give it a special meaning.
536 if ( (msg.message==WM_KEYDOWN) &&
537 (msg.wParam==VK_ESCAPE) )
539 trackerInfo.escPressed = TRUE;
543 * Notify the drop source.
545 OLEDD_TrackStateChange(&trackerInfo,
546 msg.pt,
547 OLEDD_GetButtonState());
549 else
552 * Dispatch the messages only when it's not a keyboard message.
554 DispatchMessageA(&msg);
559 * Destroy the temporary window.
561 DestroyWindow(hwndTrackWindow);
563 return trackerInfo.returnValue;
566 return E_FAIL;
569 /***********************************************************************
570 * OleQueryLinkFromData32 [OLE32.118]
572 HRESULT WINAPI OleQueryLinkFromData(
573 IDataObject* pSrcDataObject)
575 FIXME("(%p),stub!\n", pSrcDataObject);
576 return S_OK;
579 /***********************************************************************
580 * OleRegGetMiscStatus [OLE32.121]
582 HRESULT WINAPI OleRegGetMiscStatus(
583 REFCLSID clsid,
584 DWORD dwAspect,
585 DWORD* pdwStatus)
587 char xclsid[50];
588 char keyName[60];
589 HKEY clsidKey;
590 HKEY miscStatusKey;
591 HKEY aspectKey;
592 LONG result;
595 * Initialize the out parameter.
597 *pdwStatus = 0;
600 * Build the key name we're looking for
602 WINE_StringFromCLSID((LPCLSID)clsid, xclsid);
604 strcpy(keyName, "CLSID\\");
605 strcat(keyName, xclsid);
606 strcat(keyName, "\\");
608 TRACE("(%s, %ld, %p)\n", keyName, dwAspect, pdwStatus);
611 * Open the class id Key
613 result = RegOpenKeyA(HKEY_CLASSES_ROOT,
614 keyName,
615 &clsidKey);
617 if (result != ERROR_SUCCESS)
618 return REGDB_E_CLASSNOTREG;
621 * Get the MiscStatus
623 result = RegOpenKeyA(clsidKey,
624 "MiscStatus",
625 &miscStatusKey);
628 if (result != ERROR_SUCCESS)
630 RegCloseKey(clsidKey);
631 return REGDB_E_READREGDB;
635 * Read the default value
637 OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
640 * Open the key specific to the requested aspect.
642 sprintf(keyName, "%ld", dwAspect);
644 result = RegOpenKeyA(miscStatusKey,
645 keyName,
646 &aspectKey);
648 if (result == ERROR_SUCCESS)
650 OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
651 RegCloseKey(aspectKey);
655 * Cleanup
657 RegCloseKey(miscStatusKey);
658 RegCloseKey(clsidKey);
660 return S_OK;
663 /******************************************************************************
664 * OleSetContainedObject [OLE32.128]
666 HRESULT WINAPI OleSetContainedObject(
667 LPUNKNOWN pUnknown,
668 BOOL fContained)
670 IRunnableObject* runnable = NULL;
671 HRESULT hres;
673 TRACE("(%p,%x), stub!\n", pUnknown, fContained);
675 hres = IUnknown_QueryInterface(pUnknown,
676 &IID_IRunnableObject,
677 (void**)&runnable);
679 if (SUCCEEDED(hres))
681 hres = IRunnableObject_SetContainedObject(runnable, fContained);
683 IRunnableObject_Release(runnable);
685 return hres;
688 return S_OK;
691 /******************************************************************************
692 * OleLoad [OLE32.112]
694 HRESULT WINAPI OleLoad(
695 LPSTORAGE pStg,
696 REFIID riid,
697 LPOLECLIENTSITE pClientSite,
698 LPVOID* ppvObj)
700 IPersistStorage* persistStorage = NULL;
701 IOleObject* oleObject = NULL;
702 STATSTG storageInfo;
703 HRESULT hres;
705 TRACE("(%p,%p,%p,%p)\n", pStg, riid, pClientSite, ppvObj);
708 * TODO, Conversion ... OleDoAutoConvert
712 * Get the class ID for the object.
714 hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
717 * Now, try and create the handler for the object
719 hres = CoCreateInstance(&storageInfo.clsid,
720 NULL,
721 CLSCTX_INPROC_HANDLER,
722 &IID_IOleObject,
723 (void**)&oleObject);
726 * If that fails, as it will most times, load the default
727 * OLE handler.
729 if (FAILED(hres))
731 hres = OleCreateDefaultHandler(&storageInfo.clsid,
732 NULL,
733 &IID_IOleObject,
734 (void**)&oleObject);
738 * If we couldn't find a handler... this is bad. Abort the whole thing.
740 if (FAILED(hres))
741 return hres;
744 * Inform the new object of it's client site.
746 hres = IOleObject_SetClientSite(oleObject, pClientSite);
749 * Initialize the object with it's IPersistStorage interface.
751 hres = IOleObject_QueryInterface(oleObject,
752 &IID_IPersistStorage,
753 (void**)&persistStorage);
755 if (SUCCEEDED(hres))
757 IPersistStorage_Load(persistStorage, pStg);
759 IPersistStorage_Release(persistStorage);
760 persistStorage = NULL;
764 * Return the requested interface to the caller.
766 hres = IOleObject_QueryInterface(oleObject, riid, ppvObj);
769 * Cleanup interfaces used internally
771 IOleObject_Release(oleObject);
773 return hres;
776 /***********************************************************************
777 * OleSave [OLE32.124]
779 HRESULT WINAPI OleSave(
780 LPPERSISTSTORAGE pPS,
781 LPSTORAGE pStg,
782 BOOL fSameAsLoad)
784 HRESULT hres;
785 CLSID objectClass;
787 TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad);
790 * First, we transfer the class ID (if available)
792 hres = IPersistStorage_GetClassID(pPS, &objectClass);
794 if (SUCCEEDED(hres))
796 WriteClassStg(pStg, &objectClass);
800 * Then, we ask the object to save itself to the
801 * storage. If it is successful, we commit the storage.
803 hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad);
805 if (SUCCEEDED(hres))
807 IStorage_Commit(pStg,
808 STGC_DEFAULT);
811 return hres;
815 /***********************************************************************
816 * OleGetClipboard32 [OLE32.105]
818 HRESULT WINAPI OleGetClipboard(
819 IDataObject** ppDataObj)
821 FIXME("(%p),stub!\n", ppDataObj);
823 if (ppDataObj)
824 *ppDataObj=0;
826 return E_FAIL;
830 /**************************************************************************
831 * Internal methods to manage the shared OLE menu in response to the
832 * OLE***MenuDescriptor API
835 /***
836 * OLEMenu_Initialize()
838 * Initializes the OLEMENU data structures.
840 static void OLEMenu_Initialize()
842 /* Create a dynamic pointer array to store the hook handles */
843 if ( !OLEMenu_MsgHookDPA )
844 OLEMenu_MsgHookDPA = DPA_CreateEx( 2, GetProcessHeap() );
847 /***
848 * OLEMenu_UnInitialize()
850 * Releases the OLEMENU data structures.
852 static void OLEMenu_UnInitialize()
854 /* Release the hook table */
855 if ( OLEMenu_MsgHookDPA )
856 DPA_Destroy( OLEMenu_MsgHookDPA );
858 OLEMenu_MsgHookDPA = NULL;
861 /*************************************************************************
862 * OLEMenu_InstallHooks
863 * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
865 * RETURNS: TRUE if message hooks were succesfully installed
866 * FALSE on failure
868 BOOL OLEMenu_InstallHooks( DWORD tid )
870 OleMenuHookItem *pHookItem = NULL;
872 if ( !OLEMenu_MsgHookDPA ) /* No hook table? Create one */
874 /* Create a dynamic pointer array to store the hook handles */
875 if ( !(OLEMenu_MsgHookDPA = DPA_CreateEx( 2, GetProcessHeap() )) )
876 return FALSE;
879 /* Create an entry for the hook table */
880 if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
881 sizeof(OleMenuHookItem)) ) )
882 return FALSE;
884 pHookItem->tid = tid;
885 pHookItem->hHeap = GetProcessHeap();
887 /* Install a thread scope message hook for WH_GETMESSAGE */
888 pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc,
889 0, GetCurrentThreadId() );
890 if ( !pHookItem->GetMsg_hHook )
891 goto CLEANUP;
893 /* Install a thread scope message hook for WH_CALLWNDPROC */
894 pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc,
895 0, GetCurrentThreadId() );
896 if ( !pHookItem->CallWndProc_hHook )
897 goto CLEANUP;
899 /* Insert the hook table entry */
900 if ( -1 == DPA_InsertPtr( OLEMenu_MsgHookDPA, 0, pHookItem ) )
901 goto CLEANUP;
903 return TRUE;
905 CLEANUP:
906 /* Unhook any hooks */
907 if ( pHookItem->GetMsg_hHook )
908 UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
909 if ( pHookItem->CallWndProc_hHook )
910 UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
911 /* Release the hook table entry */
912 HeapFree(pHookItem->hHeap, 0, pHookItem );
914 return FALSE;
917 /*************************************************************************
918 * OLEMenu_UnInstallHooks
919 * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
921 * RETURNS: TRUE if message hooks were succesfully installed
922 * FALSE on failure
924 BOOL OLEMenu_UnInstallHooks( DWORD tid )
926 INT ixHook;
927 OleMenuHookItem *pHookItem = NULL;
929 if ( !OLEMenu_MsgHookDPA ) /* No hooks set */
930 return TRUE;
932 /* Lookup the hHook index for this tid */
933 if ( !OLEMenu_IsHookInstalled( tid , &ixHook ) )
934 return TRUE;
936 /* Remove the hook entry from the table(the pointer itself is not deleted) */
937 if ( !( pHookItem = DPA_DeletePtr(OLEMenu_MsgHookDPA, ixHook) ) )
938 return FALSE;
940 /* Uninstall the hooks installed for this thread */
941 if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
942 goto CLEANUP;
943 if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
944 goto CLEANUP;
946 /* Release the hook table entry */
947 HeapFree(pHookItem->hHeap, 0, pHookItem );
949 return TRUE;
951 CLEANUP:
952 /* Release the hook table entry */
953 if (pHookItem)
954 HeapFree(pHookItem->hHeap, 0, pHookItem );
956 return FALSE;
959 /*************************************************************************
960 * OLEMenu_IsHookInstalled
961 * Tests if OLEMenu hooks have been installed for a thread
963 * RETURNS: The pointer and index of the hook table entry for the tid
964 * NULL and -1 for the index if no hooks were installed for this thread
966 OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid, INT *pixHook )
968 INT ixHook;
969 OleMenuHookItem *pHookItem = NULL;
971 if ( pixHook )
972 *pixHook = -1;
974 if ( !OLEMenu_MsgHookDPA ) /* No hooks set */
975 return NULL;
977 /* Do a simple linear search for an entry whose tid matches ours.
978 * We really need a map but efficiency is not a concern here. */
979 for( ixHook = 0; ; ixHook++ )
981 /* Retrieve the hook entry */
982 if ( !( pHookItem = DPA_GetPtr(OLEMenu_MsgHookDPA, ixHook) ) )
983 return NULL;
985 if ( tid == pHookItem->tid )
987 if ( pixHook )
988 *pixHook = ixHook;
989 return pHookItem;
993 return NULL;
996 /***********************************************************************
997 * OLEMenu_FindMainMenuIndex
999 * Used by OLEMenu API to find the top level group a menu item belongs to.
1000 * On success pnPos contains the index of the item in the top level menu group
1002 * RETURNS: TRUE if the ID was found, FALSE on failure
1004 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
1006 UINT i, nItems;
1008 nItems = GetMenuItemCount( hMainMenu );
1010 for (i = 0; i < nItems; i++)
1012 HMENU hsubmenu;
1014 /* Is the current item a submenu? */
1015 if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
1017 /* If the handle is the same we're done */
1018 if ( hsubmenu == hPopupMenu )
1020 if (pnPos)
1021 *pnPos = i;
1022 return TRUE;
1024 /* Recursively search without updating pnPos */
1025 else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
1027 if (pnPos)
1028 *pnPos = i;
1029 return TRUE;
1034 return FALSE;
1037 /***********************************************************************
1038 * OLEMenu_SetIsServerMenu
1040 * Checks whether a popup menu belongs to a shared menu group which is
1041 * owned by the server, and sets the menu descriptor state accordingly.
1042 * All menu messages from these groups should be routed to the server.
1044 * RETURNS: TRUE if the popup menu is part of a server owned group
1045 * FASE if the popup menu is part of a container owned group
1047 BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
1049 UINT nPos = 0, nWidth, i;
1051 pOleMenuDescriptor->bIsServerItem = FALSE;
1053 /* Don't bother searching if the popup is the combined menu itself */
1054 if ( hmenu == pOleMenuDescriptor->hmenuCombined )
1055 return FALSE;
1057 /* Find the menu item index in the shared OLE menu that this item belongs to */
1058 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) )
1059 return FALSE;
1061 /* The group widths array has counts for the number of elements
1062 * in the groups File, Edit, Container, Object, Window, Help.
1063 * The Edit, Object & Help groups belong to the server object
1064 * and the other three belong to the container.
1065 * Loop thru the group widths and locate the group we are a member of.
1067 for ( i = 0, nWidth = 0; i < 6; i++ )
1069 nWidth += pOleMenuDescriptor->mgw.width[i];
1070 if ( nPos < nWidth )
1072 /* Odd elements are server menu widths */
1073 pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;
1074 break;
1078 return pOleMenuDescriptor->bIsServerItem;
1081 /*************************************************************************
1082 * OLEMenu_CallWndProc
1083 * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
1084 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1086 LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
1088 LPCWPSTRUCT pMsg = NULL;
1089 HOLEMENU hOleMenu = 0;
1090 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1091 OleMenuHookItem *pHookItem = NULL;
1092 WORD fuFlags;
1094 TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1096 /* Check if we're being asked to process the message */
1097 if ( HC_ACTION != code )
1098 goto NEXTHOOK;
1100 /* Retrieve the current message being dispatched from lParam */
1101 pMsg = (LPCWPSTRUCT)lParam;
1103 /* Check if the message is destined for a window we are interested in:
1104 * If the window has an OLEMenu property we may need to dispatch
1105 * the menu message to its active objects window instead. */
1107 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1108 if ( !hOleMenu )
1109 goto NEXTHOOK;
1111 /* Get the menu descriptor */
1112 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1113 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1114 goto NEXTHOOK;
1116 /* Process menu messages */
1117 switch( pMsg->message )
1119 case WM_INITMENU:
1121 /* Reset the menu descriptor state */
1122 pOleMenuDescriptor->bIsServerItem = FALSE;
1124 /* Send this message to the server as well */
1125 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1126 pMsg->message, pMsg->wParam, pMsg->lParam );
1127 goto NEXTHOOK;
1130 case WM_INITMENUPOPUP:
1132 /* Save the state for whether this is a server owned menu */
1133 OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
1134 break;
1137 case WM_MENUSELECT:
1139 fuFlags = HIWORD(pMsg->wParam); /* Get flags */
1140 if ( fuFlags & MF_SYSMENU )
1141 goto NEXTHOOK;
1143 /* Save the state for whether this is a server owned popup menu */
1144 else if ( fuFlags & MF_POPUP )
1145 OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
1147 break;
1150 case WM_DRAWITEM:
1152 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
1153 if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
1154 goto NEXTHOOK; /* Not a menu message */
1156 break;
1159 default:
1160 goto NEXTHOOK;
1163 /* If the message was for the server dispatch it accordingly */
1164 if ( pOleMenuDescriptor->bIsServerItem )
1166 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1167 pMsg->message, pMsg->wParam, pMsg->lParam );
1170 NEXTHOOK:
1171 if ( pOleMenuDescriptor )
1172 GlobalUnlock( hOleMenu );
1174 /* Lookup the hook item for the current thread */
1175 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId(), NULL ) ) )
1177 /* This should never fail!! */
1178 WARN("could not retrieve hHook for current thread!\n" );
1179 return 0;
1182 /* Pass on the message to the next hooker */
1183 return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
1186 /*************************************************************************
1187 * OLEMenu_GetMsgProc
1188 * Thread scope WH_GETMESSAGE hook proc filter function (callback)
1189 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1191 LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
1193 LPMSG pMsg = NULL;
1194 HOLEMENU hOleMenu = 0;
1195 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1196 OleMenuHookItem *pHookItem = NULL;
1197 WORD wCode;
1199 TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1201 /* Check if we're being asked to process a messages */
1202 if ( HC_ACTION != code )
1203 goto NEXTHOOK;
1205 /* Retrieve the current message being dispatched from lParam */
1206 pMsg = (LPMSG)lParam;
1208 /* Check if the message is destined for a window we are interested in:
1209 * If the window has an OLEMenu property we may need to dispatch
1210 * the menu message to its active objects window instead. */
1212 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1213 if ( !hOleMenu )
1214 goto NEXTHOOK;
1216 /* Process menu messages */
1217 switch( pMsg->message )
1219 case WM_COMMAND:
1221 wCode = HIWORD(pMsg->wParam); /* Get notification code */
1222 if ( wCode )
1223 goto NEXTHOOK; /* Not a menu message */
1224 break;
1226 default:
1227 goto NEXTHOOK;
1230 /* Get the menu descriptor */
1231 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1232 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1233 goto NEXTHOOK;
1235 /* If the message was for the server dispatch it accordingly */
1236 if ( pOleMenuDescriptor->bIsServerItem )
1238 /* Change the hWnd in the message to the active objects hWnd.
1239 * The message loop which reads this message will automatically
1240 * dispatch it to the embedded objects window. */
1241 pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
1244 NEXTHOOK:
1245 if ( pOleMenuDescriptor )
1246 GlobalUnlock( hOleMenu );
1248 /* Lookup the hook item for the current thread */
1249 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId(), NULL ) ) )
1251 /* This should never fail!! */
1252 WARN("could not retrieve hHook for current thread!\n" );
1253 return FALSE;
1256 /* Pass on the message to the next hooker */
1257 return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
1260 /***********************************************************************
1261 * OleCreateMenuDescriptor [OLE32.97]
1262 * Creates an OLE menu descriptor for OLE to use when dispatching
1263 * menu messages and commands.
1265 * PARAMS:
1266 * hmenuCombined - Handle to the objects combined menu
1267 * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group
1270 HOLEMENU WINAPI OleCreateMenuDescriptor(
1271 HMENU hmenuCombined,
1272 LPOLEMENUGROUPWIDTHS lpMenuWidths)
1274 HOLEMENU hOleMenu;
1275 OleMenuDescriptor *pOleMenuDescriptor;
1276 int i;
1278 if ( !hmenuCombined || !lpMenuWidths )
1279 return 0;
1281 /* Create an OLE menu descriptor */
1282 if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
1283 sizeof(OleMenuDescriptor) ) ) )
1284 return 0;
1286 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1287 if ( !pOleMenuDescriptor )
1288 return 0;
1290 /* Initialize menu group widths and hmenu */
1291 for ( i = 0; i < 6; i++ )
1292 pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
1294 pOleMenuDescriptor->hmenuCombined = hmenuCombined;
1295 pOleMenuDescriptor->bIsServerItem = FALSE;
1296 GlobalUnlock( hOleMenu );
1298 return hOleMenu;
1301 /***********************************************************************
1302 * OleDestroyMenuDescriptor [OLE32.99]
1303 * Destroy the shared menu descriptor
1305 HRESULT WINAPI OleDestroyMenuDescriptor(
1306 HOLEMENU hmenuDescriptor)
1308 if ( hmenuDescriptor )
1309 GlobalFree( hmenuDescriptor );
1310 return S_OK;
1313 /***********************************************************************
1314 * OleSetMenuDescriptor [OLE32.129]
1315 * Installs or removes OLE dispatching code for the containers frame window
1316 * FIXME: The lpFrame and lpActiveObject parameters are currently ignored
1317 * OLE should install context sensitive help F1 filtering for the app when
1318 * these are non null.
1320 * PARAMS:
1321 * hOleMenu Handle to composite menu descriptor
1322 * hwndFrame Handle to containers frame window
1323 * hwndActiveObject Handle to objects in-place activation window
1324 * lpFrame Pointer to IOleInPlaceFrame on containers window
1325 * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object
1327 * RETURNS:
1328 * S_OK - menu installed correctly
1329 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1331 HRESULT WINAPI OleSetMenuDescriptor(
1332 HOLEMENU hOleMenu,
1333 HWND hwndFrame,
1334 HWND hwndActiveObject,
1335 LPOLEINPLACEFRAME lpFrame,
1336 LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1338 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1340 /* Check args */
1341 if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
1342 return E_INVALIDARG;
1344 if ( lpFrame || lpActiveObject )
1346 FIXME("(%x, %x, %x, %p, %p), Context sensitive help filtering not implemented!\n",
1347 (unsigned int)hOleMenu,
1348 hwndFrame,
1349 hwndActiveObject,
1350 lpFrame,
1351 lpActiveObject);
1354 /* Set up a message hook to intercept the containers frame window messages.
1355 * The message filter is responsible for dispatching menu messages from the
1356 * shared menu which are intended for the object.
1359 if ( hOleMenu ) /* Want to install dispatching code */
1361 /* If OLEMenu hooks are already installed for this thread, fail
1362 * Note: This effectively means that OleSetMenuDescriptor cannot
1363 * be called twice in succession on the same frame window
1364 * without first calling it with a null hOleMenu to uninstall */
1365 if ( OLEMenu_IsHookInstalled( GetCurrentThreadId(), NULL ) )
1366 return E_FAIL;
1368 /* Get the menu descriptor */
1369 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1370 if ( !pOleMenuDescriptor )
1371 return E_UNEXPECTED;
1373 /* Update the menu descriptor */
1374 pOleMenuDescriptor->hwndFrame = hwndFrame;
1375 pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
1377 GlobalUnlock( hOleMenu );
1378 pOleMenuDescriptor = NULL;
1380 /* Add a menu descriptor windows property to the frame window */
1381 SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu );
1383 /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
1384 if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
1385 return E_FAIL;
1387 else /* Want to uninstall dispatching code */
1389 /* Uninstall the hooks */
1390 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1391 return E_FAIL;
1393 /* Remove the menu descriptor property from the frame window */
1394 RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" );
1397 return S_OK;
1400 /***********************************************************************
1401 * ReleaseStgMedium [OLE32.140]
1403 void WINAPI ReleaseStgMedium(
1404 STGMEDIUM* pmedium)
1406 switch (pmedium->tymed)
1408 case TYMED_HGLOBAL:
1410 if ( (pmedium->pUnkForRelease==0) &&
1411 (pmedium->u.hGlobal!=0) )
1412 GlobalFree(pmedium->u.hGlobal);
1414 pmedium->u.hGlobal = 0;
1415 break;
1417 case TYMED_FILE:
1419 if (pmedium->u.lpszFileName!=0)
1421 if (pmedium->pUnkForRelease==0)
1423 DeleteFileW(pmedium->u.lpszFileName);
1426 CoTaskMemFree(pmedium->u.lpszFileName);
1429 pmedium->u.lpszFileName = 0;
1430 break;
1432 case TYMED_ISTREAM:
1434 if (pmedium->u.pstm!=0)
1436 IStream_Release(pmedium->u.pstm);
1439 pmedium->u.pstm = 0;
1440 break;
1442 case TYMED_ISTORAGE:
1444 if (pmedium->u.pstg!=0)
1446 IStorage_Release(pmedium->u.pstg);
1449 pmedium->u.pstg = 0;
1450 break;
1452 case TYMED_GDI:
1454 if ( (pmedium->pUnkForRelease==0) &&
1455 (pmedium->u.hGlobal!=0) )
1456 DeleteObject(pmedium->u.hGlobal);
1458 pmedium->u.hGlobal = 0;
1459 break;
1461 case TYMED_MFPICT:
1463 if ( (pmedium->pUnkForRelease==0) &&
1464 (pmedium->u.hMetaFilePict!=0) )
1466 DeleteMetaFile(pmedium->u.hMetaFilePict);
1467 GlobalFree(pmedium->u.hMetaFilePict);
1470 pmedium->u.hMetaFilePict = 0;
1471 break;
1473 case TYMED_ENHMF:
1475 if ( (pmedium->pUnkForRelease==0) &&
1476 (pmedium->u.hEnhMetaFile!=0) )
1478 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
1481 pmedium->u.hEnhMetaFile = 0;
1482 break;
1484 case TYMED_NULL:
1485 default:
1486 break;
1490 * After cleaning up, the unknown is released
1492 if (pmedium->pUnkForRelease!=0)
1494 IUnknown_Release(pmedium->pUnkForRelease);
1495 pmedium->pUnkForRelease = 0;
1499 /***
1500 * OLEDD_Initialize()
1502 * Initializes the OLE drag and drop data structures.
1504 static void OLEDD_Initialize()
1506 WNDCLASSA wndClass;
1508 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1509 wndClass.style = CS_GLOBALCLASS;
1510 wndClass.lpfnWndProc = (WNDPROC)OLEDD_DragTrackerWindowProc;
1511 wndClass.cbClsExtra = 0;
1512 wndClass.cbWndExtra = sizeof(TrackerWindowInfo*);
1513 wndClass.hCursor = 0;
1514 wndClass.hbrBackground = 0;
1515 wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
1517 RegisterClassA (&wndClass);
1520 /***
1521 * OLEDD_UnInitialize()
1523 * Releases the OLE drag and drop data structures.
1525 static void OLEDD_UnInitialize()
1528 * Simply empty the list.
1530 while (targetListHead!=NULL)
1532 RevokeDragDrop(targetListHead->hwndTarget);
1536 /***
1537 * OLEDD_InsertDropTarget()
1539 * Insert the target node in the tree.
1541 static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd)
1543 DropTargetNode* curNode;
1544 DropTargetNode** parentNodeLink;
1547 * Iterate the tree to find the insertion point.
1549 curNode = targetListHead;
1550 parentNodeLink = &targetListHead;
1552 while (curNode!=NULL)
1554 if (nodeToAdd->hwndTarget<curNode->hwndTarget)
1557 * If the node we want to add has a smaller HWND, go left
1559 parentNodeLink = &curNode->prevDropTarget;
1560 curNode = curNode->prevDropTarget;
1562 else if (nodeToAdd->hwndTarget>curNode->hwndTarget)
1565 * If the node we want to add has a larger HWND, go right
1567 parentNodeLink = &curNode->nextDropTarget;
1568 curNode = curNode->nextDropTarget;
1570 else
1573 * The item was found in the list. It shouldn't have been there
1575 assert(FALSE);
1576 return;
1581 * If we get here, we have found a spot for our item. The parentNodeLink
1582 * pointer points to the pointer that we have to modify.
1583 * The curNode should be NULL. We just have to establish the link and Voila!
1585 assert(curNode==NULL);
1586 assert(parentNodeLink!=NULL);
1587 assert(*parentNodeLink==NULL);
1589 *parentNodeLink=nodeToAdd;
1592 /***
1593 * OLEDD_ExtractDropTarget()
1595 * Removes the target node from the tree.
1597 static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget)
1599 DropTargetNode* curNode;
1600 DropTargetNode** parentNodeLink;
1603 * Iterate the tree to find the insertion point.
1605 curNode = targetListHead;
1606 parentNodeLink = &targetListHead;
1608 while (curNode!=NULL)
1610 if (hwndOfTarget<curNode->hwndTarget)
1613 * If the node we want to add has a smaller HWND, go left
1615 parentNodeLink = &curNode->prevDropTarget;
1616 curNode = curNode->prevDropTarget;
1618 else if (hwndOfTarget>curNode->hwndTarget)
1621 * If the node we want to add has a larger HWND, go right
1623 parentNodeLink = &curNode->nextDropTarget;
1624 curNode = curNode->nextDropTarget;
1626 else
1629 * The item was found in the list. Detach it from it's parent and
1630 * re-insert it's kids in the tree.
1632 assert(parentNodeLink!=NULL);
1633 assert(*parentNodeLink==curNode);
1636 * We arbitrately re-attach the left sub-tree to the parent.
1638 *parentNodeLink = curNode->prevDropTarget;
1641 * And we re-insert the right subtree
1643 if (curNode->nextDropTarget!=NULL)
1645 OLEDD_InsertDropTarget(curNode->nextDropTarget);
1649 * The node we found is still a valid node once we complete
1650 * the unlinking of the kids.
1652 curNode->nextDropTarget=NULL;
1653 curNode->prevDropTarget=NULL;
1655 return curNode;
1660 * If we get here, the node is not in the tree
1662 return NULL;
1665 /***
1666 * OLEDD_FindDropTarget()
1668 * Finds information about the drop target.
1670 static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
1672 DropTargetNode* curNode;
1675 * Iterate the tree to find the HWND value.
1677 curNode = targetListHead;
1679 while (curNode!=NULL)
1681 if (hwndOfTarget<curNode->hwndTarget)
1684 * If the node we want to add has a smaller HWND, go left
1686 curNode = curNode->prevDropTarget;
1688 else if (hwndOfTarget>curNode->hwndTarget)
1691 * If the node we want to add has a larger HWND, go right
1693 curNode = curNode->nextDropTarget;
1695 else
1698 * The item was found in the list.
1700 return curNode;
1705 * If we get here, the item is not in the list
1707 return NULL;
1710 /***
1711 * OLEDD_DragTrackerWindowProc()
1713 * This method is the WindowProcedure of the drag n drop tracking
1714 * window. During a drag n Drop operation, an invisible window is created
1715 * to receive the user input and act upon it. This procedure is in charge
1716 * of this behavior.
1718 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
1719 HWND hwnd,
1720 UINT uMsg,
1721 WPARAM wParam,
1722 LPARAM lParam)
1724 switch (uMsg)
1726 case WM_CREATE:
1728 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
1730 SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams);
1733 break;
1735 case WM_MOUSEMOVE:
1737 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1738 POINT mousePos;
1741 * Get the current mouse position in screen coordinates.
1743 mousePos.x = LOWORD(lParam);
1744 mousePos.y = HIWORD(lParam);
1745 ClientToScreen(hwnd, &mousePos);
1748 * Track the movement of the mouse.
1750 OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam);
1752 break;
1754 case WM_LBUTTONUP:
1755 case WM_MBUTTONUP:
1756 case WM_RBUTTONUP:
1757 case WM_LBUTTONDOWN:
1758 case WM_MBUTTONDOWN:
1759 case WM_RBUTTONDOWN:
1761 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1762 POINT mousePos;
1765 * Get the current mouse position in screen coordinates.
1767 mousePos.x = LOWORD(lParam);
1768 mousePos.y = HIWORD(lParam);
1769 ClientToScreen(hwnd, &mousePos);
1772 * Notify everyone that the button state changed
1773 * TODO: Check if the "escape" key was pressed.
1775 OLEDD_TrackStateChange(trackerInfo, mousePos, wParam);
1777 break;
1782 * This is a window proc after all. Let's call the default.
1784 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1787 /***
1788 * OLEDD_TrackMouseMove()
1790 * This method is invoked while a drag and drop operation is in effect.
1791 * it will generate the appropriate callbacks in the drop source
1792 * and drop target. It will also provide the expected feedback to
1793 * the user.
1795 * params:
1796 * trackerInfo - Pointer to the structure identifying the
1797 * drag & drop operation that is currently
1798 * active.
1799 * mousePos - Current position of the mouse in screen
1800 * coordinates.
1801 * keyState - Contains the state of the shift keys and the
1802 * mouse buttons (MK_LBUTTON and the like)
1804 static void OLEDD_TrackMouseMove(
1805 TrackerWindowInfo* trackerInfo,
1806 POINT mousePos,
1807 DWORD keyState)
1809 HWND hwndNewTarget = 0;
1810 HRESULT hr = S_OK;
1813 * Get the handle of the window under the mouse
1815 hwndNewTarget = WindowFromPoint(mousePos);
1818 * Every time, we re-initialize the effects passed to the
1819 * IDropTarget to the effects allowed by the source.
1821 *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
1824 * If we are hovering over the same target as before, send the
1825 * DragOver notification
1827 if ( (trackerInfo->curDragTarget != 0) &&
1828 (trackerInfo->curDragTargetHWND==hwndNewTarget) )
1830 POINTL mousePosParam;
1833 * The documentation tells me that the coordinate should be in the target
1834 * window's coordinate space. However, the tests I made tell me the
1835 * coordinates should be in screen coordinates.
1837 mousePosParam.x = mousePos.x;
1838 mousePosParam.y = mousePos.y;
1840 IDropTarget_DragOver(trackerInfo->curDragTarget,
1841 keyState,
1842 mousePosParam,
1843 trackerInfo->pdwEffect);
1845 else
1847 DropTargetNode* newDropTargetNode = 0;
1850 * If we changed window, we have to notify our old target and check for
1851 * the new one.
1853 if (trackerInfo->curDragTarget!=0)
1855 IDropTarget_DragLeave(trackerInfo->curDragTarget);
1859 * Make sure we're hovering over a window.
1861 if (hwndNewTarget!=0)
1864 * Find-out if there is a drag target under the mouse
1866 newDropTargetNode = OLEDD_FindDropTarget(hwndNewTarget);
1868 trackerInfo->curDragTargetHWND = hwndNewTarget;
1869 trackerInfo->curDragTarget = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
1872 * If there is, notify it that we just dragged-in
1874 if (trackerInfo->curDragTarget!=0)
1876 POINTL mousePosParam;
1879 * The documentation tells me that the coordinate should be in the target
1880 * window's coordinate space. However, the tests I made tell me the
1881 * coordinates should be in screen coordinates.
1883 mousePosParam.x = mousePos.x;
1884 mousePosParam.y = mousePos.y;
1886 IDropTarget_DragEnter(trackerInfo->curDragTarget,
1887 trackerInfo->dataObject,
1888 keyState,
1889 mousePosParam,
1890 trackerInfo->pdwEffect);
1893 else
1896 * The mouse is not over a window so we don't track anything.
1898 trackerInfo->curDragTargetHWND = 0;
1899 trackerInfo->curDragTarget = 0;
1904 * Now that we have done that, we have to tell the source to give
1905 * us feedback on the work being done by the target. If we don't
1906 * have a target, simulate no effect.
1908 if (trackerInfo->curDragTarget==0)
1910 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
1913 hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
1914 *trackerInfo->pdwEffect);
1917 * When we ask for feedback from the drop source, sometimes it will
1918 * do all the necessary work and sometimes it will not handle it
1919 * when that's the case, we must display the standard drag and drop
1920 * cursors.
1922 if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
1924 if ( (*trackerInfo->pdwEffect & DROPEFFECT_MOVE) ||
1925 (*trackerInfo->pdwEffect & DROPEFFECT_COPY) ||
1926 (*trackerInfo->pdwEffect & DROPEFFECT_LINK) )
1928 SetCursor(LoadCursorA(0, IDC_SIZEALLA));
1930 else
1932 SetCursor(LoadCursorA(0, IDC_NOA));
1937 /***
1938 * OLEDD_TrackStateChange()
1940 * This method is invoked while a drag and drop operation is in effect.
1941 * It is used to notify the drop target/drop source callbacks when
1942 * the state of the keyboard or mouse button change.
1944 * params:
1945 * trackerInfo - Pointer to the structure identifying the
1946 * drag & drop operation that is currently
1947 * active.
1948 * mousePos - Current position of the mouse in screen
1949 * coordinates.
1950 * keyState - Contains the state of the shift keys and the
1951 * mouse buttons (MK_LBUTTON and the like)
1953 static void OLEDD_TrackStateChange(
1954 TrackerWindowInfo* trackerInfo,
1955 POINT mousePos,
1956 DWORD keyState)
1959 * Ask the drop source what to do with the operation.
1961 trackerInfo->returnValue = IDropSource_QueryContinueDrag(
1962 trackerInfo->dropSource,
1963 trackerInfo->escPressed,
1964 keyState);
1967 * All the return valued will stop the operation except the S_OK
1968 * return value.
1970 if (trackerInfo->returnValue!=S_OK)
1973 * Make sure the message loop in DoDragDrop stops
1975 trackerInfo->trackingDone = TRUE;
1978 * Release the mouse in case the drop target decides to show a popup
1979 * or a menu or something.
1981 ReleaseCapture();
1984 * If we end-up over a target, drop the object in the target or
1985 * inform the target that the operation was cancelled.
1987 if (trackerInfo->curDragTarget!=0)
1989 switch (trackerInfo->returnValue)
1992 * If the source wants us to complete the operation, we tell
1993 * the drop target that we just dropped the object in it.
1995 case DRAGDROP_S_DROP:
1997 POINTL mousePosParam;
2000 * The documentation tells me that the coordinate should be
2001 * in the target window's coordinate space. However, the tests
2002 * I made tell me the coordinates should be in screen coordinates.
2004 mousePosParam.x = mousePos.x;
2005 mousePosParam.y = mousePos.y;
2007 IDropTarget_Drop(trackerInfo->curDragTarget,
2008 trackerInfo->dataObject,
2009 keyState,
2010 mousePosParam,
2011 trackerInfo->pdwEffect);
2012 break;
2015 * If the source told us that we should cancel, fool the drop
2016 * target by telling it that the mouse left it's window.
2018 case DRAGDROP_S_CANCEL:
2019 IDropTarget_DragLeave(trackerInfo->curDragTarget);
2020 break;
2026 /***
2027 * OLEDD_GetButtonState()
2029 * This method will use the current state of the keyboard to build
2030 * a button state mask equivalent to the one passed in the
2031 * WM_MOUSEMOVE wParam.
2033 static DWORD OLEDD_GetButtonState()
2035 BYTE keyboardState[256];
2036 DWORD keyMask = 0;
2038 GetKeyboardState(keyboardState);
2040 if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
2041 keyMask |= MK_SHIFT;
2043 if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
2044 keyMask |= MK_CONTROL;
2046 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
2047 keyMask |= MK_LBUTTON;
2049 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
2050 keyMask |= MK_RBUTTON;
2052 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
2053 keyMask |= MK_MBUTTON;
2055 return keyMask;
2058 /***
2059 * OLEDD_GetButtonState()
2061 * This method will read the default value of the registry key in
2062 * parameter and extract a DWORD value from it. The registry key value
2063 * can be in a string key or a DWORD key.
2065 * params:
2066 * regKey - Key to read the default value from
2067 * pdwValue - Pointer to the location where the DWORD
2068 * value is returned. This value is not modified
2069 * if the value is not found.
2072 static void OLEUTL_ReadRegistryDWORDValue(
2073 HKEY regKey,
2074 DWORD* pdwValue)
2076 char buffer[20];
2077 DWORD dwKeyType;
2078 DWORD cbData = 20;
2079 LONG lres;
2081 lres = RegQueryValueExA(regKey,
2083 NULL,
2084 &dwKeyType,
2085 (LPBYTE)buffer,
2086 &cbData);
2088 if (lres==ERROR_SUCCESS)
2090 switch (dwKeyType)
2092 case REG_DWORD:
2093 *pdwValue = *(DWORD*)buffer;
2094 break;
2095 case REG_EXPAND_SZ:
2096 case REG_MULTI_SZ:
2097 case REG_SZ:
2098 *pdwValue = (DWORD)strtoul(buffer, NULL, 10);
2099 break;
2104 /******************************************************************************
2105 * OleMetaFilePictFromIconAndLabel
2107 * Returns a global memory handle to a metafile which contains the icon and
2108 * label given.
2109 * I guess the result of that should look somehow like desktop icons.
2110 * If no hIcon is given, we load the icon via lpszSourceFile and iIconIndex.
2111 * This code might be wrong at some places.
2113 HGLOBAL16 WINAPI OleMetaFilePictFromIconAndLabel16(
2114 HICON16 hIcon,
2115 LPCOLESTR16 lpszLabel,
2116 LPCOLESTR16 lpszSourceFile,
2117 UINT16 iIconIndex
2119 METAFILEPICT16 *mf;
2120 HGLOBAL16 hmf;
2121 HDC16 hdc;
2123 FIXME("(%04x, '%s', '%s', %d): incorrect metrics, please try to correct them !\n\n\n", hIcon, lpszLabel, lpszSourceFile, iIconIndex);
2125 if (!hIcon) {
2126 if (lpszSourceFile) {
2127 HINSTANCE16 hInstance = LoadLibrary16(lpszSourceFile);
2129 /* load the icon at index from lpszSourceFile */
2130 hIcon = (HICON16)LoadIconA(hInstance, (LPCSTR)(DWORD)iIconIndex);
2131 FreeLibrary16(hInstance);
2132 } else
2133 return (HGLOBAL)NULL;
2136 hdc = CreateMetaFile16(NULL);
2137 DrawIcon(hdc, 0, 0, hIcon); /* FIXME */
2138 TextOut16(hdc, 0, 0, lpszLabel, 1); /* FIXME */
2139 hmf = GlobalAlloc16(0, sizeof(METAFILEPICT16));
2140 mf = (METAFILEPICT16 *)GlobalLock16(hmf);
2141 mf->mm = MM_ANISOTROPIC;
2142 mf->xExt = 20; /* FIXME: bogus */
2143 mf->yExt = 20; /* dito */
2144 mf->hMF = CloseMetaFile16(hdc);
2145 return hmf;