Save GET_APCS data before calling any asynchronous procedure calls, in
[wine/testsucceed.git] / dlls / ole32 / ole2.c
blobe3372a2c27a9ce4d796dfb452a2ed314efee20b8
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 "commctrl.h"
20 #include "wine/obj_clientserver.h"
21 #include "wine/winbase16.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)
219 return GetCurrentProcessId();
222 /******************************************************************************
223 * OleUninitialize [OLE2.3] [OLE32.131]
225 void WINAPI OleUninitialize(void)
227 TRACE("()\n");
230 * Decrease the lock count on the OLE module.
232 OLE_moduleLockCount--;
235 * If we hit the bottom of the lock stack, free the libraries.
237 if (OLE_moduleLockCount==0)
240 * Actually free the libraries.
242 TRACE("() - Freeing the last reference count\n");
245 * OLE Clipboard
247 OLEClipbrd_UnInitialize();
250 * Drag and Drop
252 OLEDD_UnInitialize();
255 * OLE shared menu
257 OLEMenu_UnInitialize();
261 * Then, uninitialize the COM libraries.
263 CoUninitialize();
266 /******************************************************************************
267 * CoRegisterMessageFilter [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 * RegisterDragDrop (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 * RevokeDragDrop (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 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 sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
412 clsid->Data1, clsid->Data2, clsid->Data3,
413 clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
414 clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
416 TRACE("(%s, %ld, %p)\n", keyName, dwFormOfType, pszUserType);
419 * Open the class id Key
421 hres = RegOpenKeyA(HKEY_CLASSES_ROOT,
422 keyName,
423 &clsidKey);
425 if (hres != ERROR_SUCCESS)
426 return REGDB_E_CLASSNOTREG;
429 * Retrieve the size of the name string.
431 cbData = 0;
433 hres = RegQueryValueExA(clsidKey,
435 NULL,
436 &dwKeyType,
437 NULL,
438 &cbData);
440 if (hres!=ERROR_SUCCESS)
442 RegCloseKey(clsidKey);
443 return REGDB_E_READREGDB;
447 * Allocate a buffer for the registry value.
449 *pszUserType = CoTaskMemAlloc(cbData*2);
451 if (*pszUserType==NULL)
453 RegCloseKey(clsidKey);
454 return E_OUTOFMEMORY;
457 buffer = HeapAlloc(GetProcessHeap(), 0, cbData);
459 if (buffer == NULL)
461 RegCloseKey(clsidKey);
462 CoTaskMemFree(*pszUserType);
463 *pszUserType=NULL;
464 return E_OUTOFMEMORY;
467 hres = RegQueryValueExA(clsidKey,
469 NULL,
470 &dwKeyType,
471 buffer,
472 &cbData);
474 RegCloseKey(clsidKey);
477 if (hres!=ERROR_SUCCESS)
479 CoTaskMemFree(*pszUserType);
480 *pszUserType=NULL;
482 retVal = REGDB_E_READREGDB;
484 else
486 lstrcpyAtoW(*pszUserType, buffer);
487 retVal = S_OK;
489 HeapFree(GetProcessHeap(), 0, buffer);
491 return retVal;
494 /***********************************************************************
495 * DoDragDrop [OLE32.65]
497 HRESULT WINAPI DoDragDrop (
498 IDataObject *pDataObject, /* ptr to the data obj */
499 IDropSource* pDropSource, /* ptr to the source obj */
500 DWORD dwOKEffect, /* effects allowed by the source */
501 DWORD *pdwEffect) /* ptr to effects of the source */
503 TrackerWindowInfo trackerInfo;
504 HWND hwndTrackWindow;
505 MSG msg;
507 TRACE("(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
510 * Setup the drag n drop tracking window.
512 trackerInfo.dataObject = pDataObject;
513 trackerInfo.dropSource = pDropSource;
514 trackerInfo.dwOKEffect = dwOKEffect;
515 trackerInfo.pdwEffect = pdwEffect;
516 trackerInfo.trackingDone = FALSE;
517 trackerInfo.escPressed = FALSE;
518 trackerInfo.curDragTargetHWND = 0;
519 trackerInfo.curDragTarget = 0;
521 hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS,
522 "TrackerWindow",
523 WS_POPUP,
524 CW_USEDEFAULT, CW_USEDEFAULT,
525 CW_USEDEFAULT, CW_USEDEFAULT,
529 (LPVOID)&trackerInfo);
531 if (hwndTrackWindow!=0)
534 * Capture the mouse input
536 SetCapture(hwndTrackWindow);
539 * Pump messages. All mouse input should go the the capture window.
541 while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )
543 if ( (msg.message >= WM_KEYFIRST) &&
544 (msg.message <= WM_KEYLAST) )
547 * When keyboard messages are sent to windows on this thread, we
548 * want to ignore notify the drop source that the state changed.
549 * in the case of the Escape key, we also notify the drop source
550 * we give it a special meaning.
552 if ( (msg.message==WM_KEYDOWN) &&
553 (msg.wParam==VK_ESCAPE) )
555 trackerInfo.escPressed = TRUE;
559 * Notify the drop source.
561 OLEDD_TrackStateChange(&trackerInfo,
562 msg.pt,
563 OLEDD_GetButtonState());
565 else
568 * Dispatch the messages only when it's not a keyboard message.
570 DispatchMessageA(&msg);
575 * Destroy the temporary window.
577 DestroyWindow(hwndTrackWindow);
579 return trackerInfo.returnValue;
582 return E_FAIL;
585 /***********************************************************************
586 * OleQueryLinkFromData [OLE32.118]
588 HRESULT WINAPI OleQueryLinkFromData(
589 IDataObject* pSrcDataObject)
591 FIXME("(%p),stub!\n", pSrcDataObject);
592 return S_OK;
595 /***********************************************************************
596 * OleRegGetMiscStatus [OLE32.121]
598 HRESULT WINAPI OleRegGetMiscStatus(
599 REFCLSID clsid,
600 DWORD dwAspect,
601 DWORD* pdwStatus)
603 char keyName[60];
604 HKEY clsidKey;
605 HKEY miscStatusKey;
606 HKEY aspectKey;
607 LONG result;
610 * Initialize the out parameter.
612 *pdwStatus = 0;
615 * Build the key name we're looking for
617 sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
618 clsid->Data1, clsid->Data2, clsid->Data3,
619 clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
620 clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
622 TRACE("(%s, %ld, %p)\n", keyName, dwAspect, pdwStatus);
625 * Open the class id Key
627 result = RegOpenKeyA(HKEY_CLASSES_ROOT,
628 keyName,
629 &clsidKey);
631 if (result != ERROR_SUCCESS)
632 return REGDB_E_CLASSNOTREG;
635 * Get the MiscStatus
637 result = RegOpenKeyA(clsidKey,
638 "MiscStatus",
639 &miscStatusKey);
642 if (result != ERROR_SUCCESS)
644 RegCloseKey(clsidKey);
645 return REGDB_E_READREGDB;
649 * Read the default value
651 OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
654 * Open the key specific to the requested aspect.
656 sprintf(keyName, "%ld", dwAspect);
658 result = RegOpenKeyA(miscStatusKey,
659 keyName,
660 &aspectKey);
662 if (result == ERROR_SUCCESS)
664 OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
665 RegCloseKey(aspectKey);
669 * Cleanup
671 RegCloseKey(miscStatusKey);
672 RegCloseKey(clsidKey);
674 return S_OK;
677 /******************************************************************************
678 * OleSetContainedObject [OLE32.128]
680 HRESULT WINAPI OleSetContainedObject(
681 LPUNKNOWN pUnknown,
682 BOOL fContained)
684 IRunnableObject* runnable = NULL;
685 HRESULT hres;
687 TRACE("(%p,%x), stub!\n", pUnknown, fContained);
689 hres = IUnknown_QueryInterface(pUnknown,
690 &IID_IRunnableObject,
691 (void**)&runnable);
693 if (SUCCEEDED(hres))
695 hres = IRunnableObject_SetContainedObject(runnable, fContained);
697 IRunnableObject_Release(runnable);
699 return hres;
702 return S_OK;
705 /******************************************************************************
706 * OleLoad [OLE32.112]
708 HRESULT WINAPI OleLoad(
709 LPSTORAGE pStg,
710 REFIID riid,
711 LPOLECLIENTSITE pClientSite,
712 LPVOID* ppvObj)
714 IPersistStorage* persistStorage = NULL;
715 IOleObject* oleObject = NULL;
716 STATSTG storageInfo;
717 HRESULT hres;
719 TRACE("(%p,%p,%p,%p)\n", pStg, riid, pClientSite, ppvObj);
722 * TODO, Conversion ... OleDoAutoConvert
726 * Get the class ID for the object.
728 hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
731 * Now, try and create the handler for the object
733 hres = CoCreateInstance(&storageInfo.clsid,
734 NULL,
735 CLSCTX_INPROC_HANDLER,
736 &IID_IOleObject,
737 (void**)&oleObject);
740 * If that fails, as it will most times, load the default
741 * OLE handler.
743 if (FAILED(hres))
745 hres = OleCreateDefaultHandler(&storageInfo.clsid,
746 NULL,
747 &IID_IOleObject,
748 (void**)&oleObject);
752 * If we couldn't find a handler... this is bad. Abort the whole thing.
754 if (FAILED(hres))
755 return hres;
758 * Inform the new object of it's client site.
760 hres = IOleObject_SetClientSite(oleObject, pClientSite);
763 * Initialize the object with it's IPersistStorage interface.
765 hres = IOleObject_QueryInterface(oleObject,
766 &IID_IPersistStorage,
767 (void**)&persistStorage);
769 if (SUCCEEDED(hres))
771 IPersistStorage_Load(persistStorage, pStg);
773 IPersistStorage_Release(persistStorage);
774 persistStorage = NULL;
778 * Return the requested interface to the caller.
780 hres = IOleObject_QueryInterface(oleObject, riid, ppvObj);
783 * Cleanup interfaces used internally
785 IOleObject_Release(oleObject);
787 return hres;
790 /***********************************************************************
791 * OleSave [OLE32.124]
793 HRESULT WINAPI OleSave(
794 LPPERSISTSTORAGE pPS,
795 LPSTORAGE pStg,
796 BOOL fSameAsLoad)
798 HRESULT hres;
799 CLSID objectClass;
801 TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad);
804 * First, we transfer the class ID (if available)
806 hres = IPersistStorage_GetClassID(pPS, &objectClass);
808 if (SUCCEEDED(hres))
810 WriteClassStg(pStg, &objectClass);
814 * Then, we ask the object to save itself to the
815 * storage. If it is successful, we commit the storage.
817 hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad);
819 if (SUCCEEDED(hres))
821 IStorage_Commit(pStg,
822 STGC_DEFAULT);
825 return hres;
829 /**************************************************************************
830 * Internal methods to manage the shared OLE menu in response to the
831 * OLE***MenuDescriptor API
834 /***
835 * OLEMenu_Initialize()
837 * Initializes the OLEMENU data structures.
839 static void OLEMenu_Initialize()
843 /***
844 * OLEMenu_UnInitialize()
846 * Releases the OLEMENU data structures.
848 static void OLEMenu_UnInitialize()
852 /*************************************************************************
853 * OLEMenu_InstallHooks
854 * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
856 * RETURNS: TRUE if message hooks were succesfully installed
857 * FALSE on failure
859 BOOL OLEMenu_InstallHooks( DWORD tid )
861 OleMenuHookItem *pHookItem = NULL;
863 /* Create an entry for the hook table */
864 if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
865 sizeof(OleMenuHookItem)) ) )
866 return FALSE;
868 pHookItem->tid = tid;
869 pHookItem->hHeap = GetProcessHeap();
871 /* Install a thread scope message hook for WH_GETMESSAGE */
872 pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc,
873 0, GetCurrentThreadId() );
874 if ( !pHookItem->GetMsg_hHook )
875 goto CLEANUP;
877 /* Install a thread scope message hook for WH_CALLWNDPROC */
878 pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc,
879 0, GetCurrentThreadId() );
880 if ( !pHookItem->CallWndProc_hHook )
881 goto CLEANUP;
883 /* Insert the hook table entry */
884 pHookItem->next = hook_list;
885 hook_list = pHookItem;
887 return TRUE;
889 CLEANUP:
890 /* Unhook any hooks */
891 if ( pHookItem->GetMsg_hHook )
892 UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
893 if ( pHookItem->CallWndProc_hHook )
894 UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
895 /* Release the hook table entry */
896 HeapFree(pHookItem->hHeap, 0, pHookItem );
898 return FALSE;
901 /*************************************************************************
902 * OLEMenu_UnInstallHooks
903 * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
905 * RETURNS: TRUE if message hooks were succesfully installed
906 * FALSE on failure
908 BOOL OLEMenu_UnInstallHooks( DWORD tid )
910 OleMenuHookItem *pHookItem = NULL;
911 OleMenuHookItem **ppHook = &hook_list;
913 while (*ppHook)
915 if ((*ppHook)->tid == tid)
917 pHookItem = *ppHook;
918 *ppHook = pHookItem->next;
919 break;
921 ppHook = &(*ppHook)->next;
923 if (!pHookItem) return FALSE;
925 /* Uninstall the hooks installed for this thread */
926 if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
927 goto CLEANUP;
928 if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
929 goto CLEANUP;
931 /* Release the hook table entry */
932 HeapFree(pHookItem->hHeap, 0, pHookItem );
934 return TRUE;
936 CLEANUP:
937 /* Release the hook table entry */
938 if (pHookItem)
939 HeapFree(pHookItem->hHeap, 0, pHookItem );
941 return FALSE;
944 /*************************************************************************
945 * OLEMenu_IsHookInstalled
946 * Tests if OLEMenu hooks have been installed for a thread
948 * RETURNS: The pointer and index of the hook table entry for the tid
949 * NULL and -1 for the index if no hooks were installed for this thread
951 OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )
953 OleMenuHookItem *pHookItem = NULL;
955 /* Do a simple linear search for an entry whose tid matches ours.
956 * We really need a map but efficiency is not a concern here. */
957 for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next)
959 if ( tid == pHookItem->tid )
960 return pHookItem;
963 return NULL;
966 /***********************************************************************
967 * OLEMenu_FindMainMenuIndex
969 * Used by OLEMenu API to find the top level group a menu item belongs to.
970 * On success pnPos contains the index of the item in the top level menu group
972 * RETURNS: TRUE if the ID was found, FALSE on failure
974 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
976 UINT i, nItems;
978 nItems = GetMenuItemCount( hMainMenu );
980 for (i = 0; i < nItems; i++)
982 HMENU hsubmenu;
984 /* Is the current item a submenu? */
985 if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
987 /* If the handle is the same we're done */
988 if ( hsubmenu == hPopupMenu )
990 if (pnPos)
991 *pnPos = i;
992 return TRUE;
994 /* Recursively search without updating pnPos */
995 else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
997 if (pnPos)
998 *pnPos = i;
999 return TRUE;
1004 return FALSE;
1007 /***********************************************************************
1008 * OLEMenu_SetIsServerMenu
1010 * Checks whether a popup menu belongs to a shared menu group which is
1011 * owned by the server, and sets the menu descriptor state accordingly.
1012 * All menu messages from these groups should be routed to the server.
1014 * RETURNS: TRUE if the popup menu is part of a server owned group
1015 * FASE if the popup menu is part of a container owned group
1017 BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
1019 UINT nPos = 0, nWidth, i;
1021 pOleMenuDescriptor->bIsServerItem = FALSE;
1023 /* Don't bother searching if the popup is the combined menu itself */
1024 if ( hmenu == pOleMenuDescriptor->hmenuCombined )
1025 return FALSE;
1027 /* Find the menu item index in the shared OLE menu that this item belongs to */
1028 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) )
1029 return FALSE;
1031 /* The group widths array has counts for the number of elements
1032 * in the groups File, Edit, Container, Object, Window, Help.
1033 * The Edit, Object & Help groups belong to the server object
1034 * and the other three belong to the container.
1035 * Loop thru the group widths and locate the group we are a member of.
1037 for ( i = 0, nWidth = 0; i < 6; i++ )
1039 nWidth += pOleMenuDescriptor->mgw.width[i];
1040 if ( nPos < nWidth )
1042 /* Odd elements are server menu widths */
1043 pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;
1044 break;
1048 return pOleMenuDescriptor->bIsServerItem;
1051 /*************************************************************************
1052 * OLEMenu_CallWndProc
1053 * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
1054 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1056 LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
1058 LPCWPSTRUCT pMsg = NULL;
1059 HOLEMENU hOleMenu = 0;
1060 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1061 OleMenuHookItem *pHookItem = NULL;
1062 WORD fuFlags;
1064 TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1066 /* Check if we're being asked to process the message */
1067 if ( HC_ACTION != code )
1068 goto NEXTHOOK;
1070 /* Retrieve the current message being dispatched from lParam */
1071 pMsg = (LPCWPSTRUCT)lParam;
1073 /* Check if the message is destined for a window we are interested in:
1074 * If the window has an OLEMenu property we may need to dispatch
1075 * the menu message to its active objects window instead. */
1077 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1078 if ( !hOleMenu )
1079 goto NEXTHOOK;
1081 /* Get the menu descriptor */
1082 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1083 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1084 goto NEXTHOOK;
1086 /* Process menu messages */
1087 switch( pMsg->message )
1089 case WM_INITMENU:
1091 /* Reset the menu descriptor state */
1092 pOleMenuDescriptor->bIsServerItem = FALSE;
1094 /* Send this message to the server as well */
1095 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1096 pMsg->message, pMsg->wParam, pMsg->lParam );
1097 goto NEXTHOOK;
1100 case WM_INITMENUPOPUP:
1102 /* Save the state for whether this is a server owned menu */
1103 OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
1104 break;
1107 case WM_MENUSELECT:
1109 fuFlags = HIWORD(pMsg->wParam); /* Get flags */
1110 if ( fuFlags & MF_SYSMENU )
1111 goto NEXTHOOK;
1113 /* Save the state for whether this is a server owned popup menu */
1114 else if ( fuFlags & MF_POPUP )
1115 OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
1117 break;
1120 case WM_DRAWITEM:
1122 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
1123 if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
1124 goto NEXTHOOK; /* Not a menu message */
1126 break;
1129 default:
1130 goto NEXTHOOK;
1133 /* If the message was for the server dispatch it accordingly */
1134 if ( pOleMenuDescriptor->bIsServerItem )
1136 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1137 pMsg->message, pMsg->wParam, pMsg->lParam );
1140 NEXTHOOK:
1141 if ( pOleMenuDescriptor )
1142 GlobalUnlock( hOleMenu );
1144 /* Lookup the hook item for the current thread */
1145 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1147 /* This should never fail!! */
1148 WARN("could not retrieve hHook for current thread!\n" );
1149 return 0;
1152 /* Pass on the message to the next hooker */
1153 return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
1156 /*************************************************************************
1157 * OLEMenu_GetMsgProc
1158 * Thread scope WH_GETMESSAGE hook proc filter function (callback)
1159 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1161 LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
1163 LPMSG pMsg = NULL;
1164 HOLEMENU hOleMenu = 0;
1165 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1166 OleMenuHookItem *pHookItem = NULL;
1167 WORD wCode;
1169 TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1171 /* Check if we're being asked to process a messages */
1172 if ( HC_ACTION != code )
1173 goto NEXTHOOK;
1175 /* Retrieve the current message being dispatched from lParam */
1176 pMsg = (LPMSG)lParam;
1178 /* Check if the message is destined for a window we are interested in:
1179 * If the window has an OLEMenu property we may need to dispatch
1180 * the menu message to its active objects window instead. */
1182 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1183 if ( !hOleMenu )
1184 goto NEXTHOOK;
1186 /* Process menu messages */
1187 switch( pMsg->message )
1189 case WM_COMMAND:
1191 wCode = HIWORD(pMsg->wParam); /* Get notification code */
1192 if ( wCode )
1193 goto NEXTHOOK; /* Not a menu message */
1194 break;
1196 default:
1197 goto NEXTHOOK;
1200 /* Get the menu descriptor */
1201 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1202 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1203 goto NEXTHOOK;
1205 /* If the message was for the server dispatch it accordingly */
1206 if ( pOleMenuDescriptor->bIsServerItem )
1208 /* Change the hWnd in the message to the active objects hWnd.
1209 * The message loop which reads this message will automatically
1210 * dispatch it to the embedded objects window. */
1211 pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
1214 NEXTHOOK:
1215 if ( pOleMenuDescriptor )
1216 GlobalUnlock( hOleMenu );
1218 /* Lookup the hook item for the current thread */
1219 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1221 /* This should never fail!! */
1222 WARN("could not retrieve hHook for current thread!\n" );
1223 return FALSE;
1226 /* Pass on the message to the next hooker */
1227 return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
1230 /***********************************************************************
1231 * OleCreateMenuDescriptor [OLE32.97]
1232 * Creates an OLE menu descriptor for OLE to use when dispatching
1233 * menu messages and commands.
1235 * PARAMS:
1236 * hmenuCombined - Handle to the objects combined menu
1237 * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group
1240 HOLEMENU WINAPI OleCreateMenuDescriptor(
1241 HMENU hmenuCombined,
1242 LPOLEMENUGROUPWIDTHS lpMenuWidths)
1244 HOLEMENU hOleMenu;
1245 OleMenuDescriptor *pOleMenuDescriptor;
1246 int i;
1248 if ( !hmenuCombined || !lpMenuWidths )
1249 return 0;
1251 /* Create an OLE menu descriptor */
1252 if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
1253 sizeof(OleMenuDescriptor) ) ) )
1254 return 0;
1256 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1257 if ( !pOleMenuDescriptor )
1258 return 0;
1260 /* Initialize menu group widths and hmenu */
1261 for ( i = 0; i < 6; i++ )
1262 pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
1264 pOleMenuDescriptor->hmenuCombined = hmenuCombined;
1265 pOleMenuDescriptor->bIsServerItem = FALSE;
1266 GlobalUnlock( hOleMenu );
1268 return hOleMenu;
1271 /***********************************************************************
1272 * OleDestroyMenuDescriptor [OLE32.99]
1273 * Destroy the shared menu descriptor
1275 HRESULT WINAPI OleDestroyMenuDescriptor(
1276 HOLEMENU hmenuDescriptor)
1278 if ( hmenuDescriptor )
1279 GlobalFree( hmenuDescriptor );
1280 return S_OK;
1283 /***********************************************************************
1284 * OleSetMenuDescriptor [OLE32.129]
1285 * Installs or removes OLE dispatching code for the containers frame window
1286 * FIXME: The lpFrame and lpActiveObject parameters are currently ignored
1287 * OLE should install context sensitive help F1 filtering for the app when
1288 * these are non null.
1290 * PARAMS:
1291 * hOleMenu Handle to composite menu descriptor
1292 * hwndFrame Handle to containers frame window
1293 * hwndActiveObject Handle to objects in-place activation window
1294 * lpFrame Pointer to IOleInPlaceFrame on containers window
1295 * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object
1297 * RETURNS:
1298 * S_OK - menu installed correctly
1299 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1301 HRESULT WINAPI OleSetMenuDescriptor(
1302 HOLEMENU hOleMenu,
1303 HWND hwndFrame,
1304 HWND hwndActiveObject,
1305 LPOLEINPLACEFRAME lpFrame,
1306 LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1308 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1310 /* Check args */
1311 if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
1312 return E_INVALIDARG;
1314 if ( lpFrame || lpActiveObject )
1316 FIXME("(%x, %x, %x, %p, %p), Context sensitive help filtering not implemented!\n",
1317 (unsigned int)hOleMenu,
1318 hwndFrame,
1319 hwndActiveObject,
1320 lpFrame,
1321 lpActiveObject);
1324 /* Set up a message hook to intercept the containers frame window messages.
1325 * The message filter is responsible for dispatching menu messages from the
1326 * shared menu which are intended for the object.
1329 if ( hOleMenu ) /* Want to install dispatching code */
1331 /* If OLEMenu hooks are already installed for this thread, fail
1332 * Note: This effectively means that OleSetMenuDescriptor cannot
1333 * be called twice in succession on the same frame window
1334 * without first calling it with a null hOleMenu to uninstall */
1335 if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) )
1336 return E_FAIL;
1338 /* Get the menu descriptor */
1339 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1340 if ( !pOleMenuDescriptor )
1341 return E_UNEXPECTED;
1343 /* Update the menu descriptor */
1344 pOleMenuDescriptor->hwndFrame = hwndFrame;
1345 pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
1347 GlobalUnlock( hOleMenu );
1348 pOleMenuDescriptor = NULL;
1350 /* Add a menu descriptor windows property to the frame window */
1351 SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu );
1353 /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
1354 if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
1355 return E_FAIL;
1357 else /* Want to uninstall dispatching code */
1359 /* Uninstall the hooks */
1360 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1361 return E_FAIL;
1363 /* Remove the menu descriptor property from the frame window */
1364 RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" );
1367 return S_OK;
1370 /***********************************************************************
1371 * ReleaseStgMedium [OLE32.140]
1373 void WINAPI ReleaseStgMedium(
1374 STGMEDIUM* pmedium)
1376 switch (pmedium->tymed)
1378 case TYMED_HGLOBAL:
1380 if ( (pmedium->pUnkForRelease==0) &&
1381 (pmedium->u.hGlobal!=0) )
1382 GlobalFree(pmedium->u.hGlobal);
1384 pmedium->u.hGlobal = 0;
1385 break;
1387 case TYMED_FILE:
1389 if (pmedium->u.lpszFileName!=0)
1391 if (pmedium->pUnkForRelease==0)
1393 DeleteFileW(pmedium->u.lpszFileName);
1396 CoTaskMemFree(pmedium->u.lpszFileName);
1399 pmedium->u.lpszFileName = 0;
1400 break;
1402 case TYMED_ISTREAM:
1404 if (pmedium->u.pstm!=0)
1406 IStream_Release(pmedium->u.pstm);
1409 pmedium->u.pstm = 0;
1410 break;
1412 case TYMED_ISTORAGE:
1414 if (pmedium->u.pstg!=0)
1416 IStorage_Release(pmedium->u.pstg);
1419 pmedium->u.pstg = 0;
1420 break;
1422 case TYMED_GDI:
1424 if ( (pmedium->pUnkForRelease==0) &&
1425 (pmedium->u.hGlobal!=0) )
1426 DeleteObject(pmedium->u.hGlobal);
1428 pmedium->u.hGlobal = 0;
1429 break;
1431 case TYMED_MFPICT:
1433 if ( (pmedium->pUnkForRelease==0) &&
1434 (pmedium->u.hMetaFilePict!=0) )
1436 DeleteMetaFile(pmedium->u.hMetaFilePict);
1437 GlobalFree(pmedium->u.hMetaFilePict);
1440 pmedium->u.hMetaFilePict = 0;
1441 break;
1443 case TYMED_ENHMF:
1445 if ( (pmedium->pUnkForRelease==0) &&
1446 (pmedium->u.hEnhMetaFile!=0) )
1448 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
1451 pmedium->u.hEnhMetaFile = 0;
1452 break;
1454 case TYMED_NULL:
1455 default:
1456 break;
1460 * After cleaning up, the unknown is released
1462 if (pmedium->pUnkForRelease!=0)
1464 IUnknown_Release(pmedium->pUnkForRelease);
1465 pmedium->pUnkForRelease = 0;
1469 /***
1470 * OLEDD_Initialize()
1472 * Initializes the OLE drag and drop data structures.
1474 static void OLEDD_Initialize()
1476 WNDCLASSA wndClass;
1478 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1479 wndClass.style = CS_GLOBALCLASS;
1480 wndClass.lpfnWndProc = (WNDPROC)OLEDD_DragTrackerWindowProc;
1481 wndClass.cbClsExtra = 0;
1482 wndClass.cbWndExtra = sizeof(TrackerWindowInfo*);
1483 wndClass.hCursor = 0;
1484 wndClass.hbrBackground = 0;
1485 wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
1487 RegisterClassA (&wndClass);
1490 /***
1491 * OLEDD_UnInitialize()
1493 * Releases the OLE drag and drop data structures.
1495 static void OLEDD_UnInitialize()
1498 * Simply empty the list.
1500 while (targetListHead!=NULL)
1502 RevokeDragDrop(targetListHead->hwndTarget);
1506 /***
1507 * OLEDD_InsertDropTarget()
1509 * Insert the target node in the tree.
1511 static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd)
1513 DropTargetNode* curNode;
1514 DropTargetNode** parentNodeLink;
1517 * Iterate the tree to find the insertion point.
1519 curNode = targetListHead;
1520 parentNodeLink = &targetListHead;
1522 while (curNode!=NULL)
1524 if (nodeToAdd->hwndTarget<curNode->hwndTarget)
1527 * If the node we want to add has a smaller HWND, go left
1529 parentNodeLink = &curNode->prevDropTarget;
1530 curNode = curNode->prevDropTarget;
1532 else if (nodeToAdd->hwndTarget>curNode->hwndTarget)
1535 * If the node we want to add has a larger HWND, go right
1537 parentNodeLink = &curNode->nextDropTarget;
1538 curNode = curNode->nextDropTarget;
1540 else
1543 * The item was found in the list. It shouldn't have been there
1545 assert(FALSE);
1546 return;
1551 * If we get here, we have found a spot for our item. The parentNodeLink
1552 * pointer points to the pointer that we have to modify.
1553 * The curNode should be NULL. We just have to establish the link and Voila!
1555 assert(curNode==NULL);
1556 assert(parentNodeLink!=NULL);
1557 assert(*parentNodeLink==NULL);
1559 *parentNodeLink=nodeToAdd;
1562 /***
1563 * OLEDD_ExtractDropTarget()
1565 * Removes the target node from the tree.
1567 static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget)
1569 DropTargetNode* curNode;
1570 DropTargetNode** parentNodeLink;
1573 * Iterate the tree to find the insertion point.
1575 curNode = targetListHead;
1576 parentNodeLink = &targetListHead;
1578 while (curNode!=NULL)
1580 if (hwndOfTarget<curNode->hwndTarget)
1583 * If the node we want to add has a smaller HWND, go left
1585 parentNodeLink = &curNode->prevDropTarget;
1586 curNode = curNode->prevDropTarget;
1588 else if (hwndOfTarget>curNode->hwndTarget)
1591 * If the node we want to add has a larger HWND, go right
1593 parentNodeLink = &curNode->nextDropTarget;
1594 curNode = curNode->nextDropTarget;
1596 else
1599 * The item was found in the list. Detach it from it's parent and
1600 * re-insert it's kids in the tree.
1602 assert(parentNodeLink!=NULL);
1603 assert(*parentNodeLink==curNode);
1606 * We arbitrately re-attach the left sub-tree to the parent.
1608 *parentNodeLink = curNode->prevDropTarget;
1611 * And we re-insert the right subtree
1613 if (curNode->nextDropTarget!=NULL)
1615 OLEDD_InsertDropTarget(curNode->nextDropTarget);
1619 * The node we found is still a valid node once we complete
1620 * the unlinking of the kids.
1622 curNode->nextDropTarget=NULL;
1623 curNode->prevDropTarget=NULL;
1625 return curNode;
1630 * If we get here, the node is not in the tree
1632 return NULL;
1635 /***
1636 * OLEDD_FindDropTarget()
1638 * Finds information about the drop target.
1640 static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
1642 DropTargetNode* curNode;
1645 * Iterate the tree to find the HWND value.
1647 curNode = targetListHead;
1649 while (curNode!=NULL)
1651 if (hwndOfTarget<curNode->hwndTarget)
1654 * If the node we want to add has a smaller HWND, go left
1656 curNode = curNode->prevDropTarget;
1658 else if (hwndOfTarget>curNode->hwndTarget)
1661 * If the node we want to add has a larger HWND, go right
1663 curNode = curNode->nextDropTarget;
1665 else
1668 * The item was found in the list.
1670 return curNode;
1675 * If we get here, the item is not in the list
1677 return NULL;
1680 /***
1681 * OLEDD_DragTrackerWindowProc()
1683 * This method is the WindowProcedure of the drag n drop tracking
1684 * window. During a drag n Drop operation, an invisible window is created
1685 * to receive the user input and act upon it. This procedure is in charge
1686 * of this behavior.
1688 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
1689 HWND hwnd,
1690 UINT uMsg,
1691 WPARAM wParam,
1692 LPARAM lParam)
1694 switch (uMsg)
1696 case WM_CREATE:
1698 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
1700 SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams);
1703 break;
1705 case WM_MOUSEMOVE:
1707 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1708 POINT mousePos;
1711 * Get the current mouse position in screen coordinates.
1713 mousePos.x = LOWORD(lParam);
1714 mousePos.y = HIWORD(lParam);
1715 ClientToScreen(hwnd, &mousePos);
1718 * Track the movement of the mouse.
1720 OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam);
1722 break;
1724 case WM_LBUTTONUP:
1725 case WM_MBUTTONUP:
1726 case WM_RBUTTONUP:
1727 case WM_LBUTTONDOWN:
1728 case WM_MBUTTONDOWN:
1729 case WM_RBUTTONDOWN:
1731 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1732 POINT mousePos;
1735 * Get the current mouse position in screen coordinates.
1737 mousePos.x = LOWORD(lParam);
1738 mousePos.y = HIWORD(lParam);
1739 ClientToScreen(hwnd, &mousePos);
1742 * Notify everyone that the button state changed
1743 * TODO: Check if the "escape" key was pressed.
1745 OLEDD_TrackStateChange(trackerInfo, mousePos, wParam);
1747 break;
1752 * This is a window proc after all. Let's call the default.
1754 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1757 /***
1758 * OLEDD_TrackMouseMove()
1760 * This method is invoked while a drag and drop operation is in effect.
1761 * it will generate the appropriate callbacks in the drop source
1762 * and drop target. It will also provide the expected feedback to
1763 * the user.
1765 * params:
1766 * trackerInfo - Pointer to the structure identifying the
1767 * drag & drop operation that is currently
1768 * active.
1769 * mousePos - Current position of the mouse in screen
1770 * coordinates.
1771 * keyState - Contains the state of the shift keys and the
1772 * mouse buttons (MK_LBUTTON and the like)
1774 static void OLEDD_TrackMouseMove(
1775 TrackerWindowInfo* trackerInfo,
1776 POINT mousePos,
1777 DWORD keyState)
1779 HWND hwndNewTarget = 0;
1780 HRESULT hr = S_OK;
1783 * Get the handle of the window under the mouse
1785 hwndNewTarget = WindowFromPoint(mousePos);
1788 * Every time, we re-initialize the effects passed to the
1789 * IDropTarget to the effects allowed by the source.
1791 *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
1794 * If we are hovering over the same target as before, send the
1795 * DragOver notification
1797 if ( (trackerInfo->curDragTarget != 0) &&
1798 (trackerInfo->curDragTargetHWND==hwndNewTarget) )
1800 POINTL mousePosParam;
1803 * The documentation tells me that the coordinate should be in the target
1804 * window's coordinate space. However, the tests I made tell me the
1805 * coordinates should be in screen coordinates.
1807 mousePosParam.x = mousePos.x;
1808 mousePosParam.y = mousePos.y;
1810 IDropTarget_DragOver(trackerInfo->curDragTarget,
1811 keyState,
1812 mousePosParam,
1813 trackerInfo->pdwEffect);
1815 else
1817 DropTargetNode* newDropTargetNode = 0;
1820 * If we changed window, we have to notify our old target and check for
1821 * the new one.
1823 if (trackerInfo->curDragTarget!=0)
1825 IDropTarget_DragLeave(trackerInfo->curDragTarget);
1829 * Make sure we're hovering over a window.
1831 if (hwndNewTarget!=0)
1834 * Find-out if there is a drag target under the mouse
1836 newDropTargetNode = OLEDD_FindDropTarget(hwndNewTarget);
1838 trackerInfo->curDragTargetHWND = hwndNewTarget;
1839 trackerInfo->curDragTarget = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
1842 * If there is, notify it that we just dragged-in
1844 if (trackerInfo->curDragTarget!=0)
1846 POINTL mousePosParam;
1849 * The documentation tells me that the coordinate should be in the target
1850 * window's coordinate space. However, the tests I made tell me the
1851 * coordinates should be in screen coordinates.
1853 mousePosParam.x = mousePos.x;
1854 mousePosParam.y = mousePos.y;
1856 IDropTarget_DragEnter(trackerInfo->curDragTarget,
1857 trackerInfo->dataObject,
1858 keyState,
1859 mousePosParam,
1860 trackerInfo->pdwEffect);
1863 else
1866 * The mouse is not over a window so we don't track anything.
1868 trackerInfo->curDragTargetHWND = 0;
1869 trackerInfo->curDragTarget = 0;
1874 * Now that we have done that, we have to tell the source to give
1875 * us feedback on the work being done by the target. If we don't
1876 * have a target, simulate no effect.
1878 if (trackerInfo->curDragTarget==0)
1880 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
1883 hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
1884 *trackerInfo->pdwEffect);
1887 * When we ask for feedback from the drop source, sometimes it will
1888 * do all the necessary work and sometimes it will not handle it
1889 * when that's the case, we must display the standard drag and drop
1890 * cursors.
1892 if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
1894 if ( (*trackerInfo->pdwEffect & DROPEFFECT_MOVE) ||
1895 (*trackerInfo->pdwEffect & DROPEFFECT_COPY) ||
1896 (*trackerInfo->pdwEffect & DROPEFFECT_LINK) )
1898 SetCursor(LoadCursorA(0, IDC_SIZEALLA));
1900 else
1902 SetCursor(LoadCursorA(0, IDC_NOA));
1907 /***
1908 * OLEDD_TrackStateChange()
1910 * This method is invoked while a drag and drop operation is in effect.
1911 * It is used to notify the drop target/drop source callbacks when
1912 * the state of the keyboard or mouse button change.
1914 * params:
1915 * trackerInfo - Pointer to the structure identifying the
1916 * drag & drop operation that is currently
1917 * active.
1918 * mousePos - Current position of the mouse in screen
1919 * coordinates.
1920 * keyState - Contains the state of the shift keys and the
1921 * mouse buttons (MK_LBUTTON and the like)
1923 static void OLEDD_TrackStateChange(
1924 TrackerWindowInfo* trackerInfo,
1925 POINT mousePos,
1926 DWORD keyState)
1929 * Ask the drop source what to do with the operation.
1931 trackerInfo->returnValue = IDropSource_QueryContinueDrag(
1932 trackerInfo->dropSource,
1933 trackerInfo->escPressed,
1934 keyState);
1937 * All the return valued will stop the operation except the S_OK
1938 * return value.
1940 if (trackerInfo->returnValue!=S_OK)
1943 * Make sure the message loop in DoDragDrop stops
1945 trackerInfo->trackingDone = TRUE;
1948 * Release the mouse in case the drop target decides to show a popup
1949 * or a menu or something.
1951 ReleaseCapture();
1954 * If we end-up over a target, drop the object in the target or
1955 * inform the target that the operation was cancelled.
1957 if (trackerInfo->curDragTarget!=0)
1959 switch (trackerInfo->returnValue)
1962 * If the source wants us to complete the operation, we tell
1963 * the drop target that we just dropped the object in it.
1965 case DRAGDROP_S_DROP:
1967 POINTL mousePosParam;
1970 * The documentation tells me that the coordinate should be
1971 * in the target window's coordinate space. However, the tests
1972 * I made tell me the coordinates should be in screen coordinates.
1974 mousePosParam.x = mousePos.x;
1975 mousePosParam.y = mousePos.y;
1977 IDropTarget_Drop(trackerInfo->curDragTarget,
1978 trackerInfo->dataObject,
1979 keyState,
1980 mousePosParam,
1981 trackerInfo->pdwEffect);
1982 break;
1985 * If the source told us that we should cancel, fool the drop
1986 * target by telling it that the mouse left it's window.
1987 * Also set the drop effect to "NONE" in case the application
1988 * ignores the result of DoDragDrop.
1990 case DRAGDROP_S_CANCEL:
1991 IDropTarget_DragLeave(trackerInfo->curDragTarget);
1992 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
1993 break;
1999 /***
2000 * OLEDD_GetButtonState()
2002 * This method will use the current state of the keyboard to build
2003 * a button state mask equivalent to the one passed in the
2004 * WM_MOUSEMOVE wParam.
2006 static DWORD OLEDD_GetButtonState()
2008 BYTE keyboardState[256];
2009 DWORD keyMask = 0;
2011 GetKeyboardState(keyboardState);
2013 if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
2014 keyMask |= MK_SHIFT;
2016 if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
2017 keyMask |= MK_CONTROL;
2019 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
2020 keyMask |= MK_LBUTTON;
2022 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
2023 keyMask |= MK_RBUTTON;
2025 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
2026 keyMask |= MK_MBUTTON;
2028 return keyMask;
2031 /***
2032 * OLEDD_GetButtonState()
2034 * This method will read the default value of the registry key in
2035 * parameter and extract a DWORD value from it. The registry key value
2036 * can be in a string key or a DWORD key.
2038 * params:
2039 * regKey - Key to read the default value from
2040 * pdwValue - Pointer to the location where the DWORD
2041 * value is returned. This value is not modified
2042 * if the value is not found.
2045 static void OLEUTL_ReadRegistryDWORDValue(
2046 HKEY regKey,
2047 DWORD* pdwValue)
2049 char buffer[20];
2050 DWORD dwKeyType;
2051 DWORD cbData = 20;
2052 LONG lres;
2054 lres = RegQueryValueExA(regKey,
2056 NULL,
2057 &dwKeyType,
2058 (LPBYTE)buffer,
2059 &cbData);
2061 if (lres==ERROR_SUCCESS)
2063 switch (dwKeyType)
2065 case REG_DWORD:
2066 *pdwValue = *(DWORD*)buffer;
2067 break;
2068 case REG_EXPAND_SZ:
2069 case REG_MULTI_SZ:
2070 case REG_SZ:
2071 *pdwValue = (DWORD)strtoul(buffer, NULL, 10);
2072 break;
2077 /******************************************************************************
2078 * OleMetaFilePictFromIconAndLabel
2080 * Returns a global memory handle to a metafile which contains the icon and
2081 * label given.
2082 * I guess the result of that should look somehow like desktop icons.
2083 * If no hIcon is given, we load the icon via lpszSourceFile and iIconIndex.
2084 * This code might be wrong at some places.
2086 HGLOBAL16 WINAPI OleMetaFilePictFromIconAndLabel16(
2087 HICON16 hIcon,
2088 LPCOLESTR16 lpszLabel,
2089 LPCOLESTR16 lpszSourceFile,
2090 UINT16 iIconIndex
2092 METAFILEPICT16 *mf;
2093 HGLOBAL16 hmf;
2094 HDC16 hdc;
2096 FIXME("(%04x, '%s', '%s', %d): incorrect metrics, please try to correct them !\n\n\n", hIcon, lpszLabel, lpszSourceFile, iIconIndex);
2098 if (!hIcon) {
2099 if (lpszSourceFile) {
2100 HINSTANCE16 hInstance = LoadLibrary16(lpszSourceFile);
2102 /* load the icon at index from lpszSourceFile */
2103 hIcon = (HICON16)LoadIconA(hInstance, (LPCSTR)(DWORD)iIconIndex);
2104 FreeLibrary16(hInstance);
2105 } else
2106 return (HGLOBAL)NULL;
2109 hdc = CreateMetaFile16(NULL);
2110 DrawIcon(hdc, 0, 0, hIcon); /* FIXME */
2111 TextOutA(hdc, 0, 0, lpszLabel, 1); /* FIXME */
2112 hmf = GlobalAlloc16(0, sizeof(METAFILEPICT16));
2113 mf = (METAFILEPICT16 *)GlobalLock16(hmf);
2114 mf->mm = MM_ANISOTROPIC;
2115 mf->xExt = 20; /* FIXME: bogus */
2116 mf->yExt = 20; /* dito */
2117 mf->hMF = CloseMetaFile16(hdc);
2118 return hmf;