msvcp60: Export more complex numbers operators.
[wine.git] / dlls / ole32 / ole2.c
blob7929d3d6f2f138d918ff7631a72a15add3ffc356
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 2005 Juan Lang
9 * Copyright 2011 Adam Martinson for CodeWeavers
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
28 #include <assert.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <string.h>
34 #define COBJMACROS
35 #define NONAMELESSUNION
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winerror.h"
40 #include "wingdi.h"
41 #include "winuser.h"
42 #include "winnls.h"
43 #include "winreg.h"
44 #include "ole2.h"
45 #include "ole2ver.h"
47 #include "wine/unicode.h"
48 #include "compobj_private.h"
49 #include "wine/list.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(ole);
54 WINE_DECLARE_DEBUG_CHANNEL(accel);
56 /******************************************************************************
57 * These are static/global variables and internal data structures that the
58 * OLE module uses to maintain its state.
60 typedef struct tagTrackerWindowInfo
62 IDataObject* dataObject;
63 IDropSource* dropSource;
64 DWORD dwOKEffect;
65 DWORD* pdwEffect;
66 BOOL trackingDone;
67 HRESULT returnValue;
69 BOOL escPressed;
70 HWND curTargetHWND; /* window the mouse is hovering over */
71 HWND curDragTargetHWND; /* might be an ancestor of curTargetHWND */
72 IDropTarget* curDragTarget;
73 POINTL curMousePos; /* current position of the mouse in screen coordinates */
74 DWORD dwKeyState; /* current state of the shift and ctrl keys and the mouse buttons */
75 } TrackerWindowInfo;
77 typedef struct tagOleMenuDescriptor /* OleMenuDescriptor */
79 HWND hwndFrame; /* The containers frame window */
80 HWND hwndActiveObject; /* The active objects window */
81 OLEMENUGROUPWIDTHS mgw; /* OLE menu group widths for the shared menu */
82 HMENU hmenuCombined; /* The combined menu */
83 BOOL bIsServerItem; /* True if the currently open popup belongs to the server */
84 } OleMenuDescriptor;
86 typedef struct tagOleMenuHookItem /* OleMenu hook item in per thread hook list */
88 DWORD tid; /* Thread Id */
89 HANDLE hHeap; /* Heap this is allocated from */
90 HHOOK GetMsg_hHook; /* message hook for WH_GETMESSAGE */
91 HHOOK CallWndProc_hHook; /* message hook for WH_CALLWNDPROC */
92 struct tagOleMenuHookItem *next;
93 } OleMenuHookItem;
95 static OleMenuHookItem *hook_list;
98 * This is the lock count on the OLE library. It is controlled by the
99 * OLEInitialize/OLEUninitialize methods.
101 static LONG OLE_moduleLockCount = 0;
104 * Name of our registered window class.
106 static const WCHAR OLEDD_DRAGTRACKERCLASS[] =
107 {'W','i','n','e','D','r','a','g','D','r','o','p','T','r','a','c','k','e','r','3','2',0};
110 * Name of menu descriptor property.
112 static const WCHAR prop_olemenuW[] =
113 {'P','R','O','P','_','O','L','E','M','e','n','u','D','e','s','c','r','i','p','t','o','r',0};
115 /* property to store IDropTarget pointer */
116 static const WCHAR prop_oledroptarget[] =
117 {'O','l','e','D','r','o','p','T','a','r','g','e','t','I','n','t','e','r','f','a','c','e',0};
119 /* property to store Marshalled IDropTarget pointer */
120 static const WCHAR prop_marshalleddroptarget[] =
121 {'W','i','n','e','M','a','r','s','h','a','l','l','e','d','D','r','o','p','T','a','r','g','e','t',0};
123 static const WCHAR emptyW[] = { 0 };
125 /******************************************************************************
126 * These are the prototypes of miscellaneous utility methods
128 static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue);
130 /******************************************************************************
131 * These are the prototypes of the utility methods used to manage a shared menu
133 static void OLEMenu_Initialize(void);
134 static void OLEMenu_UnInitialize(void);
135 static BOOL OLEMenu_InstallHooks( DWORD tid );
136 static BOOL OLEMenu_UnInstallHooks( DWORD tid );
137 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid );
138 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
139 static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor );
140 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam);
141 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam);
143 /******************************************************************************
144 * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c)
146 extern void OLEClipbrd_UnInitialize(void);
147 extern void OLEClipbrd_Initialize(void);
149 /******************************************************************************
150 * These are the prototypes of the utility methods used for OLE Drag n Drop
152 static void OLEDD_Initialize(void);
153 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
154 static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo);
155 static DWORD OLEDD_GetButtonState(void);
157 /******************************************************************************
158 * OleBuildVersion [OLE32.@]
160 DWORD WINAPI OleBuildVersion(void)
162 TRACE("Returning version %d, build %d.\n", rmm, rup);
163 return (rmm<<16)+rup;
166 /***********************************************************************
167 * OleInitialize (OLE32.@)
169 HRESULT WINAPI DECLSPEC_HOTPATCH OleInitialize(LPVOID reserved)
171 HRESULT hr;
173 TRACE("(%p)\n", reserved);
176 * The first duty of the OleInitialize is to initialize the COM libraries.
178 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
181 * If the CoInitializeEx call failed, the OLE libraries can't be
182 * initialized.
184 if (FAILED(hr))
185 return hr;
187 if (!COM_CurrentInfo()->ole_inits)
188 hr = S_OK;
191 * Then, it has to initialize the OLE specific modules.
192 * This includes:
193 * Clipboard
194 * Drag and Drop
195 * Object linking and Embedding
196 * In-place activation
198 if (!COM_CurrentInfo()->ole_inits++ &&
199 InterlockedIncrement(&OLE_moduleLockCount) == 1)
202 * Initialize the libraries.
204 TRACE("() - Initializing the OLE libraries\n");
207 * OLE Clipboard
209 OLEClipbrd_Initialize();
212 * Drag and Drop
214 OLEDD_Initialize();
217 * OLE shared menu
219 OLEMenu_Initialize();
222 return hr;
225 /******************************************************************************
226 * OleUninitialize [OLE32.@]
228 void WINAPI DECLSPEC_HOTPATCH OleUninitialize(void)
230 TRACE("()\n");
233 * If we hit the bottom of the lock stack, free the libraries.
235 if (!--COM_CurrentInfo()->ole_inits && !InterlockedDecrement(&OLE_moduleLockCount))
238 * Actually free the libraries.
240 TRACE("() - Freeing the last reference count\n");
243 * OLE Clipboard
245 OLEClipbrd_UnInitialize();
248 * OLE shared menu
250 OLEMenu_UnInitialize();
254 * Then, uninitialize the COM libraries.
256 CoUninitialize();
259 /******************************************************************************
260 * OleInitializeWOW [OLE32.@]
262 HRESULT WINAPI OleInitializeWOW(DWORD x, DWORD y) {
263 FIXME("(0x%08x, 0x%08x),stub!\n",x, y);
264 return 0;
267 /*************************************************************
268 * get_droptarget_handle
270 * Retrieve a handle to the map containing the marshalled IDropTarget.
271 * This handle belongs to the process that called RegisterDragDrop.
272 * See get_droptarget_local_handle().
274 static inline HANDLE get_droptarget_handle(HWND hwnd)
276 return GetPropW(hwnd, prop_marshalleddroptarget);
279 /*************************************************************
280 * is_droptarget
282 * Is the window a droptarget.
284 static inline BOOL is_droptarget(HWND hwnd)
286 return get_droptarget_handle(hwnd) != 0;
289 /*************************************************************
290 * get_droptarget_local_handle
292 * Retrieve a handle to the map containing the marshalled IDropTarget.
293 * The handle should be closed when finished with.
295 static HANDLE get_droptarget_local_handle(HWND hwnd)
297 HANDLE handle, local_handle = 0;
299 handle = get_droptarget_handle(hwnd);
301 if(handle)
303 DWORD pid;
304 HANDLE process;
306 GetWindowThreadProcessId(hwnd, &pid);
307 process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid);
308 if(process)
310 DuplicateHandle(process, handle, GetCurrentProcess(), &local_handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
311 CloseHandle(process);
314 return local_handle;
317 /***********************************************************************
318 * create_map_from_stream
320 * Helper for RegisterDragDrop. Creates a file mapping object
321 * with the contents of the provided stream. The stream must
322 * be a global memory backed stream.
324 static HRESULT create_map_from_stream(IStream *stream, HANDLE *map)
326 HGLOBAL hmem;
327 DWORD size;
328 HRESULT hr;
329 void *data;
331 hr = GetHGlobalFromStream(stream, &hmem);
332 if(FAILED(hr)) return hr;
334 size = GlobalSize(hmem);
335 *map = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, NULL);
336 if(!*map) return E_OUTOFMEMORY;
338 data = MapViewOfFile(*map, FILE_MAP_WRITE, 0, 0, size);
339 memcpy(data, GlobalLock(hmem), size);
340 GlobalUnlock(hmem);
341 UnmapViewOfFile(data);
342 return S_OK;
345 /***********************************************************************
346 * create_stream_from_map
348 * Creates a stream from the provided map.
350 static HRESULT create_stream_from_map(HANDLE map, IStream **stream)
352 HRESULT hr = E_OUTOFMEMORY;
353 HGLOBAL hmem;
354 void *data;
355 MEMORY_BASIC_INFORMATION info;
357 data = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
358 if(!data) return hr;
360 VirtualQuery(data, &info, sizeof(info));
361 TRACE("size %d\n", (int)info.RegionSize);
363 hmem = GlobalAlloc(GMEM_MOVEABLE, info.RegionSize);
364 if(hmem)
366 memcpy(GlobalLock(hmem), data, info.RegionSize);
367 GlobalUnlock(hmem);
368 hr = CreateStreamOnHGlobal(hmem, TRUE, stream);
370 UnmapViewOfFile(data);
371 return hr;
374 /* This is to work around apps which break COM rules by not implementing
375 * IDropTarget::QueryInterface(). Windows doesn't expose this because it
376 * doesn't call CoMarshallInterface() in RegisterDragDrop().
377 * The wrapper is only used internally, and only exists for the life of
378 * the marshal. We don't want to hold a ref on the app provided target
379 * as some apps destroy this prior to CoUninitialize without calling
380 * RevokeDragDrop. The only (long-term) ref is held by the window prop. */
381 typedef struct {
382 IDropTarget IDropTarget_iface;
383 HWND hwnd;
384 LONG refs;
385 } DropTargetWrapper;
387 static inline DropTargetWrapper* impl_from_IDropTarget(IDropTarget* iface)
389 return CONTAINING_RECORD(iface, DropTargetWrapper, IDropTarget_iface);
392 static HRESULT WINAPI DropTargetWrapper_QueryInterface(IDropTarget* iface,
393 REFIID riid,
394 void** ppvObject)
396 DropTargetWrapper* This = impl_from_IDropTarget(iface);
397 if (IsEqualIID(riid, &IID_IUnknown) ||
398 IsEqualIID(riid, &IID_IDropTarget))
400 IDropTarget_AddRef(&This->IDropTarget_iface);
401 *ppvObject = &This->IDropTarget_iface;
402 return S_OK;
404 *ppvObject = NULL;
405 return E_NOINTERFACE;
408 static ULONG WINAPI DropTargetWrapper_AddRef(IDropTarget* iface)
410 DropTargetWrapper* This = impl_from_IDropTarget(iface);
411 return InterlockedIncrement(&This->refs);
414 static ULONG WINAPI DropTargetWrapper_Release(IDropTarget* iface)
416 DropTargetWrapper* This = impl_from_IDropTarget(iface);
417 ULONG refs = InterlockedDecrement(&This->refs);
418 if (!refs) HeapFree(GetProcessHeap(), 0, This);
419 return refs;
422 static inline HRESULT get_target_from_wrapper( IDropTarget *wrapper, IDropTarget **target )
424 DropTargetWrapper* This = impl_from_IDropTarget( wrapper );
425 *target = GetPropW( This->hwnd, prop_oledroptarget );
426 if (!*target) return DRAGDROP_E_NOTREGISTERED;
427 IDropTarget_AddRef( *target );
428 return S_OK;
431 static HRESULT WINAPI DropTargetWrapper_DragEnter(IDropTarget* iface,
432 IDataObject* pDataObj,
433 DWORD grfKeyState,
434 POINTL pt,
435 DWORD* pdwEffect)
437 IDropTarget *target;
438 HRESULT r = get_target_from_wrapper( iface, &target );
440 if (SUCCEEDED( r ))
442 r = IDropTarget_DragEnter( target, pDataObj, grfKeyState, pt, pdwEffect );
443 IDropTarget_Release( target );
445 return r;
448 static HRESULT WINAPI DropTargetWrapper_DragOver(IDropTarget* iface,
449 DWORD grfKeyState,
450 POINTL pt,
451 DWORD* pdwEffect)
453 IDropTarget *target;
454 HRESULT r = get_target_from_wrapper( iface, &target );
456 if (SUCCEEDED( r ))
458 r = IDropTarget_DragOver( target, grfKeyState, pt, pdwEffect );
459 IDropTarget_Release( target );
461 return r;
464 static HRESULT WINAPI DropTargetWrapper_DragLeave(IDropTarget* iface)
466 IDropTarget *target;
467 HRESULT r = get_target_from_wrapper( iface, &target );
469 if (SUCCEEDED( r ))
471 r = IDropTarget_DragLeave( target );
472 IDropTarget_Release( target );
474 return r;
477 static HRESULT WINAPI DropTargetWrapper_Drop(IDropTarget* iface,
478 IDataObject* pDataObj,
479 DWORD grfKeyState,
480 POINTL pt,
481 DWORD* pdwEffect)
483 IDropTarget *target;
484 HRESULT r = get_target_from_wrapper( iface, &target );
486 if (SUCCEEDED( r ))
488 r = IDropTarget_Drop( target, pDataObj, grfKeyState, pt, pdwEffect );
489 IDropTarget_Release( target );
491 return r;
494 static const IDropTargetVtbl DropTargetWrapperVTbl =
496 DropTargetWrapper_QueryInterface,
497 DropTargetWrapper_AddRef,
498 DropTargetWrapper_Release,
499 DropTargetWrapper_DragEnter,
500 DropTargetWrapper_DragOver,
501 DropTargetWrapper_DragLeave,
502 DropTargetWrapper_Drop
505 static IDropTarget* WrapDropTarget( HWND hwnd )
507 DropTargetWrapper* This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
509 if (This)
511 This->IDropTarget_iface.lpVtbl = &DropTargetWrapperVTbl;
512 This->hwnd = hwnd;
513 This->refs = 1;
515 return &This->IDropTarget_iface;
518 /***********************************************************************
519 * get_droptarget_pointer
521 * Retrieves the marshalled IDropTarget from the window.
523 static IDropTarget* get_droptarget_pointer(HWND hwnd)
525 IDropTarget *droptarget = NULL;
526 HANDLE map;
527 IStream *stream;
529 map = get_droptarget_local_handle(hwnd);
530 if(!map) return NULL;
532 if(SUCCEEDED(create_stream_from_map(map, &stream)))
534 CoUnmarshalInterface(stream, &IID_IDropTarget, (void**)&droptarget);
535 IStream_Release(stream);
537 CloseHandle(map);
538 return droptarget;
541 /***********************************************************************
542 * RegisterDragDrop (OLE32.@)
544 HRESULT WINAPI RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget)
546 DWORD pid = 0;
547 HRESULT hr;
548 IStream *stream;
549 HANDLE map;
550 IDropTarget *wrapper;
552 TRACE("(%p,%p)\n", hwnd, pDropTarget);
554 if (!COM_CurrentApt())
556 ERR("COM not initialized\n");
557 return E_OUTOFMEMORY;
560 if (!pDropTarget)
561 return E_INVALIDARG;
563 if (!IsWindow(hwnd))
565 ERR("invalid hwnd %p\n", hwnd);
566 return DRAGDROP_E_INVALIDHWND;
569 /* block register for other processes windows */
570 GetWindowThreadProcessId(hwnd, &pid);
571 if (pid != GetCurrentProcessId())
573 FIXME("register for another process windows is disabled\n");
574 return DRAGDROP_E_INVALIDHWND;
577 /* check if the window is already registered */
578 if (is_droptarget(hwnd))
579 return DRAGDROP_E_ALREADYREGISTERED;
582 * Marshal the drop target pointer into a shared memory map and
583 * store the map's handle in a Wine specific window prop. We also
584 * store the drop target pointer itself in the
585 * "OleDropTargetInterface" prop for compatibility with Windows.
588 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
589 if(FAILED(hr)) return hr;
591 /* IDropTarget::QueryInterface() shouldn't be called, some (broken) apps depend on this. */
592 wrapper = WrapDropTarget( hwnd );
593 if(!wrapper)
595 IStream_Release(stream);
596 return E_OUTOFMEMORY;
598 hr = CoMarshalInterface(stream, &IID_IDropTarget, (IUnknown*)wrapper, MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
599 IDropTarget_Release(wrapper);
601 if(SUCCEEDED(hr))
603 hr = create_map_from_stream(stream, &map);
604 if(SUCCEEDED(hr))
606 IDropTarget_AddRef(pDropTarget);
607 SetPropW(hwnd, prop_oledroptarget, pDropTarget);
608 SetPropW(hwnd, prop_marshalleddroptarget, map);
610 else
612 LARGE_INTEGER zero;
613 zero.QuadPart = 0;
614 IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
615 CoReleaseMarshalData(stream);
618 IStream_Release(stream);
620 return hr;
623 /***********************************************************************
624 * RevokeDragDrop (OLE32.@)
626 HRESULT WINAPI RevokeDragDrop(HWND hwnd)
628 HANDLE map;
629 IStream *stream;
630 IDropTarget *drop_target;
631 HRESULT hr;
633 TRACE("(%p)\n", hwnd);
635 if (!IsWindow(hwnd))
637 ERR("invalid hwnd %p\n", hwnd);
638 return DRAGDROP_E_INVALIDHWND;
641 /* no registration data */
642 if (!(map = get_droptarget_handle(hwnd)))
643 return DRAGDROP_E_NOTREGISTERED;
645 drop_target = GetPropW(hwnd, prop_oledroptarget);
646 if(drop_target) IDropTarget_Release(drop_target);
648 RemovePropW(hwnd, prop_oledroptarget);
649 RemovePropW(hwnd, prop_marshalleddroptarget);
651 hr = create_stream_from_map(map, &stream);
652 if(SUCCEEDED(hr))
654 CoReleaseMarshalData(stream);
655 IStream_Release(stream);
657 CloseHandle(map);
659 return hr;
662 /***********************************************************************
663 * OleRegGetUserType (OLE32.@)
665 HRESULT WINAPI OleRegGetUserType(REFCLSID clsid, DWORD form, LPOLESTR *usertype)
667 static const WCHAR auxusertypeW[] = {'A','u','x','U','s','e','r','T','y','p','e','\\','%','d',0};
668 DWORD valuetype, valuelen;
669 WCHAR auxkeynameW[16];
670 HKEY usertypekey;
671 HRESULT hres;
672 LONG ret;
674 TRACE("(%s, %u, %p)\n", debugstr_guid(clsid), form, usertype);
676 if (!usertype)
677 return E_INVALIDARG;
679 *usertype = NULL;
681 /* Return immediately if it's not registered. */
682 hres = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &usertypekey);
683 if (FAILED(hres))
684 return hres;
686 valuelen = 0;
688 /* Try additional types if requested. If they don't exist fall back to USERCLASSTYPE_FULL. */
689 if (form != USERCLASSTYPE_FULL)
691 HKEY auxkey;
693 sprintfW(auxkeynameW, auxusertypeW, form);
694 if (COM_OpenKeyForCLSID(clsid, auxkeynameW, KEY_READ, &auxkey) == S_OK)
696 if (!RegQueryValueExW(auxkey, emptyW, NULL, &valuetype, NULL, &valuelen) && valuelen)
698 RegCloseKey(usertypekey);
699 usertypekey = auxkey;
701 else
702 RegCloseKey(auxkey);
706 valuelen = 0;
707 if (RegQueryValueExW(usertypekey, emptyW, NULL, &valuetype, NULL, &valuelen))
709 RegCloseKey(usertypekey);
710 return REGDB_E_READREGDB;
713 *usertype = CoTaskMemAlloc(valuelen);
714 if (!*usertype)
716 RegCloseKey(usertypekey);
717 return E_OUTOFMEMORY;
720 ret = RegQueryValueExW(usertypekey,
721 emptyW,
722 NULL,
723 &valuetype,
724 (LPBYTE)*usertype,
725 &valuelen);
726 RegCloseKey(usertypekey);
727 if (ret != ERROR_SUCCESS)
729 CoTaskMemFree(*usertype);
730 *usertype = NULL;
731 return REGDB_E_READREGDB;
734 return S_OK;
737 /***********************************************************************
738 * DoDragDrop [OLE32.@]
740 HRESULT WINAPI DoDragDrop (
741 IDataObject *pDataObject, /* [in] ptr to the data obj */
742 IDropSource* pDropSource, /* [in] ptr to the source obj */
743 DWORD dwOKEffect, /* [in] effects allowed by the source */
744 DWORD *pdwEffect) /* [out] ptr to effects of the source */
746 static const WCHAR trackerW[] = {'T','r','a','c','k','e','r','W','i','n','d','o','w',0};
747 TrackerWindowInfo trackerInfo;
748 HWND hwndTrackWindow;
749 MSG msg;
751 TRACE("(%p, %p, %08x, %p)\n", pDataObject, pDropSource, dwOKEffect, pdwEffect);
753 if (!pDataObject || !pDropSource || !pdwEffect)
754 return E_INVALIDARG;
757 * Setup the drag n drop tracking window.
760 trackerInfo.dataObject = pDataObject;
761 trackerInfo.dropSource = pDropSource;
762 trackerInfo.dwOKEffect = dwOKEffect;
763 trackerInfo.pdwEffect = pdwEffect;
764 trackerInfo.trackingDone = FALSE;
765 trackerInfo.escPressed = FALSE;
766 trackerInfo.curDragTargetHWND = 0;
767 trackerInfo.curTargetHWND = 0;
768 trackerInfo.curDragTarget = 0;
770 hwndTrackWindow = CreateWindowW(OLEDD_DRAGTRACKERCLASS, trackerW,
771 WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
772 CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0,
773 &trackerInfo);
775 if (hwndTrackWindow)
778 * Capture the mouse input
780 SetCapture(hwndTrackWindow);
782 msg.message = 0;
785 * Pump messages. All mouse input should go to the capture window.
787 while (!trackerInfo.trackingDone && GetMessageW(&msg, 0, 0, 0) )
789 trackerInfo.curMousePos.x = msg.pt.x;
790 trackerInfo.curMousePos.y = msg.pt.y;
791 trackerInfo.dwKeyState = OLEDD_GetButtonState();
793 if ( (msg.message >= WM_KEYFIRST) &&
794 (msg.message <= WM_KEYLAST) )
797 * When keyboard messages are sent to windows on this thread, we
798 * want to ignore notify the drop source that the state changed.
799 * in the case of the Escape key, we also notify the drop source
800 * we give it a special meaning.
802 if ( (msg.message==WM_KEYDOWN) &&
803 (msg.wParam==VK_ESCAPE) )
805 trackerInfo.escPressed = TRUE;
809 * Notify the drop source.
811 OLEDD_TrackStateChange(&trackerInfo);
813 else
816 * Dispatch the messages only when it's not a keyboard message.
818 DispatchMessageW(&msg);
822 /* re-post the quit message to outer message loop */
823 if (msg.message == WM_QUIT)
824 PostQuitMessage(msg.wParam);
826 * Destroy the temporary window.
828 DestroyWindow(hwndTrackWindow);
830 return trackerInfo.returnValue;
833 return E_FAIL;
836 /***********************************************************************
837 * OleQueryLinkFromData [OLE32.@]
839 HRESULT WINAPI OleQueryLinkFromData(
840 IDataObject* pSrcDataObject)
842 FIXME("(%p),stub!\n", pSrcDataObject);
843 return S_FALSE;
846 /***********************************************************************
847 * OleRegGetMiscStatus [OLE32.@]
849 HRESULT WINAPI OleRegGetMiscStatus(
850 REFCLSID clsid,
851 DWORD dwAspect,
852 DWORD* pdwStatus)
854 static const WCHAR miscstatusW[] = {'M','i','s','c','S','t','a','t','u','s',0};
855 static const WCHAR dfmtW[] = {'%','d',0};
856 WCHAR keyName[16];
857 HKEY miscStatusKey;
858 HKEY aspectKey;
859 LONG result;
860 HRESULT hr;
862 TRACE("(%s, %d, %p)\n", debugstr_guid(clsid), dwAspect, pdwStatus);
864 if (!pdwStatus) return E_INVALIDARG;
866 *pdwStatus = 0;
868 if (actctx_get_miscstatus(clsid, dwAspect, pdwStatus)) return S_OK;
870 hr = COM_OpenKeyForCLSID(clsid, miscstatusW, KEY_READ, &miscStatusKey);
871 if (FAILED(hr))
872 /* missing key is not a failure */
873 return hr == REGDB_E_KEYMISSING ? S_OK : hr;
875 OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
878 * Open the key specific to the requested aspect.
880 sprintfW(keyName, dfmtW, dwAspect);
882 result = open_classes_key(miscStatusKey, keyName, KEY_READ, &aspectKey);
883 if (result == ERROR_SUCCESS)
885 OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
886 RegCloseKey(aspectKey);
889 RegCloseKey(miscStatusKey);
890 return S_OK;
893 static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum);
895 typedef struct
897 IEnumOLEVERB IEnumOLEVERB_iface;
898 LONG ref;
900 HKEY hkeyVerb;
901 ULONG index;
902 } EnumOLEVERB;
904 static inline EnumOLEVERB *impl_from_IEnumOLEVERB(IEnumOLEVERB *iface)
906 return CONTAINING_RECORD(iface, EnumOLEVERB, IEnumOLEVERB_iface);
909 static HRESULT WINAPI EnumOLEVERB_QueryInterface(
910 IEnumOLEVERB *iface, REFIID riid, void **ppv)
912 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
913 if (IsEqualIID(riid, &IID_IUnknown) ||
914 IsEqualIID(riid, &IID_IEnumOLEVERB))
916 IEnumOLEVERB_AddRef(iface);
917 *ppv = iface;
918 return S_OK;
920 return E_NOINTERFACE;
923 static ULONG WINAPI EnumOLEVERB_AddRef(
924 IEnumOLEVERB *iface)
926 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
927 TRACE("()\n");
928 return InterlockedIncrement(&This->ref);
931 static ULONG WINAPI EnumOLEVERB_Release(
932 IEnumOLEVERB *iface)
934 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
935 LONG refs = InterlockedDecrement(&This->ref);
936 TRACE("()\n");
937 if (!refs)
939 RegCloseKey(This->hkeyVerb);
940 HeapFree(GetProcessHeap(), 0, This);
942 return refs;
945 static HRESULT WINAPI EnumOLEVERB_Next(
946 IEnumOLEVERB *iface, ULONG celt, LPOLEVERB rgelt,
947 ULONG *pceltFetched)
949 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
950 HRESULT hr = S_OK;
952 TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched);
954 if (pceltFetched)
955 *pceltFetched = 0;
957 for (; celt; celt--, rgelt++)
959 WCHAR wszSubKey[20];
960 LONG cbData;
961 LPWSTR pwszOLEVERB;
962 LPWSTR pwszMenuFlags;
963 LPWSTR pwszAttribs;
964 LONG res = RegEnumKeyW(This->hkeyVerb, This->index, wszSubKey, sizeof(wszSubKey)/sizeof(wszSubKey[0]));
965 if (res == ERROR_NO_MORE_ITEMS)
967 hr = S_FALSE;
968 break;
970 else if (res != ERROR_SUCCESS)
972 ERR("RegEnumKeyW failed with error %d\n", res);
973 hr = REGDB_E_READREGDB;
974 break;
976 res = RegQueryValueW(This->hkeyVerb, wszSubKey, NULL, &cbData);
977 if (res != ERROR_SUCCESS)
979 ERR("RegQueryValueW failed with error %d\n", res);
980 hr = REGDB_E_READREGDB;
981 break;
983 pwszOLEVERB = CoTaskMemAlloc(cbData);
984 if (!pwszOLEVERB)
986 hr = E_OUTOFMEMORY;
987 break;
989 res = RegQueryValueW(This->hkeyVerb, wszSubKey, pwszOLEVERB, &cbData);
990 if (res != ERROR_SUCCESS)
992 ERR("RegQueryValueW failed with error %d\n", res);
993 hr = REGDB_E_READREGDB;
994 CoTaskMemFree(pwszOLEVERB);
995 break;
998 TRACE("verb string: %s\n", debugstr_w(pwszOLEVERB));
999 pwszMenuFlags = strchrW(pwszOLEVERB, ',');
1000 if (!pwszMenuFlags)
1002 hr = OLEOBJ_E_INVALIDVERB;
1003 CoTaskMemFree(pwszOLEVERB);
1004 break;
1006 /* nul terminate the name string and advance to first character */
1007 *pwszMenuFlags = '\0';
1008 pwszMenuFlags++;
1009 pwszAttribs = strchrW(pwszMenuFlags, ',');
1010 if (!pwszAttribs)
1012 hr = OLEOBJ_E_INVALIDVERB;
1013 CoTaskMemFree(pwszOLEVERB);
1014 break;
1016 /* nul terminate the menu string and advance to first character */
1017 *pwszAttribs = '\0';
1018 pwszAttribs++;
1020 /* fill out structure for this verb */
1021 rgelt->lVerb = atolW(wszSubKey);
1022 rgelt->lpszVerbName = pwszOLEVERB; /* user should free */
1023 rgelt->fuFlags = atolW(pwszMenuFlags);
1024 rgelt->grfAttribs = atolW(pwszAttribs);
1026 if (pceltFetched)
1027 (*pceltFetched)++;
1028 This->index++;
1030 return hr;
1033 static HRESULT WINAPI EnumOLEVERB_Skip(
1034 IEnumOLEVERB *iface, ULONG celt)
1036 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
1038 TRACE("(%d)\n", celt);
1040 This->index += celt;
1041 return S_OK;
1044 static HRESULT WINAPI EnumOLEVERB_Reset(
1045 IEnumOLEVERB *iface)
1047 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
1049 TRACE("()\n");
1051 This->index = 0;
1052 return S_OK;
1055 static HRESULT WINAPI EnumOLEVERB_Clone(
1056 IEnumOLEVERB *iface,
1057 IEnumOLEVERB **ppenum)
1059 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
1060 HKEY hkeyVerb;
1061 TRACE("(%p)\n", ppenum);
1062 if (!DuplicateHandle(GetCurrentProcess(), This->hkeyVerb, GetCurrentProcess(), (HANDLE *)&hkeyVerb, 0, FALSE, DUPLICATE_SAME_ACCESS))
1063 return HRESULT_FROM_WIN32(GetLastError());
1064 return EnumOLEVERB_Construct(hkeyVerb, This->index, ppenum);
1067 static const IEnumOLEVERBVtbl EnumOLEVERB_VTable =
1069 EnumOLEVERB_QueryInterface,
1070 EnumOLEVERB_AddRef,
1071 EnumOLEVERB_Release,
1072 EnumOLEVERB_Next,
1073 EnumOLEVERB_Skip,
1074 EnumOLEVERB_Reset,
1075 EnumOLEVERB_Clone
1078 static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum)
1080 EnumOLEVERB *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1081 if (!This)
1083 RegCloseKey(hkeyVerb);
1084 return E_OUTOFMEMORY;
1086 This->IEnumOLEVERB_iface.lpVtbl = &EnumOLEVERB_VTable;
1087 This->ref = 1;
1088 This->index = index;
1089 This->hkeyVerb = hkeyVerb;
1090 *ppenum = &This->IEnumOLEVERB_iface;
1091 return S_OK;
1094 /***********************************************************************
1095 * OleRegEnumVerbs [OLE32.@]
1097 * Enumerates verbs associated with a class stored in the registry.
1099 * PARAMS
1100 * clsid [I] Class ID to enumerate the verbs for.
1101 * ppenum [O] Enumerator.
1103 * RETURNS
1104 * S_OK: Success.
1105 * REGDB_E_CLASSNOTREG: The specified class does not have a key in the registry.
1106 * REGDB_E_READREGDB: The class key could not be opened for some other reason.
1107 * OLE_E_REGDB_KEY: The Verb subkey for the class is not present.
1108 * OLEOBJ_E_NOVERBS: The Verb subkey for the class is empty.
1110 HRESULT WINAPI OleRegEnumVerbs (REFCLSID clsid, LPENUMOLEVERB* ppenum)
1112 LONG res;
1113 HKEY hkeyVerb;
1114 DWORD dwSubKeys;
1115 static const WCHAR wszVerb[] = {'V','e','r','b',0};
1117 TRACE("(%s, %p)\n", debugstr_guid(clsid), ppenum);
1119 res = COM_OpenKeyForCLSID(clsid, wszVerb, KEY_READ, &hkeyVerb);
1120 if (FAILED(res))
1122 if (res == REGDB_E_CLASSNOTREG)
1123 ERR("CLSID %s not registered\n", debugstr_guid(clsid));
1124 else if (res == REGDB_E_KEYMISSING)
1125 ERR("no Verbs key for class %s\n", debugstr_guid(clsid));
1126 else
1127 ERR("failed to open Verbs key for CLSID %s with error %d\n",
1128 debugstr_guid(clsid), res);
1129 return res;
1132 res = RegQueryInfoKeyW(hkeyVerb, NULL, NULL, NULL, &dwSubKeys, NULL,
1133 NULL, NULL, NULL, NULL, NULL, NULL);
1134 if (res != ERROR_SUCCESS)
1136 ERR("failed to get subkey count with error %d\n", GetLastError());
1137 return REGDB_E_READREGDB;
1140 if (!dwSubKeys)
1142 WARN("class %s has no verbs\n", debugstr_guid(clsid));
1143 RegCloseKey(hkeyVerb);
1144 return OLEOBJ_E_NOVERBS;
1147 return EnumOLEVERB_Construct(hkeyVerb, 0, ppenum);
1150 /******************************************************************************
1151 * OleSetContainedObject [OLE32.@]
1153 HRESULT WINAPI OleSetContainedObject(
1154 LPUNKNOWN pUnknown,
1155 BOOL fContained)
1157 IRunnableObject* runnable = NULL;
1158 HRESULT hres;
1160 TRACE("(%p,%x)\n", pUnknown, fContained);
1162 hres = IUnknown_QueryInterface(pUnknown,
1163 &IID_IRunnableObject,
1164 (void**)&runnable);
1166 if (SUCCEEDED(hres))
1168 hres = IRunnableObject_SetContainedObject(runnable, fContained);
1170 IRunnableObject_Release(runnable);
1172 return hres;
1175 return S_OK;
1178 /******************************************************************************
1179 * OleRun [OLE32.@]
1181 * Set the OLE object to the running state.
1183 * PARAMS
1184 * pUnknown [I] OLE object to run.
1186 * RETURNS
1187 * Success: S_OK.
1188 * Failure: Any HRESULT code.
1190 HRESULT WINAPI DECLSPEC_HOTPATCH OleRun(LPUNKNOWN pUnknown)
1192 IRunnableObject *runable;
1193 HRESULT hres;
1195 TRACE("(%p)\n", pUnknown);
1197 hres = IUnknown_QueryInterface(pUnknown, &IID_IRunnableObject, (void**)&runable);
1198 if (FAILED(hres))
1199 return S_OK; /* Appears to return no error. */
1201 hres = IRunnableObject_Run(runable, NULL);
1202 IRunnableObject_Release(runable);
1203 return hres;
1206 /******************************************************************************
1207 * OleLoad [OLE32.@]
1209 HRESULT WINAPI OleLoad(
1210 LPSTORAGE pStg,
1211 REFIID riid,
1212 LPOLECLIENTSITE pClientSite,
1213 LPVOID* ppvObj)
1215 IPersistStorage* persistStorage = NULL;
1216 IUnknown* pUnk;
1217 IOleObject* pOleObject = NULL;
1218 STATSTG storageInfo;
1219 HRESULT hres;
1221 TRACE("(%p, %s, %p, %p)\n", pStg, debugstr_guid(riid), pClientSite, ppvObj);
1223 *ppvObj = NULL;
1226 * TODO, Conversion ... OleDoAutoConvert
1230 * Get the class ID for the object.
1232 hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
1233 if (FAILED(hres))
1234 return hres;
1237 * Now, try and create the handler for the object
1239 hres = CoCreateInstance(&storageInfo.clsid,
1240 NULL,
1241 CLSCTX_INPROC_HANDLER|CLSCTX_INPROC_SERVER,
1242 riid,
1243 (void**)&pUnk);
1246 * If that fails, as it will most times, load the default
1247 * OLE handler.
1249 if (FAILED(hres))
1251 hres = OleCreateDefaultHandler(&storageInfo.clsid,
1252 NULL,
1253 riid,
1254 (void**)&pUnk);
1258 * If we couldn't find a handler... this is bad. Abort the whole thing.
1260 if (FAILED(hres))
1261 return hres;
1263 if (pClientSite)
1265 hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (void **)&pOleObject);
1266 if (SUCCEEDED(hres))
1268 DWORD dwStatus;
1269 hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
1274 * Initialize the object with its IPersistStorage interface.
1276 hres = IUnknown_QueryInterface(pUnk, &IID_IPersistStorage, (void**)&persistStorage);
1277 if (SUCCEEDED(hres))
1279 hres = IPersistStorage_Load(persistStorage, pStg);
1281 IPersistStorage_Release(persistStorage);
1282 persistStorage = NULL;
1285 if (SUCCEEDED(hres) && pClientSite)
1287 * Inform the new object of its client site.
1289 hres = IOleObject_SetClientSite(pOleObject, pClientSite);
1292 * Cleanup interfaces used internally
1294 if (pOleObject)
1295 IOleObject_Release(pOleObject);
1297 if (SUCCEEDED(hres))
1299 IOleLink *pOleLink;
1300 HRESULT hres1;
1301 hres1 = IUnknown_QueryInterface(pUnk, &IID_IOleLink, (void **)&pOleLink);
1302 if (SUCCEEDED(hres1))
1304 FIXME("handle OLE link\n");
1305 IOleLink_Release(pOleLink);
1309 if (FAILED(hres))
1311 IUnknown_Release(pUnk);
1312 pUnk = NULL;
1315 *ppvObj = pUnk;
1317 return hres;
1320 /***********************************************************************
1321 * OleSave [OLE32.@]
1323 HRESULT WINAPI OleSave(
1324 LPPERSISTSTORAGE pPS,
1325 LPSTORAGE pStg,
1326 BOOL fSameAsLoad)
1328 HRESULT hres;
1329 CLSID objectClass;
1331 TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad);
1334 * First, we transfer the class ID (if available)
1336 hres = IPersistStorage_GetClassID(pPS, &objectClass);
1338 if (SUCCEEDED(hres))
1340 WriteClassStg(pStg, &objectClass);
1344 * Then, we ask the object to save itself to the
1345 * storage. If it is successful, we commit the storage.
1347 hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad);
1349 if (SUCCEEDED(hres))
1351 IStorage_Commit(pStg,
1352 STGC_DEFAULT);
1355 return hres;
1359 /******************************************************************************
1360 * OleLockRunning [OLE32.@]
1362 HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses)
1364 IRunnableObject* runnable = NULL;
1365 HRESULT hres;
1367 TRACE("(%p,%x,%x)\n", pUnknown, fLock, fLastUnlockCloses);
1369 hres = IUnknown_QueryInterface(pUnknown,
1370 &IID_IRunnableObject,
1371 (void**)&runnable);
1373 if (SUCCEEDED(hres))
1375 hres = IRunnableObject_LockRunning(runnable, fLock, fLastUnlockCloses);
1377 IRunnableObject_Release(runnable);
1379 return hres;
1382 return S_OK;
1386 /**************************************************************************
1387 * Internal methods to manage the shared OLE menu in response to the
1388 * OLE***MenuDescriptor API
1391 /***
1392 * OLEMenu_Initialize()
1394 * Initializes the OLEMENU data structures.
1396 static void OLEMenu_Initialize(void)
1400 /***
1401 * OLEMenu_UnInitialize()
1403 * Releases the OLEMENU data structures.
1405 static void OLEMenu_UnInitialize(void)
1409 /*************************************************************************
1410 * OLEMenu_InstallHooks
1411 * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
1413 * RETURNS: TRUE if message hooks were successfully installed
1414 * FALSE on failure
1416 static BOOL OLEMenu_InstallHooks( DWORD tid )
1418 OleMenuHookItem *pHookItem;
1420 /* Create an entry for the hook table */
1421 if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
1422 sizeof(OleMenuHookItem)) ) )
1423 return FALSE;
1425 pHookItem->tid = tid;
1426 pHookItem->hHeap = GetProcessHeap();
1427 pHookItem->CallWndProc_hHook = NULL;
1429 /* Install a thread scope message hook for WH_GETMESSAGE */
1430 pHookItem->GetMsg_hHook = SetWindowsHookExW( WH_GETMESSAGE, OLEMenu_GetMsgProc,
1431 0, GetCurrentThreadId() );
1432 if ( !pHookItem->GetMsg_hHook )
1433 goto CLEANUP;
1435 /* Install a thread scope message hook for WH_CALLWNDPROC */
1436 pHookItem->CallWndProc_hHook = SetWindowsHookExW( WH_CALLWNDPROC, OLEMenu_CallWndProc,
1437 0, GetCurrentThreadId() );
1438 if ( !pHookItem->CallWndProc_hHook )
1439 goto CLEANUP;
1441 /* Insert the hook table entry */
1442 pHookItem->next = hook_list;
1443 hook_list = pHookItem;
1445 return TRUE;
1447 CLEANUP:
1448 /* Unhook any hooks */
1449 if ( pHookItem->GetMsg_hHook )
1450 UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
1451 if ( pHookItem->CallWndProc_hHook )
1452 UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
1453 /* Release the hook table entry */
1454 HeapFree(pHookItem->hHeap, 0, pHookItem );
1456 return FALSE;
1459 /*************************************************************************
1460 * OLEMenu_UnInstallHooks
1461 * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
1463 * RETURNS: TRUE if message hooks were successfully installed
1464 * FALSE on failure
1466 static BOOL OLEMenu_UnInstallHooks( DWORD tid )
1468 OleMenuHookItem *pHookItem = NULL;
1469 OleMenuHookItem **ppHook = &hook_list;
1471 while (*ppHook)
1473 if ((*ppHook)->tid == tid)
1475 pHookItem = *ppHook;
1476 *ppHook = pHookItem->next;
1477 break;
1479 ppHook = &(*ppHook)->next;
1481 if (!pHookItem) return FALSE;
1483 /* Uninstall the hooks installed for this thread */
1484 if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
1485 goto CLEANUP;
1486 if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
1487 goto CLEANUP;
1489 /* Release the hook table entry */
1490 HeapFree(pHookItem->hHeap, 0, pHookItem );
1492 return TRUE;
1494 CLEANUP:
1495 /* Release the hook table entry */
1496 HeapFree(pHookItem->hHeap, 0, pHookItem );
1498 return FALSE;
1501 /*************************************************************************
1502 * OLEMenu_IsHookInstalled
1503 * Tests if OLEMenu hooks have been installed for a thread
1505 * RETURNS: The pointer and index of the hook table entry for the tid
1506 * NULL and -1 for the index if no hooks were installed for this thread
1508 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )
1510 OleMenuHookItem *pHookItem;
1512 /* Do a simple linear search for an entry whose tid matches ours.
1513 * We really need a map but efficiency is not a concern here. */
1514 for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next)
1516 if ( tid == pHookItem->tid )
1517 return pHookItem;
1520 return NULL;
1523 /***********************************************************************
1524 * OLEMenu_FindMainMenuIndex
1526 * Used by OLEMenu API to find the top level group a menu item belongs to.
1527 * On success pnPos contains the index of the item in the top level menu group
1529 * RETURNS: TRUE if the ID was found, FALSE on failure
1531 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
1533 INT i, nItems;
1535 nItems = GetMenuItemCount( hMainMenu );
1537 for (i = 0; i < nItems; i++)
1539 HMENU hsubmenu;
1541 /* Is the current item a submenu? */
1542 if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
1544 /* If the handle is the same we're done */
1545 if ( hsubmenu == hPopupMenu )
1547 if (pnPos)
1548 *pnPos = i;
1549 return TRUE;
1551 /* Recursively search without updating pnPos */
1552 else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
1554 if (pnPos)
1555 *pnPos = i;
1556 return TRUE;
1561 return FALSE;
1564 /***********************************************************************
1565 * OLEMenu_SetIsServerMenu
1567 * Checks whether a popup menu belongs to a shared menu group which is
1568 * owned by the server, and sets the menu descriptor state accordingly.
1569 * All menu messages from these groups should be routed to the server.
1571 * RETURNS: TRUE if the popup menu is part of a server owned group
1572 * FALSE if the popup menu is part of a container owned group
1574 static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
1576 UINT nPos = 0, nWidth, i;
1578 pOleMenuDescriptor->bIsServerItem = FALSE;
1580 /* Don't bother searching if the popup is the combined menu itself */
1581 if ( hmenu == pOleMenuDescriptor->hmenuCombined )
1582 return FALSE;
1584 /* Find the menu item index in the shared OLE menu that this item belongs to */
1585 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) )
1586 return FALSE;
1588 /* The group widths array has counts for the number of elements
1589 * in the groups File, Edit, Container, Object, Window, Help.
1590 * The Edit, Object & Help groups belong to the server object
1591 * and the other three belong to the container.
1592 * Loop through the group widths and locate the group we are a member of.
1594 for ( i = 0, nWidth = 0; i < 6; i++ )
1596 nWidth += pOleMenuDescriptor->mgw.width[i];
1597 if ( nPos < nWidth )
1599 /* Odd elements are server menu widths */
1600 pOleMenuDescriptor->bIsServerItem = i%2;
1601 break;
1605 return pOleMenuDescriptor->bIsServerItem;
1608 /*************************************************************************
1609 * OLEMenu_CallWndProc
1610 * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
1611 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1613 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
1615 LPCWPSTRUCT pMsg;
1616 HOLEMENU hOleMenu = 0;
1617 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1618 OleMenuHookItem *pHookItem = NULL;
1619 WORD fuFlags;
1621 TRACE("%i, %04lx, %08lx\n", code, wParam, lParam );
1623 /* Check if we're being asked to process the message */
1624 if ( HC_ACTION != code )
1625 goto NEXTHOOK;
1627 /* Retrieve the current message being dispatched from lParam */
1628 pMsg = (LPCWPSTRUCT)lParam;
1630 /* Check if the message is destined for a window we are interested in:
1631 * If the window has an OLEMenu property we may need to dispatch
1632 * the menu message to its active objects window instead. */
1634 hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW );
1635 if ( !hOleMenu )
1636 goto NEXTHOOK;
1638 /* Get the menu descriptor */
1639 pOleMenuDescriptor = GlobalLock( hOleMenu );
1640 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1641 goto NEXTHOOK;
1643 /* Process menu messages */
1644 switch( pMsg->message )
1646 case WM_INITMENU:
1648 /* Reset the menu descriptor state */
1649 pOleMenuDescriptor->bIsServerItem = FALSE;
1651 /* Send this message to the server as well */
1652 SendMessageW( pOleMenuDescriptor->hwndActiveObject,
1653 pMsg->message, pMsg->wParam, pMsg->lParam );
1654 goto NEXTHOOK;
1657 case WM_INITMENUPOPUP:
1659 /* Save the state for whether this is a server owned menu */
1660 OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
1661 break;
1664 case WM_MENUSELECT:
1666 fuFlags = HIWORD(pMsg->wParam); /* Get flags */
1667 if ( fuFlags & MF_SYSMENU )
1668 goto NEXTHOOK;
1670 /* Save the state for whether this is a server owned popup menu */
1671 else if ( fuFlags & MF_POPUP )
1672 OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
1674 break;
1677 case WM_DRAWITEM:
1679 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
1680 if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
1681 goto NEXTHOOK; /* Not a menu message */
1683 break;
1686 default:
1687 goto NEXTHOOK;
1690 /* If the message was for the server dispatch it accordingly */
1691 if ( pOleMenuDescriptor->bIsServerItem )
1693 SendMessageW( pOleMenuDescriptor->hwndActiveObject,
1694 pMsg->message, pMsg->wParam, pMsg->lParam );
1697 NEXTHOOK:
1698 if ( pOleMenuDescriptor )
1699 GlobalUnlock( hOleMenu );
1701 /* Lookup the hook item for the current thread */
1702 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1704 /* This should never fail!! */
1705 WARN("could not retrieve hHook for current thread!\n" );
1706 return 0;
1709 /* Pass on the message to the next hooker */
1710 return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
1713 /*************************************************************************
1714 * OLEMenu_GetMsgProc
1715 * Thread scope WH_GETMESSAGE hook proc filter function (callback)
1716 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1718 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
1720 LPMSG pMsg;
1721 HOLEMENU hOleMenu = 0;
1722 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1723 OleMenuHookItem *pHookItem = NULL;
1724 WORD wCode;
1726 TRACE("%i, %04lx, %08lx\n", code, wParam, lParam );
1728 /* Check if we're being asked to process a messages */
1729 if ( HC_ACTION != code )
1730 goto NEXTHOOK;
1732 /* Retrieve the current message being dispatched from lParam */
1733 pMsg = (LPMSG)lParam;
1735 /* Check if the message is destined for a window we are interested in:
1736 * If the window has an OLEMenu property we may need to dispatch
1737 * the menu message to its active objects window instead. */
1739 hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW );
1740 if ( !hOleMenu )
1741 goto NEXTHOOK;
1743 /* Process menu messages */
1744 switch( pMsg->message )
1746 case WM_COMMAND:
1748 wCode = HIWORD(pMsg->wParam); /* Get notification code */
1749 if ( wCode )
1750 goto NEXTHOOK; /* Not a menu message */
1751 break;
1753 default:
1754 goto NEXTHOOK;
1757 /* Get the menu descriptor */
1758 pOleMenuDescriptor = GlobalLock( hOleMenu );
1759 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1760 goto NEXTHOOK;
1762 /* If the message was for the server dispatch it accordingly */
1763 if ( pOleMenuDescriptor->bIsServerItem )
1765 /* Change the hWnd in the message to the active objects hWnd.
1766 * The message loop which reads this message will automatically
1767 * dispatch it to the embedded objects window. */
1768 pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
1771 NEXTHOOK:
1772 if ( pOleMenuDescriptor )
1773 GlobalUnlock( hOleMenu );
1775 /* Lookup the hook item for the current thread */
1776 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1778 /* This should never fail!! */
1779 WARN("could not retrieve hHook for current thread!\n" );
1780 return FALSE;
1783 /* Pass on the message to the next hooker */
1784 return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
1787 /***********************************************************************
1788 * OleCreateMenuDescriptor [OLE32.@]
1789 * Creates an OLE menu descriptor for OLE to use when dispatching
1790 * menu messages and commands.
1792 * PARAMS:
1793 * hmenuCombined - Handle to the objects combined menu
1794 * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group
1797 HOLEMENU WINAPI OleCreateMenuDescriptor(
1798 HMENU hmenuCombined,
1799 LPOLEMENUGROUPWIDTHS lpMenuWidths)
1801 HOLEMENU hOleMenu;
1802 OleMenuDescriptor *pOleMenuDescriptor;
1803 int i;
1805 if ( !hmenuCombined || !lpMenuWidths )
1806 return 0;
1808 /* Create an OLE menu descriptor */
1809 if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
1810 sizeof(OleMenuDescriptor) ) ) )
1811 return 0;
1813 pOleMenuDescriptor = GlobalLock( hOleMenu );
1814 if ( !pOleMenuDescriptor )
1815 return 0;
1817 /* Initialize menu group widths and hmenu */
1818 for ( i = 0; i < 6; i++ )
1819 pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
1821 pOleMenuDescriptor->hmenuCombined = hmenuCombined;
1822 pOleMenuDescriptor->bIsServerItem = FALSE;
1823 GlobalUnlock( hOleMenu );
1825 return hOleMenu;
1828 /***********************************************************************
1829 * OleDestroyMenuDescriptor [OLE32.@]
1830 * Destroy the shared menu descriptor
1832 HRESULT WINAPI OleDestroyMenuDescriptor(
1833 HOLEMENU hmenuDescriptor)
1835 if ( hmenuDescriptor )
1836 GlobalFree( hmenuDescriptor );
1837 return S_OK;
1840 /***********************************************************************
1841 * OleSetMenuDescriptor [OLE32.@]
1842 * Installs or removes OLE dispatching code for the containers frame window.
1844 * PARAMS
1845 * hOleMenu Handle to composite menu descriptor
1846 * hwndFrame Handle to containers frame window
1847 * hwndActiveObject Handle to objects in-place activation window
1848 * lpFrame Pointer to IOleInPlaceFrame on containers window
1849 * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object
1851 * RETURNS
1852 * S_OK - menu installed correctly
1853 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1855 * FIXME
1856 * The lpFrame and lpActiveObject parameters are currently ignored
1857 * OLE should install context sensitive help F1 filtering for the app when
1858 * these are non null.
1860 HRESULT WINAPI OleSetMenuDescriptor(
1861 HOLEMENU hOleMenu,
1862 HWND hwndFrame,
1863 HWND hwndActiveObject,
1864 LPOLEINPLACEFRAME lpFrame,
1865 LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1867 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1869 /* Check args */
1870 if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
1871 return E_INVALIDARG;
1873 if ( lpFrame || lpActiveObject )
1875 FIXME("(%p, %p, %p, %p, %p), Context sensitive help filtering not implemented!\n",
1876 hOleMenu,
1877 hwndFrame,
1878 hwndActiveObject,
1879 lpFrame,
1880 lpActiveObject);
1883 /* Set up a message hook to intercept the containers frame window messages.
1884 * The message filter is responsible for dispatching menu messages from the
1885 * shared menu which are intended for the object.
1888 if ( hOleMenu ) /* Want to install dispatching code */
1890 /* If OLEMenu hooks are already installed for this thread, fail
1891 * Note: This effectively means that OleSetMenuDescriptor cannot
1892 * be called twice in succession on the same frame window
1893 * without first calling it with a null hOleMenu to uninstall
1895 if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) )
1896 return E_FAIL;
1898 /* Get the menu descriptor */
1899 pOleMenuDescriptor = GlobalLock( hOleMenu );
1900 if ( !pOleMenuDescriptor )
1901 return E_UNEXPECTED;
1903 /* Update the menu descriptor */
1904 pOleMenuDescriptor->hwndFrame = hwndFrame;
1905 pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
1907 GlobalUnlock( hOleMenu );
1908 pOleMenuDescriptor = NULL;
1910 /* Add a menu descriptor windows property to the frame window */
1911 SetPropW( hwndFrame, prop_olemenuW, hOleMenu );
1913 /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
1914 if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
1915 return E_FAIL;
1917 else /* Want to uninstall dispatching code */
1919 /* Uninstall the hooks */
1920 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1921 return E_FAIL;
1923 /* Remove the menu descriptor property from the frame window */
1924 RemovePropW( hwndFrame, prop_olemenuW );
1927 return S_OK;
1930 /******************************************************************************
1931 * IsAccelerator [OLE32.@]
1932 * Mostly copied from controls/menu.c TranslateAccelerator implementation
1934 BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd)
1936 LPACCEL lpAccelTbl;
1937 int i;
1939 if(!lpMsg) return FALSE;
1940 if (!hAccel)
1942 WARN_(accel)("NULL accel handle\n");
1943 return FALSE;
1945 if((lpMsg->message != WM_KEYDOWN &&
1946 lpMsg->message != WM_SYSKEYDOWN &&
1947 lpMsg->message != WM_SYSCHAR &&
1948 lpMsg->message != WM_CHAR)) return FALSE;
1949 lpAccelTbl = HeapAlloc(GetProcessHeap(), 0, cAccelEntries * sizeof(ACCEL));
1950 if (NULL == lpAccelTbl)
1952 return FALSE;
1954 if (CopyAcceleratorTableW(hAccel, lpAccelTbl, cAccelEntries) != cAccelEntries)
1956 WARN_(accel)("CopyAcceleratorTableW failed\n");
1957 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1958 return FALSE;
1961 TRACE_(accel)("hAccel=%p, cAccelEntries=%d,"
1962 "msg->hwnd=%p, msg->message=%04x, wParam=%08lx, lParam=%08lx\n",
1963 hAccel, cAccelEntries,
1964 lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);
1965 for(i = 0; i < cAccelEntries; i++)
1967 if(lpAccelTbl[i].key != lpMsg->wParam)
1968 continue;
1970 if(lpMsg->message == WM_CHAR)
1972 if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY))
1974 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", LOWORD(lpMsg->wParam) & 0xff);
1975 goto found;
1978 else
1980 if(lpAccelTbl[i].fVirt & FVIRTKEY)
1982 INT mask = 0;
1983 TRACE_(accel)("found accel for virt_key %04lx (scan %04x)\n",
1984 lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff);
1985 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
1986 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
1987 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
1988 if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
1989 TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n");
1991 else
1993 if(!(lpMsg->lParam & 0x01000000)) /* no special_key */
1995 if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000))
1996 { /* ^^ ALT pressed */
1997 TRACE_(accel)("found accel for Alt-%c\n", LOWORD(lpMsg->wParam) & 0xff);
1998 goto found;
2005 WARN_(accel)("couldn't translate accelerator key\n");
2006 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
2007 return FALSE;
2009 found:
2010 if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd;
2011 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
2012 return TRUE;
2015 /***********************************************************************
2016 * ReleaseStgMedium [OLE32.@]
2018 void WINAPI ReleaseStgMedium(
2019 STGMEDIUM* pmedium)
2021 switch (pmedium->tymed)
2023 case TYMED_HGLOBAL:
2025 if ( (pmedium->pUnkForRelease==0) &&
2026 (pmedium->u.hGlobal!=0) )
2027 GlobalFree(pmedium->u.hGlobal);
2028 break;
2030 case TYMED_FILE:
2032 if (pmedium->u.lpszFileName!=0)
2034 if (pmedium->pUnkForRelease==0)
2036 DeleteFileW(pmedium->u.lpszFileName);
2039 CoTaskMemFree(pmedium->u.lpszFileName);
2041 break;
2043 case TYMED_ISTREAM:
2045 if (pmedium->u.pstm!=0)
2047 IStream_Release(pmedium->u.pstm);
2049 break;
2051 case TYMED_ISTORAGE:
2053 if (pmedium->u.pstg!=0)
2055 IStorage_Release(pmedium->u.pstg);
2057 break;
2059 case TYMED_GDI:
2061 if ( (pmedium->pUnkForRelease==0) &&
2062 (pmedium->u.hBitmap!=0) )
2063 DeleteObject(pmedium->u.hBitmap);
2064 break;
2066 case TYMED_MFPICT:
2068 if ( (pmedium->pUnkForRelease==0) &&
2069 (pmedium->u.hMetaFilePict!=0) )
2071 LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hMetaFilePict);
2072 DeleteMetaFile(pMP->hMF);
2073 GlobalUnlock(pmedium->u.hMetaFilePict);
2074 GlobalFree(pmedium->u.hMetaFilePict);
2076 break;
2078 case TYMED_ENHMF:
2080 if ( (pmedium->pUnkForRelease==0) &&
2081 (pmedium->u.hEnhMetaFile!=0) )
2083 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
2085 break;
2087 case TYMED_NULL:
2088 default:
2089 break;
2091 pmedium->tymed=TYMED_NULL;
2094 * After cleaning up, the unknown is released
2096 if (pmedium->pUnkForRelease!=0)
2098 IUnknown_Release(pmedium->pUnkForRelease);
2099 pmedium->pUnkForRelease = 0;
2103 /***
2104 * OLEDD_Initialize()
2106 * Initializes the OLE drag and drop data structures.
2108 static void OLEDD_Initialize(void)
2110 WNDCLASSW wndClass;
2112 ZeroMemory (&wndClass, sizeof(WNDCLASSW));
2113 wndClass.style = CS_GLOBALCLASS;
2114 wndClass.lpfnWndProc = OLEDD_DragTrackerWindowProc;
2115 wndClass.cbClsExtra = 0;
2116 wndClass.cbWndExtra = sizeof(TrackerWindowInfo*);
2117 wndClass.hCursor = 0;
2118 wndClass.hbrBackground = 0;
2119 wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
2121 RegisterClassW (&wndClass);
2124 /***
2125 * OLEDD_DragTrackerWindowProc()
2127 * This method is the WindowProcedure of the drag n drop tracking
2128 * window. During a drag n Drop operation, an invisible window is created
2129 * to receive the user input and act upon it. This procedure is in charge
2130 * of this behavior.
2133 #define DRAG_TIMER_ID 1
2135 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
2136 HWND hwnd,
2137 UINT uMsg,
2138 WPARAM wParam,
2139 LPARAM lParam)
2141 switch (uMsg)
2143 case WM_CREATE:
2145 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
2147 SetWindowLongPtrW(hwnd, 0, (LONG_PTR)createStruct->lpCreateParams);
2148 SetTimer(hwnd, DRAG_TIMER_ID, 50, NULL);
2150 break;
2152 case WM_TIMER:
2153 case WM_MOUSEMOVE:
2154 case WM_LBUTTONUP:
2155 case WM_MBUTTONUP:
2156 case WM_RBUTTONUP:
2157 case WM_LBUTTONDOWN:
2158 case WM_MBUTTONDOWN:
2159 case WM_RBUTTONDOWN:
2161 TrackerWindowInfo *trackerInfo = (TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0);
2162 if (trackerInfo->trackingDone) break;
2163 OLEDD_TrackStateChange(trackerInfo);
2164 break;
2166 case WM_DESTROY:
2168 KillTimer(hwnd, DRAG_TIMER_ID);
2169 break;
2174 * This is a window proc after all. Let's call the default.
2176 return DefWindowProcW (hwnd, uMsg, wParam, lParam);
2179 /***
2180 * OLEDD_TrackStateChange()
2182 * This method is invoked while a drag and drop operation is in effect.
2184 * params:
2185 * trackerInfo - Pointer to the structure identifying the
2186 * drag & drop operation that is currently
2187 * active.
2189 static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo)
2191 HWND hwndNewTarget = 0;
2192 HRESULT hr = S_OK;
2193 POINT pt;
2196 * Get the handle of the window under the mouse
2198 pt.x = trackerInfo->curMousePos.x;
2199 pt.y = trackerInfo->curMousePos.y;
2200 hwndNewTarget = WindowFromPoint(pt);
2202 trackerInfo->returnValue = IDropSource_QueryContinueDrag(trackerInfo->dropSource,
2203 trackerInfo->escPressed,
2204 trackerInfo->dwKeyState);
2207 * Every time, we re-initialize the effects passed to the
2208 * IDropTarget to the effects allowed by the source.
2210 *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
2213 * If we are hovering over the same target as before, send the
2214 * DragOver notification
2216 if ( (trackerInfo->curDragTarget != 0) &&
2217 (trackerInfo->curTargetHWND == hwndNewTarget) )
2219 IDropTarget_DragOver(trackerInfo->curDragTarget,
2220 trackerInfo->dwKeyState,
2221 trackerInfo->curMousePos,
2222 trackerInfo->pdwEffect);
2223 *trackerInfo->pdwEffect &= trackerInfo->dwOKEffect;
2225 else
2228 * If we changed window, we have to notify our old target and check for
2229 * the new one.
2231 if (trackerInfo->curDragTarget)
2232 IDropTarget_DragLeave(trackerInfo->curDragTarget);
2235 * Make sure we're hovering over a window.
2237 if (hwndNewTarget)
2240 * Find-out if there is a drag target under the mouse
2242 HWND next_target_wnd = hwndNewTarget;
2244 trackerInfo->curTargetHWND = hwndNewTarget;
2246 while (next_target_wnd && !is_droptarget(next_target_wnd))
2247 next_target_wnd = GetParent(next_target_wnd);
2249 if (next_target_wnd) hwndNewTarget = next_target_wnd;
2251 trackerInfo->curDragTargetHWND = hwndNewTarget;
2252 if(trackerInfo->curDragTarget) IDropTarget_Release(trackerInfo->curDragTarget);
2253 trackerInfo->curDragTarget = get_droptarget_pointer(hwndNewTarget);
2256 * If there is, notify it that we just dragged-in
2258 if (trackerInfo->curDragTarget)
2260 hr = IDropTarget_DragEnter(trackerInfo->curDragTarget,
2261 trackerInfo->dataObject,
2262 trackerInfo->dwKeyState,
2263 trackerInfo->curMousePos,
2264 trackerInfo->pdwEffect);
2265 *trackerInfo->pdwEffect &= trackerInfo->dwOKEffect;
2267 /* failed DragEnter() means invalid target */
2268 if (hr != S_OK)
2270 trackerInfo->curDragTargetHWND = 0;
2271 trackerInfo->curTargetHWND = 0;
2272 IDropTarget_Release(trackerInfo->curDragTarget);
2273 trackerInfo->curDragTarget = 0;
2277 else
2280 * The mouse is not over a window so we don't track anything.
2282 trackerInfo->curDragTargetHWND = 0;
2283 trackerInfo->curTargetHWND = 0;
2284 if(trackerInfo->curDragTarget) IDropTarget_Release(trackerInfo->curDragTarget);
2285 trackerInfo->curDragTarget = 0;
2290 * Now that we have done that, we have to tell the source to give
2291 * us feedback on the work being done by the target. If we don't
2292 * have a target, simulate no effect.
2294 if (trackerInfo->curDragTarget==0)
2296 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2299 hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
2300 *trackerInfo->pdwEffect);
2303 * When we ask for feedback from the drop source, sometimes it will
2304 * do all the necessary work and sometimes it will not handle it
2305 * when that's the case, we must display the standard drag and drop
2306 * cursors.
2308 if (hr == DRAGDROP_S_USEDEFAULTCURSORS)
2310 HCURSOR hCur;
2312 if (*trackerInfo->pdwEffect & DROPEFFECT_MOVE)
2314 hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(2));
2316 else if (*trackerInfo->pdwEffect & DROPEFFECT_COPY)
2318 hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(3));
2320 else if (*trackerInfo->pdwEffect & DROPEFFECT_LINK)
2322 hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(4));
2324 else
2326 hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(1));
2329 SetCursor(hCur);
2333 * All the return valued will stop the operation except the S_OK
2334 * return value.
2336 if (trackerInfo->returnValue!=S_OK)
2339 * Make sure the message loop in DoDragDrop stops
2341 trackerInfo->trackingDone = TRUE;
2344 * Release the mouse in case the drop target decides to show a popup
2345 * or a menu or something.
2347 ReleaseCapture();
2350 * If we end-up over a target, drop the object in the target or
2351 * inform the target that the operation was cancelled.
2353 if (trackerInfo->curDragTarget)
2355 switch (trackerInfo->returnValue)
2358 * If the source wants us to complete the operation, we tell
2359 * the drop target that we just dropped the object in it.
2361 case DRAGDROP_S_DROP:
2362 if (*trackerInfo->pdwEffect != DROPEFFECT_NONE)
2364 hr = IDropTarget_Drop(trackerInfo->curDragTarget, trackerInfo->dataObject,
2365 trackerInfo->dwKeyState, trackerInfo->curMousePos, trackerInfo->pdwEffect);
2366 if (FAILED(hr))
2367 trackerInfo->returnValue = hr;
2369 else
2370 IDropTarget_DragLeave(trackerInfo->curDragTarget);
2371 break;
2374 * If the source told us that we should cancel, fool the drop
2375 * target by telling it that the mouse left its window.
2376 * Also set the drop effect to "NONE" in case the application
2377 * ignores the result of DoDragDrop.
2379 case DRAGDROP_S_CANCEL:
2380 IDropTarget_DragLeave(trackerInfo->curDragTarget);
2381 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2382 break;
2388 /***
2389 * OLEDD_GetButtonState()
2391 * This method will use the current state of the keyboard to build
2392 * a button state mask equivalent to the one passed in the
2393 * WM_MOUSEMOVE wParam.
2395 static DWORD OLEDD_GetButtonState(void)
2397 BYTE keyboardState[256];
2398 DWORD keyMask = 0;
2400 GetKeyboardState(keyboardState);
2402 if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
2403 keyMask |= MK_SHIFT;
2405 if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
2406 keyMask |= MK_CONTROL;
2408 if ( (keyboardState[VK_MENU] & 0x80) !=0)
2409 keyMask |= MK_ALT;
2411 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
2412 keyMask |= MK_LBUTTON;
2414 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
2415 keyMask |= MK_RBUTTON;
2417 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
2418 keyMask |= MK_MBUTTON;
2420 return keyMask;
2423 /***
2424 * OLEDD_GetButtonState()
2426 * This method will read the default value of the registry key in
2427 * parameter and extract a DWORD value from it. The registry key value
2428 * can be in a string key or a DWORD key.
2430 * params:
2431 * regKey - Key to read the default value from
2432 * pdwValue - Pointer to the location where the DWORD
2433 * value is returned. This value is not modified
2434 * if the value is not found.
2437 static void OLEUTL_ReadRegistryDWORDValue(
2438 HKEY regKey,
2439 DWORD* pdwValue)
2441 WCHAR buffer[20];
2442 DWORD cbData = sizeof(buffer);
2443 DWORD dwKeyType;
2444 LONG lres;
2446 lres = RegQueryValueExW(regKey,
2447 emptyW,
2448 NULL,
2449 &dwKeyType,
2450 (LPBYTE)buffer,
2451 &cbData);
2453 if (lres==ERROR_SUCCESS)
2455 switch (dwKeyType)
2457 case REG_DWORD:
2458 *pdwValue = *(DWORD*)buffer;
2459 break;
2460 case REG_EXPAND_SZ:
2461 case REG_MULTI_SZ:
2462 case REG_SZ:
2463 *pdwValue = (DWORD)strtoulW(buffer, NULL, 10);
2464 break;
2469 /******************************************************************************
2470 * OleDraw (OLE32.@)
2472 * The operation of this function is documented literally in the WinAPI
2473 * documentation to involve a QueryInterface for the IViewObject interface,
2474 * followed by a call to IViewObject::Draw.
2476 HRESULT WINAPI OleDraw(
2477 IUnknown *pUnk,
2478 DWORD dwAspect,
2479 HDC hdcDraw,
2480 LPCRECT rect)
2482 HRESULT hres;
2483 IViewObject *viewobject;
2485 if (!pUnk) return E_INVALIDARG;
2487 hres = IUnknown_QueryInterface(pUnk,
2488 &IID_IViewObject,
2489 (void**)&viewobject);
2490 if (SUCCEEDED(hres))
2492 hres = IViewObject_Draw(viewobject, dwAspect, -1, 0, 0, 0, hdcDraw, (RECTL*)rect, 0, 0, 0);
2493 IViewObject_Release(viewobject);
2494 return hres;
2496 else
2497 return DV_E_NOIVIEWOBJECT;
2500 /***********************************************************************
2501 * OleTranslateAccelerator [OLE32.@]
2503 HRESULT WINAPI OleTranslateAccelerator (LPOLEINPLACEFRAME lpFrame,
2504 LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpmsg)
2506 WORD wID;
2508 TRACE("(%p,%p,%p)\n", lpFrame, lpFrameInfo, lpmsg);
2510 if (IsAccelerator(lpFrameInfo->haccel,lpFrameInfo->cAccelEntries,lpmsg,&wID))
2511 return IOleInPlaceFrame_TranslateAccelerator(lpFrame,lpmsg,wID);
2513 return S_FALSE;
2516 /******************************************************************************
2517 * OleCreate [OLE32.@]
2520 HRESULT WINAPI OleCreate(
2521 REFCLSID rclsid,
2522 REFIID riid,
2523 DWORD renderopt,
2524 LPFORMATETC pFormatEtc,
2525 LPOLECLIENTSITE pClientSite,
2526 LPSTORAGE pStg,
2527 LPVOID* ppvObj)
2529 HRESULT hres;
2530 IUnknown * pUnk = NULL;
2531 IOleObject *pOleObject = NULL;
2533 TRACE("(%s, %s, %d, %p, %p, %p, %p)\n", debugstr_guid(rclsid),
2534 debugstr_guid(riid), renderopt, pFormatEtc, pClientSite, pStg, ppvObj);
2536 hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, riid, (LPVOID*)&pUnk);
2538 if (SUCCEEDED(hres))
2539 hres = IStorage_SetClass(pStg, rclsid);
2541 if (pClientSite && SUCCEEDED(hres))
2543 hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (LPVOID*)&pOleObject);
2544 if (SUCCEEDED(hres))
2546 DWORD dwStatus;
2547 IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
2551 if (SUCCEEDED(hres))
2553 IPersistStorage * pPS;
2554 if (SUCCEEDED((hres = IUnknown_QueryInterface(pUnk, &IID_IPersistStorage, (LPVOID*)&pPS))))
2556 TRACE("trying to set stg %p\n", pStg);
2557 hres = IPersistStorage_InitNew(pPS, pStg);
2558 TRACE("-- result 0x%08x\n", hres);
2559 IPersistStorage_Release(pPS);
2563 if (pClientSite && SUCCEEDED(hres))
2565 TRACE("trying to set clientsite %p\n", pClientSite);
2566 hres = IOleObject_SetClientSite(pOleObject, pClientSite);
2567 TRACE("-- result 0x%08x\n", hres);
2570 if (pOleObject)
2571 IOleObject_Release(pOleObject);
2573 if (((renderopt == OLERENDER_DRAW) || (renderopt == OLERENDER_FORMAT)) &&
2574 SUCCEEDED(hres))
2576 hres = OleRun(pUnk);
2577 if (SUCCEEDED(hres))
2579 IOleCache *pOleCache;
2581 if (SUCCEEDED(IUnknown_QueryInterface(pUnk, &IID_IOleCache, (void **)&pOleCache)))
2583 DWORD dwConnection;
2584 if (renderopt == OLERENDER_DRAW && !pFormatEtc) {
2585 FORMATETC pfe;
2586 pfe.cfFormat = 0;
2587 pfe.ptd = NULL;
2588 pfe.dwAspect = DVASPECT_CONTENT;
2589 pfe.lindex = -1;
2590 pfe.tymed = TYMED_NULL;
2591 hres = IOleCache_Cache(pOleCache, &pfe, ADVF_PRIMEFIRST, &dwConnection);
2593 else
2594 hres = IOleCache_Cache(pOleCache, pFormatEtc, ADVF_PRIMEFIRST, &dwConnection);
2595 IOleCache_Release(pOleCache);
2600 if (FAILED(hres) && pUnk)
2602 IUnknown_Release(pUnk);
2603 pUnk = NULL;
2606 *ppvObj = pUnk;
2608 TRACE("-- %p\n", pUnk);
2609 return hres;
2612 /******************************************************************************
2613 * OleGetAutoConvert [OLE32.@]
2615 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2617 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2618 HKEY hkey = NULL;
2619 WCHAR buf[CHARS_IN_GUID];
2620 LONG len;
2621 HRESULT res = S_OK;
2623 res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey);
2624 if (FAILED(res))
2625 goto done;
2627 len = sizeof(buf);
2628 if (RegQueryValueW(hkey, NULL, buf, &len))
2630 res = REGDB_E_KEYMISSING;
2631 goto done;
2633 res = CLSIDFromString(buf, pClsidNew);
2634 done:
2635 if (hkey) RegCloseKey(hkey);
2636 return res;
2639 /******************************************************************************
2640 * OleSetAutoConvert [OLE32.@]
2642 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
2644 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2645 HKEY hkey = NULL;
2646 WCHAR szClsidNew[CHARS_IN_GUID];
2647 HRESULT res = S_OK;
2649 TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
2651 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2652 if (FAILED(res))
2653 goto done;
2654 StringFromGUID2(clsidNew, szClsidNew, CHARS_IN_GUID);
2655 if (RegSetValueW(hkey, wszAutoConvertTo, REG_SZ, szClsidNew, (strlenW(szClsidNew)+1) * sizeof(WCHAR)))
2657 res = REGDB_E_WRITEREGDB;
2658 goto done;
2661 done:
2662 if (hkey) RegCloseKey(hkey);
2663 return res;
2666 /******************************************************************************
2667 * OleDoAutoConvert [OLE32.@]
2669 HRESULT WINAPI OleDoAutoConvert(LPSTORAGE pStg, LPCLSID pClsidNew)
2671 WCHAR *user_type_old, *user_type_new;
2672 CLIPFORMAT cf;
2673 STATSTG stat;
2674 CLSID clsid;
2675 HRESULT hr;
2677 TRACE("(%p, %p)\n", pStg, pClsidNew);
2679 *pClsidNew = CLSID_NULL;
2680 if(!pStg)
2681 return E_INVALIDARG;
2682 hr = IStorage_Stat(pStg, &stat, STATFLAG_NONAME);
2683 if(FAILED(hr))
2684 return hr;
2686 *pClsidNew = stat.clsid;
2687 hr = OleGetAutoConvert(&stat.clsid, &clsid);
2688 if(FAILED(hr))
2689 return hr;
2691 hr = IStorage_SetClass(pStg, &clsid);
2692 if(FAILED(hr))
2693 return hr;
2695 hr = ReadFmtUserTypeStg(pStg, &cf, &user_type_old);
2696 if(FAILED(hr)) {
2697 cf = 0;
2698 user_type_new = NULL;
2701 hr = OleRegGetUserType(&clsid, USERCLASSTYPE_FULL, &user_type_new);
2702 if(FAILED(hr))
2703 user_type_new = NULL;
2705 hr = WriteFmtUserTypeStg(pStg, cf, user_type_new);
2706 CoTaskMemFree(user_type_new);
2707 if(FAILED(hr))
2709 CoTaskMemFree(user_type_old);
2710 IStorage_SetClass(pStg, &stat.clsid);
2711 return hr;
2714 hr = SetConvertStg(pStg, TRUE);
2715 if(FAILED(hr))
2717 WriteFmtUserTypeStg(pStg, cf, user_type_old);
2718 IStorage_SetClass(pStg, &stat.clsid);
2720 else
2721 *pClsidNew = clsid;
2722 CoTaskMemFree(user_type_old);
2723 return hr;
2726 /******************************************************************************
2727 * OleIsRunning [OLE32.@]
2729 BOOL WINAPI OleIsRunning(LPOLEOBJECT object)
2731 IRunnableObject *pRunnable;
2732 HRESULT hr;
2733 BOOL running;
2735 TRACE("(%p)\n", object);
2737 if (!object) return FALSE;
2739 hr = IOleObject_QueryInterface(object, &IID_IRunnableObject, (void **)&pRunnable);
2740 if (FAILED(hr))
2741 return TRUE;
2742 running = IRunnableObject_IsRunning(pRunnable);
2743 IRunnableObject_Release(pRunnable);
2744 return running;
2747 /***********************************************************************
2748 * OleNoteObjectVisible [OLE32.@]
2750 HRESULT WINAPI OleNoteObjectVisible(LPUNKNOWN pUnknown, BOOL bVisible)
2752 TRACE("(%p, %s)\n", pUnknown, bVisible ? "TRUE" : "FALSE");
2753 return CoLockObjectExternal(pUnknown, bVisible, TRUE);
2757 /***********************************************************************
2758 * OLE_FreeClipDataArray [internal]
2760 * NOTES:
2761 * frees the data associated with an array of CLIPDATAs
2763 static void OLE_FreeClipDataArray(ULONG count, CLIPDATA * pClipDataArray)
2765 ULONG i;
2766 for (i = 0; i < count; i++)
2767 if (pClipDataArray[i].pClipData)
2768 CoTaskMemFree(pClipDataArray[i].pClipData);
2771 /***********************************************************************
2772 * PropSysAllocString [OLE32.@]
2773 * NOTES
2774 * Forward to oleaut32.
2776 BSTR WINAPI PropSysAllocString(LPCOLESTR str)
2778 return SysAllocString(str);
2781 /***********************************************************************
2782 * PropSysFreeString [OLE32.@]
2783 * NOTES
2784 * Forward to oleaut32.
2786 void WINAPI PropSysFreeString(LPOLESTR str)
2788 SysFreeString(str);
2791 /******************************************************************************
2792 * Check if a PROPVARIANT's type is valid.
2794 static inline HRESULT PROPVARIANT_ValidateType(VARTYPE vt)
2796 switch (vt)
2798 case VT_EMPTY:
2799 case VT_NULL:
2800 case VT_I1:
2801 case VT_I2:
2802 case VT_I4:
2803 case VT_I8:
2804 case VT_R4:
2805 case VT_R8:
2806 case VT_CY:
2807 case VT_DATE:
2808 case VT_BSTR:
2809 case VT_ERROR:
2810 case VT_BOOL:
2811 case VT_DECIMAL:
2812 case VT_UI1:
2813 case VT_UI2:
2814 case VT_UI4:
2815 case VT_UI8:
2816 case VT_INT:
2817 case VT_UINT:
2818 case VT_LPSTR:
2819 case VT_LPWSTR:
2820 case VT_FILETIME:
2821 case VT_BLOB:
2822 case VT_DISPATCH:
2823 case VT_UNKNOWN:
2824 case VT_STREAM:
2825 case VT_STORAGE:
2826 case VT_STREAMED_OBJECT:
2827 case VT_STORED_OBJECT:
2828 case VT_BLOB_OBJECT:
2829 case VT_CF:
2830 case VT_CLSID:
2831 case VT_I1|VT_VECTOR:
2832 case VT_I2|VT_VECTOR:
2833 case VT_I4|VT_VECTOR:
2834 case VT_I8|VT_VECTOR:
2835 case VT_R4|VT_VECTOR:
2836 case VT_R8|VT_VECTOR:
2837 case VT_CY|VT_VECTOR:
2838 case VT_DATE|VT_VECTOR:
2839 case VT_BSTR|VT_VECTOR:
2840 case VT_ERROR|VT_VECTOR:
2841 case VT_BOOL|VT_VECTOR:
2842 case VT_VARIANT|VT_VECTOR:
2843 case VT_UI1|VT_VECTOR:
2844 case VT_UI2|VT_VECTOR:
2845 case VT_UI4|VT_VECTOR:
2846 case VT_UI8|VT_VECTOR:
2847 case VT_LPSTR|VT_VECTOR:
2848 case VT_LPWSTR|VT_VECTOR:
2849 case VT_FILETIME|VT_VECTOR:
2850 case VT_CF|VT_VECTOR:
2851 case VT_CLSID|VT_VECTOR:
2852 return S_OK;
2854 WARN("Bad type %d\n", vt);
2855 return STG_E_INVALIDPARAMETER;
2858 /***********************************************************************
2859 * PropVariantClear [OLE32.@]
2861 HRESULT WINAPI PropVariantClear(PROPVARIANT * pvar) /* [in/out] */
2863 HRESULT hr;
2865 TRACE("(%p)\n", pvar);
2867 if (!pvar)
2868 return S_OK;
2870 hr = PROPVARIANT_ValidateType(pvar->vt);
2871 if (FAILED(hr))
2873 memset(pvar, 0, sizeof(*pvar));
2874 return hr;
2877 switch(pvar->vt)
2879 case VT_EMPTY:
2880 case VT_NULL:
2881 case VT_I1:
2882 case VT_I2:
2883 case VT_I4:
2884 case VT_I8:
2885 case VT_R4:
2886 case VT_R8:
2887 case VT_CY:
2888 case VT_DATE:
2889 case VT_ERROR:
2890 case VT_BOOL:
2891 case VT_DECIMAL:
2892 case VT_UI1:
2893 case VT_UI2:
2894 case VT_UI4:
2895 case VT_UI8:
2896 case VT_INT:
2897 case VT_UINT:
2898 case VT_FILETIME:
2899 break;
2900 case VT_DISPATCH:
2901 case VT_UNKNOWN:
2902 case VT_STREAM:
2903 case VT_STREAMED_OBJECT:
2904 case VT_STORAGE:
2905 case VT_STORED_OBJECT:
2906 if (pvar->u.pStream)
2907 IStream_Release(pvar->u.pStream);
2908 break;
2909 case VT_CLSID:
2910 case VT_LPSTR:
2911 case VT_LPWSTR:
2912 /* pick an arbitrary typed pointer - we don't care about the type
2913 * as we are just freeing it */
2914 CoTaskMemFree(pvar->u.puuid);
2915 break;
2916 case VT_BLOB:
2917 case VT_BLOB_OBJECT:
2918 CoTaskMemFree(pvar->u.blob.pBlobData);
2919 break;
2920 case VT_BSTR:
2921 PropSysFreeString(pvar->u.bstrVal);
2922 break;
2923 case VT_CF:
2924 if (pvar->u.pclipdata)
2926 OLE_FreeClipDataArray(1, pvar->u.pclipdata);
2927 CoTaskMemFree(pvar->u.pclipdata);
2929 break;
2930 default:
2931 if (pvar->vt & VT_VECTOR)
2933 ULONG i;
2935 switch (pvar->vt & ~VT_VECTOR)
2937 case VT_VARIANT:
2938 FreePropVariantArray(pvar->u.capropvar.cElems, pvar->u.capropvar.pElems);
2939 break;
2940 case VT_CF:
2941 OLE_FreeClipDataArray(pvar->u.caclipdata.cElems, pvar->u.caclipdata.pElems);
2942 break;
2943 case VT_BSTR:
2944 for (i = 0; i < pvar->u.cabstr.cElems; i++)
2945 PropSysFreeString(pvar->u.cabstr.pElems[i]);
2946 break;
2947 case VT_LPSTR:
2948 for (i = 0; i < pvar->u.calpstr.cElems; i++)
2949 CoTaskMemFree(pvar->u.calpstr.pElems[i]);
2950 break;
2951 case VT_LPWSTR:
2952 for (i = 0; i < pvar->u.calpwstr.cElems; i++)
2953 CoTaskMemFree(pvar->u.calpwstr.pElems[i]);
2954 break;
2956 if (pvar->vt & ~VT_VECTOR)
2958 /* pick an arbitrary VT_VECTOR structure - they all have the same
2959 * memory layout */
2960 CoTaskMemFree(pvar->u.capropvar.pElems);
2963 else
2965 WARN("Invalid/unsupported type %d\n", pvar->vt);
2966 hr = STG_E_INVALIDPARAMETER;
2970 memset(pvar, 0, sizeof(*pvar));
2971 return hr;
2974 /***********************************************************************
2975 * PropVariantCopy [OLE32.@]
2977 HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, /* [out] */
2978 const PROPVARIANT *pvarSrc) /* [in] */
2980 ULONG len;
2981 HRESULT hr;
2983 TRACE("(%p, %p vt %04x)\n", pvarDest, pvarSrc, pvarSrc->vt);
2985 hr = PROPVARIANT_ValidateType(pvarSrc->vt);
2986 if (FAILED(hr))
2987 return DISP_E_BADVARTYPE;
2989 /* this will deal with most cases */
2990 *pvarDest = *pvarSrc;
2992 switch(pvarSrc->vt)
2994 case VT_EMPTY:
2995 case VT_NULL:
2996 case VT_I1:
2997 case VT_UI1:
2998 case VT_I2:
2999 case VT_UI2:
3000 case VT_BOOL:
3001 case VT_DECIMAL:
3002 case VT_I4:
3003 case VT_UI4:
3004 case VT_R4:
3005 case VT_ERROR:
3006 case VT_I8:
3007 case VT_UI8:
3008 case VT_INT:
3009 case VT_UINT:
3010 case VT_R8:
3011 case VT_CY:
3012 case VT_DATE:
3013 case VT_FILETIME:
3014 break;
3015 case VT_DISPATCH:
3016 case VT_UNKNOWN:
3017 case VT_STREAM:
3018 case VT_STREAMED_OBJECT:
3019 case VT_STORAGE:
3020 case VT_STORED_OBJECT:
3021 if (pvarDest->u.pStream)
3022 IStream_AddRef(pvarDest->u.pStream);
3023 break;
3024 case VT_CLSID:
3025 pvarDest->u.puuid = CoTaskMemAlloc(sizeof(CLSID));
3026 *pvarDest->u.puuid = *pvarSrc->u.puuid;
3027 break;
3028 case VT_LPSTR:
3029 if (pvarSrc->u.pszVal)
3031 len = strlen(pvarSrc->u.pszVal);
3032 pvarDest->u.pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR));
3033 CopyMemory(pvarDest->u.pszVal, pvarSrc->u.pszVal, (len+1)*sizeof(CHAR));
3035 break;
3036 case VT_LPWSTR:
3037 if (pvarSrc->u.pwszVal)
3039 len = lstrlenW(pvarSrc->u.pwszVal);
3040 pvarDest->u.pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
3041 CopyMemory(pvarDest->u.pwszVal, pvarSrc->u.pwszVal, (len+1)*sizeof(WCHAR));
3043 break;
3044 case VT_BLOB:
3045 case VT_BLOB_OBJECT:
3046 if (pvarSrc->u.blob.pBlobData)
3048 len = pvarSrc->u.blob.cbSize;
3049 pvarDest->u.blob.pBlobData = CoTaskMemAlloc(len);
3050 CopyMemory(pvarDest->u.blob.pBlobData, pvarSrc->u.blob.pBlobData, len);
3052 break;
3053 case VT_BSTR:
3054 pvarDest->u.bstrVal = PropSysAllocString(pvarSrc->u.bstrVal);
3055 break;
3056 case VT_CF:
3057 if (pvarSrc->u.pclipdata)
3059 len = pvarSrc->u.pclipdata->cbSize - sizeof(pvarSrc->u.pclipdata->ulClipFmt);
3060 pvarDest->u.pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA));
3061 pvarDest->u.pclipdata->cbSize = pvarSrc->u.pclipdata->cbSize;
3062 pvarDest->u.pclipdata->ulClipFmt = pvarSrc->u.pclipdata->ulClipFmt;
3063 pvarDest->u.pclipdata->pClipData = CoTaskMemAlloc(len);
3064 CopyMemory(pvarDest->u.pclipdata->pClipData, pvarSrc->u.pclipdata->pClipData, len);
3066 break;
3067 default:
3068 if (pvarSrc->vt & VT_VECTOR)
3070 int elemSize;
3071 ULONG i;
3073 switch(pvarSrc->vt & ~VT_VECTOR)
3075 case VT_I1: elemSize = sizeof(pvarSrc->u.cVal); break;
3076 case VT_UI1: elemSize = sizeof(pvarSrc->u.bVal); break;
3077 case VT_I2: elemSize = sizeof(pvarSrc->u.iVal); break;
3078 case VT_UI2: elemSize = sizeof(pvarSrc->u.uiVal); break;
3079 case VT_BOOL: elemSize = sizeof(pvarSrc->u.boolVal); break;
3080 case VT_I4: elemSize = sizeof(pvarSrc->u.lVal); break;
3081 case VT_UI4: elemSize = sizeof(pvarSrc->u.ulVal); break;
3082 case VT_R4: elemSize = sizeof(pvarSrc->u.fltVal); break;
3083 case VT_R8: elemSize = sizeof(pvarSrc->u.dblVal); break;
3084 case VT_ERROR: elemSize = sizeof(pvarSrc->u.scode); break;
3085 case VT_I8: elemSize = sizeof(pvarSrc->u.hVal); break;
3086 case VT_UI8: elemSize = sizeof(pvarSrc->u.uhVal); break;
3087 case VT_CY: elemSize = sizeof(pvarSrc->u.cyVal); break;
3088 case VT_DATE: elemSize = sizeof(pvarSrc->u.date); break;
3089 case VT_FILETIME: elemSize = sizeof(pvarSrc->u.filetime); break;
3090 case VT_CLSID: elemSize = sizeof(*pvarSrc->u.puuid); break;
3091 case VT_CF: elemSize = sizeof(*pvarSrc->u.pclipdata); break;
3092 case VT_BSTR: elemSize = sizeof(pvarSrc->u.bstrVal); break;
3093 case VT_LPSTR: elemSize = sizeof(pvarSrc->u.pszVal); break;
3094 case VT_LPWSTR: elemSize = sizeof(pvarSrc->u.pwszVal); break;
3095 case VT_VARIANT: elemSize = sizeof(*pvarSrc->u.pvarVal); break;
3097 default:
3098 FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR);
3099 return E_INVALIDARG;
3101 len = pvarSrc->u.capropvar.cElems;
3102 pvarDest->u.capropvar.pElems = len ? CoTaskMemAlloc(len * elemSize) : NULL;
3103 if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT))
3105 for (i = 0; i < len; i++)
3106 PropVariantCopy(&pvarDest->u.capropvar.pElems[i], &pvarSrc->u.capropvar.pElems[i]);
3108 else if (pvarSrc->vt == (VT_VECTOR | VT_CF))
3110 FIXME("Copy clipformats\n");
3112 else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR))
3114 for (i = 0; i < len; i++)
3115 pvarDest->u.cabstr.pElems[i] = PropSysAllocString(pvarSrc->u.cabstr.pElems[i]);
3117 else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
3119 size_t strLen;
3120 for (i = 0; i < len; i++)
3122 strLen = lstrlenA(pvarSrc->u.calpstr.pElems[i]) + 1;
3123 pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
3124 memcpy(pvarDest->u.calpstr.pElems[i],
3125 pvarSrc->u.calpstr.pElems[i], strLen);
3128 else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR))
3130 size_t strLen;
3131 for (i = 0; i < len; i++)
3133 strLen = (lstrlenW(pvarSrc->u.calpwstr.pElems[i]) + 1) *
3134 sizeof(WCHAR);
3135 pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
3136 memcpy(pvarDest->u.calpstr.pElems[i],
3137 pvarSrc->u.calpstr.pElems[i], strLen);
3140 else
3141 CopyMemory(pvarDest->u.capropvar.pElems, pvarSrc->u.capropvar.pElems, len * elemSize);
3143 else
3144 WARN("Invalid/unsupported type %d\n", pvarSrc->vt);
3147 return S_OK;
3150 /***********************************************************************
3151 * FreePropVariantArray [OLE32.@]
3153 HRESULT WINAPI FreePropVariantArray(ULONG cVariants, /* [in] */
3154 PROPVARIANT *rgvars) /* [in/out] */
3156 ULONG i;
3158 TRACE("(%u, %p)\n", cVariants, rgvars);
3160 if (!rgvars)
3161 return E_INVALIDARG;
3163 for(i = 0; i < cVariants; i++)
3164 PropVariantClear(&rgvars[i]);
3166 return S_OK;
3169 /******************************************************************************
3170 * DllDebugObjectRPCHook (OLE32.@)
3171 * turns on and off internal debugging, pointer is only used on macintosh
3174 BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy)
3176 FIXME("stub\n");
3177 return TRUE;