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
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
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 it's state.
60 typedef struct tagDropTargetNode
63 IDropTarget* dropTarget;
67 typedef struct tagTrackerWindowInfo
69 IDataObject* dataObject;
70 IDropSource* dropSource;
77 HWND curTargetHWND; /* window the mouse is hovering over */
78 HWND curDragTargetHWND; /* might be a ancestor of curTargetHWND */
79 IDropTarget* curDragTarget;
80 POINTL curMousePos; /* current position of the mouse in screen coordinates */
81 DWORD dwKeyState; /* current state of the shift and ctrl keys and the mouse buttons */
84 typedef struct tagOleMenuDescriptor /* OleMenuDescriptor */
86 HWND hwndFrame; /* The containers frame window */
87 HWND hwndActiveObject; /* The active objects window */
88 OLEMENUGROUPWIDTHS mgw; /* OLE menu group widths for the shared menu */
89 HMENU hmenuCombined; /* The combined menu */
90 BOOL bIsServerItem; /* True if the currently open popup belongs to the server */
93 typedef struct tagOleMenuHookItem /* OleMenu hook item in per thread hook list */
95 DWORD tid; /* Thread Id */
96 HANDLE hHeap; /* Heap this is allocated from */
97 HHOOK GetMsg_hHook; /* message hook for WH_GETMESSAGE */
98 HHOOK CallWndProc_hHook; /* message hook for WH_CALLWNDPROC */
99 struct tagOleMenuHookItem *next;
102 static OleMenuHookItem *hook_list;
105 * This is the lock count on the OLE library. It is controlled by the
106 * OLEInitialize/OLEUninitialize methods.
108 static LONG OLE_moduleLockCount = 0;
111 * Name of our registered window class.
113 static const WCHAR OLEDD_DRAGTRACKERCLASS[] =
114 {'W','i','n','e','D','r','a','g','D','r','o','p','T','r','a','c','k','e','r','3','2',0};
117 * Name of menu descriptor property.
119 static const WCHAR prop_olemenuW[] =
120 {'P','R','O','P','_','O','L','E','M','e','n','u','D','e','s','c','r','i','p','t','o','r',0};
123 * This is the head of the Drop target container.
125 static struct list targetListHead = LIST_INIT(targetListHead);
127 /******************************************************************************
128 * These are the prototypes of miscellaneous utility methods
130 static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue);
132 /******************************************************************************
133 * These are the prototypes of the utility methods used to manage a shared menu
135 static void OLEMenu_Initialize(void);
136 static void OLEMenu_UnInitialize(void);
137 static BOOL OLEMenu_InstallHooks( DWORD tid );
138 static BOOL OLEMenu_UnInstallHooks( DWORD tid );
139 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid );
140 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
141 static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor );
142 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam);
143 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam);
145 /******************************************************************************
146 * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c)
148 extern void OLEClipbrd_UnInitialize(void);
149 extern void OLEClipbrd_Initialize(void);
151 /******************************************************************************
152 * These are the prototypes of the utility methods used for OLE Drag n Drop
154 static void OLEDD_Initialize(void);
155 static DropTargetNode* OLEDD_FindDropTarget(
157 static void OLEDD_FreeDropTarget(DropTargetNode*, BOOL);
158 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
163 static void OLEDD_TrackMouseMove(
164 TrackerWindowInfo* trackerInfo);
165 static void OLEDD_TrackStateChange(
166 TrackerWindowInfo* trackerInfo);
167 static DWORD OLEDD_GetButtonState(void);
170 /******************************************************************************
171 * OleBuildVersion [OLE32.@]
173 DWORD WINAPI OleBuildVersion(void)
175 TRACE("Returning version %d, build %d.\n", rmm, rup);
176 return (rmm<<16)+rup;
179 /***********************************************************************
180 * OleInitialize (OLE32.@)
182 HRESULT WINAPI OleInitialize(LPVOID reserved)
186 TRACE("(%p)\n", reserved);
189 * The first duty of the OleInitialize is to initialize the COM libraries.
191 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
194 * If the CoInitializeEx call failed, the OLE libraries can't be
200 if (!COM_CurrentInfo()->ole_inits)
204 * Then, it has to initialize the OLE specific modules.
208 * Object linking and Embedding
209 * In-place activation
211 if (!COM_CurrentInfo()->ole_inits++ &&
212 InterlockedIncrement(&OLE_moduleLockCount) == 1)
215 * Initialize the libraries.
217 TRACE("() - Initializing the OLE libraries\n");
222 OLEClipbrd_Initialize();
232 OLEMenu_Initialize();
238 /******************************************************************************
239 * OleUninitialize [OLE32.@]
241 void WINAPI OleUninitialize(void)
246 * If we hit the bottom of the lock stack, free the libraries.
248 if (!--COM_CurrentInfo()->ole_inits && !InterlockedDecrement(&OLE_moduleLockCount))
251 * Actually free the libraries.
253 TRACE("() - Freeing the last reference count\n");
258 OLEClipbrd_UnInitialize();
263 OLEMenu_UnInitialize();
267 * Then, uninitialize the COM libraries.
272 /******************************************************************************
273 * OleInitializeWOW [OLE32.@]
275 HRESULT WINAPI OleInitializeWOW(DWORD x, DWORD y) {
276 FIXME("(0x%08x, 0x%08x),stub!\n",x, y);
280 /***********************************************************************
281 * RegisterDragDrop (OLE32.@)
283 HRESULT WINAPI RegisterDragDrop(
285 LPDROPTARGET pDropTarget)
287 DropTargetNode* dropTargetInfo;
289 TRACE("(%p,%p)\n", hwnd, pDropTarget);
291 if (!COM_CurrentApt())
293 ERR("COM not initialized\n");
294 return E_OUTOFMEMORY;
302 ERR("invalid hwnd %p\n", hwnd);
303 return DRAGDROP_E_INVALIDHWND;
307 * First, check if the window is already registered.
309 dropTargetInfo = OLEDD_FindDropTarget(hwnd);
311 if (dropTargetInfo!=NULL)
312 return DRAGDROP_E_ALREADYREGISTERED;
315 * If it's not there, we can add it. We first create a node for it.
317 dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));
319 if (dropTargetInfo==NULL)
320 return E_OUTOFMEMORY;
322 dropTargetInfo->hwndTarget = hwnd;
325 * Don't forget that this is an interface pointer, need to nail it down since
326 * we keep a copy of it.
328 IDropTarget_AddRef(pDropTarget);
329 dropTargetInfo->dropTarget = pDropTarget;
331 list_add_tail(&targetListHead, &dropTargetInfo->entry);
336 /***********************************************************************
337 * RevokeDragDrop (OLE32.@)
339 HRESULT WINAPI RevokeDragDrop(
342 DropTargetNode* dropTargetInfo;
344 TRACE("(%p)\n", hwnd);
348 ERR("invalid hwnd %p\n", hwnd);
349 return DRAGDROP_E_INVALIDHWND;
353 * First, check if the window is already registered.
355 dropTargetInfo = OLEDD_FindDropTarget(hwnd);
358 * If it ain't in there, it's an error.
360 if (dropTargetInfo==NULL)
361 return DRAGDROP_E_NOTREGISTERED;
363 OLEDD_FreeDropTarget(dropTargetInfo, TRUE);
368 /***********************************************************************
369 * OleRegGetUserType (OLE32.@)
371 * This implementation of OleRegGetUserType ignores the dwFormOfType
372 * parameter and always returns the full name of the object. This is
373 * not too bad since this is the case for many objects because of the
374 * way they are registered.
376 HRESULT WINAPI OleRegGetUserType(
379 LPOLESTR* pszUserType)
389 * Initialize the out parameter.
394 * Build the key name we're looking for
396 sprintf( keyName, "CLSID\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
397 clsid->Data1, clsid->Data2, clsid->Data3,
398 clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
399 clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
401 TRACE("(%s, %d, %p)\n", keyName, dwFormOfType, pszUserType);
404 * Open the class id Key
406 hres = RegOpenKeyA(HKEY_CLASSES_ROOT,
410 if (hres != ERROR_SUCCESS)
411 return REGDB_E_CLASSNOTREG;
414 * Retrieve the size of the name string.
418 hres = RegQueryValueExA(clsidKey,
425 if (hres!=ERROR_SUCCESS)
427 RegCloseKey(clsidKey);
428 return REGDB_E_READREGDB;
432 * Allocate a buffer for the registry value.
434 *pszUserType = CoTaskMemAlloc(cbData*2);
436 if (*pszUserType==NULL)
438 RegCloseKey(clsidKey);
439 return E_OUTOFMEMORY;
442 buffer = HeapAlloc(GetProcessHeap(), 0, cbData);
446 RegCloseKey(clsidKey);
447 CoTaskMemFree(*pszUserType);
449 return E_OUTOFMEMORY;
452 hres = RegQueryValueExA(clsidKey,
459 RegCloseKey(clsidKey);
462 if (hres!=ERROR_SUCCESS)
464 CoTaskMemFree(*pszUserType);
467 retVal = REGDB_E_READREGDB;
471 MultiByteToWideChar( CP_ACP, 0, buffer, -1, *pszUserType, cbData /*FIXME*/ );
474 HeapFree(GetProcessHeap(), 0, buffer);
479 /***********************************************************************
480 * DoDragDrop [OLE32.@]
482 HRESULT WINAPI DoDragDrop (
483 IDataObject *pDataObject, /* [in] ptr to the data obj */
484 IDropSource* pDropSource, /* [in] ptr to the source obj */
485 DWORD dwOKEffect, /* [in] effects allowed by the source */
486 DWORD *pdwEffect) /* [out] ptr to effects of the source */
488 static const WCHAR trackerW[] = {'T','r','a','c','k','e','r','W','i','n','d','o','w',0};
489 TrackerWindowInfo trackerInfo;
490 HWND hwndTrackWindow;
493 TRACE("(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
496 * Setup the drag n drop tracking window.
498 if (!IsValidInterface((LPUNKNOWN)pDropSource))
501 trackerInfo.dataObject = pDataObject;
502 trackerInfo.dropSource = pDropSource;
503 trackerInfo.dwOKEffect = dwOKEffect;
504 trackerInfo.pdwEffect = pdwEffect;
505 trackerInfo.trackingDone = FALSE;
506 trackerInfo.escPressed = FALSE;
507 trackerInfo.curDragTargetHWND = 0;
508 trackerInfo.curTargetHWND = 0;
509 trackerInfo.curDragTarget = 0;
511 hwndTrackWindow = CreateWindowW(OLEDD_DRAGTRACKERCLASS, trackerW,
512 WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
513 CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0,
519 * Capture the mouse input
521 SetCapture(hwndTrackWindow);
526 * Pump messages. All mouse input should go to the capture window.
528 while (!trackerInfo.trackingDone && GetMessageW(&msg, 0, 0, 0) )
530 trackerInfo.curMousePos.x = msg.pt.x;
531 trackerInfo.curMousePos.y = msg.pt.y;
532 trackerInfo.dwKeyState = OLEDD_GetButtonState();
534 if ( (msg.message >= WM_KEYFIRST) &&
535 (msg.message <= WM_KEYLAST) )
538 * When keyboard messages are sent to windows on this thread, we
539 * want to ignore notify the drop source that the state changed.
540 * in the case of the Escape key, we also notify the drop source
541 * we give it a special meaning.
543 if ( (msg.message==WM_KEYDOWN) &&
544 (msg.wParam==VK_ESCAPE) )
546 trackerInfo.escPressed = TRUE;
550 * Notify the drop source.
552 OLEDD_TrackStateChange(&trackerInfo);
557 * Dispatch the messages only when it's not a keyboard message.
559 DispatchMessageW(&msg);
563 /* re-post the quit message to outer message loop */
564 if (msg.message == WM_QUIT)
565 PostQuitMessage(msg.wParam);
567 * Destroy the temporary window.
569 DestroyWindow(hwndTrackWindow);
571 return trackerInfo.returnValue;
577 /***********************************************************************
578 * OleQueryLinkFromData [OLE32.@]
580 HRESULT WINAPI OleQueryLinkFromData(
581 IDataObject* pSrcDataObject)
583 FIXME("(%p),stub!\n", pSrcDataObject);
587 /***********************************************************************
588 * OleRegGetMiscStatus [OLE32.@]
590 HRESULT WINAPI OleRegGetMiscStatus(
602 * Initialize the out parameter.
607 * Build the key name we're looking for
609 sprintf( keyName, "CLSID\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
610 clsid->Data1, clsid->Data2, clsid->Data3,
611 clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
612 clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
614 TRACE("(%s, %d, %p)\n", keyName, dwAspect, pdwStatus);
617 * Open the class id Key
619 result = RegOpenKeyA(HKEY_CLASSES_ROOT,
623 if (result != ERROR_SUCCESS)
624 return REGDB_E_CLASSNOTREG;
629 result = RegOpenKeyA(clsidKey,
634 if (result != ERROR_SUCCESS)
636 RegCloseKey(clsidKey);
637 return REGDB_E_READREGDB;
641 * Read the default value
643 OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
646 * Open the key specific to the requested aspect.
648 sprintf(keyName, "%d", dwAspect);
650 result = RegOpenKeyA(miscStatusKey,
654 if (result == ERROR_SUCCESS)
656 OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
657 RegCloseKey(aspectKey);
663 RegCloseKey(miscStatusKey);
664 RegCloseKey(clsidKey);
669 static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum);
673 const IEnumOLEVERBVtbl *lpvtbl;
680 static HRESULT WINAPI EnumOLEVERB_QueryInterface(
681 IEnumOLEVERB *iface, REFIID riid, void **ppv)
683 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
684 if (IsEqualIID(riid, &IID_IUnknown) ||
685 IsEqualIID(riid, &IID_IEnumOLEVERB))
687 IUnknown_AddRef(iface);
691 return E_NOINTERFACE;
694 static ULONG WINAPI EnumOLEVERB_AddRef(
697 EnumOLEVERB *This = (EnumOLEVERB *)iface;
699 return InterlockedIncrement(&This->ref);
702 static ULONG WINAPI EnumOLEVERB_Release(
705 EnumOLEVERB *This = (EnumOLEVERB *)iface;
706 LONG refs = InterlockedDecrement(&This->ref);
710 RegCloseKey(This->hkeyVerb);
711 HeapFree(GetProcessHeap(), 0, This);
716 static HRESULT WINAPI EnumOLEVERB_Next(
717 IEnumOLEVERB *iface, ULONG celt, LPOLEVERB rgelt,
720 EnumOLEVERB *This = (EnumOLEVERB *)iface;
723 TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched);
728 for (; celt; celt--, rgelt++)
733 LPWSTR pwszMenuFlags;
735 LONG res = RegEnumKeyW(This->hkeyVerb, This->index, wszSubKey, sizeof(wszSubKey)/sizeof(wszSubKey[0]));
736 if (res == ERROR_NO_MORE_ITEMS)
741 else if (res != ERROR_SUCCESS)
743 ERR("RegEnumKeyW failed with error %d\n", res);
744 hr = REGDB_E_READREGDB;
747 res = RegQueryValueW(This->hkeyVerb, wszSubKey, NULL, &cbData);
748 if (res != ERROR_SUCCESS)
750 ERR("RegQueryValueW failed with error %d\n", res);
751 hr = REGDB_E_READREGDB;
754 pwszOLEVERB = CoTaskMemAlloc(cbData);
760 res = RegQueryValueW(This->hkeyVerb, wszSubKey, pwszOLEVERB, &cbData);
761 if (res != ERROR_SUCCESS)
763 ERR("RegQueryValueW failed with error %d\n", res);
764 hr = REGDB_E_READREGDB;
765 CoTaskMemFree(pwszOLEVERB);
769 TRACE("verb string: %s\n", debugstr_w(pwszOLEVERB));
770 pwszMenuFlags = strchrW(pwszOLEVERB, ',');
773 hr = OLEOBJ_E_INVALIDVERB;
774 CoTaskMemFree(pwszOLEVERB);
777 /* nul terminate the name string and advance to first character */
778 *pwszMenuFlags = '\0';
780 pwszAttribs = strchrW(pwszMenuFlags, ',');
783 hr = OLEOBJ_E_INVALIDVERB;
784 CoTaskMemFree(pwszOLEVERB);
787 /* nul terminate the menu string and advance to first character */
791 /* fill out structure for this verb */
792 rgelt->lVerb = atolW(wszSubKey);
793 rgelt->lpszVerbName = pwszOLEVERB; /* user should free */
794 rgelt->fuFlags = atolW(pwszMenuFlags);
795 rgelt->grfAttribs = atolW(pwszAttribs);
804 static HRESULT WINAPI EnumOLEVERB_Skip(
805 IEnumOLEVERB *iface, ULONG celt)
807 EnumOLEVERB *This = (EnumOLEVERB *)iface;
809 TRACE("(%d)\n", celt);
815 static HRESULT WINAPI EnumOLEVERB_Reset(
818 EnumOLEVERB *This = (EnumOLEVERB *)iface;
826 static HRESULT WINAPI EnumOLEVERB_Clone(
828 IEnumOLEVERB **ppenum)
830 EnumOLEVERB *This = (EnumOLEVERB *)iface;
832 TRACE("(%p)\n", ppenum);
833 if (!DuplicateHandle(GetCurrentProcess(), This->hkeyVerb, GetCurrentProcess(), (HANDLE *)&hkeyVerb, 0, FALSE, DUPLICATE_SAME_ACCESS))
834 return HRESULT_FROM_WIN32(GetLastError());
835 return EnumOLEVERB_Construct(hkeyVerb, This->index, ppenum);
838 static const IEnumOLEVERBVtbl EnumOLEVERB_VTable =
840 EnumOLEVERB_QueryInterface,
849 static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum)
851 EnumOLEVERB *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
854 RegCloseKey(hkeyVerb);
855 return E_OUTOFMEMORY;
857 This->lpvtbl = &EnumOLEVERB_VTable;
860 This->hkeyVerb = hkeyVerb;
861 *ppenum = (IEnumOLEVERB *)&This->lpvtbl;
865 /***********************************************************************
866 * OleRegEnumVerbs [OLE32.@]
868 * Enumerates verbs associated with a class stored in the registry.
871 * clsid [I] Class ID to enumerate the verbs for.
872 * ppenum [O] Enumerator.
876 * REGDB_E_CLASSNOTREG: The specified class does not have a key in the registry.
877 * REGDB_E_READREGDB: The class key could not be opened for some other reason.
878 * OLE_E_REGDB_KEY: The Verb subkey for the class is not present.
879 * OLEOBJ_E_NOVERBS: The Verb subkey for the class is empty.
881 HRESULT WINAPI OleRegEnumVerbs (REFCLSID clsid, LPENUMOLEVERB* ppenum)
886 static const WCHAR wszVerb[] = {'V','e','r','b',0};
888 TRACE("(%s, %p)\n", debugstr_guid(clsid), ppenum);
890 res = COM_OpenKeyForCLSID(clsid, wszVerb, KEY_READ, &hkeyVerb);
893 if (res == REGDB_E_CLASSNOTREG)
894 ERR("CLSID %s not registered\n", debugstr_guid(clsid));
895 else if (res == REGDB_E_KEYMISSING)
896 ERR("no Verbs key for class %s\n", debugstr_guid(clsid));
898 ERR("failed to open Verbs key for CLSID %s with error %d\n",
899 debugstr_guid(clsid), res);
903 res = RegQueryInfoKeyW(hkeyVerb, NULL, NULL, NULL, &dwSubKeys, NULL,
904 NULL, NULL, NULL, NULL, NULL, NULL);
905 if (res != ERROR_SUCCESS)
907 ERR("failed to get subkey count with error %d\n", GetLastError());
908 return REGDB_E_READREGDB;
913 WARN("class %s has no verbs\n", debugstr_guid(clsid));
914 RegCloseKey(hkeyVerb);
915 return OLEOBJ_E_NOVERBS;
918 return EnumOLEVERB_Construct(hkeyVerb, 0, ppenum);
921 /******************************************************************************
922 * OleSetContainedObject [OLE32.@]
924 HRESULT WINAPI OleSetContainedObject(
928 IRunnableObject* runnable = NULL;
931 TRACE("(%p,%x)\n", pUnknown, fContained);
933 hres = IUnknown_QueryInterface(pUnknown,
934 &IID_IRunnableObject,
939 hres = IRunnableObject_SetContainedObject(runnable, fContained);
941 IRunnableObject_Release(runnable);
949 /******************************************************************************
952 * Set the OLE object to the running state.
955 * pUnknown [I] OLE object to run.
959 * Failure: Any HRESULT code.
961 HRESULT WINAPI OleRun(LPUNKNOWN pUnknown)
963 IRunnableObject *runable;
966 TRACE("(%p)\n", pUnknown);
968 hres = IUnknown_QueryInterface(pUnknown, &IID_IRunnableObject, (void**)&runable);
970 return S_OK; /* Appears to return no error. */
972 hres = IRunnableObject_Run(runable, NULL);
973 IRunnableObject_Release(runable);
977 /******************************************************************************
980 HRESULT WINAPI OleLoad(
983 LPOLECLIENTSITE pClientSite,
986 IPersistStorage* persistStorage = NULL;
988 IOleObject* pOleObject = NULL;
992 TRACE("(%p, %s, %p, %p)\n", pStg, debugstr_guid(riid), pClientSite, ppvObj);
997 * TODO, Conversion ... OleDoAutoConvert
1001 * Get the class ID for the object.
1003 hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
1006 * Now, try and create the handler for the object
1008 hres = CoCreateInstance(&storageInfo.clsid,
1010 CLSCTX_INPROC_HANDLER|CLSCTX_INPROC_SERVER,
1015 * If that fails, as it will most times, load the default
1020 hres = OleCreateDefaultHandler(&storageInfo.clsid,
1027 * If we couldn't find a handler... this is bad. Abort the whole thing.
1034 hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (void **)&pOleObject);
1035 if (SUCCEEDED(hres))
1038 hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
1042 if (SUCCEEDED(hres))
1044 * Initialize the object with it's IPersistStorage interface.
1046 hres = IOleObject_QueryInterface(pUnk,
1047 &IID_IPersistStorage,
1048 (void**)&persistStorage);
1050 if (SUCCEEDED(hres))
1052 hres = IPersistStorage_Load(persistStorage, pStg);
1054 IPersistStorage_Release(persistStorage);
1055 persistStorage = NULL;
1058 if (SUCCEEDED(hres) && pClientSite)
1060 * Inform the new object of it's client site.
1062 hres = IOleObject_SetClientSite(pOleObject, pClientSite);
1065 * Cleanup interfaces used internally
1068 IOleObject_Release(pOleObject);
1070 if (SUCCEEDED(hres))
1074 hres1 = IUnknown_QueryInterface(pUnk, &IID_IOleLink, (void **)&pOleLink);
1075 if (SUCCEEDED(hres1))
1077 FIXME("handle OLE link\n");
1078 IOleLink_Release(pOleLink);
1084 IUnknown_Release(pUnk);
1093 /***********************************************************************
1096 HRESULT WINAPI OleSave(
1097 LPPERSISTSTORAGE pPS,
1104 TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad);
1107 * First, we transfer the class ID (if available)
1109 hres = IPersistStorage_GetClassID(pPS, &objectClass);
1111 if (SUCCEEDED(hres))
1113 WriteClassStg(pStg, &objectClass);
1117 * Then, we ask the object to save itself to the
1118 * storage. If it is successful, we commit the storage.
1120 hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad);
1122 if (SUCCEEDED(hres))
1124 IStorage_Commit(pStg,
1132 /******************************************************************************
1133 * OleLockRunning [OLE32.@]
1135 HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses)
1137 IRunnableObject* runnable = NULL;
1140 TRACE("(%p,%x,%x)\n", pUnknown, fLock, fLastUnlockCloses);
1142 hres = IUnknown_QueryInterface(pUnknown,
1143 &IID_IRunnableObject,
1146 if (SUCCEEDED(hres))
1148 hres = IRunnableObject_LockRunning(runnable, fLock, fLastUnlockCloses);
1150 IRunnableObject_Release(runnable);
1159 /**************************************************************************
1160 * Internal methods to manage the shared OLE menu in response to the
1161 * OLE***MenuDescriptor API
1165 * OLEMenu_Initialize()
1167 * Initializes the OLEMENU data structures.
1169 static void OLEMenu_Initialize(void)
1174 * OLEMenu_UnInitialize()
1176 * Releases the OLEMENU data structures.
1178 static void OLEMenu_UnInitialize(void)
1182 /*************************************************************************
1183 * OLEMenu_InstallHooks
1184 * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
1186 * RETURNS: TRUE if message hooks were successfully installed
1189 static BOOL OLEMenu_InstallHooks( DWORD tid )
1191 OleMenuHookItem *pHookItem;
1193 /* Create an entry for the hook table */
1194 if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
1195 sizeof(OleMenuHookItem)) ) )
1198 pHookItem->tid = tid;
1199 pHookItem->hHeap = GetProcessHeap();
1200 pHookItem->CallWndProc_hHook = NULL;
1202 /* Install a thread scope message hook for WH_GETMESSAGE */
1203 pHookItem->GetMsg_hHook = SetWindowsHookExW( WH_GETMESSAGE, OLEMenu_GetMsgProc,
1204 0, GetCurrentThreadId() );
1205 if ( !pHookItem->GetMsg_hHook )
1208 /* Install a thread scope message hook for WH_CALLWNDPROC */
1209 pHookItem->CallWndProc_hHook = SetWindowsHookExW( WH_CALLWNDPROC, OLEMenu_CallWndProc,
1210 0, GetCurrentThreadId() );
1211 if ( !pHookItem->CallWndProc_hHook )
1214 /* Insert the hook table entry */
1215 pHookItem->next = hook_list;
1216 hook_list = pHookItem;
1221 /* Unhook any hooks */
1222 if ( pHookItem->GetMsg_hHook )
1223 UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
1224 if ( pHookItem->CallWndProc_hHook )
1225 UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
1226 /* Release the hook table entry */
1227 HeapFree(pHookItem->hHeap, 0, pHookItem );
1232 /*************************************************************************
1233 * OLEMenu_UnInstallHooks
1234 * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
1236 * RETURNS: TRUE if message hooks were successfully installed
1239 static BOOL OLEMenu_UnInstallHooks( DWORD tid )
1241 OleMenuHookItem *pHookItem = NULL;
1242 OleMenuHookItem **ppHook = &hook_list;
1246 if ((*ppHook)->tid == tid)
1248 pHookItem = *ppHook;
1249 *ppHook = pHookItem->next;
1252 ppHook = &(*ppHook)->next;
1254 if (!pHookItem) return FALSE;
1256 /* Uninstall the hooks installed for this thread */
1257 if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
1259 if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
1262 /* Release the hook table entry */
1263 HeapFree(pHookItem->hHeap, 0, pHookItem );
1268 /* Release the hook table entry */
1269 HeapFree(pHookItem->hHeap, 0, pHookItem );
1274 /*************************************************************************
1275 * OLEMenu_IsHookInstalled
1276 * Tests if OLEMenu hooks have been installed for a thread
1278 * RETURNS: The pointer and index of the hook table entry for the tid
1279 * NULL and -1 for the index if no hooks were installed for this thread
1281 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )
1283 OleMenuHookItem *pHookItem;
1285 /* Do a simple linear search for an entry whose tid matches ours.
1286 * We really need a map but efficiency is not a concern here. */
1287 for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next)
1289 if ( tid == pHookItem->tid )
1296 /***********************************************************************
1297 * OLEMenu_FindMainMenuIndex
1299 * Used by OLEMenu API to find the top level group a menu item belongs to.
1300 * On success pnPos contains the index of the item in the top level menu group
1302 * RETURNS: TRUE if the ID was found, FALSE on failure
1304 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
1308 nItems = GetMenuItemCount( hMainMenu );
1310 for (i = 0; i < nItems; i++)
1314 /* Is the current item a submenu? */
1315 if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
1317 /* If the handle is the same we're done */
1318 if ( hsubmenu == hPopupMenu )
1324 /* Recursively search without updating pnPos */
1325 else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
1337 /***********************************************************************
1338 * OLEMenu_SetIsServerMenu
1340 * Checks whether a popup menu belongs to a shared menu group which is
1341 * owned by the server, and sets the menu descriptor state accordingly.
1342 * All menu messages from these groups should be routed to the server.
1344 * RETURNS: TRUE if the popup menu is part of a server owned group
1345 * FALSE if the popup menu is part of a container owned group
1347 static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
1349 UINT nPos = 0, nWidth, i;
1351 pOleMenuDescriptor->bIsServerItem = FALSE;
1353 /* Don't bother searching if the popup is the combined menu itself */
1354 if ( hmenu == pOleMenuDescriptor->hmenuCombined )
1357 /* Find the menu item index in the shared OLE menu that this item belongs to */
1358 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) )
1361 /* The group widths array has counts for the number of elements
1362 * in the groups File, Edit, Container, Object, Window, Help.
1363 * The Edit, Object & Help groups belong to the server object
1364 * and the other three belong to the container.
1365 * Loop through the group widths and locate the group we are a member of.
1367 for ( i = 0, nWidth = 0; i < 6; i++ )
1369 nWidth += pOleMenuDescriptor->mgw.width[i];
1370 if ( nPos < nWidth )
1372 /* Odd elements are server menu widths */
1373 pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;
1378 return pOleMenuDescriptor->bIsServerItem;
1381 /*************************************************************************
1382 * OLEMenu_CallWndProc
1383 * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
1384 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1386 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
1389 HOLEMENU hOleMenu = 0;
1390 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1391 OleMenuHookItem *pHookItem = NULL;
1394 TRACE("%i, %04lx, %08lx\n", code, wParam, lParam );
1396 /* Check if we're being asked to process the message */
1397 if ( HC_ACTION != code )
1400 /* Retrieve the current message being dispatched from lParam */
1401 pMsg = (LPCWPSTRUCT)lParam;
1403 /* Check if the message is destined for a window we are interested in:
1404 * If the window has an OLEMenu property we may need to dispatch
1405 * the menu message to its active objects window instead. */
1407 hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW );
1411 /* Get the menu descriptor */
1412 pOleMenuDescriptor = GlobalLock( hOleMenu );
1413 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1416 /* Process menu messages */
1417 switch( pMsg->message )
1421 /* Reset the menu descriptor state */
1422 pOleMenuDescriptor->bIsServerItem = FALSE;
1424 /* Send this message to the server as well */
1425 SendMessageW( pOleMenuDescriptor->hwndActiveObject,
1426 pMsg->message, pMsg->wParam, pMsg->lParam );
1430 case WM_INITMENUPOPUP:
1432 /* Save the state for whether this is a server owned menu */
1433 OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
1439 fuFlags = HIWORD(pMsg->wParam); /* Get flags */
1440 if ( fuFlags & MF_SYSMENU )
1443 /* Save the state for whether this is a server owned popup menu */
1444 else if ( fuFlags & MF_POPUP )
1445 OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
1452 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
1453 if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
1454 goto NEXTHOOK; /* Not a menu message */
1463 /* If the message was for the server dispatch it accordingly */
1464 if ( pOleMenuDescriptor->bIsServerItem )
1466 SendMessageW( pOleMenuDescriptor->hwndActiveObject,
1467 pMsg->message, pMsg->wParam, pMsg->lParam );
1471 if ( pOleMenuDescriptor )
1472 GlobalUnlock( hOleMenu );
1474 /* Lookup the hook item for the current thread */
1475 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1477 /* This should never fail!! */
1478 WARN("could not retrieve hHook for current thread!\n" );
1482 /* Pass on the message to the next hooker */
1483 return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
1486 /*************************************************************************
1487 * OLEMenu_GetMsgProc
1488 * Thread scope WH_GETMESSAGE hook proc filter function (callback)
1489 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1491 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
1494 HOLEMENU hOleMenu = 0;
1495 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1496 OleMenuHookItem *pHookItem = NULL;
1499 TRACE("%i, %04lx, %08lx\n", code, wParam, lParam );
1501 /* Check if we're being asked to process a messages */
1502 if ( HC_ACTION != code )
1505 /* Retrieve the current message being dispatched from lParam */
1506 pMsg = (LPMSG)lParam;
1508 /* Check if the message is destined for a window we are interested in:
1509 * If the window has an OLEMenu property we may need to dispatch
1510 * the menu message to its active objects window instead. */
1512 hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW );
1516 /* Process menu messages */
1517 switch( pMsg->message )
1521 wCode = HIWORD(pMsg->wParam); /* Get notification code */
1523 goto NEXTHOOK; /* Not a menu message */
1530 /* Get the menu descriptor */
1531 pOleMenuDescriptor = GlobalLock( hOleMenu );
1532 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1535 /* If the message was for the server dispatch it accordingly */
1536 if ( pOleMenuDescriptor->bIsServerItem )
1538 /* Change the hWnd in the message to the active objects hWnd.
1539 * The message loop which reads this message will automatically
1540 * dispatch it to the embedded objects window. */
1541 pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
1545 if ( pOleMenuDescriptor )
1546 GlobalUnlock( hOleMenu );
1548 /* Lookup the hook item for the current thread */
1549 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1551 /* This should never fail!! */
1552 WARN("could not retrieve hHook for current thread!\n" );
1556 /* Pass on the message to the next hooker */
1557 return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
1560 /***********************************************************************
1561 * OleCreateMenuDescriptor [OLE32.@]
1562 * Creates an OLE menu descriptor for OLE to use when dispatching
1563 * menu messages and commands.
1566 * hmenuCombined - Handle to the objects combined menu
1567 * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group
1570 HOLEMENU WINAPI OleCreateMenuDescriptor(
1571 HMENU hmenuCombined,
1572 LPOLEMENUGROUPWIDTHS lpMenuWidths)
1575 OleMenuDescriptor *pOleMenuDescriptor;
1578 if ( !hmenuCombined || !lpMenuWidths )
1581 /* Create an OLE menu descriptor */
1582 if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
1583 sizeof(OleMenuDescriptor) ) ) )
1586 pOleMenuDescriptor = GlobalLock( hOleMenu );
1587 if ( !pOleMenuDescriptor )
1590 /* Initialize menu group widths and hmenu */
1591 for ( i = 0; i < 6; i++ )
1592 pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
1594 pOleMenuDescriptor->hmenuCombined = hmenuCombined;
1595 pOleMenuDescriptor->bIsServerItem = FALSE;
1596 GlobalUnlock( hOleMenu );
1601 /***********************************************************************
1602 * OleDestroyMenuDescriptor [OLE32.@]
1603 * Destroy the shared menu descriptor
1605 HRESULT WINAPI OleDestroyMenuDescriptor(
1606 HOLEMENU hmenuDescriptor)
1608 if ( hmenuDescriptor )
1609 GlobalFree( hmenuDescriptor );
1613 /***********************************************************************
1614 * OleSetMenuDescriptor [OLE32.@]
1615 * Installs or removes OLE dispatching code for the containers frame window.
1618 * hOleMenu Handle to composite menu descriptor
1619 * hwndFrame Handle to containers frame window
1620 * hwndActiveObject Handle to objects in-place activation window
1621 * lpFrame Pointer to IOleInPlaceFrame on containers window
1622 * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object
1625 * S_OK - menu installed correctly
1626 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1629 * The lpFrame and lpActiveObject parameters are currently ignored
1630 * OLE should install context sensitive help F1 filtering for the app when
1631 * these are non null.
1633 HRESULT WINAPI OleSetMenuDescriptor(
1636 HWND hwndActiveObject,
1637 LPOLEINPLACEFRAME lpFrame,
1638 LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1640 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1643 if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
1644 return E_INVALIDARG;
1646 if ( lpFrame || lpActiveObject )
1648 FIXME("(%p, %p, %p, %p, %p), Context sensitive help filtering not implemented!\n",
1656 /* Set up a message hook to intercept the containers frame window messages.
1657 * The message filter is responsible for dispatching menu messages from the
1658 * shared menu which are intended for the object.
1661 if ( hOleMenu ) /* Want to install dispatching code */
1663 /* If OLEMenu hooks are already installed for this thread, fail
1664 * Note: This effectively means that OleSetMenuDescriptor cannot
1665 * be called twice in succession on the same frame window
1666 * without first calling it with a null hOleMenu to uninstall */
1667 if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) )
1670 /* Get the menu descriptor */
1671 pOleMenuDescriptor = GlobalLock( hOleMenu );
1672 if ( !pOleMenuDescriptor )
1673 return E_UNEXPECTED;
1675 /* Update the menu descriptor */
1676 pOleMenuDescriptor->hwndFrame = hwndFrame;
1677 pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
1679 GlobalUnlock( hOleMenu );
1680 pOleMenuDescriptor = NULL;
1682 /* Add a menu descriptor windows property to the frame window */
1683 SetPropW( hwndFrame, prop_olemenuW, hOleMenu );
1685 /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
1686 if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
1689 else /* Want to uninstall dispatching code */
1691 /* Uninstall the hooks */
1692 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1695 /* Remove the menu descriptor property from the frame window */
1696 RemovePropW( hwndFrame, prop_olemenuW );
1702 /******************************************************************************
1703 * IsAccelerator [OLE32.@]
1704 * Mostly copied from controls/menu.c TranslateAccelerator implementation
1706 BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd)
1711 if(!lpMsg) return FALSE;
1714 WARN_(accel)("NULL accel handle\n");
1717 if((lpMsg->message != WM_KEYDOWN &&
1718 lpMsg->message != WM_SYSKEYDOWN &&
1719 lpMsg->message != WM_SYSCHAR &&
1720 lpMsg->message != WM_CHAR)) return FALSE;
1721 lpAccelTbl = HeapAlloc(GetProcessHeap(), 0, cAccelEntries * sizeof(ACCEL));
1722 if (NULL == lpAccelTbl)
1726 if (CopyAcceleratorTableW(hAccel, lpAccelTbl, cAccelEntries) != cAccelEntries)
1728 WARN_(accel)("CopyAcceleratorTableW failed\n");
1729 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1733 TRACE_(accel)("hAccel=%p, cAccelEntries=%d,"
1734 "msg->hwnd=%p, msg->message=%04x, wParam=%08lx, lParam=%08lx\n",
1735 hAccel, cAccelEntries,
1736 lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);
1737 for(i = 0; i < cAccelEntries; i++)
1739 if(lpAccelTbl[i].key != lpMsg->wParam)
1742 if(lpMsg->message == WM_CHAR)
1744 if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY))
1746 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", LOWORD(lpMsg->wParam) & 0xff);
1752 if(lpAccelTbl[i].fVirt & FVIRTKEY)
1755 TRACE_(accel)("found accel for virt_key %04lx (scan %04x)\n",
1756 lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff);
1757 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
1758 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
1759 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
1760 if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
1761 TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n");
1765 if(!(lpMsg->lParam & 0x01000000)) /* no special_key */
1767 if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000))
1768 { /* ^^ ALT pressed */
1769 TRACE_(accel)("found accel for Alt-%c\n", LOWORD(lpMsg->wParam) & 0xff);
1777 WARN_(accel)("couldn't translate accelerator key\n");
1778 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1782 if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd;
1783 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1787 /***********************************************************************
1788 * ReleaseStgMedium [OLE32.@]
1790 void WINAPI ReleaseStgMedium(
1793 switch (pmedium->tymed)
1797 if ( (pmedium->pUnkForRelease==0) &&
1798 (pmedium->u.hGlobal!=0) )
1799 GlobalFree(pmedium->u.hGlobal);
1804 if (pmedium->u.lpszFileName!=0)
1806 if (pmedium->pUnkForRelease==0)
1808 DeleteFileW(pmedium->u.lpszFileName);
1811 CoTaskMemFree(pmedium->u.lpszFileName);
1817 if (pmedium->u.pstm!=0)
1819 IStream_Release(pmedium->u.pstm);
1823 case TYMED_ISTORAGE:
1825 if (pmedium->u.pstg!=0)
1827 IStorage_Release(pmedium->u.pstg);
1833 if ( (pmedium->pUnkForRelease==0) &&
1834 (pmedium->u.hBitmap!=0) )
1835 DeleteObject(pmedium->u.hBitmap);
1840 if ( (pmedium->pUnkForRelease==0) &&
1841 (pmedium->u.hMetaFilePict!=0) )
1843 LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hMetaFilePict);
1844 DeleteMetaFile(pMP->hMF);
1845 GlobalUnlock(pmedium->u.hMetaFilePict);
1846 GlobalFree(pmedium->u.hMetaFilePict);
1852 if ( (pmedium->pUnkForRelease==0) &&
1853 (pmedium->u.hEnhMetaFile!=0) )
1855 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
1863 pmedium->tymed=TYMED_NULL;
1866 * After cleaning up, the unknown is released
1868 if (pmedium->pUnkForRelease!=0)
1870 IUnknown_Release(pmedium->pUnkForRelease);
1871 pmedium->pUnkForRelease = 0;
1876 * OLEDD_Initialize()
1878 * Initializes the OLE drag and drop data structures.
1880 static void OLEDD_Initialize(void)
1884 ZeroMemory (&wndClass, sizeof(WNDCLASSW));
1885 wndClass.style = CS_GLOBALCLASS;
1886 wndClass.lpfnWndProc = OLEDD_DragTrackerWindowProc;
1887 wndClass.cbClsExtra = 0;
1888 wndClass.cbWndExtra = sizeof(TrackerWindowInfo*);
1889 wndClass.hCursor = 0;
1890 wndClass.hbrBackground = 0;
1891 wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
1893 RegisterClassW (&wndClass);
1897 * OLEDD_FreeDropTarget()
1899 * Frees the drag and drop data structure
1901 static void OLEDD_FreeDropTarget(DropTargetNode *dropTargetInfo, BOOL release_drop_target)
1903 list_remove(&dropTargetInfo->entry);
1904 if (release_drop_target) IDropTarget_Release(dropTargetInfo->dropTarget);
1905 HeapFree(GetProcessHeap(), 0, dropTargetInfo);
1909 * OLEDD_UnInitialize()
1911 * Releases the OLE drag and drop data structures.
1913 void OLEDD_UnInitialize(void)
1916 * Simply empty the list.
1918 while (!list_empty(&targetListHead))
1920 DropTargetNode* curNode = LIST_ENTRY(list_head(&targetListHead), DropTargetNode, entry);
1921 OLEDD_FreeDropTarget(curNode, FALSE);
1926 * OLEDD_FindDropTarget()
1928 * Finds information about the drop target.
1930 static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
1932 DropTargetNode* curNode;
1935 * Iterate the list to find the HWND value.
1937 LIST_FOR_EACH_ENTRY(curNode, &targetListHead, DropTargetNode, entry)
1938 if (hwndOfTarget==curNode->hwndTarget)
1942 * If we get here, the item is not in the list
1948 * OLEDD_DragTrackerWindowProc()
1950 * This method is the WindowProcedure of the drag n drop tracking
1951 * window. During a drag n Drop operation, an invisible window is created
1952 * to receive the user input and act upon it. This procedure is in charge
1956 #define DRAG_TIMER_ID 1
1958 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
1968 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
1970 SetWindowLongPtrW(hwnd, 0, (LONG_PTR)createStruct->lpCreateParams);
1971 SetTimer(hwnd, DRAG_TIMER_ID, 50, NULL);
1978 OLEDD_TrackMouseMove((TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0));
1984 case WM_LBUTTONDOWN:
1985 case WM_MBUTTONDOWN:
1986 case WM_RBUTTONDOWN:
1988 OLEDD_TrackStateChange((TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0));
1993 KillTimer(hwnd, DRAG_TIMER_ID);
1999 * This is a window proc after all. Let's call the default.
2001 return DefWindowProcW (hwnd, uMsg, wParam, lParam);
2005 * OLEDD_TrackMouseMove()
2007 * This method is invoked while a drag and drop operation is in effect.
2008 * it will generate the appropriate callbacks in the drop source
2009 * and drop target. It will also provide the expected feedback to
2013 * trackerInfo - Pointer to the structure identifying the
2014 * drag & drop operation that is currently
2017 static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo)
2019 HWND hwndNewTarget = 0;
2024 * Get the handle of the window under the mouse
2026 pt.x = trackerInfo->curMousePos.x;
2027 pt.y = trackerInfo->curMousePos.y;
2028 hwndNewTarget = WindowFromPoint(pt);
2031 * Every time, we re-initialize the effects passed to the
2032 * IDropTarget to the effects allowed by the source.
2034 *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
2037 * If we are hovering over the same target as before, send the
2038 * DragOver notification
2040 if ( (trackerInfo->curDragTarget != 0) &&
2041 (trackerInfo->curTargetHWND == hwndNewTarget) )
2043 IDropTarget_DragOver(trackerInfo->curDragTarget,
2044 trackerInfo->dwKeyState,
2045 trackerInfo->curMousePos,
2046 trackerInfo->pdwEffect);
2050 DropTargetNode* newDropTargetNode = 0;
2053 * If we changed window, we have to notify our old target and check for
2056 if (trackerInfo->curDragTarget!=0)
2058 IDropTarget_DragLeave(trackerInfo->curDragTarget);
2062 * Make sure we're hovering over a window.
2064 if (hwndNewTarget!=0)
2067 * Find-out if there is a drag target under the mouse
2069 HWND nexttar = hwndNewTarget;
2070 trackerInfo->curTargetHWND = hwndNewTarget;
2073 newDropTargetNode = OLEDD_FindDropTarget(nexttar);
2074 } while (!newDropTargetNode && (nexttar = GetParent(nexttar)) != 0);
2075 if(nexttar) hwndNewTarget = nexttar;
2077 trackerInfo->curDragTargetHWND = hwndNewTarget;
2078 trackerInfo->curDragTarget = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
2081 * If there is, notify it that we just dragged-in
2083 if (trackerInfo->curDragTarget!=0)
2085 IDropTarget_DragEnter(trackerInfo->curDragTarget,
2086 trackerInfo->dataObject,
2087 trackerInfo->dwKeyState,
2088 trackerInfo->curMousePos,
2089 trackerInfo->pdwEffect);
2095 * The mouse is not over a window so we don't track anything.
2097 trackerInfo->curDragTargetHWND = 0;
2098 trackerInfo->curTargetHWND = 0;
2099 trackerInfo->curDragTarget = 0;
2104 * Now that we have done that, we have to tell the source to give
2105 * us feedback on the work being done by the target. If we don't
2106 * have a target, simulate no effect.
2108 if (trackerInfo->curDragTarget==0)
2110 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2113 hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
2114 *trackerInfo->pdwEffect);
2117 * When we ask for feedback from the drop source, sometimes it will
2118 * do all the necessary work and sometimes it will not handle it
2119 * when that's the case, we must display the standard drag and drop
2122 if (hr == DRAGDROP_S_USEDEFAULTCURSORS)
2126 if (*trackerInfo->pdwEffect & DROPEFFECT_MOVE)
2128 hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(1));
2130 else if (*trackerInfo->pdwEffect & DROPEFFECT_COPY)
2132 hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(2));
2134 else if (*trackerInfo->pdwEffect & DROPEFFECT_LINK)
2136 hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(3));
2140 hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(0));
2148 * OLEDD_TrackStateChange()
2150 * This method is invoked while a drag and drop operation is in effect.
2151 * It is used to notify the drop target/drop source callbacks when
2152 * the state of the keyboard or mouse button change.
2155 * trackerInfo - Pointer to the structure identifying the
2156 * drag & drop operation that is currently
2159 static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo)
2162 * Ask the drop source what to do with the operation.
2164 trackerInfo->returnValue = IDropSource_QueryContinueDrag(
2165 trackerInfo->dropSource,
2166 trackerInfo->escPressed,
2167 trackerInfo->dwKeyState);
2170 * All the return valued will stop the operation except the S_OK
2173 if (trackerInfo->returnValue!=S_OK)
2176 * Make sure the message loop in DoDragDrop stops
2178 trackerInfo->trackingDone = TRUE;
2181 * Release the mouse in case the drop target decides to show a popup
2182 * or a menu or something.
2187 * If we end-up over a target, drop the object in the target or
2188 * inform the target that the operation was cancelled.
2190 if (trackerInfo->curDragTarget!=0)
2192 switch (trackerInfo->returnValue)
2195 * If the source wants us to complete the operation, we tell
2196 * the drop target that we just dropped the object in it.
2198 case DRAGDROP_S_DROP:
2200 IDropTarget_Drop(trackerInfo->curDragTarget,
2201 trackerInfo->dataObject,
2202 trackerInfo->dwKeyState,
2203 trackerInfo->curMousePos,
2204 trackerInfo->pdwEffect);
2208 * If the source told us that we should cancel, fool the drop
2209 * target by telling it that the mouse left it's window.
2210 * Also set the drop effect to "NONE" in case the application
2211 * ignores the result of DoDragDrop.
2213 case DRAGDROP_S_CANCEL:
2214 IDropTarget_DragLeave(trackerInfo->curDragTarget);
2215 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2223 * OLEDD_GetButtonState()
2225 * This method will use the current state of the keyboard to build
2226 * a button state mask equivalent to the one passed in the
2227 * WM_MOUSEMOVE wParam.
2229 static DWORD OLEDD_GetButtonState(void)
2231 BYTE keyboardState[256];
2234 GetKeyboardState(keyboardState);
2236 if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
2237 keyMask |= MK_SHIFT;
2239 if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
2240 keyMask |= MK_CONTROL;
2242 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
2243 keyMask |= MK_LBUTTON;
2245 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
2246 keyMask |= MK_RBUTTON;
2248 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
2249 keyMask |= MK_MBUTTON;
2255 * OLEDD_GetButtonState()
2257 * This method will read the default value of the registry key in
2258 * parameter and extract a DWORD value from it. The registry key value
2259 * can be in a string key or a DWORD key.
2262 * regKey - Key to read the default value from
2263 * pdwValue - Pointer to the location where the DWORD
2264 * value is returned. This value is not modified
2265 * if the value is not found.
2268 static void OLEUTL_ReadRegistryDWORDValue(
2273 DWORD cbData = sizeof(buffer);
2277 lres = RegQueryValueExA(regKey,
2284 if (lres==ERROR_SUCCESS)
2289 *pdwValue = *(DWORD*)buffer;
2294 *pdwValue = (DWORD)strtoul(buffer, NULL, 10);
2300 /******************************************************************************
2303 * The operation of this function is documented literally in the WinAPI
2304 * documentation to involve a QueryInterface for the IViewObject interface,
2305 * followed by a call to IViewObject::Draw.
2307 HRESULT WINAPI OleDraw(
2314 IViewObject *viewobject;
2316 hres = IUnknown_QueryInterface(pUnk,
2318 (void**)&viewobject);
2320 if (SUCCEEDED(hres))
2324 rectl.left = lprcBounds->left;
2325 rectl.right = lprcBounds->right;
2326 rectl.top = lprcBounds->top;
2327 rectl.bottom = lprcBounds->bottom;
2328 hres = IViewObject_Draw(viewobject, dwAspect, -1, 0, 0, 0, hdcDraw, &rectl, 0, 0, 0);
2330 IViewObject_Release(viewobject);
2335 return DV_E_NOIVIEWOBJECT;
2339 /***********************************************************************
2340 * OleTranslateAccelerator [OLE32.@]
2342 HRESULT WINAPI OleTranslateAccelerator (LPOLEINPLACEFRAME lpFrame,
2343 LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpmsg)
2347 TRACE("(%p,%p,%p)\n", lpFrame, lpFrameInfo, lpmsg);
2349 if (IsAccelerator(lpFrameInfo->haccel,lpFrameInfo->cAccelEntries,lpmsg,&wID))
2350 return IOleInPlaceFrame_TranslateAccelerator(lpFrame,lpmsg,wID);
2355 /******************************************************************************
2356 * OleCreate [OLE32.@]
2359 HRESULT WINAPI OleCreate(
2363 LPFORMATETC pFormatEtc,
2364 LPOLECLIENTSITE pClientSite,
2369 IUnknown * pUnk = NULL;
2370 IOleObject *pOleObject = NULL;
2372 TRACE("(%s, %s, %d, %p, %p, %p, %p)\n", debugstr_guid(rclsid),
2373 debugstr_guid(riid), renderopt, pFormatEtc, pClientSite, pStg, ppvObj);
2375 hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, riid, (LPVOID*)&pUnk);
2377 if (SUCCEEDED(hres))
2378 hres = IStorage_SetClass(pStg, rclsid);
2380 if (pClientSite && SUCCEEDED(hres))
2382 hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (LPVOID*)&pOleObject);
2383 if (SUCCEEDED(hres))
2386 hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
2390 if (SUCCEEDED(hres))
2392 IPersistStorage * pPS;
2393 if (SUCCEEDED((hres = IUnknown_QueryInterface(pUnk, &IID_IPersistStorage, (LPVOID*)&pPS))))
2395 TRACE("trying to set stg %p\n", pStg);
2396 hres = IPersistStorage_InitNew(pPS, pStg);
2397 TRACE("-- result 0x%08x\n", hres);
2398 IPersistStorage_Release(pPS);
2402 if (pClientSite && SUCCEEDED(hres))
2404 TRACE("trying to set clientsite %p\n", pClientSite);
2405 hres = IOleObject_SetClientSite(pOleObject, pClientSite);
2406 TRACE("-- result 0x%08x\n", hres);
2410 IOleObject_Release(pOleObject);
2412 if (((renderopt == OLERENDER_DRAW) || (renderopt == OLERENDER_FORMAT)) &&
2415 IRunnableObject *pRunnable;
2416 IOleCache *pOleCache;
2419 hres2 = IUnknown_QueryInterface(pUnk, &IID_IRunnableObject, (void **)&pRunnable);
2420 if (SUCCEEDED(hres2))
2422 hres = IRunnableObject_Run(pRunnable, NULL);
2423 IRunnableObject_Release(pRunnable);
2426 if (SUCCEEDED(hres))
2428 hres2 = IUnknown_QueryInterface(pUnk, &IID_IOleCache, (void **)&pOleCache);
2429 if (SUCCEEDED(hres2))
2432 hres = IOleCache_Cache(pOleCache, pFormatEtc, ADVF_PRIMEFIRST, &dwConnection);
2433 IOleCache_Release(pOleCache);
2438 if (FAILED(hres) && pUnk)
2440 IUnknown_Release(pUnk);
2446 TRACE("-- %p\n", pUnk);
2450 /******************************************************************************
2451 * OleGetAutoConvert [OLE32.@]
2453 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2455 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2457 WCHAR buf[CHARS_IN_GUID];
2461 res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey);
2466 if (RegQueryValueW(hkey, NULL, buf, &len))
2468 res = REGDB_E_KEYMISSING;
2471 res = CLSIDFromString(buf, pClsidNew);
2473 if (hkey) RegCloseKey(hkey);
2477 /******************************************************************************
2478 * OleSetAutoConvert [OLE32.@]
2480 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
2482 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2484 WCHAR szClsidNew[CHARS_IN_GUID];
2487 TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
2489 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2492 StringFromGUID2(clsidNew, szClsidNew, CHARS_IN_GUID);
2493 if (RegSetValueW(hkey, wszAutoConvertTo, REG_SZ, szClsidNew, (strlenW(szClsidNew)+1) * sizeof(WCHAR)))
2495 res = REGDB_E_WRITEREGDB;
2500 if (hkey) RegCloseKey(hkey);
2504 /******************************************************************************
2505 * OleDoAutoConvert [OLE32.@]
2507 HRESULT WINAPI OleDoAutoConvert(LPSTORAGE pStg, LPCLSID pClsidNew)
2509 FIXME("(%p,%p) : stub\n",pStg,pClsidNew);
2513 /******************************************************************************
2514 * OleIsRunning [OLE32.@]
2516 BOOL WINAPI OleIsRunning(LPOLEOBJECT pObject)
2518 IRunnableObject *pRunnable;
2522 TRACE("(%p)\n", pObject);
2524 hr = IOleObject_QueryInterface(pObject, &IID_IRunnableObject, (void **)&pRunnable);
2527 running = IRunnableObject_IsRunning(pRunnable);
2528 IRunnableObject_Release(pRunnable);
2532 /***********************************************************************
2533 * OleNoteObjectVisible [OLE32.@]
2535 HRESULT WINAPI OleNoteObjectVisible(LPUNKNOWN pUnknown, BOOL bVisible)
2537 TRACE("(%p, %s)\n", pUnknown, bVisible ? "TRUE" : "FALSE");
2538 return CoLockObjectExternal(pUnknown, bVisible, TRUE);
2542 /***********************************************************************
2543 * OLE_FreeClipDataArray [internal]
2546 * frees the data associated with an array of CLIPDATAs
2548 static void OLE_FreeClipDataArray(ULONG count, CLIPDATA * pClipDataArray)
2551 for (i = 0; i < count; i++)
2552 if (pClipDataArray[i].pClipData)
2553 CoTaskMemFree(pClipDataArray[i].pClipData);
2556 /***********************************************************************
2557 * PropSysAllocString [OLE32.@]
2559 * Basically a copy of SysAllocStringLen.
2561 BSTR WINAPI PropSysAllocString(LPCOLESTR str)
2565 WCHAR* stringBuffer;
2570 len = lstrlenW(str);
2572 * Find the length of the buffer passed-in, in bytes.
2574 bufferSize = len * sizeof (WCHAR);
2577 * Allocate a new buffer to hold the string.
2578 * Don't forget to keep an empty spot at the beginning of the
2579 * buffer for the character count and an extra character at the
2582 newBuffer = HeapAlloc(GetProcessHeap(), 0,
2583 bufferSize + sizeof(WCHAR) + sizeof(DWORD));
2586 * If the memory allocation failed, return a null pointer.
2592 * Copy the length of the string in the placeholder.
2594 *newBuffer = bufferSize;
2597 * Skip the byte count.
2601 memcpy(newBuffer, str, bufferSize);
2604 * Make sure that there is a nul character at the end of the
2607 stringBuffer = (WCHAR*)newBuffer;
2608 stringBuffer[len] = '\0';
2610 return stringBuffer;
2613 /***********************************************************************
2614 * PropSysFreeString [OLE32.@]
2616 * Copy of SysFreeString.
2618 void WINAPI PropSysFreeString(LPOLESTR str)
2620 DWORD* bufferPointer;
2622 /* NULL is a valid parameter */
2626 * We have to be careful when we free a BSTR pointer, it points to
2627 * the beginning of the string but it skips the byte count contained
2628 * before the string.
2630 bufferPointer = (DWORD*)str;
2635 * Free the memory from its "real" origin.
2637 HeapFree(GetProcessHeap(), 0, bufferPointer);
2640 /******************************************************************************
2641 * Check if a PROPVARIANT's type is valid.
2643 static inline HRESULT PROPVARIANT_ValidateType(VARTYPE vt)
2670 case VT_STREAMED_OBJECT:
2671 case VT_STORED_OBJECT:
2672 case VT_BLOB_OBJECT:
2675 case VT_I2|VT_VECTOR:
2676 case VT_I4|VT_VECTOR:
2677 case VT_R4|VT_VECTOR:
2678 case VT_R8|VT_VECTOR:
2679 case VT_CY|VT_VECTOR:
2680 case VT_DATE|VT_VECTOR:
2681 case VT_BSTR|VT_VECTOR:
2682 case VT_ERROR|VT_VECTOR:
2683 case VT_BOOL|VT_VECTOR:
2684 case VT_VARIANT|VT_VECTOR:
2685 case VT_UI1|VT_VECTOR:
2686 case VT_UI2|VT_VECTOR:
2687 case VT_UI4|VT_VECTOR:
2688 case VT_I8|VT_VECTOR:
2689 case VT_UI8|VT_VECTOR:
2690 case VT_LPSTR|VT_VECTOR:
2691 case VT_LPWSTR|VT_VECTOR:
2692 case VT_FILETIME|VT_VECTOR:
2693 case VT_CF|VT_VECTOR:
2694 case VT_CLSID|VT_VECTOR:
2697 WARN("Bad type %d\n", vt);
2698 return STG_E_INVALIDPARAMETER;
2701 /***********************************************************************
2702 * PropVariantClear [OLE32.@]
2704 HRESULT WINAPI PropVariantClear(PROPVARIANT * pvar) /* [in/out] */
2708 TRACE("(%p)\n", pvar);
2713 hr = PROPVARIANT_ValidateType(pvar->vt);
2738 case VT_STREAMED_OBJECT:
2740 case VT_STORED_OBJECT:
2741 if (pvar->u.pStream)
2742 IUnknown_Release(pvar->u.pStream);
2747 /* pick an arbitrary typed pointer - we don't care about the type
2748 * as we are just freeing it */
2749 CoTaskMemFree(pvar->u.puuid);
2752 case VT_BLOB_OBJECT:
2753 CoTaskMemFree(pvar->u.blob.pBlobData);
2756 if (pvar->u.bstrVal)
2757 PropSysFreeString(pvar->u.bstrVal);
2760 if (pvar->u.pclipdata)
2762 OLE_FreeClipDataArray(1, pvar->u.pclipdata);
2763 CoTaskMemFree(pvar->u.pclipdata);
2767 if (pvar->vt & VT_VECTOR)
2771 switch (pvar->vt & ~VT_VECTOR)
2774 FreePropVariantArray(pvar->u.capropvar.cElems, pvar->u.capropvar.pElems);
2777 OLE_FreeClipDataArray(pvar->u.caclipdata.cElems, pvar->u.caclipdata.pElems);
2780 for (i = 0; i < pvar->u.cabstr.cElems; i++)
2781 PropSysFreeString(pvar->u.cabstr.pElems[i]);
2784 for (i = 0; i < pvar->u.calpstr.cElems; i++)
2785 CoTaskMemFree(pvar->u.calpstr.pElems[i]);
2788 for (i = 0; i < pvar->u.calpwstr.cElems; i++)
2789 CoTaskMemFree(pvar->u.calpwstr.pElems[i]);
2792 if (pvar->vt & ~VT_VECTOR)
2794 /* pick an arbitrary VT_VECTOR structure - they all have the same
2796 CoTaskMemFree(pvar->u.capropvar.pElems);
2800 WARN("Invalid/unsupported type %d\n", pvar->vt);
2803 ZeroMemory(pvar, sizeof(*pvar));
2808 /***********************************************************************
2809 * PropVariantCopy [OLE32.@]
2811 HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, /* [out] */
2812 const PROPVARIANT *pvarSrc) /* [in] */
2817 TRACE("(%p, %p vt %04x)\n", pvarDest, pvarSrc, pvarSrc->vt);
2819 hr = PROPVARIANT_ValidateType(pvarSrc->vt);
2823 /* this will deal with most cases */
2824 *pvarDest = *pvarSrc;
2848 case VT_STREAMED_OBJECT:
2850 case VT_STORED_OBJECT:
2851 IUnknown_AddRef((LPUNKNOWN)pvarDest->u.pStream);
2854 pvarDest->u.puuid = CoTaskMemAlloc(sizeof(CLSID));
2855 *pvarDest->u.puuid = *pvarSrc->u.puuid;
2858 len = strlen(pvarSrc->u.pszVal);
2859 pvarDest->u.pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR));
2860 CopyMemory(pvarDest->u.pszVal, pvarSrc->u.pszVal, (len+1)*sizeof(CHAR));
2863 len = lstrlenW(pvarSrc->u.pwszVal);
2864 pvarDest->u.pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
2865 CopyMemory(pvarDest->u.pwszVal, pvarSrc->u.pwszVal, (len+1)*sizeof(WCHAR));
2868 case VT_BLOB_OBJECT:
2869 if (pvarSrc->u.blob.pBlobData)
2871 len = pvarSrc->u.blob.cbSize;
2872 pvarDest->u.blob.pBlobData = CoTaskMemAlloc(len);
2873 CopyMemory(pvarDest->u.blob.pBlobData, pvarSrc->u.blob.pBlobData, len);
2877 pvarDest->u.bstrVal = PropSysAllocString(pvarSrc->u.bstrVal);
2880 if (pvarSrc->u.pclipdata)
2882 len = pvarSrc->u.pclipdata->cbSize - sizeof(pvarSrc->u.pclipdata->ulClipFmt);
2883 pvarDest->u.pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA));
2884 pvarDest->u.pclipdata->cbSize = pvarSrc->u.pclipdata->cbSize;
2885 pvarDest->u.pclipdata->ulClipFmt = pvarSrc->u.pclipdata->ulClipFmt;
2886 pvarDest->u.pclipdata->pClipData = CoTaskMemAlloc(len);
2887 CopyMemory(pvarDest->u.pclipdata->pClipData, pvarSrc->u.pclipdata->pClipData, len);
2891 if (pvarSrc->vt & VT_VECTOR)
2896 switch(pvarSrc->vt & ~VT_VECTOR)
2898 case VT_I1: elemSize = sizeof(pvarSrc->u.cVal); break;
2899 case VT_UI1: elemSize = sizeof(pvarSrc->u.bVal); break;
2900 case VT_I2: elemSize = sizeof(pvarSrc->u.iVal); break;
2901 case VT_UI2: elemSize = sizeof(pvarSrc->u.uiVal); break;
2902 case VT_BOOL: elemSize = sizeof(pvarSrc->u.boolVal); break;
2903 case VT_I4: elemSize = sizeof(pvarSrc->u.lVal); break;
2904 case VT_UI4: elemSize = sizeof(pvarSrc->u.ulVal); break;
2905 case VT_R4: elemSize = sizeof(pvarSrc->u.fltVal); break;
2906 case VT_R8: elemSize = sizeof(pvarSrc->u.dblVal); break;
2907 case VT_ERROR: elemSize = sizeof(pvarSrc->u.scode); break;
2908 case VT_I8: elemSize = sizeof(pvarSrc->u.hVal); break;
2909 case VT_UI8: elemSize = sizeof(pvarSrc->u.uhVal); break;
2910 case VT_CY: elemSize = sizeof(pvarSrc->u.cyVal); break;
2911 case VT_DATE: elemSize = sizeof(pvarSrc->u.date); break;
2912 case VT_FILETIME: elemSize = sizeof(pvarSrc->u.filetime); break;
2913 case VT_CLSID: elemSize = sizeof(*pvarSrc->u.puuid); break;
2914 case VT_CF: elemSize = sizeof(*pvarSrc->u.pclipdata); break;
2915 case VT_BSTR: elemSize = sizeof(pvarSrc->u.bstrVal); break;
2916 case VT_LPSTR: elemSize = sizeof(pvarSrc->u.pszVal); break;
2917 case VT_LPWSTR: elemSize = sizeof(pvarSrc->u.pwszVal); break;
2918 case VT_VARIANT: elemSize = sizeof(*pvarSrc->u.pvarVal); break;
2921 FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR);
2922 return E_INVALIDARG;
2924 len = pvarSrc->u.capropvar.cElems;
2925 pvarDest->u.capropvar.pElems = CoTaskMemAlloc(len * elemSize);
2926 if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT))
2928 for (i = 0; i < len; i++)
2929 PropVariantCopy(&pvarDest->u.capropvar.pElems[i], &pvarSrc->u.capropvar.pElems[i]);
2931 else if (pvarSrc->vt == (VT_VECTOR | VT_CF))
2933 FIXME("Copy clipformats\n");
2935 else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR))
2937 for (i = 0; i < len; i++)
2938 pvarDest->u.cabstr.pElems[i] = PropSysAllocString(pvarSrc->u.cabstr.pElems[i]);
2940 else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
2943 for (i = 0; i < len; i++)
2945 strLen = lstrlenA(pvarSrc->u.calpstr.pElems[i]) + 1;
2946 pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
2947 memcpy(pvarDest->u.calpstr.pElems[i],
2948 pvarSrc->u.calpstr.pElems[i], strLen);
2951 else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR))
2954 for (i = 0; i < len; i++)
2956 strLen = (lstrlenW(pvarSrc->u.calpwstr.pElems[i]) + 1) *
2958 pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
2959 memcpy(pvarDest->u.calpstr.pElems[i],
2960 pvarSrc->u.calpstr.pElems[i], strLen);
2964 CopyMemory(pvarDest->u.capropvar.pElems, pvarSrc->u.capropvar.pElems, len * elemSize);
2967 WARN("Invalid/unsupported type %d\n", pvarSrc->vt);
2973 /***********************************************************************
2974 * FreePropVariantArray [OLE32.@]
2976 HRESULT WINAPI FreePropVariantArray(ULONG cVariants, /* [in] */
2977 PROPVARIANT *rgvars) /* [in/out] */
2981 TRACE("(%u, %p)\n", cVariants, rgvars);
2984 return E_INVALIDARG;
2986 for(i = 0; i < cVariants; i++)
2987 PropVariantClear(&rgvars[i]);
2992 /******************************************************************************
2993 * DllDebugObjectRPCHook (OLE32.@)
2994 * turns on and off internal debugging, pointer is only used on macintosh
2997 BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy)