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
49 #include "wine/unicode.h"
50 #include "compobj_private.h"
51 #include "wine/list.h"
53 #include "wine/debug.h"
55 WINE_DEFAULT_DEBUG_CHANNEL(ole);
56 WINE_DECLARE_DEBUG_CHANNEL(accel);
58 /******************************************************************************
59 * These are static/global variables and internal data structures that the
60 * OLE module uses to maintain it's state.
62 typedef struct tagDropTargetNode
65 IDropTarget* dropTarget;
69 typedef struct tagTrackerWindowInfo
71 IDataObject* dataObject;
72 IDropSource* dropSource;
79 HWND curTargetHWND; /* window the mouse is hovering over */
80 HWND curDragTargetHWND; /* might be a ancestor of curTargetHWND */
81 IDropTarget* curDragTarget;
82 POINTL curMousePos; /* current position of the mouse in screen coordinates */
83 DWORD dwKeyState; /* current state of the shift and ctrl keys and the mouse buttons */
86 typedef struct tagOleMenuDescriptor /* OleMenuDescriptor */
88 HWND hwndFrame; /* The containers frame window */
89 HWND hwndActiveObject; /* The active objects window */
90 OLEMENUGROUPWIDTHS mgw; /* OLE menu group widths for the shared menu */
91 HMENU hmenuCombined; /* The combined menu */
92 BOOL bIsServerItem; /* True if the currently open popup belongs to the server */
95 typedef struct tagOleMenuHookItem /* OleMenu hook item in per thread hook list */
97 DWORD tid; /* Thread Id */
98 HANDLE hHeap; /* Heap this is allocated from */
99 HHOOK GetMsg_hHook; /* message hook for WH_GETMESSAGE */
100 HHOOK CallWndProc_hHook; /* message hook for WH_CALLWNDPROC */
101 struct tagOleMenuHookItem *next;
104 static OleMenuHookItem *hook_list;
107 * This is the lock count on the OLE library. It is controlled by the
108 * OLEInitialize/OLEUninitialize methods.
110 static LONG OLE_moduleLockCount = 0;
113 * Name of our registered window class.
115 static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";
118 * This is the head of the Drop target container.
120 static struct list targetListHead = LIST_INIT(targetListHead);
122 /******************************************************************************
123 * These are the prototypes of miscelaneous utility methods
125 static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue);
127 /******************************************************************************
128 * These are the prototypes of the utility methods used to manage a shared menu
130 static void OLEMenu_Initialize(void);
131 static void OLEMenu_UnInitialize(void);
132 static BOOL OLEMenu_InstallHooks( DWORD tid );
133 static BOOL OLEMenu_UnInstallHooks( DWORD tid );
134 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid );
135 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
136 static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor );
137 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam);
138 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam);
140 /******************************************************************************
141 * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c)
143 extern void OLEClipbrd_UnInitialize(void);
144 extern void OLEClipbrd_Initialize(void);
146 /******************************************************************************
147 * These are the prototypes of the utility methods used for OLE Drag n Drop
149 static void OLEDD_Initialize(void);
150 static void OLEDD_UnInitialize(void);
151 static DropTargetNode* OLEDD_FindDropTarget(
153 static void OLEDD_FreeDropTarget(DropTargetNode*);
154 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
159 static void OLEDD_TrackMouseMove(
160 TrackerWindowInfo* trackerInfo);
161 static void OLEDD_TrackStateChange(
162 TrackerWindowInfo* trackerInfo);
163 static DWORD OLEDD_GetButtonState(void);
166 /******************************************************************************
167 * OleBuildVersion [OLE2.1]
168 * OleBuildVersion [OLE32.@]
170 DWORD WINAPI OleBuildVersion(void)
172 TRACE("Returning version %d, build %d.\n", rmm, rup);
173 return (rmm<<16)+rup;
176 /***********************************************************************
177 * OleInitialize (OLE2.2)
178 * OleInitialize (OLE32.@)
180 HRESULT WINAPI OleInitialize(LPVOID reserved)
184 TRACE("(%p)\n", reserved);
187 * The first duty of the OleInitialize is to initialize the COM libraries.
189 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
192 * If the CoInitializeEx call failed, the OLE libraries can't be
199 * Then, it has to initialize the OLE specific modules.
203 * Object linking and Embedding
204 * In-place activation
206 if (!COM_CurrentInfo()->ole_inits++ &&
207 InterlockedIncrement(&OLE_moduleLockCount) == 1)
210 * Initialize the libraries.
212 TRACE("() - Initializing the OLE libraries\n");
217 OLEClipbrd_Initialize();
227 OLEMenu_Initialize();
233 /******************************************************************************
234 * OleUninitialize [OLE2.3]
235 * OleUninitialize [OLE32.@]
237 void WINAPI OleUninitialize(void)
242 * If we hit the bottom of the lock stack, free the libraries.
244 if (!--COM_CurrentInfo()->ole_inits && !InterlockedDecrement(&OLE_moduleLockCount))
247 * Actually free the libraries.
249 TRACE("() - Freeing the last reference count\n");
254 OLEClipbrd_UnInitialize();
259 OLEDD_UnInitialize();
264 OLEMenu_UnInitialize();
268 * Then, uninitialize the COM libraries.
273 /******************************************************************************
274 * OleInitializeWOW [OLE32.@]
276 HRESULT WINAPI OleInitializeWOW(DWORD x, DWORD y) {
277 FIXME("(0x%08x, 0x%08x),stub!\n",x, y);
281 /***********************************************************************
282 * RegisterDragDrop (OLE32.@)
284 HRESULT WINAPI RegisterDragDrop(
286 LPDROPTARGET pDropTarget)
288 DropTargetNode* dropTargetInfo;
290 TRACE("(%p,%p)\n", hwnd, pDropTarget);
296 * First, check if the window is already registered.
298 dropTargetInfo = OLEDD_FindDropTarget(hwnd);
300 if (dropTargetInfo!=NULL)
301 return DRAGDROP_E_ALREADYREGISTERED;
304 * If it's not there, we can add it. We first create a node for it.
306 dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));
308 if (dropTargetInfo==NULL)
309 return E_OUTOFMEMORY;
311 dropTargetInfo->hwndTarget = hwnd;
314 * Don't forget that this is an interface pointer, need to nail it down since
315 * we keep a copy of it.
317 IDropTarget_AddRef(pDropTarget);
318 dropTargetInfo->dropTarget = pDropTarget;
320 list_add_tail(&targetListHead, &dropTargetInfo->entry);
325 /***********************************************************************
326 * RevokeDragDrop (OLE32.@)
328 HRESULT WINAPI RevokeDragDrop(
331 DropTargetNode* dropTargetInfo;
333 TRACE("(%p)\n", hwnd);
336 * First, check if the window is already registered.
338 dropTargetInfo = OLEDD_FindDropTarget(hwnd);
341 * If it ain't in there, it's an error.
343 if (dropTargetInfo==NULL)
344 return DRAGDROP_E_NOTREGISTERED;
346 OLEDD_FreeDropTarget(dropTargetInfo);
351 /***********************************************************************
352 * OleRegGetUserType (OLE32.@)
354 * This implementation of OleRegGetUserType ignores the dwFormOfType
355 * parameter and always returns the full name of the object. This is
356 * not too bad since this is the case for many objects because of the
357 * way they are registered.
359 HRESULT WINAPI OleRegGetUserType(
362 LPOLESTR* pszUserType)
372 * Initialize the out parameter.
377 * Build the key name we're looking for
379 sprintf( keyName, "CLSID\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
380 clsid->Data1, clsid->Data2, clsid->Data3,
381 clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
382 clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
384 TRACE("(%s, %d, %p)\n", keyName, dwFormOfType, pszUserType);
387 * Open the class id Key
389 hres = RegOpenKeyA(HKEY_CLASSES_ROOT,
393 if (hres != ERROR_SUCCESS)
394 return REGDB_E_CLASSNOTREG;
397 * Retrieve the size of the name string.
401 hres = RegQueryValueExA(clsidKey,
408 if (hres!=ERROR_SUCCESS)
410 RegCloseKey(clsidKey);
411 return REGDB_E_READREGDB;
415 * Allocate a buffer for the registry value.
417 *pszUserType = CoTaskMemAlloc(cbData*2);
419 if (*pszUserType==NULL)
421 RegCloseKey(clsidKey);
422 return E_OUTOFMEMORY;
425 buffer = HeapAlloc(GetProcessHeap(), 0, cbData);
429 RegCloseKey(clsidKey);
430 CoTaskMemFree(*pszUserType);
432 return E_OUTOFMEMORY;
435 hres = RegQueryValueExA(clsidKey,
442 RegCloseKey(clsidKey);
445 if (hres!=ERROR_SUCCESS)
447 CoTaskMemFree(*pszUserType);
450 retVal = REGDB_E_READREGDB;
454 MultiByteToWideChar( CP_ACP, 0, buffer, -1, *pszUserType, cbData /*FIXME*/ );
457 HeapFree(GetProcessHeap(), 0, buffer);
462 /***********************************************************************
463 * DoDragDrop [OLE32.@]
465 HRESULT WINAPI DoDragDrop (
466 IDataObject *pDataObject, /* [in] ptr to the data obj */
467 IDropSource* pDropSource, /* [in] ptr to the source obj */
468 DWORD dwOKEffect, /* [in] effects allowed by the source */
469 DWORD *pdwEffect) /* [out] ptr to effects of the source */
471 TrackerWindowInfo trackerInfo;
472 HWND hwndTrackWindow;
475 TRACE("(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
478 * Setup the drag n drop tracking window.
480 if (!IsValidInterface((LPUNKNOWN)pDropSource))
483 trackerInfo.dataObject = pDataObject;
484 trackerInfo.dropSource = pDropSource;
485 trackerInfo.dwOKEffect = dwOKEffect;
486 trackerInfo.pdwEffect = pdwEffect;
487 trackerInfo.trackingDone = FALSE;
488 trackerInfo.escPressed = FALSE;
489 trackerInfo.curDragTargetHWND = 0;
490 trackerInfo.curTargetHWND = 0;
491 trackerInfo.curDragTarget = 0;
493 hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS,
496 CW_USEDEFAULT, CW_USEDEFAULT,
497 CW_USEDEFAULT, CW_USEDEFAULT,
501 (LPVOID)&trackerInfo);
503 if (hwndTrackWindow!=0)
506 * Capture the mouse input
508 SetCapture(hwndTrackWindow);
513 * Pump messages. All mouse input should go the the capture window.
515 while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )
517 trackerInfo.curMousePos.x = msg.pt.x;
518 trackerInfo.curMousePos.y = msg.pt.y;
519 trackerInfo.dwKeyState = OLEDD_GetButtonState();
521 if ( (msg.message >= WM_KEYFIRST) &&
522 (msg.message <= WM_KEYLAST) )
525 * When keyboard messages are sent to windows on this thread, we
526 * want to ignore notify the drop source that the state changed.
527 * in the case of the Escape key, we also notify the drop source
528 * we give it a special meaning.
530 if ( (msg.message==WM_KEYDOWN) &&
531 (msg.wParam==VK_ESCAPE) )
533 trackerInfo.escPressed = TRUE;
537 * Notify the drop source.
539 OLEDD_TrackStateChange(&trackerInfo);
544 * Dispatch the messages only when it's not a keyboard message.
546 DispatchMessageA(&msg);
550 /* re-post the quit message to outer message loop */
551 if (msg.message == WM_QUIT)
552 PostQuitMessage(msg.wParam);
554 * Destroy the temporary window.
556 DestroyWindow(hwndTrackWindow);
558 return trackerInfo.returnValue;
564 /***********************************************************************
565 * OleQueryLinkFromData [OLE32.@]
567 HRESULT WINAPI OleQueryLinkFromData(
568 IDataObject* pSrcDataObject)
570 FIXME("(%p),stub!\n", pSrcDataObject);
574 /***********************************************************************
575 * OleRegGetMiscStatus [OLE32.@]
577 HRESULT WINAPI OleRegGetMiscStatus(
589 * Initialize the out parameter.
594 * Build the key name we're looking for
596 sprintf( keyName, "CLSID\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
597 clsid->Data1, clsid->Data2, clsid->Data3,
598 clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
599 clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
601 TRACE("(%s, %d, %p)\n", keyName, dwAspect, pdwStatus);
604 * Open the class id Key
606 result = RegOpenKeyA(HKEY_CLASSES_ROOT,
610 if (result != ERROR_SUCCESS)
611 return REGDB_E_CLASSNOTREG;
616 result = RegOpenKeyA(clsidKey,
621 if (result != ERROR_SUCCESS)
623 RegCloseKey(clsidKey);
624 return REGDB_E_READREGDB;
628 * Read the default value
630 OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
633 * Open the key specific to the requested aspect.
635 sprintf(keyName, "%d", dwAspect);
637 result = RegOpenKeyA(miscStatusKey,
641 if (result == ERROR_SUCCESS)
643 OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
644 RegCloseKey(aspectKey);
650 RegCloseKey(miscStatusKey);
651 RegCloseKey(clsidKey);
656 static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum);
660 const IEnumOLEVERBVtbl *lpvtbl;
667 static HRESULT WINAPI EnumOLEVERB_QueryInterface(
668 IEnumOLEVERB *iface, REFIID riid, void **ppv)
670 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
671 if (IsEqualIID(riid, &IID_IUnknown) ||
672 IsEqualIID(riid, &IID_IEnumOLEVERB))
674 IUnknown_AddRef(iface);
678 return E_NOINTERFACE;
681 static ULONG WINAPI EnumOLEVERB_AddRef(
684 EnumOLEVERB *This = (EnumOLEVERB *)iface;
686 return InterlockedIncrement(&This->ref);
689 static ULONG WINAPI EnumOLEVERB_Release(
692 EnumOLEVERB *This = (EnumOLEVERB *)iface;
693 LONG refs = InterlockedDecrement(&This->ref);
697 RegCloseKey(This->hkeyVerb);
698 HeapFree(GetProcessHeap(), 0, This);
703 static HRESULT WINAPI EnumOLEVERB_Next(
704 IEnumOLEVERB *iface, ULONG celt, LPOLEVERB rgelt,
707 EnumOLEVERB *This = (EnumOLEVERB *)iface;
710 TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched);
715 for (; celt; celt--, rgelt++)
720 LPWSTR pwszMenuFlags;
722 LONG res = RegEnumKeyW(This->hkeyVerb, This->index, wszSubKey, sizeof(wszSubKey)/sizeof(wszSubKey[0]));
723 if (res == ERROR_NO_MORE_ITEMS)
728 else if (res != ERROR_SUCCESS)
730 ERR("RegEnumKeyW failed with error %d\n", res);
731 hr = REGDB_E_READREGDB;
734 res = RegQueryValueW(This->hkeyVerb, wszSubKey, NULL, &cbData);
735 if (res != ERROR_SUCCESS)
737 ERR("RegQueryValueW failed with error %d\n", res);
738 hr = REGDB_E_READREGDB;
741 pwszOLEVERB = CoTaskMemAlloc(cbData);
747 res = RegQueryValueW(This->hkeyVerb, wszSubKey, pwszOLEVERB, &cbData);
748 if (res != ERROR_SUCCESS)
750 ERR("RegQueryValueW failed with error %d\n", res);
751 hr = REGDB_E_READREGDB;
752 CoTaskMemFree(pwszOLEVERB);
756 TRACE("verb string: %s\n", debugstr_w(pwszOLEVERB));
757 pwszMenuFlags = strchrW(pwszOLEVERB, ',');
760 hr = OLEOBJ_E_INVALIDVERB;
761 CoTaskMemFree(pwszOLEVERB);
764 /* nul terminate the name string and advance to first character */
765 *pwszMenuFlags = '\0';
767 pwszAttribs = strchrW(pwszMenuFlags, ',');
770 hr = OLEOBJ_E_INVALIDVERB;
771 CoTaskMemFree(pwszOLEVERB);
774 /* nul terminate the menu string and advance to first character */
778 /* fill out structure for this verb */
779 rgelt->lVerb = atolW(wszSubKey);
780 rgelt->lpszVerbName = pwszOLEVERB; /* user should free */
781 rgelt->fuFlags = atolW(pwszMenuFlags);
782 rgelt->grfAttribs = atolW(pwszAttribs);
791 static HRESULT WINAPI EnumOLEVERB_Skip(
792 IEnumOLEVERB *iface, ULONG celt)
794 EnumOLEVERB *This = (EnumOLEVERB *)iface;
796 TRACE("(%d)\n", celt);
802 static HRESULT WINAPI EnumOLEVERB_Reset(
805 EnumOLEVERB *This = (EnumOLEVERB *)iface;
813 static HRESULT WINAPI EnumOLEVERB_Clone(
815 IEnumOLEVERB **ppenum)
817 EnumOLEVERB *This = (EnumOLEVERB *)iface;
819 TRACE("(%p)\n", ppenum);
820 if (!DuplicateHandle(GetCurrentProcess(), This->hkeyVerb, GetCurrentProcess(), (HANDLE *)&hkeyVerb, 0, FALSE, DUPLICATE_SAME_ACCESS))
821 return HRESULT_FROM_WIN32(GetLastError());
822 return EnumOLEVERB_Construct(hkeyVerb, This->index, ppenum);
825 static const IEnumOLEVERBVtbl EnumOLEVERB_VTable =
827 EnumOLEVERB_QueryInterface,
836 static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum)
838 EnumOLEVERB *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
841 RegCloseKey(hkeyVerb);
842 return E_OUTOFMEMORY;
844 This->lpvtbl = &EnumOLEVERB_VTable;
847 This->hkeyVerb = hkeyVerb;
848 *ppenum = (IEnumOLEVERB *)&This->lpvtbl;
852 /***********************************************************************
853 * OleRegEnumVerbs [OLE32.@]
855 * Enumerates verbs associated with a class stored in the registry.
858 * clsid [I] Class ID to enumerate the verbs for.
859 * ppenum [O] Enumerator.
863 * REGDB_E_CLASSNOTREG: The specified class does not have a key in the registry.
864 * REGDB_E_READREGDB: The class key could not be opened for some other reason.
865 * OLE_E_REGDB_KEY: The Verb subkey for the class is not present.
866 * OLEOBJ_E_NOVERBS: The Verb subkey for the class is empty.
868 HRESULT WINAPI OleRegEnumVerbs (REFCLSID clsid, LPENUMOLEVERB* ppenum)
873 static const WCHAR wszVerb[] = {'V','e','r','b',0};
875 TRACE("(%s, %p)\n", debugstr_guid(clsid), ppenum);
877 res = COM_OpenKeyForCLSID(clsid, wszVerb, KEY_READ, &hkeyVerb);
880 if (res == REGDB_E_CLASSNOTREG)
881 ERR("CLSID %s not registered\n", debugstr_guid(clsid));
882 else if (res == REGDB_E_KEYMISSING)
883 ERR("no Verbs key for class %s\n", debugstr_guid(clsid));
885 ERR("failed to open Verbs key for CLSID %s with error %d\n",
886 debugstr_guid(clsid), res);
890 res = RegQueryInfoKeyW(hkeyVerb, NULL, NULL, NULL, &dwSubKeys, NULL,
891 NULL, NULL, NULL, NULL, NULL, NULL);
892 if (res != ERROR_SUCCESS)
894 ERR("failed to get subkey count with error %d\n", GetLastError());
895 return REGDB_E_READREGDB;
900 WARN("class %s has no verbs\n", debugstr_guid(clsid));
901 RegCloseKey(hkeyVerb);
902 return OLEOBJ_E_NOVERBS;
905 return EnumOLEVERB_Construct(hkeyVerb, 0, ppenum);
908 /******************************************************************************
909 * OleSetContainedObject [OLE32.@]
911 HRESULT WINAPI OleSetContainedObject(
915 IRunnableObject* runnable = NULL;
918 TRACE("(%p,%x)\n", pUnknown, fContained);
920 hres = IUnknown_QueryInterface(pUnknown,
921 &IID_IRunnableObject,
926 hres = IRunnableObject_SetContainedObject(runnable, fContained);
928 IRunnableObject_Release(runnable);
936 /******************************************************************************
939 HRESULT WINAPI OleLoad(
942 LPOLECLIENTSITE pClientSite,
945 IPersistStorage* persistStorage = NULL;
947 IOleObject* pOleObject = NULL;
951 TRACE("(%p,%p,%p,%p)\n", pStg, riid, pClientSite, ppvObj);
956 * TODO, Conversion ... OleDoAutoConvert
960 * Get the class ID for the object.
962 hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
965 * Now, try and create the handler for the object
967 hres = CoCreateInstance(&storageInfo.clsid,
969 CLSCTX_INPROC_HANDLER,
974 * If that fails, as it will most times, load the default
979 hres = OleCreateDefaultHandler(&storageInfo.clsid,
986 * If we couldn't find a handler... this is bad. Abort the whole thing.
993 hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (void **)&pOleObject);
997 hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
1001 if (SUCCEEDED(hres))
1003 * Initialize the object with it's IPersistStorage interface.
1005 hres = IOleObject_QueryInterface(pUnk,
1006 &IID_IPersistStorage,
1007 (void**)&persistStorage);
1009 if (SUCCEEDED(hres))
1011 hres = IPersistStorage_Load(persistStorage, pStg);
1013 IPersistStorage_Release(persistStorage);
1014 persistStorage = NULL;
1017 if (SUCCEEDED(hres) && pClientSite)
1019 * Inform the new object of it's client site.
1021 hres = IOleObject_SetClientSite(pOleObject, pClientSite);
1024 * Cleanup interfaces used internally
1027 IOleObject_Release(pOleObject);
1029 if (SUCCEEDED(hres))
1033 hres1 = IUnknown_QueryInterface(pUnk, &IID_IOleLink, (void **)&pOleLink);
1034 if (SUCCEEDED(hres1))
1036 FIXME("handle OLE link\n");
1037 IOleLink_Release(pOleLink);
1043 IUnknown_Release(pUnk);
1052 /***********************************************************************
1055 HRESULT WINAPI OleSave(
1056 LPPERSISTSTORAGE pPS,
1063 TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad);
1066 * First, we transfer the class ID (if available)
1068 hres = IPersistStorage_GetClassID(pPS, &objectClass);
1070 if (SUCCEEDED(hres))
1072 WriteClassStg(pStg, &objectClass);
1076 * Then, we ask the object to save itself to the
1077 * storage. If it is successful, we commit the storage.
1079 hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad);
1081 if (SUCCEEDED(hres))
1083 IStorage_Commit(pStg,
1091 /******************************************************************************
1092 * OleLockRunning [OLE32.@]
1094 HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses)
1096 IRunnableObject* runnable = NULL;
1099 TRACE("(%p,%x,%x)\n", pUnknown, fLock, fLastUnlockCloses);
1101 hres = IUnknown_QueryInterface(pUnknown,
1102 &IID_IRunnableObject,
1105 if (SUCCEEDED(hres))
1107 hres = IRunnableObject_LockRunning(runnable, fLock, fLastUnlockCloses);
1109 IRunnableObject_Release(runnable);
1114 return E_INVALIDARG;
1118 /**************************************************************************
1119 * Internal methods to manage the shared OLE menu in response to the
1120 * OLE***MenuDescriptor API
1124 * OLEMenu_Initialize()
1126 * Initializes the OLEMENU data structures.
1128 static void OLEMenu_Initialize(void)
1133 * OLEMenu_UnInitialize()
1135 * Releases the OLEMENU data structures.
1137 static void OLEMenu_UnInitialize(void)
1141 /*************************************************************************
1142 * OLEMenu_InstallHooks
1143 * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
1145 * RETURNS: TRUE if message hooks were successfully installed
1148 static BOOL OLEMenu_InstallHooks( DWORD tid )
1150 OleMenuHookItem *pHookItem = NULL;
1152 /* Create an entry for the hook table */
1153 if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
1154 sizeof(OleMenuHookItem)) ) )
1157 pHookItem->tid = tid;
1158 pHookItem->hHeap = GetProcessHeap();
1160 /* Install a thread scope message hook for WH_GETMESSAGE */
1161 pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc,
1162 0, GetCurrentThreadId() );
1163 if ( !pHookItem->GetMsg_hHook )
1166 /* Install a thread scope message hook for WH_CALLWNDPROC */
1167 pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc,
1168 0, GetCurrentThreadId() );
1169 if ( !pHookItem->CallWndProc_hHook )
1172 /* Insert the hook table entry */
1173 pHookItem->next = hook_list;
1174 hook_list = pHookItem;
1179 /* Unhook any hooks */
1180 if ( pHookItem->GetMsg_hHook )
1181 UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
1182 if ( pHookItem->CallWndProc_hHook )
1183 UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
1184 /* Release the hook table entry */
1185 HeapFree(pHookItem->hHeap, 0, pHookItem );
1190 /*************************************************************************
1191 * OLEMenu_UnInstallHooks
1192 * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
1194 * RETURNS: TRUE if message hooks were successfully installed
1197 static BOOL OLEMenu_UnInstallHooks( DWORD tid )
1199 OleMenuHookItem *pHookItem = NULL;
1200 OleMenuHookItem **ppHook = &hook_list;
1204 if ((*ppHook)->tid == tid)
1206 pHookItem = *ppHook;
1207 *ppHook = pHookItem->next;
1210 ppHook = &(*ppHook)->next;
1212 if (!pHookItem) return FALSE;
1214 /* Uninstall the hooks installed for this thread */
1215 if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
1217 if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
1220 /* Release the hook table entry */
1221 HeapFree(pHookItem->hHeap, 0, pHookItem );
1226 /* Release the hook table entry */
1227 HeapFree(pHookItem->hHeap, 0, pHookItem );
1232 /*************************************************************************
1233 * OLEMenu_IsHookInstalled
1234 * Tests if OLEMenu hooks have been installed for a thread
1236 * RETURNS: The pointer and index of the hook table entry for the tid
1237 * NULL and -1 for the index if no hooks were installed for this thread
1239 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )
1241 OleMenuHookItem *pHookItem = NULL;
1243 /* Do a simple linear search for an entry whose tid matches ours.
1244 * We really need a map but efficiency is not a concern here. */
1245 for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next)
1247 if ( tid == pHookItem->tid )
1254 /***********************************************************************
1255 * OLEMenu_FindMainMenuIndex
1257 * Used by OLEMenu API to find the top level group a menu item belongs to.
1258 * On success pnPos contains the index of the item in the top level menu group
1260 * RETURNS: TRUE if the ID was found, FALSE on failure
1262 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
1266 nItems = GetMenuItemCount( hMainMenu );
1268 for (i = 0; i < nItems; i++)
1272 /* Is the current item a submenu? */
1273 if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
1275 /* If the handle is the same we're done */
1276 if ( hsubmenu == hPopupMenu )
1282 /* Recursively search without updating pnPos */
1283 else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
1295 /***********************************************************************
1296 * OLEMenu_SetIsServerMenu
1298 * Checks whether a popup menu belongs to a shared menu group which is
1299 * owned by the server, and sets the menu descriptor state accordingly.
1300 * All menu messages from these groups should be routed to the server.
1302 * RETURNS: TRUE if the popup menu is part of a server owned group
1303 * FALSE if the popup menu is part of a container owned group
1305 static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
1307 UINT nPos = 0, nWidth, i;
1309 pOleMenuDescriptor->bIsServerItem = FALSE;
1311 /* Don't bother searching if the popup is the combined menu itself */
1312 if ( hmenu == pOleMenuDescriptor->hmenuCombined )
1315 /* Find the menu item index in the shared OLE menu that this item belongs to */
1316 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) )
1319 /* The group widths array has counts for the number of elements
1320 * in the groups File, Edit, Container, Object, Window, Help.
1321 * The Edit, Object & Help groups belong to the server object
1322 * and the other three belong to the container.
1323 * Loop through the group widths and locate the group we are a member of.
1325 for ( i = 0, nWidth = 0; i < 6; i++ )
1327 nWidth += pOleMenuDescriptor->mgw.width[i];
1328 if ( nPos < nWidth )
1330 /* Odd elements are server menu widths */
1331 pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;
1336 return pOleMenuDescriptor->bIsServerItem;
1339 /*************************************************************************
1340 * OLEMenu_CallWndProc
1341 * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
1342 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1344 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
1346 LPCWPSTRUCT pMsg = NULL;
1347 HOLEMENU hOleMenu = 0;
1348 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1349 OleMenuHookItem *pHookItem = NULL;
1352 TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1354 /* Check if we're being asked to process the message */
1355 if ( HC_ACTION != code )
1358 /* Retrieve the current message being dispatched from lParam */
1359 pMsg = (LPCWPSTRUCT)lParam;
1361 /* Check if the message is destined for a window we are interested in:
1362 * If the window has an OLEMenu property we may need to dispatch
1363 * the menu message to its active objects window instead. */
1365 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1369 /* Get the menu descriptor */
1370 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1371 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1374 /* Process menu messages */
1375 switch( pMsg->message )
1379 /* Reset the menu descriptor state */
1380 pOleMenuDescriptor->bIsServerItem = FALSE;
1382 /* Send this message to the server as well */
1383 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1384 pMsg->message, pMsg->wParam, pMsg->lParam );
1388 case WM_INITMENUPOPUP:
1390 /* Save the state for whether this is a server owned menu */
1391 OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
1397 fuFlags = HIWORD(pMsg->wParam); /* Get flags */
1398 if ( fuFlags & MF_SYSMENU )
1401 /* Save the state for whether this is a server owned popup menu */
1402 else if ( fuFlags & MF_POPUP )
1403 OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
1410 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
1411 if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
1412 goto NEXTHOOK; /* Not a menu message */
1421 /* If the message was for the server dispatch it accordingly */
1422 if ( pOleMenuDescriptor->bIsServerItem )
1424 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1425 pMsg->message, pMsg->wParam, pMsg->lParam );
1429 if ( pOleMenuDescriptor )
1430 GlobalUnlock( hOleMenu );
1432 /* Lookup the hook item for the current thread */
1433 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1435 /* This should never fail!! */
1436 WARN("could not retrieve hHook for current thread!\n" );
1440 /* Pass on the message to the next hooker */
1441 return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
1444 /*************************************************************************
1445 * OLEMenu_GetMsgProc
1446 * Thread scope WH_GETMESSAGE hook proc filter function (callback)
1447 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1449 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
1452 HOLEMENU hOleMenu = 0;
1453 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1454 OleMenuHookItem *pHookItem = NULL;
1457 TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1459 /* Check if we're being asked to process a messages */
1460 if ( HC_ACTION != code )
1463 /* Retrieve the current message being dispatched from lParam */
1464 pMsg = (LPMSG)lParam;
1466 /* Check if the message is destined for a window we are interested in:
1467 * If the window has an OLEMenu property we may need to dispatch
1468 * the menu message to its active objects window instead. */
1470 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1474 /* Process menu messages */
1475 switch( pMsg->message )
1479 wCode = HIWORD(pMsg->wParam); /* Get notification code */
1481 goto NEXTHOOK; /* Not a menu message */
1488 /* Get the menu descriptor */
1489 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1490 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1493 /* If the message was for the server dispatch it accordingly */
1494 if ( pOleMenuDescriptor->bIsServerItem )
1496 /* Change the hWnd in the message to the active objects hWnd.
1497 * The message loop which reads this message will automatically
1498 * dispatch it to the embedded objects window. */
1499 pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
1503 if ( pOleMenuDescriptor )
1504 GlobalUnlock( hOleMenu );
1506 /* Lookup the hook item for the current thread */
1507 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1509 /* This should never fail!! */
1510 WARN("could not retrieve hHook for current thread!\n" );
1514 /* Pass on the message to the next hooker */
1515 return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
1518 /***********************************************************************
1519 * OleCreateMenuDescriptor [OLE32.@]
1520 * Creates an OLE menu descriptor for OLE to use when dispatching
1521 * menu messages and commands.
1524 * hmenuCombined - Handle to the objects combined menu
1525 * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group
1528 HOLEMENU WINAPI OleCreateMenuDescriptor(
1529 HMENU hmenuCombined,
1530 LPOLEMENUGROUPWIDTHS lpMenuWidths)
1533 OleMenuDescriptor *pOleMenuDescriptor;
1536 if ( !hmenuCombined || !lpMenuWidths )
1539 /* Create an OLE menu descriptor */
1540 if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
1541 sizeof(OleMenuDescriptor) ) ) )
1544 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1545 if ( !pOleMenuDescriptor )
1548 /* Initialize menu group widths and hmenu */
1549 for ( i = 0; i < 6; i++ )
1550 pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
1552 pOleMenuDescriptor->hmenuCombined = hmenuCombined;
1553 pOleMenuDescriptor->bIsServerItem = FALSE;
1554 GlobalUnlock( hOleMenu );
1559 /***********************************************************************
1560 * OleDestroyMenuDescriptor [OLE32.@]
1561 * Destroy the shared menu descriptor
1563 HRESULT WINAPI OleDestroyMenuDescriptor(
1564 HOLEMENU hmenuDescriptor)
1566 if ( hmenuDescriptor )
1567 GlobalFree( hmenuDescriptor );
1571 /***********************************************************************
1572 * OleSetMenuDescriptor [OLE32.@]
1573 * Installs or removes OLE dispatching code for the containers frame window.
1576 * hOleMenu Handle to composite menu descriptor
1577 * hwndFrame Handle to containers frame window
1578 * hwndActiveObject Handle to objects in-place activation window
1579 * lpFrame Pointer to IOleInPlaceFrame on containers window
1580 * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object
1583 * S_OK - menu installed correctly
1584 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1587 * The lpFrame and lpActiveObject parameters are currently ignored
1588 * OLE should install context sensitive help F1 filtering for the app when
1589 * these are non null.
1591 HRESULT WINAPI OleSetMenuDescriptor(
1594 HWND hwndActiveObject,
1595 LPOLEINPLACEFRAME lpFrame,
1596 LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1598 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1601 if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
1602 return E_INVALIDARG;
1604 if ( lpFrame || lpActiveObject )
1606 FIXME("(%p, %p, %p, %p, %p), Context sensitive help filtering not implemented!\n",
1614 /* Set up a message hook to intercept the containers frame window messages.
1615 * The message filter is responsible for dispatching menu messages from the
1616 * shared menu which are intended for the object.
1619 if ( hOleMenu ) /* Want to install dispatching code */
1621 /* If OLEMenu hooks are already installed for this thread, fail
1622 * Note: This effectively means that OleSetMenuDescriptor cannot
1623 * be called twice in succession on the same frame window
1624 * without first calling it with a null hOleMenu to uninstall */
1625 if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) )
1628 /* Get the menu descriptor */
1629 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1630 if ( !pOleMenuDescriptor )
1631 return E_UNEXPECTED;
1633 /* Update the menu descriptor */
1634 pOleMenuDescriptor->hwndFrame = hwndFrame;
1635 pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
1637 GlobalUnlock( hOleMenu );
1638 pOleMenuDescriptor = NULL;
1640 /* Add a menu descriptor windows property to the frame window */
1641 SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu );
1643 /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
1644 if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
1647 else /* Want to uninstall dispatching code */
1649 /* Uninstall the hooks */
1650 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1653 /* Remove the menu descriptor property from the frame window */
1654 RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" );
1660 /******************************************************************************
1661 * IsAccelerator [OLE32.@]
1662 * Mostly copied from controls/menu.c TranslateAccelerator implementation
1664 BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd)
1669 if(!lpMsg) return FALSE;
1672 WARN_(accel)("NULL accel handle\n");
1675 if((lpMsg->message != WM_KEYDOWN &&
1676 lpMsg->message != WM_KEYUP &&
1677 lpMsg->message != WM_SYSKEYDOWN &&
1678 lpMsg->message != WM_SYSKEYUP &&
1679 lpMsg->message != WM_CHAR)) return FALSE;
1680 lpAccelTbl = HeapAlloc(GetProcessHeap(), 0, cAccelEntries * sizeof(ACCEL));
1681 if (NULL == lpAccelTbl)
1685 if (CopyAcceleratorTableW(hAccel, lpAccelTbl, cAccelEntries) != cAccelEntries)
1687 WARN_(accel)("CopyAcceleratorTableW failed\n");
1688 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1692 TRACE_(accel)("hAccel=%p, cAccelEntries=%d,"
1693 "msg->hwnd=%p, msg->message=%04x, wParam=%08x, lParam=%08lx\n",
1694 hAccel, cAccelEntries,
1695 lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);
1696 for(i = 0; i < cAccelEntries; i++)
1698 if(lpAccelTbl[i].key != lpMsg->wParam)
1701 if(lpMsg->message == WM_CHAR)
1703 if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY))
1705 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", lpMsg->wParam & 0xff);
1711 if(lpAccelTbl[i].fVirt & FVIRTKEY)
1714 TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
1715 lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff);
1716 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
1717 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
1718 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
1719 if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
1720 TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n");
1724 if(!(lpMsg->lParam & 0x01000000)) /* no special_key */
1726 if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000))
1727 { /* ^^ ALT pressed */
1728 TRACE_(accel)("found accel for Alt-%c\n", lpMsg->wParam & 0xff);
1736 WARN_(accel)("couldn't translate accelerator key\n");
1737 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1741 if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd;
1742 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1746 /***********************************************************************
1747 * ReleaseStgMedium [OLE32.@]
1749 void WINAPI ReleaseStgMedium(
1752 switch (pmedium->tymed)
1756 if ( (pmedium->pUnkForRelease==0) &&
1757 (pmedium->u.hGlobal!=0) )
1758 GlobalFree(pmedium->u.hGlobal);
1763 if (pmedium->u.lpszFileName!=0)
1765 if (pmedium->pUnkForRelease==0)
1767 DeleteFileW(pmedium->u.lpszFileName);
1770 CoTaskMemFree(pmedium->u.lpszFileName);
1776 if (pmedium->u.pstm!=0)
1778 IStream_Release(pmedium->u.pstm);
1782 case TYMED_ISTORAGE:
1784 if (pmedium->u.pstg!=0)
1786 IStorage_Release(pmedium->u.pstg);
1792 if ( (pmedium->pUnkForRelease==0) &&
1793 (pmedium->u.hBitmap!=0) )
1794 DeleteObject(pmedium->u.hBitmap);
1799 if ( (pmedium->pUnkForRelease==0) &&
1800 (pmedium->u.hMetaFilePict!=0) )
1802 LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hMetaFilePict);
1803 DeleteMetaFile(pMP->hMF);
1804 GlobalUnlock(pmedium->u.hMetaFilePict);
1805 GlobalFree(pmedium->u.hMetaFilePict);
1811 if ( (pmedium->pUnkForRelease==0) &&
1812 (pmedium->u.hEnhMetaFile!=0) )
1814 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
1822 pmedium->tymed=TYMED_NULL;
1825 * After cleaning up, the unknown is released
1827 if (pmedium->pUnkForRelease!=0)
1829 IUnknown_Release(pmedium->pUnkForRelease);
1830 pmedium->pUnkForRelease = 0;
1835 * OLEDD_Initialize()
1837 * Initializes the OLE drag and drop data structures.
1839 static void OLEDD_Initialize(void)
1843 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1844 wndClass.style = CS_GLOBALCLASS;
1845 wndClass.lpfnWndProc = OLEDD_DragTrackerWindowProc;
1846 wndClass.cbClsExtra = 0;
1847 wndClass.cbWndExtra = sizeof(TrackerWindowInfo*);
1848 wndClass.hCursor = 0;
1849 wndClass.hbrBackground = 0;
1850 wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
1852 RegisterClassA (&wndClass);
1856 * OLEDD_FreeDropTarget()
1858 * Frees the drag and drop data structure
1860 static void OLEDD_FreeDropTarget(DropTargetNode *dropTargetInfo)
1862 list_remove(&dropTargetInfo->entry);
1863 IDropTarget_Release(dropTargetInfo->dropTarget);
1864 HeapFree(GetProcessHeap(), 0, dropTargetInfo);
1868 * OLEDD_UnInitialize()
1870 * Releases the OLE drag and drop data structures.
1872 static void OLEDD_UnInitialize(void)
1875 * Simply empty the list.
1877 while (!list_empty(&targetListHead))
1879 DropTargetNode* curNode;
1880 curNode = LIST_ENTRY(list_head(&targetListHead), DropTargetNode, entry);
1881 OLEDD_FreeDropTarget(curNode);
1886 * OLEDD_FindDropTarget()
1888 * Finds information about the drop target.
1890 static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
1892 DropTargetNode* curNode;
1895 * Iterate the list to find the HWND value.
1897 LIST_FOR_EACH_ENTRY(curNode, &targetListHead, DropTargetNode, entry)
1898 if (hwndOfTarget==curNode->hwndTarget)
1902 * If we get here, the item is not in the list
1908 * OLEDD_DragTrackerWindowProc()
1910 * This method is the WindowProcedure of the drag n drop tracking
1911 * window. During a drag n Drop operation, an invisible window is created
1912 * to receive the user input and act upon it. This procedure is in charge
1916 #define DRAG_TIMER_ID 1
1918 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
1928 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
1930 SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams);
1931 SetTimer(hwnd, DRAG_TIMER_ID, 50, NULL);
1938 OLEDD_TrackMouseMove((TrackerWindowInfo*)GetWindowLongA(hwnd, 0));
1944 case WM_LBUTTONDOWN:
1945 case WM_MBUTTONDOWN:
1946 case WM_RBUTTONDOWN:
1948 OLEDD_TrackStateChange((TrackerWindowInfo*)GetWindowLongA(hwnd, 0));
1953 KillTimer(hwnd, DRAG_TIMER_ID);
1959 * This is a window proc after all. Let's call the default.
1961 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1965 * OLEDD_TrackMouseMove()
1967 * This method is invoked while a drag and drop operation is in effect.
1968 * it will generate the appropriate callbacks in the drop source
1969 * and drop target. It will also provide the expected feedback to
1973 * trackerInfo - Pointer to the structure identifying the
1974 * drag & drop operation that is currently
1977 static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo)
1979 HWND hwndNewTarget = 0;
1984 * Get the handle of the window under the mouse
1986 pt.x = trackerInfo->curMousePos.x;
1987 pt.y = trackerInfo->curMousePos.y;
1988 hwndNewTarget = WindowFromPoint(pt);
1991 * Every time, we re-initialize the effects passed to the
1992 * IDropTarget to the effects allowed by the source.
1994 *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
1997 * If we are hovering over the same target as before, send the
1998 * DragOver notification
2000 if ( (trackerInfo->curDragTarget != 0) &&
2001 (trackerInfo->curTargetHWND == hwndNewTarget) )
2003 IDropTarget_DragOver(trackerInfo->curDragTarget,
2004 trackerInfo->dwKeyState,
2005 trackerInfo->curMousePos,
2006 trackerInfo->pdwEffect);
2010 DropTargetNode* newDropTargetNode = 0;
2013 * If we changed window, we have to notify our old target and check for
2016 if (trackerInfo->curDragTarget!=0)
2018 IDropTarget_DragLeave(trackerInfo->curDragTarget);
2022 * Make sure we're hovering over a window.
2024 if (hwndNewTarget!=0)
2027 * Find-out if there is a drag target under the mouse
2029 HWND nexttar = hwndNewTarget;
2030 trackerInfo->curTargetHWND = hwndNewTarget;
2033 newDropTargetNode = OLEDD_FindDropTarget(nexttar);
2034 } while (!newDropTargetNode && (nexttar = GetParent(nexttar)) != 0);
2035 if(nexttar) hwndNewTarget = nexttar;
2037 trackerInfo->curDragTargetHWND = hwndNewTarget;
2038 trackerInfo->curDragTarget = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
2041 * If there is, notify it that we just dragged-in
2043 if (trackerInfo->curDragTarget!=0)
2045 IDropTarget_DragEnter(trackerInfo->curDragTarget,
2046 trackerInfo->dataObject,
2047 trackerInfo->dwKeyState,
2048 trackerInfo->curMousePos,
2049 trackerInfo->pdwEffect);
2055 * The mouse is not over a window so we don't track anything.
2057 trackerInfo->curDragTargetHWND = 0;
2058 trackerInfo->curTargetHWND = 0;
2059 trackerInfo->curDragTarget = 0;
2064 * Now that we have done that, we have to tell the source to give
2065 * us feedback on the work being done by the target. If we don't
2066 * have a target, simulate no effect.
2068 if (trackerInfo->curDragTarget==0)
2070 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2073 hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
2074 *trackerInfo->pdwEffect);
2077 * When we ask for feedback from the drop source, sometimes it will
2078 * do all the necessary work and sometimes it will not handle it
2079 * when that's the case, we must display the standard drag and drop
2082 if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
2084 if (*trackerInfo->pdwEffect & DROPEFFECT_MOVE)
2086 SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(1)));
2088 else if (*trackerInfo->pdwEffect & DROPEFFECT_COPY)
2090 SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(2)));
2092 else if (*trackerInfo->pdwEffect & DROPEFFECT_LINK)
2094 SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(3)));
2098 SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(0)));
2104 * OLEDD_TrackStateChange()
2106 * This method is invoked while a drag and drop operation is in effect.
2107 * It is used to notify the drop target/drop source callbacks when
2108 * the state of the keyboard or mouse button change.
2111 * trackerInfo - Pointer to the structure identifying the
2112 * drag & drop operation that is currently
2115 static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo)
2118 * Ask the drop source what to do with the operation.
2120 trackerInfo->returnValue = IDropSource_QueryContinueDrag(
2121 trackerInfo->dropSource,
2122 trackerInfo->escPressed,
2123 trackerInfo->dwKeyState);
2126 * All the return valued will stop the operation except the S_OK
2129 if (trackerInfo->returnValue!=S_OK)
2132 * Make sure the message loop in DoDragDrop stops
2134 trackerInfo->trackingDone = TRUE;
2137 * Release the mouse in case the drop target decides to show a popup
2138 * or a menu or something.
2143 * If we end-up over a target, drop the object in the target or
2144 * inform the target that the operation was cancelled.
2146 if (trackerInfo->curDragTarget!=0)
2148 switch (trackerInfo->returnValue)
2151 * If the source wants us to complete the operation, we tell
2152 * the drop target that we just dropped the object in it.
2154 case DRAGDROP_S_DROP:
2156 IDropTarget_Drop(trackerInfo->curDragTarget,
2157 trackerInfo->dataObject,
2158 trackerInfo->dwKeyState,
2159 trackerInfo->curMousePos,
2160 trackerInfo->pdwEffect);
2164 * If the source told us that we should cancel, fool the drop
2165 * target by telling it that the mouse left it's window.
2166 * Also set the drop effect to "NONE" in case the application
2167 * ignores the result of DoDragDrop.
2169 case DRAGDROP_S_CANCEL:
2170 IDropTarget_DragLeave(trackerInfo->curDragTarget);
2171 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2179 * OLEDD_GetButtonState()
2181 * This method will use the current state of the keyboard to build
2182 * a button state mask equivalent to the one passed in the
2183 * WM_MOUSEMOVE wParam.
2185 static DWORD OLEDD_GetButtonState(void)
2187 BYTE keyboardState[256];
2190 GetKeyboardState(keyboardState);
2192 if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
2193 keyMask |= MK_SHIFT;
2195 if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
2196 keyMask |= MK_CONTROL;
2198 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
2199 keyMask |= MK_LBUTTON;
2201 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
2202 keyMask |= MK_RBUTTON;
2204 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
2205 keyMask |= MK_MBUTTON;
2211 * OLEDD_GetButtonState()
2213 * This method will read the default value of the registry key in
2214 * parameter and extract a DWORD value from it. The registry key value
2215 * can be in a string key or a DWORD key.
2218 * regKey - Key to read the default value from
2219 * pdwValue - Pointer to the location where the DWORD
2220 * value is returned. This value is not modified
2221 * if the value is not found.
2224 static void OLEUTL_ReadRegistryDWORDValue(
2233 lres = RegQueryValueExA(regKey,
2240 if (lres==ERROR_SUCCESS)
2245 *pdwValue = *(DWORD*)buffer;
2250 *pdwValue = (DWORD)strtoul(buffer, NULL, 10);
2256 /******************************************************************************
2259 * The operation of this function is documented literally in the WinAPI
2260 * documentation to involve a QueryInterface for the IViewObject interface,
2261 * followed by a call to IViewObject::Draw.
2263 HRESULT WINAPI OleDraw(
2270 IViewObject *viewobject;
2272 hres = IUnknown_QueryInterface(pUnk,
2274 (void**)&viewobject);
2276 if (SUCCEEDED(hres))
2280 rectl.left = lprcBounds->left;
2281 rectl.right = lprcBounds->right;
2282 rectl.top = lprcBounds->top;
2283 rectl.bottom = lprcBounds->bottom;
2284 hres = IViewObject_Draw(viewobject, dwAspect, -1, 0, 0, 0, hdcDraw, &rectl, 0, 0, 0);
2286 IViewObject_Release(viewobject);
2291 return DV_E_NOIVIEWOBJECT;
2295 /***********************************************************************
2296 * OleTranslateAccelerator [OLE32.@]
2298 HRESULT WINAPI OleTranslateAccelerator (LPOLEINPLACEFRAME lpFrame,
2299 LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpmsg)
2303 TRACE("(%p,%p,%p)\n", lpFrame, lpFrameInfo, lpmsg);
2305 if (IsAccelerator(lpFrameInfo->haccel,lpFrameInfo->cAccelEntries,lpmsg,&wID))
2306 return IOleInPlaceFrame_TranslateAccelerator(lpFrame,lpmsg,wID);
2311 /******************************************************************************
2312 * OleCreate [OLE32.@]
2315 HRESULT WINAPI OleCreate(
2319 LPFORMATETC pFormatEtc,
2320 LPOLECLIENTSITE pClientSite,
2325 IUnknown * pUnk = NULL;
2326 IOleObject *pOleObject = NULL;
2328 FIXME("\n\t%s\n\t%s semi-stub!\n", debugstr_guid(rclsid), debugstr_guid(riid));
2330 hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER|CLSCTX_LOCAL_SERVER , riid, (LPVOID*)&pUnk);
2332 if (SUCCEEDED(hres))
2333 hres = IStorage_SetClass(pStg, rclsid);
2335 if (pClientSite && SUCCEEDED(hres))
2337 hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (LPVOID*)&pOleObject);
2338 if (SUCCEEDED(hres))
2341 hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
2345 if (SUCCEEDED(hres))
2347 IPersistStorage * pPS;
2348 if (SUCCEEDED((hres = IUnknown_QueryInterface(pUnk, &IID_IPersistStorage, (LPVOID*)&pPS))))
2350 TRACE("trying to set stg %p\n", pStg);
2351 hres = IPersistStorage_InitNew(pPS, pStg);
2352 TRACE("-- result 0x%08x\n", hres);
2353 IPersistStorage_Release(pPS);
2357 if (pClientSite && SUCCEEDED(hres))
2359 TRACE("trying to set clientsite %p\n", pClientSite);
2360 hres = IOleObject_SetClientSite(pOleObject, pClientSite);
2361 TRACE("-- result 0x%08x\n", hres);
2365 IOleObject_Release(pOleObject);
2367 if (((renderopt == OLERENDER_DRAW) || (renderopt == OLERENDER_FORMAT)) &&
2370 IRunnableObject *pRunnable;
2371 IOleCache *pOleCache;
2374 hres2 = IUnknown_QueryInterface(pUnk, &IID_IRunnableObject, (void **)&pRunnable);
2375 if (SUCCEEDED(hres2))
2377 hres = IRunnableObject_Run(pRunnable, NULL);
2378 IRunnableObject_Release(pRunnable);
2381 if (SUCCEEDED(hres))
2383 hres2 = IUnknown_QueryInterface(pUnk, &IID_IOleCache, (void **)&pOleCache);
2384 if (SUCCEEDED(hres2))
2387 hres = IOleCache_Cache(pOleCache, pFormatEtc, ADVF_PRIMEFIRST, &dwConnection);
2388 IOleCache_Release(pOleCache);
2393 if (FAILED(hres) && pUnk)
2395 IUnknown_Release(pUnk);
2401 TRACE("-- %p\n", pUnk);
2405 /******************************************************************************
2406 * OleGetAutoConvert [OLE32.@]
2408 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2410 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2412 WCHAR buf[CHARS_IN_GUID];
2416 res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey);
2421 if (RegQueryValueW(hkey, NULL, buf, &len))
2423 res = REGDB_E_KEYMISSING;
2426 res = CLSIDFromString(buf, pClsidNew);
2428 if (hkey) RegCloseKey(hkey);
2432 /******************************************************************************
2433 * OleSetAutoConvert [OLE32.@]
2435 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
2437 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2439 WCHAR szClsidNew[CHARS_IN_GUID];
2442 TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
2444 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2447 StringFromGUID2(clsidNew, szClsidNew, CHARS_IN_GUID);
2448 if (RegSetValueW(hkey, wszAutoConvertTo, REG_SZ, szClsidNew, (strlenW(szClsidNew)+1) * sizeof(WCHAR)))
2450 res = REGDB_E_WRITEREGDB;
2455 if (hkey) RegCloseKey(hkey);
2459 /******************************************************************************
2460 * OleDoAutoConvert [OLE32.@]
2462 HRESULT WINAPI OleDoAutoConvert(LPSTORAGE pStg, LPCLSID pClsidNew)
2464 FIXME("(%p,%p) : stub\n",pStg,pClsidNew);
2468 /******************************************************************************
2469 * OleIsRunning [OLE32.@]
2471 BOOL WINAPI OleIsRunning(LPOLEOBJECT pObject)
2473 IRunnableObject *pRunnable;
2477 TRACE("(%p)\n", pObject);
2479 hr = IOleObject_QueryInterface(pObject, &IID_IRunnableObject, (void **)&pRunnable);
2482 running = IRunnableObject_IsRunning(pRunnable);
2483 IRunnableObject_Release(pRunnable);
2487 /***********************************************************************
2488 * OleNoteObjectVisible [OLE32.@]
2490 HRESULT WINAPI OleNoteObjectVisible(LPUNKNOWN pUnknown, BOOL bVisible)
2492 TRACE("(%p, %s)\n", pUnknown, bVisible ? "TRUE" : "FALSE");
2493 return CoLockObjectExternal(pUnknown, bVisible, TRUE);
2497 /***********************************************************************
2498 * OLE_FreeClipDataArray [internal]
2501 * frees the data associated with an array of CLIPDATAs
2503 static void OLE_FreeClipDataArray(ULONG count, CLIPDATA * pClipDataArray)
2506 for (i = 0; i < count; i++)
2507 if (pClipDataArray[i].pClipData)
2508 CoTaskMemFree(pClipDataArray[i].pClipData);
2511 /***********************************************************************
2512 * PropSysAllocString [OLE32.@]
2514 * Basically a copy of SysAllocStringLen.
2516 BSTR WINAPI PropSysAllocString(LPCOLESTR str)
2520 WCHAR* stringBuffer;
2525 len = lstrlenW(str);
2527 * Find the length of the buffer passed-in, in bytes.
2529 bufferSize = len * sizeof (WCHAR);
2532 * Allocate a new buffer to hold the string.
2533 * Don't forget to keep an empty spot at the beginning of the
2534 * buffer for the character count and an extra character at the
2537 newBuffer = HeapAlloc(GetProcessHeap(), 0,
2538 bufferSize + sizeof(WCHAR) + sizeof(DWORD));
2541 * If the memory allocation failed, return a null pointer.
2547 * Copy the length of the string in the placeholder.
2549 *newBuffer = bufferSize;
2552 * Skip the byte count.
2556 memcpy(newBuffer, str, bufferSize);
2559 * Make sure that there is a nul character at the end of the
2562 stringBuffer = (WCHAR*)newBuffer;
2563 stringBuffer[len] = L'\0';
2565 return (LPWSTR)stringBuffer;
2568 /***********************************************************************
2569 * PropSysFreeString [OLE32.@]
2571 * Copy of SysFreeString.
2573 void WINAPI PropSysFreeString(LPOLESTR str)
2575 DWORD* bufferPointer;
2577 /* NULL is a valid parameter */
2581 * We have to be careful when we free a BSTR pointer, it points to
2582 * the beginning of the string but it skips the byte count contained
2583 * before the string.
2585 bufferPointer = (DWORD*)str;
2590 * Free the memory from its "real" origin.
2592 HeapFree(GetProcessHeap(), 0, bufferPointer);
2595 /******************************************************************************
2596 * Check if a PROPVARIANT's type is valid.
2598 static inline HRESULT PROPVARIANT_ValidateType(VARTYPE vt)
2624 case VT_STREAMED_OBJECT:
2625 case VT_STORED_OBJECT:
2626 case VT_BLOB_OBJECT:
2629 case VT_I2|VT_VECTOR:
2630 case VT_I4|VT_VECTOR:
2631 case VT_R4|VT_VECTOR:
2632 case VT_R8|VT_VECTOR:
2633 case VT_CY|VT_VECTOR:
2634 case VT_DATE|VT_VECTOR:
2635 case VT_BSTR|VT_VECTOR:
2636 case VT_ERROR|VT_VECTOR:
2637 case VT_BOOL|VT_VECTOR:
2638 case VT_VARIANT|VT_VECTOR:
2639 case VT_UI1|VT_VECTOR:
2640 case VT_UI2|VT_VECTOR:
2641 case VT_UI4|VT_VECTOR:
2642 case VT_I8|VT_VECTOR:
2643 case VT_UI8|VT_VECTOR:
2644 case VT_LPSTR|VT_VECTOR:
2645 case VT_LPWSTR|VT_VECTOR:
2646 case VT_FILETIME|VT_VECTOR:
2647 case VT_CF|VT_VECTOR:
2648 case VT_CLSID|VT_VECTOR:
2651 WARN("Bad type %d\n", vt);
2652 return STG_E_INVALIDPARAMETER;
2655 /***********************************************************************
2656 * PropVariantClear [OLE32.@]
2658 HRESULT WINAPI PropVariantClear(PROPVARIANT * pvar) /* [in/out] */
2662 TRACE("(%p)\n", pvar);
2667 hr = PROPVARIANT_ValidateType(pvar->vt);
2691 case VT_STREAMED_OBJECT:
2693 case VT_STORED_OBJECT:
2694 if (pvar->u.pStream)
2695 IUnknown_Release(pvar->u.pStream);
2700 /* pick an arbitary typed pointer - we don't care about the type
2701 * as we are just freeing it */
2702 CoTaskMemFree(pvar->u.puuid);
2705 case VT_BLOB_OBJECT:
2706 CoTaskMemFree(pvar->u.blob.pBlobData);
2709 if (pvar->u.bstrVal)
2710 PropSysFreeString(pvar->u.bstrVal);
2713 if (pvar->u.pclipdata)
2715 OLE_FreeClipDataArray(1, pvar->u.pclipdata);
2716 CoTaskMemFree(pvar->u.pclipdata);
2720 if (pvar->vt & VT_VECTOR)
2724 switch (pvar->vt & ~VT_VECTOR)
2727 FreePropVariantArray(pvar->u.capropvar.cElems, pvar->u.capropvar.pElems);
2730 OLE_FreeClipDataArray(pvar->u.caclipdata.cElems, pvar->u.caclipdata.pElems);
2733 for (i = 0; i < pvar->u.cabstr.cElems; i++)
2734 PropSysFreeString(pvar->u.cabstr.pElems[i]);
2737 for (i = 0; i < pvar->u.calpstr.cElems; i++)
2738 CoTaskMemFree(pvar->u.calpstr.pElems[i]);
2741 for (i = 0; i < pvar->u.calpwstr.cElems; i++)
2742 CoTaskMemFree(pvar->u.calpwstr.pElems[i]);
2745 if (pvar->vt & ~VT_VECTOR)
2747 /* pick an arbitary VT_VECTOR structure - they all have the same
2749 CoTaskMemFree(pvar->u.capropvar.pElems);
2753 WARN("Invalid/unsupported type %d\n", pvar->vt);
2756 ZeroMemory(pvar, sizeof(*pvar));
2761 /***********************************************************************
2762 * PropVariantCopy [OLE32.@]
2764 HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, /* [out] */
2765 const PROPVARIANT *pvarSrc) /* [in] */
2770 TRACE("(%p, %p)\n", pvarDest, pvarSrc);
2772 hr = PROPVARIANT_ValidateType(pvarSrc->vt);
2776 /* this will deal with most cases */
2777 CopyMemory(pvarDest, pvarSrc, sizeof(*pvarDest));
2784 case VT_STREAMED_OBJECT:
2786 case VT_STORED_OBJECT:
2787 IUnknown_AddRef((LPUNKNOWN)pvarDest->u.pStream);
2790 pvarDest->u.puuid = CoTaskMemAlloc(sizeof(CLSID));
2791 CopyMemory(pvarDest->u.puuid, pvarSrc->u.puuid, sizeof(CLSID));
2794 len = strlen(pvarSrc->u.pszVal);
2795 pvarDest->u.pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR));
2796 CopyMemory(pvarDest->u.pszVal, pvarSrc->u.pszVal, (len+1)*sizeof(CHAR));
2799 len = lstrlenW(pvarSrc->u.pwszVal);
2800 pvarDest->u.pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
2801 CopyMemory(pvarDest->u.pwszVal, pvarSrc->u.pwszVal, (len+1)*sizeof(WCHAR));
2804 case VT_BLOB_OBJECT:
2805 if (pvarSrc->u.blob.pBlobData)
2807 len = pvarSrc->u.blob.cbSize;
2808 pvarDest->u.blob.pBlobData = CoTaskMemAlloc(len);
2809 CopyMemory(pvarDest->u.blob.pBlobData, pvarSrc->u.blob.pBlobData, len);
2813 pvarDest->u.bstrVal = PropSysAllocString(pvarSrc->u.bstrVal);
2816 if (pvarSrc->u.pclipdata)
2818 len = pvarSrc->u.pclipdata->cbSize - sizeof(pvarSrc->u.pclipdata->ulClipFmt);
2819 pvarDest->u.pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA));
2820 pvarDest->u.pclipdata->cbSize = pvarSrc->u.pclipdata->cbSize;
2821 pvarDest->u.pclipdata->ulClipFmt = pvarSrc->u.pclipdata->ulClipFmt;
2822 pvarDest->u.pclipdata->pClipData = CoTaskMemAlloc(len);
2823 CopyMemory(pvarDest->u.pclipdata->pClipData, pvarSrc->u.pclipdata->pClipData, len);
2827 if (pvarSrc->vt & VT_VECTOR)
2832 switch(pvarSrc->vt & ~VT_VECTOR)
2834 case VT_I1: elemSize = sizeof(pvarSrc->u.cVal); break;
2835 case VT_UI1: elemSize = sizeof(pvarSrc->u.bVal); break;
2836 case VT_I2: elemSize = sizeof(pvarSrc->u.iVal); break;
2837 case VT_UI2: elemSize = sizeof(pvarSrc->u.uiVal); break;
2838 case VT_BOOL: elemSize = sizeof(pvarSrc->u.boolVal); break;
2839 case VT_I4: elemSize = sizeof(pvarSrc->u.lVal); break;
2840 case VT_UI4: elemSize = sizeof(pvarSrc->u.ulVal); break;
2841 case VT_R4: elemSize = sizeof(pvarSrc->u.fltVal); break;
2842 case VT_R8: elemSize = sizeof(pvarSrc->u.dblVal); break;
2843 case VT_ERROR: elemSize = sizeof(pvarSrc->u.scode); break;
2844 case VT_I8: elemSize = sizeof(pvarSrc->u.hVal); break;
2845 case VT_UI8: elemSize = sizeof(pvarSrc->u.uhVal); break;
2846 case VT_CY: elemSize = sizeof(pvarSrc->u.cyVal); break;
2847 case VT_DATE: elemSize = sizeof(pvarSrc->u.date); break;
2848 case VT_FILETIME: elemSize = sizeof(pvarSrc->u.filetime); break;
2849 case VT_CLSID: elemSize = sizeof(*pvarSrc->u.puuid); break;
2850 case VT_CF: elemSize = sizeof(*pvarSrc->u.pclipdata); break;
2851 case VT_BSTR: elemSize = sizeof(*pvarSrc->u.bstrVal); break;
2852 case VT_LPSTR: elemSize = sizeof(*pvarSrc->u.pszVal); break;
2853 case VT_LPWSTR: elemSize = sizeof(*pvarSrc->u.pwszVal); break;
2857 FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR);
2858 return E_INVALIDARG;
2860 len = pvarSrc->u.capropvar.cElems;
2861 pvarDest->u.capropvar.pElems = CoTaskMemAlloc(len * elemSize);
2862 if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT))
2864 for (i = 0; i < len; i++)
2865 PropVariantCopy(&pvarDest->u.capropvar.pElems[i], &pvarSrc->u.capropvar.pElems[i]);
2867 else if (pvarSrc->vt == (VT_VECTOR | VT_CF))
2869 FIXME("Copy clipformats\n");
2871 else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR))
2873 for (i = 0; i < len; i++)
2874 pvarDest->u.cabstr.pElems[i] = PropSysAllocString(pvarSrc->u.cabstr.pElems[i]);
2876 else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
2879 for (i = 0; i < len; i++)
2881 strLen = lstrlenA(pvarSrc->u.calpstr.pElems[i]) + 1;
2882 pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
2883 memcpy(pvarDest->u.calpstr.pElems[i],
2884 pvarSrc->u.calpstr.pElems[i], strLen);
2887 else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR))
2890 for (i = 0; i < len; i++)
2892 strLen = (lstrlenW(pvarSrc->u.calpwstr.pElems[i]) + 1) *
2894 pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
2895 memcpy(pvarDest->u.calpstr.pElems[i],
2896 pvarSrc->u.calpstr.pElems[i], strLen);
2900 CopyMemory(pvarDest->u.capropvar.pElems, pvarSrc->u.capropvar.pElems, len * elemSize);
2903 WARN("Invalid/unsupported type %d\n", pvarSrc->vt);
2909 /***********************************************************************
2910 * FreePropVariantArray [OLE32.@]
2912 HRESULT WINAPI FreePropVariantArray(ULONG cVariants, /* [in] */
2913 PROPVARIANT *rgvars) /* [in/out] */
2917 TRACE("(%u, %p)\n", cVariants, rgvars);
2920 return E_INVALIDARG;
2922 for(i = 0; i < cVariants; i++)
2923 PropVariantClear(&rgvars[i]);
2928 /******************************************************************************
2929 * DllDebugObjectRPCHook (OLE32.@)
2930 * turns on and off internal debugging, pointer is only used on macintosh
2933 BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy)