From 57e86f270910447837efd833e716cf240f40a3dc Mon Sep 17 00:00:00 2001 From: Dmitry Chapyshev Date: Tue, 5 May 2009 15:31:02 +0000 Subject: [PATCH] - Sync ole32 and oleaut32 with Wine 1.1.20 svn path=/trunk/; revision=40795 --- reactos/dll/win32/ole32/clipboard.c | 3186 +++++++++++---------- reactos/dll/win32/ole32/compobj.c | 3 + reactos/dll/win32/ole32/compobj_private.h | 12 + reactos/dll/win32/ole32/marshal.c | 10 +- reactos/dll/win32/ole32/moniker.c | 4 +- reactos/dll/win32/ole32/ole2impl.c | 71 +- reactos/dll/win32/ole32/ole32.spec | 2 +- reactos/dll/win32/ole32/rpc.c | 6 +- reactos/dll/win32/ole32/stg_prop.c | 4 +- reactos/dll/win32/ole32/storage32.c | 8 +- reactos/dll/win32/ole32/storage32.h | 8 +- reactos/dll/win32/ole32/stubmanager.c | 4 +- reactos/dll/win32/ole32/usrmarshal.c | 4 +- reactos/dll/win32/ole32/version16.rc | 24 - reactos/dll/win32/oleaut32/olepicture.c | 3 +- reactos/dll/win32/oleaut32/typelib.c | 53 +- reactos/dll/win32/oleaut32/typelib.h | 1 - reactos/dll/win32/oleaut32/usrmarshal.c | 25 +- reactos/dll/win32/oleaut32/variant.c | 14 +- reactos/dll/win32/oleaut32/variant.h | 3 + reactos/dll/win32/oleaut32/vartype.c | 26 +- reactos/include/psdk/objidl.idl | 4 +- 22 files changed, 1850 insertions(+), 1625 deletions(-) delete mode 100644 reactos/dll/win32/ole32/version16.rc diff --git a/reactos/dll/win32/ole32/clipboard.c b/reactos/dll/win32/ole32/clipboard.c index b33cb525660..4d7a7db7058 100644 --- a/reactos/dll/win32/ole32/clipboard.c +++ b/reactos/dll/win32/ole32/clipboard.c @@ -61,6 +61,7 @@ #include #include #include +#include #define COBJMACROS #define NONAMELESSUNION @@ -84,73 +85,84 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); #define HANDLE_ERROR(err) do { hr = err; TRACE("(HRESULT=%x)\n", (HRESULT)err); goto CLEANUP; } while (0) - -/**************************************************************************** - * OLEClipbrd - * DO NOT add any members before the VTables declaration! - */ -struct OLEClipbrd -{ - /* - * List all interface VTables here - */ - const IDataObjectVtbl* lpvtbl1; /* IDataObject VTable */ - - /* - * The hidden OLE clipboard window. This window is used as the bridge between the - * the OLE and windows clipboard API. (Windows creates one such window per process) - */ - HWND hWndClipboard; - - /* - * Pointer to the source data object (via OleSetClipboard) - */ - IDataObject* pIDataObjectSrc; - - /* - * The registered DataObject clipboard format - */ - UINT cfDataObj; - - /* - * The handle to ourself - */ - HGLOBAL hSelf; - - /* - * Reference count of this object - */ - LONG ref; -}; - -typedef struct OLEClipbrd OLEClipbrd; - - -/**************************************************************************** -* IEnumFORMATETC implementation -* DO NOT add any members before the VTables declaration! -*/ +/* Structure of 'Ole Private Data' clipboard format */ typedef struct { - /* IEnumFORMATETC VTable */ - const IEnumFORMATETCVtbl *lpVtbl; + FORMATETC fmtetc; + DWORD first_use; /* Has this cf been added to the list already */ + DWORD unk[2]; +} ole_priv_data_entry; - /* IEnumFORMATETC fields */ - UINT posFmt; /* current enumerator position */ - UINT countFmt; /* number of EnumFORMATETC's in array */ - LPFORMATETC pFmt; /* array of EnumFORMATETC's */ +typedef struct +{ + DWORD unk1; + DWORD size; /* in bytes of the entire structure */ + DWORD unk2; + DWORD count; /* no. of format entries */ + DWORD unk3[2]; + ole_priv_data_entry entries[1]; /* array of size count */ + /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */ +} ole_priv_data; - /* - * Reference count of this object - */ - LONG ref; +/***************************************************************************** + * td_offs_to_ptr + * + * Returns a ptr to a target device at a given offset from the + * start of the ole_priv_data. + * + * Used when unpacking ole private data from the clipboard. + */ +static inline DVTARGETDEVICE *td_offs_to_ptr(ole_priv_data *data, DWORD_PTR off) +{ + if(off == 0) return NULL; + return (DVTARGETDEVICE*)((char*)data + off); +} - /* - * IUnknown implementation of the parent data object. - */ - IUnknown* pUnkDataObj; +/***************************************************************************** + * td_get_offs + * + * Get the offset from the start of the ole_priv_data of the idx'th + * target device. + * + * Used when packing ole private data to the clipboard. + */ +static inline DWORD_PTR td_get_offs(ole_priv_data *data, DWORD idx) +{ + if(data->entries[idx].fmtetc.ptd == NULL) return 0; + return (char*)data->entries[idx].fmtetc.ptd - (char*)data; +} -} IEnumFORMATETCImpl; +/**************************************************************************** + * Consumer snapshot. Represents the state of the ole clipboard + * returned by OleGetClipboard(). + */ +typedef struct snapshot +{ + const IDataObjectVtbl* lpVtbl; + LONG ref; + + DWORD seq_no; /* Clipboard sequence number corresponding to this snapshot */ + + IDataObject *data; /* If we unmarshal a remote data object we hold a ref here */ +} snapshot; + +/**************************************************************************** + * ole_clipbrd + */ +typedef struct ole_clipbrd +{ + snapshot *latest_snapshot; /* Latest consumer snapshot */ + + HWND window; /* Hidden clipboard window */ + IDataObject *src_data; /* Source object passed to OleSetClipboard */ + ole_priv_data *cached_enum; /* Cached result from the enumeration of src data object */ + IStream *marshal_data; /* Stream onto which to marshal src_data */ +} ole_clipbrd; + +static inline snapshot *impl_from_IDataObject(IDataObject *iface) +{ + return (snapshot*)((char*)iface - FIELD_OFFSET(snapshot, lpVtbl)); +} typedef struct PresentationDataHeader { @@ -161,1425 +173,71 @@ typedef struct PresentationDataHeader } PresentationDataHeader; /* - * The one and only OLEClipbrd object which is created by OLEClipbrd_Initialize() + * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize() */ -static HGLOBAL hTheOleClipboard = 0; -static OLEClipbrd* theOleClipboard = NULL; +static ole_clipbrd* theOleClipboard; - -/* - * Prototypes for the methods of the OLEClipboard class. - */ -void OLEClipbrd_Initialize(void); -void OLEClipbrd_UnInitialize(void); -static OLEClipbrd* OLEClipbrd_Construct(void); -static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy); -static HWND OLEClipbrd_CreateWindow(void); -static void OLEClipbrd_DestroyWindow(HWND hwnd); -static LRESULT CALLBACK OLEClipbrd_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); -static HRESULT OLEClipbrd_RenderFormat( IDataObject *pIDataObject, LPFORMATETC pFormatetc ); -static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc ); - -/* - * Prototypes for the methods of the OLEClipboard class - * that implement IDataObject methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_QueryInterface( - IDataObject* iface, - REFIID riid, - void** ppvObject); -static ULONG WINAPI OLEClipbrd_IDataObject_AddRef( - IDataObject* iface); -static ULONG WINAPI OLEClipbrd_IDataObject_Release( - IDataObject* iface); -static HRESULT WINAPI OLEClipbrd_IDataObject_GetData( - IDataObject* iface, - LPFORMATETC pformatetcIn, - STGMEDIUM* pmedium); -static HRESULT WINAPI OLEClipbrd_IDataObject_GetDataHere( - IDataObject* iface, - LPFORMATETC pformatetc, - STGMEDIUM* pmedium); -static HRESULT WINAPI OLEClipbrd_IDataObject_QueryGetData( - IDataObject* iface, - LPFORMATETC pformatetc); -static HRESULT WINAPI OLEClipbrd_IDataObject_GetCanonicalFormatEtc( - IDataObject* iface, - LPFORMATETC pformatectIn, - LPFORMATETC pformatetcOut); -static HRESULT WINAPI OLEClipbrd_IDataObject_SetData( - IDataObject* iface, - LPFORMATETC pformatetc, - STGMEDIUM* pmedium, - BOOL fRelease); -static HRESULT WINAPI OLEClipbrd_IDataObject_EnumFormatEtc( - IDataObject* iface, - DWORD dwDirection, - IEnumFORMATETC** ppenumFormatEtc); -static HRESULT WINAPI OLEClipbrd_IDataObject_DAdvise( - IDataObject* iface, - FORMATETC* pformatetc, - DWORD advf, - IAdviseSink* pAdvSink, - DWORD* pdwConnection); -static HRESULT WINAPI OLEClipbrd_IDataObject_DUnadvise( - IDataObject* iface, - DWORD dwConnection); -static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise( - IDataObject* iface, - IEnumSTATDATA** ppenumAdvise); - -/* - * Prototypes for the IEnumFORMATETC methods. - */ -static LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[], - LPUNKNOWN pUnkDataObj); -static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface(LPENUMFORMATETC iface, REFIID riid, - LPVOID* ppvObj); -static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface); -static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface); -static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next(LPENUMFORMATETC iface, ULONG celt, - FORMATETC* rgelt, ULONG* pceltFethed); -static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt); -static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface); -static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone(LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum); - - -/* - * Virtual function table for the OLEClipbrd's exposed IDataObject interface - */ -static const IDataObjectVtbl OLEClipbrd_IDataObject_VTable = +static inline HRESULT get_ole_clipbrd(ole_clipbrd **clipbrd) { - OLEClipbrd_IDataObject_QueryInterface, - OLEClipbrd_IDataObject_AddRef, - OLEClipbrd_IDataObject_Release, - OLEClipbrd_IDataObject_GetData, - OLEClipbrd_IDataObject_GetDataHere, - OLEClipbrd_IDataObject_QueryGetData, - OLEClipbrd_IDataObject_GetCanonicalFormatEtc, - OLEClipbrd_IDataObject_SetData, - OLEClipbrd_IDataObject_EnumFormatEtc, - OLEClipbrd_IDataObject_DAdvise, - OLEClipbrd_IDataObject_DUnadvise, - OLEClipbrd_IDataObject_EnumDAdvise -}; + struct oletls *info = COM_CurrentInfo(); + *clipbrd = NULL; -/* - * Virtual function table for IEnumFORMATETC interface - */ -static const IEnumFORMATETCVtbl efvt = -{ - OLEClipbrd_IEnumFORMATETC_QueryInterface, - OLEClipbrd_IEnumFORMATETC_AddRef, - OLEClipbrd_IEnumFORMATETC_Release, - OLEClipbrd_IEnumFORMATETC_Next, - OLEClipbrd_IEnumFORMATETC_Skip, - OLEClipbrd_IEnumFORMATETC_Reset, - OLEClipbrd_IEnumFORMATETC_Clone -}; + if(!info->ole_inits) + return CO_E_NOTINITIALIZED; + *clipbrd = theOleClipboard; + + return S_OK; +} /* * Name of our registered OLE clipboard window class */ -static const CHAR OLEClipbrd_WNDCLASS[] = "CLIPBRDWNDCLASS"; +static const WCHAR clipbrd_wndclass[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0}; -/* - * If we need to store state info we can store it here. - * For now we don't need this functionality. - * -typedef struct tagClipboardWindowInfo +static const WCHAR wine_marshal_dataobject[] = {'W','i','n','e',' ','m','a','r','s','h','a','l',' ','d','a','t','a','o','b','j','e','c','t',0}; + +UINT ownerlink_clipboard_format = 0; +UINT filename_clipboard_format = 0; +UINT filenameW_clipboard_format = 0; +UINT dataobject_clipboard_format = 0; +UINT embedded_object_clipboard_format = 0; +UINT embed_source_clipboard_format = 0; +UINT custom_link_source_clipboard_format = 0; +UINT link_source_clipboard_format = 0; +UINT object_descriptor_clipboard_format = 0; +UINT link_source_descriptor_clipboard_format = 0; +UINT ole_private_data_clipboard_format = 0; + +static UINT wine_marshal_clipboard_format; + +static inline char *dump_fmtetc(FORMATETC *fmt) { -} ClipboardWindowInfo; - */ + static char buf[100]; -/*---------------------------------------------------------------------* - * Win32 OLE clipboard API - *---------------------------------------------------------------------*/ - -/*********************************************************************** - * OleSetClipboard [OLE32.@] - * Places a pointer to the specified data object onto the clipboard, - * making the data object accessible to the OleGetClipboard function. - * - * RETURNS - * - * S_OK IDataObject pointer placed on the clipboard - * CLIPBRD_E_CANT_OPEN OpenClipboard failed - * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed - * CLIPBRD_E_CANT_CLOSE CloseClipboard failed - * CLIPBRD_E_CANT_SET SetClipboard failed - */ - -HRESULT WINAPI OleSetClipboard(IDataObject* pDataObj) -{ - HRESULT hr = S_OK; - IEnumFORMATETC* penumFormatetc = NULL; - FORMATETC rgelt; - BOOL bClipboardOpen = FALSE; - struct oletls *info = COM_CurrentInfo(); -/* - HGLOBAL hDataObject = 0; - OLEClipbrd **ppDataObject; -*/ - - TRACE("(%p)\n", pDataObj); - - if(!info) - WARN("Could not allocate tls\n"); - else - if(!info->ole_inits) - return CO_E_NOTINITIALIZED; - - /* - * Make sure we have a clipboard object - */ - OLEClipbrd_Initialize(); - - /* - * If the Ole clipboard window hasn't been created yet, create it now. - */ - if ( !theOleClipboard->hWndClipboard ) - theOleClipboard->hWndClipboard = OLEClipbrd_CreateWindow(); - - if ( !theOleClipboard->hWndClipboard ) /* sanity check */ - HANDLE_ERROR( E_FAIL ); - - /* - * Open the Windows clipboard, associating it with our hidden window - */ - if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) ) - HANDLE_ERROR( CLIPBRD_E_CANT_OPEN ); - - /* - * Empty the current clipboard and make our window the clipboard owner - * NOTE: This will trigger a WM_DESTROYCLIPBOARD message - */ - if ( !EmptyClipboard() ) - HANDLE_ERROR( CLIPBRD_E_CANT_EMPTY ); - - /* - * If we are already holding on to an IDataObject first release that. - */ - if ( theOleClipboard->pIDataObjectSrc ) - { - IDataObject_Release(theOleClipboard->pIDataObjectSrc); - theOleClipboard->pIDataObjectSrc = NULL; - } - - /* - * AddRef the data object passed in and save its pointer. - * A NULL value indicates that the clipboard should be emptied. - */ - theOleClipboard->pIDataObjectSrc = pDataObj; - if ( pDataObj ) - { - IDataObject_AddRef(theOleClipboard->pIDataObjectSrc); - } - - /* - * Enumerate all HGLOBAL formats supported by the source and make - * those formats available using delayed rendering using SetClipboardData. - * Only global memory based data items may be made available to non-OLE - * applications via the standard Windows clipboard API. Data based on other - * mediums(non TYMED_HGLOBAL) can only be accessed via the Ole Clipboard API. - * - * TODO: Do we need to additionally handle TYMED_IStorage media by copying - * the storage into global memory? - */ - if ( pDataObj ) - { - if ( FAILED(hr = IDataObject_EnumFormatEtc( pDataObj, - DATADIR_GET, - &penumFormatetc ))) - { - HANDLE_ERROR( hr ); - } - - while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) ) - { - if ( rgelt.tymed == TYMED_HGLOBAL ) - { - CHAR szFmtName[80]; - TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat, - GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1) - ? szFmtName : ""); - - SetClipboardData( rgelt.cfFormat, NULL); - } - } - IEnumFORMATETC_Release(penumFormatetc); - } - - /* - * Windows additionally creates a new "DataObject" clipboard format - * and stores in on the clipboard. We could possibly store a pointer - * to our internal IDataObject interface on the clipboard. I'm not - * sure what the use of this is though. - * Enable the code below for this functionality. - */ -/* - theOleClipboard->cfDataObj = RegisterClipboardFormatA("DataObject"); - hDataObject = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, - sizeof(OLEClipbrd *)); - if (hDataObject==0) - HANDLE_ERROR( E_OUTOFMEMORY ); - - ppDataObject = GlobalLock(hDataObject); - *ppDataObject = theOleClipboard; - GlobalUnlock(hDataObject); - - if ( !SetClipboardData( theOleClipboard->cfDataObj, hDataObject ) ) - HANDLE_ERROR( CLIPBRD_E_CANT_SET ); -*/ - - hr = S_OK; - -CLEANUP: - - /* - * Close Windows clipboard (It remains associated with our window) - */ - if ( bClipboardOpen && !CloseClipboard() ) - hr = CLIPBRD_E_CANT_CLOSE; - - /* - * Release the source IDataObject if something failed - */ - if ( FAILED(hr) ) - { - if (theOleClipboard->pIDataObjectSrc) - { - IDataObject_Release(theOleClipboard->pIDataObjectSrc); - theOleClipboard->pIDataObjectSrc = NULL; - } - } - - return hr; + snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x", + fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed); + return buf; } - -/*********************************************************************** - * OleGetClipboard [OLE32.@] - * Returns a pointer to our internal IDataObject which represents the conceptual - * state of the Windows clipboard. If the current clipboard already contains - * an IDataObject, our internal IDataObject will delegate to this object. - */ -HRESULT WINAPI OleGetClipboard(IDataObject** ppDataObj) -{ - HRESULT hr = S_OK; - TRACE("()\n"); - - /* - * Make sure we have a clipboard object - */ - OLEClipbrd_Initialize(); - - if (!theOleClipboard) - return E_OUTOFMEMORY; - - /* Return a reference counted IDataObject */ - hr = IDataObject_QueryInterface( (IDataObject*)&(theOleClipboard->lpvtbl1), - &IID_IDataObject, (void**)ppDataObj); - return hr; -} - -/****************************************************************************** - * OleFlushClipboard [OLE32.@] - * Renders the data from the source IDataObject into the windows clipboard - * - * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media - * by copying the storage into global memory. Subsequently the default - * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL - * back to TYMED_IStorage. - */ -HRESULT WINAPI OleFlushClipboard(void) -{ - IEnumFORMATETC* penumFormatetc = NULL; - FORMATETC rgelt; - HRESULT hr = S_OK; - BOOL bClipboardOpen = FALSE; - IDataObject* pIDataObjectSrc = NULL; - - TRACE("()\n"); - - /* - * Make sure we have a clipboard object - */ - OLEClipbrd_Initialize(); - - /* - * Already flushed or no source DataObject? Nothing to do. - */ - if (!theOleClipboard->pIDataObjectSrc) - return S_OK; - - /* - * Addref and save the source data object we are holding on to temporarily, - * since it will be released when we empty the clipboard. - */ - pIDataObjectSrc = theOleClipboard->pIDataObjectSrc; - IDataObject_AddRef(pIDataObjectSrc); - - /* - * Open the Windows clipboard - */ - if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) ) - HANDLE_ERROR( CLIPBRD_E_CANT_OPEN ); - - /* - * Empty the current clipboard - */ - if ( !EmptyClipboard() ) - HANDLE_ERROR( CLIPBRD_E_CANT_EMPTY ); - - /* - * Render all HGLOBAL formats supported by the source into - * the windows clipboard. - */ - if ( FAILED( hr = IDataObject_EnumFormatEtc( pIDataObjectSrc, - DATADIR_GET, - &penumFormatetc) )) - { - HANDLE_ERROR( hr ); - } - - while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) ) - { - if ( rgelt.tymed == TYMED_HGLOBAL ) - { - CHAR szFmtName[80]; - TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat, - GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1) - ? szFmtName : ""); - - /* - * Render the clipboard data - */ - if ( FAILED(OLEClipbrd_RenderFormat( pIDataObjectSrc, &rgelt )) ) - continue; - } - } - - IEnumFORMATETC_Release(penumFormatetc); - - /* - * Release the source data object we are holding on to - */ - IDataObject_Release(pIDataObjectSrc); - -CLEANUP: - - /* - * Close Windows clipboard (It remains associated with our window) - */ - if ( bClipboardOpen && !CloseClipboard() ) - hr = CLIPBRD_E_CANT_CLOSE; - - return hr; -} - - -/*********************************************************************** - * OleIsCurrentClipboard [OLE32.@] - */ -HRESULT WINAPI OleIsCurrentClipboard(IDataObject *pDataObject) -{ - TRACE("()\n"); - /* - * Make sure we have a clipboard object - */ - OLEClipbrd_Initialize(); - - if (!theOleClipboard) - return E_OUTOFMEMORY; - - if (pDataObject == NULL) - return S_FALSE; - - return (pDataObject == theOleClipboard->pIDataObjectSrc) ? S_OK : S_FALSE; -} - - -/*---------------------------------------------------------------------* - * Internal implementation methods for the OLE clipboard - *---------------------------------------------------------------------*/ - -/*********************************************************************** - * OLEClipbrd_Initialize() - * Initializes the OLE clipboard. - */ -void OLEClipbrd_Initialize(void) -{ - /* - * Create the clipboard if necessary - */ - if ( !theOleClipboard ) - { - TRACE("()\n"); - theOleClipboard = OLEClipbrd_Construct(); - } -} - - -/*********************************************************************** - * OLEClipbrd_UnInitialize() - * Un-Initializes the OLE clipboard - */ -void OLEClipbrd_UnInitialize(void) -{ - TRACE("()\n"); - /* - * Destroy the clipboard if no one holds a reference to us. - * Note that the clipboard was created with a reference count of 1. - */ - if ( theOleClipboard && (theOleClipboard->ref <= 1) ) - { - OLEClipbrd_Destroy( theOleClipboard ); - } - else - { - WARN( "() : OLEClipbrd_UnInitialize called while client holds an IDataObject reference!\n"); - } -} - - -/********************************************************* - * Construct the OLEClipbrd class. - */ -static OLEClipbrd* OLEClipbrd_Construct(void) -{ - OLEClipbrd* newObject = NULL; - HGLOBAL hNewObject = 0; - - /* - * Allocate space for the object. We use GlobalAlloc since we need - * an HGLOBAL to expose our DataObject as a registered clipboard type. - */ - hNewObject = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, - sizeof(OLEClipbrd)); - if (hNewObject==0) - return NULL; - - /* - * Lock the handle for the entire lifetime of the clipboard. - */ - newObject = GlobalLock(hNewObject); - - /* - * Initialize the virtual function table. - */ - newObject->lpvtbl1 = &OLEClipbrd_IDataObject_VTable; - - /* - * Start with one reference count. The caller of this function - * must release the interface pointer when it is done. - */ - newObject->ref = 1; - - newObject->hSelf = hNewObject; - - /* - * The Ole clipboard is a singleton - save the global handle and pointer - */ - theOleClipboard = newObject; - hTheOleClipboard = hNewObject; - - return theOleClipboard; -} - -static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy) -{ - TRACE("()\n"); - - if ( !ptrToDestroy ) - return; - - /* - * Destroy the Ole clipboard window - */ - if ( ptrToDestroy->hWndClipboard ) - OLEClipbrd_DestroyWindow(ptrToDestroy->hWndClipboard); - - /* - * Free the actual OLE Clipboard structure. - */ - TRACE("() - Destroying clipboard data object.\n"); - GlobalUnlock(ptrToDestroy->hSelf); - GlobalFree(ptrToDestroy->hSelf); - - /* - * The Ole clipboard is a singleton (ptrToDestroy == theOleClipboard) - */ - theOleClipboard = NULL; - hTheOleClipboard = 0; -} - - -/*********************************************************************** - * OLEClipbrd_CreateWindow() - * Create the clipboard window - */ -static HWND OLEClipbrd_CreateWindow(void) -{ - HWND hwnd = 0; - WNDCLASSEXA wcex; - - /* - * Register the clipboard window class if necessary - */ - ZeroMemory( &wcex, sizeof(WNDCLASSEXA)); - - wcex.cbSize = sizeof(WNDCLASSEXA); - /* Windows creates this class with a style mask of 0 - * We don't bother doing this since the FindClassByAtom code - * would have to be changed to deal with this idiosyncrasy. */ - wcex.style = CS_GLOBALCLASS; - wcex.lpfnWndProc = OLEClipbrd_WndProc; - wcex.hInstance = 0; - wcex.lpszClassName = OLEClipbrd_WNDCLASS; - - RegisterClassExA(&wcex); - - /* - * Create a hidden window to receive OLE clipboard messages - */ - -/* - * If we need to store state info we can store it here. - * For now we don't need this functionality. - * ClipboardWindowInfo clipboardInfo; - * ZeroMemory( &trackerInfo, sizeof(ClipboardWindowInfo)); - */ - - hwnd = CreateWindowA(OLEClipbrd_WNDCLASS, - "ClipboardWindow", - WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - 0, - 0, - 0, - 0 /*(LPVOID)&clipboardInfo */); - - return hwnd; -} - -/*********************************************************************** - * OLEClipbrd_DestroyWindow(HWND) - * Destroy the clipboard window and unregister its class - */ -static void OLEClipbrd_DestroyWindow(HWND hwnd) -{ - /* - * Destroy clipboard window and unregister its WNDCLASS - */ - DestroyWindow(hwnd); - UnregisterClassA( OLEClipbrd_WNDCLASS, 0 ); -} - -/*********************************************************************** - * OLEClipbrd_WndProc(HWND, unsigned, WORD, LONG) - * Processes messages sent to the OLE clipboard window. - * Note that we will intercept messages in our WndProc only when data - * has been placed in the clipboard via OleSetClipboard(). - * i.e. Only when OLE owns the windows clipboard. - */ -static LRESULT CALLBACK OLEClipbrd_WndProc - (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - /* - * WM_RENDERFORMAT - * We receive this message to allow us to handle delayed rendering of - * a specific clipboard format when an application requests data in - * that format by calling GetClipboardData. - * (Recall that in OleSetClipboard, we used SetClipboardData to - * make all HGLOBAL formats supported by the source IDataObject - * available using delayed rendering) - * On receiving this message we must actually render the data in the - * specified format and place it on the clipboard by calling the - * SetClipboardData function. - */ - case WM_RENDERFORMAT: - { - FORMATETC rgelt; - - ZeroMemory( &rgelt, sizeof(FORMATETC)); - - /* - * Initialize FORMATETC to a Windows clipboard friendly format - */ - rgelt.cfFormat = (UINT) wParam; - rgelt.dwAspect = DVASPECT_CONTENT; - rgelt.lindex = -1; - rgelt.tymed = TYMED_HGLOBAL; - - TRACE("(): WM_RENDERFORMAT(cfFormat=%d)\n", rgelt.cfFormat); - - /* - * Render the clipboard data. - * (We must have a source data object or we wouldn't be in this WndProc) - */ - OLEClipbrd_RenderFormat( (IDataObject*)&(theOleClipboard->lpvtbl1), &rgelt ); - - break; - } - - /* - * WM_RENDERALLFORMATS - * Sent before the clipboard owner window is destroyed. - * We should receive this message only when OleUninitialize is called - * while we have an IDataObject in the clipboard. - * For the content of the clipboard to remain available to other - * applications, we must render data in all the formats the source IDataObject - * is capable of generating, and place the data on the clipboard by calling - * SetClipboardData. - */ - case WM_RENDERALLFORMATS: - { - IEnumFORMATETC* penumFormatetc = NULL; - FORMATETC rgelt; - - TRACE("(): WM_RENDERALLFORMATS\n"); - - /* - * Render all HGLOBAL formats supported by the source into - * the windows clipboard. - */ - if ( FAILED( IDataObject_EnumFormatEtc( (IDataObject*)&(theOleClipboard->lpvtbl1), - DATADIR_GET, &penumFormatetc) ) ) - { - WARN("(): WM_RENDERALLFORMATS failed to retrieve EnumFormatEtc!\n"); - return 0; - } - - while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) ) - { - if ( rgelt.tymed == TYMED_HGLOBAL ) - { - /* - * Render the clipboard data. - */ - if ( FAILED(OLEClipbrd_RenderFormat( (IDataObject*)&(theOleClipboard->lpvtbl1), &rgelt )) ) - continue; - - TRACE("(): WM_RENDERALLFORMATS(cfFormat=%d)\n", rgelt.cfFormat); - } - } - - IEnumFORMATETC_Release(penumFormatetc); - - break; - } - - /* - * WM_DESTROYCLIPBOARD - * This is sent by EmptyClipboard before the clipboard is emptied. - * We should release any IDataObject we are holding onto when we receive - * this message, since it indicates that the OLE clipboard should be empty - * from this point on. - */ - case WM_DESTROYCLIPBOARD: - { - TRACE("(): WM_DESTROYCLIPBOARD\n"); - /* - * Release the data object we are holding on to - */ - if ( theOleClipboard->pIDataObjectSrc ) - { - IDataObject_Release(theOleClipboard->pIDataObjectSrc); - theOleClipboard->pIDataObjectSrc = NULL; - } - break; - } - -/* - case WM_ASKCBFORMATNAME: - case WM_CHANGECBCHAIN: - case WM_DRAWCLIPBOARD: - case WM_SIZECLIPBOARD: - case WM_HSCROLLCLIPBOARD: - case WM_VSCROLLCLIPBOARD: - case WM_PAINTCLIPBOARD: -*/ - default: - return DefWindowProcA(hWnd, message, wParam, lParam); - } - - return 0; -} - -#define MAX_CLIPFORMAT_NAME 80 - -/*********************************************************************** - * OLEClipbrd_RenderFormat(LPFORMATETC) - * Render the clipboard data. Note that this call will delegate to the - * source data object. - * Note: This function assumes it is passed an HGLOBAL format to render. - */ -static HRESULT OLEClipbrd_RenderFormat(IDataObject *pIDataObject, LPFORMATETC pFormatetc) -{ - STGMEDIUM std; - HGLOBAL hDup; - HRESULT hr = S_OK; - char szFmtName[MAX_CLIPFORMAT_NAME]; - ILockBytes *ptrILockBytes = 0; - HGLOBAL hStorage = 0; - - if (!GetClipboardFormatNameA(pFormatetc->cfFormat, szFmtName, MAX_CLIPFORMAT_NAME)) - szFmtName[0] = '\0'; - - /* If embed source */ - if (!strcmp(szFmtName, CF_EMBEDSOURCE)) - { - memset(&std, 0, sizeof(STGMEDIUM)); - std.tymed = pFormatetc->tymed = TYMED_ISTORAGE; - - hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0); - if (hStorage == NULL) - HANDLE_ERROR( E_OUTOFMEMORY ); - hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes); - hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg); - - if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->pIDataObjectSrc, pFormatetc, &std))) - { - WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr); - GlobalFree(hStorage); - return hr; - } - - if (1) /* check whether the presentation data is already -not- present */ - { - FORMATETC fmt2; - STGMEDIUM std2; - METAFILEPICT *mfp = 0; - - fmt2.cfFormat = CF_METAFILEPICT; - fmt2.ptd = 0; - fmt2.dwAspect = DVASPECT_CONTENT; - fmt2.lindex = -1; - fmt2.tymed = TYMED_MFPICT; - - memset(&std2, 0, sizeof(STGMEDIUM)); - std2.tymed = TYMED_MFPICT; - - /* Get the metafile picture out of it */ - - if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->pIDataObjectSrc, &fmt2, &std2))) - { - mfp = GlobalLock(std2.u.hGlobal); - } - - if (mfp) - { - OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0}; - IStream *pStream = 0; - void *mfBits; - PresentationDataHeader pdh; - INT nSize; - CLSID clsID; - LPOLESTR strProgID; - CHAR strOleTypeName[51]; - BYTE OlePresStreamHeader [] = - { - 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 - }; - - nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL); - - memset(&pdh, 0, sizeof(PresentationDataHeader)); - memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader)); - - pdh.dwObjectExtentX = mfp->xExt; - pdh.dwObjectExtentY = mfp->yExt; - pdh.dwSize = nSize; - - hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream); - - hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL); - - mfBits = HeapAlloc(GetProcessHeap(), 0, nSize); - nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits); - - hr = IStream_Write(pStream, mfBits, nSize, NULL); - - IStream_Release(pStream); - - HeapFree(GetProcessHeap(), 0, mfBits); - - GlobalUnlock(std2.u.hGlobal); - - ReadClassStg(std.u.pstg, &clsID); - ProgIDFromCLSID(&clsID, &strProgID); - - WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL ); - OLECONVERT_CreateOleStream(std.u.pstg); - OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName); - } - } - } - else - { - if (FAILED(hr = IDataObject_GetData(pIDataObject, pFormatetc, &std))) - { - WARN("() : IDataObject_GetData failed to render clipboard data! (%x)\n", hr); - GlobalFree(hStorage); - return hr; - } - - /* To put a copy back on the clipboard */ - - hStorage = std.u.hGlobal; - } - - /* - * Put a copy of the rendered data back on the clipboard - */ - - if ( !(hDup = OLEClipbrd_GlobalDupMem(hStorage)) ) - HANDLE_ERROR( E_OUTOFMEMORY ); - - if ( !SetClipboardData( pFormatetc->cfFormat, hDup ) ) - { - GlobalFree(hDup); - WARN("() : Failed to set rendered clipboard data into clipboard!\n"); - } - -CLEANUP: - - ReleaseStgMedium(&std); - - return hr; -} - - -/*********************************************************************** - * OLEClipbrd_GlobalDupMem( HGLOBAL ) - * Helper method to duplicate an HGLOBAL chunk of memory - */ -static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc ) -{ - HGLOBAL hGlobalDest; - PVOID pGlobalSrc, pGlobalDest; - DWORD cBytes; - - if ( !hGlobalSrc ) - return 0; - - cBytes = GlobalSize(hGlobalSrc); - if ( 0 == cBytes ) - return 0; - - hGlobalDest = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, - cBytes ); - if ( !hGlobalDest ) - return 0; - - pGlobalSrc = GlobalLock(hGlobalSrc); - pGlobalDest = GlobalLock(hGlobalDest); - if ( !pGlobalSrc || !pGlobalDest ) - { - GlobalFree(hGlobalDest); - return 0; - } - - memcpy(pGlobalDest, pGlobalSrc, cBytes); - - GlobalUnlock(hGlobalSrc); - GlobalUnlock(hGlobalDest); - - return hGlobalDest; -} - - -/*---------------------------------------------------------------------* - * Implementation of the internal IDataObject interface exposed by - * the OLE clipboard. - *---------------------------------------------------------------------*/ - - -/************************************************************************ - * OLEClipbrd_IDataObject_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_QueryInterface( - IDataObject* iface, - REFIID riid, - void** ppvObject) -{ - /* - * Declare "This" pointer - */ - OLEClipbrd *This = (OLEClipbrd *)iface; - TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObject); - - /* - * Perform a sanity check on the parameters. - */ - if ( (This==0) || (ppvObject==0) ) - return E_INVALIDARG; - - /* - * Initialize the return parameter. - */ - *ppvObject = 0; - - /* - * Compare the riid with the interface IDs implemented by this object. - */ - if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) - { - *ppvObject = iface; - } - else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0) - { - *ppvObject = &This->lpvtbl1; - } - else /* We only support IUnknown and IDataObject */ - { - WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; - } - - /* - * Query Interface always increases the reference count by one when it is - * successful. - */ - IUnknown_AddRef((IUnknown*)*ppvObject); - - return S_OK; -} - -/************************************************************************ - * OLEClipbrd_IDataObject_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI OLEClipbrd_IDataObject_AddRef( - IDataObject* iface) -{ - /* - * Declare "This" pointer - */ - OLEClipbrd *This = (OLEClipbrd *)iface; - - TRACE("(%p)->(count=%u)\n",This, This->ref); - - return InterlockedIncrement(&This->ref); - -} - -/************************************************************************ - * OLEClipbrd_IDataObject_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI OLEClipbrd_IDataObject_Release( - IDataObject* iface) -{ - /* - * Declare "This" pointer - */ - OLEClipbrd *This = (OLEClipbrd *)iface; - ULONG ref; - - TRACE("(%p)->(count=%u)\n",This, This->ref); - - /* - * Decrease the reference count on this object. - */ - ref = InterlockedDecrement(&This->ref); - - /* - * If the reference count goes down to 0, perform suicide. - */ - if (ref == 0) - { - OLEClipbrd_Destroy(This); - } - - return ref; -} - - -/************************************************************************ - * OLEClipbrd_IDataObject_GetData (IDataObject) - * - * The OLE Clipboard's implementation of this method delegates to - * a data source if there is one or wraps around the windows clipboard - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_GetData( - IDataObject* iface, - LPFORMATETC pformatetcIn, - STGMEDIUM* pmedium) -{ - HANDLE hData = 0; - BOOL bClipboardOpen = FALSE; - HRESULT hr = S_OK; - LPVOID src; - - /* - * Declare "This" pointer - */ - OLEClipbrd *This = (OLEClipbrd *)iface; - - TRACE("(%p,%p,%p)\n", iface, pformatetcIn, pmedium); - - if ( !pformatetcIn || !pmedium ) - return E_INVALIDARG; - - /* - * If we have a data source placed on the clipboard (via OleSetClipboard) - * simply delegate to the source object's QueryGetData - * NOTE: This code assumes that the IDataObject is in the same address space! - * We will need to add marshalling support when Wine handles multiple processes. - */ - if ( This->pIDataObjectSrc ) - { - return IDataObject_GetData(This->pIDataObjectSrc, pformatetcIn, pmedium); - } - - if ( pformatetcIn->lindex != -1 ) - return DV_E_FORMATETC; - - if ( (pformatetcIn->tymed & TYMED_HGLOBAL) != TYMED_HGLOBAL ) - return DV_E_TYMED; -/* - if ( pformatetcIn->dwAspect != DVASPECT_CONTENT ) - return DV_E_DVASPECT; -*/ - - /* - * Otherwise, get the data from the windows clipboard using GetClipboardData - */ - if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) ) - HANDLE_ERROR( CLIPBRD_E_CANT_OPEN ); - - hData = GetClipboardData(pformatetcIn->cfFormat); - - /* Must make a copy of global handle returned by GetClipboardData; it - * is not valid after we call CloseClipboard - * Application is responsible for freeing the memory (Forte Agent does this) - */ - src = GlobalLock(hData); - if(src) { - LPVOID dest; - ULONG size; - HANDLE hDest; - - size = GlobalSize(hData); - hDest = GlobalAlloc(GHND, size); - dest = GlobalLock(hDest); - memcpy(dest, src, size); - GlobalUnlock(hDest); - GlobalUnlock(hData); - hData = hDest; - } - - /* - * Return the clipboard data in the storage medium structure - */ - pmedium->tymed = (hData == 0) ? TYMED_NULL : TYMED_HGLOBAL; - pmedium->u.hGlobal = hData; - pmedium->pUnkForRelease = NULL; - - hr = S_OK; - -CLEANUP: - /* - * Close Windows clipboard - */ - if ( bClipboardOpen && !CloseClipboard() ) - hr = CLIPBRD_E_CANT_CLOSE; - - if ( FAILED(hr) ) - return hr; - return (hData == 0) ? DV_E_FORMATETC : S_OK; -} - -static HRESULT WINAPI OLEClipbrd_IDataObject_GetDataHere( - IDataObject* iface, - LPFORMATETC pformatetc, - STGMEDIUM* pmedium) -{ - FIXME(": Stub\n"); - return E_NOTIMPL; -} - -/************************************************************************ - * OLEClipbrd_IDataObject_QueryGetData (IDataObject) - * - * The OLE Clipboard's implementation of this method delegates to - * a data source if there is one or wraps around the windows clipboard - * function IsClipboardFormatAvailable() otherwise. - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_QueryGetData( - IDataObject* iface, - LPFORMATETC pformatetc) -{ - TRACE("(%p, %p)\n", iface, pformatetc); - - if (!pformatetc) - return E_INVALIDARG; - - if ( pformatetc->dwAspect != DVASPECT_CONTENT ) - return DV_E_FORMATETC; - - if ( pformatetc->lindex != -1 ) - return DV_E_FORMATETC; - - /* - * Delegate to the Windows clipboard function IsClipboardFormatAvailable - */ - return (IsClipboardFormatAvailable(pformatetc->cfFormat)) ? S_OK : DV_E_CLIPFORMAT; -} - -/************************************************************************ - * OLEClipbrd_IDataObject_GetCanonicalFormatEtc (IDataObject) - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_GetCanonicalFormatEtc( - IDataObject* iface, - LPFORMATETC pformatectIn, - LPFORMATETC pformatetcOut) -{ - TRACE("(%p, %p, %p)\n", iface, pformatectIn, pformatetcOut); - - if ( !pformatectIn || !pformatetcOut ) - return E_INVALIDARG; - - *pformatetcOut = *pformatectIn; - return DATA_S_SAMEFORMATETC; -} - -/************************************************************************ - * OLEClipbrd_IDataObject_SetData (IDataObject) - * - * The OLE Clipboard's does not implement this method - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_SetData( - IDataObject* iface, - LPFORMATETC pformatetc, - STGMEDIUM* pmedium, - BOOL fRelease) -{ - TRACE("\n"); - return E_NOTIMPL; -} - -/************************************************************************ - * OLEClipbrd_IDataObject_EnumFormatEtc (IDataObject) - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_EnumFormatEtc( - IDataObject* iface, - DWORD dwDirection, - IEnumFORMATETC** ppenumFormatEtc) -{ - HRESULT hr = S_OK; - FORMATETC *afmt = NULL; - int cfmt, i; - UINT format; - BOOL bClipboardOpen; - - /* - * Declare "This" pointer - */ - OLEClipbrd *This = (OLEClipbrd *)iface; - - TRACE("(%p, %x, %p)\n", iface, dwDirection, ppenumFormatEtc); - - /* - * If we have a data source placed on the clipboard (via OleSetClipboard) - * simply delegate to the source object's EnumFormatEtc - */ - if ( This->pIDataObjectSrc ) - { - return IDataObject_EnumFormatEtc(This->pIDataObjectSrc, - dwDirection, ppenumFormatEtc); - } - - /* - * Otherwise we must provide our own enumerator which wraps around the - * Windows clipboard function EnumClipboardFormats - */ - if ( !ppenumFormatEtc ) - return E_INVALIDARG; - - if ( dwDirection != DATADIR_GET ) /* IDataObject_SetData not implemented */ - return E_NOTIMPL; - - /* - * Store all current clipboard formats in an array of FORMATETC's, - * and create an IEnumFORMATETC enumerator from this list. - */ - cfmt = CountClipboardFormats(); - afmt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(FORMATETC) * cfmt); - /* - * Open the Windows clipboard, associating it with our hidden window - */ - if ( !(bClipboardOpen = OpenClipboard(This->hWndClipboard)) ) - HANDLE_ERROR( CLIPBRD_E_CANT_OPEN ); - - /* - * Store all current clipboard formats in an array of FORMATETC's - * TODO: Handle TYMED_IStorage media which were put on the clipboard - * by copying the storage into global memory. We must convert this - * TYMED_HGLOBAL back to TYMED_IStorage. - */ - for (i = 0, format = 0; i < cfmt; i++) - { - format = EnumClipboardFormats(format); - if (!format) /* Failed! */ - { - ERR("EnumClipboardFormats failed to return format!\n"); - HANDLE_ERROR( E_FAIL ); - } - - /* Init the FORMATETC struct */ - afmt[i].cfFormat = format; - afmt[i].ptd = NULL; - afmt[i].dwAspect = DVASPECT_CONTENT; - afmt[i].lindex = -1; - afmt[i].tymed = TYMED_HGLOBAL; - } - - /* - * Create an EnumFORMATETC enumerator and return an - * EnumFORMATETC after bumping up its ref count - */ - *ppenumFormatEtc = OLEClipbrd_IEnumFORMATETC_Construct( cfmt, afmt, (LPUNKNOWN)iface); - if (!(*ppenumFormatEtc)) - HANDLE_ERROR( E_OUTOFMEMORY ); - - if (FAILED( hr = IEnumFORMATETC_AddRef(*ppenumFormatEtc))) - HANDLE_ERROR( hr ); - - hr = S_OK; - -CLEANUP: - /* - * Free the array of FORMATETC's - */ - HeapFree(GetProcessHeap(), 0, afmt); - - /* - * Close Windows clipboard - */ - if ( bClipboardOpen && !CloseClipboard() ) - hr = CLIPBRD_E_CANT_CLOSE; - - return hr; -} - -/************************************************************************ - * OLEClipbrd_IDataObject_DAdvise (IDataObject) - * - * The OLE Clipboard's does not implement this method - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_DAdvise( - IDataObject* iface, - FORMATETC* pformatetc, - DWORD advf, - IAdviseSink* pAdvSink, - DWORD* pdwConnection) -{ - TRACE("\n"); - return E_NOTIMPL; -} - -/************************************************************************ - * OLEClipbrd_IDataObject_DUnadvise (IDataObject) - * - * The OLE Clipboard's does not implement this method - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_DUnadvise( - IDataObject* iface, - DWORD dwConnection) -{ - TRACE("\n"); - return E_NOTIMPL; -} - -/************************************************************************ - * OLEClipbrd_IDataObject_EnumDAdvise (IDataObject) - * - * The OLE Clipboard does not implement this method - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise( - IDataObject* iface, - IEnumSTATDATA** ppenumAdvise) -{ - TRACE("\n"); - return E_NOTIMPL; -} - - /*---------------------------------------------------------------------* * Implementation of the internal IEnumFORMATETC interface returned by * the OLE clipboard's IDataObject. *---------------------------------------------------------------------*/ -/************************************************************************ - * OLEClipbrd_IEnumFORMATETC_Construct (UINT, const FORMATETC, LPUNKNOWN) - * - * Creates an IEnumFORMATETC enumerator from an array of FORMATETC - * Structures. pUnkOuter is the outer unknown for reference counting only. - * NOTE: this does not AddRef the interface. - */ - -static LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[], - LPUNKNOWN pUnkDataObj) +typedef struct enum_fmtetc { - IEnumFORMATETCImpl* ef; - DWORD size=cfmt * sizeof(FORMATETC); - LPMALLOC pIMalloc; + const IEnumFORMATETCVtbl *lpVtbl; + LONG ref; - ef = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumFORMATETCImpl)); - if (!ef) - return NULL; + UINT pos; /* current enumerator position */ + ole_priv_data *data; +} enum_fmtetc; - ef->ref = 0; - ef->lpVtbl = &efvt; - ef->pUnkDataObj = pUnkDataObj; - - ef->posFmt = 0; - ef->countFmt = cfmt; - if (FAILED(CoGetMalloc(MEMCTX_TASK, &pIMalloc))) { - HeapFree(GetProcessHeap(), 0, ef); - return NULL; - } - ef->pFmt = IMalloc_Alloc(pIMalloc, size); - IMalloc_Release(pIMalloc); - - if (ef->pFmt) - memcpy(ef->pFmt, afmt, size); - - TRACE("(%p)->()\n",ef); - return (LPENUMFORMATETC)ef; +static inline enum_fmtetc *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface) +{ + return (enum_fmtetc*)((char*)iface - FIELD_OFFSET(enum_fmtetc, lpVtbl)); } - /************************************************************************ * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown) * @@ -1588,24 +246,16 @@ static LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORM static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj) { - IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; + enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); - TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj); - - /* - * Since enumerators are separate objects from the parent data object - * we only need to support the IUnknown and IEnumFORMATETC interfaces - */ + TRACE("(%p)->(IID: %s, %p)\n", This, debugstr_guid(riid), ppvObj); *ppvObj = NULL; - if(IsEqualIID(riid, &IID_IUnknown)) + if(IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IEnumFORMATETC)) { - *ppvObj = This; - } - else if(IsEqualIID(riid, &IID_IEnumFORMATETC)) - { - *ppvObj = This; + *ppvObj = iface; } if(*ppvObj) @@ -1622,20 +272,12 @@ static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface /************************************************************************ * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown) * - * Since enumerating formats only makes sense when our data object is around, - * we insure that it stays as long as we stay by calling our parents IUnknown - * for AddRef and Release. But since we are not controlled by the lifetime of - * the outer object, we still keep our own reference count in order to - * free ourselves. */ static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface) { - IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; + enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); TRACE("(%p)->(count=%u)\n",This, This->ref); - if (This->pUnkDataObj) - IUnknown_AddRef(This->pUnkDataObj); - return InterlockedIncrement(&This->ref); } @@ -1646,26 +288,17 @@ static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface) */ static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface) { - IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; - LPMALLOC pIMalloc; + enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); ULONG ref; TRACE("(%p)->(count=%u)\n",This, This->ref); - if (This->pUnkDataObj) - IUnknown_Release(This->pUnkDataObj); /* Release parent data object */ - ref = InterlockedDecrement(&This->ref); if (!ref) { TRACE("() - destroying IEnumFORMATETC(%p)\n",This); - if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pIMalloc))) - { - IMalloc_Free(pIMalloc, This->pFmt); - IMalloc_Release(pIMalloc); - } - - HeapFree(GetProcessHeap(),0,This); + HeapFree(GetProcessHeap(), 0, This->data); + HeapFree(GetProcessHeap(), 0, This); } return ref; } @@ -1678,23 +311,32 @@ static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface) static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed) { - IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; - UINT cfetch; + enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); + UINT cfetch, i; HRESULT hres = S_FALSE; - TRACE("(%p)->(pos=%u)\n", This, This->posFmt); + TRACE("(%p)->(pos=%u)\n", This, This->pos); - if (This->posFmt < This->countFmt) + if (This->pos < This->data->count) { - cfetch = This->countFmt - This->posFmt; + cfetch = This->data->count - This->pos; if (cfetch >= celt) { cfetch = celt; hres = S_OK; } - memcpy(rgelt, &This->pFmt[This->posFmt], cfetch * sizeof(FORMATETC)); - This->posFmt += cfetch; + for(i = 0; i < cfetch; i++) + { + rgelt[i] = This->data->entries[This->pos++].fmtetc; + if(rgelt[i].ptd) + { + DVTARGETDEVICE *target = rgelt[i].ptd; + rgelt[i].ptd = CoTaskMemAlloc(target->tdSize); + if(!rgelt[i].ptd) return E_OUTOFMEMORY; + memcpy(rgelt[i].ptd, target, target->tdSize); + } + } } else { @@ -1716,13 +358,13 @@ static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next */ static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt) { - IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; + enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); TRACE("(%p)->(num=%u)\n", This, celt); - This->posFmt += celt; - if (This->posFmt > This->countFmt) + This->pos += celt; + if (This->pos > This->data->count) { - This->posFmt = This->countFmt; + This->pos = This->data->count; return S_FALSE; } return S_OK; @@ -1735,35 +377,1549 @@ static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULON */ static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface) { - IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; + enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); TRACE("(%p)->()\n", This); - This->posFmt = 0; + This->pos = 0; return S_OK; } +static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj); + /************************************************************************ * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC) * * Standard enumerator members for IEnumFORMATETC */ static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone - (LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum) + (LPENUMFORMATETC iface, LPENUMFORMATETC* obj) { - IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; - HRESULT hr = S_OK; + enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); + ole_priv_data *new_data; + DWORD i; - TRACE("(%p)->(ppenum=%p)\n", This, ppenum); + TRACE("(%p)->(%p)\n", This, obj); - if ( !ppenum ) + if ( !obj ) return E_INVALIDARG; + *obj = NULL; + + new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size); + if(!new_data) return E_OUTOFMEMORY; + memcpy(new_data, This->data, This->data->size); + + /* Fixup any target device ptrs */ + for(i = 0; i < This->data->count; i++) + new_data->entries[i].fmtetc.ptd = + td_offs_to_ptr(new_data, td_get_offs(This->data, i)); + + return enum_fmtetc_construct(new_data, This->pos, obj); +} + +static const IEnumFORMATETCVtbl efvt = +{ + OLEClipbrd_IEnumFORMATETC_QueryInterface, + OLEClipbrd_IEnumFORMATETC_AddRef, + OLEClipbrd_IEnumFORMATETC_Release, + OLEClipbrd_IEnumFORMATETC_Next, + OLEClipbrd_IEnumFORMATETC_Skip, + OLEClipbrd_IEnumFORMATETC_Reset, + OLEClipbrd_IEnumFORMATETC_Clone +}; + +/************************************************************************ + * enum_fmtetc_construct + * + * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns. + */ +static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj) +{ + enum_fmtetc* ef; + + *obj = NULL; + ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef)); + if (!ef) return E_OUTOFMEMORY; + + ef->ref = 1; + ef->lpVtbl = &efvt; + ef->data = data; + ef->pos = pos; + + TRACE("(%p)->()\n", ef); + *obj = (IEnumFORMATETC *)ef; + return S_OK; +} + +/*********************************************************************** + * dup_global_mem + * + * Helper method to duplicate an HGLOBAL chunk of memory + */ +static HRESULT dup_global_mem( HGLOBAL src, DWORD flags, HGLOBAL *dst ) +{ + void *src_ptr, *dst_ptr; + DWORD size; + + *dst = NULL; + if ( !src ) return S_FALSE; + + size = GlobalSize(src); + + *dst = GlobalAlloc( flags, size ); + if ( !*dst ) return E_OUTOFMEMORY; + + src_ptr = GlobalLock(src); + dst_ptr = GlobalLock(*dst); + + memcpy(dst_ptr, src_ptr, size); + + GlobalUnlock(*dst); + GlobalUnlock(src); + + return S_OK; +} + +/************************************************************ + * render_embed_source_hack + * + * This is clearly a hack and has no place in the clipboard code. + * + */ +static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt) +{ + STGMEDIUM std; + HGLOBAL hStorage = 0; + HRESULT hr = S_OK; + ILockBytes *ptrILockBytes; + + memset(&std, 0, sizeof(STGMEDIUM)); + std.tymed = fmt->tymed = TYMED_ISTORAGE; + + hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0); + if (hStorage == NULL) return E_OUTOFMEMORY; + hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes); + hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg); + ILockBytes_Release(ptrILockBytes); + + if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->src_data, fmt, &std))) + { + WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr); + GlobalFree(hStorage); + return hr; + } + + if (1) /* check whether the presentation data is already -not- present */ + { + FORMATETC fmt2; + STGMEDIUM std2; + METAFILEPICT *mfp = 0; + + fmt2.cfFormat = CF_METAFILEPICT; + fmt2.ptd = 0; + fmt2.dwAspect = DVASPECT_CONTENT; + fmt2.lindex = -1; + fmt2.tymed = TYMED_MFPICT; + + memset(&std2, 0, sizeof(STGMEDIUM)); + std2.tymed = TYMED_MFPICT; + + /* Get the metafile picture out of it */ + + if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->src_data, &fmt2, &std2))) + { + mfp = GlobalLock(std2.u.hGlobal); + } + + if (mfp) + { + OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0}; + IStream *pStream = 0; + void *mfBits; + PresentationDataHeader pdh; + INT nSize; + CLSID clsID; + LPOLESTR strProgID; + CHAR strOleTypeName[51]; + BYTE OlePresStreamHeader [] = + { + 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + + nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL); + + memset(&pdh, 0, sizeof(PresentationDataHeader)); + memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader)); + + pdh.dwObjectExtentX = mfp->xExt; + pdh.dwObjectExtentY = mfp->yExt; + pdh.dwSize = nSize; + + hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream); + + hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL); + + mfBits = HeapAlloc(GetProcessHeap(), 0, nSize); + nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits); + + hr = IStream_Write(pStream, mfBits, nSize, NULL); + + IStream_Release(pStream); + + HeapFree(GetProcessHeap(), 0, mfBits); + + GlobalUnlock(std2.u.hGlobal); + ReleaseStgMedium(&std2); + + ReadClassStg(std.u.pstg, &clsID); + ProgIDFromCLSID(&clsID, &strProgID); + + WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL ); + OLECONVERT_CreateOleStream(std.u.pstg); + OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName); + } + } + + if ( !SetClipboardData( fmt->cfFormat, hStorage ) ) + { + WARN("() : Failed to set rendered clipboard data into clipboard!\n"); + GlobalFree(hStorage); + hr = CLIPBRD_E_CANT_SET; + } + + ReleaseStgMedium(&std); + return hr; +} + +/************************************************************************ + * find_format_in_list + * + * Returns the first entry that matches the provided clipboard format. + */ +static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf) +{ + DWORD i; + for(i = 0; i < num; i++) + if(entries[i].fmtetc.cfFormat == cf) + return &entries[i]; + + return NULL; +} + +/*************************************************************************** + * get_data_from_storage + * + * Returns storage data in an HGLOBAL. + */ +static HRESULT get_data_from_storage(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem) +{ + HGLOBAL h; + IStorage *stg; + HRESULT hr; + FORMATETC stg_fmt; + STGMEDIUM med; + ILockBytes *lbs; + + *mem = NULL; + + h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 ); + if(!h) return E_OUTOFMEMORY; + + hr = CreateILockBytesOnHGlobal(h, FALSE, &lbs); + if(SUCCEEDED(hr)) + { + hr = StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg); + ILockBytes_Release(lbs); + } + if(FAILED(hr)) + { + GlobalFree(h); + return hr; + } + + stg_fmt = *fmt; + med.tymed = stg_fmt.tymed = TYMED_ISTORAGE; + med.u.pstg = stg; + med.pUnkForRelease = NULL; + + hr = IDataObject_GetDataHere(data, &stg_fmt, &med); + if(FAILED(hr)) + { + med.u.pstg = NULL; + hr = IDataObject_GetData(data, &stg_fmt, &med); + if(FAILED(hr)) goto end; + + hr = IStorage_CopyTo(med.u.pstg, 0, NULL, NULL, stg); + ReleaseStgMedium(&med); + if(FAILED(hr)) goto end; + } + *mem = h; + +end: + IStorage_Release(stg); + if(FAILED(hr)) GlobalFree(h); + return hr; +} + +/*************************************************************************** + * get_data_from_stream + * + * Returns stream data in an HGLOBAL. + */ +static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem) +{ + HGLOBAL h; + IStream *stm = NULL; + HRESULT hr; + FORMATETC stm_fmt; + STGMEDIUM med; + + *mem = NULL; + + h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 ); + if(!h) return E_OUTOFMEMORY; + + hr = CreateStreamOnHGlobal(h, FALSE, &stm); + if(FAILED(hr)) goto error; + + stm_fmt = *fmt; + med.tymed = stm_fmt.tymed = TYMED_ISTREAM; + med.u.pstm = stm; + med.pUnkForRelease = NULL; + + hr = IDataObject_GetDataHere(data, &stm_fmt, &med); + if(FAILED(hr)) + { + LARGE_INTEGER offs; + ULARGE_INTEGER pos; + + med.u.pstm = NULL; + hr = IDataObject_GetData(data, &stm_fmt, &med); + if(FAILED(hr)) goto error; + + offs.QuadPart = 0; + IStream_Seek(med.u.pstm, offs, STREAM_SEEK_CUR, &pos); + IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL); + hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL); + ReleaseStgMedium(&med); + if(FAILED(hr)) goto error; + } + *mem = h; + IStream_Release(stm); + return S_OK; + +error: + if(stm) IStream_Release(stm); + GlobalFree(h); + return hr; +} + +/*************************************************************************** + * get_data_from_global + * + * Returns global data in an HGLOBAL. + */ +static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem) +{ + HGLOBAL h; + HRESULT hr; + FORMATETC mem_fmt; + STGMEDIUM med; + + *mem = NULL; + + mem_fmt = *fmt; + mem_fmt.tymed = TYMED_HGLOBAL; + + hr = IDataObject_GetData(data, &mem_fmt, &med); + if(FAILED(hr)) return hr; + + hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h); + + if(SUCCEEDED(hr)) *mem = h; + + ReleaseStgMedium(&med); + + return hr; +} + +/*********************************************************************** + * render_format + * + * Render the clipboard data. Note that this call will delegate to the + * source data object. + */ +static HRESULT render_format(IDataObject *data, LPFORMATETC fmt) +{ + HGLOBAL clip_data = NULL; + HRESULT hr; + + /* Embed source hack */ + if(fmt->cfFormat == embed_source_clipboard_format) + { + return render_embed_source_hack(data, fmt); + } + + if(fmt->tymed & TYMED_ISTORAGE) + { + hr = get_data_from_storage(data, fmt, &clip_data); + } + else if(fmt->tymed & TYMED_ISTREAM) + { + hr = get_data_from_stream(data, fmt, &clip_data); + } + else if(fmt->tymed & TYMED_HGLOBAL) + { + hr = get_data_from_global(data, fmt, &clip_data); + } + else + { + FIXME("Unhandled tymed %x\n", fmt->tymed); + hr = DV_E_FORMATETC; + } + + if(SUCCEEDED(hr)) + { + if ( !SetClipboardData(fmt->cfFormat, clip_data) ) + { + WARN("() : Failed to set rendered clipboard data into clipboard!\n"); + GlobalFree(clip_data); + hr = CLIPBRD_E_CANT_SET; + } + } + + return hr; +} + +/*---------------------------------------------------------------------* + * Implementation of the internal IDataObject interface exposed by + * the OLE clipboard. + *---------------------------------------------------------------------*/ + + +/************************************************************************ + * snapshot_QueryInterface + */ +static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface, + REFIID riid, void **ppvObject) +{ + snapshot *This = impl_from_IDataObject(iface); + TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject); + + if ( (This==0) || (ppvObject==0) ) return E_INVALIDARG; - *ppenum = OLEClipbrd_IEnumFORMATETC_Construct(This->countFmt, - This->pFmt, - This->pUnkDataObj); + *ppvObject = 0; - if (FAILED( hr = IEnumFORMATETC_AddRef(*ppenum))) - return ( hr ); + if (IsEqualIID(&IID_IUnknown, riid) || + IsEqualIID(&IID_IDataObject, riid)) + { + *ppvObject = iface; + } + else + { + WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; + } - return (*ppenum) ? S_OK : E_OUTOFMEMORY; + IUnknown_AddRef((IUnknown*)*ppvObject); + + return S_OK; +} + +/************************************************************************ + * snapshot_AddRef + */ +static ULONG WINAPI snapshot_AddRef(IDataObject *iface) +{ + snapshot *This = impl_from_IDataObject(iface); + + TRACE("(%p)->(count=%u)\n", This, This->ref); + + return InterlockedIncrement(&This->ref); +} + +/************************************************************************ + * snapshot_Release + */ +static ULONG WINAPI snapshot_Release(IDataObject *iface) +{ + snapshot *This = impl_from_IDataObject(iface); + ULONG ref; + + TRACE("(%p)->(count=%u)\n", This, This->ref); + + ref = InterlockedDecrement(&This->ref); + + if (ref == 0) + { + ole_clipbrd *clipbrd; + HRESULT hr = get_ole_clipbrd(&clipbrd); + + if(This->data) IDataObject_Release(This->data); + + if(SUCCEEDED(hr) && clipbrd->latest_snapshot == This) + clipbrd->latest_snapshot = NULL; + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} + +/************************************************************ + * get_current_ole_clip_window + * + * Return the window that owns the ole clipboard. + * + * If the clipboard is flushed or not owned by ole this will + * return NULL. + */ +static HWND get_current_ole_clip_window(void) +{ + HGLOBAL h; + HWND *ptr, wnd; + + h = GetClipboardData(dataobject_clipboard_format); + if(!h) return NULL; + ptr = GlobalLock(h); + if(!ptr) return NULL; + wnd = *ptr; + GlobalUnlock(h); + return wnd; +} + +/************************************************************ + * get_current_dataobject + * + * Return an unmarshalled IDataObject if there is a current + * (ie non-flushed) object on the ole clipboard. + */ +static HRESULT get_current_dataobject(IDataObject **data) +{ + HRESULT hr = S_FALSE; + HWND wnd = get_current_ole_clip_window(); + HGLOBAL h; + void *ptr; + IStream *stm; + LARGE_INTEGER pos; + + *data = NULL; + if(!wnd) return S_FALSE; + + h = GetClipboardData(wine_marshal_clipboard_format); + if(!h) return S_FALSE; + if(GlobalSize(h) == 0) return S_FALSE; + ptr = GlobalLock(h); + if(!ptr) return S_FALSE; + + hr = CreateStreamOnHGlobal(NULL, TRUE, &stm); + if(FAILED(hr)) goto end; + + hr = IStream_Write(stm, ptr, GlobalSize(h), NULL); + if(SUCCEEDED(hr)) + { + pos.QuadPart = 0; + IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL); + hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data); + } + IStream_Release(stm); + +end: + GlobalUnlock(h); + return hr; +} + +static DWORD get_tymed_from_nonole_cf(UINT cf) +{ + if(cf >= 0xc000) return TYMED_ISTREAM | TYMED_HGLOBAL; + + switch(cf) + { + case CF_TEXT: + case CF_OEMTEXT: + case CF_UNICODETEXT: + return TYMED_ISTREAM | TYMED_HGLOBAL; + case CF_ENHMETAFILE: + return TYMED_ENHMF; + case CF_METAFILEPICT: + return TYMED_MFPICT; + default: + FIXME("returning TYMED_NULL for cf %04x\n", cf); + return TYMED_NULL; + } +} + +/*********************************************************** + * get_priv_data + * + * Returns a copy of the Ole Private Data + */ +static HRESULT get_priv_data(ole_priv_data **data) +{ + HGLOBAL handle; + HRESULT hr = S_OK; + ole_priv_data *ret = NULL; + + *data = NULL; + + handle = GetClipboardData( ole_private_data_clipboard_format ); + if(handle) + { + ole_priv_data *src = GlobalLock(handle); + if(src) + { + DWORD i; + + /* FIXME: sanity check on size */ + ret = HeapAlloc(GetProcessHeap(), 0, src->size); + if(!ret) + { + GlobalUnlock(handle); + return E_OUTOFMEMORY; + } + memcpy(ret, src, src->size); + GlobalUnlock(handle); + + /* Fixup any target device offsets to ptrs */ + for(i = 0; i < ret->count; i++) + ret->entries[i].fmtetc.ptd = + td_offs_to_ptr(ret, (DWORD_PTR) ret->entries[i].fmtetc.ptd); + } + } + + if(!ret) /* Non-ole data */ + { + UINT cf; + DWORD count = 0, idx, size = FIELD_OFFSET(ole_priv_data, entries); + + for(cf = 0; (cf = EnumClipboardFormats(cf)) != 0; count++) + { + char buf[100]; + GetClipboardFormatNameA(cf, buf, sizeof(buf)); + TRACE("\tcf %04x %s\n", cf, buf); + ; + } + TRACE("count %d\n", count); + size += count * sizeof(ret->entries[0]); + + /* There are holes in fmtetc so zero init */ + ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); + if(!ret) return E_OUTOFMEMORY; + ret->size = size; + ret->count = count; + + for(cf = 0, idx = 0; (cf = EnumClipboardFormats(cf)) != 0; idx++) + { + ret->entries[idx].fmtetc.cfFormat = cf; + ret->entries[idx].fmtetc.ptd = NULL; + ret->entries[idx].fmtetc.dwAspect = DVASPECT_CONTENT; + ret->entries[idx].fmtetc.lindex = -1; + ret->entries[idx].fmtetc.tymed = get_tymed_from_nonole_cf(cf); + ret->entries[idx].first_use = 1; + } + } + + *data = ret; + return hr; +} + +/************************************************************************ + * get_stgmed_for_global + * + * Returns a stg medium with a copy of the global handle + */ +static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med) +{ + HRESULT hr; + + med->pUnkForRelease = NULL; + med->tymed = TYMED_NULL; + + hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal); + + if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL; + + return hr; +} + +/************************************************************************ + * get_stgmed_for_stream + * + * Returns a stg medium with a stream based on the handle + */ +static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med) +{ + HRESULT hr; + HGLOBAL dst; + + med->pUnkForRelease = NULL; + med->tymed = TYMED_NULL; + + hr = dup_global_mem(h, GMEM_MOVEABLE, &dst); + if(FAILED(hr)) return hr; + + hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm); + if(FAILED(hr)) + { + GlobalFree(dst); + return hr; + } + + med->tymed = TYMED_ISTREAM; + return hr; +} + +/************************************************************************ + * get_stgmed_for_storage + * + * Returns a stg medium with a storage based on the handle + */ +static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med) +{ + HRESULT hr; + HGLOBAL dst; + ILockBytes *lbs; + + med->pUnkForRelease = NULL; + med->tymed = TYMED_NULL; + + hr = dup_global_mem(h, GMEM_MOVEABLE, &dst); + if(FAILED(hr)) return hr; + + hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs); + if(FAILED(hr)) + { + GlobalFree(dst); + return hr; + } + + hr = StgOpenStorageOnILockBytes(lbs, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg); + ILockBytes_Release(lbs); + if(FAILED(hr)) + { + GlobalFree(dst); + return hr; + } + + med->tymed = TYMED_ISTORAGE; + return hr; +} + +static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2) +{ + const WCHAR *str1, *str2; + + if(off1 == 0 && off2 == 0) return TRUE; + if(off1 == 0 || off2 == 0) return FALSE; + + str1 = (const WCHAR*)((const char*)t1 + off1); + str2 = (const WCHAR*)((const char*)t2 + off2); + + return !lstrcmpW(str1, str2); +} + +static inline BOOL td_equal(const DVTARGETDEVICE *t1, const DVTARGETDEVICE *t2) +{ + if(t1 == NULL && t2 == NULL) return TRUE; + if(t1 == NULL || t2 == NULL) return FALSE; + + if(!string_off_equal(t1, t1->tdDriverNameOffset, t2, t2->tdDriverNameOffset)) + return FALSE; + if(!string_off_equal(t1, t1->tdDeviceNameOffset, t2, t2->tdDeviceNameOffset)) + return FALSE; + if(!string_off_equal(t1, t1->tdPortNameOffset, t2, t2->tdPortNameOffset)) + return FALSE; + + /* FIXME check devmode? */ + + return TRUE; +} + +/************************************************************************ + * snapshot_GetData + */ +static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt, + STGMEDIUM *med) +{ + snapshot *This = impl_from_IDataObject(iface); + HANDLE h; + HRESULT hr; + ole_priv_data *enum_data = NULL; + ole_priv_data_entry *entry; + DWORD mask; + + TRACE("(%p, %p {%s}, %p)\n", iface, fmt, dump_fmtetc(fmt), med); + + if ( !fmt || !med ) return E_INVALIDARG; + + if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN; + + if(!This->data) + hr = get_current_dataobject(&This->data); + + if(This->data) + { + hr = IDataObject_GetData(This->data, fmt, med); + CloseClipboard(); + return hr; + } + + h = GetClipboardData(fmt->cfFormat); + if(!h) + { + hr = DV_E_FORMATETC; + goto end; + } + + hr = get_priv_data(&enum_data); + if(FAILED(hr)) goto end; + + entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat); + if(entry) + { + if(!td_equal(fmt->ptd, entry->fmtetc.ptd)) + { + hr = DV_E_FORMATETC; + goto end; + } + mask = fmt->tymed & entry->fmtetc.tymed; + if(!mask) mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL); + } + else /* non-Ole format */ + mask = fmt->tymed & TYMED_HGLOBAL; + + if(mask & TYMED_ISTORAGE) + hr = get_stgmed_for_storage(h, med); + else if(mask & TYMED_HGLOBAL) + hr = get_stgmed_for_global(h, med); + else if(mask & TYMED_ISTREAM) + hr = get_stgmed_for_stream(h, med); + else + { + FIXME("Unhandled tymed - emum tymed %x req tymed %x\n", entry->fmtetc.tymed, fmt->tymed); + hr = E_FAIL; + goto end; + } + +end: + HeapFree(GetProcessHeap(), 0, enum_data); + if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE; + return hr; +} + +/************************************************************************ + * snapshot_GetDataHere + */ +static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt, + STGMEDIUM *med) +{ + FIXME("(%p, %p {%s}, %p): stub\n", iface, fmt, dump_fmtetc(fmt), med); + return E_NOTIMPL; +} + +/************************************************************************ + * snapshot_QueryGetData + * + * The OLE Clipboard's implementation of this method delegates to + * a data source if there is one or wraps around the windows clipboard + * function IsClipboardFormatAvailable() otherwise. + * + */ +static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt) +{ + FIXME("(%p, %p {%s})\n", iface, fmt, dump_fmtetc(fmt)); + + if (!fmt) return E_INVALIDARG; + + if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC; + + if ( fmt->lindex != -1 ) return DV_E_FORMATETC; + + return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT; +} + +/************************************************************************ + * snapshot_GetCanonicalFormatEtc + */ +static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in, + FORMATETC *fmt_out) +{ + TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out); + + if ( !fmt_in || !fmt_out ) return E_INVALIDARG; + + *fmt_out = *fmt_in; + return DATA_S_SAMEFORMATETC; +} + +/************************************************************************ + * snapshot_SetData + * + * The OLE Clipboard does not implement this method + */ +static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt, + STGMEDIUM *med, BOOL release) +{ + TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release); + return E_NOTIMPL; +} + +/************************************************************************ + * snapshot_EnumFormatEtc + * + */ +static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir, + IEnumFORMATETC **enum_fmt) +{ + HRESULT hr; + ole_priv_data *data = NULL; + + TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt); + + *enum_fmt = NULL; + + if ( dir != DATADIR_GET ) return E_NOTIMPL; + if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN; + + hr = get_priv_data(&data); + + if(FAILED(hr)) goto end; + + hr = enum_fmtetc_construct( data, 0, enum_fmt ); + +end: + if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE; + return hr; +} + +/************************************************************************ + * snapshot_DAdvise + * + * The OLE Clipboard does not implement this method + */ +static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt, + DWORD flags, IAdviseSink *sink, + DWORD *conn) +{ + TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn); + return E_NOTIMPL; +} + +/************************************************************************ + * snapshot_DUnadvise + * + * The OLE Clipboard does not implement this method + */ +static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn) +{ + TRACE("(%p, %d): not implemented\n", iface, conn); + return E_NOTIMPL; +} + +/************************************************************************ + * snapshot_EnumDAdvise + * + * The OLE Clipboard does not implement this method + */ +static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface, + IEnumSTATDATA** enum_advise) +{ + TRACE("(%p, %p): not implemented\n", iface, enum_advise); + return E_NOTIMPL; +} + +static const IDataObjectVtbl snapshot_vtable = +{ + snapshot_QueryInterface, + snapshot_AddRef, + snapshot_Release, + snapshot_GetData, + snapshot_GetDataHere, + snapshot_QueryGetData, + snapshot_GetCanonicalFormatEtc, + snapshot_SetData, + snapshot_EnumFormatEtc, + snapshot_DAdvise, + snapshot_DUnadvise, + snapshot_EnumDAdvise +}; + +/*---------------------------------------------------------------------* + * Internal implementation methods for the OLE clipboard + *---------------------------------------------------------------------*/ + +static snapshot *snapshot_construct(DWORD seq_no) +{ + snapshot *This; + + This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) ); + if (!This) return NULL; + + This->lpVtbl = &snapshot_vtable; + This->ref = 0; + This->seq_no = seq_no; + This->data = NULL; + + return This; +} + +/********************************************************* + * register_clipboard_formats + */ +static void register_clipboard_formats(void) +{ + static const WCHAR OwnerLink[] = {'O','w','n','e','r','L','i','n','k',0}; + static const WCHAR FileName[] = {'F','i','l','e','N','a','m','e',0}; + static const WCHAR FileNameW[] = {'F','i','l','e','N','a','m','e','W',0}; + static const WCHAR DataObject[] = {'D','a','t','a','O','b','j','e','c','t',0}; + static const WCHAR EmbeddedObject[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0}; + static const WCHAR EmbedSource[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0}; + static const WCHAR CustomLinkSource[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0}; + static const WCHAR LinkSource[] = {'L','i','n','k',' ','S','o','u','r','c','e',0}; + static const WCHAR ObjectDescriptor[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0}; + static const WCHAR LinkSourceDescriptor[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ', + 'D','e','s','c','r','i','p','t','o','r',0}; + static const WCHAR OlePrivateData[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0}; + + static const WCHAR WineMarshalledDataObject[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ', + 'D','a','t','a','O','b','j','e','c','t',0}; + + ownerlink_clipboard_format = RegisterClipboardFormatW(OwnerLink); + filename_clipboard_format = RegisterClipboardFormatW(FileName); + filenameW_clipboard_format = RegisterClipboardFormatW(FileNameW); + dataobject_clipboard_format = RegisterClipboardFormatW(DataObject); + embedded_object_clipboard_format = RegisterClipboardFormatW(EmbeddedObject); + embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSource); + custom_link_source_clipboard_format = RegisterClipboardFormatW(CustomLinkSource); + link_source_clipboard_format = RegisterClipboardFormatW(LinkSource); + object_descriptor_clipboard_format = RegisterClipboardFormatW(ObjectDescriptor); + link_source_descriptor_clipboard_format = RegisterClipboardFormatW(LinkSourceDescriptor); + ole_private_data_clipboard_format = RegisterClipboardFormatW(OlePrivateData); + + wine_marshal_clipboard_format = RegisterClipboardFormatW(WineMarshalledDataObject); +} + +/*********************************************************************** + * OLEClipbrd_Initialize() + * Initializes the OLE clipboard. + */ +void OLEClipbrd_Initialize(void) +{ + register_clipboard_formats(); + + if ( !theOleClipboard ) + { + ole_clipbrd* clipbrd; + HGLOBAL h; + + TRACE("()\n"); + + clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) ); + if (!clipbrd) return; + + clipbrd->latest_snapshot = NULL; + clipbrd->window = NULL; + clipbrd->src_data = NULL; + clipbrd->cached_enum = NULL; + + h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0); + if(!h) + { + HeapFree(GetProcessHeap(), 0, clipbrd); + return; + } + + if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data))) + { + GlobalFree(h); + HeapFree(GetProcessHeap(), 0, clipbrd); + return; + } + + theOleClipboard = clipbrd; + } +} + +/*********************************************************************** + * OLEClipbrd_UnInitialize() + * Un-Initializes the OLE clipboard + */ +void OLEClipbrd_UnInitialize(void) +{ + ole_clipbrd *clipbrd = theOleClipboard; + + TRACE("()\n"); + + if ( clipbrd ) + { + static const WCHAR ole32W[] = {'o','l','e','3','2',0}; + HINSTANCE hinst = GetModuleHandleW(ole32W); + + if ( clipbrd->window ) + { + DestroyWindow(clipbrd->window); + UnregisterClassW( clipbrd_wndclass, hinst ); + } + + IStream_Release(clipbrd->marshal_data); + HeapFree(GetProcessHeap(), 0, clipbrd); + theOleClipboard = NULL; + } +} + +/********************************************************************* + * set_clipboard_formats + * + * Enumerate all formats supported by the source and make + * those formats available using delayed rendering using SetClipboardData. + * Cache the enumeration list and make that list visibile as the + * 'Ole Private Data' format on the clipboard. + * + */ +static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data) +{ + HRESULT hr; + FORMATETC fmt; + IEnumFORMATETC *enum_fmt; + HGLOBAL priv_data_handle; + DWORD_PTR target_offset; + ole_priv_data *priv_data; + DWORD count = 0, needed = sizeof(*priv_data), idx; + + hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt); + if(FAILED(hr)) return hr; + + while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK) + { + count++; + needed += sizeof(priv_data->entries[0]); + if(fmt.ptd) + { + needed += fmt.ptd->tdSize; + CoTaskMemFree(fmt.ptd); + } + } + + /* Windows pads the list with two empty ole_priv_data_entries, one + * after the entries array and one after the target device data. + * Allocating with zero init to zero these pads. */ + + needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */ + priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed); + priv_data = GlobalLock(priv_data_handle); + + priv_data->unk1 = 0; + priv_data->size = needed; + priv_data->unk2 = 1; + priv_data->count = count; + priv_data->unk3[0] = 0; + priv_data->unk3[1] = 0; + + IEnumFORMATETC_Reset(enum_fmt); + + idx = 0; + target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */ + + while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK) + { + TRACE("%s\n", dump_fmtetc(&fmt)); + + priv_data->entries[idx].fmtetc = fmt; + if(fmt.ptd) + { + memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize); + priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset; + target_offset += fmt.ptd->tdSize; + CoTaskMemFree(fmt.ptd); + } + + priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat); + priv_data->entries[idx].unk[0] = 0; + priv_data->entries[idx].unk[1] = 0; + + if (priv_data->entries[idx].first_use) + SetClipboardData(fmt.cfFormat, NULL); + + idx++; + } + + IEnumFORMATETC_Release(enum_fmt); + + /* Cache the list and fixup any target device offsets to ptrs */ + clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed); + memcpy(clipbrd->cached_enum, priv_data, needed); + for(idx = 0; idx < clipbrd->cached_enum->count; idx++) + clipbrd->cached_enum->entries[idx].fmtetc.ptd = + td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd); + + GlobalUnlock(priv_data_handle); + SetClipboardData(ole_private_data_clipboard_format, priv_data_handle); + + return S_OK; +} + +static HWND create_clipbrd_window(void); + +/*********************************************************************** + * get_clipbrd_window + */ +static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd) +{ + if ( !clipbrd->window ) + clipbrd->window = create_clipbrd_window(); + + *wnd = clipbrd->window; + return *wnd ? S_OK : E_FAIL; +} + + +/********************************************************************** + * release_marshal_data + * + * Releases the data and sets the stream back to zero size. + */ +static inline void release_marshal_data(IStream *stm) +{ + LARGE_INTEGER pos; + ULARGE_INTEGER size; + pos.QuadPart = size.QuadPart = 0; + + IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL); + CoReleaseMarshalData(stm); + IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL); + IStream_SetSize(stm, size); +} + +/*********************************************************************** + * expose_marshalled_dataobject + * + * Sets the marshalled dataobject to the clipboard. In the flushed case + * we set a zero sized HGLOBAL to clear the old marshalled data. + */ +static HRESULT expose_marshalled_dataobject(ole_clipbrd *clipbrd, IDataObject *data) +{ + HGLOBAL h; + + if(data) + { + HGLOBAL h_stm; + GetHGlobalFromStream(clipbrd->marshal_data, &h_stm); + dup_global_mem(h_stm, GMEM_DDESHARE|GMEM_MOVEABLE, &h); + } + else /* flushed */ + h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 0); + + if(!h) return E_OUTOFMEMORY; + + SetClipboardData(wine_marshal_clipboard_format, h); + return S_OK; +} + +/*********************************************************************** + * set_src_dataobject + * + * Clears and sets the clipboard's src IDataObject. + * + * To marshal the source dataobject we do something rather different from Windows. + * We set a clipboard format which contains the marshalled data. + * Windows sets two window props one of which is an IID, the other is an endpoint number. + */ +static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data) +{ + HRESULT hr; + HWND wnd; + + if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr; + + if(clipbrd->src_data) + { + release_marshal_data(clipbrd->marshal_data); + + IDataObject_Release(clipbrd->src_data); + clipbrd->src_data = NULL; + HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum); + clipbrd->cached_enum = NULL; + } + + if(data) + { + IUnknown *unk; + + IDataObject_AddRef(data); + clipbrd->src_data = data; + + IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk); + hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk, + MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG); + IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */ + if(FAILED(hr)) return hr; + hr = set_clipboard_formats(clipbrd, data); + } + return hr; +} + +/*********************************************************************** + * clipbrd_wndproc + */ +static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + ole_clipbrd *clipbrd; + + get_ole_clipbrd(&clipbrd); + + switch (message) + { + case WM_RENDERFORMAT: + { + UINT cf = wparam; + ole_priv_data_entry *entry; + + TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf); + entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf); + + if(entry) + render_format(clipbrd->src_data, &entry->fmtetc); + + break; + } + + case WM_RENDERALLFORMATS: + { + DWORD i; + ole_priv_data_entry *entries = clipbrd->cached_enum->entries; + + TRACE("(): WM_RENDERALLFORMATS\n"); + + for(i = 0; i < clipbrd->cached_enum->count; i++) + { + if(entries[i].first_use) + render_format(clipbrd->src_data, &entries[i].fmtetc); + } + break; + } + + case WM_DESTROYCLIPBOARD: + { + TRACE("(): WM_DESTROYCLIPBOARD\n"); + + set_src_dataobject(clipbrd, NULL); + break; + } + + default: + return DefWindowProcW(hwnd, message, wparam, lparam); + } + + return 0; +} + + +/*********************************************************************** + * create_clipbrd_window + */ +static HWND create_clipbrd_window(void) +{ + WNDCLASSEXW class; + static const WCHAR ole32W[] = {'o','l','e','3','2',0}; + static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0}; + HINSTANCE hinst = GetModuleHandleW(ole32W); + + class.cbSize = sizeof(class); + class.style = 0; + class.lpfnWndProc = clipbrd_wndproc; + class.cbClsExtra = 0; + class.cbWndExtra = 0; + class.hInstance = hinst; + class.hIcon = 0; + class.hCursor = 0; + class.hbrBackground = 0; + class.lpszMenuName = NULL; + class.lpszClassName = clipbrd_wndclass; + class.hIconSm = NULL; + + RegisterClassExW(&class); + + return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, hinst, 0); +} + +/********************************************************************* + * set_dataobject_format + * + * Windows creates a 'DataObject' clipboard format that contains the + * clipboard window's HWND or NULL if the Ole clipboard has been flushed. + */ +static HRESULT set_dataobject_format(HWND hwnd) +{ + HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd)); + HWND *data; + + if(!h) return E_OUTOFMEMORY; + + data = GlobalLock(h); + *data = hwnd; + GlobalUnlock(h); + + if(!SetClipboardData(dataobject_clipboard_format, h)) + { + GlobalFree(h); + return CLIPBRD_E_CANT_SET; + } + + return S_OK; +} + +/*---------------------------------------------------------------------* + * Win32 OLE clipboard API + *---------------------------------------------------------------------*/ + +/*********************************************************************** + * OleSetClipboard [OLE32.@] + * Places a pointer to the specified data object onto the clipboard, + * making the data object accessible to the OleGetClipboard function. + * + * RETURNS + * + * S_OK IDataObject pointer placed on the clipboard + * CLIPBRD_E_CANT_OPEN OpenClipboard failed + * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed + * CLIPBRD_E_CANT_CLOSE CloseClipboard failed + * CLIPBRD_E_CANT_SET SetClipboard failed + */ + +HRESULT WINAPI OleSetClipboard(IDataObject* data) +{ + HRESULT hr; + ole_clipbrd *clipbrd; + HWND wnd; + + TRACE("(%p)\n", data); + + if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr; + + if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr; + + if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN; + + if ( !EmptyClipboard() ) + { + hr = CLIPBRD_E_CANT_EMPTY; + goto end; + } + + hr = set_src_dataobject(clipbrd, data); + if(FAILED(hr)) goto end; + + if(data) + { + hr = expose_marshalled_dataobject(clipbrd, data); + if(FAILED(hr)) goto end; + hr = set_dataobject_format(wnd); + } + +end: + + if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE; + + if ( FAILED(hr) ) + { + expose_marshalled_dataobject(clipbrd, NULL); + set_src_dataobject(clipbrd, NULL); + } + + return hr; +} + + +/*********************************************************************** + * OleGetClipboard [OLE32.@] + * Returns a pointer to our internal IDataObject which represents the conceptual + * state of the Windows clipboard. If the current clipboard already contains + * an IDataObject, our internal IDataObject will delegate to this object. + */ +HRESULT WINAPI OleGetClipboard(IDataObject **obj) +{ + HRESULT hr; + ole_clipbrd *clipbrd; + DWORD seq_no; + + TRACE("(%p)\n", obj); + + if(!obj) return E_INVALIDARG; + + if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr; + + seq_no = GetClipboardSequenceNumber(); + if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no) + clipbrd->latest_snapshot = NULL; + + if(!clipbrd->latest_snapshot) + { + clipbrd->latest_snapshot = snapshot_construct(seq_no); + if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY; + } + + *obj = (IDataObject*)&clipbrd->latest_snapshot->lpVtbl; + IDataObject_AddRef(*obj); + + return S_OK; +} + +/****************************************************************************** + * OleFlushClipboard [OLE32.@] + * Renders the data from the source IDataObject into the windows clipboard + * + * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media + * by copying the storage into global memory. Subsequently the default + * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL + * back to TYMED_IStorage. + */ +HRESULT WINAPI OleFlushClipboard(void) +{ + HRESULT hr; + ole_clipbrd *clipbrd; + HWND wnd; + + TRACE("()\n"); + + if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr; + + if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr; + + /* + * Already flushed or no source DataObject? Nothing to do. + */ + if (!clipbrd->src_data) return S_OK; + + if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN; + + SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0); + + hr = set_dataobject_format(NULL); + + expose_marshalled_dataobject(clipbrd, NULL); + set_src_dataobject(clipbrd, NULL); + + if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE; + + return hr; +} + + +/*********************************************************************** + * OleIsCurrentClipboard [OLE32.@] + */ +HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data) +{ + HRESULT hr; + ole_clipbrd *clipbrd; + TRACE("()\n"); + + if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr; + + if (data == NULL) return S_FALSE; + + return (data == clipbrd->src_data) ? S_OK : S_FALSE; } diff --git a/reactos/dll/win32/ole32/compobj.c b/reactos/dll/win32/ole32/compobj.c index 3eb0182043a..4a570099f4a 100644 --- a/reactos/dll/win32/ole32/compobj.c +++ b/reactos/dll/win32/ole32/compobj.c @@ -2922,7 +2922,10 @@ HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew) res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey); if (FAILED(res)) + { + res = S_FALSE; goto done; + } if (RegQueryValueW(hkey, NULL, szClsidNew, &len)) { res = S_FALSE; diff --git a/reactos/dll/win32/ole32/compobj_private.h b/reactos/dll/win32/ole32/compobj_private.h index 65d459f7822..a7c6dfa67ce 100644 --- a/reactos/dll/win32/ole32/compobj_private.h +++ b/reactos/dll/win32/ole32/compobj_private.h @@ -319,4 +319,16 @@ extern HRESULT WINAPI OLE32_DllUnregisterServer(void) DECLSPEC_HIDDEN; HRESULT DataAdviseHolder_OnConnect(IDataAdviseHolder *iface, IDataObject *pDelegate); void DataAdviseHolder_OnDisconnect(IDataAdviseHolder *iface); +extern UINT ownerlink_clipboard_format; +extern UINT filename_clipboard_format; +extern UINT filenameW_clipboard_format; +extern UINT dataobject_clipboard_format; +extern UINT embedded_object_clipboard_format; +extern UINT embed_source_clipboard_format; +extern UINT custom_link_source_clipboard_format; +extern UINT link_source_clipboard_format; +extern UINT object_descriptor_clipboard_format; +extern UINT link_source_descriptor_clipboard_format; +extern UINT ole_private_data_clipboard_format; + #endif /* __WINE_OLE_COMPOBJ_H */ diff --git a/reactos/dll/win32/ole32/marshal.c b/reactos/dll/win32/ole32/marshal.c index bd84cd92534..006615320fc 100644 --- a/reactos/dll/win32/ole32/marshal.c +++ b/reactos/dll/win32/ole32/marshal.c @@ -431,7 +431,7 @@ static HRESULT WINAPI Proxy_MarshalInterface( if (SUCCEEDED(hr)) { - TRACE("writing stdobjref:\n\tflags = %04lx\n\tcPublicRefs = %ld\n\toxid = %s\n\toid = %s\n\tipid = %s\n", + TRACE("writing stdobjref:\n\tflags = %04x\n\tcPublicRefs = %d\n\toxid = %s\n\toid = %s\n\tipid = %s\n", stdobjref.flags, stdobjref.cPublicRefs, wine_dbgstr_longlong(stdobjref.oxid), wine_dbgstr_longlong(stdobjref.oid), @@ -925,7 +925,7 @@ static HRESULT proxy_manager_create_ifproxy( LeaveCriticalSection(&This->cs); *iif_out = ifproxy; - TRACE("ifproxy %p created for IPID %s, interface %s with %lu public refs\n", + TRACE("ifproxy %p created for IPID %s, interface %s with %u public refs\n", ifproxy, debugstr_guid(&stdobjref->ipid), debugstr_guid(riid), stdobjref->cPublicRefs); } else @@ -1239,7 +1239,7 @@ static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, assert(apt); - TRACE("stdobjref:\n\tflags = %04lx\n\tcPublicRefs = %ld\n\toxid = %s\n\toid = %s\n\tipid = %s\n", + TRACE("stdobjref:\n\tflags = %04x\n\tcPublicRefs = %d\n\toxid = %s\n\toid = %s\n\tipid = %s\n", stdobjref->flags, stdobjref->cPublicRefs, wine_dbgstr_longlong(stdobjref->oxid), wine_dbgstr_longlong(stdobjref->oid), @@ -1546,7 +1546,7 @@ static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, /* sanity check on header */ if (objref.signature != OBJREF_SIGNATURE) { - ERR("Bad OBJREF signature 0x%08lx\n", objref.signature); + ERR("Bad OBJREF signature 0x%08x\n", objref.signature); return RPC_E_INVALID_OBJREF; } @@ -1578,7 +1578,7 @@ static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, } else { - FIXME("Invalid or unimplemented marshaling type specified: %lx\n", + FIXME("Invalid or unimplemented marshaling type specified: %x\n", objref.flags); return RPC_E_INVALID_OBJREF; } diff --git a/reactos/dll/win32/ole32/moniker.c b/reactos/dll/win32/ole32/moniker.c index 5fefca23645..9ef82b5ff59 100644 --- a/reactos/dll/win32/ole32/moniker.c +++ b/reactos/dll/win32/ole32/moniker.c @@ -340,7 +340,7 @@ RunningObjectTableImpl_AddRef(IRunningObjectTable* iface) } /*********************************************************************** - * RunningObjectTable_Initialize + * RunningObjectTable_Destroy */ static HRESULT RunningObjectTableImpl_Destroy(void) @@ -414,7 +414,7 @@ RunningObjectTableImpl_Release(IRunningObjectTable* iface) * grfFlags [in] Registration options * punkObject [in] the object being registered * pmkObjectName [in] the moniker of the object being registered - * pdwRegister [in] the value identifying the registration + * pdwRegister [out] the value identifying the registration */ static HRESULT WINAPI RunningObjectTableImpl_Register(IRunningObjectTable* iface, DWORD grfFlags, diff --git a/reactos/dll/win32/ole32/ole2impl.c b/reactos/dll/win32/ole32/ole2impl.c index da50f4a6387..f7da399e69a 100644 --- a/reactos/dll/win32/ole32/ole2impl.c +++ b/reactos/dll/win32/ole32/ole2impl.c @@ -32,6 +32,7 @@ #include "wine/debug.h" #include "ole2.h" #include "olestd.h" +#include "compobj_private.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); @@ -40,7 +41,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); /****************************************************************************** * OleQueryCreateFromData [OLE32.@] * - * Author : Abey George * Checks whether an object can become an embedded object. * the clipboard or OLE drag and drop. * Returns : S_OK - Format that supports Embedded object creation are present. @@ -48,41 +48,58 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); * S_FALSE - No acceptable format is available. */ -HRESULT WINAPI OleQueryCreateFromData(LPDATAOBJECT pSrcDataObject) +HRESULT WINAPI OleQueryCreateFromData(IDataObject *data) { - IEnumFORMATETC *pfmt; - FORMATETC fmt; - CHAR szFmtName[MAX_CLIPFORMAT_NAME]; - BOOL bFoundStatic = FALSE; + IEnumFORMATETC *enum_fmt; + FORMATETC fmt; + BOOL found_static = FALSE; + HRESULT hr; - HRESULT hr = IDataObject_EnumFormatEtc(pSrcDataObject, DATADIR_GET, &pfmt); + hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt); - if (hr == S_OK) - hr = IEnumFORMATETC_Next(pfmt, 1, &fmt, NULL); + if(FAILED(hr)) return hr; - while (hr == S_OK) - { - GetClipboardFormatNameA(fmt.cfFormat, szFmtName, MAX_CLIPFORMAT_NAME-1); + do + { + hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL); + if(hr == S_OK) + { + if(fmt.cfFormat == embedded_object_clipboard_format || + fmt.cfFormat == embed_source_clipboard_format || + fmt.cfFormat == filename_clipboard_format) + { + IEnumFORMATETC_Release(enum_fmt); + return S_OK; + } - /* first, Check for Embedded Object, Embed Source or Filename */ + if(fmt.cfFormat == CF_METAFILEPICT || + fmt.cfFormat == CF_BITMAP || + fmt.cfFormat == CF_DIB) + found_static = TRUE; + } + } while (hr == S_OK); - if (!strcmp(szFmtName, CF_EMBEDDEDOBJECT) || !strcmp(szFmtName, CF_EMBEDSOURCE) || !strcmp(szFmtName, CF_FILENAME)) - return S_OK; + IEnumFORMATETC_Release(enum_fmt); - /* Check for Metafile, Bitmap or DIB */ + return found_static ? OLE_S_STATIC : S_FALSE; +} - if (fmt.cfFormat == CF_METAFILEPICT || fmt.cfFormat == CF_BITMAP || fmt.cfFormat == CF_DIB) - bFoundStatic = TRUE; +/****************************************************************************** + * OleCreateFromDataEx [OLE32.@] + * + * Creates an embedded object from data transfer object retrieved from + * the clipboard or OLE drag and drop. + */ +HRESULT WINAPI OleCreateFromDataEx(IDataObject *data, REFIID iid, DWORD flags, + DWORD renderopt, ULONG num_fmts, DWORD *adv_flags, FORMATETC *fmts, + IAdviseSink *sink, DWORD *conns, + IOleClientSite *client_site, IStorage *stg, void **obj) +{ + FIXME("(%p, %s, %08x, %08x, %d, %p, %p, %p, %p, %p, %p, %p): stub\n", + data, debugstr_guid(iid), flags, renderopt, num_fmts, adv_flags, fmts, + sink, conns, client_site, stg, obj); - hr = IEnumFORMATETC_Next(pfmt, 1, &fmt, NULL); - } - - /* Found a static format, but no embed format */ - - if (bFoundStatic) - return OLE_S_STATIC; - - return S_FALSE; + return E_NOTIMPL; } /****************************************************************************** diff --git a/reactos/dll/win32/ole32/ole32.spec b/reactos/dll/win32/ole32/ole32.spec index 7d69bd8fecf..b9e5c4c3a79 100644 --- a/reactos/dll/win32/ole32/ole32.spec +++ b/reactos/dll/win32/ole32/ole32.spec @@ -183,7 +183,7 @@ @ stub OleCreateEmbeddingHelper @ stub OleCreateEx @ stdcall OleCreateFromData(ptr ptr long ptr ptr ptr ptr) -@ stub OleCreateFromDataEx +@ stdcall OleCreateFromDataEx(ptr ptr long long long ptr ptr ptr ptr ptr ptr ptr) @ stdcall OleCreateFromFile(ptr ptr ptr long ptr ptr ptr ptr) @ stub OleCreateFromFileEx @ stdcall OleCreateLink(ptr ptr long ptr ptr ptr ptr) diff --git a/reactos/dll/win32/ole32/rpc.c b/reactos/dll/win32/ole32/rpc.c index bcd581bb62c..132506376dc 100644 --- a/reactos/dll/win32/ole32/rpc.c +++ b/reactos/dll/win32/ole32/rpc.c @@ -1175,7 +1175,7 @@ static HRESULT unmarshal_ORPC_EXTENT_ARRAY(RPC_MESSAGE *msg, const char *end, /* arbitrary limit for security (don't know what native does) */ if (extensions->size > 256) { - ERR("too many extensions: %ld\n", extensions->size); + ERR("too many extensions: %d\n", extensions->size); return RPC_S_INVALID_BOUND; } @@ -1242,7 +1242,7 @@ static HRESULT unmarshal_ORPCTHIS(RPC_MESSAGE *msg, ORPCTHIS *orpcthis, if (orpcthis->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4)) { - ERR("invalid flags 0x%lx\n", orpcthis->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4)); + ERR("invalid flags 0x%x\n", orpcthis->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4)); return RPC_E_INVALID_HEADER; } @@ -1285,7 +1285,7 @@ static HRESULT unmarshal_ORPCTHAT(RPC_MESSAGE *msg, ORPCTHAT *orpcthat, if (orpcthat->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4)) { - ERR("invalid flags 0x%lx\n", orpcthat->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4)); + ERR("invalid flags 0x%x\n", orpcthat->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4)); return RPC_E_INVALID_HEADER; } diff --git a/reactos/dll/win32/ole32/stg_prop.c b/reactos/dll/win32/ole32/stg_prop.c index fd390397457..381e0799e24 100644 --- a/reactos/dll/win32/ole32/stg_prop.c +++ b/reactos/dll/win32/ole32/stg_prop.c @@ -967,7 +967,7 @@ static void PropertyStorage_PropertyDestroy(void *k, void *d, void *extra) #ifdef WORDS_BIGENDIAN /* Swaps each character in str to or from little endian; assumes the conversion - * is symmetric, that is, that le16toh is equivalent to htole16. + * is symmetric, that is, that lendian16toh is equivalent to htole16. */ static void PropertyStorage_ByteSwapString(LPWSTR str, size_t len) { @@ -1063,7 +1063,7 @@ static HRESULT PropertyStorage_ReadProperty(PropertyStorage_impl *This, case VT_INT: case VT_I4: StorageUtl_ReadDWord(data, 0, (DWORD*)&prop->u.lVal); - TRACE("Read long %ld\n", prop->u.lVal); + TRACE("Read long %d\n", prop->u.lVal); break; case VT_UINT: case VT_UI4: diff --git a/reactos/dll/win32/ole32/storage32.c b/reactos/dll/win32/ole32/storage32.c index 9f3148b0684..90328f056a5 100644 --- a/reactos/dll/win32/ole32/storage32.c +++ b/reactos/dll/win32/ole32/storage32.c @@ -912,7 +912,7 @@ static HRESULT WINAPI StorageBaseImpl_RenameElement( * Invoke Destroy to get rid of the ole property and automatically redo * the linking of its previous and next members... */ - IStorage_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName); + IStorage_DestroyElement(iface, pwcsOldName); } else @@ -3472,7 +3472,7 @@ static BOOL StorageImpl_ReadDWordFromBigBlock( ulOffset.u.LowPart += offset; StorageImpl_ReadAt(This, ulOffset, &tmp, sizeof(DWORD), &read); - *value = le32toh(tmp); + *value = lendian32toh(tmp); return (read == sizeof(DWORD)); } @@ -4250,7 +4250,7 @@ void StorageUtl_ReadWord(const BYTE* buffer, ULONG offset, WORD* value) WORD tmp; memcpy(&tmp, buffer+offset, sizeof(WORD)); - *value = le16toh(tmp); + *value = lendian16toh(tmp); } void StorageUtl_WriteWord(BYTE* buffer, ULONG offset, WORD value) @@ -4264,7 +4264,7 @@ void StorageUtl_ReadDWord(const BYTE* buffer, ULONG offset, DWORD* value) DWORD tmp; memcpy(&tmp, buffer+offset, sizeof(DWORD)); - *value = le32toh(tmp); + *value = lendian32toh(tmp); } void StorageUtl_WriteDWord(BYTE* buffer, ULONG offset, DWORD value) diff --git a/reactos/dll/win32/ole32/storage32.h b/reactos/dll/win32/ole32/storage32.h index 1e40b3af906..1e42afb69a8 100644 --- a/reactos/dll/win32/ole32/storage32.h +++ b/reactos/dll/win32/ole32/storage32.h @@ -376,15 +376,15 @@ StgStreamImpl* StgStreamImpl_Construct( #define htole32(x) RtlUlongByteSwap(x) #define htole16(x) RtlUshortByteSwap(x) -#define le32toh(x) RtlUlongByteSwap(x) -#define le16toh(x) RtlUshortByteSwap(x) +#define lendian32toh(x) RtlUlongByteSwap(x) +#define lendian16toh(x) RtlUshortByteSwap(x) #else #define htole32(x) (x) #define htole16(x) (x) -#define le32toh(x) (x) -#define le16toh(x) (x) +#define lendian32toh(x) (x) +#define lendian16toh(x) (x) #endif diff --git a/reactos/dll/win32/ole32/stubmanager.c b/reactos/dll/win32/ole32/stubmanager.c index 29abcb83cb2..0aa80fa15a8 100644 --- a/reactos/dll/win32/ole32/stubmanager.c +++ b/reactos/dll/win32/ole32/stubmanager.c @@ -702,7 +702,7 @@ static HRESULT WINAPI RemUnknown_RemAddRef(IRemUnknown *iface, stub_manager_ext_addref(stubmgr, InterfaceRefs[i].cPublicRefs, FALSE); if (InterfaceRefs[i].cPrivateRefs) - FIXME("Adding %ld refs securely not implemented\n", InterfaceRefs[i].cPrivateRefs); + FIXME("Adding %d refs securely not implemented\n", InterfaceRefs[i].cPrivateRefs); stub_manager_int_release(stubmgr); apartment_release(apt); @@ -735,7 +735,7 @@ static HRESULT WINAPI RemUnknown_RemRelease(IRemUnknown *iface, stub_manager_ext_release(stubmgr, InterfaceRefs[i].cPublicRefs, FALSE, TRUE); if (InterfaceRefs[i].cPrivateRefs) - FIXME("Releasing %ld refs securely not implemented\n", InterfaceRefs[i].cPrivateRefs); + FIXME("Releasing %d refs securely not implemented\n", InterfaceRefs[i].cPrivateRefs); stub_manager_int_release(stubmgr); apartment_release(apt); diff --git a/reactos/dll/win32/ole32/usrmarshal.c b/reactos/dll/win32/ole32/usrmarshal.c index afe456bb597..8159a60d4d3 100644 --- a/reactos/dll/win32/ole32/usrmarshal.c +++ b/reactos/dll/win32/ole32/usrmarshal.c @@ -2414,7 +2414,7 @@ HRESULT CALLBACK IStorage_OpenStream_Proxy( HRESULT __RPC_STUB IStorage_OpenStream_Stub( IStorage* This, LPCOLESTR pwcsName, - unsigned long cbReserved1, + ULONG cbReserved1, byte *reserved1, DWORD grfMode, DWORD reserved2, @@ -2438,7 +2438,7 @@ HRESULT CALLBACK IStorage_EnumElements_Proxy( HRESULT __RPC_STUB IStorage_EnumElements_Stub( IStorage* This, DWORD reserved1, - unsigned long cbReserved2, + ULONG cbReserved2, byte *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum) diff --git a/reactos/dll/win32/ole32/version16.rc b/reactos/dll/win32/ole32/version16.rc deleted file mode 100644 index 3cabba9c86f..00000000000 --- a/reactos/dll/win32/ole32/version16.rc +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2007 Stefan Leichter - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define WINE_FILEVERSION 2,10,3050,1 -#define WINE_FILEVERSION_STR "2.10.3050.1" -#define WINE_FILEDESCRIPTION_STR "Wine OLE dll" -#define WINE_FILENAME_STR "OLE2NLS.DLL" - -#include "wine/wine_common_ver.rc" diff --git a/reactos/dll/win32/oleaut32/olepicture.c b/reactos/dll/win32/oleaut32/olepicture.c index 03119f29c99..adaad97def6 100644 --- a/reactos/dll/win32/oleaut32/olepicture.c +++ b/reactos/dll/win32/oleaut32/olepicture.c @@ -81,8 +81,7 @@ #include "urlmon.h" #include "wine/debug.h" #include "wine/unicode.h" - -#include "wine/wingdi16.h" +#include "wine/library.h" #include "ungif.h" diff --git a/reactos/dll/win32/oleaut32/typelib.c b/reactos/dll/win32/oleaut32/typelib.c index d1a719b12da..a0af8473c4e 100644 --- a/reactos/dll/win32/oleaut32/typelib.c +++ b/reactos/dll/win32/oleaut32/typelib.c @@ -66,7 +66,6 @@ #include "winuser.h" #include "lzexpand.h" -#include "wine/winbase16.h" #include "wine/unicode.h" #include "objbase.h" #include "typelib.h" @@ -77,6 +76,26 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); WINE_DECLARE_DEBUG_CHANNEL(typelib); +typedef struct +{ + WORD offset; + WORD length; + WORD flags; + WORD id; + WORD handle; + WORD usage; +} NE_NAMEINFO; + +typedef struct +{ + WORD type_id; /* Type identifier */ + WORD count; /* Number of resources of this type */ + DWORD resloader; /* SetResourceHandler() */ + /* + * Name info array. + */ +} NE_TYPEINFO; + static HRESULT typedescvt_to_variantvt(ITypeInfo *tinfo, const TYPEDESC *tdesc, VARTYPE *vt); static HRESULT TLB_AllocAndInitVarDesc(const VARDESC *src, VARDESC **dest_ptr); @@ -149,13 +168,13 @@ static void FromLEDWords(void *p_Val, int p_iSize) /* * Find a typelib key which matches a requested maj.min version. */ -static BOOL find_typelib_key( REFGUID guid, WORD wMaj, WORD *wMin ) +static BOOL find_typelib_key( REFGUID guid, WORD *wMaj, WORD *wMin ) { static const WCHAR typelibW[] = {'T','y','p','e','l','i','b','\\',0}; WCHAR buffer[60]; char key_name[16]; DWORD len, i; - INT best_min = -1; + INT best_maj = -1, best_min = -1; HKEY hkey; memcpy( buffer, typelibW, sizeof(typelibW) ); @@ -174,20 +193,40 @@ static BOOL find_typelib_key( REFGUID guid, WORD wMaj, WORD *wMin ) { TRACE("found %s: %x.%x\n", debugstr_w(buffer), v_maj, v_min); - if (wMaj == v_maj) + if (*wMaj == 0xffff && *wMin == 0xffff) { + if (v_maj > best_maj) best_maj = v_maj; + if (v_min > best_min) best_min = v_min; + } + else if (*wMaj == v_maj) + { + best_maj = v_maj; + if (*wMin == v_min) { best_min = v_min; break; /* exact match */ } - if (v_min > best_min) best_min = v_min; + if (*wMin != 0xffff && v_min > best_min) best_min = v_min; } } len = sizeof(key_name); } RegCloseKey( hkey ); - if (best_min >= 0) + + TRACE("found best_maj %d, best_min %d\n", best_maj, best_min); + + if (*wMaj == 0xffff && *wMin == 0xffff) + { + if (best_maj >= 0 && best_min >= 0) + { + *wMaj = best_maj; + *wMin = best_min; + return TRUE; + } + } + + if (*wMaj == best_maj && best_min >= 0) { *wMin = best_min; return TRUE; @@ -276,7 +315,7 @@ HRESULT WINAPI QueryPathOfRegTypeLib( TRACE_(typelib)("(%s, %x.%x, 0x%x, %p)\n", debugstr_guid(guid), wMaj, wMin, lcid, path); - if (!find_typelib_key( guid, wMaj, &wMin )) return TYPE_E_LIBNOTREGISTERED; + if (!find_typelib_key( guid, &wMaj, &wMin )) return TYPE_E_LIBNOTREGISTERED; get_typelib_key( guid, wMaj, wMin, buffer ); res = RegOpenKeyExW( HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hkey ); diff --git a/reactos/dll/win32/oleaut32/typelib.h b/reactos/dll/win32/oleaut32/typelib.h index 821981f1cdf..1fe8ecf7619 100644 --- a/reactos/dll/win32/oleaut32/typelib.h +++ b/reactos/dll/win32/oleaut32/typelib.h @@ -26,7 +26,6 @@ #include "windef.h" #include "winbase.h" #include "oleauto.h" -#include "wine/windef16.h" #define HELPDLLFLAG (0x0100) #define DO_NOT_SEEK (-1) diff --git a/reactos/dll/win32/oleaut32/usrmarshal.c b/reactos/dll/win32/oleaut32/usrmarshal.c index a119c282701..1e20c3cd322 100644 --- a/reactos/dll/win32/oleaut32/usrmarshal.c +++ b/reactos/dll/win32/oleaut32/usrmarshal.c @@ -755,7 +755,7 @@ ULONG WINAPI LPSAFEARRAY_UserSize(ULONG *pFlags, ULONG StartingSize, LPSAFEARRAY TRACE("("); dump_user_flags(pFlags); TRACE(", %d, %p\n", StartingSize, *ppsa); ALIGN_LENGTH(size, 3); - size += sizeof(ULONG_PTR); + size += sizeof(ULONG); if (*ppsa) { SAFEARRAY *psa = *ppsa; @@ -770,7 +770,7 @@ ULONG WINAPI LPSAFEARRAY_UserSize(ULONG *pFlags, ULONG StartingSize, LPSAFEARRAY size += sizeof(ULONG); size += sizeof(ULONG); - size += sizeof(ULONG_PTR); + size += sizeof(ULONG); if (sftype == SF_HAVEIID) size += sizeof(IID); @@ -843,8 +843,8 @@ unsigned char * WINAPI LPSAFEARRAY_UserMarshal(ULONG *pFlags, unsigned char *Buf TRACE("("); dump_user_flags(pFlags); TRACE(", %p, &%p\n", Buffer, *ppsa); ALIGN_POINTER(Buffer, 3); - *(ULONG_PTR *)Buffer = *ppsa ? TRUE : FALSE; - Buffer += sizeof(ULONG_PTR); + *(ULONG *)Buffer = *ppsa ? 0x1 : 0x0; + Buffer += sizeof(ULONG); if (*ppsa) { VARTYPE vt; @@ -874,8 +874,8 @@ unsigned char * WINAPI LPSAFEARRAY_UserMarshal(ULONG *pFlags, unsigned char *Buf *(ULONG *)Buffer = ulCellCount; Buffer += sizeof(ULONG); - *(ULONG_PTR *)Buffer = (ULONG_PTR)psa->pvData; - Buffer += sizeof(ULONG_PTR); + *(ULONG *)Buffer = psa->pvData ? 0x2 : 0x0; + Buffer += sizeof(ULONG); if (sftype == SF_HAVEIID) { SafeArrayGetIID(psa, &guid); @@ -958,7 +958,7 @@ unsigned char * WINAPI LPSAFEARRAY_UserMarshal(ULONG *pFlags, unsigned char *Buf unsigned char * WINAPI LPSAFEARRAY_UserUnmarshal(ULONG *pFlags, unsigned char *Buffer, LPSAFEARRAY *ppsa) { - ULONG_PTR ptr; + ULONG ptr; wireSAFEARRAY wiresa; ULONG cDims; HRESULT hr; @@ -971,8 +971,8 @@ unsigned char * WINAPI LPSAFEARRAY_UserUnmarshal(ULONG *pFlags, unsigned char *B TRACE("("); dump_user_flags(pFlags); TRACE(", %p, %p\n", Buffer, ppsa); ALIGN_POINTER(Buffer, 3); - ptr = *(ULONG_PTR *)Buffer; - Buffer += sizeof(ULONG_PTR); + ptr = *(ULONG *)Buffer; + Buffer += sizeof(ULONG); if (!ptr) { @@ -1001,8 +1001,8 @@ unsigned char * WINAPI LPSAFEARRAY_UserUnmarshal(ULONG *pFlags, unsigned char *B cell_count = *(ULONG *)Buffer; Buffer += sizeof(ULONG); - ptr = *(ULONG_PTR *)Buffer; - Buffer += sizeof(ULONG_PTR); + ptr = *(ULONG *)Buffer; + Buffer += sizeof(ULONG); if (sftype == SF_HAVEIID) { memcpy(&guid, Buffer, sizeof(guid)); @@ -2041,7 +2041,8 @@ HRESULT CALLBACK IPropertyBag_Read_Proxy( FIXME("Safearray support not yet implemented.\n"); return E_NOTIMPL; default: - break; + FIXME("Unknown V_VT %d - support not yet implemented.\n", V_VT(pVar)); + return E_NOTIMPL; } return IPropertyBag_RemoteRead_Proxy(This, pszPropName, pVar, pErrorLog, diff --git a/reactos/dll/win32/oleaut32/variant.c b/reactos/dll/win32/oleaut32/variant.c index 26a19bbbe85..909cf8a830c 100644 --- a/reactos/dll/win32/oleaut32/variant.c +++ b/reactos/dll/win32/oleaut32/variant.c @@ -40,6 +40,7 @@ #include "wine/unicode.h" #include "winerror.h" #include "variant.h" +#include "resource.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(variant); @@ -2467,8 +2468,8 @@ HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out) { VARTYPE leftvt,rightvt,resultvt; HRESULT hres; - static const WCHAR str_true[] = {'T','r','u','e','\0'}; - static const WCHAR str_false[] = {'F','a','l','s','e','\0'}; + static WCHAR str_true[32]; + static WCHAR str_false[32]; static const WCHAR sz_empty[] = {'\0'}; leftvt = V_VT(left); rightvt = V_VT(right); @@ -2476,6 +2477,11 @@ HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out) TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left), debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), out); + if (!str_true[0]) { + VARIANT_GetLocalisedText(LOCALE_USER_DEFAULT, IDS_FALSE, str_false); + VARIANT_GetLocalisedText(LOCALE_USER_DEFAULT, IDS_TRUE, str_true); + } + /* when both left and right are NULL the result is NULL */ if (leftvt == VT_NULL && rightvt == VT_NULL) { @@ -2558,7 +2564,7 @@ HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out) { if (leftvt == VT_BOOL) { - /* Bools are handled as True/False strings instead of 0/-1 as in MSDN */ + /* Bools are handled as localized True/False strings instead of 0/-1 as in MSDN */ V_VT(&bstrvar_left) = VT_BSTR; if (V_BOOL(left) == TRUE) V_BSTR(&bstrvar_left) = SysAllocString(str_true); @@ -2598,7 +2604,7 @@ HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out) { if (rightvt == VT_BOOL) { - /* Bools are handled as True/False strings instead of 0/-1 as in MSDN */ + /* Bools are handled as localized True/False strings instead of 0/-1 as in MSDN */ V_VT(&bstrvar_right) = VT_BSTR; if (V_BOOL(right) == TRUE) V_BSTR(&bstrvar_right) = SysAllocString(str_true); diff --git a/reactos/dll/win32/oleaut32/variant.h b/reactos/dll/win32/oleaut32/variant.h index 41f8a9af6ee..c881b24d60f 100644 --- a/reactos/dll/win32/oleaut32/variant.h +++ b/reactos/dll/win32/oleaut32/variant.h @@ -123,3 +123,6 @@ typedef struct tagVARIANT_NUMBER_CHARS WCHAR cCurrencyDecimalPoint; WCHAR cCurrencyDigitSeparator; } VARIANT_NUMBER_CHARS; + + +BOOL VARIANT_GetLocalisedText(LANGID, DWORD, WCHAR *); diff --git a/reactos/dll/win32/oleaut32/vartype.c b/reactos/dll/win32/oleaut32/vartype.c index 6d972a2d2b7..2d5ae7d8ea4 100644 --- a/reactos/dll/win32/oleaut32/vartype.c +++ b/reactos/dll/win32/oleaut32/vartype.c @@ -5961,7 +5961,13 @@ HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut) return S_OK; } -static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest) +/************************************************************************ + * VARIANT_GetLocalisedText [internal] + * + * Get a localized string from the resources + * + */ +BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest) { HRSRC hrsrc; @@ -6957,9 +6963,8 @@ HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFl if (!pbstrLeft || !*pbstrLeft) { - if (!pbstrRight || !*pbstrRight) - return VARCMP_EQ; - return VARCMP_LT; + if (pbstrRight && *pbstrRight) + return VARCMP_LT; } else if (!pbstrRight || !*pbstrRight) return VARCMP_GT; @@ -6981,8 +6986,17 @@ HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFl } else { - hres = CompareStringW(lcid, dwFlags, pbstrLeft, SysStringLen(pbstrLeft), - pbstrRight, SysStringLen(pbstrRight)) - 1; + unsigned int lenLeft = SysStringLen(pbstrLeft); + unsigned int lenRight = SysStringLen(pbstrRight); + + if (lenLeft == 0 || lenRight == 0) + { + if (lenLeft == 0 && lenRight == 0) return VARCMP_EQ; + return lenLeft < lenRight ? VARCMP_LT : VARCMP_GT; + } + + hres = CompareStringW(lcid, dwFlags, pbstrLeft, lenLeft, + pbstrRight, lenRight) - 1; TRACE("%d\n", hres); return hres; } diff --git a/reactos/include/psdk/objidl.idl b/reactos/include/psdk/objidl.idl index b3dcf654979..fb34c20f2e4 100644 --- a/reactos/include/psdk/objidl.idl +++ b/reactos/include/psdk/objidl.idl @@ -907,7 +907,7 @@ interface IStorage : IUnknown [call_as(OpenStream)] HRESULT RemoteOpenStream( [in] LPCOLESTR pwcsName, - [in] unsigned long cbReserved1, + [in] ULONG cbReserved1, [in, unique, size_is(cbReserved1)] byte *reserved1, [in] DWORD grfMode, [in] DWORD reserved2, @@ -955,7 +955,7 @@ interface IStorage : IUnknown [call_as(EnumElements)] HRESULT RemoteEnumElements( [in] DWORD reserved1, - [in] unsigned long cbReserved2, + [in] ULONG cbReserved2, [in, unique, size_is(cbReserved2)] byte *reserved2, [in] DWORD reserved3, [out] IEnumSTATSTG **ppenum);