Fill the filedialog95 controls before sending a CDN_INITDONE
[wine/wine64.git] / dlls / ole32 / ole2.c
blob8fafea3cde94d89c8b57d7caca4568a07e110ad5
2 /*
3 * OLE2 library
5 * Copyright 1995 Martin von Loewis
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Noel Borthwick
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "config.h"
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
33 #include "commctrl.h"
34 #include "ole2.h"
35 #include "ole2ver.h"
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winerror.h"
39 #include "winuser.h"
40 #include "winreg.h"
41 #include "wownt32.h"
43 #include "wine/winbase16.h"
44 #include "wine/wingdi16.h"
45 #include "wine/winuser16.h"
46 #include "ole32_main.h"
48 #include "wine/debug.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(ole);
51 WINE_DECLARE_DEBUG_CHANNEL(accel);
53 #define HICON_16(h32) (LOWORD(h32))
54 #define HICON_32(h16) ((HICON)(ULONG_PTR)(h16))
55 #define HINSTANCE_32(h16) ((HINSTANCE)(ULONG_PTR)(h16))
57 /******************************************************************************
58 * These are static/global variables and internal data structures that the
59 * OLE module uses to maintain it's state.
61 typedef struct tagDropTargetNode
63 HWND hwndTarget;
64 IDropTarget* dropTarget;
65 struct tagDropTargetNode* prevDropTarget;
66 struct tagDropTargetNode* nextDropTarget;
67 } DropTargetNode;
69 typedef struct tagTrackerWindowInfo
71 IDataObject* dataObject;
72 IDropSource* dropSource;
73 DWORD dwOKEffect;
74 DWORD* pdwEffect;
75 BOOL trackingDone;
76 HRESULT returnValue;
78 BOOL escPressed;
79 HWND curTargetHWND; /* window the mouse is hovering over */
80 HWND curDragTargetHWND; /* might be a ancestor of curTargetHWND */
81 IDropTarget* curDragTarget;
82 } TrackerWindowInfo;
84 typedef struct tagOleMenuDescriptor /* OleMenuDescriptor */
86 HWND hwndFrame; /* The containers frame window */
87 HWND hwndActiveObject; /* The active objects window */
88 OLEMENUGROUPWIDTHS mgw; /* OLE menu group widths for the shared menu */
89 HMENU hmenuCombined; /* The combined menu */
90 BOOL bIsServerItem; /* True if the currently open popup belongs to the server */
91 } OleMenuDescriptor;
93 typedef struct tagOleMenuHookItem /* OleMenu hook item in per thread hook list */
95 DWORD tid; /* Thread Id */
96 HANDLE hHeap; /* Heap this is allocated from */
97 HHOOK GetMsg_hHook; /* message hook for WH_GETMESSAGE */
98 HHOOK CallWndProc_hHook; /* message hook for WH_CALLWNDPROC */
99 struct tagOleMenuHookItem *next;
100 } OleMenuHookItem;
102 static OleMenuHookItem *hook_list;
105 * This is the lock count on the OLE library. It is controlled by the
106 * OLEInitialize/OLEUninitialize methods.
108 static ULONG OLE_moduleLockCount = 0;
111 * Name of our registered window class.
113 static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";
116 * This is the head of the Drop target container.
118 static DropTargetNode* targetListHead = NULL;
120 /******************************************************************************
121 * These are the prototypes of miscelaneous utility methods
123 static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue);
125 /******************************************************************************
126 * These are the prototypes of the utility methods used to manage a shared menu
128 static void OLEMenu_Initialize();
129 static void OLEMenu_UnInitialize();
130 BOOL OLEMenu_InstallHooks( DWORD tid );
131 BOOL OLEMenu_UnInstallHooks( DWORD tid );
132 OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid );
133 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
134 BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor );
135 LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam);
136 LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam);
138 /******************************************************************************
139 * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c)
141 void OLEClipbrd_UnInitialize();
142 void OLEClipbrd_Initialize();
144 /******************************************************************************
145 * These are the prototypes of the utility methods used for OLE Drag n Drop
147 static void OLEDD_Initialize();
148 static void OLEDD_UnInitialize();
149 static void OLEDD_InsertDropTarget(
150 DropTargetNode* nodeToAdd);
151 static DropTargetNode* OLEDD_ExtractDropTarget(
152 HWND hwndOfTarget);
153 static DropTargetNode* OLEDD_FindDropTarget(
154 HWND hwndOfTarget);
155 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
156 HWND hwnd,
157 UINT uMsg,
158 WPARAM wParam,
159 LPARAM lParam);
160 static void OLEDD_TrackMouseMove(
161 TrackerWindowInfo* trackerInfo,
162 POINT mousePos,
163 DWORD keyState);
164 static void OLEDD_TrackStateChange(
165 TrackerWindowInfo* trackerInfo,
166 POINT mousePos,
167 DWORD keyState);
168 static DWORD OLEDD_GetButtonState();
171 /******************************************************************************
172 * OleBuildVersion [OLE2.1]
173 * OleBuildVersion [OLE32.84]
175 DWORD WINAPI OleBuildVersion(void)
177 TRACE("Returning version %d, build %d.\n", rmm, rup);
178 return (rmm<<16)+rup;
181 /***********************************************************************
182 * OleInitialize (OLE2.2)
183 * OleInitialize (OLE32.108)
185 HRESULT WINAPI OleInitialize(LPVOID reserved)
187 HRESULT hr;
189 TRACE("(%p)\n", reserved);
192 * The first duty of the OleInitialize is to initialize the COM libraries.
194 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
197 * If the CoInitializeEx call failed, the OLE libraries can't be
198 * initialized.
200 if (FAILED(hr))
201 return hr;
204 * Then, it has to initialize the OLE specific modules.
205 * This includes:
206 * Clipboard
207 * Drag and Drop
208 * Object linking and Embedding
209 * In-place activation
211 if (OLE_moduleLockCount==0)
214 * Initialize the libraries.
216 TRACE("() - Initializing the OLE libraries\n");
219 * OLE Clipboard
221 OLEClipbrd_Initialize();
224 * Drag and Drop
226 OLEDD_Initialize();
229 * OLE shared menu
231 OLEMenu_Initialize();
235 * Then, we increase the lock count on the OLE module.
237 OLE_moduleLockCount++;
239 return hr;
242 /******************************************************************************
243 * CoGetCurrentProcess [COMPOBJ.34]
244 * CoGetCurrentProcess [OLE32.18]
246 * NOTES
247 * Is DWORD really the correct return type for this function?
249 DWORD WINAPI CoGetCurrentProcess(void)
251 return GetCurrentProcessId();
254 /******************************************************************************
255 * OleUninitialize [OLE2.3]
256 * OleUninitialize [OLE32.131]
258 void WINAPI OleUninitialize(void)
260 TRACE("()\n");
263 * Decrease the lock count on the OLE module.
265 OLE_moduleLockCount--;
268 * If we hit the bottom of the lock stack, free the libraries.
270 if (OLE_moduleLockCount==0)
273 * Actually free the libraries.
275 TRACE("() - Freeing the last reference count\n");
278 * OLE Clipboard
280 OLEClipbrd_UnInitialize();
283 * Drag and Drop
285 OLEDD_UnInitialize();
288 * OLE shared menu
290 OLEMenu_UnInitialize();
294 * Then, uninitialize the COM libraries.
296 CoUninitialize();
299 /******************************************************************************
300 * CoRegisterMessageFilter [OLE32.38]
302 HRESULT WINAPI CoRegisterMessageFilter(
303 LPMESSAGEFILTER lpMessageFilter, /* [in] Pointer to interface */
304 LPMESSAGEFILTER *lplpMessageFilter /* [out] Indirect pointer to prior instance if non-NULL */
306 FIXME("stub\n");
307 if (lplpMessageFilter) {
308 *lplpMessageFilter = NULL;
310 return S_OK;
313 /******************************************************************************
314 * OleInitializeWOW [OLE32.109]
316 HRESULT WINAPI OleInitializeWOW(DWORD x) {
317 FIXME("(0x%08lx),stub!\n",x);
318 return 0;
321 /***********************************************************************
322 * RegisterDragDrop (OLE2.35)
324 HRESULT WINAPI RegisterDragDrop16(
325 HWND16 hwnd,
326 LPDROPTARGET pDropTarget
328 FIXME("(0x%04x,%p),stub!\n",hwnd,pDropTarget);
329 return S_OK;
332 /***********************************************************************
333 * RegisterDragDrop (OLE32.139)
335 HRESULT WINAPI RegisterDragDrop(
336 HWND hwnd,
337 LPDROPTARGET pDropTarget)
339 DropTargetNode* dropTargetInfo;
341 TRACE("(%p,%p)\n", hwnd, pDropTarget);
344 * First, check if the window is already registered.
346 dropTargetInfo = OLEDD_FindDropTarget(hwnd);
348 if (dropTargetInfo!=NULL)
349 return DRAGDROP_E_ALREADYREGISTERED;
352 * If it's not there, we can add it. We first create a node for it.
354 dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));
356 if (dropTargetInfo==NULL)
357 return E_OUTOFMEMORY;
359 dropTargetInfo->hwndTarget = hwnd;
360 dropTargetInfo->prevDropTarget = NULL;
361 dropTargetInfo->nextDropTarget = NULL;
364 * Don't forget that this is an interface pointer, need to nail it down since
365 * we keep a copy of it.
367 dropTargetInfo->dropTarget = pDropTarget;
368 IDropTarget_AddRef(dropTargetInfo->dropTarget);
370 OLEDD_InsertDropTarget(dropTargetInfo);
372 return S_OK;
375 /***********************************************************************
376 * RevokeDragDrop (OLE2.36)
378 HRESULT WINAPI RevokeDragDrop16(
379 HWND16 hwnd
381 FIXME("(0x%04x),stub!\n",hwnd);
382 return S_OK;
385 /***********************************************************************
386 * RevokeDragDrop (OLE32.141)
388 HRESULT WINAPI RevokeDragDrop(
389 HWND hwnd)
391 DropTargetNode* dropTargetInfo;
393 TRACE("(%p)\n", hwnd);
396 * First, check if the window is already registered.
398 dropTargetInfo = OLEDD_ExtractDropTarget(hwnd);
401 * If it ain't in there, it's an error.
403 if (dropTargetInfo==NULL)
404 return DRAGDROP_E_NOTREGISTERED;
407 * If it's in there, clean-up it's used memory and
408 * references
410 IDropTarget_Release(dropTargetInfo->dropTarget);
411 HeapFree(GetProcessHeap(), 0, dropTargetInfo);
413 return S_OK;
416 /***********************************************************************
417 * OleRegGetUserType (OLE32.122)
419 * This implementation of OleRegGetUserType ignores the dwFormOfType
420 * parameter and always returns the full name of the object. This is
421 * not too bad since this is the case for many objects because of the
422 * way they are registered.
424 HRESULT WINAPI OleRegGetUserType(
425 REFCLSID clsid,
426 DWORD dwFormOfType,
427 LPOLESTR* pszUserType)
429 char keyName[60];
430 DWORD dwKeyType;
431 DWORD cbData;
432 HKEY clsidKey;
433 LONG hres;
434 LPBYTE buffer;
435 HRESULT retVal;
437 * Initialize the out parameter.
439 *pszUserType = NULL;
442 * Build the key name we're looking for
444 sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
445 clsid->Data1, clsid->Data2, clsid->Data3,
446 clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
447 clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
449 TRACE("(%s, %ld, %p)\n", keyName, dwFormOfType, pszUserType);
452 * Open the class id Key
454 hres = RegOpenKeyA(HKEY_CLASSES_ROOT,
455 keyName,
456 &clsidKey);
458 if (hres != ERROR_SUCCESS)
459 return REGDB_E_CLASSNOTREG;
462 * Retrieve the size of the name string.
464 cbData = 0;
466 hres = RegQueryValueExA(clsidKey,
468 NULL,
469 &dwKeyType,
470 NULL,
471 &cbData);
473 if (hres!=ERROR_SUCCESS)
475 RegCloseKey(clsidKey);
476 return REGDB_E_READREGDB;
480 * Allocate a buffer for the registry value.
482 *pszUserType = CoTaskMemAlloc(cbData*2);
484 if (*pszUserType==NULL)
486 RegCloseKey(clsidKey);
487 return E_OUTOFMEMORY;
490 buffer = HeapAlloc(GetProcessHeap(), 0, cbData);
492 if (buffer == NULL)
494 RegCloseKey(clsidKey);
495 CoTaskMemFree(*pszUserType);
496 *pszUserType=NULL;
497 return E_OUTOFMEMORY;
500 hres = RegQueryValueExA(clsidKey,
502 NULL,
503 &dwKeyType,
504 buffer,
505 &cbData);
507 RegCloseKey(clsidKey);
510 if (hres!=ERROR_SUCCESS)
512 CoTaskMemFree(*pszUserType);
513 *pszUserType=NULL;
515 retVal = REGDB_E_READREGDB;
517 else
519 MultiByteToWideChar( CP_ACP, 0, buffer, -1, *pszUserType, cbData /*FIXME*/ );
520 retVal = S_OK;
522 HeapFree(GetProcessHeap(), 0, buffer);
524 return retVal;
527 /***********************************************************************
528 * DoDragDrop [OLE32.65]
530 HRESULT WINAPI DoDragDrop (
531 IDataObject *pDataObject, /* [in] ptr to the data obj */
532 IDropSource* pDropSource, /* [in] ptr to the source obj */
533 DWORD dwOKEffect, /* [in] effects allowed by the source */
534 DWORD *pdwEffect) /* [out] ptr to effects of the source */
536 TrackerWindowInfo trackerInfo;
537 HWND hwndTrackWindow;
538 MSG msg;
540 TRACE("(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
543 * Setup the drag n drop tracking window.
545 if (!IsValidInterface((LPUNKNOWN)pDropSource))
546 return E_INVALIDARG;
548 trackerInfo.dataObject = pDataObject;
549 trackerInfo.dropSource = pDropSource;
550 trackerInfo.dwOKEffect = dwOKEffect;
551 trackerInfo.pdwEffect = pdwEffect;
552 trackerInfo.trackingDone = FALSE;
553 trackerInfo.escPressed = FALSE;
554 trackerInfo.curDragTargetHWND = 0;
555 trackerInfo.curTargetHWND = 0;
556 trackerInfo.curDragTarget = 0;
558 hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS,
559 "TrackerWindow",
560 WS_POPUP,
561 CW_USEDEFAULT, CW_USEDEFAULT,
562 CW_USEDEFAULT, CW_USEDEFAULT,
566 (LPVOID)&trackerInfo);
568 if (hwndTrackWindow!=0)
571 * Capture the mouse input
573 SetCapture(hwndTrackWindow);
576 * Pump messages. All mouse input should go the the capture window.
578 while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )
580 if ( (msg.message >= WM_KEYFIRST) &&
581 (msg.message <= WM_KEYLAST) )
584 * When keyboard messages are sent to windows on this thread, we
585 * want to ignore notify the drop source that the state changed.
586 * in the case of the Escape key, we also notify the drop source
587 * we give it a special meaning.
589 if ( (msg.message==WM_KEYDOWN) &&
590 (msg.wParam==VK_ESCAPE) )
592 trackerInfo.escPressed = TRUE;
596 * Notify the drop source.
598 OLEDD_TrackStateChange(&trackerInfo,
599 msg.pt,
600 OLEDD_GetButtonState());
602 else
605 * Dispatch the messages only when it's not a keyboard message.
607 DispatchMessageA(&msg);
612 * Destroy the temporary window.
614 DestroyWindow(hwndTrackWindow);
616 return trackerInfo.returnValue;
619 return E_FAIL;
622 /***********************************************************************
623 * OleQueryLinkFromData [OLE32.118]
625 HRESULT WINAPI OleQueryLinkFromData(
626 IDataObject* pSrcDataObject)
628 FIXME("(%p),stub!\n", pSrcDataObject);
629 return S_OK;
632 /***********************************************************************
633 * OleRegGetMiscStatus [OLE32.121]
635 HRESULT WINAPI OleRegGetMiscStatus(
636 REFCLSID clsid,
637 DWORD dwAspect,
638 DWORD* pdwStatus)
640 char keyName[60];
641 HKEY clsidKey;
642 HKEY miscStatusKey;
643 HKEY aspectKey;
644 LONG result;
647 * Initialize the out parameter.
649 *pdwStatus = 0;
652 * Build the key name we're looking for
654 sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
655 clsid->Data1, clsid->Data2, clsid->Data3,
656 clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
657 clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
659 TRACE("(%s, %ld, %p)\n", keyName, dwAspect, pdwStatus);
662 * Open the class id Key
664 result = RegOpenKeyA(HKEY_CLASSES_ROOT,
665 keyName,
666 &clsidKey);
668 if (result != ERROR_SUCCESS)
669 return REGDB_E_CLASSNOTREG;
672 * Get the MiscStatus
674 result = RegOpenKeyA(clsidKey,
675 "MiscStatus",
676 &miscStatusKey);
679 if (result != ERROR_SUCCESS)
681 RegCloseKey(clsidKey);
682 return REGDB_E_READREGDB;
686 * Read the default value
688 OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
691 * Open the key specific to the requested aspect.
693 sprintf(keyName, "%ld", dwAspect);
695 result = RegOpenKeyA(miscStatusKey,
696 keyName,
697 &aspectKey);
699 if (result == ERROR_SUCCESS)
701 OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
702 RegCloseKey(aspectKey);
706 * Cleanup
708 RegCloseKey(miscStatusKey);
709 RegCloseKey(clsidKey);
711 return S_OK;
714 /******************************************************************************
715 * OleSetContainedObject [OLE32.128]
717 HRESULT WINAPI OleSetContainedObject(
718 LPUNKNOWN pUnknown,
719 BOOL fContained)
721 IRunnableObject* runnable = NULL;
722 HRESULT hres;
724 TRACE("(%p,%x), stub!\n", pUnknown, fContained);
726 hres = IUnknown_QueryInterface(pUnknown,
727 &IID_IRunnableObject,
728 (void**)&runnable);
730 if (SUCCEEDED(hres))
732 hres = IRunnableObject_SetContainedObject(runnable, fContained);
734 IRunnableObject_Release(runnable);
736 return hres;
739 return S_OK;
742 /******************************************************************************
743 * OleLoad [OLE32.112]
745 HRESULT WINAPI OleLoad(
746 LPSTORAGE pStg,
747 REFIID riid,
748 LPOLECLIENTSITE pClientSite,
749 LPVOID* ppvObj)
751 IPersistStorage* persistStorage = NULL;
752 IOleObject* oleObject = NULL;
753 STATSTG storageInfo;
754 HRESULT hres;
756 TRACE("(%p,%p,%p,%p)\n", pStg, riid, pClientSite, ppvObj);
759 * TODO, Conversion ... OleDoAutoConvert
763 * Get the class ID for the object.
765 hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
768 * Now, try and create the handler for the object
770 hres = CoCreateInstance(&storageInfo.clsid,
771 NULL,
772 CLSCTX_INPROC_HANDLER,
773 &IID_IOleObject,
774 (void**)&oleObject);
777 * If that fails, as it will most times, load the default
778 * OLE handler.
780 if (FAILED(hres))
782 hres = OleCreateDefaultHandler(&storageInfo.clsid,
783 NULL,
784 &IID_IOleObject,
785 (void**)&oleObject);
789 * If we couldn't find a handler... this is bad. Abort the whole thing.
791 if (FAILED(hres))
792 return hres;
795 * Inform the new object of it's client site.
797 hres = IOleObject_SetClientSite(oleObject, pClientSite);
800 * Initialize the object with it's IPersistStorage interface.
802 hres = IOleObject_QueryInterface(oleObject,
803 &IID_IPersistStorage,
804 (void**)&persistStorage);
806 if (SUCCEEDED(hres))
808 IPersistStorage_Load(persistStorage, pStg);
810 IPersistStorage_Release(persistStorage);
811 persistStorage = NULL;
815 * Return the requested interface to the caller.
817 hres = IOleObject_QueryInterface(oleObject, riid, ppvObj);
820 * Cleanup interfaces used internally
822 IOleObject_Release(oleObject);
824 return hres;
827 /***********************************************************************
828 * OleSave [OLE32.124]
830 HRESULT WINAPI OleSave(
831 LPPERSISTSTORAGE pPS,
832 LPSTORAGE pStg,
833 BOOL fSameAsLoad)
835 HRESULT hres;
836 CLSID objectClass;
838 TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad);
841 * First, we transfer the class ID (if available)
843 hres = IPersistStorage_GetClassID(pPS, &objectClass);
845 if (SUCCEEDED(hres))
847 WriteClassStg(pStg, &objectClass);
851 * Then, we ask the object to save itself to the
852 * storage. If it is successful, we commit the storage.
854 hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad);
856 if (SUCCEEDED(hres))
858 IStorage_Commit(pStg,
859 STGC_DEFAULT);
862 return hres;
866 /******************************************************************************
867 * OleLockRunning [OLE32.114]
869 HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses)
871 IRunnableObject* runnable = NULL;
872 HRESULT hres;
874 TRACE("(%p,%x,%x)\n", pUnknown, fLock, fLastUnlockCloses);
876 hres = IUnknown_QueryInterface(pUnknown,
877 &IID_IRunnableObject,
878 (void**)&runnable);
880 if (SUCCEEDED(hres))
882 hres = IRunnableObject_LockRunning(runnable, fLock, fLastUnlockCloses);
884 IRunnableObject_Release(runnable);
886 return hres;
888 else
889 return E_INVALIDARG;
893 /**************************************************************************
894 * Internal methods to manage the shared OLE menu in response to the
895 * OLE***MenuDescriptor API
898 /***
899 * OLEMenu_Initialize()
901 * Initializes the OLEMENU data structures.
903 static void OLEMenu_Initialize()
907 /***
908 * OLEMenu_UnInitialize()
910 * Releases the OLEMENU data structures.
912 static void OLEMenu_UnInitialize()
916 /*************************************************************************
917 * OLEMenu_InstallHooks
918 * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
920 * RETURNS: TRUE if message hooks were succesfully installed
921 * FALSE on failure
923 BOOL OLEMenu_InstallHooks( DWORD tid )
925 OleMenuHookItem *pHookItem = NULL;
927 /* Create an entry for the hook table */
928 if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
929 sizeof(OleMenuHookItem)) ) )
930 return FALSE;
932 pHookItem->tid = tid;
933 pHookItem->hHeap = GetProcessHeap();
935 /* Install a thread scope message hook for WH_GETMESSAGE */
936 pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc,
937 0, GetCurrentThreadId() );
938 if ( !pHookItem->GetMsg_hHook )
939 goto CLEANUP;
941 /* Install a thread scope message hook for WH_CALLWNDPROC */
942 pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc,
943 0, GetCurrentThreadId() );
944 if ( !pHookItem->CallWndProc_hHook )
945 goto CLEANUP;
947 /* Insert the hook table entry */
948 pHookItem->next = hook_list;
949 hook_list = pHookItem;
951 return TRUE;
953 CLEANUP:
954 /* Unhook any hooks */
955 if ( pHookItem->GetMsg_hHook )
956 UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
957 if ( pHookItem->CallWndProc_hHook )
958 UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
959 /* Release the hook table entry */
960 HeapFree(pHookItem->hHeap, 0, pHookItem );
962 return FALSE;
965 /*************************************************************************
966 * OLEMenu_UnInstallHooks
967 * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
969 * RETURNS: TRUE if message hooks were succesfully installed
970 * FALSE on failure
972 BOOL OLEMenu_UnInstallHooks( DWORD tid )
974 OleMenuHookItem *pHookItem = NULL;
975 OleMenuHookItem **ppHook = &hook_list;
977 while (*ppHook)
979 if ((*ppHook)->tid == tid)
981 pHookItem = *ppHook;
982 *ppHook = pHookItem->next;
983 break;
985 ppHook = &(*ppHook)->next;
987 if (!pHookItem) return FALSE;
989 /* Uninstall the hooks installed for this thread */
990 if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
991 goto CLEANUP;
992 if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
993 goto CLEANUP;
995 /* Release the hook table entry */
996 HeapFree(pHookItem->hHeap, 0, pHookItem );
998 return TRUE;
1000 CLEANUP:
1001 /* Release the hook table entry */
1002 if (pHookItem)
1003 HeapFree(pHookItem->hHeap, 0, pHookItem );
1005 return FALSE;
1008 /*************************************************************************
1009 * OLEMenu_IsHookInstalled
1010 * Tests if OLEMenu hooks have been installed for a thread
1012 * RETURNS: The pointer and index of the hook table entry for the tid
1013 * NULL and -1 for the index if no hooks were installed for this thread
1015 OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )
1017 OleMenuHookItem *pHookItem = NULL;
1019 /* Do a simple linear search for an entry whose tid matches ours.
1020 * We really need a map but efficiency is not a concern here. */
1021 for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next)
1023 if ( tid == pHookItem->tid )
1024 return pHookItem;
1027 return NULL;
1030 /***********************************************************************
1031 * OLEMenu_FindMainMenuIndex
1033 * Used by OLEMenu API to find the top level group a menu item belongs to.
1034 * On success pnPos contains the index of the item in the top level menu group
1036 * RETURNS: TRUE if the ID was found, FALSE on failure
1038 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
1040 UINT i, nItems;
1042 nItems = GetMenuItemCount( hMainMenu );
1044 for (i = 0; i < nItems; i++)
1046 HMENU hsubmenu;
1048 /* Is the current item a submenu? */
1049 if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
1051 /* If the handle is the same we're done */
1052 if ( hsubmenu == hPopupMenu )
1054 if (pnPos)
1055 *pnPos = i;
1056 return TRUE;
1058 /* Recursively search without updating pnPos */
1059 else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
1061 if (pnPos)
1062 *pnPos = i;
1063 return TRUE;
1068 return FALSE;
1071 /***********************************************************************
1072 * OLEMenu_SetIsServerMenu
1074 * Checks whether a popup menu belongs to a shared menu group which is
1075 * owned by the server, and sets the menu descriptor state accordingly.
1076 * All menu messages from these groups should be routed to the server.
1078 * RETURNS: TRUE if the popup menu is part of a server owned group
1079 * FASE if the popup menu is part of a container owned group
1081 BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
1083 UINT nPos = 0, nWidth, i;
1085 pOleMenuDescriptor->bIsServerItem = FALSE;
1087 /* Don't bother searching if the popup is the combined menu itself */
1088 if ( hmenu == pOleMenuDescriptor->hmenuCombined )
1089 return FALSE;
1091 /* Find the menu item index in the shared OLE menu that this item belongs to */
1092 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) )
1093 return FALSE;
1095 /* The group widths array has counts for the number of elements
1096 * in the groups File, Edit, Container, Object, Window, Help.
1097 * The Edit, Object & Help groups belong to the server object
1098 * and the other three belong to the container.
1099 * Loop through the group widths and locate the group we are a member of.
1101 for ( i = 0, nWidth = 0; i < 6; i++ )
1103 nWidth += pOleMenuDescriptor->mgw.width[i];
1104 if ( nPos < nWidth )
1106 /* Odd elements are server menu widths */
1107 pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;
1108 break;
1112 return pOleMenuDescriptor->bIsServerItem;
1115 /*************************************************************************
1116 * OLEMenu_CallWndProc
1117 * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
1118 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1120 LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
1122 LPCWPSTRUCT pMsg = NULL;
1123 HOLEMENU hOleMenu = 0;
1124 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1125 OleMenuHookItem *pHookItem = NULL;
1126 WORD fuFlags;
1128 TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1130 /* Check if we're being asked to process the message */
1131 if ( HC_ACTION != code )
1132 goto NEXTHOOK;
1134 /* Retrieve the current message being dispatched from lParam */
1135 pMsg = (LPCWPSTRUCT)lParam;
1137 /* Check if the message is destined for a window we are interested in:
1138 * If the window has an OLEMenu property we may need to dispatch
1139 * the menu message to its active objects window instead. */
1141 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1142 if ( !hOleMenu )
1143 goto NEXTHOOK;
1145 /* Get the menu descriptor */
1146 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1147 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1148 goto NEXTHOOK;
1150 /* Process menu messages */
1151 switch( pMsg->message )
1153 case WM_INITMENU:
1155 /* Reset the menu descriptor state */
1156 pOleMenuDescriptor->bIsServerItem = FALSE;
1158 /* Send this message to the server as well */
1159 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1160 pMsg->message, pMsg->wParam, pMsg->lParam );
1161 goto NEXTHOOK;
1164 case WM_INITMENUPOPUP:
1166 /* Save the state for whether this is a server owned menu */
1167 OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
1168 break;
1171 case WM_MENUSELECT:
1173 fuFlags = HIWORD(pMsg->wParam); /* Get flags */
1174 if ( fuFlags & MF_SYSMENU )
1175 goto NEXTHOOK;
1177 /* Save the state for whether this is a server owned popup menu */
1178 else if ( fuFlags & MF_POPUP )
1179 OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
1181 break;
1184 case WM_DRAWITEM:
1186 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
1187 if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
1188 goto NEXTHOOK; /* Not a menu message */
1190 break;
1193 default:
1194 goto NEXTHOOK;
1197 /* If the message was for the server dispatch it accordingly */
1198 if ( pOleMenuDescriptor->bIsServerItem )
1200 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1201 pMsg->message, pMsg->wParam, pMsg->lParam );
1204 NEXTHOOK:
1205 if ( pOleMenuDescriptor )
1206 GlobalUnlock( hOleMenu );
1208 /* Lookup the hook item for the current thread */
1209 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1211 /* This should never fail!! */
1212 WARN("could not retrieve hHook for current thread!\n" );
1213 return 0;
1216 /* Pass on the message to the next hooker */
1217 return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
1220 /*************************************************************************
1221 * OLEMenu_GetMsgProc
1222 * Thread scope WH_GETMESSAGE hook proc filter function (callback)
1223 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1225 LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
1227 LPMSG pMsg = NULL;
1228 HOLEMENU hOleMenu = 0;
1229 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1230 OleMenuHookItem *pHookItem = NULL;
1231 WORD wCode;
1233 TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1235 /* Check if we're being asked to process a messages */
1236 if ( HC_ACTION != code )
1237 goto NEXTHOOK;
1239 /* Retrieve the current message being dispatched from lParam */
1240 pMsg = (LPMSG)lParam;
1242 /* Check if the message is destined for a window we are interested in:
1243 * If the window has an OLEMenu property we may need to dispatch
1244 * the menu message to its active objects window instead. */
1246 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1247 if ( !hOleMenu )
1248 goto NEXTHOOK;
1250 /* Process menu messages */
1251 switch( pMsg->message )
1253 case WM_COMMAND:
1255 wCode = HIWORD(pMsg->wParam); /* Get notification code */
1256 if ( wCode )
1257 goto NEXTHOOK; /* Not a menu message */
1258 break;
1260 default:
1261 goto NEXTHOOK;
1264 /* Get the menu descriptor */
1265 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1266 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1267 goto NEXTHOOK;
1269 /* If the message was for the server dispatch it accordingly */
1270 if ( pOleMenuDescriptor->bIsServerItem )
1272 /* Change the hWnd in the message to the active objects hWnd.
1273 * The message loop which reads this message will automatically
1274 * dispatch it to the embedded objects window. */
1275 pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
1278 NEXTHOOK:
1279 if ( pOleMenuDescriptor )
1280 GlobalUnlock( hOleMenu );
1282 /* Lookup the hook item for the current thread */
1283 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1285 /* This should never fail!! */
1286 WARN("could not retrieve hHook for current thread!\n" );
1287 return FALSE;
1290 /* Pass on the message to the next hooker */
1291 return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
1294 /***********************************************************************
1295 * OleCreateMenuDescriptor [OLE32.97]
1296 * Creates an OLE menu descriptor for OLE to use when dispatching
1297 * menu messages and commands.
1299 * PARAMS:
1300 * hmenuCombined - Handle to the objects combined menu
1301 * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group
1304 HOLEMENU WINAPI OleCreateMenuDescriptor(
1305 HMENU hmenuCombined,
1306 LPOLEMENUGROUPWIDTHS lpMenuWidths)
1308 HOLEMENU hOleMenu;
1309 OleMenuDescriptor *pOleMenuDescriptor;
1310 int i;
1312 if ( !hmenuCombined || !lpMenuWidths )
1313 return 0;
1315 /* Create an OLE menu descriptor */
1316 if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
1317 sizeof(OleMenuDescriptor) ) ) )
1318 return 0;
1320 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1321 if ( !pOleMenuDescriptor )
1322 return 0;
1324 /* Initialize menu group widths and hmenu */
1325 for ( i = 0; i < 6; i++ )
1326 pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
1328 pOleMenuDescriptor->hmenuCombined = hmenuCombined;
1329 pOleMenuDescriptor->bIsServerItem = FALSE;
1330 GlobalUnlock( hOleMenu );
1332 return hOleMenu;
1335 /***********************************************************************
1336 * OleDestroyMenuDescriptor [OLE32.99]
1337 * Destroy the shared menu descriptor
1339 HRESULT WINAPI OleDestroyMenuDescriptor(
1340 HOLEMENU hmenuDescriptor)
1342 if ( hmenuDescriptor )
1343 GlobalFree( hmenuDescriptor );
1344 return S_OK;
1347 /***********************************************************************
1348 * OleSetMenuDescriptor [OLE32.129]
1349 * Installs or removes OLE dispatching code for the containers frame window
1350 * FIXME: The lpFrame and lpActiveObject parameters are currently ignored
1351 * OLE should install context sensitive help F1 filtering for the app when
1352 * these are non null.
1354 * PARAMS:
1355 * hOleMenu Handle to composite menu descriptor
1356 * hwndFrame Handle to containers frame window
1357 * hwndActiveObject Handle to objects in-place activation window
1358 * lpFrame Pointer to IOleInPlaceFrame on containers window
1359 * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object
1361 * RETURNS:
1362 * S_OK - menu installed correctly
1363 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1365 HRESULT WINAPI OleSetMenuDescriptor(
1366 HOLEMENU hOleMenu,
1367 HWND hwndFrame,
1368 HWND hwndActiveObject,
1369 LPOLEINPLACEFRAME lpFrame,
1370 LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1372 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1374 /* Check args */
1375 if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
1376 return E_INVALIDARG;
1378 if ( lpFrame || lpActiveObject )
1380 FIXME("(%x, %p, %p, %p, %p), Context sensitive help filtering not implemented!\n",
1381 (unsigned int)hOleMenu,
1382 hwndFrame,
1383 hwndActiveObject,
1384 lpFrame,
1385 lpActiveObject);
1388 /* Set up a message hook to intercept the containers frame window messages.
1389 * The message filter is responsible for dispatching menu messages from the
1390 * shared menu which are intended for the object.
1393 if ( hOleMenu ) /* Want to install dispatching code */
1395 /* If OLEMenu hooks are already installed for this thread, fail
1396 * Note: This effectively means that OleSetMenuDescriptor cannot
1397 * be called twice in succession on the same frame window
1398 * without first calling it with a null hOleMenu to uninstall */
1399 if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) )
1400 return E_FAIL;
1402 /* Get the menu descriptor */
1403 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1404 if ( !pOleMenuDescriptor )
1405 return E_UNEXPECTED;
1407 /* Update the menu descriptor */
1408 pOleMenuDescriptor->hwndFrame = hwndFrame;
1409 pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
1411 GlobalUnlock( hOleMenu );
1412 pOleMenuDescriptor = NULL;
1414 /* Add a menu descriptor windows property to the frame window */
1415 SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu );
1417 /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
1418 if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
1419 return E_FAIL;
1421 else /* Want to uninstall dispatching code */
1423 /* Uninstall the hooks */
1424 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1425 return E_FAIL;
1427 /* Remove the menu descriptor property from the frame window */
1428 RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" );
1431 return S_OK;
1434 /******************************************************************************
1435 * IsAccelerator [OLE32.75]
1436 * Mostly copied from controls/menu.c TranslateAccelerator implementation
1438 BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd)
1440 /* YES, Accel16! */
1441 LPACCEL16 lpAccelTbl;
1442 int i;
1444 if(!lpMsg) return FALSE;
1445 if (!hAccel || !(lpAccelTbl = (LPACCEL16)LockResource16(HACCEL_16(hAccel))))
1447 WARN_(accel)("invalid accel handle=%p\n", hAccel);
1448 return FALSE;
1450 if((lpMsg->message != WM_KEYDOWN &&
1451 lpMsg->message != WM_KEYUP &&
1452 lpMsg->message != WM_SYSKEYDOWN &&
1453 lpMsg->message != WM_SYSKEYUP &&
1454 lpMsg->message != WM_CHAR)) return FALSE;
1456 TRACE_(accel)("hAccel=%p, cAccelEntries=%d,"
1457 "msg->hwnd=%p, msg->message=%04x, wParam=%08x, lParam=%08lx\n",
1458 hAccel, cAccelEntries,
1459 lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);
1460 for(i = 0; i < cAccelEntries; i++)
1462 if(lpAccelTbl[i].key != lpMsg->wParam)
1463 continue;
1465 if(lpMsg->message == WM_CHAR)
1467 if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY))
1469 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", lpMsg->wParam & 0xff);
1470 goto found;
1473 else
1475 if(lpAccelTbl[i].fVirt & FVIRTKEY)
1477 INT mask = 0;
1478 TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
1479 lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff);
1480 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
1481 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
1482 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
1483 if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
1484 TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n");
1486 else
1488 if(!(lpMsg->lParam & 0x01000000)) /* no special_key */
1490 if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000))
1491 { /* ^^ ALT pressed */
1492 TRACE_(accel)("found accel for Alt-%c\n", lpMsg->wParam & 0xff);
1493 goto found;
1500 WARN_(accel)("couldn't translate accelerator key\n");
1501 return FALSE;
1503 found:
1504 if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd;
1505 return TRUE;
1508 /***********************************************************************
1509 * ReleaseStgMedium [OLE32.140]
1511 void WINAPI ReleaseStgMedium(
1512 STGMEDIUM* pmedium)
1514 switch (pmedium->tymed)
1516 case TYMED_HGLOBAL:
1518 if ( (pmedium->pUnkForRelease==0) &&
1519 (pmedium->u.hGlobal!=0) )
1520 GlobalFree(pmedium->u.hGlobal);
1521 break;
1523 case TYMED_FILE:
1525 if (pmedium->u.lpszFileName!=0)
1527 if (pmedium->pUnkForRelease==0)
1529 DeleteFileW(pmedium->u.lpszFileName);
1532 CoTaskMemFree(pmedium->u.lpszFileName);
1534 break;
1536 case TYMED_ISTREAM:
1538 if (pmedium->u.pstm!=0)
1540 IStream_Release(pmedium->u.pstm);
1542 break;
1544 case TYMED_ISTORAGE:
1546 if (pmedium->u.pstg!=0)
1548 IStorage_Release(pmedium->u.pstg);
1550 break;
1552 case TYMED_GDI:
1554 if ( (pmedium->pUnkForRelease==0) &&
1555 (pmedium->u.hBitmap!=0) )
1556 DeleteObject(pmedium->u.hBitmap);
1557 break;
1559 case TYMED_MFPICT:
1561 if ( (pmedium->pUnkForRelease==0) &&
1562 (pmedium->u.hMetaFilePict!=0) )
1564 LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hMetaFilePict);
1565 DeleteMetaFile(pMP->hMF);
1566 GlobalUnlock(pmedium->u.hMetaFilePict);
1567 GlobalFree(pmedium->u.hMetaFilePict);
1569 break;
1571 case TYMED_ENHMF:
1573 if ( (pmedium->pUnkForRelease==0) &&
1574 (pmedium->u.hEnhMetaFile!=0) )
1576 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
1578 break;
1580 case TYMED_NULL:
1581 default:
1582 break;
1584 pmedium->tymed=TYMED_NULL;
1587 * After cleaning up, the unknown is released
1589 if (pmedium->pUnkForRelease!=0)
1591 IUnknown_Release(pmedium->pUnkForRelease);
1592 pmedium->pUnkForRelease = 0;
1596 /***
1597 * OLEDD_Initialize()
1599 * Initializes the OLE drag and drop data structures.
1601 static void OLEDD_Initialize()
1603 WNDCLASSA wndClass;
1605 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1606 wndClass.style = CS_GLOBALCLASS;
1607 wndClass.lpfnWndProc = (WNDPROC)OLEDD_DragTrackerWindowProc;
1608 wndClass.cbClsExtra = 0;
1609 wndClass.cbWndExtra = sizeof(TrackerWindowInfo*);
1610 wndClass.hCursor = 0;
1611 wndClass.hbrBackground = 0;
1612 wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
1614 RegisterClassA (&wndClass);
1617 /***
1618 * OLEDD_UnInitialize()
1620 * Releases the OLE drag and drop data structures.
1622 static void OLEDD_UnInitialize()
1625 * Simply empty the list.
1627 while (targetListHead!=NULL)
1629 RevokeDragDrop(targetListHead->hwndTarget);
1633 /***
1634 * OLEDD_InsertDropTarget()
1636 * Insert the target node in the tree.
1638 static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd)
1640 DropTargetNode* curNode;
1641 DropTargetNode** parentNodeLink;
1644 * Iterate the tree to find the insertion point.
1646 curNode = targetListHead;
1647 parentNodeLink = &targetListHead;
1649 while (curNode!=NULL)
1651 if (nodeToAdd->hwndTarget<curNode->hwndTarget)
1654 * If the node we want to add has a smaller HWND, go left
1656 parentNodeLink = &curNode->prevDropTarget;
1657 curNode = curNode->prevDropTarget;
1659 else if (nodeToAdd->hwndTarget>curNode->hwndTarget)
1662 * If the node we want to add has a larger HWND, go right
1664 parentNodeLink = &curNode->nextDropTarget;
1665 curNode = curNode->nextDropTarget;
1667 else
1670 * The item was found in the list. It shouldn't have been there
1672 assert(FALSE);
1673 return;
1678 * If we get here, we have found a spot for our item. The parentNodeLink
1679 * pointer points to the pointer that we have to modify.
1680 * The curNode should be NULL. We just have to establish the link and Voila!
1682 assert(curNode==NULL);
1683 assert(parentNodeLink!=NULL);
1684 assert(*parentNodeLink==NULL);
1686 *parentNodeLink=nodeToAdd;
1689 /***
1690 * OLEDD_ExtractDropTarget()
1692 * Removes the target node from the tree.
1694 static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget)
1696 DropTargetNode* curNode;
1697 DropTargetNode** parentNodeLink;
1700 * Iterate the tree to find the insertion point.
1702 curNode = targetListHead;
1703 parentNodeLink = &targetListHead;
1705 while (curNode!=NULL)
1707 if (hwndOfTarget<curNode->hwndTarget)
1710 * If the node we want to add has a smaller HWND, go left
1712 parentNodeLink = &curNode->prevDropTarget;
1713 curNode = curNode->prevDropTarget;
1715 else if (hwndOfTarget>curNode->hwndTarget)
1718 * If the node we want to add has a larger HWND, go right
1720 parentNodeLink = &curNode->nextDropTarget;
1721 curNode = curNode->nextDropTarget;
1723 else
1726 * The item was found in the list. Detach it from it's parent and
1727 * re-insert it's kids in the tree.
1729 assert(parentNodeLink!=NULL);
1730 assert(*parentNodeLink==curNode);
1733 * We arbitrately re-attach the left sub-tree to the parent.
1735 *parentNodeLink = curNode->prevDropTarget;
1738 * And we re-insert the right subtree
1740 if (curNode->nextDropTarget!=NULL)
1742 OLEDD_InsertDropTarget(curNode->nextDropTarget);
1746 * The node we found is still a valid node once we complete
1747 * the unlinking of the kids.
1749 curNode->nextDropTarget=NULL;
1750 curNode->prevDropTarget=NULL;
1752 return curNode;
1757 * If we get here, the node is not in the tree
1759 return NULL;
1762 /***
1763 * OLEDD_FindDropTarget()
1765 * Finds information about the drop target.
1767 static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
1769 DropTargetNode* curNode;
1772 * Iterate the tree to find the HWND value.
1774 curNode = targetListHead;
1776 while (curNode!=NULL)
1778 if (hwndOfTarget<curNode->hwndTarget)
1781 * If the node we want to add has a smaller HWND, go left
1783 curNode = curNode->prevDropTarget;
1785 else if (hwndOfTarget>curNode->hwndTarget)
1788 * If the node we want to add has a larger HWND, go right
1790 curNode = curNode->nextDropTarget;
1792 else
1795 * The item was found in the list.
1797 return curNode;
1802 * If we get here, the item is not in the list
1804 return NULL;
1807 /***
1808 * OLEDD_DragTrackerWindowProc()
1810 * This method is the WindowProcedure of the drag n drop tracking
1811 * window. During a drag n Drop operation, an invisible window is created
1812 * to receive the user input and act upon it. This procedure is in charge
1813 * of this behavior.
1815 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
1816 HWND hwnd,
1817 UINT uMsg,
1818 WPARAM wParam,
1819 LPARAM lParam)
1821 switch (uMsg)
1823 case WM_CREATE:
1825 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
1827 SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams);
1830 break;
1832 case WM_MOUSEMOVE:
1834 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1835 POINT mousePos;
1838 * Get the current mouse position in screen coordinates.
1840 mousePos.x = LOWORD(lParam);
1841 mousePos.y = HIWORD(lParam);
1842 ClientToScreen(hwnd, &mousePos);
1845 * Track the movement of the mouse.
1847 OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam);
1849 break;
1851 case WM_LBUTTONUP:
1852 case WM_MBUTTONUP:
1853 case WM_RBUTTONUP:
1854 case WM_LBUTTONDOWN:
1855 case WM_MBUTTONDOWN:
1856 case WM_RBUTTONDOWN:
1858 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1859 POINT mousePos;
1862 * Get the current mouse position in screen coordinates.
1864 mousePos.x = LOWORD(lParam);
1865 mousePos.y = HIWORD(lParam);
1866 ClientToScreen(hwnd, &mousePos);
1869 * Notify everyone that the button state changed
1870 * TODO: Check if the "escape" key was pressed.
1872 OLEDD_TrackStateChange(trackerInfo, mousePos, wParam);
1874 break;
1879 * This is a window proc after all. Let's call the default.
1881 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1884 /***
1885 * OLEDD_TrackMouseMove()
1887 * This method is invoked while a drag and drop operation is in effect.
1888 * it will generate the appropriate callbacks in the drop source
1889 * and drop target. It will also provide the expected feedback to
1890 * the user.
1892 * params:
1893 * trackerInfo - Pointer to the structure identifying the
1894 * drag & drop operation that is currently
1895 * active.
1896 * mousePos - Current position of the mouse in screen
1897 * coordinates.
1898 * keyState - Contains the state of the shift keys and the
1899 * mouse buttons (MK_LBUTTON and the like)
1901 static void OLEDD_TrackMouseMove(
1902 TrackerWindowInfo* trackerInfo,
1903 POINT mousePos,
1904 DWORD keyState)
1906 HWND hwndNewTarget = 0;
1907 HRESULT hr = S_OK;
1910 * Get the handle of the window under the mouse
1912 hwndNewTarget = WindowFromPoint(mousePos);
1915 * Every time, we re-initialize the effects passed to the
1916 * IDropTarget to the effects allowed by the source.
1918 *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
1921 * If we are hovering over the same target as before, send the
1922 * DragOver notification
1924 if ( (trackerInfo->curDragTarget != 0) &&
1925 (trackerInfo->curTargetHWND == hwndNewTarget) )
1927 POINTL mousePosParam;
1930 * The documentation tells me that the coordinate should be in the target
1931 * window's coordinate space. However, the tests I made tell me the
1932 * coordinates should be in screen coordinates.
1934 mousePosParam.x = mousePos.x;
1935 mousePosParam.y = mousePos.y;
1937 IDropTarget_DragOver(trackerInfo->curDragTarget,
1938 keyState,
1939 mousePosParam,
1940 trackerInfo->pdwEffect);
1942 else
1944 DropTargetNode* newDropTargetNode = 0;
1947 * If we changed window, we have to notify our old target and check for
1948 * the new one.
1950 if (trackerInfo->curDragTarget!=0)
1952 IDropTarget_DragLeave(trackerInfo->curDragTarget);
1956 * Make sure we're hovering over a window.
1958 if (hwndNewTarget!=0)
1961 * Find-out if there is a drag target under the mouse
1963 HWND nexttar = hwndNewTarget;
1964 trackerInfo->curTargetHWND = hwndNewTarget;
1966 do {
1967 newDropTargetNode = OLEDD_FindDropTarget(nexttar);
1968 } while (!newDropTargetNode && (nexttar = GetParent(nexttar)) != 0);
1969 if(nexttar) hwndNewTarget = nexttar;
1971 trackerInfo->curDragTargetHWND = hwndNewTarget;
1972 trackerInfo->curDragTarget = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
1975 * If there is, notify it that we just dragged-in
1977 if (trackerInfo->curDragTarget!=0)
1979 POINTL mousePosParam;
1982 * The documentation tells me that the coordinate should be in the target
1983 * window's coordinate space. However, the tests I made tell me the
1984 * coordinates should be in screen coordinates.
1986 mousePosParam.x = mousePos.x;
1987 mousePosParam.y = mousePos.y;
1989 IDropTarget_DragEnter(trackerInfo->curDragTarget,
1990 trackerInfo->dataObject,
1991 keyState,
1992 mousePosParam,
1993 trackerInfo->pdwEffect);
1996 else
1999 * The mouse is not over a window so we don't track anything.
2001 trackerInfo->curDragTargetHWND = 0;
2002 trackerInfo->curTargetHWND = 0;
2003 trackerInfo->curDragTarget = 0;
2008 * Now that we have done that, we have to tell the source to give
2009 * us feedback on the work being done by the target. If we don't
2010 * have a target, simulate no effect.
2012 if (trackerInfo->curDragTarget==0)
2014 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2017 hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
2018 *trackerInfo->pdwEffect);
2021 * When we ask for feedback from the drop source, sometimes it will
2022 * do all the necessary work and sometimes it will not handle it
2023 * when that's the case, we must display the standard drag and drop
2024 * cursors.
2026 if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
2028 if (*trackerInfo->pdwEffect & DROPEFFECT_MOVE)
2030 SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(1)));
2032 else if (*trackerInfo->pdwEffect & DROPEFFECT_COPY)
2034 SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(2)));
2036 else if (*trackerInfo->pdwEffect & DROPEFFECT_LINK)
2038 SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(3)));
2040 else
2042 SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(0)));
2047 /***
2048 * OLEDD_TrackStateChange()
2050 * This method is invoked while a drag and drop operation is in effect.
2051 * It is used to notify the drop target/drop source callbacks when
2052 * the state of the keyboard or mouse button change.
2054 * params:
2055 * trackerInfo - Pointer to the structure identifying the
2056 * drag & drop operation that is currently
2057 * active.
2058 * mousePos - Current position of the mouse in screen
2059 * coordinates.
2060 * keyState - Contains the state of the shift keys and the
2061 * mouse buttons (MK_LBUTTON and the like)
2063 static void OLEDD_TrackStateChange(
2064 TrackerWindowInfo* trackerInfo,
2065 POINT mousePos,
2066 DWORD keyState)
2069 * Ask the drop source what to do with the operation.
2071 trackerInfo->returnValue = IDropSource_QueryContinueDrag(
2072 trackerInfo->dropSource,
2073 trackerInfo->escPressed,
2074 keyState);
2077 * All the return valued will stop the operation except the S_OK
2078 * return value.
2080 if (trackerInfo->returnValue!=S_OK)
2083 * Make sure the message loop in DoDragDrop stops
2085 trackerInfo->trackingDone = TRUE;
2088 * Release the mouse in case the drop target decides to show a popup
2089 * or a menu or something.
2091 ReleaseCapture();
2094 * If we end-up over a target, drop the object in the target or
2095 * inform the target that the operation was cancelled.
2097 if (trackerInfo->curDragTarget!=0)
2099 switch (trackerInfo->returnValue)
2102 * If the source wants us to complete the operation, we tell
2103 * the drop target that we just dropped the object in it.
2105 case DRAGDROP_S_DROP:
2107 POINTL mousePosParam;
2110 * The documentation tells me that the coordinate should be
2111 * in the target window's coordinate space. However, the tests
2112 * I made tell me the coordinates should be in screen coordinates.
2114 mousePosParam.x = mousePos.x;
2115 mousePosParam.y = mousePos.y;
2117 IDropTarget_Drop(trackerInfo->curDragTarget,
2118 trackerInfo->dataObject,
2119 keyState,
2120 mousePosParam,
2121 trackerInfo->pdwEffect);
2122 break;
2125 * If the source told us that we should cancel, fool the drop
2126 * target by telling it that the mouse left it's window.
2127 * Also set the drop effect to "NONE" in case the application
2128 * ignores the result of DoDragDrop.
2130 case DRAGDROP_S_CANCEL:
2131 IDropTarget_DragLeave(trackerInfo->curDragTarget);
2132 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2133 break;
2139 /***
2140 * OLEDD_GetButtonState()
2142 * This method will use the current state of the keyboard to build
2143 * a button state mask equivalent to the one passed in the
2144 * WM_MOUSEMOVE wParam.
2146 static DWORD OLEDD_GetButtonState()
2148 BYTE keyboardState[256];
2149 DWORD keyMask = 0;
2151 GetKeyboardState(keyboardState);
2153 if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
2154 keyMask |= MK_SHIFT;
2156 if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
2157 keyMask |= MK_CONTROL;
2159 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
2160 keyMask |= MK_LBUTTON;
2162 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
2163 keyMask |= MK_RBUTTON;
2165 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
2166 keyMask |= MK_MBUTTON;
2168 return keyMask;
2171 /***
2172 * OLEDD_GetButtonState()
2174 * This method will read the default value of the registry key in
2175 * parameter and extract a DWORD value from it. The registry key value
2176 * can be in a string key or a DWORD key.
2178 * params:
2179 * regKey - Key to read the default value from
2180 * pdwValue - Pointer to the location where the DWORD
2181 * value is returned. This value is not modified
2182 * if the value is not found.
2185 static void OLEUTL_ReadRegistryDWORDValue(
2186 HKEY regKey,
2187 DWORD* pdwValue)
2189 char buffer[20];
2190 DWORD dwKeyType;
2191 DWORD cbData = 20;
2192 LONG lres;
2194 lres = RegQueryValueExA(regKey,
2196 NULL,
2197 &dwKeyType,
2198 (LPBYTE)buffer,
2199 &cbData);
2201 if (lres==ERROR_SUCCESS)
2203 switch (dwKeyType)
2205 case REG_DWORD:
2206 *pdwValue = *(DWORD*)buffer;
2207 break;
2208 case REG_EXPAND_SZ:
2209 case REG_MULTI_SZ:
2210 case REG_SZ:
2211 *pdwValue = (DWORD)strtoul(buffer, NULL, 10);
2212 break;
2217 /******************************************************************************
2218 * OleMetaFilePictFromIconAndLabel (OLE2.56)
2220 * Returns a global memory handle to a metafile which contains the icon and
2221 * label given.
2222 * I guess the result of that should look somehow like desktop icons.
2223 * If no hIcon is given, we load the icon via lpszSourceFile and iIconIndex.
2224 * This code might be wrong at some places.
2226 HGLOBAL16 WINAPI OleMetaFilePictFromIconAndLabel16(
2227 HICON16 hIcon,
2228 LPCOLESTR16 lpszLabel,
2229 LPCOLESTR16 lpszSourceFile,
2230 UINT16 iIconIndex
2232 METAFILEPICT16 *mf;
2233 HGLOBAL16 hmf;
2234 HDC hdc;
2236 FIXME("(%04x, '%s', '%s', %d): incorrect metrics, please try to correct them !\n\n\n", hIcon, lpszLabel, lpszSourceFile, iIconIndex);
2238 if (!hIcon) {
2239 if (lpszSourceFile) {
2240 HINSTANCE16 hInstance = LoadLibrary16(lpszSourceFile);
2242 /* load the icon at index from lpszSourceFile */
2243 hIcon = HICON_16(LoadIconA(HINSTANCE_32(hInstance), (LPCSTR)(DWORD)iIconIndex));
2244 FreeLibrary16(hInstance);
2245 } else
2246 return 0;
2249 hdc = CreateMetaFileA(NULL);
2250 DrawIcon(hdc, 0, 0, HICON_32(hIcon)); /* FIXME */
2251 TextOutA(hdc, 0, 0, lpszLabel, 1); /* FIXME */
2252 hmf = GlobalAlloc16(0, sizeof(METAFILEPICT16));
2253 mf = (METAFILEPICT16 *)GlobalLock16(hmf);
2254 mf->mm = MM_ANISOTROPIC;
2255 mf->xExt = 20; /* FIXME: bogus */
2256 mf->yExt = 20; /* dito */
2257 mf->hMF = CloseMetaFile16(HDC_16(hdc));
2258 return hmf;
2261 /******************************************************************************
2262 * DllDebugObjectRPCHook (OLE32.62)
2263 * turns on and off internal debugging, pointer is only used on macintosh
2266 BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy)
2268 FIXME("stub\n");
2269 return TRUE;