winevulkan: Update to VK spec version 1.2.195.
[wine.git] / dlls / ole32 / ole2.c
bloba2781e51d5bc17a9f5af295ad3dca6668d05d358
1 /*
2 * OLE2 library
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1999 Francis Beaudet
6 * Copyright 1999 Noel Borthwick
7 * Copyright 1999, 2000 Marcus Meissner
8 * Copyright 1999-2000 Abey George
9 * Copyright 2005 Juan Lang
10 * Copyright 2011 Adam Martinson for CodeWeavers
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include <assert.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
33 #define COBJMACROS
34 #define NONAMELESSUNION
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winerror.h"
39 #include "wingdi.h"
40 #include "winuser.h"
41 #include "winnls.h"
42 #include "winreg.h"
43 #include "ole2.h"
44 #include "ole2ver.h"
46 #include "compobj_private.h"
47 #include "olestd.h"
48 #include "wine/list.h"
50 #include "wine/debug.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(ole);
53 WINE_DECLARE_DEBUG_CHANNEL(accel);
55 /******************************************************************************
56 * These are static/global variables and internal data structures that the
57 * OLE module uses to maintain its state.
59 typedef struct tagTrackerWindowInfo
61 IDataObject* dataObject;
62 IDropSource* dropSource;
63 DWORD dwOKEffect;
64 DWORD* pdwEffect;
65 BOOL trackingDone;
66 BOOL inTrackCall;
67 HRESULT returnValue;
69 BOOL escPressed;
70 HWND curTargetHWND; /* window the mouse is hovering over */
71 IDropTarget* curDragTarget;
72 POINTL curMousePos; /* current position of the mouse in screen coordinates */
73 DWORD dwKeyState; /* current state of the shift and ctrl keys and the mouse buttons */
74 } TrackerWindowInfo;
76 typedef struct tagOleMenuDescriptor /* OleMenuDescriptor */
78 HWND hwndFrame; /* The containers frame window */
79 HWND hwndActiveObject; /* The active objects window */
80 OLEMENUGROUPWIDTHS mgw; /* OLE menu group widths for the shared menu */
81 HMENU hmenuCombined; /* The combined menu */
82 BOOL bIsServerItem; /* True if the currently open popup belongs to the server */
83 } OleMenuDescriptor;
85 typedef struct tagOleMenuHookItem /* OleMenu hook item in per thread hook list */
87 DWORD tid; /* Thread Id */
88 HANDLE hHeap; /* Heap this is allocated from */
89 HHOOK GetMsg_hHook; /* message hook for WH_GETMESSAGE */
90 HHOOK CallWndProc_hHook; /* message hook for WH_CALLWNDPROC */
91 struct tagOleMenuHookItem *next;
92 } OleMenuHookItem;
94 static OleMenuHookItem *hook_list;
97 * This is the lock count on the OLE library. It is controlled by the
98 * OLEInitialize/OLEUninitialize methods.
100 static LONG OLE_moduleLockCount = 0;
103 * Name of our registered window class.
105 static const WCHAR OLEDD_DRAGTRACKERCLASS[] = L"WineDragDropTracker32";
108 * Name of menu descriptor property.
110 static const WCHAR prop_olemenuW[] = L"PROP_OLEMenuDescriptor";
112 /* property to store IDropTarget pointer */
113 static const WCHAR prop_oledroptarget[] = L"OleDropTargetInterface";
115 /* property to store Marshalled IDropTarget pointer */
116 static const WCHAR prop_marshalleddroptarget[] = L"WineMarshalledDropTarget";
118 /******************************************************************************
119 * These are the prototypes of miscellaneous utility methods
121 static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue);
123 /******************************************************************************
124 * These are the prototypes of the utility methods used to manage a shared menu
126 static void OLEMenu_Initialize(void);
127 static void OLEMenu_UnInitialize(void);
128 static BOOL OLEMenu_InstallHooks( DWORD tid );
129 static BOOL OLEMenu_UnInstallHooks( DWORD tid );
130 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid );
131 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
132 static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor );
133 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam);
134 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam);
136 /******************************************************************************
137 * This is a prototype of the OLE Clipboard uninitialization method (in clipboard.c)
139 extern void clipbrd_uninitialize(void);
141 /******************************************************************************
142 * These are the prototypes of the utility methods used for OLE Drag n Drop
144 static void OLEDD_Initialize(void);
145 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
146 static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo);
147 static DWORD OLEDD_GetButtonState(void);
149 /******************************************************************************
150 * OleBuildVersion [OLE32.@]
152 DWORD WINAPI OleBuildVersion(void)
154 TRACE("Returning version %d, build %d.\n", rmm, rup);
155 return (rmm<<16)+rup;
158 /***********************************************************************
159 * OleInitialize (OLE32.@)
161 HRESULT WINAPI DECLSPEC_HOTPATCH OleInitialize(LPVOID reserved)
163 HRESULT hr;
165 TRACE("(%p)\n", reserved);
168 * The first duty of the OleInitialize is to initialize the COM libraries.
170 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
173 * If the CoInitializeEx call failed, the OLE libraries can't be
174 * initialized.
176 if (FAILED(hr))
177 return hr;
179 if (!COM_CurrentInfo()->ole_inits)
180 hr = S_OK;
181 else
182 hr = S_FALSE;
185 * Then, it has to initialize the OLE specific modules.
186 * This includes:
187 * Clipboard
188 * Drag and Drop
189 * Object linking and Embedding
190 * In-place activation
192 if (!COM_CurrentInfo()->ole_inits++ &&
193 InterlockedIncrement(&OLE_moduleLockCount) == 1)
196 * Initialize the libraries.
198 TRACE("() - Initializing the OLE libraries\n");
201 * Drag and Drop
203 OLEDD_Initialize();
206 * OLE shared menu
208 OLEMenu_Initialize();
211 return hr;
214 /******************************************************************************
215 * OleUninitialize [OLE32.@]
217 void WINAPI DECLSPEC_HOTPATCH OleUninitialize(void)
219 TRACE("()\n");
221 if (COM_CurrentInfo()->ole_inits == 0)
223 WARN("ole_inits is already 0\n");
224 return ;
227 * If we hit the bottom of the lock stack, free the libraries.
229 if (!--COM_CurrentInfo()->ole_inits && !InterlockedDecrement(&OLE_moduleLockCount))
232 * Actually free the libraries.
234 TRACE("() - Freeing the last reference count\n");
237 * OLE Clipboard
239 clipbrd_uninitialize();
242 * OLE shared menu
244 OLEMenu_UnInitialize();
248 * Then, uninitialize the COM libraries.
250 CoUninitialize();
253 /******************************************************************************
254 * OleInitializeWOW [OLE32.@]
256 HRESULT WINAPI OleInitializeWOW(DWORD x, DWORD y) {
257 FIXME("(0x%08x, 0x%08x),stub!\n",x, y);
258 return 0;
261 /*************************************************************
262 * get_droptarget_handle
264 * Retrieve a handle to the map containing the marshalled IDropTarget.
265 * This handle belongs to the process that called RegisterDragDrop.
266 * See get_droptarget_local_handle().
268 static inline HANDLE get_droptarget_handle(HWND hwnd)
270 return GetPropW(hwnd, prop_marshalleddroptarget);
273 /*************************************************************
274 * is_droptarget
276 * Is the window a droptarget.
278 static inline BOOL is_droptarget(HWND hwnd)
280 return get_droptarget_handle(hwnd) != 0;
283 /*************************************************************
284 * get_droptarget_local_handle
286 * Retrieve a handle to the map containing the marshalled IDropTarget.
287 * The handle should be closed when finished with.
289 static HANDLE get_droptarget_local_handle(HWND hwnd)
291 HANDLE handle, local_handle = 0;
293 handle = get_droptarget_handle(hwnd);
295 if(handle)
297 DWORD pid;
298 HANDLE process;
300 GetWindowThreadProcessId(hwnd, &pid);
301 process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid);
302 if(process)
304 DuplicateHandle(process, handle, GetCurrentProcess(), &local_handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
305 CloseHandle(process);
308 return local_handle;
311 /***********************************************************************
312 * create_map_from_stream
314 * Helper for RegisterDragDrop. Creates a file mapping object
315 * with the contents of the provided stream. The stream must
316 * be a global memory backed stream.
318 static HRESULT create_map_from_stream(IStream *stream, HANDLE *map)
320 HGLOBAL hmem;
321 DWORD size;
322 HRESULT hr;
323 void *data;
325 hr = GetHGlobalFromStream(stream, &hmem);
326 if(FAILED(hr)) return hr;
328 size = GlobalSize(hmem);
329 *map = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, NULL);
330 if(!*map) return E_OUTOFMEMORY;
332 data = MapViewOfFile(*map, FILE_MAP_WRITE, 0, 0, size);
333 memcpy(data, GlobalLock(hmem), size);
334 GlobalUnlock(hmem);
335 UnmapViewOfFile(data);
336 return S_OK;
339 /***********************************************************************
340 * create_stream_from_map
342 * Creates a stream from the provided map.
344 static HRESULT create_stream_from_map(HANDLE map, IStream **stream)
346 HRESULT hr = E_OUTOFMEMORY;
347 HGLOBAL hmem;
348 void *data;
349 MEMORY_BASIC_INFORMATION info;
351 data = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
352 if(!data) return hr;
354 VirtualQuery(data, &info, sizeof(info));
355 TRACE("size %d\n", (int)info.RegionSize);
357 hmem = GlobalAlloc(GMEM_MOVEABLE, info.RegionSize);
358 if(hmem)
360 memcpy(GlobalLock(hmem), data, info.RegionSize);
361 GlobalUnlock(hmem);
362 hr = CreateStreamOnHGlobal(hmem, TRUE, stream);
364 UnmapViewOfFile(data);
365 return hr;
368 /* This is to work around apps which break COM rules by not implementing
369 * IDropTarget::QueryInterface(). Windows doesn't expose this because it
370 * doesn't call CoMarshallInterface() in RegisterDragDrop().
371 * The wrapper is only used internally, and only exists for the life of
372 * the marshal. We don't want to hold a ref on the app provided target
373 * as some apps destroy this prior to CoUninitialize without calling
374 * RevokeDragDrop. The only (long-term) ref is held by the window prop. */
375 typedef struct {
376 IDropTarget IDropTarget_iface;
377 HWND hwnd;
378 LONG refs;
379 } DropTargetWrapper;
381 static inline DropTargetWrapper* impl_from_IDropTarget(IDropTarget* iface)
383 return CONTAINING_RECORD(iface, DropTargetWrapper, IDropTarget_iface);
386 static HRESULT WINAPI DropTargetWrapper_QueryInterface(IDropTarget* iface,
387 REFIID riid,
388 void** ppvObject)
390 DropTargetWrapper* This = impl_from_IDropTarget(iface);
391 if (IsEqualIID(riid, &IID_IUnknown) ||
392 IsEqualIID(riid, &IID_IDropTarget))
394 IDropTarget_AddRef(&This->IDropTarget_iface);
395 *ppvObject = &This->IDropTarget_iface;
396 return S_OK;
398 *ppvObject = NULL;
399 return E_NOINTERFACE;
402 static ULONG WINAPI DropTargetWrapper_AddRef(IDropTarget* iface)
404 DropTargetWrapper* This = impl_from_IDropTarget(iface);
405 return InterlockedIncrement(&This->refs);
408 static ULONG WINAPI DropTargetWrapper_Release(IDropTarget* iface)
410 DropTargetWrapper* This = impl_from_IDropTarget(iface);
411 ULONG refs = InterlockedDecrement(&This->refs);
412 if (!refs) HeapFree(GetProcessHeap(), 0, This);
413 return refs;
416 static inline HRESULT get_target_from_wrapper( IDropTarget *wrapper, IDropTarget **target )
418 DropTargetWrapper* This = impl_from_IDropTarget( wrapper );
419 *target = GetPropW( This->hwnd, prop_oledroptarget );
420 if (!*target) return DRAGDROP_E_NOTREGISTERED;
421 IDropTarget_AddRef( *target );
422 return S_OK;
425 static HRESULT WINAPI DropTargetWrapper_DragEnter(IDropTarget* iface,
426 IDataObject* pDataObj,
427 DWORD grfKeyState,
428 POINTL pt,
429 DWORD* pdwEffect)
431 IDropTarget *target;
432 HRESULT r = get_target_from_wrapper( iface, &target );
434 if (SUCCEEDED( r ))
436 r = IDropTarget_DragEnter( target, pDataObj, grfKeyState, pt, pdwEffect );
437 IDropTarget_Release( target );
439 return r;
442 static HRESULT WINAPI DropTargetWrapper_DragOver(IDropTarget* iface,
443 DWORD grfKeyState,
444 POINTL pt,
445 DWORD* pdwEffect)
447 IDropTarget *target;
448 HRESULT r = get_target_from_wrapper( iface, &target );
450 if (SUCCEEDED( r ))
452 r = IDropTarget_DragOver( target, grfKeyState, pt, pdwEffect );
453 IDropTarget_Release( target );
455 return r;
458 static HRESULT WINAPI DropTargetWrapper_DragLeave(IDropTarget* iface)
460 IDropTarget *target;
461 HRESULT r = get_target_from_wrapper( iface, &target );
463 if (SUCCEEDED( r ))
465 r = IDropTarget_DragLeave( target );
466 IDropTarget_Release( target );
468 return r;
471 static HRESULT WINAPI DropTargetWrapper_Drop(IDropTarget* iface,
472 IDataObject* pDataObj,
473 DWORD grfKeyState,
474 POINTL pt,
475 DWORD* pdwEffect)
477 IDropTarget *target;
478 HRESULT r = get_target_from_wrapper( iface, &target );
480 if (SUCCEEDED( r ))
482 r = IDropTarget_Drop( target, pDataObj, grfKeyState, pt, pdwEffect );
483 IDropTarget_Release( target );
485 return r;
488 static const IDropTargetVtbl DropTargetWrapperVTbl =
490 DropTargetWrapper_QueryInterface,
491 DropTargetWrapper_AddRef,
492 DropTargetWrapper_Release,
493 DropTargetWrapper_DragEnter,
494 DropTargetWrapper_DragOver,
495 DropTargetWrapper_DragLeave,
496 DropTargetWrapper_Drop
499 static IDropTarget* WrapDropTarget( HWND hwnd )
501 DropTargetWrapper* This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
503 if (This)
505 This->IDropTarget_iface.lpVtbl = &DropTargetWrapperVTbl;
506 This->hwnd = hwnd;
507 This->refs = 1;
509 return &This->IDropTarget_iface;
512 /***********************************************************************
513 * get_droptarget_pointer
515 * Retrieves the marshalled IDropTarget from the window.
517 static IDropTarget* get_droptarget_pointer(HWND hwnd)
519 IDropTarget *droptarget = NULL;
520 HANDLE map;
521 IStream *stream;
523 map = get_droptarget_local_handle(hwnd);
524 if(!map) return NULL;
526 if(SUCCEEDED(create_stream_from_map(map, &stream)))
528 CoUnmarshalInterface(stream, &IID_IDropTarget, (void**)&droptarget);
529 IStream_Release(stream);
531 CloseHandle(map);
532 return droptarget;
535 /***********************************************************************
536 * RegisterDragDrop (OLE32.@)
538 HRESULT WINAPI RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget)
540 DWORD pid = 0;
541 HRESULT hr;
542 IStream *stream;
543 HANDLE map;
544 IDropTarget *wrapper;
546 TRACE("(%p,%p)\n", hwnd, pDropTarget);
548 if (!COM_CurrentApt())
550 ERR("COM not initialized\n");
551 return E_OUTOFMEMORY;
554 if (!pDropTarget)
555 return E_INVALIDARG;
557 if (!IsWindow(hwnd))
559 ERR("invalid hwnd %p\n", hwnd);
560 return DRAGDROP_E_INVALIDHWND;
563 /* block register for other processes windows */
564 GetWindowThreadProcessId(hwnd, &pid);
565 if (pid != GetCurrentProcessId())
567 FIXME("register for another process windows is disabled\n");
568 return DRAGDROP_E_INVALIDHWND;
571 /* check if the window is already registered */
572 if (is_droptarget(hwnd))
573 return DRAGDROP_E_ALREADYREGISTERED;
576 * Marshal the drop target pointer into a shared memory map and
577 * store the map's handle in a Wine specific window prop. We also
578 * store the drop target pointer itself in the
579 * "OleDropTargetInterface" prop for compatibility with Windows.
582 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
583 if(FAILED(hr)) return hr;
585 /* IDropTarget::QueryInterface() shouldn't be called, some (broken) apps depend on this. */
586 wrapper = WrapDropTarget( hwnd );
587 if(!wrapper)
589 IStream_Release(stream);
590 return E_OUTOFMEMORY;
592 hr = CoMarshalInterface(stream, &IID_IDropTarget, (IUnknown*)wrapper, MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
593 IDropTarget_Release(wrapper);
595 if(SUCCEEDED(hr))
597 hr = create_map_from_stream(stream, &map);
598 if(SUCCEEDED(hr))
600 IDropTarget_AddRef(pDropTarget);
601 SetPropW(hwnd, prop_oledroptarget, pDropTarget);
602 SetPropW(hwnd, prop_marshalleddroptarget, map);
604 else
606 LARGE_INTEGER zero;
607 zero.QuadPart = 0;
608 IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
609 CoReleaseMarshalData(stream);
612 IStream_Release(stream);
614 return hr;
617 /***********************************************************************
618 * RevokeDragDrop (OLE32.@)
620 HRESULT WINAPI RevokeDragDrop(HWND hwnd)
622 HANDLE map;
623 IStream *stream;
624 IDropTarget *drop_target;
625 HRESULT hr;
627 TRACE("(%p)\n", hwnd);
629 if (!IsWindow(hwnd))
631 ERR("invalid hwnd %p\n", hwnd);
632 return DRAGDROP_E_INVALIDHWND;
635 /* no registration data */
636 if (!(map = get_droptarget_handle(hwnd)))
637 return DRAGDROP_E_NOTREGISTERED;
639 drop_target = GetPropW(hwnd, prop_oledroptarget);
640 if(drop_target) IDropTarget_Release(drop_target);
642 RemovePropW(hwnd, prop_oledroptarget);
643 RemovePropW(hwnd, prop_marshalleddroptarget);
645 hr = create_stream_from_map(map, &stream);
646 if(SUCCEEDED(hr))
648 CoReleaseMarshalData(stream);
649 IStream_Release(stream);
651 CloseHandle(map);
653 return hr;
656 /***********************************************************************
657 * OleRegGetUserType (OLE32.@)
659 HRESULT WINAPI OleRegGetUserType(REFCLSID clsid, DWORD form, LPOLESTR *usertype)
661 DWORD valuetype, valuelen;
662 WCHAR auxkeynameW[16];
663 HKEY usertypekey;
664 HRESULT hres;
665 LONG ret;
667 TRACE("(%s, %u, %p)\n", debugstr_guid(clsid), form, usertype);
669 if (!usertype)
670 return E_INVALIDARG;
672 *usertype = NULL;
674 /* Return immediately if it's not registered. */
675 hres = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &usertypekey);
676 if (FAILED(hres))
677 return hres;
679 valuelen = 0;
681 /* Try additional types if requested. If they don't exist fall back to USERCLASSTYPE_FULL. */
682 if (form != USERCLASSTYPE_FULL)
684 HKEY auxkey;
686 swprintf(auxkeynameW, ARRAY_SIZE(auxkeynameW), L"AuxUserType\\%d", form);
687 if (COM_OpenKeyForCLSID(clsid, auxkeynameW, KEY_READ, &auxkey) == S_OK)
689 if (!RegQueryValueExW(auxkey, L"", NULL, &valuetype, NULL, &valuelen) && valuelen)
691 RegCloseKey(usertypekey);
692 usertypekey = auxkey;
694 else
695 RegCloseKey(auxkey);
699 valuelen = 0;
700 if (RegQueryValueExW(usertypekey, L"", NULL, &valuetype, NULL, &valuelen))
702 RegCloseKey(usertypekey);
703 return REGDB_E_READREGDB;
706 *usertype = CoTaskMemAlloc(valuelen);
707 if (!*usertype)
709 RegCloseKey(usertypekey);
710 return E_OUTOFMEMORY;
713 ret = RegQueryValueExW(usertypekey, L"", NULL, &valuetype, (BYTE *)*usertype, &valuelen);
714 RegCloseKey(usertypekey);
715 if (ret != ERROR_SUCCESS)
717 CoTaskMemFree(*usertype);
718 *usertype = NULL;
719 return REGDB_E_READREGDB;
722 return S_OK;
725 /***********************************************************************
726 * DoDragDrop [OLE32.@]
728 HRESULT WINAPI DoDragDrop (
729 IDataObject *pDataObject, /* [in] ptr to the data obj */
730 IDropSource* pDropSource, /* [in] ptr to the source obj */
731 DWORD dwOKEffect, /* [in] effects allowed by the source */
732 DWORD *pdwEffect) /* [out] ptr to effects of the source */
734 TrackerWindowInfo trackerInfo;
735 HWND hwndTrackWindow;
736 MSG msg;
738 TRACE("(%p, %p, %08x, %p)\n", pDataObject, pDropSource, dwOKEffect, pdwEffect);
740 if (!pDataObject || !pDropSource || !pdwEffect)
741 return E_INVALIDARG;
744 * Setup the drag n drop tracking window.
747 trackerInfo.dataObject = pDataObject;
748 trackerInfo.dropSource = pDropSource;
749 trackerInfo.dwOKEffect = dwOKEffect;
750 trackerInfo.pdwEffect = pdwEffect;
751 trackerInfo.trackingDone = FALSE;
752 trackerInfo.inTrackCall = FALSE;
753 trackerInfo.escPressed = FALSE;
754 trackerInfo.curTargetHWND = 0;
755 trackerInfo.curDragTarget = 0;
757 hwndTrackWindow = CreateWindowW(OLEDD_DRAGTRACKERCLASS, L"TrackerWindow",
758 WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
759 CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0,
760 &trackerInfo);
762 if (hwndTrackWindow)
765 * Capture the mouse input
767 SetCapture(hwndTrackWindow);
769 msg.message = 0;
772 * Pump messages. All mouse input should go to the capture window.
774 while (!trackerInfo.trackingDone && GetMessageW(&msg, 0, 0, 0) )
776 trackerInfo.curMousePos.x = msg.pt.x;
777 trackerInfo.curMousePos.y = msg.pt.y;
778 trackerInfo.dwKeyState = OLEDD_GetButtonState();
780 if ( (msg.message >= WM_KEYFIRST) &&
781 (msg.message <= WM_KEYLAST) )
784 * When keyboard messages are sent to windows on this thread, we
785 * want to ignore notify the drop source that the state changed.
786 * in the case of the Escape key, we also notify the drop source
787 * we give it a special meaning.
789 if ( (msg.message==WM_KEYDOWN) &&
790 (msg.wParam==VK_ESCAPE) )
792 trackerInfo.escPressed = TRUE;
796 * Notify the drop source.
798 OLEDD_TrackStateChange(&trackerInfo);
800 else
803 * Dispatch the messages only when it's not a keyboard message.
805 DispatchMessageW(&msg);
809 /* re-post the quit message to outer message loop */
810 if (msg.message == WM_QUIT)
811 PostQuitMessage(msg.wParam);
813 * Destroy the temporary window.
815 DestroyWindow(hwndTrackWindow);
817 return trackerInfo.returnValue;
820 return E_FAIL;
823 /***********************************************************************
824 * OleQueryLinkFromData [OLE32.@]
826 HRESULT WINAPI OleQueryLinkFromData(
827 IDataObject* pSrcDataObject)
829 FIXME("(%p),stub!\n", pSrcDataObject);
830 return S_FALSE;
833 /***********************************************************************
834 * OleRegGetMiscStatus [OLE32.@]
836 HRESULT WINAPI OleRegGetMiscStatus(
837 REFCLSID clsid,
838 DWORD dwAspect,
839 DWORD* pdwStatus)
841 WCHAR keyName[16];
842 HKEY miscStatusKey;
843 HKEY aspectKey;
844 LONG result;
845 HRESULT hr;
847 TRACE("(%s, %d, %p)\n", debugstr_guid(clsid), dwAspect, pdwStatus);
849 if (!pdwStatus) return E_INVALIDARG;
851 *pdwStatus = 0;
853 if (actctx_get_miscstatus(clsid, dwAspect, pdwStatus)) return S_OK;
855 hr = COM_OpenKeyForCLSID(clsid, L"MiscStatus", KEY_READ, &miscStatusKey);
856 if (FAILED(hr))
857 /* missing key is not a failure */
858 return hr == REGDB_E_KEYMISSING ? S_OK : hr;
860 OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
863 * Open the key specific to the requested aspect.
865 swprintf(keyName, ARRAY_SIZE(keyName), L"%d", dwAspect);
867 result = open_classes_key(miscStatusKey, keyName, KEY_READ, &aspectKey);
868 if (result == ERROR_SUCCESS)
870 OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
871 RegCloseKey(aspectKey);
874 RegCloseKey(miscStatusKey);
875 return S_OK;
878 static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum);
880 typedef struct
882 IEnumOLEVERB IEnumOLEVERB_iface;
883 LONG ref;
885 HKEY hkeyVerb;
886 ULONG index;
887 } EnumOLEVERB;
889 static inline EnumOLEVERB *impl_from_IEnumOLEVERB(IEnumOLEVERB *iface)
891 return CONTAINING_RECORD(iface, EnumOLEVERB, IEnumOLEVERB_iface);
894 static HRESULT WINAPI EnumOLEVERB_QueryInterface(
895 IEnumOLEVERB *iface, REFIID riid, void **ppv)
897 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
898 if (IsEqualIID(riid, &IID_IUnknown) ||
899 IsEqualIID(riid, &IID_IEnumOLEVERB))
901 IEnumOLEVERB_AddRef(iface);
902 *ppv = iface;
903 return S_OK;
905 return E_NOINTERFACE;
908 static ULONG WINAPI EnumOLEVERB_AddRef(
909 IEnumOLEVERB *iface)
911 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
912 TRACE("()\n");
913 return InterlockedIncrement(&This->ref);
916 static ULONG WINAPI EnumOLEVERB_Release(
917 IEnumOLEVERB *iface)
919 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
920 LONG refs = InterlockedDecrement(&This->ref);
921 TRACE("()\n");
922 if (!refs)
924 RegCloseKey(This->hkeyVerb);
925 HeapFree(GetProcessHeap(), 0, This);
927 return refs;
930 static HRESULT WINAPI EnumOLEVERB_Next(
931 IEnumOLEVERB *iface, ULONG celt, LPOLEVERB rgelt,
932 ULONG *pceltFetched)
934 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
935 HRESULT hr = S_OK;
937 TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched);
939 if (pceltFetched)
940 *pceltFetched = 0;
942 for (; celt; celt--, rgelt++)
944 WCHAR wszSubKey[20];
945 LONG cbData;
946 LPWSTR pwszOLEVERB;
947 LPWSTR pwszMenuFlags;
948 LPWSTR pwszAttribs;
949 LONG res = RegEnumKeyW(This->hkeyVerb, This->index, wszSubKey, ARRAY_SIZE(wszSubKey));
950 if (res == ERROR_NO_MORE_ITEMS)
952 hr = S_FALSE;
953 break;
955 else if (res != ERROR_SUCCESS)
957 ERR("RegEnumKeyW failed with error %d\n", res);
958 hr = REGDB_E_READREGDB;
959 break;
961 res = RegQueryValueW(This->hkeyVerb, wszSubKey, NULL, &cbData);
962 if (res != ERROR_SUCCESS)
964 ERR("RegQueryValueW failed with error %d\n", res);
965 hr = REGDB_E_READREGDB;
966 break;
968 pwszOLEVERB = CoTaskMemAlloc(cbData);
969 if (!pwszOLEVERB)
971 hr = E_OUTOFMEMORY;
972 break;
974 res = RegQueryValueW(This->hkeyVerb, wszSubKey, pwszOLEVERB, &cbData);
975 if (res != ERROR_SUCCESS)
977 ERR("RegQueryValueW failed with error %d\n", res);
978 hr = REGDB_E_READREGDB;
979 CoTaskMemFree(pwszOLEVERB);
980 break;
983 TRACE("verb string: %s\n", debugstr_w(pwszOLEVERB));
984 pwszMenuFlags = wcschr(pwszOLEVERB, ',');
985 if (!pwszMenuFlags)
987 hr = OLEOBJ_E_INVALIDVERB;
988 CoTaskMemFree(pwszOLEVERB);
989 break;
991 /* nul terminate the name string and advance to first character */
992 *pwszMenuFlags = '\0';
993 pwszMenuFlags++;
994 pwszAttribs = wcschr(pwszMenuFlags, ',');
995 if (!pwszAttribs)
997 hr = OLEOBJ_E_INVALIDVERB;
998 CoTaskMemFree(pwszOLEVERB);
999 break;
1001 /* nul terminate the menu string and advance to first character */
1002 *pwszAttribs = '\0';
1003 pwszAttribs++;
1005 /* fill out structure for this verb */
1006 rgelt->lVerb = wcstol(wszSubKey, NULL, 10);
1007 rgelt->lpszVerbName = pwszOLEVERB; /* user should free */
1008 rgelt->fuFlags = wcstol(pwszMenuFlags, NULL, 10);
1009 rgelt->grfAttribs = wcstol(pwszAttribs, NULL, 10);
1011 if (pceltFetched)
1012 (*pceltFetched)++;
1013 This->index++;
1015 return hr;
1018 static HRESULT WINAPI EnumOLEVERB_Skip(
1019 IEnumOLEVERB *iface, ULONG celt)
1021 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
1023 TRACE("(%d)\n", celt);
1025 This->index += celt;
1026 return S_OK;
1029 static HRESULT WINAPI EnumOLEVERB_Reset(
1030 IEnumOLEVERB *iface)
1032 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
1034 TRACE("()\n");
1036 This->index = 0;
1037 return S_OK;
1040 static HRESULT WINAPI EnumOLEVERB_Clone(
1041 IEnumOLEVERB *iface,
1042 IEnumOLEVERB **ppenum)
1044 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
1045 HKEY hkeyVerb;
1046 TRACE("(%p)\n", ppenum);
1047 if (!DuplicateHandle(GetCurrentProcess(), This->hkeyVerb, GetCurrentProcess(), (HANDLE *)&hkeyVerb, 0, FALSE, DUPLICATE_SAME_ACCESS))
1048 return HRESULT_FROM_WIN32(GetLastError());
1049 return EnumOLEVERB_Construct(hkeyVerb, This->index, ppenum);
1052 static const IEnumOLEVERBVtbl EnumOLEVERB_VTable =
1054 EnumOLEVERB_QueryInterface,
1055 EnumOLEVERB_AddRef,
1056 EnumOLEVERB_Release,
1057 EnumOLEVERB_Next,
1058 EnumOLEVERB_Skip,
1059 EnumOLEVERB_Reset,
1060 EnumOLEVERB_Clone
1063 static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum)
1065 EnumOLEVERB *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1066 if (!This)
1068 RegCloseKey(hkeyVerb);
1069 return E_OUTOFMEMORY;
1071 This->IEnumOLEVERB_iface.lpVtbl = &EnumOLEVERB_VTable;
1072 This->ref = 1;
1073 This->index = index;
1074 This->hkeyVerb = hkeyVerb;
1075 *ppenum = &This->IEnumOLEVERB_iface;
1076 return S_OK;
1079 /***********************************************************************
1080 * OleRegEnumVerbs [OLE32.@]
1082 * Enumerates verbs associated with a class stored in the registry.
1084 * PARAMS
1085 * clsid [I] Class ID to enumerate the verbs for.
1086 * ppenum [O] Enumerator.
1088 * RETURNS
1089 * S_OK: Success.
1090 * REGDB_E_CLASSNOTREG: The specified class does not have a key in the registry.
1091 * REGDB_E_READREGDB: The class key could not be opened for some other reason.
1092 * OLE_E_REGDB_KEY: The Verb subkey for the class is not present.
1093 * OLEOBJ_E_NOVERBS: The Verb subkey for the class is empty.
1095 HRESULT WINAPI OleRegEnumVerbs (REFCLSID clsid, LPENUMOLEVERB* ppenum)
1097 LONG res;
1098 HKEY hkeyVerb;
1099 DWORD dwSubKeys;
1101 TRACE("(%s, %p)\n", debugstr_guid(clsid), ppenum);
1103 res = COM_OpenKeyForCLSID(clsid, L"Verb", KEY_READ, &hkeyVerb);
1104 if (FAILED(res))
1106 if (res == REGDB_E_CLASSNOTREG)
1107 ERR("CLSID %s not registered\n", debugstr_guid(clsid));
1108 else if (res == REGDB_E_KEYMISSING)
1109 ERR("no Verbs key for class %s\n", debugstr_guid(clsid));
1110 else
1111 ERR("failed to open Verbs key for CLSID %s with error %d\n",
1112 debugstr_guid(clsid), res);
1113 return res;
1116 res = RegQueryInfoKeyW(hkeyVerb, NULL, NULL, NULL, &dwSubKeys, NULL,
1117 NULL, NULL, NULL, NULL, NULL, NULL);
1118 if (res != ERROR_SUCCESS)
1120 ERR("failed to get subkey count with error %d\n", GetLastError());
1121 return REGDB_E_READREGDB;
1124 if (!dwSubKeys)
1126 WARN("class %s has no verbs\n", debugstr_guid(clsid));
1127 RegCloseKey(hkeyVerb);
1128 return OLEOBJ_E_NOVERBS;
1131 return EnumOLEVERB_Construct(hkeyVerb, 0, ppenum);
1134 /******************************************************************************
1135 * OleSetContainedObject [OLE32.@]
1137 HRESULT WINAPI OleSetContainedObject(
1138 LPUNKNOWN pUnknown,
1139 BOOL fContained)
1141 IRunnableObject* runnable = NULL;
1142 HRESULT hres;
1144 TRACE("(%p,%x)\n", pUnknown, fContained);
1146 hres = IUnknown_QueryInterface(pUnknown,
1147 &IID_IRunnableObject,
1148 (void**)&runnable);
1150 if (SUCCEEDED(hres))
1152 hres = IRunnableObject_SetContainedObject(runnable, fContained);
1154 IRunnableObject_Release(runnable);
1156 return hres;
1159 return S_OK;
1162 /******************************************************************************
1163 * OleRun [OLE32.@]
1165 * Set the OLE object to the running state.
1167 * PARAMS
1168 * pUnknown [I] OLE object to run.
1170 * RETURNS
1171 * Success: S_OK.
1172 * Failure: Any HRESULT code.
1174 HRESULT WINAPI DECLSPEC_HOTPATCH OleRun(LPUNKNOWN pUnknown)
1176 IRunnableObject *runable;
1177 HRESULT hres;
1179 TRACE("(%p)\n", pUnknown);
1181 hres = IUnknown_QueryInterface(pUnknown, &IID_IRunnableObject, (void**)&runable);
1182 if (FAILED(hres))
1183 return S_OK; /* Appears to return no error. */
1185 hres = IRunnableObject_Run(runable, NULL);
1186 IRunnableObject_Release(runable);
1187 return hres;
1190 /******************************************************************************
1191 * OleLoad [OLE32.@]
1193 HRESULT WINAPI OleLoad(
1194 LPSTORAGE pStg,
1195 REFIID riid,
1196 LPOLECLIENTSITE pClientSite,
1197 LPVOID* ppvObj)
1199 IPersistStorage* persistStorage = NULL;
1200 IUnknown* pUnk;
1201 IOleObject* pOleObject = NULL;
1202 STATSTG storageInfo;
1203 HRESULT hres;
1205 TRACE("(%p, %s, %p, %p)\n", pStg, debugstr_guid(riid), pClientSite, ppvObj);
1207 *ppvObj = NULL;
1210 * TODO, Conversion ... OleDoAutoConvert
1214 * Get the class ID for the object.
1216 hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
1217 if (FAILED(hres))
1218 return hres;
1221 * Now, try and create the handler for the object
1223 hres = CoCreateInstance(&storageInfo.clsid,
1224 NULL,
1225 CLSCTX_INPROC_HANDLER|CLSCTX_INPROC_SERVER,
1226 riid,
1227 (void**)&pUnk);
1230 * If that fails, as it will most times, load the default
1231 * OLE handler.
1233 if (FAILED(hres))
1235 hres = OleCreateDefaultHandler(&storageInfo.clsid,
1236 NULL,
1237 riid,
1238 (void**)&pUnk);
1242 * If we couldn't find a handler... this is bad. Abort the whole thing.
1244 if (FAILED(hres))
1245 return hres;
1247 if (pClientSite)
1249 hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (void **)&pOleObject);
1250 if (SUCCEEDED(hres))
1252 DWORD dwStatus;
1253 hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
1258 * Initialize the object with its IPersistStorage interface.
1260 hres = IUnknown_QueryInterface(pUnk, &IID_IPersistStorage, (void**)&persistStorage);
1261 if (SUCCEEDED(hres))
1263 hres = IPersistStorage_Load(persistStorage, pStg);
1265 IPersistStorage_Release(persistStorage);
1266 persistStorage = NULL;
1269 if (SUCCEEDED(hres) && pClientSite)
1271 * Inform the new object of its client site.
1273 hres = IOleObject_SetClientSite(pOleObject, pClientSite);
1276 * Cleanup interfaces used internally
1278 if (pOleObject)
1279 IOleObject_Release(pOleObject);
1281 if (SUCCEEDED(hres))
1283 IOleLink *pOleLink;
1284 HRESULT hres1;
1285 hres1 = IUnknown_QueryInterface(pUnk, &IID_IOleLink, (void **)&pOleLink);
1286 if (SUCCEEDED(hres1))
1288 FIXME("handle OLE link\n");
1289 IOleLink_Release(pOleLink);
1293 if (FAILED(hres))
1295 IUnknown_Release(pUnk);
1296 pUnk = NULL;
1299 *ppvObj = pUnk;
1301 return hres;
1304 /***********************************************************************
1305 * OleSave [OLE32.@]
1307 HRESULT WINAPI OleSave(
1308 LPPERSISTSTORAGE pPS,
1309 LPSTORAGE pStg,
1310 BOOL fSameAsLoad)
1312 HRESULT hres;
1313 CLSID objectClass;
1315 TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad);
1318 * First, we transfer the class ID (if available)
1320 hres = IPersistStorage_GetClassID(pPS, &objectClass);
1322 if (SUCCEEDED(hres))
1324 WriteClassStg(pStg, &objectClass);
1328 * Then, we ask the object to save itself to the
1329 * storage. If it is successful, we commit the storage.
1331 hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad);
1333 if (SUCCEEDED(hres))
1335 IStorage_Commit(pStg,
1336 STGC_DEFAULT);
1339 return hres;
1343 /******************************************************************************
1344 * OleLockRunning [OLE32.@]
1346 HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses)
1348 IRunnableObject* runnable = NULL;
1349 HRESULT hres;
1351 TRACE("(%p,%x,%x)\n", pUnknown, fLock, fLastUnlockCloses);
1353 hres = IUnknown_QueryInterface(pUnknown,
1354 &IID_IRunnableObject,
1355 (void**)&runnable);
1357 if (SUCCEEDED(hres))
1359 hres = IRunnableObject_LockRunning(runnable, fLock, fLastUnlockCloses);
1361 IRunnableObject_Release(runnable);
1363 return hres;
1366 return S_OK;
1370 /**************************************************************************
1371 * Internal methods to manage the shared OLE menu in response to the
1372 * OLE***MenuDescriptor API
1375 /***
1376 * OLEMenu_Initialize()
1378 * Initializes the OLEMENU data structures.
1380 static void OLEMenu_Initialize(void)
1384 /***
1385 * OLEMenu_UnInitialize()
1387 * Releases the OLEMENU data structures.
1389 static void OLEMenu_UnInitialize(void)
1393 /*************************************************************************
1394 * OLEMenu_InstallHooks
1395 * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
1397 * RETURNS: TRUE if message hooks were successfully installed
1398 * FALSE on failure
1400 static BOOL OLEMenu_InstallHooks( DWORD tid )
1402 OleMenuHookItem *pHookItem;
1404 /* Create an entry for the hook table */
1405 if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
1406 sizeof(OleMenuHookItem)) ) )
1407 return FALSE;
1409 pHookItem->tid = tid;
1410 pHookItem->hHeap = GetProcessHeap();
1411 pHookItem->CallWndProc_hHook = NULL;
1413 /* Install a thread scope message hook for WH_GETMESSAGE */
1414 pHookItem->GetMsg_hHook = SetWindowsHookExW( WH_GETMESSAGE, OLEMenu_GetMsgProc,
1415 0, GetCurrentThreadId() );
1416 if ( !pHookItem->GetMsg_hHook )
1417 goto CLEANUP;
1419 /* Install a thread scope message hook for WH_CALLWNDPROC */
1420 pHookItem->CallWndProc_hHook = SetWindowsHookExW( WH_CALLWNDPROC, OLEMenu_CallWndProc,
1421 0, GetCurrentThreadId() );
1422 if ( !pHookItem->CallWndProc_hHook )
1423 goto CLEANUP;
1425 /* Insert the hook table entry */
1426 pHookItem->next = hook_list;
1427 hook_list = pHookItem;
1429 return TRUE;
1431 CLEANUP:
1432 /* Unhook any hooks */
1433 if ( pHookItem->GetMsg_hHook )
1434 UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
1435 if ( pHookItem->CallWndProc_hHook )
1436 UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
1437 /* Release the hook table entry */
1438 HeapFree(pHookItem->hHeap, 0, pHookItem );
1440 return FALSE;
1443 /*************************************************************************
1444 * OLEMenu_UnInstallHooks
1445 * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
1447 * RETURNS: TRUE if message hooks were successfully installed
1448 * FALSE on failure
1450 static BOOL OLEMenu_UnInstallHooks( DWORD tid )
1452 OleMenuHookItem *pHookItem = NULL;
1453 OleMenuHookItem **ppHook = &hook_list;
1455 while (*ppHook)
1457 if ((*ppHook)->tid == tid)
1459 pHookItem = *ppHook;
1460 *ppHook = pHookItem->next;
1461 break;
1463 ppHook = &(*ppHook)->next;
1465 if (!pHookItem) return FALSE;
1467 /* Uninstall the hooks installed for this thread */
1468 if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
1469 goto CLEANUP;
1470 if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
1471 goto CLEANUP;
1473 /* Release the hook table entry */
1474 HeapFree(pHookItem->hHeap, 0, pHookItem );
1476 return TRUE;
1478 CLEANUP:
1479 /* Release the hook table entry */
1480 HeapFree(pHookItem->hHeap, 0, pHookItem );
1482 return FALSE;
1485 /*************************************************************************
1486 * OLEMenu_IsHookInstalled
1487 * Tests if OLEMenu hooks have been installed for a thread
1489 * RETURNS: The pointer and index of the hook table entry for the tid
1490 * NULL and -1 for the index if no hooks were installed for this thread
1492 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )
1494 OleMenuHookItem *pHookItem;
1496 /* Do a simple linear search for an entry whose tid matches ours.
1497 * We really need a map but efficiency is not a concern here. */
1498 for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next)
1500 if ( tid == pHookItem->tid )
1501 return pHookItem;
1504 return NULL;
1507 /***********************************************************************
1508 * OLEMenu_FindMainMenuIndex
1510 * Used by OLEMenu API to find the top level group a menu item belongs to.
1511 * On success pnPos contains the index of the item in the top level menu group
1513 * RETURNS: TRUE if the ID was found, FALSE on failure
1515 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
1517 INT i, nItems;
1519 nItems = GetMenuItemCount( hMainMenu );
1521 for (i = 0; i < nItems; i++)
1523 HMENU hsubmenu;
1525 /* Is the current item a submenu? */
1526 if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
1528 /* If the handle is the same we're done */
1529 if ( hsubmenu == hPopupMenu )
1531 if (pnPos)
1532 *pnPos = i;
1533 return TRUE;
1535 /* Recursively search without updating pnPos */
1536 else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
1538 if (pnPos)
1539 *pnPos = i;
1540 return TRUE;
1545 return FALSE;
1548 /***********************************************************************
1549 * OLEMenu_SetIsServerMenu
1551 * Checks whether a popup menu belongs to a shared menu group which is
1552 * owned by the server, and sets the menu descriptor state accordingly.
1553 * All menu messages from these groups should be routed to the server.
1555 * RETURNS: TRUE if the popup menu is part of a server owned group
1556 * FALSE if the popup menu is part of a container owned group
1558 static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
1560 UINT nPos = 0, nWidth, i;
1562 pOleMenuDescriptor->bIsServerItem = FALSE;
1564 /* Don't bother searching if the popup is the combined menu itself */
1565 if ( hmenu == pOleMenuDescriptor->hmenuCombined )
1566 return FALSE;
1568 /* Find the menu item index in the shared OLE menu that this item belongs to */
1569 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) )
1570 return FALSE;
1572 /* The group widths array has counts for the number of elements
1573 * in the groups File, Edit, Container, Object, Window, Help.
1574 * The Edit, Object & Help groups belong to the server object
1575 * and the other three belong to the container.
1576 * Loop through the group widths and locate the group we are a member of.
1578 for ( i = 0, nWidth = 0; i < 6; i++ )
1580 nWidth += pOleMenuDescriptor->mgw.width[i];
1581 if ( nPos < nWidth )
1583 /* Odd elements are server menu widths */
1584 pOleMenuDescriptor->bIsServerItem = i%2;
1585 break;
1589 return pOleMenuDescriptor->bIsServerItem;
1592 /*************************************************************************
1593 * OLEMenu_CallWndProc
1594 * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
1595 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1597 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
1599 LPCWPSTRUCT pMsg;
1600 HOLEMENU hOleMenu = 0;
1601 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1602 OleMenuHookItem *pHookItem = NULL;
1603 WORD fuFlags;
1605 TRACE("%i, %04lx, %08lx\n", code, wParam, lParam );
1607 /* Check if we're being asked to process the message */
1608 if ( HC_ACTION != code )
1609 goto NEXTHOOK;
1611 /* Retrieve the current message being dispatched from lParam */
1612 pMsg = (LPCWPSTRUCT)lParam;
1614 /* Check if the message is destined for a window we are interested in:
1615 * If the window has an OLEMenu property we may need to dispatch
1616 * the menu message to its active objects window instead. */
1618 hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW );
1619 if ( !hOleMenu )
1620 goto NEXTHOOK;
1622 /* Get the menu descriptor */
1623 pOleMenuDescriptor = GlobalLock( hOleMenu );
1624 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1625 goto NEXTHOOK;
1627 /* Process menu messages */
1628 switch( pMsg->message )
1630 case WM_INITMENU:
1632 /* Reset the menu descriptor state */
1633 pOleMenuDescriptor->bIsServerItem = FALSE;
1635 /* Send this message to the server as well */
1636 SendMessageW( pOleMenuDescriptor->hwndActiveObject,
1637 pMsg->message, pMsg->wParam, pMsg->lParam );
1638 goto NEXTHOOK;
1641 case WM_INITMENUPOPUP:
1643 /* Save the state for whether this is a server owned menu */
1644 OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
1645 break;
1648 case WM_MENUSELECT:
1650 fuFlags = HIWORD(pMsg->wParam); /* Get flags */
1651 if ( fuFlags & MF_SYSMENU )
1652 goto NEXTHOOK;
1654 /* Save the state for whether this is a server owned popup menu */
1655 else if ( fuFlags & MF_POPUP )
1656 OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
1658 break;
1661 case WM_DRAWITEM:
1663 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
1664 if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
1665 goto NEXTHOOK; /* Not a menu message */
1667 break;
1670 default:
1671 goto NEXTHOOK;
1674 /* If the message was for the server dispatch it accordingly */
1675 if ( pOleMenuDescriptor->bIsServerItem )
1677 SendMessageW( pOleMenuDescriptor->hwndActiveObject,
1678 pMsg->message, pMsg->wParam, pMsg->lParam );
1681 NEXTHOOK:
1682 if ( pOleMenuDescriptor )
1683 GlobalUnlock( hOleMenu );
1685 /* Lookup the hook item for the current thread */
1686 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1688 /* This should never fail!! */
1689 WARN("could not retrieve hHook for current thread!\n" );
1690 return 0;
1693 /* Pass on the message to the next hooker */
1694 return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
1697 /*************************************************************************
1698 * OLEMenu_GetMsgProc
1699 * Thread scope WH_GETMESSAGE hook proc filter function (callback)
1700 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1702 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
1704 LPMSG pMsg;
1705 HOLEMENU hOleMenu = 0;
1706 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1707 OleMenuHookItem *pHookItem = NULL;
1708 WORD wCode;
1710 TRACE("%i, %04lx, %08lx\n", code, wParam, lParam );
1712 /* Check if we're being asked to process a messages */
1713 if ( HC_ACTION != code )
1714 goto NEXTHOOK;
1716 /* Retrieve the current message being dispatched from lParam */
1717 pMsg = (LPMSG)lParam;
1719 /* Check if the message is destined for a window we are interested in:
1720 * If the window has an OLEMenu property we may need to dispatch
1721 * the menu message to its active objects window instead. */
1723 hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW );
1724 if ( !hOleMenu )
1725 goto NEXTHOOK;
1727 /* Process menu messages */
1728 switch( pMsg->message )
1730 case WM_COMMAND:
1732 wCode = HIWORD(pMsg->wParam); /* Get notification code */
1733 if ( wCode )
1734 goto NEXTHOOK; /* Not a menu message */
1735 break;
1737 default:
1738 goto NEXTHOOK;
1741 /* Get the menu descriptor */
1742 pOleMenuDescriptor = GlobalLock( hOleMenu );
1743 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1744 goto NEXTHOOK;
1746 /* If the message was for the server dispatch it accordingly */
1747 if ( pOleMenuDescriptor->bIsServerItem )
1749 /* Change the hWnd in the message to the active objects hWnd.
1750 * The message loop which reads this message will automatically
1751 * dispatch it to the embedded objects window. */
1752 pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
1755 NEXTHOOK:
1756 if ( pOleMenuDescriptor )
1757 GlobalUnlock( hOleMenu );
1759 /* Lookup the hook item for the current thread */
1760 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1762 /* This should never fail!! */
1763 WARN("could not retrieve hHook for current thread!\n" );
1764 return FALSE;
1767 /* Pass on the message to the next hooker */
1768 return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
1771 /***********************************************************************
1772 * OleCreateMenuDescriptor [OLE32.@]
1773 * Creates an OLE menu descriptor for OLE to use when dispatching
1774 * menu messages and commands.
1776 * PARAMS:
1777 * hmenuCombined - Handle to the objects combined menu
1778 * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group
1781 HOLEMENU WINAPI OleCreateMenuDescriptor(
1782 HMENU hmenuCombined,
1783 LPOLEMENUGROUPWIDTHS lpMenuWidths)
1785 HOLEMENU hOleMenu;
1786 OleMenuDescriptor *pOleMenuDescriptor;
1787 int i;
1789 if ( !hmenuCombined || !lpMenuWidths )
1790 return 0;
1792 /* Create an OLE menu descriptor */
1793 if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
1794 sizeof(OleMenuDescriptor) ) ) )
1795 return 0;
1797 pOleMenuDescriptor = GlobalLock( hOleMenu );
1798 if ( !pOleMenuDescriptor )
1799 return 0;
1801 /* Initialize menu group widths and hmenu */
1802 for ( i = 0; i < 6; i++ )
1803 pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
1805 pOleMenuDescriptor->hmenuCombined = hmenuCombined;
1806 pOleMenuDescriptor->bIsServerItem = FALSE;
1807 GlobalUnlock( hOleMenu );
1809 return hOleMenu;
1812 /***********************************************************************
1813 * OleDestroyMenuDescriptor [OLE32.@]
1814 * Destroy the shared menu descriptor
1816 HRESULT WINAPI OleDestroyMenuDescriptor(
1817 HOLEMENU hmenuDescriptor)
1819 if ( hmenuDescriptor )
1820 GlobalFree( hmenuDescriptor );
1821 return S_OK;
1824 /***********************************************************************
1825 * OleSetMenuDescriptor [OLE32.@]
1826 * Installs or removes OLE dispatching code for the containers frame window.
1828 * PARAMS
1829 * hOleMenu Handle to composite menu descriptor
1830 * hwndFrame Handle to containers frame window
1831 * hwndActiveObject Handle to objects in-place activation window
1832 * lpFrame Pointer to IOleInPlaceFrame on containers window
1833 * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object
1835 * RETURNS
1836 * S_OK - menu installed correctly
1837 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1839 * FIXME
1840 * The lpFrame and lpActiveObject parameters are currently ignored
1841 * OLE should install context sensitive help F1 filtering for the app when
1842 * these are non null.
1844 HRESULT WINAPI OleSetMenuDescriptor(
1845 HOLEMENU hOleMenu,
1846 HWND hwndFrame,
1847 HWND hwndActiveObject,
1848 LPOLEINPLACEFRAME lpFrame,
1849 LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1851 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1853 /* Check args */
1854 if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
1855 return E_INVALIDARG;
1857 if ( lpFrame || lpActiveObject )
1859 FIXME("(%p, %p, %p, %p, %p), Context sensitive help filtering not implemented!\n",
1860 hOleMenu,
1861 hwndFrame,
1862 hwndActiveObject,
1863 lpFrame,
1864 lpActiveObject);
1867 /* Set up a message hook to intercept the containers frame window messages.
1868 * The message filter is responsible for dispatching menu messages from the
1869 * shared menu which are intended for the object.
1872 if ( hOleMenu ) /* Want to install dispatching code */
1874 /* If OLEMenu hooks are already installed for this thread, fail
1875 * Note: This effectively means that OleSetMenuDescriptor cannot
1876 * be called twice in succession on the same frame window
1877 * without first calling it with a null hOleMenu to uninstall
1879 if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) )
1880 return E_FAIL;
1882 /* Get the menu descriptor */
1883 pOleMenuDescriptor = GlobalLock( hOleMenu );
1884 if ( !pOleMenuDescriptor )
1885 return E_UNEXPECTED;
1887 /* Update the menu descriptor */
1888 pOleMenuDescriptor->hwndFrame = hwndFrame;
1889 pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
1891 GlobalUnlock( hOleMenu );
1892 pOleMenuDescriptor = NULL;
1894 /* Add a menu descriptor windows property to the frame window */
1895 SetPropW( hwndFrame, prop_olemenuW, hOleMenu );
1897 /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
1898 if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
1899 return E_FAIL;
1901 else /* Want to uninstall dispatching code */
1903 /* Uninstall the hooks */
1904 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1905 return E_FAIL;
1907 /* Remove the menu descriptor property from the frame window */
1908 RemovePropW( hwndFrame, prop_olemenuW );
1911 return S_OK;
1914 /******************************************************************************
1915 * IsAccelerator [OLE32.@]
1916 * Mostly copied from controls/menu.c TranslateAccelerator implementation
1918 BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd)
1920 LPACCEL lpAccelTbl;
1921 int i;
1923 if(!lpMsg) return FALSE;
1924 if (!hAccel)
1926 WARN_(accel)("NULL accel handle\n");
1927 return FALSE;
1929 if((lpMsg->message != WM_KEYDOWN &&
1930 lpMsg->message != WM_SYSKEYDOWN &&
1931 lpMsg->message != WM_SYSCHAR &&
1932 lpMsg->message != WM_CHAR)) return FALSE;
1933 lpAccelTbl = HeapAlloc(GetProcessHeap(), 0, cAccelEntries * sizeof(ACCEL));
1934 if (NULL == lpAccelTbl)
1936 return FALSE;
1938 if (CopyAcceleratorTableW(hAccel, lpAccelTbl, cAccelEntries) != cAccelEntries)
1940 WARN_(accel)("CopyAcceleratorTableW failed\n");
1941 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1942 return FALSE;
1945 TRACE_(accel)("hAccel=%p, cAccelEntries=%d,"
1946 "msg->hwnd=%p, msg->message=%04x, wParam=%08lx, lParam=%08lx\n",
1947 hAccel, cAccelEntries,
1948 lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);
1949 for(i = 0; i < cAccelEntries; i++)
1951 if(lpAccelTbl[i].key != lpMsg->wParam)
1952 continue;
1954 if(lpMsg->message == WM_CHAR)
1956 if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY))
1958 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", LOWORD(lpMsg->wParam) & 0xff);
1959 goto found;
1962 else
1964 if(lpAccelTbl[i].fVirt & FVIRTKEY)
1966 INT mask = 0;
1967 TRACE_(accel)("found accel for virt_key %04lx (scan %04x)\n",
1968 lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff);
1969 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
1970 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
1971 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
1972 if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
1973 TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n");
1975 else
1977 if(!(lpMsg->lParam & 0x01000000)) /* no special_key */
1979 if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000))
1980 { /* ^^ ALT pressed */
1981 TRACE_(accel)("found accel for Alt-%c\n", LOWORD(lpMsg->wParam) & 0xff);
1982 goto found;
1989 WARN_(accel)("couldn't translate accelerator key\n");
1990 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1991 return FALSE;
1993 found:
1994 if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd;
1995 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1996 return TRUE;
1999 /***********************************************************************
2000 * ReleaseStgMedium [OLE32.@]
2002 void WINAPI ReleaseStgMedium(
2003 STGMEDIUM* pmedium)
2005 if (!pmedium) return;
2007 switch (pmedium->tymed)
2009 case TYMED_HGLOBAL:
2011 if ( (pmedium->pUnkForRelease==0) &&
2012 (pmedium->u.hGlobal!=0) )
2013 GlobalFree(pmedium->u.hGlobal);
2014 break;
2016 case TYMED_FILE:
2018 if (pmedium->u.lpszFileName!=0)
2020 if (pmedium->pUnkForRelease==0)
2022 DeleteFileW(pmedium->u.lpszFileName);
2025 CoTaskMemFree(pmedium->u.lpszFileName);
2027 break;
2029 case TYMED_ISTREAM:
2031 if (pmedium->u.pstm!=0)
2033 IStream_Release(pmedium->u.pstm);
2035 break;
2037 case TYMED_ISTORAGE:
2039 if (pmedium->u.pstg!=0)
2041 IStorage_Release(pmedium->u.pstg);
2043 break;
2045 case TYMED_GDI:
2047 if ( (pmedium->pUnkForRelease==0) &&
2048 (pmedium->u.hBitmap!=0) )
2049 DeleteObject(pmedium->u.hBitmap);
2050 break;
2052 case TYMED_MFPICT:
2054 if ( (pmedium->pUnkForRelease==0) &&
2055 (pmedium->u.hMetaFilePict!=0) )
2057 LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hMetaFilePict);
2058 DeleteMetaFile(pMP->hMF);
2059 GlobalUnlock(pmedium->u.hMetaFilePict);
2060 GlobalFree(pmedium->u.hMetaFilePict);
2062 break;
2064 case TYMED_ENHMF:
2066 if ( (pmedium->pUnkForRelease==0) &&
2067 (pmedium->u.hEnhMetaFile!=0) )
2069 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
2071 break;
2073 case TYMED_NULL:
2074 default:
2075 break;
2077 pmedium->tymed=TYMED_NULL;
2080 * After cleaning up, the unknown is released
2082 if (pmedium->pUnkForRelease!=0)
2084 IUnknown_Release(pmedium->pUnkForRelease);
2085 pmedium->pUnkForRelease = 0;
2089 /***
2090 * OLEDD_Initialize()
2092 * Initializes the OLE drag and drop data structures.
2094 static void OLEDD_Initialize(void)
2096 WNDCLASSW wndClass;
2098 ZeroMemory (&wndClass, sizeof(WNDCLASSW));
2099 wndClass.style = CS_GLOBALCLASS;
2100 wndClass.lpfnWndProc = OLEDD_DragTrackerWindowProc;
2101 wndClass.cbClsExtra = 0;
2102 wndClass.cbWndExtra = sizeof(TrackerWindowInfo*);
2103 wndClass.hCursor = 0;
2104 wndClass.hbrBackground = 0;
2105 wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
2107 RegisterClassW (&wndClass);
2110 /***
2111 * OLEDD_DragTrackerWindowProc()
2113 * This method is the WindowProcedure of the drag n drop tracking
2114 * window. During a drag n Drop operation, an invisible window is created
2115 * to receive the user input and act upon it. This procedure is in charge
2116 * of this behavior.
2119 #define DRAG_TIMER_ID 1
2121 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
2122 HWND hwnd,
2123 UINT uMsg,
2124 WPARAM wParam,
2125 LPARAM lParam)
2127 switch (uMsg)
2129 case WM_CREATE:
2131 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
2133 SetWindowLongPtrW(hwnd, 0, (LONG_PTR)createStruct->lpCreateParams);
2134 SetTimer(hwnd, DRAG_TIMER_ID, 50, NULL);
2136 break;
2138 case WM_TIMER:
2139 case WM_MOUSEMOVE:
2140 case WM_LBUTTONUP:
2141 case WM_MBUTTONUP:
2142 case WM_RBUTTONUP:
2143 case WM_LBUTTONDOWN:
2144 case WM_MBUTTONDOWN:
2145 case WM_RBUTTONDOWN:
2147 TrackerWindowInfo *trackerInfo = (TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0);
2148 if (trackerInfo->trackingDone) break;
2149 OLEDD_TrackStateChange(trackerInfo);
2150 break;
2152 case WM_DESTROY:
2154 KillTimer(hwnd, DRAG_TIMER_ID);
2155 break;
2160 * This is a window proc after all. Let's call the default.
2162 return DefWindowProcW (hwnd, uMsg, wParam, lParam);
2165 static void drag_enter( TrackerWindowInfo *info, HWND new_target )
2167 HRESULT hr;
2169 info->curTargetHWND = new_target;
2171 while (new_target && !is_droptarget( new_target ))
2172 new_target = GetParent( new_target );
2174 info->curDragTarget = get_droptarget_pointer( new_target );
2176 if (info->curDragTarget)
2178 *info->pdwEffect = info->dwOKEffect;
2179 hr = IDropTarget_DragEnter( info->curDragTarget, info->dataObject,
2180 info->dwKeyState, info->curMousePos,
2181 info->pdwEffect );
2182 *info->pdwEffect &= info->dwOKEffect;
2184 /* failed DragEnter() means invalid target */
2185 if (hr != S_OK)
2187 IDropTarget_Release( info->curDragTarget );
2188 info->curDragTarget = NULL;
2189 info->curTargetHWND = NULL;
2194 static void drag_end( TrackerWindowInfo *info )
2196 HRESULT hr;
2198 info->trackingDone = TRUE;
2199 ReleaseCapture();
2201 if (info->curDragTarget)
2203 if (info->returnValue == DRAGDROP_S_DROP &&
2204 *info->pdwEffect != DROPEFFECT_NONE)
2206 *info->pdwEffect = info->dwOKEffect;
2207 hr = IDropTarget_Drop( info->curDragTarget, info->dataObject, info->dwKeyState,
2208 info->curMousePos, info->pdwEffect );
2209 *info->pdwEffect &= info->dwOKEffect;
2211 if (FAILED( hr ))
2212 info->returnValue = hr;
2214 else
2216 IDropTarget_DragLeave( info->curDragTarget );
2217 *info->pdwEffect = DROPEFFECT_NONE;
2219 IDropTarget_Release( info->curDragTarget );
2220 info->curDragTarget = NULL;
2222 else
2223 *info->pdwEffect = DROPEFFECT_NONE;
2226 static HRESULT give_feedback( TrackerWindowInfo *info )
2228 HRESULT hr;
2229 int res;
2230 HCURSOR cur;
2232 if (info->curDragTarget == NULL)
2233 *info->pdwEffect = DROPEFFECT_NONE;
2235 hr = IDropSource_GiveFeedback( info->dropSource, *info->pdwEffect );
2237 if (hr == DRAGDROP_S_USEDEFAULTCURSORS)
2239 if (*info->pdwEffect & DROPEFFECT_MOVE)
2240 res = CURSOR_MOVE;
2241 else if (*info->pdwEffect & DROPEFFECT_COPY)
2242 res = CURSOR_COPY;
2243 else if (*info->pdwEffect & DROPEFFECT_LINK)
2244 res = CURSOR_LINK;
2245 else
2246 res = CURSOR_NODROP;
2248 cur = LoadCursorW( hProxyDll, MAKEINTRESOURCEW( res ) );
2249 SetCursor( cur );
2252 return hr;
2255 /***
2256 * OLEDD_TrackStateChange()
2258 * This method is invoked while a drag and drop operation is in effect.
2260 * params:
2261 * trackerInfo - Pointer to the structure identifying the
2262 * drag & drop operation that is currently
2263 * active.
2265 static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo)
2267 HWND hwndNewTarget = 0;
2268 POINT pt;
2271 * This method may be called from QueryContinueDrag again,
2272 * (i.e. by running message loop) so avoid recursive call chain.
2274 if (trackerInfo->inTrackCall) return;
2275 trackerInfo->inTrackCall = TRUE;
2278 * Get the handle of the window under the mouse
2280 pt.x = trackerInfo->curMousePos.x;
2281 pt.y = trackerInfo->curMousePos.y;
2282 hwndNewTarget = WindowFromPoint(pt);
2284 trackerInfo->returnValue = IDropSource_QueryContinueDrag(trackerInfo->dropSource,
2285 trackerInfo->escPressed,
2286 trackerInfo->dwKeyState);
2288 if (trackerInfo->curTargetHWND != hwndNewTarget &&
2289 (trackerInfo->returnValue == S_OK ||
2290 trackerInfo->returnValue == DRAGDROP_S_DROP))
2292 if (trackerInfo->curDragTarget)
2294 IDropTarget_DragLeave(trackerInfo->curDragTarget);
2295 IDropTarget_Release(trackerInfo->curDragTarget);
2296 trackerInfo->curDragTarget = NULL;
2297 trackerInfo->curTargetHWND = NULL;
2300 if (hwndNewTarget)
2301 drag_enter( trackerInfo, hwndNewTarget );
2303 give_feedback( trackerInfo );
2307 if (trackerInfo->returnValue == S_OK)
2309 if (trackerInfo->curDragTarget)
2311 *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
2312 IDropTarget_DragOver(trackerInfo->curDragTarget,
2313 trackerInfo->dwKeyState,
2314 trackerInfo->curMousePos,
2315 trackerInfo->pdwEffect);
2316 *trackerInfo->pdwEffect &= trackerInfo->dwOKEffect;
2318 give_feedback( trackerInfo );
2320 else
2321 drag_end( trackerInfo );
2323 trackerInfo->inTrackCall = FALSE;
2326 /***
2327 * OLEDD_GetButtonState()
2329 * This method will use the current state of the keyboard to build
2330 * a button state mask equivalent to the one passed in the
2331 * WM_MOUSEMOVE wParam.
2333 static DWORD OLEDD_GetButtonState(void)
2335 BYTE keyboardState[256];
2336 DWORD keyMask = 0;
2338 GetKeyboardState(keyboardState);
2340 if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
2341 keyMask |= MK_SHIFT;
2343 if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
2344 keyMask |= MK_CONTROL;
2346 if ( (keyboardState[VK_MENU] & 0x80) !=0)
2347 keyMask |= MK_ALT;
2349 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
2350 keyMask |= MK_LBUTTON;
2352 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
2353 keyMask |= MK_RBUTTON;
2355 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
2356 keyMask |= MK_MBUTTON;
2358 return keyMask;
2361 /***
2362 * OLEDD_GetButtonState()
2364 * This method will read the default value of the registry key in
2365 * parameter and extract a DWORD value from it. The registry key value
2366 * can be in a string key or a DWORD key.
2368 * params:
2369 * regKey - Key to read the default value from
2370 * pdwValue - Pointer to the location where the DWORD
2371 * value is returned. This value is not modified
2372 * if the value is not found.
2375 static void OLEUTL_ReadRegistryDWORDValue(
2376 HKEY regKey,
2377 DWORD* pdwValue)
2379 WCHAR buffer[20];
2380 DWORD cbData = sizeof(buffer);
2381 DWORD dwKeyType;
2382 LONG lres;
2384 lres = RegQueryValueExW(regKey, L"", NULL, &dwKeyType, (BYTE *)buffer, &cbData);
2386 if (lres==ERROR_SUCCESS)
2388 switch (dwKeyType)
2390 case REG_DWORD:
2391 *pdwValue = *(DWORD*)buffer;
2392 break;
2393 case REG_EXPAND_SZ:
2394 case REG_MULTI_SZ:
2395 case REG_SZ:
2396 *pdwValue = wcstoul(buffer, NULL, 10);
2397 break;
2402 /******************************************************************************
2403 * OleDraw (OLE32.@)
2405 * The operation of this function is documented literally in the WinAPI
2406 * documentation to involve a QueryInterface for the IViewObject interface,
2407 * followed by a call to IViewObject::Draw.
2409 HRESULT WINAPI OleDraw(
2410 IUnknown *pUnk,
2411 DWORD dwAspect,
2412 HDC hdcDraw,
2413 LPCRECT rect)
2415 HRESULT hres;
2416 IViewObject *viewobject;
2418 if (!pUnk) return E_INVALIDARG;
2420 hres = IUnknown_QueryInterface(pUnk,
2421 &IID_IViewObject,
2422 (void**)&viewobject);
2423 if (SUCCEEDED(hres))
2425 hres = IViewObject_Draw(viewobject, dwAspect, -1, 0, 0, 0, hdcDraw, (RECTL*)rect, 0, 0, 0);
2426 IViewObject_Release(viewobject);
2427 return hres;
2429 else
2430 return DV_E_NOIVIEWOBJECT;
2433 /***********************************************************************
2434 * OleTranslateAccelerator [OLE32.@]
2436 HRESULT WINAPI OleTranslateAccelerator (LPOLEINPLACEFRAME lpFrame,
2437 LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpmsg)
2439 WORD wID;
2441 TRACE("(%p,%p,%p)\n", lpFrame, lpFrameInfo, lpmsg);
2443 if (IsAccelerator(lpFrameInfo->haccel,lpFrameInfo->cAccelEntries,lpmsg,&wID))
2444 return IOleInPlaceFrame_TranslateAccelerator(lpFrame,lpmsg,wID);
2446 return S_FALSE;
2449 /******************************************************************************
2450 * OleCreate [OLE32.@]
2453 HRESULT WINAPI OleCreate(
2454 REFCLSID rclsid,
2455 REFIID riid,
2456 DWORD renderopt,
2457 LPFORMATETC pFormatEtc,
2458 LPOLECLIENTSITE pClientSite,
2459 LPSTORAGE pStg,
2460 LPVOID* ppvObj)
2462 HRESULT hres;
2463 IUnknown * pUnk = NULL;
2464 IOleObject *pOleObject = NULL;
2466 TRACE("(%s, %s, %d, %p, %p, %p, %p)\n", debugstr_guid(rclsid),
2467 debugstr_guid(riid), renderopt, pFormatEtc, pClientSite, pStg, ppvObj);
2469 hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, riid, (LPVOID*)&pUnk);
2471 if (SUCCEEDED(hres))
2472 hres = IStorage_SetClass(pStg, rclsid);
2474 if (pClientSite && SUCCEEDED(hres))
2476 hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (LPVOID*)&pOleObject);
2477 if (SUCCEEDED(hres))
2479 DWORD dwStatus;
2480 IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
2484 if (SUCCEEDED(hres))
2486 IPersistStorage * pPS;
2487 if (SUCCEEDED((hres = IUnknown_QueryInterface(pUnk, &IID_IPersistStorage, (LPVOID*)&pPS))))
2489 TRACE("trying to set stg %p\n", pStg);
2490 hres = IPersistStorage_InitNew(pPS, pStg);
2491 TRACE("-- result 0x%08x\n", hres);
2492 IPersistStorage_Release(pPS);
2496 if (pClientSite && SUCCEEDED(hres))
2498 TRACE("trying to set clientsite %p\n", pClientSite);
2499 hres = IOleObject_SetClientSite(pOleObject, pClientSite);
2500 TRACE("-- result 0x%08x\n", hres);
2503 if (pOleObject)
2504 IOleObject_Release(pOleObject);
2506 if (((renderopt == OLERENDER_DRAW) || (renderopt == OLERENDER_FORMAT)) &&
2507 SUCCEEDED(hres))
2509 hres = OleRun(pUnk);
2510 if (SUCCEEDED(hres))
2512 IOleCache *pOleCache;
2514 if (SUCCEEDED(IUnknown_QueryInterface(pUnk, &IID_IOleCache, (void **)&pOleCache)))
2516 DWORD dwConnection;
2517 if (renderopt == OLERENDER_DRAW && !pFormatEtc) {
2518 FORMATETC pfe;
2519 pfe.cfFormat = 0;
2520 pfe.ptd = NULL;
2521 pfe.dwAspect = DVASPECT_CONTENT;
2522 pfe.lindex = -1;
2523 pfe.tymed = TYMED_NULL;
2524 hres = IOleCache_Cache(pOleCache, &pfe, ADVF_PRIMEFIRST, &dwConnection);
2526 else
2527 hres = IOleCache_Cache(pOleCache, pFormatEtc, ADVF_PRIMEFIRST, &dwConnection);
2528 IOleCache_Release(pOleCache);
2533 if (FAILED(hres) && pUnk)
2535 IUnknown_Release(pUnk);
2536 pUnk = NULL;
2539 *ppvObj = pUnk;
2541 TRACE("-- %p\n", pUnk);
2542 return hres;
2545 /******************************************************************************
2546 * OleGetAutoConvert [OLE32.@]
2548 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2550 HKEY hkey = NULL;
2551 WCHAR buf[CHARS_IN_GUID];
2552 LONG len;
2553 HRESULT res = S_OK;
2555 res = COM_OpenKeyForCLSID(clsidOld, L"AutoConvertTo", KEY_READ, &hkey);
2556 if (FAILED(res))
2557 goto done;
2559 len = sizeof(buf);
2560 if (RegQueryValueW(hkey, NULL, buf, &len))
2562 res = REGDB_E_KEYMISSING;
2563 goto done;
2565 res = CLSIDFromString(buf, pClsidNew);
2566 done:
2567 if (hkey) RegCloseKey(hkey);
2568 return res;
2571 /******************************************************************************
2572 * OleSetAutoConvert [OLE32.@]
2574 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
2576 HKEY hkey = NULL;
2577 WCHAR szClsidNew[CHARS_IN_GUID];
2578 HRESULT res = S_OK;
2580 TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
2582 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2583 if (FAILED(res))
2584 goto done;
2585 StringFromGUID2(clsidNew, szClsidNew, CHARS_IN_GUID);
2586 if (RegSetValueW(hkey, L"AutoConvertTo", REG_SZ, szClsidNew, (lstrlenW(szClsidNew)+1) * sizeof(WCHAR)))
2588 res = REGDB_E_WRITEREGDB;
2589 goto done;
2592 done:
2593 if (hkey) RegCloseKey(hkey);
2594 return res;
2597 /******************************************************************************
2598 * OleDoAutoConvert [OLE32.@]
2600 HRESULT WINAPI OleDoAutoConvert(LPSTORAGE pStg, LPCLSID pClsidNew)
2602 WCHAR *user_type_old, *user_type_new;
2603 CLIPFORMAT cf;
2604 STATSTG stat;
2605 CLSID clsid;
2606 HRESULT hr;
2608 TRACE("(%p, %p)\n", pStg, pClsidNew);
2610 *pClsidNew = CLSID_NULL;
2611 if(!pStg)
2612 return E_INVALIDARG;
2613 hr = IStorage_Stat(pStg, &stat, STATFLAG_NONAME);
2614 if(FAILED(hr))
2615 return hr;
2617 *pClsidNew = stat.clsid;
2618 hr = OleGetAutoConvert(&stat.clsid, &clsid);
2619 if(FAILED(hr))
2620 return hr;
2622 hr = IStorage_SetClass(pStg, &clsid);
2623 if(FAILED(hr))
2624 return hr;
2626 hr = ReadFmtUserTypeStg(pStg, &cf, &user_type_old);
2627 if(FAILED(hr)) {
2628 cf = 0;
2629 user_type_new = NULL;
2632 hr = OleRegGetUserType(&clsid, USERCLASSTYPE_FULL, &user_type_new);
2633 if(FAILED(hr))
2634 user_type_new = NULL;
2636 hr = WriteFmtUserTypeStg(pStg, cf, user_type_new);
2637 CoTaskMemFree(user_type_new);
2638 if(FAILED(hr))
2640 CoTaskMemFree(user_type_old);
2641 IStorage_SetClass(pStg, &stat.clsid);
2642 return hr;
2645 hr = SetConvertStg(pStg, TRUE);
2646 if(FAILED(hr))
2648 WriteFmtUserTypeStg(pStg, cf, user_type_old);
2649 IStorage_SetClass(pStg, &stat.clsid);
2651 else
2652 *pClsidNew = clsid;
2653 CoTaskMemFree(user_type_old);
2654 return hr;
2657 /******************************************************************************
2658 * OleIsRunning [OLE32.@]
2660 BOOL WINAPI OleIsRunning(LPOLEOBJECT object)
2662 IRunnableObject *pRunnable;
2663 HRESULT hr;
2664 BOOL running;
2666 TRACE("(%p)\n", object);
2668 if (!object) return FALSE;
2670 hr = IOleObject_QueryInterface(object, &IID_IRunnableObject, (void **)&pRunnable);
2671 if (FAILED(hr))
2672 return TRUE;
2673 running = IRunnableObject_IsRunning(pRunnable);
2674 IRunnableObject_Release(pRunnable);
2675 return running;
2678 /***********************************************************************
2679 * OleNoteObjectVisible [OLE32.@]
2681 HRESULT WINAPI OleNoteObjectVisible(LPUNKNOWN pUnknown, BOOL bVisible)
2683 TRACE("(%p, %s)\n", pUnknown, bVisible ? "TRUE" : "FALSE");
2684 return CoLockObjectExternal(pUnknown, bVisible, TRUE);
2687 /***********************************************************************
2688 * PropSysAllocString [OLE32.@]
2689 * NOTES
2690 * Forward to oleaut32.
2692 BSTR WINAPI PropSysAllocString(LPCOLESTR str)
2694 return SysAllocString(str);
2697 /***********************************************************************
2698 * PropSysFreeString [OLE32.@]
2699 * NOTES
2700 * Forward to oleaut32.
2702 void WINAPI PropSysFreeString(LPOLESTR str)
2704 SysFreeString(str);
2707 /******************************************************************************
2708 * OleQueryCreateFromData [OLE32.@]
2710 * Checks whether an object can become an embedded object.
2711 * the clipboard or OLE drag and drop.
2712 * Returns : S_OK - Format that supports Embedded object creation are present.
2713 * OLE_E_STATIC - Format that supports static object creation are present.
2714 * S_FALSE - No acceptable format is available.
2717 HRESULT WINAPI OleQueryCreateFromData(IDataObject *data)
2719 IEnumFORMATETC *enum_fmt;
2720 FORMATETC fmt;
2721 BOOL found_static = FALSE;
2722 HRESULT hr;
2724 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
2726 if(FAILED(hr)) return hr;
2730 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
2731 if(hr == S_OK)
2733 if(fmt.cfFormat == embedded_object_clipboard_format ||
2734 fmt.cfFormat == embed_source_clipboard_format ||
2735 fmt.cfFormat == filename_clipboard_format)
2737 IEnumFORMATETC_Release(enum_fmt);
2738 return S_OK;
2741 if(fmt.cfFormat == CF_METAFILEPICT ||
2742 fmt.cfFormat == CF_BITMAP ||
2743 fmt.cfFormat == CF_DIB)
2744 found_static = TRUE;
2746 } while (hr == S_OK);
2748 IEnumFORMATETC_Release(enum_fmt);
2750 return found_static ? OLE_S_STATIC : S_FALSE;
2753 static inline void init_fmtetc(FORMATETC *fmt, CLIPFORMAT cf, TYMED tymed)
2755 fmt->cfFormat = cf;
2756 fmt->ptd = NULL;
2757 fmt->dwAspect = DVASPECT_CONTENT;
2758 fmt->lindex = -1;
2759 fmt->tymed = tymed;
2762 /***************************************************************************
2763 * get_storage
2765 * Retrieve an object's storage from a variety of sources.
2767 * FIXME: CF_FILENAME.
2769 static HRESULT get_storage(IDataObject *data, IStorage *stg, UINT *src_cf, BOOL other_fmts)
2771 static const UINT fmt_id[] = { CF_METAFILEPICT, CF_BITMAP, CF_DIB };
2772 UINT i;
2773 HRESULT hr;
2774 FORMATETC fmt;
2775 STGMEDIUM med;
2776 IPersistStorage *persist;
2777 CLSID clsid;
2779 if (src_cf) *src_cf = 0;
2781 /* CF_EMBEDEDOBJECT */
2782 init_fmtetc(&fmt, embedded_object_clipboard_format, TYMED_ISTORAGE);
2783 med.tymed = TYMED_ISTORAGE;
2784 med.u.pstg = stg;
2785 med.pUnkForRelease = NULL;
2786 hr = IDataObject_GetDataHere(data, &fmt, &med);
2787 if(SUCCEEDED(hr))
2789 if (src_cf) *src_cf = embedded_object_clipboard_format;
2790 return hr;
2793 /* CF_EMBEDSOURCE */
2794 init_fmtetc(&fmt, embed_source_clipboard_format, TYMED_ISTORAGE);
2795 med.tymed = TYMED_ISTORAGE;
2796 med.u.pstg = stg;
2797 med.pUnkForRelease = NULL;
2798 hr = IDataObject_GetDataHere(data, &fmt, &med);
2799 if(SUCCEEDED(hr))
2801 if (src_cf) *src_cf = embed_source_clipboard_format;
2802 return hr;
2805 if (other_fmts)
2807 for (i = 0; i < ARRAY_SIZE(fmt_id); i++)
2809 init_fmtetc(&fmt, fmt_id[i], TYMED_ISTORAGE);
2810 hr = IDataObject_QueryGetData(data, &fmt);
2811 if (SUCCEEDED(hr))
2813 if (src_cf) *src_cf = fmt_id[i];
2814 return hr;
2819 /* IPersistStorage */
2820 hr = IDataObject_QueryInterface(data, &IID_IPersistStorage, (void**)&persist);
2821 if(FAILED(hr)) return hr;
2823 hr = IPersistStorage_GetClassID(persist, &clsid);
2824 if(FAILED(hr)) goto end;
2826 hr = IStorage_SetClass(stg, &clsid);
2827 if(FAILED(hr)) goto end;
2829 hr = IPersistStorage_Save(persist, stg, FALSE);
2830 if(FAILED(hr)) goto end;
2832 hr = IPersistStorage_SaveCompleted(persist, NULL);
2834 end:
2835 IPersistStorage_Release(persist);
2837 return hr;
2840 /******************************************************************************
2841 * OleCreateFromDataEx [OLE32.@]
2843 * Creates an embedded object from data transfer object retrieved from
2844 * the clipboard or OLE drag and drop.
2846 HRESULT WINAPI OleCreateFromDataEx(IDataObject *data, REFIID iid, DWORD flags,
2847 DWORD renderopt, ULONG num_cache_fmts, DWORD *adv_flags, FORMATETC *cache_fmts,
2848 IAdviseSink *sink, DWORD *conns,
2849 IOleClientSite *client_site, IStorage *stg, void **obj)
2851 HRESULT hr;
2852 UINT src_cf;
2854 FIXME("(%p, %s, %08x, %08x, %d, %p, %p, %p, %p, %p, %p, %p): stub\n",
2855 data, debugstr_guid(iid), flags, renderopt, num_cache_fmts, adv_flags, cache_fmts,
2856 sink, conns, client_site, stg, obj);
2858 hr = get_storage(data, stg, &src_cf, TRUE);
2859 if(FAILED(hr)) return hr;
2861 hr = OleLoad(stg, iid, client_site, obj);
2862 if(FAILED(hr)) return hr;
2864 /* FIXME: Init cache */
2866 return hr;
2869 /******************************************************************************
2870 * OleCreateFromData [OLE32.@]
2872 HRESULT WINAPI OleCreateFromData(IDataObject *data, REFIID iid, DWORD renderopt, FORMATETC *fmt,
2873 IOleClientSite *client_site, IStorage *stg, void **obj)
2875 DWORD advf = ADVF_PRIMEFIRST;
2877 return OleCreateFromDataEx(data, iid, 0, renderopt, fmt ? 1 : 0, fmt ? &advf : NULL,
2878 fmt, NULL, NULL, client_site, stg, obj);
2881 /******************************************************************************
2882 * OleCreateLinkFromData [OLE32.@]
2884 HRESULT WINAPI OleCreateLinkFromData(IDataObject *data, REFIID iid, DWORD renderopt, FORMATETC *fmt,
2885 IOleClientSite *client_site, IStorage *stg, void **obj)
2887 FIXME("%p,%s,%08x,%p,%p,%p,%p: semi-stub\n",
2888 data, debugstr_guid(iid), renderopt, fmt, client_site, stg, obj);
2889 return OleCreateFromData(data, iid, renderopt, fmt, client_site, stg, obj);
2892 /******************************************************************************
2893 * OleCreateStaticFromData [OLE32.@]
2895 HRESULT WINAPI OleCreateStaticFromData(IDataObject *data, REFIID iid, DWORD renderopt, FORMATETC *fmt,
2896 IOleClientSite *client_site, IStorage *stg, void **obj)
2898 HRESULT hr;
2899 CLSID clsid;
2900 IOleObject * ole_object = NULL;
2901 IOleCache2 *ole_cache = NULL;
2902 IPersistStorage *persist = NULL;
2903 DWORD connection;
2904 STGMEDIUM stgmedium;
2905 LPOLESTR ole_typename;
2907 TRACE("(%p, %s, 0x%08x, %p, %p, %p, %p)\n",
2908 data, debugstr_guid(iid), renderopt, fmt, client_site, stg, obj);
2910 if (!obj || !stg)
2911 return E_INVALIDARG;
2913 if (renderopt != OLERENDER_FORMAT)
2915 FIXME("semi-stub\n");
2916 return OleCreateFromData(data, iid, renderopt, fmt, client_site, stg, obj);
2919 if (!fmt)
2920 return E_INVALIDARG;
2922 hr = IDataObject_GetData(data, fmt, &stgmedium);
2923 if (FAILED(hr)) return hr;
2925 switch (fmt->cfFormat)
2927 case CF_BITMAP:
2928 case CF_DIB:
2929 clsid = CLSID_Picture_Dib;
2930 break;
2931 case CF_ENHMETAFILE:
2932 clsid = CLSID_Picture_EnhMetafile;
2933 break;
2934 case CF_METAFILEPICT:
2935 clsid = CLSID_Picture_Metafile;
2936 break;
2937 default:
2938 ReleaseStgMedium(&stgmedium);
2939 return DV_E_CLIPFORMAT;
2941 hr = OleCreateDefaultHandler(&clsid, NULL, &IID_IOleObject, (void **)&ole_object);
2942 if (FAILED(hr)) goto end;
2944 if (client_site)
2946 hr = IOleObject_SetClientSite(ole_object, client_site);
2947 if (FAILED(hr)) goto end;
2950 hr = IOleObject_QueryInterface(ole_object, &IID_IOleCache2, (void **)&ole_cache);
2951 if (FAILED(hr)) goto end;
2953 hr = IOleObject_QueryInterface(ole_object, &IID_IPersistStorage, (void **)&persist);
2954 if (FAILED(hr)) goto end;
2956 hr = WriteClassStg(stg, &clsid);
2957 if (FAILED(hr)) goto end;
2959 hr = IPersistStorage_InitNew(persist, stg);
2960 if (FAILED(hr)) goto end;
2962 hr = IOleCache2_Cache(ole_cache, fmt, ADVF_PRIMEFIRST, &connection);
2963 if (FAILED(hr)) goto end;
2965 hr = IOleCache2_SetData(ole_cache, fmt, &stgmedium, TRUE);
2966 if (FAILED(hr)) goto end;
2967 stgmedium.tymed = TYMED_NULL;
2969 hr = IOleObject_GetUserType(ole_object, USERCLASSTYPE_FULL, &ole_typename);
2970 if(FAILED(hr))
2971 ole_typename = NULL;
2972 hr = WriteFmtUserTypeStg(stg, fmt->cfFormat, ole_typename);
2973 CoTaskMemFree(ole_typename);
2974 if (FAILED(hr)) goto end;
2976 hr = IPersistStorage_Save(persist, stg, TRUE);
2977 if (FAILED(hr)) goto end;
2979 hr = IPersistStorage_SaveCompleted(persist, NULL);
2980 if (FAILED(hr)) goto end;
2982 hr = IOleObject_QueryInterface(ole_object, iid, obj);
2984 end:
2985 if (stgmedium.tymed == TYMED_NULL)
2986 ReleaseStgMedium(&stgmedium);
2987 if (persist)
2988 IPersistStorage_Release(persist);
2989 if (ole_cache)
2990 IOleCache2_Release(ole_cache);
2991 if (ole_object)
2992 IOleObject_Release(ole_object);
2993 return hr;
2996 /******************************************************************************
2997 * OleCreateFromFileEx [OLE32.@]
2999 HRESULT WINAPI OleCreateFromFileEx(REFCLSID clsid, const OLECHAR *filename, REFIID iid, DWORD flags,
3000 DWORD renderopt, ULONG num_fmts, DWORD *adv_flags, FORMATETC *fmts, IAdviseSink *sink,
3001 DWORD *conns, IOleClientSite *client_site, IStorage *stg, void **obj)
3003 HRESULT hr;
3004 IMoniker *mon;
3005 IDataObject *data;
3006 IUnknown *unk = NULL;
3007 IOleCache *cache = NULL;
3008 ULONG i;
3010 TRACE("cls %s, %s, iid %s, flags %d, render opts %d, num fmts %d, adv flags %p, fmts %p\n", debugstr_guid(clsid),
3011 debugstr_w(filename), debugstr_guid(iid), flags, renderopt, num_fmts, adv_flags, fmts);
3012 TRACE("sink %p, conns %p, client site %p, storage %p, obj %p\n", sink, conns, client_site, stg, obj);
3013 for (i = 0; i < num_fmts; i++)
3014 TRACE("\t%d: fmt %s adv flags %d\n", i, debugstr_formatetc(fmts + i), adv_flags[i]);
3016 hr = CreateFileMoniker( filename, &mon );
3017 if (FAILED(hr)) return hr;
3019 hr = BindMoniker( mon, 0, &IID_IDataObject, (void**)&data );
3020 IMoniker_Release( mon );
3021 if (FAILED(hr)) return hr;
3023 hr = get_storage( data, stg, NULL, FALSE );
3024 if (FAILED(hr)) goto end;
3026 hr = OleLoad( stg, &IID_IUnknown, client_site, (void**)&unk );
3027 if (FAILED(hr)) goto end;
3029 if (renderopt == OLERENDER_FORMAT)
3031 hr = IUnknown_QueryInterface( unk, &IID_IOleCache, (void**)&cache );
3032 if (FAILED(hr)) goto end;
3034 for (i = 0; i < num_fmts; i++)
3036 STGMEDIUM med;
3037 DWORD dummy_conn;
3039 memset( &med, 0, sizeof(med) );
3040 hr = IDataObject_GetData( data, fmts + i, &med );
3041 if (FAILED(hr)) goto end;
3042 hr = IOleCache_Cache( cache, fmts + i, adv_flags[i], &dummy_conn );
3043 if (SUCCEEDED(hr))
3044 hr = IOleCache_SetData( cache, fmts + i, &med, TRUE );
3045 if (FAILED(hr))
3047 ReleaseStgMedium( &med );
3048 goto end;
3053 hr = IUnknown_QueryInterface( unk, iid, obj );
3055 end:
3056 if (cache) IOleCache_Release( cache );
3057 if (unk) IUnknown_Release( unk );
3058 IDataObject_Release( data );
3059 return hr;
3062 /******************************************************************************
3063 * OleCreateFromFile [OLE32.@]
3065 HRESULT WINAPI OleCreateFromFile(REFCLSID clsid, const OLECHAR *filename, REFIID iid, DWORD renderopt,
3066 FORMATETC *fmt, IOleClientSite *client_site, IStorage *storage, void **obj)
3068 DWORD advf = ADVF_PRIMEFIRST;
3070 return OleCreateFromFileEx(clsid, filename, iid, 0, renderopt, fmt ? 1 : 0, fmt ? &advf : NULL, fmt,
3071 NULL, NULL, client_site, storage, obj);
3074 /******************************************************************************
3075 * OleDuplicateData [OLE32.@]
3077 HANDLE WINAPI OleDuplicateData(HANDLE hSrc, CLIPFORMAT cfFormat, UINT uiFlags)
3079 HANDLE hDst = NULL;
3081 TRACE("(%p,%x,%x)\n", hSrc, cfFormat, uiFlags);
3083 if (!uiFlags) uiFlags = GMEM_MOVEABLE;
3085 switch (cfFormat)
3087 case CF_ENHMETAFILE:
3088 hDst = CopyEnhMetaFileW(hSrc, NULL);
3089 break;
3090 case CF_METAFILEPICT:
3091 hDst = CopyMetaFileW(hSrc, NULL);
3092 break;
3093 case CF_PALETTE:
3095 LOGPALETTE * logpalette;
3096 UINT nEntries = GetPaletteEntries(hSrc, 0, 0, NULL);
3097 if (!nEntries) return NULL;
3098 logpalette = HeapAlloc(GetProcessHeap(), 0,
3099 FIELD_OFFSET(LOGPALETTE, palPalEntry[nEntries]));
3100 if (!logpalette) return NULL;
3101 if (!GetPaletteEntries(hSrc, 0, nEntries, logpalette->palPalEntry))
3103 HeapFree(GetProcessHeap(), 0, logpalette);
3104 return NULL;
3106 logpalette->palVersion = 0x300;
3107 logpalette->palNumEntries = (WORD)nEntries;
3109 hDst = CreatePalette(logpalette);
3111 HeapFree(GetProcessHeap(), 0, logpalette);
3112 break;
3114 case CF_BITMAP:
3116 LONG size;
3117 BITMAP bm;
3118 if (!GetObjectW(hSrc, sizeof(bm), &bm))
3119 return NULL;
3120 size = GetBitmapBits(hSrc, 0, NULL);
3121 if (!size) return NULL;
3122 bm.bmBits = HeapAlloc(GetProcessHeap(), 0, size);
3123 if (!bm.bmBits) return NULL;
3124 if (GetBitmapBits(hSrc, size, bm.bmBits))
3125 hDst = CreateBitmapIndirect(&bm);
3126 HeapFree(GetProcessHeap(), 0, bm.bmBits);
3127 break;
3129 default:
3131 SIZE_T size = GlobalSize(hSrc);
3132 LPVOID pvSrc = NULL;
3133 LPVOID pvDst = NULL;
3135 /* allocate space for object */
3136 if (!size) return NULL;
3137 hDst = GlobalAlloc(uiFlags, size);
3138 if (!hDst) return NULL;
3140 /* lock pointers */
3141 pvSrc = GlobalLock(hSrc);
3142 if (!pvSrc)
3144 GlobalFree(hDst);
3145 return NULL;
3147 pvDst = GlobalLock(hDst);
3148 if (!pvDst)
3150 GlobalUnlock(hSrc);
3151 GlobalFree(hDst);
3152 return NULL;
3154 /* copy data */
3155 memcpy(pvDst, pvSrc, size);
3157 /* cleanup */
3158 GlobalUnlock(hDst);
3159 GlobalUnlock(hSrc);
3163 TRACE("returning %p\n", hDst);
3164 return hDst;