From 9df4541c5c07e69564595ccb73ab83b02246a4e6 Mon Sep 17 00:00:00 2001 From: Zhang Zhaolong Date: Wed, 5 Mar 2014 16:00:30 +0800 Subject: [PATCH] clipboard: wfreerdp: implement COM objects for file clipping. --- client/Windows/wf_cliprdr_DataObject.c | 109 +++++++++++++++++++++++++++++- client/Windows/wf_cliprdr_DataObject.h | 5 +- client/Windows/wf_cliprdr_EnumFORMATETC.c | 3 - client/Windows/wf_cliprdr_EnumFORMATETC.h | 7 +- client/Windows/wf_cliprdr_Stream.c | 38 +++++++++-- client/Windows/wf_cliprdr_Stream.h | 3 + 6 files changed, 151 insertions(+), 14 deletions(-) diff --git a/client/Windows/wf_cliprdr_DataObject.c b/client/Windows/wf_cliprdr_DataObject.c index abfa60b..7dafbb2 100644 --- a/client/Windows/wf_cliprdr_DataObject.c +++ b/client/Windows/wf_cliprdr_DataObject.c @@ -83,7 +83,9 @@ ULONG STDMETHODCALLTYPE CliprdrDataObject_Release(IDataObject *This) HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData(IDataObject *This, FORMATETC *pFormatEtc, STGMEDIUM *pMedium) { CliprdrDataObject *instance = (CliprdrDataObject *)This; + cliprdrContext *cliprdr = (cliprdrContext *)instance->m_pData; int idx; + int i; if (pFormatEtc == NULL || pMedium == NULL) { @@ -95,7 +97,65 @@ HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData(IDataObject *This, FORMATETC return DV_E_FORMATETC; } - return E_NOTIMPL; + pMedium->tymed = instance->m_pFormatEtc[idx].tymed; + pMedium->pUnkForRelease = 0; + + if (instance->m_pFormatEtc[idx].cfFormat == cliprdr->ID_FILEDESCRIPTORW) + { + if (cliprdr_send_data_request(cliprdr, instance->m_pFormatEtc[idx].cfFormat) != 0) + return E_UNEXPECTED; + + pMedium->hGlobal = cliprdr->hmem; /* points to a FILEGROUPDESCRIPTOR structure */ + + /* GlobalLock returns a pointer to the first byte of the memory block, + * in which is a FILEGROUPDESCRIPTOR structure, whose first UINT member + * is the number of FILEDESCRIPTOR's */ + instance->m_nStreams = *(PUINT)GlobalLock(cliprdr->hmem); + GlobalUnlock(cliprdr->hmem); + + if (instance->m_nStreams > 0) + { + if (!instance->m_pStream) + { + instance->m_pStream = (LPSTREAM *)calloc(instance->m_nStreams, sizeof(LPSTREAM)); + if (instance->m_pStream) + for(i = 0; i < instance->m_nStreams; i++) + instance->m_pStream[i] = (IStream *)CliprdrStream_New(i, cliprdr); + } + } + + if (!instance->m_pStream) + { + cliprdr->hmem = GlobalFree(cliprdr->hmem); + pMedium->hGlobal = cliprdr->hmem; + return E_OUTOFMEMORY; + } + } + else if (instance->m_pFormatEtc[idx].cfFormat == cliprdr->ID_FILECONTENTS) + { + if (pFormatEtc->lindex < instance->m_nStreams) + { + pMedium->pstm = instance->m_pStream[pFormatEtc->lindex]; + IDataObject_AddRef(instance->m_pStream[pFormatEtc->lindex]); + } + else + { + return E_INVALIDARG; + } + } + else if (instance->m_pFormatEtc[idx].cfFormat == cliprdr->ID_PREFERREDDROPEFFECT) + { + if (cliprdr_send_data_request(cliprdr, instance->m_pFormatEtc[idx].cfFormat) != 0) + return E_UNEXPECTED; + + pMedium->hGlobal = cliprdr->hmem; + } + else + { + return E_UNEXPECTED; + } + + return S_OK; } HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetDataHere(IDataObject *This, FORMATETC *pformatetc, STGMEDIUM *pmedium) @@ -252,3 +312,50 @@ void CliprdrDataObject_Delete(CliprdrDataObject *instance) free(instance); } } + + +BOOL wf_create_file_obj(cliprdrContext *cliprdr, IDataObject **ppDataObject) +{ + FORMATETC fmtetc[3]; + STGMEDIUM stgmeds[3]; + + if(!ppDataObject) + return FALSE; + + fmtetc[0].cfFormat = RegisterClipboardFormatW(CFSTR_FILEDESCRIPTORW); + fmtetc[0].dwAspect = DVASPECT_CONTENT; + fmtetc[0].lindex = 0; + fmtetc[0].ptd = NULL; + fmtetc[0].tymed = TYMED_HGLOBAL; + stgmeds[0].tymed = TYMED_HGLOBAL; + stgmeds[0].hGlobal = NULL; + stgmeds[0].pUnkForRelease = NULL; + + fmtetc[1].cfFormat = RegisterClipboardFormatW(CFSTR_FILECONTENTS); + fmtetc[1].dwAspect = DVASPECT_CONTENT; + fmtetc[1].lindex = 0; + fmtetc[1].ptd = NULL; + fmtetc[1].tymed = TYMED_ISTREAM; + stgmeds[1].tymed = TYMED_ISTREAM; + stgmeds[1].pstm = NULL; + stgmeds[1].pUnkForRelease = NULL; + + fmtetc[2].cfFormat = RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECT); + fmtetc[2].dwAspect = DVASPECT_CONTENT; + fmtetc[2].lindex = 0; + fmtetc[2].ptd = NULL; + fmtetc[2].tymed = TYMED_HGLOBAL; + stgmeds[2].tymed = TYMED_HGLOBAL; + stgmeds[2].hGlobal = NULL; + stgmeds[2].pUnkForRelease = NULL; + + *ppDataObject = (IDataObject *)CliprdrDataObject_New(fmtetc, stgmeds, 3, cliprdr); + + return (*ppDataObject) ? TRUE : FALSE; +} + +void wf_destroy_file_obj(IDataObject *instance) +{ + if(instance) + IDataObject_Release(instance); +} diff --git a/client/Windows/wf_cliprdr_DataObject.h b/client/Windows/wf_cliprdr_DataObject.h index 334b58b..e67869e 100644 --- a/client/Windows/wf_cliprdr_DataObject.h +++ b/client/Windows/wf_cliprdr_DataObject.h @@ -20,6 +20,9 @@ #ifndef __WF_CLIPRDR_DATAOBJECT_H__ #define __WF_CLIPRDR_DATAOBJECT_H__ +#define CINTERFACE +#define COBJMACROS + #include #include #include @@ -32,7 +35,7 @@ typedef struct _CliprdrDataObject { FORMATETC *m_pFormatEtc; STGMEDIUM *m_pStgMedium; LONG m_nNumFormats; - UINT m_nStreams; + LONG m_nStreams; IStream **m_pStream; void *m_pData; }CliprdrDataObject; diff --git a/client/Windows/wf_cliprdr_EnumFORMATETC.c b/client/Windows/wf_cliprdr_EnumFORMATETC.c index eb6cb8b..48a3bfb 100644 --- a/client/Windows/wf_cliprdr_EnumFORMATETC.c +++ b/client/Windows/wf_cliprdr_EnumFORMATETC.c @@ -17,10 +17,7 @@ * limitations under the License. */ -#include -#include #include - #include "wf_cliprdr_EnumFORMATETC.h" static void cliprdr_format_deep_copy(FORMATETC *dest, FORMATETC *source) diff --git a/client/Windows/wf_cliprdr_EnumFORMATETC.h b/client/Windows/wf_cliprdr_EnumFORMATETC.h index 88e38fc..efa9148 100644 --- a/client/Windows/wf_cliprdr_EnumFORMATETC.h +++ b/client/Windows/wf_cliprdr_EnumFORMATETC.h @@ -20,6 +20,9 @@ #ifndef __WF_CLIPRDR_ENUMFORMATETC_H__ #define __WF_CLIPRDR_ENUMFORMATETC_H__ +#define CINTERFACE +#define COBJMACROS + #include #include @@ -28,8 +31,8 @@ typedef struct _CliprdrEnumFORMATETC { // private LONG m_lRefCount; - ULONG m_nIndex; - ULONG m_nNumFormats; + LONG m_nIndex; + LONG m_nNumFormats; FORMATETC *m_pFormatEtc; } CliprdrEnumFORMATETC; diff --git a/client/Windows/wf_cliprdr_Stream.c b/client/Windows/wf_cliprdr_Stream.c index 69db01b..308ed36 100644 --- a/client/Windows/wf_cliprdr_Stream.c +++ b/client/Windows/wf_cliprdr_Stream.c @@ -62,23 +62,42 @@ ULONG STDMETHODCALLTYPE CliprdrStream_Release(IStream * This) } } -#define FILECONTENTS_SIZE 0x1 -#define FILECONTENTS_RANGE 0x2 +#define FILECONTENTS_SIZE 0x00000001 +#define FILECONTENTS_RANGE 0x00000002 HRESULT STDMETHODCALLTYPE CliprdrStream_Read(IStream *This, void *pv, ULONG cb, ULONG *pcbRead) { CliprdrStream *instance = (CliprdrStream *)This; + cliprdrContext *cliprdr = (cliprdrContext *)instance->m_pData; + int ret; if (pv == NULL || pcbRead == NULL) return E_INVALIDARG; + *pcbRead = 0; if (instance->m_lOffset.QuadPart >= instance->m_lSize.QuadPart) - { - *pcbRead = 0; return S_FALSE; + + ret = cliprdr_send_request_filecontents(cliprdr, (void *)This, + instance->m_lIndex, FILECONTENTS_RANGE, + instance->m_lOffset.HighPart, instance->m_lOffset.LowPart, + cb); + if (ret < 0) + return S_FALSE; + + if (cliprdr->req_fdata) + { + memcpy(pv, cliprdr->req_fdata, cliprdr->req_fsize); + free(cliprdr->req_fdata); } - return E_NOTIMPL; + *pcbRead = cliprdr->req_fsize; + instance->m_lOffset.QuadPart += cliprdr->req_fsize; + + if (cliprdr->req_fsize < cb) + return S_FALSE; + + return S_OK; } HRESULT STDMETHODCALLTYPE CliprdrStream_Write(IStream *This, const void *pv, ULONG cb, ULONG *pcbWritten) @@ -91,7 +110,7 @@ HRESULT STDMETHODCALLTYPE CliprdrStream_Write(IStream *This, const void *pv, ULO HRESULT STDMETHODCALLTYPE CliprdrStream_Seek(IStream *This, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) { CliprdrStream *instance = (CliprdrStream *)This; - LONGLONG newoffset; + ULONGLONG newoffset; newoffset = instance->m_lOffset.QuadPart; @@ -203,6 +222,7 @@ HRESULT STDMETHODCALLTYPE CliprdrStream_Clone(IStream *This, IStream **ppstm) CliprdrStream *CliprdrStream_New(LONG index, void *pData) { + cliprdrContext *cliprdr = (cliprdrContext *)pData; CliprdrStream *instance; IStream *iStream; @@ -234,7 +254,11 @@ CliprdrStream *CliprdrStream_New(LONG index, void *pData) instance->m_lIndex = index; instance->m_pData = pData; instance->m_lOffset.QuadPart = 0; - instance->m_lSize.QuadPart = -1; + + /* get content size of this stream */ + cliprdr_send_request_filecontents(cliprdr, (void *)instance, instance->m_lIndex, FILECONTENTS_SIZE, 0, 0, 8); + instance->m_lSize.QuadPart = *(LONGLONG *)cliprdr->req_fdata; + free(cliprdr->req_fdata); } else { diff --git a/client/Windows/wf_cliprdr_Stream.h b/client/Windows/wf_cliprdr_Stream.h index f1fe582..d1bc6ec 100644 --- a/client/Windows/wf_cliprdr_Stream.h +++ b/client/Windows/wf_cliprdr_Stream.h @@ -20,6 +20,9 @@ #ifndef __WF_CLIPRDR_STREAM_H__ #define __WF_CLIPRDR_STREAM_H__ +#define CINTERFACE +#define COBJMACROS + #include #include -- 2.7.4