kernel32/tests/pipe: Enable compilation with long types.
[wine.git] / dlls / ole32 / ole2.c
blobee6a0b69b069ab5817dd2ec6de5f5689ed08b1c8
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)
258 FIXME("%#lx, %#lx stub!\n", x, y);
259 return 0;
262 /*************************************************************
263 * get_droptarget_handle
265 * Retrieve a handle to the map containing the marshalled IDropTarget.
266 * This handle belongs to the process that called RegisterDragDrop.
267 * See get_droptarget_local_handle().
269 static inline HANDLE get_droptarget_handle(HWND hwnd)
271 return GetPropW(hwnd, prop_marshalleddroptarget);
274 /*************************************************************
275 * is_droptarget
277 * Is the window a droptarget.
279 static inline BOOL is_droptarget(HWND hwnd)
281 return get_droptarget_handle(hwnd) != 0;
284 /*************************************************************
285 * get_droptarget_local_handle
287 * Retrieve a handle to the map containing the marshalled IDropTarget.
288 * The handle should be closed when finished with.
290 static HANDLE get_droptarget_local_handle(HWND hwnd)
292 HANDLE handle, local_handle = 0;
294 handle = get_droptarget_handle(hwnd);
296 if(handle)
298 DWORD pid;
299 HANDLE process;
301 GetWindowThreadProcessId(hwnd, &pid);
302 process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid);
303 if(process)
305 DuplicateHandle(process, handle, GetCurrentProcess(), &local_handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
306 CloseHandle(process);
309 return local_handle;
312 /***********************************************************************
313 * create_map_from_stream
315 * Helper for RegisterDragDrop. Creates a file mapping object
316 * with the contents of the provided stream. The stream must
317 * be a global memory backed stream.
319 static HRESULT create_map_from_stream(IStream *stream, HANDLE *map)
321 HGLOBAL hmem;
322 DWORD size;
323 HRESULT hr;
324 void *data;
326 hr = GetHGlobalFromStream(stream, &hmem);
327 if(FAILED(hr)) return hr;
329 size = GlobalSize(hmem);
330 *map = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, NULL);
331 if(!*map) return E_OUTOFMEMORY;
333 data = MapViewOfFile(*map, FILE_MAP_WRITE, 0, 0, size);
334 memcpy(data, GlobalLock(hmem), size);
335 GlobalUnlock(hmem);
336 UnmapViewOfFile(data);
337 return S_OK;
340 /***********************************************************************
341 * create_stream_from_map
343 * Creates a stream from the provided map.
345 static HRESULT create_stream_from_map(HANDLE map, IStream **stream)
347 HRESULT hr = E_OUTOFMEMORY;
348 HGLOBAL hmem;
349 void *data;
350 MEMORY_BASIC_INFORMATION info;
352 data = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
353 if(!data) return hr;
355 VirtualQuery(data, &info, sizeof(info));
356 TRACE("size %d\n", (int)info.RegionSize);
358 hmem = GlobalAlloc(GMEM_MOVEABLE, info.RegionSize);
359 if(hmem)
361 memcpy(GlobalLock(hmem), data, info.RegionSize);
362 GlobalUnlock(hmem);
363 hr = CreateStreamOnHGlobal(hmem, TRUE, stream);
365 UnmapViewOfFile(data);
366 return hr;
369 /* This is to work around apps which break COM rules by not implementing
370 * IDropTarget::QueryInterface(). Windows doesn't expose this because it
371 * doesn't call CoMarshallInterface() in RegisterDragDrop().
372 * The wrapper is only used internally, and only exists for the life of
373 * the marshal. We don't want to hold a ref on the app provided target
374 * as some apps destroy this prior to CoUninitialize without calling
375 * RevokeDragDrop. The only (long-term) ref is held by the window prop. */
376 typedef struct {
377 IDropTarget IDropTarget_iface;
378 HWND hwnd;
379 LONG refs;
380 } DropTargetWrapper;
382 static inline DropTargetWrapper* impl_from_IDropTarget(IDropTarget* iface)
384 return CONTAINING_RECORD(iface, DropTargetWrapper, IDropTarget_iface);
387 static HRESULT WINAPI DropTargetWrapper_QueryInterface(IDropTarget* iface,
388 REFIID riid,
389 void** ppvObject)
391 DropTargetWrapper* This = impl_from_IDropTarget(iface);
392 if (IsEqualIID(riid, &IID_IUnknown) ||
393 IsEqualIID(riid, &IID_IDropTarget))
395 IDropTarget_AddRef(&This->IDropTarget_iface);
396 *ppvObject = &This->IDropTarget_iface;
397 return S_OK;
399 *ppvObject = NULL;
400 return E_NOINTERFACE;
403 static ULONG WINAPI DropTargetWrapper_AddRef(IDropTarget* iface)
405 DropTargetWrapper* This = impl_from_IDropTarget(iface);
406 return InterlockedIncrement(&This->refs);
409 static ULONG WINAPI DropTargetWrapper_Release(IDropTarget* iface)
411 DropTargetWrapper* This = impl_from_IDropTarget(iface);
412 ULONG refs = InterlockedDecrement(&This->refs);
413 if (!refs) HeapFree(GetProcessHeap(), 0, This);
414 return refs;
417 static inline HRESULT get_target_from_wrapper( IDropTarget *wrapper, IDropTarget **target )
419 DropTargetWrapper* This = impl_from_IDropTarget( wrapper );
420 *target = GetPropW( This->hwnd, prop_oledroptarget );
421 if (!*target) return DRAGDROP_E_NOTREGISTERED;
422 IDropTarget_AddRef( *target );
423 return S_OK;
426 static HRESULT WINAPI DropTargetWrapper_DragEnter(IDropTarget* iface,
427 IDataObject* pDataObj,
428 DWORD grfKeyState,
429 POINTL pt,
430 DWORD* pdwEffect)
432 IDropTarget *target;
433 HRESULT r = get_target_from_wrapper( iface, &target );
435 if (SUCCEEDED( r ))
437 r = IDropTarget_DragEnter( target, pDataObj, grfKeyState, pt, pdwEffect );
438 IDropTarget_Release( target );
440 return r;
443 static HRESULT WINAPI DropTargetWrapper_DragOver(IDropTarget* iface,
444 DWORD grfKeyState,
445 POINTL pt,
446 DWORD* pdwEffect)
448 IDropTarget *target;
449 HRESULT r = get_target_from_wrapper( iface, &target );
451 if (SUCCEEDED( r ))
453 r = IDropTarget_DragOver( target, grfKeyState, pt, pdwEffect );
454 IDropTarget_Release( target );
456 return r;
459 static HRESULT WINAPI DropTargetWrapper_DragLeave(IDropTarget* iface)
461 IDropTarget *target;
462 HRESULT r = get_target_from_wrapper( iface, &target );
464 if (SUCCEEDED( r ))
466 r = IDropTarget_DragLeave( target );
467 IDropTarget_Release( target );
469 return r;
472 static HRESULT WINAPI DropTargetWrapper_Drop(IDropTarget* iface,
473 IDataObject* pDataObj,
474 DWORD grfKeyState,
475 POINTL pt,
476 DWORD* pdwEffect)
478 IDropTarget *target;
479 HRESULT r = get_target_from_wrapper( iface, &target );
481 if (SUCCEEDED( r ))
483 r = IDropTarget_Drop( target, pDataObj, grfKeyState, pt, pdwEffect );
484 IDropTarget_Release( target );
486 return r;
489 static const IDropTargetVtbl DropTargetWrapperVTbl =
491 DropTargetWrapper_QueryInterface,
492 DropTargetWrapper_AddRef,
493 DropTargetWrapper_Release,
494 DropTargetWrapper_DragEnter,
495 DropTargetWrapper_DragOver,
496 DropTargetWrapper_DragLeave,
497 DropTargetWrapper_Drop
500 static IDropTarget* WrapDropTarget( HWND hwnd )
502 DropTargetWrapper* This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
504 if (This)
506 This->IDropTarget_iface.lpVtbl = &DropTargetWrapperVTbl;
507 This->hwnd = hwnd;
508 This->refs = 1;
510 return &This->IDropTarget_iface;
513 /***********************************************************************
514 * get_droptarget_pointer
516 * Retrieves the marshalled IDropTarget from the window.
518 static IDropTarget* get_droptarget_pointer(HWND hwnd)
520 IDropTarget *droptarget = NULL;
521 HANDLE map;
522 IStream *stream;
524 map = get_droptarget_local_handle(hwnd);
525 if(!map) return NULL;
527 if(SUCCEEDED(create_stream_from_map(map, &stream)))
529 CoUnmarshalInterface(stream, &IID_IDropTarget, (void**)&droptarget);
530 IStream_Release(stream);
532 CloseHandle(map);
533 return droptarget;
536 /***********************************************************************
537 * RegisterDragDrop (OLE32.@)
539 HRESULT WINAPI RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget)
541 DWORD pid = 0;
542 HRESULT hr;
543 IStream *stream;
544 HANDLE map;
545 IDropTarget *wrapper;
547 TRACE("(%p,%p)\n", hwnd, pDropTarget);
549 if (!COM_CurrentApt())
551 ERR("COM not initialized\n");
552 return E_OUTOFMEMORY;
555 if (!pDropTarget)
556 return E_INVALIDARG;
558 if (!IsWindow(hwnd))
560 ERR("invalid hwnd %p\n", hwnd);
561 return DRAGDROP_E_INVALIDHWND;
564 /* block register for other processes windows */
565 GetWindowThreadProcessId(hwnd, &pid);
566 if (pid != GetCurrentProcessId())
568 FIXME("register for another process windows is disabled\n");
569 return DRAGDROP_E_INVALIDHWND;
572 /* check if the window is already registered */
573 if (is_droptarget(hwnd))
574 return DRAGDROP_E_ALREADYREGISTERED;
577 * Marshal the drop target pointer into a shared memory map and
578 * store the map's handle in a Wine specific window prop. We also
579 * store the drop target pointer itself in the
580 * "OleDropTargetInterface" prop for compatibility with Windows.
583 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
584 if(FAILED(hr)) return hr;
586 /* IDropTarget::QueryInterface() shouldn't be called, some (broken) apps depend on this. */
587 wrapper = WrapDropTarget( hwnd );
588 if(!wrapper)
590 IStream_Release(stream);
591 return E_OUTOFMEMORY;
593 hr = CoMarshalInterface(stream, &IID_IDropTarget, (IUnknown*)wrapper, MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
594 IDropTarget_Release(wrapper);
596 if(SUCCEEDED(hr))
598 hr = create_map_from_stream(stream, &map);
599 if(SUCCEEDED(hr))
601 IDropTarget_AddRef(pDropTarget);
602 SetPropW(hwnd, prop_oledroptarget, pDropTarget);
603 SetPropW(hwnd, prop_marshalleddroptarget, map);
605 else
607 LARGE_INTEGER zero;
608 zero.QuadPart = 0;
609 IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
610 CoReleaseMarshalData(stream);
613 IStream_Release(stream);
615 return hr;
618 /***********************************************************************
619 * RevokeDragDrop (OLE32.@)
621 HRESULT WINAPI RevokeDragDrop(HWND hwnd)
623 HANDLE map;
624 IStream *stream;
625 IDropTarget *drop_target;
626 HRESULT hr;
628 TRACE("(%p)\n", hwnd);
630 if (!IsWindow(hwnd))
632 ERR("invalid hwnd %p\n", hwnd);
633 return DRAGDROP_E_INVALIDHWND;
636 /* no registration data */
637 if (!(map = get_droptarget_handle(hwnd)))
638 return DRAGDROP_E_NOTREGISTERED;
640 drop_target = GetPropW(hwnd, prop_oledroptarget);
641 if(drop_target) IDropTarget_Release(drop_target);
643 RemovePropW(hwnd, prop_oledroptarget);
644 RemovePropW(hwnd, prop_marshalleddroptarget);
646 hr = create_stream_from_map(map, &stream);
647 if(SUCCEEDED(hr))
649 CoReleaseMarshalData(stream);
650 IStream_Release(stream);
652 CloseHandle(map);
654 return hr;
657 /***********************************************************************
658 * OleRegGetUserType (OLE32.@)
660 HRESULT WINAPI OleRegGetUserType(REFCLSID clsid, DWORD form, LPOLESTR *usertype)
662 DWORD valuetype, valuelen;
663 WCHAR auxkeynameW[16];
664 HKEY usertypekey;
665 HRESULT hres;
666 LONG ret;
668 TRACE("%s, %lu, %p.\n", debugstr_guid(clsid), form, usertype);
670 if (!usertype)
671 return E_INVALIDARG;
673 *usertype = NULL;
675 /* Return immediately if it's not registered. */
676 hres = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &usertypekey);
677 if (FAILED(hres))
678 return hres;
680 valuelen = 0;
682 /* Try additional types if requested. If they don't exist fall back to USERCLASSTYPE_FULL. */
683 if (form != USERCLASSTYPE_FULL)
685 HKEY auxkey;
687 swprintf(auxkeynameW, ARRAY_SIZE(auxkeynameW), L"AuxUserType\\%d", form);
688 if (COM_OpenKeyForCLSID(clsid, auxkeynameW, KEY_READ, &auxkey) == S_OK)
690 if (!RegQueryValueExW(auxkey, L"", NULL, &valuetype, NULL, &valuelen) && valuelen)
692 RegCloseKey(usertypekey);
693 usertypekey = auxkey;
695 else
696 RegCloseKey(auxkey);
700 valuelen = 0;
701 if (RegQueryValueExW(usertypekey, L"", NULL, &valuetype, NULL, &valuelen))
703 RegCloseKey(usertypekey);
704 return REGDB_E_READREGDB;
707 *usertype = CoTaskMemAlloc(valuelen);
708 if (!*usertype)
710 RegCloseKey(usertypekey);
711 return E_OUTOFMEMORY;
714 ret = RegQueryValueExW(usertypekey, L"", NULL, &valuetype, (BYTE *)*usertype, &valuelen);
715 RegCloseKey(usertypekey);
716 if (ret != ERROR_SUCCESS)
718 CoTaskMemFree(*usertype);
719 *usertype = NULL;
720 return REGDB_E_READREGDB;
723 return S_OK;
726 /***********************************************************************
727 * DoDragDrop [OLE32.@]
729 HRESULT WINAPI DoDragDrop (
730 IDataObject *pDataObject, /* [in] ptr to the data obj */
731 IDropSource* pDropSource, /* [in] ptr to the source obj */
732 DWORD dwOKEffect, /* [in] effects allowed by the source */
733 DWORD *pdwEffect) /* [out] ptr to effects of the source */
735 TrackerWindowInfo trackerInfo;
736 HWND hwndTrackWindow;
737 MSG msg;
739 TRACE("%p, %p, %#lx, %p.\n", pDataObject, pDropSource, dwOKEffect, pdwEffect);
741 if (!pDataObject || !pDropSource || !pdwEffect)
742 return E_INVALIDARG;
745 * Setup the drag n drop tracking window.
748 trackerInfo.dataObject = pDataObject;
749 trackerInfo.dropSource = pDropSource;
750 trackerInfo.dwOKEffect = dwOKEffect;
751 trackerInfo.pdwEffect = pdwEffect;
752 trackerInfo.trackingDone = FALSE;
753 trackerInfo.inTrackCall = FALSE;
754 trackerInfo.escPressed = FALSE;
755 trackerInfo.curTargetHWND = 0;
756 trackerInfo.curDragTarget = 0;
758 hwndTrackWindow = CreateWindowW(OLEDD_DRAGTRACKERCLASS, L"TrackerWindow",
759 WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
760 CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0,
761 &trackerInfo);
763 if (hwndTrackWindow)
766 * Capture the mouse input
768 SetCapture(hwndTrackWindow);
770 msg.message = 0;
773 * Pump messages. All mouse input should go to the capture window.
775 while (!trackerInfo.trackingDone && GetMessageW(&msg, 0, 0, 0) )
777 trackerInfo.curMousePos.x = msg.pt.x;
778 trackerInfo.curMousePos.y = msg.pt.y;
779 trackerInfo.dwKeyState = OLEDD_GetButtonState();
781 if ( (msg.message >= WM_KEYFIRST) &&
782 (msg.message <= WM_KEYLAST) )
785 * When keyboard messages are sent to windows on this thread, we
786 * want to ignore notify the drop source that the state changed.
787 * in the case of the Escape key, we also notify the drop source
788 * we give it a special meaning.
790 if ( (msg.message==WM_KEYDOWN) &&
791 (msg.wParam==VK_ESCAPE) )
793 trackerInfo.escPressed = TRUE;
797 * Notify the drop source.
799 OLEDD_TrackStateChange(&trackerInfo);
801 else
804 * Dispatch the messages only when it's not a keyboard message.
806 DispatchMessageW(&msg);
810 /* re-post the quit message to outer message loop */
811 if (msg.message == WM_QUIT)
812 PostQuitMessage(msg.wParam);
814 * Destroy the temporary window.
816 DestroyWindow(hwndTrackWindow);
818 return trackerInfo.returnValue;
821 return E_FAIL;
824 /***********************************************************************
825 * OleQueryLinkFromData [OLE32.@]
827 HRESULT WINAPI OleQueryLinkFromData(
828 IDataObject* pSrcDataObject)
830 FIXME("(%p),stub!\n", pSrcDataObject);
831 return S_FALSE;
834 /***********************************************************************
835 * OleRegGetMiscStatus [OLE32.@]
837 HRESULT WINAPI OleRegGetMiscStatus(
838 REFCLSID clsid,
839 DWORD dwAspect,
840 DWORD* pdwStatus)
842 WCHAR keyName[16];
843 HKEY miscStatusKey;
844 HKEY aspectKey;
845 LONG result;
846 HRESULT hr;
848 TRACE("%s, %ld, %p.\n", debugstr_guid(clsid), dwAspect, pdwStatus);
850 if (!pdwStatus) return E_INVALIDARG;
852 *pdwStatus = 0;
854 if (actctx_get_miscstatus(clsid, dwAspect, pdwStatus)) return S_OK;
856 hr = COM_OpenKeyForCLSID(clsid, L"MiscStatus", KEY_READ, &miscStatusKey);
857 if (FAILED(hr))
858 /* missing key is not a failure */
859 return hr == REGDB_E_KEYMISSING ? S_OK : hr;
861 OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
864 * Open the key specific to the requested aspect.
866 swprintf(keyName, ARRAY_SIZE(keyName), L"%d", dwAspect);
868 result = open_classes_key(miscStatusKey, keyName, KEY_READ, &aspectKey);
869 if (result == ERROR_SUCCESS)
871 OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
872 RegCloseKey(aspectKey);
875 RegCloseKey(miscStatusKey);
876 return S_OK;
879 static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum);
881 typedef struct
883 IEnumOLEVERB IEnumOLEVERB_iface;
884 LONG ref;
886 HKEY hkeyVerb;
887 ULONG index;
888 } EnumOLEVERB;
890 static inline EnumOLEVERB *impl_from_IEnumOLEVERB(IEnumOLEVERB *iface)
892 return CONTAINING_RECORD(iface, EnumOLEVERB, IEnumOLEVERB_iface);
895 static HRESULT WINAPI EnumOLEVERB_QueryInterface(
896 IEnumOLEVERB *iface, REFIID riid, void **ppv)
898 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
899 if (IsEqualIID(riid, &IID_IUnknown) ||
900 IsEqualIID(riid, &IID_IEnumOLEVERB))
902 IEnumOLEVERB_AddRef(iface);
903 *ppv = iface;
904 return S_OK;
906 return E_NOINTERFACE;
909 static ULONG WINAPI EnumOLEVERB_AddRef(
910 IEnumOLEVERB *iface)
912 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
913 TRACE("()\n");
914 return InterlockedIncrement(&This->ref);
917 static ULONG WINAPI EnumOLEVERB_Release(
918 IEnumOLEVERB *iface)
920 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
921 LONG refs = InterlockedDecrement(&This->ref);
922 TRACE("()\n");
923 if (!refs)
925 RegCloseKey(This->hkeyVerb);
926 HeapFree(GetProcessHeap(), 0, This);
928 return refs;
931 static HRESULT WINAPI EnumOLEVERB_Next(
932 IEnumOLEVERB *iface, ULONG celt, LPOLEVERB rgelt,
933 ULONG *pceltFetched)
935 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
936 HRESULT hr = S_OK;
938 TRACE("%p, %lu, %p, %p.\n", iface, celt, rgelt, pceltFetched);
940 if (pceltFetched)
941 *pceltFetched = 0;
943 for (; celt; celt--, rgelt++)
945 WCHAR wszSubKey[20];
946 LONG cbData;
947 LPWSTR pwszOLEVERB;
948 LPWSTR pwszMenuFlags;
949 LPWSTR pwszAttribs;
950 LONG res = RegEnumKeyW(This->hkeyVerb, This->index, wszSubKey, ARRAY_SIZE(wszSubKey));
951 if (res == ERROR_NO_MORE_ITEMS)
953 hr = S_FALSE;
954 break;
956 else if (res != ERROR_SUCCESS)
958 ERR("RegEnumKeyW failed with error %ld\n", res);
959 hr = REGDB_E_READREGDB;
960 break;
962 res = RegQueryValueW(This->hkeyVerb, wszSubKey, NULL, &cbData);
963 if (res != ERROR_SUCCESS)
965 ERR("RegQueryValueW failed with error %ld\n", res);
966 hr = REGDB_E_READREGDB;
967 break;
969 pwszOLEVERB = CoTaskMemAlloc(cbData);
970 if (!pwszOLEVERB)
972 hr = E_OUTOFMEMORY;
973 break;
975 res = RegQueryValueW(This->hkeyVerb, wszSubKey, pwszOLEVERB, &cbData);
976 if (res != ERROR_SUCCESS)
978 ERR("RegQueryValueW failed with error %ld\n", res);
979 hr = REGDB_E_READREGDB;
980 CoTaskMemFree(pwszOLEVERB);
981 break;
984 TRACE("verb string: %s\n", debugstr_w(pwszOLEVERB));
985 pwszMenuFlags = wcschr(pwszOLEVERB, ',');
986 if (!pwszMenuFlags)
988 hr = OLEOBJ_E_INVALIDVERB;
989 CoTaskMemFree(pwszOLEVERB);
990 break;
992 /* nul terminate the name string and advance to first character */
993 *pwszMenuFlags = '\0';
994 pwszMenuFlags++;
995 pwszAttribs = wcschr(pwszMenuFlags, ',');
996 if (!pwszAttribs)
998 hr = OLEOBJ_E_INVALIDVERB;
999 CoTaskMemFree(pwszOLEVERB);
1000 break;
1002 /* nul terminate the menu string and advance to first character */
1003 *pwszAttribs = '\0';
1004 pwszAttribs++;
1006 /* fill out structure for this verb */
1007 rgelt->lVerb = wcstol(wszSubKey, NULL, 10);
1008 rgelt->lpszVerbName = pwszOLEVERB; /* user should free */
1009 rgelt->fuFlags = wcstol(pwszMenuFlags, NULL, 10);
1010 rgelt->grfAttribs = wcstol(pwszAttribs, NULL, 10);
1012 if (pceltFetched)
1013 (*pceltFetched)++;
1014 This->index++;
1016 return hr;
1019 static HRESULT WINAPI EnumOLEVERB_Skip(
1020 IEnumOLEVERB *iface, ULONG celt)
1022 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
1024 TRACE("%p, %lu.\n", iface, celt);
1026 This->index += celt;
1027 return S_OK;
1030 static HRESULT WINAPI EnumOLEVERB_Reset(
1031 IEnumOLEVERB *iface)
1033 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
1035 TRACE("()\n");
1037 This->index = 0;
1038 return S_OK;
1041 static HRESULT WINAPI EnumOLEVERB_Clone(
1042 IEnumOLEVERB *iface,
1043 IEnumOLEVERB **ppenum)
1045 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
1046 HKEY hkeyVerb;
1047 TRACE("(%p)\n", ppenum);
1048 if (!DuplicateHandle(GetCurrentProcess(), This->hkeyVerb, GetCurrentProcess(), (HANDLE *)&hkeyVerb, 0, FALSE, DUPLICATE_SAME_ACCESS))
1049 return HRESULT_FROM_WIN32(GetLastError());
1050 return EnumOLEVERB_Construct(hkeyVerb, This->index, ppenum);
1053 static const IEnumOLEVERBVtbl EnumOLEVERB_VTable =
1055 EnumOLEVERB_QueryInterface,
1056 EnumOLEVERB_AddRef,
1057 EnumOLEVERB_Release,
1058 EnumOLEVERB_Next,
1059 EnumOLEVERB_Skip,
1060 EnumOLEVERB_Reset,
1061 EnumOLEVERB_Clone
1064 static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum)
1066 EnumOLEVERB *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1067 if (!This)
1069 RegCloseKey(hkeyVerb);
1070 return E_OUTOFMEMORY;
1072 This->IEnumOLEVERB_iface.lpVtbl = &EnumOLEVERB_VTable;
1073 This->ref = 1;
1074 This->index = index;
1075 This->hkeyVerb = hkeyVerb;
1076 *ppenum = &This->IEnumOLEVERB_iface;
1077 return S_OK;
1080 /***********************************************************************
1081 * OleRegEnumVerbs [OLE32.@]
1083 * Enumerates verbs associated with a class stored in the registry.
1085 * PARAMS
1086 * clsid [I] Class ID to enumerate the verbs for.
1087 * ppenum [O] Enumerator.
1089 * RETURNS
1090 * S_OK: Success.
1091 * REGDB_E_CLASSNOTREG: The specified class does not have a key in the registry.
1092 * REGDB_E_READREGDB: The class key could not be opened for some other reason.
1093 * OLE_E_REGDB_KEY: The Verb subkey for the class is not present.
1094 * OLEOBJ_E_NOVERBS: The Verb subkey for the class is empty.
1096 HRESULT WINAPI OleRegEnumVerbs (REFCLSID clsid, LPENUMOLEVERB* ppenum)
1098 LONG res;
1099 HKEY hkeyVerb;
1100 DWORD dwSubKeys;
1102 TRACE("(%s, %p)\n", debugstr_guid(clsid), ppenum);
1104 res = COM_OpenKeyForCLSID(clsid, L"Verb", KEY_READ, &hkeyVerb);
1105 if (FAILED(res))
1107 if (res == REGDB_E_CLASSNOTREG)
1108 ERR("CLSID %s not registered\n", debugstr_guid(clsid));
1109 else if (res == REGDB_E_KEYMISSING)
1110 ERR("no Verbs key for class %s\n", debugstr_guid(clsid));
1111 else
1112 ERR("failed to open Verbs key for CLSID %s with error %ld\n",
1113 debugstr_guid(clsid), res);
1114 return res;
1117 res = RegQueryInfoKeyW(hkeyVerb, NULL, NULL, NULL, &dwSubKeys, NULL,
1118 NULL, NULL, NULL, NULL, NULL, NULL);
1119 if (res != ERROR_SUCCESS)
1121 ERR("failed to get subkey count with error %ld\n", GetLastError());
1122 return REGDB_E_READREGDB;
1125 if (!dwSubKeys)
1127 WARN("class %s has no verbs\n", debugstr_guid(clsid));
1128 RegCloseKey(hkeyVerb);
1129 return OLEOBJ_E_NOVERBS;
1132 return EnumOLEVERB_Construct(hkeyVerb, 0, ppenum);
1135 /******************************************************************************
1136 * OleSetContainedObject [OLE32.@]
1138 HRESULT WINAPI OleSetContainedObject(
1139 LPUNKNOWN pUnknown,
1140 BOOL fContained)
1142 IRunnableObject* runnable = NULL;
1143 HRESULT hres;
1145 TRACE("(%p,%x)\n", pUnknown, fContained);
1147 hres = IUnknown_QueryInterface(pUnknown,
1148 &IID_IRunnableObject,
1149 (void**)&runnable);
1151 if (SUCCEEDED(hres))
1153 hres = IRunnableObject_SetContainedObject(runnable, fContained);
1155 IRunnableObject_Release(runnable);
1157 return hres;
1160 return S_OK;
1163 /******************************************************************************
1164 * OleRun [OLE32.@]
1166 * Set the OLE object to the running state.
1168 * PARAMS
1169 * pUnknown [I] OLE object to run.
1171 * RETURNS
1172 * Success: S_OK.
1173 * Failure: Any HRESULT code.
1175 HRESULT WINAPI DECLSPEC_HOTPATCH OleRun(LPUNKNOWN pUnknown)
1177 IRunnableObject *runable;
1178 HRESULT hres;
1180 TRACE("(%p)\n", pUnknown);
1182 hres = IUnknown_QueryInterface(pUnknown, &IID_IRunnableObject, (void**)&runable);
1183 if (FAILED(hres))
1184 return S_OK; /* Appears to return no error. */
1186 hres = IRunnableObject_Run(runable, NULL);
1187 IRunnableObject_Release(runable);
1188 return hres;
1191 /******************************************************************************
1192 * OleLoad [OLE32.@]
1194 HRESULT WINAPI OleLoad(
1195 LPSTORAGE pStg,
1196 REFIID riid,
1197 LPOLECLIENTSITE pClientSite,
1198 LPVOID* ppvObj)
1200 IPersistStorage* persistStorage = NULL;
1201 IUnknown* pUnk;
1202 IOleObject* pOleObject = NULL;
1203 STATSTG storageInfo;
1204 HRESULT hres;
1206 TRACE("(%p, %s, %p, %p)\n", pStg, debugstr_guid(riid), pClientSite, ppvObj);
1208 *ppvObj = NULL;
1211 * TODO, Conversion ... OleDoAutoConvert
1215 * Get the class ID for the object.
1217 hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
1218 if (FAILED(hres))
1219 return hres;
1222 * Now, try and create the handler for the object
1224 hres = CoCreateInstance(&storageInfo.clsid,
1225 NULL,
1226 CLSCTX_INPROC_HANDLER|CLSCTX_INPROC_SERVER,
1227 riid,
1228 (void**)&pUnk);
1231 * If that fails, as it will most times, load the default
1232 * OLE handler.
1234 if (FAILED(hres))
1236 hres = OleCreateDefaultHandler(&storageInfo.clsid,
1237 NULL,
1238 riid,
1239 (void**)&pUnk);
1243 * If we couldn't find a handler... this is bad. Abort the whole thing.
1245 if (FAILED(hres))
1246 return hres;
1248 if (pClientSite)
1250 hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (void **)&pOleObject);
1251 if (SUCCEEDED(hres))
1253 DWORD dwStatus;
1254 hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
1259 * Initialize the object with its IPersistStorage interface.
1261 hres = IUnknown_QueryInterface(pUnk, &IID_IPersistStorage, (void**)&persistStorage);
1262 if (SUCCEEDED(hres))
1264 hres = IPersistStorage_Load(persistStorage, pStg);
1266 IPersistStorage_Release(persistStorage);
1267 persistStorage = NULL;
1270 if (SUCCEEDED(hres) && pClientSite)
1272 * Inform the new object of its client site.
1274 hres = IOleObject_SetClientSite(pOleObject, pClientSite);
1277 * Cleanup interfaces used internally
1279 if (pOleObject)
1280 IOleObject_Release(pOleObject);
1282 if (SUCCEEDED(hres))
1284 IOleLink *pOleLink;
1285 HRESULT hres1;
1286 hres1 = IUnknown_QueryInterface(pUnk, &IID_IOleLink, (void **)&pOleLink);
1287 if (SUCCEEDED(hres1))
1289 FIXME("handle OLE link\n");
1290 IOleLink_Release(pOleLink);
1294 if (FAILED(hres))
1296 IUnknown_Release(pUnk);
1297 pUnk = NULL;
1300 *ppvObj = pUnk;
1302 return hres;
1305 /***********************************************************************
1306 * OleSave [OLE32.@]
1308 HRESULT WINAPI OleSave(
1309 LPPERSISTSTORAGE pPS,
1310 LPSTORAGE pStg,
1311 BOOL fSameAsLoad)
1313 HRESULT hres;
1314 CLSID objectClass;
1316 TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad);
1319 * First, we transfer the class ID (if available)
1321 hres = IPersistStorage_GetClassID(pPS, &objectClass);
1323 if (SUCCEEDED(hres))
1325 WriteClassStg(pStg, &objectClass);
1329 * Then, we ask the object to save itself to the
1330 * storage. If it is successful, we commit the storage.
1332 hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad);
1334 if (SUCCEEDED(hres))
1336 IStorage_Commit(pStg,
1337 STGC_DEFAULT);
1340 return hres;
1344 /******************************************************************************
1345 * OleLockRunning [OLE32.@]
1347 HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses)
1349 IRunnableObject* runnable = NULL;
1350 HRESULT hres;
1352 TRACE("(%p,%x,%x)\n", pUnknown, fLock, fLastUnlockCloses);
1354 hres = IUnknown_QueryInterface(pUnknown,
1355 &IID_IRunnableObject,
1356 (void**)&runnable);
1358 if (SUCCEEDED(hres))
1360 hres = IRunnableObject_LockRunning(runnable, fLock, fLastUnlockCloses);
1362 IRunnableObject_Release(runnable);
1364 return hres;
1367 return S_OK;
1371 /**************************************************************************
1372 * Internal methods to manage the shared OLE menu in response to the
1373 * OLE***MenuDescriptor API
1376 /***
1377 * OLEMenu_Initialize()
1379 * Initializes the OLEMENU data structures.
1381 static void OLEMenu_Initialize(void)
1385 /***
1386 * OLEMenu_UnInitialize()
1388 * Releases the OLEMENU data structures.
1390 static void OLEMenu_UnInitialize(void)
1394 /*************************************************************************
1395 * OLEMenu_InstallHooks
1396 * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
1398 * RETURNS: TRUE if message hooks were successfully installed
1399 * FALSE on failure
1401 static BOOL OLEMenu_InstallHooks( DWORD tid )
1403 OleMenuHookItem *pHookItem;
1405 /* Create an entry for the hook table */
1406 if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
1407 sizeof(OleMenuHookItem)) ) )
1408 return FALSE;
1410 pHookItem->tid = tid;
1411 pHookItem->hHeap = GetProcessHeap();
1412 pHookItem->CallWndProc_hHook = NULL;
1414 /* Install a thread scope message hook for WH_GETMESSAGE */
1415 pHookItem->GetMsg_hHook = SetWindowsHookExW( WH_GETMESSAGE, OLEMenu_GetMsgProc,
1416 0, GetCurrentThreadId() );
1417 if ( !pHookItem->GetMsg_hHook )
1418 goto CLEANUP;
1420 /* Install a thread scope message hook for WH_CALLWNDPROC */
1421 pHookItem->CallWndProc_hHook = SetWindowsHookExW( WH_CALLWNDPROC, OLEMenu_CallWndProc,
1422 0, GetCurrentThreadId() );
1423 if ( !pHookItem->CallWndProc_hHook )
1424 goto CLEANUP;
1426 /* Insert the hook table entry */
1427 pHookItem->next = hook_list;
1428 hook_list = pHookItem;
1430 return TRUE;
1432 CLEANUP:
1433 /* Unhook any hooks */
1434 if ( pHookItem->GetMsg_hHook )
1435 UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
1436 if ( pHookItem->CallWndProc_hHook )
1437 UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
1438 /* Release the hook table entry */
1439 HeapFree(pHookItem->hHeap, 0, pHookItem );
1441 return FALSE;
1444 /*************************************************************************
1445 * OLEMenu_UnInstallHooks
1446 * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
1448 * RETURNS: TRUE if message hooks were successfully installed
1449 * FALSE on failure
1451 static BOOL OLEMenu_UnInstallHooks( DWORD tid )
1453 OleMenuHookItem *pHookItem = NULL;
1454 OleMenuHookItem **ppHook = &hook_list;
1456 while (*ppHook)
1458 if ((*ppHook)->tid == tid)
1460 pHookItem = *ppHook;
1461 *ppHook = pHookItem->next;
1462 break;
1464 ppHook = &(*ppHook)->next;
1466 if (!pHookItem) return FALSE;
1468 /* Uninstall the hooks installed for this thread */
1469 if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
1470 goto CLEANUP;
1471 if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
1472 goto CLEANUP;
1474 /* Release the hook table entry */
1475 HeapFree(pHookItem->hHeap, 0, pHookItem );
1477 return TRUE;
1479 CLEANUP:
1480 /* Release the hook table entry */
1481 HeapFree(pHookItem->hHeap, 0, pHookItem );
1483 return FALSE;
1486 /*************************************************************************
1487 * OLEMenu_IsHookInstalled
1488 * Tests if OLEMenu hooks have been installed for a thread
1490 * RETURNS: The pointer and index of the hook table entry for the tid
1491 * NULL and -1 for the index if no hooks were installed for this thread
1493 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )
1495 OleMenuHookItem *pHookItem;
1497 /* Do a simple linear search for an entry whose tid matches ours.
1498 * We really need a map but efficiency is not a concern here. */
1499 for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next)
1501 if ( tid == pHookItem->tid )
1502 return pHookItem;
1505 return NULL;
1508 /***********************************************************************
1509 * OLEMenu_FindMainMenuIndex
1511 * Used by OLEMenu API to find the top level group a menu item belongs to.
1512 * On success pnPos contains the index of the item in the top level menu group
1514 * RETURNS: TRUE if the ID was found, FALSE on failure
1516 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
1518 INT i, nItems;
1520 nItems = GetMenuItemCount( hMainMenu );
1522 for (i = 0; i < nItems; i++)
1524 HMENU hsubmenu;
1526 /* Is the current item a submenu? */
1527 if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
1529 /* If the handle is the same we're done */
1530 if ( hsubmenu == hPopupMenu )
1532 if (pnPos)
1533 *pnPos = i;
1534 return TRUE;
1536 /* Recursively search without updating pnPos */
1537 else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
1539 if (pnPos)
1540 *pnPos = i;
1541 return TRUE;
1546 return FALSE;
1549 /***********************************************************************
1550 * OLEMenu_SetIsServerMenu
1552 * Checks whether a popup menu belongs to a shared menu group which is
1553 * owned by the server, and sets the menu descriptor state accordingly.
1554 * All menu messages from these groups should be routed to the server.
1556 * RETURNS: TRUE if the popup menu is part of a server owned group
1557 * FALSE if the popup menu is part of a container owned group
1559 static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
1561 UINT nPos = 0, nWidth, i;
1563 pOleMenuDescriptor->bIsServerItem = FALSE;
1565 /* Don't bother searching if the popup is the combined menu itself */
1566 if ( hmenu == pOleMenuDescriptor->hmenuCombined )
1567 return FALSE;
1569 /* Find the menu item index in the shared OLE menu that this item belongs to */
1570 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) )
1571 return FALSE;
1573 /* The group widths array has counts for the number of elements
1574 * in the groups File, Edit, Container, Object, Window, Help.
1575 * The Edit, Object & Help groups belong to the server object
1576 * and the other three belong to the container.
1577 * Loop through the group widths and locate the group we are a member of.
1579 for ( i = 0, nWidth = 0; i < 6; i++ )
1581 nWidth += pOleMenuDescriptor->mgw.width[i];
1582 if ( nPos < nWidth )
1584 /* Odd elements are server menu widths */
1585 pOleMenuDescriptor->bIsServerItem = i%2;
1586 break;
1590 return pOleMenuDescriptor->bIsServerItem;
1593 /*************************************************************************
1594 * OLEMenu_CallWndProc
1595 * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
1596 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1598 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
1600 LPCWPSTRUCT pMsg;
1601 HOLEMENU hOleMenu = 0;
1602 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1603 OleMenuHookItem *pHookItem = NULL;
1604 WORD fuFlags;
1606 TRACE("%i, %#Ix, %#Ix.\n", code, wParam, lParam );
1608 /* Check if we're being asked to process the message */
1609 if ( HC_ACTION != code )
1610 goto NEXTHOOK;
1612 /* Retrieve the current message being dispatched from lParam */
1613 pMsg = (LPCWPSTRUCT)lParam;
1615 /* Check if the message is destined for a window we are interested in:
1616 * If the window has an OLEMenu property we may need to dispatch
1617 * the menu message to its active objects window instead. */
1619 hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW );
1620 if ( !hOleMenu )
1621 goto NEXTHOOK;
1623 /* Get the menu descriptor */
1624 pOleMenuDescriptor = GlobalLock( hOleMenu );
1625 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1626 goto NEXTHOOK;
1628 /* Process menu messages */
1629 switch( pMsg->message )
1631 case WM_INITMENU:
1633 /* Reset the menu descriptor state */
1634 pOleMenuDescriptor->bIsServerItem = FALSE;
1636 /* Send this message to the server as well */
1637 SendMessageW( pOleMenuDescriptor->hwndActiveObject,
1638 pMsg->message, pMsg->wParam, pMsg->lParam );
1639 goto NEXTHOOK;
1642 case WM_INITMENUPOPUP:
1644 /* Save the state for whether this is a server owned menu */
1645 OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
1646 break;
1649 case WM_MENUSELECT:
1651 fuFlags = HIWORD(pMsg->wParam); /* Get flags */
1652 if ( fuFlags & MF_SYSMENU )
1653 goto NEXTHOOK;
1655 /* Save the state for whether this is a server owned popup menu */
1656 else if ( fuFlags & MF_POPUP )
1657 OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
1659 break;
1662 case WM_DRAWITEM:
1664 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
1665 if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
1666 goto NEXTHOOK; /* Not a menu message */
1668 break;
1671 default:
1672 goto NEXTHOOK;
1675 /* If the message was for the server dispatch it accordingly */
1676 if ( pOleMenuDescriptor->bIsServerItem )
1678 SendMessageW( pOleMenuDescriptor->hwndActiveObject,
1679 pMsg->message, pMsg->wParam, pMsg->lParam );
1682 NEXTHOOK:
1683 if ( pOleMenuDescriptor )
1684 GlobalUnlock( hOleMenu );
1686 /* Lookup the hook item for the current thread */
1687 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1689 /* This should never fail!! */
1690 WARN("could not retrieve hHook for current thread!\n" );
1691 return 0;
1694 /* Pass on the message to the next hooker */
1695 return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
1698 /*************************************************************************
1699 * OLEMenu_GetMsgProc
1700 * Thread scope WH_GETMESSAGE hook proc filter function (callback)
1701 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1703 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
1705 LPMSG pMsg;
1706 HOLEMENU hOleMenu = 0;
1707 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1708 OleMenuHookItem *pHookItem = NULL;
1709 WORD wCode;
1711 TRACE("%i, %#Ix, %#Ix.\n", code, wParam, lParam );
1713 /* Check if we're being asked to process a messages */
1714 if ( HC_ACTION != code )
1715 goto NEXTHOOK;
1717 /* Retrieve the current message being dispatched from lParam */
1718 pMsg = (LPMSG)lParam;
1720 /* Check if the message is destined for a window we are interested in:
1721 * If the window has an OLEMenu property we may need to dispatch
1722 * the menu message to its active objects window instead. */
1724 hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW );
1725 if ( !hOleMenu )
1726 goto NEXTHOOK;
1728 /* Process menu messages */
1729 switch( pMsg->message )
1731 case WM_COMMAND:
1733 wCode = HIWORD(pMsg->wParam); /* Get notification code */
1734 if ( wCode )
1735 goto NEXTHOOK; /* Not a menu message */
1736 break;
1738 default:
1739 goto NEXTHOOK;
1742 /* Get the menu descriptor */
1743 pOleMenuDescriptor = GlobalLock( hOleMenu );
1744 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1745 goto NEXTHOOK;
1747 /* If the message was for the server dispatch it accordingly */
1748 if ( pOleMenuDescriptor->bIsServerItem )
1750 /* Change the hWnd in the message to the active objects hWnd.
1751 * The message loop which reads this message will automatically
1752 * dispatch it to the embedded objects window. */
1753 pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
1756 NEXTHOOK:
1757 if ( pOleMenuDescriptor )
1758 GlobalUnlock( hOleMenu );
1760 /* Lookup the hook item for the current thread */
1761 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1763 /* This should never fail!! */
1764 WARN("could not retrieve hHook for current thread!\n" );
1765 return FALSE;
1768 /* Pass on the message to the next hooker */
1769 return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
1772 /***********************************************************************
1773 * OleCreateMenuDescriptor [OLE32.@]
1774 * Creates an OLE menu descriptor for OLE to use when dispatching
1775 * menu messages and commands.
1777 * PARAMS:
1778 * hmenuCombined - Handle to the objects combined menu
1779 * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group
1782 HOLEMENU WINAPI OleCreateMenuDescriptor(
1783 HMENU hmenuCombined,
1784 LPOLEMENUGROUPWIDTHS lpMenuWidths)
1786 HOLEMENU hOleMenu;
1787 OleMenuDescriptor *pOleMenuDescriptor;
1788 int i;
1790 if ( !hmenuCombined || !lpMenuWidths )
1791 return 0;
1793 /* Create an OLE menu descriptor */
1794 if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
1795 sizeof(OleMenuDescriptor) ) ) )
1796 return 0;
1798 pOleMenuDescriptor = GlobalLock( hOleMenu );
1799 if ( !pOleMenuDescriptor )
1800 return 0;
1802 /* Initialize menu group widths and hmenu */
1803 for ( i = 0; i < 6; i++ )
1804 pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
1806 pOleMenuDescriptor->hmenuCombined = hmenuCombined;
1807 pOleMenuDescriptor->bIsServerItem = FALSE;
1808 GlobalUnlock( hOleMenu );
1810 return hOleMenu;
1813 /***********************************************************************
1814 * OleDestroyMenuDescriptor [OLE32.@]
1815 * Destroy the shared menu descriptor
1817 HRESULT WINAPI OleDestroyMenuDescriptor(
1818 HOLEMENU hmenuDescriptor)
1820 if ( hmenuDescriptor )
1821 GlobalFree( hmenuDescriptor );
1822 return S_OK;
1825 /***********************************************************************
1826 * OleSetMenuDescriptor [OLE32.@]
1827 * Installs or removes OLE dispatching code for the containers frame window.
1829 * PARAMS
1830 * hOleMenu Handle to composite menu descriptor
1831 * hwndFrame Handle to containers frame window
1832 * hwndActiveObject Handle to objects in-place activation window
1833 * lpFrame Pointer to IOleInPlaceFrame on containers window
1834 * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object
1836 * RETURNS
1837 * S_OK - menu installed correctly
1838 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1840 * FIXME
1841 * The lpFrame and lpActiveObject parameters are currently ignored
1842 * OLE should install context sensitive help F1 filtering for the app when
1843 * these are non null.
1845 HRESULT WINAPI OleSetMenuDescriptor(
1846 HOLEMENU hOleMenu,
1847 HWND hwndFrame,
1848 HWND hwndActiveObject,
1849 LPOLEINPLACEFRAME lpFrame,
1850 LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1852 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1854 /* Check args */
1855 if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
1856 return E_INVALIDARG;
1858 if ( lpFrame || lpActiveObject )
1860 FIXME("(%p, %p, %p, %p, %p), Context sensitive help filtering not implemented!\n",
1861 hOleMenu,
1862 hwndFrame,
1863 hwndActiveObject,
1864 lpFrame,
1865 lpActiveObject);
1868 /* Set up a message hook to intercept the containers frame window messages.
1869 * The message filter is responsible for dispatching menu messages from the
1870 * shared menu which are intended for the object.
1873 if ( hOleMenu ) /* Want to install dispatching code */
1875 /* If OLEMenu hooks are already installed for this thread, fail
1876 * Note: This effectively means that OleSetMenuDescriptor cannot
1877 * be called twice in succession on the same frame window
1878 * without first calling it with a null hOleMenu to uninstall
1880 if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) )
1881 return E_FAIL;
1883 /* Get the menu descriptor */
1884 pOleMenuDescriptor = GlobalLock( hOleMenu );
1885 if ( !pOleMenuDescriptor )
1886 return E_UNEXPECTED;
1888 /* Update the menu descriptor */
1889 pOleMenuDescriptor->hwndFrame = hwndFrame;
1890 pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
1892 GlobalUnlock( hOleMenu );
1893 pOleMenuDescriptor = NULL;
1895 /* Add a menu descriptor windows property to the frame window */
1896 SetPropW( hwndFrame, prop_olemenuW, hOleMenu );
1898 /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
1899 if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
1900 return E_FAIL;
1902 else /* Want to uninstall dispatching code */
1904 /* Uninstall the hooks */
1905 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1906 return E_FAIL;
1908 /* Remove the menu descriptor property from the frame window */
1909 RemovePropW( hwndFrame, prop_olemenuW );
1912 return S_OK;
1915 /******************************************************************************
1916 * IsAccelerator [OLE32.@]
1917 * Mostly copied from controls/menu.c TranslateAccelerator implementation
1919 BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd)
1921 LPACCEL lpAccelTbl;
1922 int i;
1924 if(!lpMsg) return FALSE;
1925 if (!hAccel)
1927 WARN_(accel)("NULL accel handle\n");
1928 return FALSE;
1930 if((lpMsg->message != WM_KEYDOWN &&
1931 lpMsg->message != WM_SYSKEYDOWN &&
1932 lpMsg->message != WM_SYSCHAR &&
1933 lpMsg->message != WM_CHAR)) return FALSE;
1934 lpAccelTbl = HeapAlloc(GetProcessHeap(), 0, cAccelEntries * sizeof(ACCEL));
1935 if (NULL == lpAccelTbl)
1937 return FALSE;
1939 if (CopyAcceleratorTableW(hAccel, lpAccelTbl, cAccelEntries) != cAccelEntries)
1941 WARN_(accel)("CopyAcceleratorTableW failed\n");
1942 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1943 return FALSE;
1946 TRACE_(accel)("hAccel=%p, cAccelEntries=%d,"
1947 "msg->hwnd=%p, msg->message=%04x, wParam=%#Ix, lParam=%#Ix\n",
1948 hAccel, cAccelEntries,
1949 lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);
1950 for(i = 0; i < cAccelEntries; i++)
1952 if(lpAccelTbl[i].key != lpMsg->wParam)
1953 continue;
1955 if(lpMsg->message == WM_CHAR)
1957 if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY))
1959 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", LOWORD(lpMsg->wParam) & 0xff);
1960 goto found;
1963 else
1965 if(lpAccelTbl[i].fVirt & FVIRTKEY)
1967 INT mask = 0;
1968 TRACE_(accel)("found accel for virt_key %Ix (scan %04x)\n",
1969 lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff);
1970 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
1971 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
1972 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
1973 if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
1974 TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n");
1976 else
1978 if(!(lpMsg->lParam & 0x01000000)) /* no special_key */
1980 if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000))
1981 { /* ^^ ALT pressed */
1982 TRACE_(accel)("found accel for Alt-%c\n", LOWORD(lpMsg->wParam) & 0xff);
1983 goto found;
1990 WARN_(accel)("couldn't translate accelerator key\n");
1991 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1992 return FALSE;
1994 found:
1995 if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd;
1996 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1997 return TRUE;
2000 /***********************************************************************
2001 * ReleaseStgMedium [OLE32.@]
2003 void WINAPI ReleaseStgMedium(
2004 STGMEDIUM* pmedium)
2006 if (!pmedium) return;
2008 switch (pmedium->tymed)
2010 case TYMED_HGLOBAL:
2012 if ( (pmedium->pUnkForRelease==0) &&
2013 (pmedium->u.hGlobal!=0) )
2014 GlobalFree(pmedium->u.hGlobal);
2015 break;
2017 case TYMED_FILE:
2019 if (pmedium->u.lpszFileName!=0)
2021 if (pmedium->pUnkForRelease==0)
2023 DeleteFileW(pmedium->u.lpszFileName);
2026 CoTaskMemFree(pmedium->u.lpszFileName);
2028 break;
2030 case TYMED_ISTREAM:
2032 if (pmedium->u.pstm!=0)
2034 IStream_Release(pmedium->u.pstm);
2036 break;
2038 case TYMED_ISTORAGE:
2040 if (pmedium->u.pstg!=0)
2042 IStorage_Release(pmedium->u.pstg);
2044 break;
2046 case TYMED_GDI:
2048 if ( (pmedium->pUnkForRelease==0) &&
2049 (pmedium->u.hBitmap!=0) )
2050 DeleteObject(pmedium->u.hBitmap);
2051 break;
2053 case TYMED_MFPICT:
2055 if ( (pmedium->pUnkForRelease==0) &&
2056 (pmedium->u.hMetaFilePict!=0) )
2058 LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hMetaFilePict);
2059 DeleteMetaFile(pMP->hMF);
2060 GlobalUnlock(pmedium->u.hMetaFilePict);
2061 GlobalFree(pmedium->u.hMetaFilePict);
2063 break;
2065 case TYMED_ENHMF:
2067 if ( (pmedium->pUnkForRelease==0) &&
2068 (pmedium->u.hEnhMetaFile!=0) )
2070 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
2072 break;
2074 case TYMED_NULL:
2075 default:
2076 break;
2078 pmedium->tymed=TYMED_NULL;
2081 * After cleaning up, the unknown is released
2083 if (pmedium->pUnkForRelease!=0)
2085 IUnknown_Release(pmedium->pUnkForRelease);
2086 pmedium->pUnkForRelease = 0;
2090 /***
2091 * OLEDD_Initialize()
2093 * Initializes the OLE drag and drop data structures.
2095 static void OLEDD_Initialize(void)
2097 WNDCLASSW wndClass;
2099 ZeroMemory (&wndClass, sizeof(WNDCLASSW));
2100 wndClass.style = CS_GLOBALCLASS;
2101 wndClass.lpfnWndProc = OLEDD_DragTrackerWindowProc;
2102 wndClass.cbClsExtra = 0;
2103 wndClass.cbWndExtra = sizeof(TrackerWindowInfo*);
2104 wndClass.hCursor = 0;
2105 wndClass.hbrBackground = 0;
2106 wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
2108 RegisterClassW (&wndClass);
2111 /***
2112 * OLEDD_DragTrackerWindowProc()
2114 * This method is the WindowProcedure of the drag n drop tracking
2115 * window. During a drag n Drop operation, an invisible window is created
2116 * to receive the user input and act upon it. This procedure is in charge
2117 * of this behavior.
2120 #define DRAG_TIMER_ID 1
2122 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
2123 HWND hwnd,
2124 UINT uMsg,
2125 WPARAM wParam,
2126 LPARAM lParam)
2128 switch (uMsg)
2130 case WM_CREATE:
2132 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
2134 SetWindowLongPtrW(hwnd, 0, (LONG_PTR)createStruct->lpCreateParams);
2135 SetTimer(hwnd, DRAG_TIMER_ID, 50, NULL);
2137 break;
2139 case WM_TIMER:
2140 case WM_MOUSEMOVE:
2141 case WM_LBUTTONUP:
2142 case WM_MBUTTONUP:
2143 case WM_RBUTTONUP:
2144 case WM_LBUTTONDOWN:
2145 case WM_MBUTTONDOWN:
2146 case WM_RBUTTONDOWN:
2148 TrackerWindowInfo *trackerInfo = (TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0);
2149 if (trackerInfo->trackingDone) break;
2150 OLEDD_TrackStateChange(trackerInfo);
2151 break;
2153 case WM_DESTROY:
2155 KillTimer(hwnd, DRAG_TIMER_ID);
2156 break;
2161 * This is a window proc after all. Let's call the default.
2163 return DefWindowProcW (hwnd, uMsg, wParam, lParam);
2166 static void drag_enter( TrackerWindowInfo *info, HWND new_target )
2168 HRESULT hr;
2170 info->curTargetHWND = new_target;
2172 while (new_target && !is_droptarget( new_target ))
2173 new_target = GetParent( new_target );
2175 info->curDragTarget = get_droptarget_pointer( new_target );
2177 if (info->curDragTarget)
2179 *info->pdwEffect = info->dwOKEffect;
2180 hr = IDropTarget_DragEnter( info->curDragTarget, info->dataObject,
2181 info->dwKeyState, info->curMousePos,
2182 info->pdwEffect );
2183 *info->pdwEffect &= info->dwOKEffect;
2185 /* failed DragEnter() means invalid target */
2186 if (hr != S_OK)
2188 IDropTarget_Release( info->curDragTarget );
2189 info->curDragTarget = NULL;
2190 info->curTargetHWND = NULL;
2195 static void drag_end( TrackerWindowInfo *info )
2197 HRESULT hr;
2199 info->trackingDone = TRUE;
2200 ReleaseCapture();
2202 if (info->curDragTarget)
2204 if (info->returnValue == DRAGDROP_S_DROP &&
2205 *info->pdwEffect != DROPEFFECT_NONE)
2207 *info->pdwEffect = info->dwOKEffect;
2208 hr = IDropTarget_Drop( info->curDragTarget, info->dataObject, info->dwKeyState,
2209 info->curMousePos, info->pdwEffect );
2210 *info->pdwEffect &= info->dwOKEffect;
2212 if (FAILED( hr ))
2213 info->returnValue = hr;
2215 else
2217 IDropTarget_DragLeave( info->curDragTarget );
2218 *info->pdwEffect = DROPEFFECT_NONE;
2220 IDropTarget_Release( info->curDragTarget );
2221 info->curDragTarget = NULL;
2223 else
2224 *info->pdwEffect = DROPEFFECT_NONE;
2227 static HRESULT give_feedback( TrackerWindowInfo *info )
2229 HRESULT hr;
2230 int res;
2231 HCURSOR cur;
2233 if (info->curDragTarget == NULL)
2234 *info->pdwEffect = DROPEFFECT_NONE;
2236 hr = IDropSource_GiveFeedback( info->dropSource, *info->pdwEffect );
2238 if (hr == DRAGDROP_S_USEDEFAULTCURSORS)
2240 if (*info->pdwEffect & DROPEFFECT_MOVE)
2241 res = CURSOR_MOVE;
2242 else if (*info->pdwEffect & DROPEFFECT_COPY)
2243 res = CURSOR_COPY;
2244 else if (*info->pdwEffect & DROPEFFECT_LINK)
2245 res = CURSOR_LINK;
2246 else
2247 res = CURSOR_NODROP;
2249 cur = LoadCursorW( hProxyDll, MAKEINTRESOURCEW( res ) );
2250 SetCursor( cur );
2253 return hr;
2256 /***
2257 * OLEDD_TrackStateChange()
2259 * This method is invoked while a drag and drop operation is in effect.
2261 * params:
2262 * trackerInfo - Pointer to the structure identifying the
2263 * drag & drop operation that is currently
2264 * active.
2266 static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo)
2268 HWND hwndNewTarget = 0;
2269 POINT pt;
2272 * This method may be called from QueryContinueDrag again,
2273 * (i.e. by running message loop) so avoid recursive call chain.
2275 if (trackerInfo->inTrackCall) return;
2276 trackerInfo->inTrackCall = TRUE;
2279 * Get the handle of the window under the mouse
2281 pt.x = trackerInfo->curMousePos.x;
2282 pt.y = trackerInfo->curMousePos.y;
2283 hwndNewTarget = WindowFromPoint(pt);
2285 trackerInfo->returnValue = IDropSource_QueryContinueDrag(trackerInfo->dropSource,
2286 trackerInfo->escPressed,
2287 trackerInfo->dwKeyState);
2289 if (trackerInfo->curTargetHWND != hwndNewTarget &&
2290 (trackerInfo->returnValue == S_OK ||
2291 trackerInfo->returnValue == DRAGDROP_S_DROP))
2293 if (trackerInfo->curDragTarget)
2295 IDropTarget_DragLeave(trackerInfo->curDragTarget);
2296 IDropTarget_Release(trackerInfo->curDragTarget);
2297 trackerInfo->curDragTarget = NULL;
2298 trackerInfo->curTargetHWND = NULL;
2301 if (hwndNewTarget)
2302 drag_enter( trackerInfo, hwndNewTarget );
2304 give_feedback( trackerInfo );
2308 if (trackerInfo->returnValue == S_OK)
2310 if (trackerInfo->curDragTarget)
2312 *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
2313 IDropTarget_DragOver(trackerInfo->curDragTarget,
2314 trackerInfo->dwKeyState,
2315 trackerInfo->curMousePos,
2316 trackerInfo->pdwEffect);
2317 *trackerInfo->pdwEffect &= trackerInfo->dwOKEffect;
2319 give_feedback( trackerInfo );
2321 else
2322 drag_end( trackerInfo );
2324 trackerInfo->inTrackCall = FALSE;
2327 /***
2328 * OLEDD_GetButtonState()
2330 * This method will use the current state of the keyboard to build
2331 * a button state mask equivalent to the one passed in the
2332 * WM_MOUSEMOVE wParam.
2334 static DWORD OLEDD_GetButtonState(void)
2336 BYTE keyboardState[256];
2337 DWORD keyMask = 0;
2339 GetKeyboardState(keyboardState);
2341 if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
2342 keyMask |= MK_SHIFT;
2344 if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
2345 keyMask |= MK_CONTROL;
2347 if ( (keyboardState[VK_MENU] & 0x80) !=0)
2348 keyMask |= MK_ALT;
2350 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
2351 keyMask |= MK_LBUTTON;
2353 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
2354 keyMask |= MK_RBUTTON;
2356 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
2357 keyMask |= MK_MBUTTON;
2359 return keyMask;
2362 /***
2363 * OLEDD_GetButtonState()
2365 * This method will read the default value of the registry key in
2366 * parameter and extract a DWORD value from it. The registry key value
2367 * can be in a string key or a DWORD key.
2369 * params:
2370 * regKey - Key to read the default value from
2371 * pdwValue - Pointer to the location where the DWORD
2372 * value is returned. This value is not modified
2373 * if the value is not found.
2376 static void OLEUTL_ReadRegistryDWORDValue(
2377 HKEY regKey,
2378 DWORD* pdwValue)
2380 WCHAR buffer[20];
2381 DWORD cbData = sizeof(buffer);
2382 DWORD dwKeyType;
2383 LONG lres;
2385 lres = RegQueryValueExW(regKey, L"", NULL, &dwKeyType, (BYTE *)buffer, &cbData);
2387 if (lres==ERROR_SUCCESS)
2389 switch (dwKeyType)
2391 case REG_DWORD:
2392 *pdwValue = *(DWORD*)buffer;
2393 break;
2394 case REG_EXPAND_SZ:
2395 case REG_MULTI_SZ:
2396 case REG_SZ:
2397 *pdwValue = wcstoul(buffer, NULL, 10);
2398 break;
2403 /******************************************************************************
2404 * OleDraw (OLE32.@)
2406 * The operation of this function is documented literally in the WinAPI
2407 * documentation to involve a QueryInterface for the IViewObject interface,
2408 * followed by a call to IViewObject::Draw.
2410 HRESULT WINAPI OleDraw(
2411 IUnknown *pUnk,
2412 DWORD dwAspect,
2413 HDC hdcDraw,
2414 LPCRECT rect)
2416 HRESULT hres;
2417 IViewObject *viewobject;
2419 if (!pUnk) return E_INVALIDARG;
2421 hres = IUnknown_QueryInterface(pUnk,
2422 &IID_IViewObject,
2423 (void**)&viewobject);
2424 if (SUCCEEDED(hres))
2426 hres = IViewObject_Draw(viewobject, dwAspect, -1, 0, 0, 0, hdcDraw, (RECTL*)rect, 0, 0, 0);
2427 IViewObject_Release(viewobject);
2428 return hres;
2430 else
2431 return DV_E_NOIVIEWOBJECT;
2434 /***********************************************************************
2435 * OleTranslateAccelerator [OLE32.@]
2437 HRESULT WINAPI OleTranslateAccelerator (LPOLEINPLACEFRAME lpFrame,
2438 LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpmsg)
2440 WORD wID;
2442 TRACE("(%p,%p,%p)\n", lpFrame, lpFrameInfo, lpmsg);
2444 if (IsAccelerator(lpFrameInfo->haccel,lpFrameInfo->cAccelEntries,lpmsg,&wID))
2445 return IOleInPlaceFrame_TranslateAccelerator(lpFrame,lpmsg,wID);
2447 return S_FALSE;
2450 /******************************************************************************
2451 * OleCreate [OLE32.@]
2454 HRESULT WINAPI OleCreate(
2455 REFCLSID rclsid,
2456 REFIID riid,
2457 DWORD renderopt,
2458 LPFORMATETC pFormatEtc,
2459 LPOLECLIENTSITE pClientSite,
2460 LPSTORAGE pStg,
2461 LPVOID* ppvObj)
2463 HRESULT hres;
2464 IUnknown * pUnk = NULL;
2465 IOleObject *pOleObject = NULL;
2467 TRACE("%s, %s, %ld, %p, %p, %p, %p.\n", debugstr_guid(rclsid),
2468 debugstr_guid(riid), renderopt, pFormatEtc, pClientSite, pStg, ppvObj);
2470 hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, riid, (LPVOID*)&pUnk);
2472 if (SUCCEEDED(hres))
2473 hres = IStorage_SetClass(pStg, rclsid);
2475 if (pClientSite && SUCCEEDED(hres))
2477 hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (LPVOID*)&pOleObject);
2478 if (SUCCEEDED(hres))
2480 DWORD dwStatus;
2481 IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
2485 if (SUCCEEDED(hres))
2487 IPersistStorage * pPS;
2488 if (SUCCEEDED((hres = IUnknown_QueryInterface(pUnk, &IID_IPersistStorage, (LPVOID*)&pPS))))
2490 TRACE("trying to set stg %p\n", pStg);
2491 hres = IPersistStorage_InitNew(pPS, pStg);
2492 TRACE("-- result %#lx\n", hres);
2493 IPersistStorage_Release(pPS);
2497 if (pClientSite && SUCCEEDED(hres))
2499 TRACE("trying to set clientsite %p\n", pClientSite);
2500 hres = IOleObject_SetClientSite(pOleObject, pClientSite);
2501 TRACE("-- result %#lx\n", hres);
2504 if (pOleObject)
2505 IOleObject_Release(pOleObject);
2507 if (((renderopt == OLERENDER_DRAW) || (renderopt == OLERENDER_FORMAT)) &&
2508 SUCCEEDED(hres))
2510 hres = OleRun(pUnk);
2511 if (SUCCEEDED(hres))
2513 IOleCache *pOleCache;
2515 if (SUCCEEDED(IUnknown_QueryInterface(pUnk, &IID_IOleCache, (void **)&pOleCache)))
2517 DWORD dwConnection;
2518 if (renderopt == OLERENDER_DRAW && !pFormatEtc) {
2519 FORMATETC pfe;
2520 pfe.cfFormat = 0;
2521 pfe.ptd = NULL;
2522 pfe.dwAspect = DVASPECT_CONTENT;
2523 pfe.lindex = -1;
2524 pfe.tymed = TYMED_NULL;
2525 hres = IOleCache_Cache(pOleCache, &pfe, ADVF_PRIMEFIRST, &dwConnection);
2527 else
2528 hres = IOleCache_Cache(pOleCache, pFormatEtc, ADVF_PRIMEFIRST, &dwConnection);
2529 IOleCache_Release(pOleCache);
2534 if (FAILED(hres) && pUnk)
2536 IUnknown_Release(pUnk);
2537 pUnk = NULL;
2540 *ppvObj = pUnk;
2542 TRACE("-- %p\n", pUnk);
2543 return hres;
2546 /******************************************************************************
2547 * OleGetAutoConvert [OLE32.@]
2549 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2551 HKEY hkey = NULL;
2552 WCHAR buf[CHARS_IN_GUID];
2553 LONG len;
2554 HRESULT res = S_OK;
2556 res = COM_OpenKeyForCLSID(clsidOld, L"AutoConvertTo", KEY_READ, &hkey);
2557 if (FAILED(res))
2558 goto done;
2560 len = sizeof(buf);
2561 if (RegQueryValueW(hkey, NULL, buf, &len))
2563 res = REGDB_E_KEYMISSING;
2564 goto done;
2566 res = CLSIDFromString(buf, pClsidNew);
2567 done:
2568 if (hkey) RegCloseKey(hkey);
2569 return res;
2572 /******************************************************************************
2573 * OleSetAutoConvert [OLE32.@]
2575 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
2577 HKEY hkey = NULL;
2578 WCHAR szClsidNew[CHARS_IN_GUID];
2579 HRESULT res = S_OK;
2581 TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
2583 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2584 if (FAILED(res))
2585 goto done;
2586 StringFromGUID2(clsidNew, szClsidNew, CHARS_IN_GUID);
2587 if (RegSetValueW(hkey, L"AutoConvertTo", REG_SZ, szClsidNew, (lstrlenW(szClsidNew)+1) * sizeof(WCHAR)))
2589 res = REGDB_E_WRITEREGDB;
2590 goto done;
2593 done:
2594 if (hkey) RegCloseKey(hkey);
2595 return res;
2598 /******************************************************************************
2599 * OleDoAutoConvert [OLE32.@]
2601 HRESULT WINAPI OleDoAutoConvert(LPSTORAGE pStg, LPCLSID pClsidNew)
2603 WCHAR *user_type_old, *user_type_new;
2604 CLIPFORMAT cf;
2605 STATSTG stat;
2606 CLSID clsid;
2607 HRESULT hr;
2609 TRACE("(%p, %p)\n", pStg, pClsidNew);
2611 *pClsidNew = CLSID_NULL;
2612 if(!pStg)
2613 return E_INVALIDARG;
2614 hr = IStorage_Stat(pStg, &stat, STATFLAG_NONAME);
2615 if(FAILED(hr))
2616 return hr;
2618 *pClsidNew = stat.clsid;
2619 hr = OleGetAutoConvert(&stat.clsid, &clsid);
2620 if(FAILED(hr))
2621 return hr;
2623 hr = IStorage_SetClass(pStg, &clsid);
2624 if(FAILED(hr))
2625 return hr;
2627 hr = ReadFmtUserTypeStg(pStg, &cf, &user_type_old);
2628 if(FAILED(hr)) {
2629 cf = 0;
2630 user_type_new = NULL;
2633 hr = OleRegGetUserType(&clsid, USERCLASSTYPE_FULL, &user_type_new);
2634 if(FAILED(hr))
2635 user_type_new = NULL;
2637 hr = WriteFmtUserTypeStg(pStg, cf, user_type_new);
2638 CoTaskMemFree(user_type_new);
2639 if(FAILED(hr))
2641 CoTaskMemFree(user_type_old);
2642 IStorage_SetClass(pStg, &stat.clsid);
2643 return hr;
2646 hr = SetConvertStg(pStg, TRUE);
2647 if(FAILED(hr))
2649 WriteFmtUserTypeStg(pStg, cf, user_type_old);
2650 IStorage_SetClass(pStg, &stat.clsid);
2652 else
2653 *pClsidNew = clsid;
2654 CoTaskMemFree(user_type_old);
2655 return hr;
2658 /******************************************************************************
2659 * OleIsRunning [OLE32.@]
2661 BOOL WINAPI OleIsRunning(LPOLEOBJECT object)
2663 IRunnableObject *pRunnable;
2664 HRESULT hr;
2665 BOOL running;
2667 TRACE("(%p)\n", object);
2669 if (!object) return FALSE;
2671 hr = IOleObject_QueryInterface(object, &IID_IRunnableObject, (void **)&pRunnable);
2672 if (FAILED(hr))
2673 return TRUE;
2674 running = IRunnableObject_IsRunning(pRunnable);
2675 IRunnableObject_Release(pRunnable);
2676 return running;
2679 /***********************************************************************
2680 * OleNoteObjectVisible [OLE32.@]
2682 HRESULT WINAPI OleNoteObjectVisible(LPUNKNOWN pUnknown, BOOL bVisible)
2684 TRACE("(%p, %s)\n", pUnknown, bVisible ? "TRUE" : "FALSE");
2685 return CoLockObjectExternal(pUnknown, bVisible, TRUE);
2688 /***********************************************************************
2689 * PropSysAllocString [OLE32.@]
2690 * NOTES
2691 * Forward to oleaut32.
2693 BSTR WINAPI PropSysAllocString(LPCOLESTR str)
2695 return SysAllocString(str);
2698 /***********************************************************************
2699 * PropSysFreeString [OLE32.@]
2700 * NOTES
2701 * Forward to oleaut32.
2703 void WINAPI PropSysFreeString(LPOLESTR str)
2705 SysFreeString(str);
2708 /******************************************************************************
2709 * OleQueryCreateFromData [OLE32.@]
2711 * Checks whether an object can become an embedded object.
2712 * the clipboard or OLE drag and drop.
2713 * Returns : S_OK - Format that supports Embedded object creation are present.
2714 * OLE_E_STATIC - Format that supports static object creation are present.
2715 * S_FALSE - No acceptable format is available.
2718 HRESULT WINAPI OleQueryCreateFromData(IDataObject *data)
2720 IEnumFORMATETC *enum_fmt;
2721 FORMATETC fmt;
2722 BOOL found_static = FALSE;
2723 HRESULT hr;
2725 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
2727 if(FAILED(hr)) return hr;
2731 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
2732 if(hr == S_OK)
2734 if(fmt.cfFormat == embedded_object_clipboard_format ||
2735 fmt.cfFormat == embed_source_clipboard_format ||
2736 fmt.cfFormat == filename_clipboard_format)
2738 IEnumFORMATETC_Release(enum_fmt);
2739 return S_OK;
2742 if(fmt.cfFormat == CF_METAFILEPICT ||
2743 fmt.cfFormat == CF_BITMAP ||
2744 fmt.cfFormat == CF_DIB)
2745 found_static = TRUE;
2747 } while (hr == S_OK);
2749 IEnumFORMATETC_Release(enum_fmt);
2751 return found_static ? OLE_S_STATIC : S_FALSE;
2754 static inline void init_fmtetc(FORMATETC *fmt, CLIPFORMAT cf, TYMED tymed)
2756 fmt->cfFormat = cf;
2757 fmt->ptd = NULL;
2758 fmt->dwAspect = DVASPECT_CONTENT;
2759 fmt->lindex = -1;
2760 fmt->tymed = tymed;
2763 /***************************************************************************
2764 * get_storage
2766 * Retrieve an object's storage from a variety of sources.
2768 * FIXME: CF_FILENAME.
2770 static HRESULT get_storage(IDataObject *data, IStorage *stg, UINT *src_cf, BOOL other_fmts)
2772 static const UINT fmt_id[] = { CF_METAFILEPICT, CF_BITMAP, CF_DIB };
2773 UINT i;
2774 HRESULT hr;
2775 FORMATETC fmt;
2776 STGMEDIUM med;
2777 IPersistStorage *persist;
2778 CLSID clsid;
2780 if (src_cf) *src_cf = 0;
2782 /* CF_EMBEDEDOBJECT */
2783 init_fmtetc(&fmt, embedded_object_clipboard_format, TYMED_ISTORAGE);
2784 med.tymed = TYMED_ISTORAGE;
2785 med.u.pstg = stg;
2786 med.pUnkForRelease = NULL;
2787 hr = IDataObject_GetDataHere(data, &fmt, &med);
2788 if(SUCCEEDED(hr))
2790 if (src_cf) *src_cf = embedded_object_clipboard_format;
2791 return hr;
2794 /* CF_EMBEDSOURCE */
2795 init_fmtetc(&fmt, embed_source_clipboard_format, TYMED_ISTORAGE);
2796 med.tymed = TYMED_ISTORAGE;
2797 med.u.pstg = stg;
2798 med.pUnkForRelease = NULL;
2799 hr = IDataObject_GetDataHere(data, &fmt, &med);
2800 if(SUCCEEDED(hr))
2802 if (src_cf) *src_cf = embed_source_clipboard_format;
2803 return hr;
2806 if (other_fmts)
2808 for (i = 0; i < ARRAY_SIZE(fmt_id); i++)
2810 init_fmtetc(&fmt, fmt_id[i], TYMED_ISTORAGE);
2811 hr = IDataObject_QueryGetData(data, &fmt);
2812 if (SUCCEEDED(hr))
2814 if (src_cf) *src_cf = fmt_id[i];
2815 return hr;
2820 /* IPersistStorage */
2821 hr = IDataObject_QueryInterface(data, &IID_IPersistStorage, (void**)&persist);
2822 if(FAILED(hr)) return hr;
2824 hr = IPersistStorage_GetClassID(persist, &clsid);
2825 if(FAILED(hr)) goto end;
2827 hr = IStorage_SetClass(stg, &clsid);
2828 if(FAILED(hr)) goto end;
2830 hr = IPersistStorage_Save(persist, stg, FALSE);
2831 if(FAILED(hr)) goto end;
2833 hr = IPersistStorage_SaveCompleted(persist, NULL);
2835 end:
2836 IPersistStorage_Release(persist);
2838 return hr;
2841 /******************************************************************************
2842 * OleCreateFromDataEx [OLE32.@]
2844 * Creates an embedded object from data transfer object retrieved from
2845 * the clipboard or OLE drag and drop.
2847 HRESULT WINAPI OleCreateFromDataEx(IDataObject *data, REFIID iid, DWORD flags,
2848 DWORD renderopt, ULONG num_cache_fmts, DWORD *adv_flags, FORMATETC *cache_fmts,
2849 IAdviseSink *sink, DWORD *conns,
2850 IOleClientSite *client_site, IStorage *stg, void **obj)
2852 HRESULT hr;
2853 UINT src_cf;
2855 FIXME("%p, %s, %#lx, %#lx, %ld, %p, %p, %p, %p, %p, %p, %p: stub\n",
2856 data, debugstr_guid(iid), flags, renderopt, num_cache_fmts, adv_flags, cache_fmts,
2857 sink, conns, client_site, stg, obj);
2859 hr = get_storage(data, stg, &src_cf, TRUE);
2860 if(FAILED(hr)) return hr;
2862 hr = OleLoad(stg, iid, client_site, obj);
2863 if(FAILED(hr)) return hr;
2865 /* FIXME: Init cache */
2867 return hr;
2870 /******************************************************************************
2871 * OleCreateFromData [OLE32.@]
2873 HRESULT WINAPI OleCreateFromData(IDataObject *data, REFIID iid, DWORD renderopt, FORMATETC *fmt,
2874 IOleClientSite *client_site, IStorage *stg, void **obj)
2876 DWORD advf = ADVF_PRIMEFIRST;
2878 return OleCreateFromDataEx(data, iid, 0, renderopt, fmt ? 1 : 0, fmt ? &advf : NULL,
2879 fmt, NULL, NULL, client_site, stg, obj);
2882 /******************************************************************************
2883 * OleCreateLinkFromData [OLE32.@]
2885 HRESULT WINAPI OleCreateLinkFromData(IDataObject *data, REFIID iid, DWORD renderopt, FORMATETC *fmt,
2886 IOleClientSite *client_site, IStorage *stg, void **obj)
2888 FIXME("%p, %s, %#lx, %p, %p, %p, %p: semi-stub\n",
2889 data, debugstr_guid(iid), renderopt, fmt, client_site, stg, obj);
2890 return OleCreateFromData(data, iid, renderopt, fmt, client_site, stg, obj);
2893 /******************************************************************************
2894 * OleCreateStaticFromData [OLE32.@]
2896 HRESULT WINAPI OleCreateStaticFromData(IDataObject *data, REFIID iid, DWORD renderopt, FORMATETC *fmt,
2897 IOleClientSite *client_site, IStorage *stg, void **obj)
2899 HRESULT hr;
2900 CLSID clsid;
2901 IOleObject * ole_object = NULL;
2902 IOleCache2 *ole_cache = NULL;
2903 IPersistStorage *persist = NULL;
2904 DWORD connection;
2905 STGMEDIUM stgmedium;
2906 LPOLESTR ole_typename;
2908 TRACE("%p, %s, %#lx, %p, %p, %p, %p.\n", 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 %ld, render opts %ld, num fmts %ld, 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%ld: fmt %s adv flags %ld\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;