362 lines
9.9 KiB
C
362 lines
9.9 KiB
C
/**
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
* Implementation of the IDataObject COM interface
|
|
*
|
|
* Copyright 2014 Zhang Zhaolong <zhangzl2013@126.com>
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "wf_cliprdr.h"
|
|
#include "wf_cliprdr_Stream.h"
|
|
#include "wf_cliprdr_DataObject.h"
|
|
#include "wf_cliprdr_EnumFORMATETC.h"
|
|
|
|
static int cliprdr_lookup_format(CliprdrDataObject *instance, FORMATETC *pFormatEtc)
|
|
{
|
|
int i;
|
|
for (i = 0; i < instance->m_nNumFormats; i++)
|
|
{
|
|
if((pFormatEtc->tymed & instance->m_pFormatEtc[i].tymed) &&
|
|
pFormatEtc->cfFormat == instance->m_pFormatEtc[i].cfFormat &&
|
|
pFormatEtc->dwAspect == instance->m_pFormatEtc[i].dwAspect)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CliprdrDataObject_QueryInterface(IDataObject *This, REFIID riid, void **ppvObject)
|
|
{
|
|
CliprdrDataObject *instance = (CliprdrDataObject *)This;
|
|
|
|
if (IsEqualIID(riid, &IID_IDataObject) || IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
IDataObject_AddRef(This);
|
|
*ppvObject = This;
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
*ppvObject = 0;
|
|
return E_NOINTERFACE;
|
|
}
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE CliprdrDataObject_AddRef(IDataObject *This)
|
|
{
|
|
CliprdrDataObject *instance = (CliprdrDataObject *)This;
|
|
|
|
return InterlockedIncrement(&instance->m_lRefCount);
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE CliprdrDataObject_Release(IDataObject *This)
|
|
{
|
|
CliprdrDataObject *instance = (CliprdrDataObject *)This;
|
|
LONG count;
|
|
|
|
count = InterlockedDecrement(&instance->m_lRefCount);
|
|
|
|
if(count == 0)
|
|
{
|
|
CliprdrDataObject_Delete(instance);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return count;
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if((idx = cliprdr_lookup_format(instance, pFormatEtc)) == -1)
|
|
{
|
|
return DV_E_FORMATETC;
|
|
}
|
|
|
|
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)
|
|
{
|
|
CliprdrDataObject *instance = (CliprdrDataObject *)This;
|
|
|
|
return DATA_E_FORMATETC;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CliprdrDataObject_QueryGetData(IDataObject *This, FORMATETC *pformatetc)
|
|
{
|
|
CliprdrDataObject *instance = (CliprdrDataObject *)This;
|
|
|
|
if (!pformatetc)
|
|
return E_INVALIDARG;
|
|
|
|
return (cliprdr_lookup_format(instance, pformatetc) == -1) ? DV_E_FORMATETC : S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetCanonicalFormatEtc(IDataObject *This, FORMATETC *pformatectIn, FORMATETC *pformatetcOut)
|
|
{
|
|
CliprdrDataObject *instance = (CliprdrDataObject *)This;
|
|
|
|
if (!pformatetcOut)
|
|
return E_INVALIDARG;
|
|
|
|
pformatetcOut->ptd = NULL;
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CliprdrDataObject_SetData(IDataObject *This, FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
|
|
{
|
|
CliprdrDataObject *instance = (CliprdrDataObject *)This;
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CliprdrDataObject_EnumFormatEtc(IDataObject *This, DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
|
|
{
|
|
CliprdrDataObject *instance = (CliprdrDataObject *)This;
|
|
|
|
if (!ppenumFormatEtc)
|
|
return E_INVALIDARG;
|
|
|
|
if(dwDirection == DATADIR_GET)
|
|
{
|
|
*ppenumFormatEtc = (IEnumFORMATETC *)CliprdrEnumFORMATETC_New(instance->m_nNumFormats, instance->m_pFormatEtc);
|
|
return (*ppenumFormatEtc) ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CliprdrDataObject_DAdvise(IDataObject *This, FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
|
|
{
|
|
CliprdrDataObject *instance = (CliprdrDataObject *)This;
|
|
|
|
return OLE_E_ADVISENOTSUPPORTED;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CliprdrDataObject_DUnadvise(IDataObject *This, DWORD dwConnection)
|
|
{
|
|
CliprdrDataObject *instance = (CliprdrDataObject *)This;
|
|
|
|
return OLE_E_ADVISENOTSUPPORTED;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CliprdrDataObject_EnumDAdvise(IDataObject *This, IEnumSTATDATA **ppenumAdvise)
|
|
{
|
|
CliprdrDataObject *instance = (CliprdrDataObject *)This;
|
|
|
|
return OLE_E_ADVISENOTSUPPORTED;
|
|
}
|
|
|
|
CliprdrDataObject *CliprdrDataObject_New(FORMATETC *fmtetc, STGMEDIUM *stgmed, int count, void *data)
|
|
{
|
|
CliprdrDataObject *instance;
|
|
IDataObject *iDataObject;
|
|
int i;
|
|
|
|
instance = (CliprdrDataObject *)calloc(1, sizeof(CliprdrDataObject));
|
|
|
|
if (instance)
|
|
{
|
|
iDataObject = &instance->iDataObject;
|
|
|
|
iDataObject->lpVtbl = (IDataObjectVtbl *)calloc(1, sizeof(IDataObjectVtbl));
|
|
if (iDataObject->lpVtbl)
|
|
{
|
|
iDataObject->lpVtbl->QueryInterface = CliprdrDataObject_QueryInterface;
|
|
iDataObject->lpVtbl->AddRef = CliprdrDataObject_AddRef;
|
|
iDataObject->lpVtbl->Release = CliprdrDataObject_Release;
|
|
iDataObject->lpVtbl->GetData = CliprdrDataObject_GetData;
|
|
iDataObject->lpVtbl->GetDataHere = CliprdrDataObject_GetDataHere;
|
|
iDataObject->lpVtbl->QueryGetData = CliprdrDataObject_QueryGetData;
|
|
iDataObject->lpVtbl->GetCanonicalFormatEtc = CliprdrDataObject_GetCanonicalFormatEtc;
|
|
iDataObject->lpVtbl->SetData = CliprdrDataObject_SetData;
|
|
iDataObject->lpVtbl->EnumFormatEtc = CliprdrDataObject_EnumFormatEtc;
|
|
iDataObject->lpVtbl->DAdvise = CliprdrDataObject_DAdvise;
|
|
iDataObject->lpVtbl->DUnadvise = CliprdrDataObject_DUnadvise;
|
|
iDataObject->lpVtbl->EnumDAdvise = CliprdrDataObject_EnumDAdvise;
|
|
|
|
instance->m_lRefCount = 1;
|
|
instance->m_nNumFormats = count;
|
|
instance->m_pData = data;
|
|
instance->m_nStreams = 0;
|
|
instance->m_pStream = NULL;
|
|
|
|
instance->m_pFormatEtc = (FORMATETC *)calloc(count, sizeof(FORMATETC));
|
|
instance->m_pStgMedium = (STGMEDIUM *)calloc(count, sizeof(STGMEDIUM));
|
|
|
|
for(i = 0; i < count; i++)
|
|
{
|
|
instance->m_pFormatEtc[i] = fmtetc[i];
|
|
instance->m_pStgMedium[i] = stgmed[i];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
free(instance);
|
|
instance = NULL;
|
|
}
|
|
}
|
|
|
|
return instance;
|
|
}
|
|
|
|
void CliprdrDataObject_Delete(CliprdrDataObject *instance)
|
|
{
|
|
if (instance)
|
|
{
|
|
if (instance->iDataObject.lpVtbl)
|
|
free(instance->iDataObject.lpVtbl);
|
|
|
|
if (instance->m_pFormatEtc)
|
|
free(instance->m_pFormatEtc);
|
|
|
|
if (instance->m_pStgMedium)
|
|
free(instance->m_pStgMedium);
|
|
|
|
if(instance->m_pStream)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < instance->m_nStreams; i++)
|
|
CliprdrStream_Release(instance->m_pStream[i]);
|
|
|
|
free(instance->m_pStream);
|
|
}
|
|
|
|
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);
|
|
}
|