FreeRDP/client/Windows/wf_cliprdr.c

2549 lines
62 KiB
C
Raw Normal View History

/**
2012-10-09 07:02:04 +04:00
* FreeRDP: A Remote Desktop Protocol Implementation
* Windows Clipboard Redirection
*
* Copyright 2012 Jason Champion
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.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.
*/
2022-02-16 13:20:38 +03:00
#include <freerdp/config.h>
2015-10-22 10:31:47 +03:00
#define CINTERFACE
#define COBJMACROS
#include <ole2.h>
#include <shlobj.h>
#include <windows.h>
#include <winuser.h>
2015-10-22 10:31:47 +03:00
2021-06-09 15:03:34 +03:00
#include <winpr/assert.h>
#include <winpr/crt.h>
#include <winpr/tchar.h>
#include <winpr/stream.h>
2014-09-12 19:13:01 +04:00
#include <freerdp/log.h>
#include <freerdp/client/cliprdr.h>
#include <strsafe.h>
#include "wf_cliprdr.h"
2014-09-12 19:13:01 +04:00
#define TAG CLIENT_TAG("windows")
2015-10-22 10:31:47 +03:00
#ifdef WITH_DEBUG_CLIPRDR
#define DEBUG_CLIPRDR(...) WLog_DBG(TAG, __VA_ARGS__)
2015-10-22 10:31:47 +03:00
#else
2019-11-06 17:24:51 +03:00
#define DEBUG_CLIPRDR(...) \
do \
{ \
} while (0)
2015-10-22 10:31:47 +03:00
#endif
2019-11-06 17:24:51 +03:00
typedef BOOL(WINAPI* fnAddClipboardFormatListener)(HWND hwnd);
typedef BOOL(WINAPI* fnRemoveClipboardFormatListener)(HWND hwnd);
typedef BOOL(WINAPI* fnGetUpdatedClipboardFormats)(PUINT lpuiFormats, UINT cFormats,
PUINT pcFormatsOut);
typedef struct
2015-10-22 10:31:47 +03:00
{
UINT32 remote_format_id;
UINT32 local_format_id;
WCHAR* name;
} formatMapping;
2015-10-22 10:31:47 +03:00
typedef struct
2015-10-22 10:31:47 +03:00
{
IEnumFORMATETC iEnumFORMATETC;
LONG m_lRefCount;
LONG m_nIndex;
LONG m_nNumFormats;
FORMATETC* m_pFormatEtc;
} CliprdrEnumFORMATETC;
2015-10-22 10:31:47 +03:00
typedef struct
2015-10-22 10:31:47 +03:00
{
IStream iStream;
LONG m_lRefCount;
2018-11-28 16:44:26 +03:00
ULONG m_lIndex;
2015-10-22 10:31:47 +03:00
ULARGE_INTEGER m_lSize;
ULARGE_INTEGER m_lOffset;
FILEDESCRIPTORW m_Dsc;
2015-10-22 10:31:47 +03:00
void* m_pData;
} CliprdrStream;
2015-10-22 10:31:47 +03:00
typedef struct
2015-10-22 10:31:47 +03:00
{
IDataObject iDataObject;
LONG m_lRefCount;
FORMATETC* m_pFormatEtc;
STGMEDIUM* m_pStgMedium;
2018-11-28 16:44:26 +03:00
ULONG m_nNumFormats;
ULONG m_nStreams;
2015-10-22 10:31:47 +03:00
IStream** m_pStream;
void* m_pData;
} CliprdrDataObject;
2015-10-22 10:31:47 +03:00
typedef struct
2015-10-22 10:31:47 +03:00
{
wfContext* wfc;
rdpChannels* channels;
CliprdrClientContext* context;
BOOL sync;
UINT32 capabilities;
size_t map_size;
size_t map_capacity;
formatMapping* format_mappings;
UINT32 requestedFormatId;
HWND hwnd;
HANDLE hmem;
HANDLE thread;
HANDLE response_data_event;
LPDATAOBJECT data_obj;
ULONG req_fsize;
char* req_fdata;
HANDLE req_fevent;
size_t nFiles;
size_t file_array_size;
WCHAR** file_names;
FILEDESCRIPTORW** fileDescriptor;
BOOL legacyApi;
HMODULE hUser32;
HWND hWndNextViewer;
fnAddClipboardFormatListener AddClipboardFormatListener;
fnRemoveClipboardFormatListener RemoveClipboardFormatListener;
fnGetUpdatedClipboardFormats GetUpdatedClipboardFormats;
} wfClipboard;
2015-10-22 10:31:47 +03:00
2019-11-06 17:24:51 +03:00
#define WM_CLIPRDR_MESSAGE (WM_USER + 156)
#define OLE_SETCLIPBOARD 1
2019-11-06 17:24:51 +03:00
static BOOL wf_create_file_obj(wfClipboard* cliprdrrdr, IDataObject** ppDataObject);
2015-10-22 10:31:47 +03:00
static void wf_destroy_file_obj(IDataObject* instance);
static UINT32 get_remote_format_id(wfClipboard* clipboard, UINT32 local_format);
static UINT cliprdr_send_data_request(wfClipboard* clipboard, UINT32 format);
static UINT cliprdr_send_lock(wfClipboard* clipboard);
static UINT cliprdr_send_unlock(wfClipboard* clipboard);
2019-11-06 17:24:51 +03:00
static UINT cliprdr_send_request_filecontents(wfClipboard* clipboard, const void* streamid,
ULONG index, UINT32 flag, DWORD positionhigh,
DWORD positionlow, ULONG request);
2015-10-22 10:31:47 +03:00
static void CliprdrDataObject_Delete(CliprdrDataObject* instance);
2019-11-06 17:24:51 +03:00
static CliprdrEnumFORMATETC* CliprdrEnumFORMATETC_New(ULONG nFormats, FORMATETC* pFormatEtc);
2015-10-22 10:31:47 +03:00
static void CliprdrEnumFORMATETC_Delete(CliprdrEnumFORMATETC* instance);
static void CliprdrStream_Delete(CliprdrStream* instance);
static BOOL try_open_clipboard(HWND hwnd)
{
size_t x;
for (x = 0; x < 10; x++)
{
if (OpenClipboard(hwnd))
return TRUE;
Sleep(10);
}
return FALSE;
}
2014-10-23 21:11:20 +04:00
/**
* IStream
*/
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrStream_QueryInterface(IStream* This, REFIID riid,
void** ppvObject)
2014-10-23 21:11:20 +04:00
{
if (IsEqualIID(riid, &IID_IStream) || IsEqualIID(riid, &IID_IUnknown))
{
IStream_AddRef(This);
*ppvObject = This;
return S_OK;
}
else
{
*ppvObject = 0;
return E_NOINTERFACE;
}
}
2015-10-22 10:31:47 +03:00
static ULONG STDMETHODCALLTYPE CliprdrStream_AddRef(IStream* This)
2014-10-23 21:11:20 +04:00
{
2019-11-06 17:24:51 +03:00
CliprdrStream* instance = (CliprdrStream*)This;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
if (!instance)
return 0;
2014-10-23 21:11:20 +04:00
return InterlockedIncrement(&instance->m_lRefCount);
}
2015-10-22 10:31:47 +03:00
static ULONG STDMETHODCALLTYPE CliprdrStream_Release(IStream* This)
2014-10-23 21:11:20 +04:00
{
LONG count;
2019-11-06 17:24:51 +03:00
CliprdrStream* instance = (CliprdrStream*)This;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
if (!instance)
return 0;
2014-10-23 21:11:20 +04:00
count = InterlockedDecrement(&instance->m_lRefCount);
if (count == 0)
{
CliprdrStream_Delete(instance);
return 0;
}
else
{
return count;
}
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrStream_Read(IStream* This, void* pv, ULONG cb,
ULONG* pcbRead)
2014-10-23 21:11:20 +04:00
{
int ret;
2019-11-06 17:24:51 +03:00
CliprdrStream* instance = (CliprdrStream*)This;
2015-10-22 10:31:47 +03:00
wfClipboard* clipboard;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
if (!pv || !pcbRead || !instance)
2014-10-23 21:11:20 +04:00
return E_INVALIDARG;
2019-11-06 17:24:51 +03:00
clipboard = (wfClipboard*)instance->m_pData;
2014-10-23 21:11:20 +04:00
*pcbRead = 0;
if (instance->m_lOffset.QuadPart >= instance->m_lSize.QuadPart)
2015-10-22 10:31:47 +03:00
return S_FALSE;
2014-10-23 21:11:20 +04:00
2019-11-06 17:24:51 +03:00
ret = cliprdr_send_request_filecontents(clipboard, (void*)This, instance->m_lIndex,
FILECONTENTS_RANGE, instance->m_lOffset.HighPart,
instance->m_lOffset.LowPart, cb);
2014-10-23 21:11:20 +04:00
if (ret < 0)
return E_FAIL;
2014-10-23 21:11:20 +04:00
if (clipboard->req_fdata)
2014-10-23 21:11:20 +04:00
{
CopyMemory(pv, clipboard->req_fdata, clipboard->req_fsize);
free(clipboard->req_fdata);
2014-10-23 21:11:20 +04:00
}
*pcbRead = clipboard->req_fsize;
instance->m_lOffset.QuadPart += clipboard->req_fsize;
2014-10-23 21:11:20 +04:00
if (clipboard->req_fsize < cb)
2015-10-22 10:31:47 +03:00
return S_FALSE;
2014-10-23 21:11:20 +04:00
return S_OK;
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrStream_Write(IStream* This, const void* pv, ULONG cb,
ULONG* pcbWritten)
2014-10-23 21:11:20 +04:00
{
2015-10-22 10:31:47 +03:00
(void)This;
(void)pv;
(void)cb;
(void)pcbWritten;
2014-10-23 21:11:20 +04:00
return STG_E_ACCESSDENIED;
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrStream_Seek(IStream* This, LARGE_INTEGER dlibMove,
DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
2014-10-23 21:11:20 +04:00
{
ULONGLONG newoffset;
2019-11-06 17:24:51 +03:00
CliprdrStream* instance = (CliprdrStream*)This;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
if (!instance)
return E_INVALIDARG;
2014-10-23 21:11:20 +04:00
newoffset = instance->m_lOffset.QuadPart;
switch (dwOrigin)
{
2016-08-03 13:09:24 +03:00
case STREAM_SEEK_SET:
newoffset = dlibMove.QuadPart;
break;
case STREAM_SEEK_CUR:
newoffset += dlibMove.QuadPart;
break;
case STREAM_SEEK_END:
newoffset = instance->m_lSize.QuadPart + dlibMove.QuadPart;
break;
default:
return E_INVALIDARG;
2014-10-23 21:11:20 +04:00
}
if (newoffset < 0 || newoffset >= instance->m_lSize.QuadPart)
return E_FAIL;
2014-10-23 21:11:20 +04:00
instance->m_lOffset.QuadPart = newoffset;
2014-10-23 21:11:20 +04:00
if (plibNewPosition)
plibNewPosition->QuadPart = instance->m_lOffset.QuadPart;
return S_OK;
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrStream_SetSize(IStream* This, ULARGE_INTEGER libNewSize)
2014-10-23 21:11:20 +04:00
{
2015-10-22 10:31:47 +03:00
(void)This;
(void)libNewSize;
return E_NOTIMPL;
2014-10-23 21:11:20 +04:00
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrStream_CopyTo(IStream* This, IStream* pstm,
ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead,
ULARGE_INTEGER* pcbWritten)
2014-10-23 21:11:20 +04:00
{
2015-10-22 10:31:47 +03:00
(void)This;
(void)pstm;
(void)cb;
(void)pcbRead;
(void)pcbWritten;
return E_NOTIMPL;
2014-10-23 21:11:20 +04:00
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrStream_Commit(IStream* This, DWORD grfCommitFlags)
2014-10-23 21:11:20 +04:00
{
2015-10-22 10:31:47 +03:00
(void)This;
(void)grfCommitFlags;
return E_NOTIMPL;
2014-10-23 21:11:20 +04:00
}
2015-10-22 10:31:47 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrStream_Revert(IStream* This)
2014-10-23 21:11:20 +04:00
{
2015-10-22 10:31:47 +03:00
(void)This;
return E_NOTIMPL;
2014-10-23 21:11:20 +04:00
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrStream_LockRegion(IStream* This, ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb, DWORD dwLockType)
2014-10-23 21:11:20 +04:00
{
2015-10-22 10:31:47 +03:00
(void)This;
(void)libOffset;
(void)cb;
(void)dwLockType;
return E_NOTIMPL;
2014-10-23 21:11:20 +04:00
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrStream_UnlockRegion(IStream* This, ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb, DWORD dwLockType)
2014-10-23 21:11:20 +04:00
{
2015-10-22 10:31:47 +03:00
(void)This;
(void)libOffset;
(void)cb;
(void)dwLockType;
return E_NOTIMPL;
2014-10-23 21:11:20 +04:00
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrStream_Stat(IStream* This, STATSTG* pstatstg,
DWORD grfStatFlag)
2014-10-23 21:11:20 +04:00
{
2019-11-06 17:24:51 +03:00
CliprdrStream* instance = (CliprdrStream*)This;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
if (!instance)
return E_INVALIDARG;
2014-10-23 21:11:20 +04:00
if (pstatstg == NULL)
return STG_E_INVALIDPOINTER;
ZeroMemory(pstatstg, sizeof(STATSTG));
switch (grfStatFlag)
{
2016-08-03 13:09:24 +03:00
case STATFLAG_DEFAULT:
return STG_E_INSUFFICIENTMEMORY;
2014-10-23 21:11:20 +04:00
2016-08-03 13:09:24 +03:00
case STATFLAG_NONAME:
pstatstg->cbSize.QuadPart = instance->m_lSize.QuadPart;
pstatstg->grfLocksSupported = LOCK_EXCLUSIVE;
pstatstg->grfMode = GENERIC_READ;
pstatstg->grfStateBits = 0;
pstatstg->type = STGTY_STREAM;
break;
2014-10-23 21:11:20 +04:00
2016-08-03 13:09:24 +03:00
case STATFLAG_NOOPEN:
return STG_E_INVALIDFLAG;
2014-10-23 21:11:20 +04:00
2016-08-03 13:09:24 +03:00
default:
return STG_E_INVALIDFLAG;
2014-10-23 21:11:20 +04:00
}
return S_OK;
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrStream_Clone(IStream* This, IStream** ppstm)
2014-10-23 21:11:20 +04:00
{
2015-10-22 10:31:47 +03:00
(void)This;
(void)ppstm;
return E_NOTIMPL;
2014-10-23 21:11:20 +04:00
}
2019-11-06 17:24:51 +03:00
static CliprdrStream* CliprdrStream_New(ULONG index, void* pData, const FILEDESCRIPTORW* dsc)
2014-10-23 21:11:20 +04:00
{
IStream* iStream;
2015-10-22 10:31:47 +03:00
BOOL success = FALSE;
BOOL isDir = FALSE;
2014-10-23 21:11:20 +04:00
CliprdrStream* instance;
2019-11-06 17:24:51 +03:00
wfClipboard* clipboard = (wfClipboard*)pData;
instance = (CliprdrStream*)calloc(1, sizeof(CliprdrStream));
2014-10-23 21:11:20 +04:00
if (instance)
{
instance->m_Dsc = *dsc;
2014-10-23 21:11:20 +04:00
iStream = &instance->iStream;
2019-11-06 17:24:51 +03:00
iStream->lpVtbl = (IStreamVtbl*)calloc(1, sizeof(IStreamVtbl));
2014-10-23 21:11:20 +04:00
if (iStream->lpVtbl)
{
iStream->lpVtbl->QueryInterface = CliprdrStream_QueryInterface;
iStream->lpVtbl->AddRef = CliprdrStream_AddRef;
iStream->lpVtbl->Release = CliprdrStream_Release;
iStream->lpVtbl->Read = CliprdrStream_Read;
iStream->lpVtbl->Write = CliprdrStream_Write;
iStream->lpVtbl->Seek = CliprdrStream_Seek;
iStream->lpVtbl->SetSize = CliprdrStream_SetSize;
iStream->lpVtbl->CopyTo = CliprdrStream_CopyTo;
iStream->lpVtbl->Commit = CliprdrStream_Commit;
iStream->lpVtbl->Revert = CliprdrStream_Revert;
iStream->lpVtbl->LockRegion = CliprdrStream_LockRegion;
iStream->lpVtbl->UnlockRegion = CliprdrStream_UnlockRegion;
iStream->lpVtbl->Stat = CliprdrStream_Stat;
iStream->lpVtbl->Clone = CliprdrStream_Clone;
instance->m_lRefCount = 1;
instance->m_lIndex = index;
instance->m_pData = pData;
instance->m_lOffset.QuadPart = 0;
if (instance->m_Dsc.dwFlags & FD_ATTRIBUTES)
2015-10-22 10:31:47 +03:00
{
if (instance->m_Dsc.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
isDir = TRUE;
2015-10-22 10:31:47 +03:00
}
2016-08-03 13:09:24 +03:00
if (((instance->m_Dsc.dwFlags & FD_FILESIZE) == 0) && !isDir)
{
/* get content size of this stream */
2019-11-06 17:24:51 +03:00
if (cliprdr_send_request_filecontents(clipboard, (void*)instance,
instance->m_lIndex, FILECONTENTS_SIZE, 0, 0,
8) == CHANNEL_RC_OK)
{
success = TRUE;
}
2019-11-06 17:24:51 +03:00
instance->m_lSize.QuadPart = *((LONGLONG*)clipboard->req_fdata);
free(clipboard->req_fdata);
}
else
success = TRUE;
2014-10-23 21:11:20 +04:00
}
2015-10-22 10:31:47 +03:00
}
if (!success)
{
CliprdrStream_Delete(instance);
instance = NULL;
2014-10-23 21:11:20 +04:00
}
return instance;
}
void CliprdrStream_Delete(CliprdrStream* instance)
{
if (instance)
{
2015-05-11 10:07:39 +03:00
free(instance->iStream.lpVtbl);
2014-10-23 21:11:20 +04:00
free(instance);
}
}
/**
* IDataObject
*/
2019-11-06 17:24:51 +03:00
static LONG cliprdr_lookup_format(CliprdrDataObject* instance, FORMATETC* pFormatEtc)
2014-10-23 21:11:20 +04:00
{
2018-11-28 16:44:26 +03:00
ULONG i;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
if (!instance || !pFormatEtc)
return -1;
2014-10-23 21:11:20 +04:00
for (i = 0; i < instance->m_nNumFormats; i++)
{
if ((pFormatEtc->tymed & instance->m_pFormatEtc[i].tymed) &&
2016-08-03 13:09:24 +03:00
pFormatEtc->cfFormat == instance->m_pFormatEtc[i].cfFormat &&
pFormatEtc->dwAspect & instance->m_pFormatEtc[i].dwAspect)
2014-10-23 21:11:20 +04:00
{
2018-11-28 16:44:26 +03:00
return (LONG)i;
2014-10-23 21:11:20 +04:00
}
}
return -1;
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrDataObject_QueryInterface(IDataObject* This, REFIID riid,
void** ppvObject)
2014-10-23 21:11:20 +04:00
{
2015-10-22 10:31:47 +03:00
(void)This;
if (!ppvObject)
return E_INVALIDARG;
2014-10-23 21:11:20 +04:00
if (IsEqualIID(riid, &IID_IDataObject) || IsEqualIID(riid, &IID_IUnknown))
{
IDataObject_AddRef(This);
*ppvObject = This;
return S_OK;
}
else
{
*ppvObject = 0;
return E_NOINTERFACE;
}
}
2015-10-22 10:31:47 +03:00
static ULONG STDMETHODCALLTYPE CliprdrDataObject_AddRef(IDataObject* This)
2014-10-23 21:11:20 +04:00
{
2019-11-06 17:24:51 +03:00
CliprdrDataObject* instance = (CliprdrDataObject*)This;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
if (!instance)
return E_INVALIDARG;
2014-10-23 21:11:20 +04:00
return InterlockedIncrement(&instance->m_lRefCount);
}
2015-10-22 10:31:47 +03:00
static ULONG STDMETHODCALLTYPE CliprdrDataObject_Release(IDataObject* This)
2014-10-23 21:11:20 +04:00
{
LONG count;
2019-11-06 17:24:51 +03:00
CliprdrDataObject* instance = (CliprdrDataObject*)This;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
if (!instance)
return E_INVALIDARG;
2014-10-23 21:11:20 +04:00
count = InterlockedDecrement(&instance->m_lRefCount);
if (count == 0)
{
CliprdrDataObject_Delete(instance);
return 0;
}
else
return count;
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData(IDataObject* This, FORMATETC* pFormatEtc,
STGMEDIUM* pMedium)
2014-10-23 21:11:20 +04:00
{
2018-11-28 16:44:26 +03:00
ULONG i;
LONG idx;
2019-11-06 17:24:51 +03:00
CliprdrDataObject* instance = (CliprdrDataObject*)This;
2015-10-22 10:31:47 +03:00
wfClipboard* clipboard;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
if (!pFormatEtc || !pMedium || !instance)
return E_INVALIDARG;
2019-11-06 17:24:51 +03:00
clipboard = (wfClipboard*)instance->m_pData;
2015-10-22 10:31:47 +03:00
if (!clipboard)
2014-10-23 21:11:20 +04:00
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;
2019-11-06 17:24:51 +03:00
if (instance->m_pFormatEtc[idx].cfFormat == RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW))
2014-10-23 21:11:20 +04:00
{
2016-08-03 13:09:24 +03:00
FILEGROUPDESCRIPTOR* dsc;
2019-11-06 17:24:51 +03:00
DWORD remote = get_remote_format_id(clipboard, instance->m_pFormatEtc[idx].cfFormat);
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (cliprdr_send_data_request(clipboard, remote) != 0)
2014-10-23 21:11:20 +04:00
return E_UNEXPECTED;
2019-11-06 17:24:51 +03:00
pMedium->hGlobal = clipboard->hmem; /* points to a FILEGROUPDESCRIPTOR structure */
2014-10-23 21:11:20 +04:00
/* GlobalLock returns a pointer to the first byte of the memory block,
2019-11-06 17:24:51 +03:00
* in which is a FILEGROUPDESCRIPTOR structure, whose first UINT member
* is the number of FILEDESCRIPTOR's */
dsc = (FILEGROUPDESCRIPTOR*)GlobalLock(clipboard->hmem);
2015-10-22 10:31:47 +03:00
instance->m_nStreams = dsc->cItems;
GlobalUnlock(clipboard->hmem);
2014-10-23 21:11:20 +04:00
if (instance->m_nStreams > 0)
{
if (!instance->m_pStream)
{
2019-11-06 17:24:51 +03:00
instance->m_pStream = (LPSTREAM*)calloc(instance->m_nStreams, sizeof(LPSTREAM));
2014-10-23 21:11:20 +04:00
if (instance->m_pStream)
{
for (i = 0; i < instance->m_nStreams; i++)
{
2019-11-06 17:24:51 +03:00
instance->m_pStream[i] =
(IStream*)CliprdrStream_New(i, clipboard, &dsc->fgd[i]);
2016-08-03 13:09:24 +03:00
if (!instance->m_pStream[i])
return E_OUTOFMEMORY;
}
2014-10-23 21:11:20 +04:00
}
}
}
if (!instance->m_pStream)
{
if (clipboard->hmem)
{
GlobalFree(clipboard->hmem);
clipboard->hmem = NULL;
}
pMedium->hGlobal = NULL;
2014-10-23 21:11:20 +04:00
return E_OUTOFMEMORY;
}
}
2019-11-06 17:24:51 +03:00
else if (instance->m_pFormatEtc[idx].cfFormat == RegisterClipboardFormat(CFSTR_FILECONTENTS))
2014-10-23 21:11:20 +04:00
{
if ((pFormatEtc->lindex >= 0) && ((ULONG)pFormatEtc->lindex < instance->m_nStreams))
2014-10-23 21:11:20 +04:00
{
pMedium->pstm = instance->m_pStream[pFormatEtc->lindex];
IDataObject_AddRef(instance->m_pStream[pFormatEtc->lindex]);
}
else
return E_INVALIDARG;
}
else
return E_UNEXPECTED;
return S_OK;
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetDataHere(IDataObject* This,
FORMATETC* pformatetc,
STGMEDIUM* pmedium)
2014-10-23 21:11:20 +04:00
{
2015-10-22 10:31:47 +03:00
(void)This;
(void)pformatetc;
(void)pmedium;
return E_NOTIMPL;
2014-10-23 21:11:20 +04:00
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrDataObject_QueryGetData(IDataObject* This,
FORMATETC* pformatetc)
2014-10-23 21:11:20 +04:00
{
2019-11-06 17:24:51 +03:00
CliprdrDataObject* instance = (CliprdrDataObject*)This;
2014-10-23 21:11:20 +04:00
if (!pformatetc)
return E_INVALIDARG;
2015-10-22 10:31:47 +03:00
if (cliprdr_lookup_format(instance, pformatetc) == -1)
return DV_E_FORMATETC;
return S_OK;
2014-10-23 21:11:20 +04:00
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetCanonicalFormatEtc(IDataObject* This,
FORMATETC* pformatectIn,
FORMATETC* pformatetcOut)
2014-10-23 21:11:20 +04:00
{
2015-10-22 10:31:47 +03:00
(void)This;
(void)pformatectIn;
2014-10-23 21:11:20 +04:00
if (!pformatetcOut)
return E_INVALIDARG;
pformatetcOut->ptd = NULL;
return E_NOTIMPL;
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrDataObject_SetData(IDataObject* This, FORMATETC* pformatetc,
STGMEDIUM* pmedium, BOOL fRelease)
2014-10-23 21:11:20 +04:00
{
2015-10-22 10:31:47 +03:00
(void)This;
(void)pformatetc;
(void)pmedium;
(void)fRelease;
2014-10-23 21:11:20 +04:00
return E_NOTIMPL;
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrDataObject_EnumFormatEtc(IDataObject* This,
DWORD dwDirection,
IEnumFORMATETC** ppenumFormatEtc)
2014-10-23 21:11:20 +04:00
{
2019-11-06 17:24:51 +03:00
CliprdrDataObject* instance = (CliprdrDataObject*)This;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
if (!instance || !ppenumFormatEtc)
2014-10-23 21:11:20 +04:00
return E_INVALIDARG;
if (dwDirection == DATADIR_GET)
{
2019-11-06 17:24:51 +03:00
*ppenumFormatEtc = (IEnumFORMATETC*)CliprdrEnumFORMATETC_New(instance->m_nNumFormats,
instance->m_pFormatEtc);
2014-10-23 21:11:20 +04:00
return (*ppenumFormatEtc) ? S_OK : E_OUTOFMEMORY;
}
else
{
return E_NOTIMPL;
}
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrDataObject_DAdvise(IDataObject* This, FORMATETC* pformatetc,
DWORD advf, IAdviseSink* pAdvSink,
DWORD* pdwConnection)
2014-10-23 21:11:20 +04:00
{
2015-10-22 10:31:47 +03:00
(void)This;
(void)pformatetc;
(void)advf;
(void)pAdvSink;
(void)pdwConnection;
2014-10-23 21:11:20 +04:00
return OLE_E_ADVISENOTSUPPORTED;
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrDataObject_DUnadvise(IDataObject* This, DWORD dwConnection)
2014-10-23 21:11:20 +04:00
{
2015-10-22 10:31:47 +03:00
(void)This;
(void)dwConnection;
2014-10-23 21:11:20 +04:00
return OLE_E_ADVISENOTSUPPORTED;
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrDataObject_EnumDAdvise(IDataObject* This,
IEnumSTATDATA** ppenumAdvise)
2014-10-23 21:11:20 +04:00
{
2015-10-22 10:31:47 +03:00
(void)This;
(void)ppenumAdvise;
2014-10-23 21:11:20 +04:00
return OLE_E_ADVISENOTSUPPORTED;
}
2019-11-06 17:24:51 +03:00
static CliprdrDataObject* CliprdrDataObject_New(FORMATETC* fmtetc, STGMEDIUM* stgmed, ULONG count,
void* data)
2014-10-23 21:11:20 +04:00
{
CliprdrDataObject* instance;
IDataObject* iDataObject;
2019-11-06 17:24:51 +03:00
instance = (CliprdrDataObject*)calloc(1, sizeof(CliprdrDataObject));
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
if (!instance)
goto error;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
iDataObject = &instance->iDataObject;
2019-11-06 17:24:51 +03:00
iDataObject->lpVtbl = (IDataObjectVtbl*)calloc(1, sizeof(IDataObjectVtbl));
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
if (!iDataObject->lpVtbl)
goto error;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
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;
2019-11-06 17:24:51 +03:00
iDataObject->lpVtbl->GetCanonicalFormatEtc = CliprdrDataObject_GetCanonicalFormatEtc;
2015-10-22 10:31:47 +03:00
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;
if (count > 0)
{
ULONG i;
2019-11-06 17:24:51 +03:00
instance->m_pFormatEtc = (FORMATETC*)calloc(count, sizeof(FORMATETC));
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (!instance->m_pFormatEtc)
goto error;
2016-08-03 13:09:24 +03:00
2019-11-06 17:24:51 +03:00
instance->m_pStgMedium = (STGMEDIUM*)calloc(count, sizeof(STGMEDIUM));
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (!instance->m_pStgMedium)
goto error;
for (i = 0; i < count; i++)
2014-10-23 21:11:20 +04:00
{
2015-10-22 10:31:47 +03:00
instance->m_pFormatEtc[i] = fmtetc[i];
instance->m_pStgMedium[i] = stgmed[i];
2014-10-23 21:11:20 +04:00
}
}
return instance;
2015-10-22 10:31:47 +03:00
error:
CliprdrDataObject_Delete(instance);
return NULL;
2014-10-23 21:11:20 +04:00
}
void CliprdrDataObject_Delete(CliprdrDataObject* instance)
{
if (instance)
{
2015-05-11 10:07:39 +03:00
free(instance->iDataObject.lpVtbl);
free(instance->m_pFormatEtc);
free(instance->m_pStgMedium);
2014-10-23 21:11:20 +04:00
if (instance->m_pStream)
{
2018-11-28 16:44:26 +03:00
ULONG i;
2014-10-23 21:11:20 +04:00
for (i = 0; i < instance->m_nStreams; i++)
CliprdrStream_Release(instance->m_pStream[i]);
free(instance->m_pStream);
}
free(instance);
}
}
2019-11-06 17:24:51 +03:00
static BOOL wf_create_file_obj(wfClipboard* clipboard, IDataObject** ppDataObject)
2014-10-23 21:11:20 +04:00
{
2015-10-22 10:31:47 +03:00
FORMATETC fmtetc[2];
STGMEDIUM stgmeds[2];
2014-10-23 21:11:20 +04:00
if (!ppDataObject)
return FALSE;
2015-10-22 10:31:47 +03:00
fmtetc[0].cfFormat = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
2014-10-23 21:11:20 +04:00
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;
2015-10-22 10:31:47 +03:00
fmtetc[1].cfFormat = RegisterClipboardFormat(CFSTR_FILECONTENTS);
2014-10-23 21:11:20 +04:00
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;
2019-11-06 17:24:51 +03:00
*ppDataObject = (IDataObject*)CliprdrDataObject_New(fmtetc, stgmeds, 2, clipboard);
2014-10-23 21:11:20 +04:00
return (*ppDataObject) ? TRUE : FALSE;
}
2015-10-22 10:31:47 +03:00
static void wf_destroy_file_obj(IDataObject* instance)
2014-10-23 21:11:20 +04:00
{
if (instance)
IDataObject_Release(instance);
}
/**
* IEnumFORMATETC
*/
static void cliprdr_format_deep_copy(FORMATETC* dest, FORMATETC* source)
{
*dest = *source;
if (source->ptd)
{
2019-11-06 17:24:51 +03:00
dest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE));
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (dest->ptd)
*(dest->ptd) = *(source->ptd);
2014-10-23 21:11:20 +04:00
}
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrEnumFORMATETC_QueryInterface(IEnumFORMATETC* This,
REFIID riid, void** ppvObject)
2014-10-23 21:11:20 +04:00
{
2015-10-22 10:31:47 +03:00
(void)This;
2014-10-23 21:11:20 +04:00
if (IsEqualIID(riid, &IID_IEnumFORMATETC) || IsEqualIID(riid, &IID_IUnknown))
{
IEnumFORMATETC_AddRef(This);
*ppvObject = This;
return S_OK;
}
else
{
*ppvObject = 0;
return E_NOINTERFACE;
}
}
2015-10-22 10:31:47 +03:00
static ULONG STDMETHODCALLTYPE CliprdrEnumFORMATETC_AddRef(IEnumFORMATETC* This)
2014-10-23 21:11:20 +04:00
{
2019-11-06 17:24:51 +03:00
CliprdrEnumFORMATETC* instance = (CliprdrEnumFORMATETC*)This;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
if (!instance)
return 0;
2014-10-23 21:11:20 +04:00
return InterlockedIncrement(&instance->m_lRefCount);
}
2019-11-06 17:24:51 +03:00
static ULONG STDMETHODCALLTYPE CliprdrEnumFORMATETC_Release(IEnumFORMATETC* This)
2014-10-23 21:11:20 +04:00
{
LONG count;
2019-11-06 17:24:51 +03:00
CliprdrEnumFORMATETC* instance = (CliprdrEnumFORMATETC*)This;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
if (!instance)
return 0;
2014-10-23 21:11:20 +04:00
count = InterlockedDecrement(&instance->m_lRefCount);
if (count == 0)
{
CliprdrEnumFORMATETC_Delete(instance);
return 0;
}
else
{
return count;
}
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrEnumFORMATETC_Next(IEnumFORMATETC* This, ULONG celt,
FORMATETC* rgelt, ULONG* pceltFetched)
2014-10-23 21:11:20 +04:00
{
2019-11-06 17:24:51 +03:00
ULONG copied = 0;
CliprdrEnumFORMATETC* instance = (CliprdrEnumFORMATETC*)This;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
if (!instance || !celt || !rgelt)
2014-10-23 21:11:20 +04:00
return E_INVALIDARG;
while ((instance->m_nIndex < instance->m_nNumFormats) && (copied < celt))
2014-10-23 21:11:20 +04:00
{
2019-11-06 17:24:51 +03:00
cliprdr_format_deep_copy(&rgelt[copied++], &instance->m_pFormatEtc[instance->m_nIndex++]);
2014-10-23 21:11:20 +04:00
}
if (pceltFetched != 0)
*pceltFetched = copied;
return (copied == celt) ? S_OK : E_FAIL;
2014-10-23 21:11:20 +04:00
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrEnumFORMATETC_Skip(IEnumFORMATETC* This, ULONG celt)
2014-10-23 21:11:20 +04:00
{
2019-11-06 17:24:51 +03:00
CliprdrEnumFORMATETC* instance = (CliprdrEnumFORMATETC*)This;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
if (!instance)
return E_INVALIDARG;
2019-11-06 17:24:51 +03:00
if (instance->m_nIndex + (LONG)celt > instance->m_nNumFormats)
return E_FAIL;
2014-10-23 21:11:20 +04:00
instance->m_nIndex += celt;
return S_OK;
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrEnumFORMATETC_Reset(IEnumFORMATETC* This)
2014-10-23 21:11:20 +04:00
{
2019-11-06 17:24:51 +03:00
CliprdrEnumFORMATETC* instance = (CliprdrEnumFORMATETC*)This;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
if (!instance)
return E_INVALIDARG;
2014-10-23 21:11:20 +04:00
instance->m_nIndex = 0;
return S_OK;
}
2019-11-06 17:24:51 +03:00
static HRESULT STDMETHODCALLTYPE CliprdrEnumFORMATETC_Clone(IEnumFORMATETC* This,
IEnumFORMATETC** ppEnum)
2014-10-23 21:11:20 +04:00
{
2019-11-06 17:24:51 +03:00
CliprdrEnumFORMATETC* instance = (CliprdrEnumFORMATETC*)This;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
if (!instance || !ppEnum)
2014-10-23 21:11:20 +04:00
return E_INVALIDARG;
2019-11-06 17:24:51 +03:00
*ppEnum =
(IEnumFORMATETC*)CliprdrEnumFORMATETC_New(instance->m_nNumFormats, instance->m_pFormatEtc);
2014-10-23 21:11:20 +04:00
if (!*ppEnum)
return E_OUTOFMEMORY;
2019-11-06 17:24:51 +03:00
((CliprdrEnumFORMATETC*)*ppEnum)->m_nIndex = instance->m_nIndex;
2014-10-23 21:11:20 +04:00
return S_OK;
}
2019-11-06 17:24:51 +03:00
CliprdrEnumFORMATETC* CliprdrEnumFORMATETC_New(ULONG nFormats, FORMATETC* pFormatEtc)
2014-10-23 21:11:20 +04:00
{
2018-11-28 16:44:26 +03:00
ULONG i;
2014-10-23 21:11:20 +04:00
CliprdrEnumFORMATETC* instance;
IEnumFORMATETC* iEnumFORMATETC;
2015-10-22 10:31:47 +03:00
if ((nFormats != 0) && !pFormatEtc)
2014-10-23 21:11:20 +04:00
return NULL;
2019-11-06 17:24:51 +03:00
instance = (CliprdrEnumFORMATETC*)calloc(1, sizeof(CliprdrEnumFORMATETC));
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
if (!instance)
goto error;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
iEnumFORMATETC = &instance->iEnumFORMATETC;
2019-11-06 17:24:51 +03:00
iEnumFORMATETC->lpVtbl = (IEnumFORMATETCVtbl*)calloc(1, sizeof(IEnumFORMATETCVtbl));
2015-10-22 10:31:47 +03:00
if (!iEnumFORMATETC->lpVtbl)
goto error;
iEnumFORMATETC->lpVtbl->QueryInterface = CliprdrEnumFORMATETC_QueryInterface;
iEnumFORMATETC->lpVtbl->AddRef = CliprdrEnumFORMATETC_AddRef;
iEnumFORMATETC->lpVtbl->Release = CliprdrEnumFORMATETC_Release;
iEnumFORMATETC->lpVtbl->Next = CliprdrEnumFORMATETC_Next;
iEnumFORMATETC->lpVtbl->Skip = CliprdrEnumFORMATETC_Skip;
iEnumFORMATETC->lpVtbl->Reset = CliprdrEnumFORMATETC_Reset;
iEnumFORMATETC->lpVtbl->Clone = CliprdrEnumFORMATETC_Clone;
2018-11-28 16:44:26 +03:00
instance->m_lRefCount = 1;
2015-10-22 10:31:47 +03:00
instance->m_nIndex = 0;
instance->m_nNumFormats = nFormats;
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (nFormats > 0)
{
2019-11-06 17:24:51 +03:00
instance->m_pFormatEtc = (FORMATETC*)calloc(nFormats, sizeof(FORMATETC));
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (!instance->m_pFormatEtc)
goto error;
2014-10-23 21:11:20 +04:00
2015-10-22 10:31:47 +03:00
for (i = 0; i < nFormats; i++)
cliprdr_format_deep_copy(&instance->m_pFormatEtc[i], &pFormatEtc[i]);
}
2016-08-03 13:09:24 +03:00
return instance;
2015-10-22 10:31:47 +03:00
error:
CliprdrEnumFORMATETC_Delete(instance);
return NULL;
2014-10-23 21:11:20 +04:00
}
void CliprdrEnumFORMATETC_Delete(CliprdrEnumFORMATETC* instance)
{
2015-10-22 10:31:47 +03:00
LONG i;
2014-10-23 21:11:20 +04:00
if (instance)
{
2015-05-11 10:07:39 +03:00
free(instance->iEnumFORMATETC.lpVtbl);
2014-10-23 21:11:20 +04:00
if (instance->m_pFormatEtc)
{
for (i = 0; i < instance->m_nNumFormats; i++)
{
if (instance->m_pFormatEtc[i].ptd)
CoTaskMemFree(instance->m_pFormatEtc[i].ptd);
}
free(instance->m_pFormatEtc);
}
free(instance);
}
}
/***********************************************************************************/
2019-11-06 17:24:51 +03:00
static UINT32 get_local_format_id_by_name(wfClipboard* clipboard, const TCHAR* format_name)
{
2015-10-22 10:31:47 +03:00
size_t i;
2014-10-23 06:32:55 +04:00
formatMapping* map;
2015-10-22 10:31:47 +03:00
WCHAR* unicode_name;
#if !defined(UNICODE)
size_t size;
#endif
if (!clipboard || !format_name)
return 0;
#if defined(UNICODE)
unicode_name = _wcsdup(format_name);
#else
size = _tcslen(format_name);
unicode_name = calloc(size + 1, sizeof(WCHAR));
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (!unicode_name)
return 0;
2019-11-06 17:24:51 +03:00
MultiByteToWideChar(CP_OEMCP, 0, format_name, strlen(format_name), unicode_name, size);
2015-10-22 10:31:47 +03:00
#endif
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (!unicode_name)
return 0;
for (i = 0; i < clipboard->map_size; i++)
2013-11-21 09:45:16 +04:00
{
map = &clipboard->format_mappings[i];
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (map->name)
2013-11-21 09:45:16 +04:00
{
2015-10-22 10:31:47 +03:00
if (wcscmp(map->name, unicode_name) == 0)
2013-11-21 09:45:16 +04:00
{
2016-08-03 13:09:24 +03:00
free(unicode_name);
2015-10-22 10:31:47 +03:00
return map->local_format_id;
}
}
}
2016-08-03 13:09:24 +03:00
free(unicode_name);
return 0;
}
static INLINE BOOL file_transferring(wfClipboard* clipboard)
{
2019-11-06 17:24:51 +03:00
return get_local_format_id_by_name(clipboard, CFSTR_FILEDESCRIPTORW) ? TRUE : FALSE;
}
static UINT32 get_remote_format_id(wfClipboard* clipboard, UINT32 local_format)
{
2015-10-22 10:31:47 +03:00
UINT32 i;
2014-10-23 06:32:55 +04:00
formatMapping* map;
2015-10-22 10:31:47 +03:00
if (!clipboard)
return 0;
for (i = 0; i < clipboard->map_size; i++)
2013-11-21 09:45:16 +04:00
{
map = &clipboard->format_mappings[i];
2014-10-23 06:32:55 +04:00
2013-11-21 09:45:16 +04:00
if (map->local_format_id == local_format)
return map->remote_format_id;
}
return local_format;
}
static void map_ensure_capacity(wfClipboard* clipboard)
{
2015-10-22 10:31:47 +03:00
if (!clipboard)
return;
if (clipboard->map_size >= clipboard->map_capacity)
2013-11-21 09:45:16 +04:00
{
2015-10-22 10:31:47 +03:00
size_t new_size;
2016-08-03 13:09:24 +03:00
formatMapping* new_map;
new_size = clipboard->map_capacity * 2;
2019-11-06 17:24:51 +03:00
new_map =
(formatMapping*)realloc(clipboard->format_mappings, sizeof(formatMapping) * new_size);
2016-08-03 13:09:24 +03:00
if (!new_map)
return;
2016-08-03 13:09:24 +03:00
clipboard->format_mappings = new_map;
clipboard->map_capacity = new_size;
}
}
2015-10-22 10:31:47 +03:00
static BOOL clear_format_map(wfClipboard* clipboard)
{
2015-10-22 10:31:47 +03:00
size_t i;
2014-10-23 06:32:55 +04:00
formatMapping* map;
2015-10-22 10:31:47 +03:00
if (!clipboard)
return FALSE;
if (clipboard->format_mappings)
2013-11-21 09:45:16 +04:00
{
for (i = 0; i < clipboard->map_capacity; i++)
2013-11-21 09:45:16 +04:00
{
map = &clipboard->format_mappings[i];
map->remote_format_id = 0;
map->local_format_id = 0;
2015-05-11 10:07:39 +03:00
free(map->name);
map->name = NULL;
}
}
clipboard->map_size = 0;
2015-10-22 10:31:47 +03:00
return TRUE;
}
2015-10-22 10:31:47 +03:00
static UINT cliprdr_send_tempdir(wfClipboard* clipboard)
{
CLIPRDR_TEMP_DIRECTORY tempDirectory;
2015-10-22 10:31:47 +03:00
if (!clipboard)
return -1;
2019-11-06 17:24:51 +03:00
if (GetEnvironmentVariableA("TEMP", tempDirectory.szTempDir, sizeof(tempDirectory.szTempDir)) ==
0)
2015-10-22 10:31:47 +03:00
return -1;
2015-10-22 10:31:47 +03:00
return clipboard->context->TempDirectory(clipboard->context, &tempDirectory);
}
2019-11-06 17:24:51 +03:00
static BOOL cliprdr_GetUpdatedClipboardFormats(wfClipboard* clipboard, PUINT lpuiFormats,
UINT cFormats, PUINT pcFormatsOut)
{
UINT index = 0;
UINT format = 0;
BOOL clipboardOpen = FALSE;
if (!clipboard->legacyApi)
2019-11-06 17:24:51 +03:00
return clipboard->GetUpdatedClipboardFormats(lpuiFormats, cFormats, pcFormatsOut);
clipboardOpen = try_open_clipboard(clipboard->hwnd);
if (!clipboardOpen)
{
*pcFormatsOut = 0;
return TRUE; /* Other app holding clipboard */
}
while (index < cFormats)
{
format = EnumClipboardFormats(format);
if (!format)
break;
lpuiFormats[index] = format;
index++;
}
*pcFormatsOut = index;
CloseClipboard();
return TRUE;
}
2015-10-22 10:31:47 +03:00
static UINT cliprdr_send_format_list(wfClipboard* clipboard)
{
2015-10-22 10:31:47 +03:00
UINT rc;
int count = 0;
UINT32 index;
UINT32 numFormats = 0;
UINT32 formatId = 0;
char formatName[1024];
CLIPRDR_FORMAT* formats = NULL;
CLIPRDR_FORMAT_LIST formatList = { 0 };
2015-10-22 10:31:47 +03:00
if (!clipboard)
return ERROR_INTERNAL_ERROR;
ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST));
2014-10-23 06:32:55 +04:00
/* Ignore if other app is holding clipboard */
if (try_open_clipboard(clipboard->hwnd))
2015-10-22 10:31:47 +03:00
{
count = CountClipboardFormats();
numFormats = (UINT32)count;
formats = (CLIPRDR_FORMAT*)calloc(numFormats, sizeof(CLIPRDR_FORMAT));
if (!formats)
{
CloseClipboard();
return CHANNEL_RC_NO_MEMORY;
}
index = 0;
if (IsClipboardFormatAvailable(CF_HDROP))
{
formats[index++].formatId = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
formats[index++].formatId = RegisterClipboardFormat(CFSTR_FILECONTENTS);
}
else
{
while (formatId = EnumClipboardFormats(formatId))
formats[index++].formatId = formatId;
}
numFormats = index;
if (!CloseClipboard())
{
free(formats);
return ERROR_INTERNAL_ERROR;
}
for (index = 0; index < numFormats; index++)
{
if (GetClipboardFormatNameA(formats[index].formatId, formatName, sizeof(formatName)))
{
formats[index].formatName = _strdup(formatName);
}
}
2015-10-22 10:31:47 +03:00
}
formatList.numFormats = numFormats;
formatList.formats = formats;
2022-07-01 12:04:22 +03:00
formatList.common.msgType = CB_FORMAT_LIST;
2015-10-22 10:31:47 +03:00
rc = clipboard->context->ClientFormatList(clipboard->context, &formatList);
for (index = 0; index < numFormats; index++)
2015-10-22 10:31:47 +03:00
free(formats[index].formatName);
free(formats);
2015-10-22 10:31:47 +03:00
return rc;
}
2015-10-22 10:31:47 +03:00
static UINT cliprdr_send_data_request(wfClipboard* clipboard, UINT32 formatId)
{
2015-10-22 10:31:47 +03:00
UINT rc;
UINT32 remoteFormatId;
CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest;
2019-11-06 17:24:51 +03:00
if (!clipboard || !clipboard->context || !clipboard->context->ClientFormatDataRequest)
2015-10-22 10:31:47 +03:00
return ERROR_INTERNAL_ERROR;
remoteFormatId = get_remote_format_id(clipboard, formatId);
formatDataRequest.requestedFormatId = remoteFormatId;
clipboard->requestedFormatId = formatId;
2019-11-06 17:24:51 +03:00
rc = clipboard->context->ClientFormatDataRequest(clipboard->context, &formatDataRequest);
2019-11-06 17:24:51 +03:00
if (WaitForSingleObject(clipboard->response_data_event, INFINITE) != WAIT_OBJECT_0)
2015-10-22 10:31:47 +03:00
rc = ERROR_INTERNAL_ERROR;
else if (!ResetEvent(clipboard->response_data_event))
rc = ERROR_INTERNAL_ERROR;
2015-10-22 10:31:47 +03:00
return rc;
}
2019-11-06 17:24:51 +03:00
UINT cliprdr_send_request_filecontents(wfClipboard* clipboard, const void* streamid, ULONG index,
UINT32 flag, DWORD positionhigh, DWORD positionlow,
ULONG nreq)
{
2015-10-22 10:31:47 +03:00
UINT rc;
CLIPRDR_FILE_CONTENTS_REQUEST fileContentsRequest;
2019-11-06 17:24:51 +03:00
if (!clipboard || !clipboard->context || !clipboard->context->ClientFileContentsRequest)
2015-10-22 10:31:47 +03:00
return ERROR_INTERNAL_ERROR;
fileContentsRequest.streamId = (UINT32)(ULONG_PTR)streamid;
fileContentsRequest.listIndex = index;
fileContentsRequest.dwFlags = flag;
fileContentsRequest.nPositionLow = positionlow;
fileContentsRequest.nPositionHigh = positionhigh;
fileContentsRequest.cbRequested = nreq;
fileContentsRequest.clipDataId = 0;
2022-07-01 12:04:22 +03:00
fileContentsRequest.common.msgFlags = 0;
2019-11-06 17:24:51 +03:00
rc = clipboard->context->ClientFileContentsRequest(clipboard->context, &fileContentsRequest);
2015-10-22 10:31:47 +03:00
if (WaitForSingleObject(clipboard->req_fevent, INFINITE) != WAIT_OBJECT_0)
rc = ERROR_INTERNAL_ERROR;
else if (!ResetEvent(clipboard->req_fevent))
rc = ERROR_INTERNAL_ERROR;
2015-10-22 10:31:47 +03:00
return rc;
}
2019-11-06 17:24:51 +03:00
static UINT cliprdr_send_response_filecontents(wfClipboard* clipboard, UINT32 streamId, UINT32 size,
BYTE* data)
{
CLIPRDR_FILE_CONTENTS_RESPONSE fileContentsResponse;
2019-11-06 17:24:51 +03:00
if (!clipboard || !clipboard->context || !clipboard->context->ClientFileContentsResponse)
2015-10-22 10:31:47 +03:00
return ERROR_INTERNAL_ERROR;
fileContentsResponse.streamId = streamId;
fileContentsResponse.cbRequested = size;
fileContentsResponse.requestedData = data;
2022-07-01 12:04:22 +03:00
fileContentsResponse.common.msgFlags = CB_RESPONSE_OK;
2016-08-03 13:09:24 +03:00
return clipboard->context->ClientFileContentsResponse(clipboard->context,
2019-11-06 17:24:51 +03:00
&fileContentsResponse);
}
2019-11-06 17:24:51 +03:00
static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
static wfClipboard* clipboard = NULL;
2013-11-21 09:45:16 +04:00
switch (Msg)
{
2016-08-03 13:09:24 +03:00
case WM_CREATE:
DEBUG_CLIPRDR("info: WM_CREATE");
2019-11-06 17:24:51 +03:00
clipboard = (wfClipboard*)((CREATESTRUCT*)lParam)->lpCreateParams;
2016-08-03 13:09:24 +03:00
clipboard->hwnd = hWnd;
2016-08-03 13:09:24 +03:00
if (!clipboard->legacyApi)
clipboard->AddClipboardFormatListener(hWnd);
else
clipboard->hWndNextViewer = SetClipboardViewer(hWnd);
2016-08-03 13:09:24 +03:00
break;
2016-08-03 13:09:24 +03:00
case WM_CLOSE:
DEBUG_CLIPRDR("info: WM_CLOSE");
2016-08-03 13:09:24 +03:00
if (!clipboard->legacyApi)
clipboard->RemoveClipboardFormatListener(hWnd);
2016-08-03 13:09:24 +03:00
break;
2016-08-03 13:09:24 +03:00
case WM_DESTROY:
if (clipboard->legacyApi)
ChangeClipboardChain(hWnd, clipboard->hWndNextViewer);
break;
case WM_CLIPBOARDUPDATE:
DEBUG_CLIPRDR("info: WM_CLIPBOARDUPDATE");
if (clipboard->sync)
2015-10-22 10:31:47 +03:00
{
2016-08-03 13:09:24 +03:00
if ((GetClipboardOwner() != clipboard->hwnd) &&
(S_FALSE == OleIsCurrentClipboard(clipboard->data_obj)))
2013-11-21 09:45:16 +04:00
{
2016-08-03 13:09:24 +03:00
if (clipboard->hmem)
{
GlobalFree(clipboard->hmem);
clipboard->hmem = NULL;
}
2015-10-22 10:31:47 +03:00
2016-08-03 13:09:24 +03:00
cliprdr_send_format_list(clipboard);
}
}
break;
2016-08-03 13:09:24 +03:00
case WM_RENDERALLFORMATS:
DEBUG_CLIPRDR("info: WM_RENDERALLFORMATS");
2015-10-22 10:31:47 +03:00
2016-08-03 13:09:24 +03:00
/* discard all contexts in clipboard */
if (!try_open_clipboard(clipboard->hwnd))
2013-11-21 09:45:16 +04:00
{
2016-08-03 13:09:24 +03:00
DEBUG_CLIPRDR("OpenClipboard failed with 0x%x", GetLastError());
break;
}
2016-08-03 13:09:24 +03:00
EmptyClipboard();
CloseClipboard();
break;
2016-08-03 13:09:24 +03:00
case WM_RENDERFORMAT:
DEBUG_CLIPRDR("info: WM_RENDERFORMAT");
2019-11-06 17:24:51 +03:00
if (cliprdr_send_data_request(clipboard, (UINT32)wParam) != 0)
{
2016-08-03 13:09:24 +03:00
DEBUG_CLIPRDR("error: cliprdr_send_data_request failed.");
break;
}
2019-11-06 17:24:51 +03:00
if (!SetClipboardData((UINT)wParam, clipboard->hmem))
2016-08-03 13:09:24 +03:00
{
DEBUG_CLIPRDR("SetClipboardData failed with 0x%x", GetLastError());
2016-08-03 13:09:24 +03:00
if (clipboard->hmem)
{
GlobalFree(clipboard->hmem);
clipboard->hmem = NULL;
}
}
2016-08-03 13:09:24 +03:00
/* Note: GlobalFree() is not needed when success */
break;
2016-08-03 13:09:24 +03:00
case WM_DRAWCLIPBOARD:
if (clipboard->legacyApi)
2013-11-21 09:45:16 +04:00
{
2016-08-03 13:09:24 +03:00
if ((GetClipboardOwner() != clipboard->hwnd) &&
(S_FALSE == OleIsCurrentClipboard(clipboard->data_obj)))
{
2016-08-03 13:09:24 +03:00
cliprdr_send_format_list(clipboard);
}
2016-08-03 13:09:24 +03:00
SendMessage(clipboard->hWndNextViewer, Msg, wParam, lParam);
}
2016-08-03 13:09:24 +03:00
break;
2016-08-03 13:09:24 +03:00
case WM_CHANGECBCHAIN:
if (clipboard->legacyApi)
{
2019-11-06 17:24:51 +03:00
HWND hWndCurrViewer = (HWND)wParam;
HWND hWndNextViewer = (HWND)lParam;
2016-08-03 13:09:24 +03:00
if (hWndCurrViewer == clipboard->hWndNextViewer)
clipboard->hWndNextViewer = hWndNextViewer;
else if (clipboard->hWndNextViewer)
SendMessage(clipboard->hWndNextViewer, Msg, wParam, lParam);
}
break;
2016-08-03 13:09:24 +03:00
case WM_CLIPRDR_MESSAGE:
DEBUG_CLIPRDR("info: WM_CLIPRDR_MESSAGE");
switch (wParam)
{
case OLE_SETCLIPBOARD:
DEBUG_CLIPRDR("info: OLE_SETCLIPBOARD");
2018-11-28 16:44:26 +03:00
if (S_FALSE == OleIsCurrentClipboard(clipboard->data_obj))
2016-08-03 13:09:24 +03:00
{
2018-11-28 16:44:26 +03:00
if (wf_create_file_obj(clipboard, &clipboard->data_obj))
2016-08-03 13:09:24 +03:00
{
2018-11-28 16:44:26 +03:00
if (OleSetClipboard(clipboard->data_obj) != S_OK)
{
wf_destroy_file_obj(clipboard->data_obj);
clipboard->data_obj = NULL;
}
2016-08-03 13:09:24 +03:00
}
}
break;
default:
break;
}
break;
case WM_DESTROYCLIPBOARD:
case WM_ASKCBFORMATNAME:
case WM_HSCROLLCLIPBOARD:
case WM_PAINTCLIPBOARD:
case WM_SIZECLIPBOARD:
case WM_VSCROLLCLIPBOARD:
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}
2014-10-23 21:11:20 +04:00
static int create_cliprdr_window(wfClipboard* clipboard)
{
WNDCLASSEX wnd_cls;
ZeroMemory(&wnd_cls, sizeof(WNDCLASSEX));
2014-10-23 21:11:20 +04:00
wnd_cls.cbSize = sizeof(WNDCLASSEX);
wnd_cls.style = CS_OWNDC;
wnd_cls.lpfnWndProc = cliprdr_proc;
wnd_cls.cbClsExtra = 0;
wnd_cls.cbWndExtra = 0;
wnd_cls.hIcon = NULL;
wnd_cls.hCursor = NULL;
wnd_cls.hbrBackground = NULL;
2014-10-23 21:11:20 +04:00
wnd_cls.lpszMenuName = NULL;
wnd_cls.lpszClassName = _T("ClipboardHiddenMessageProcessor");
2014-10-23 21:11:20 +04:00
wnd_cls.hInstance = GetModuleHandle(NULL);
wnd_cls.hIconSm = NULL;
RegisterClassEx(&wnd_cls);
2019-11-06 17:24:51 +03:00
clipboard->hwnd =
CreateWindowEx(WS_EX_LEFT, _T("ClipboardHiddenMessageProcessor"), _T("rdpclip"), 0, 0, 0, 0,
0, HWND_MESSAGE, NULL, GetModuleHandle(NULL), clipboard);
if (!clipboard->hwnd)
2013-11-21 09:45:16 +04:00
{
DEBUG_CLIPRDR("error: CreateWindowEx failed with %x.", GetLastError());
return -1;
}
return 0;
}
static DWORD WINAPI cliprdr_thread_func(LPVOID arg)
{
int ret;
2014-02-10 09:34:17 +04:00
MSG msg;
BOOL mcode;
2019-11-06 17:24:51 +03:00
wfClipboard* clipboard = (wfClipboard*)arg;
OleInitialize(0);
if ((ret = create_cliprdr_window(clipboard)) != 0)
2013-11-21 09:45:16 +04:00
{
OleUninitialize();
DEBUG_CLIPRDR("error: create clipboard window failed.");
return 0;
}
while ((mcode = GetMessage(&msg, 0, 0, 0)) != 0)
2013-11-21 09:45:16 +04:00
{
if (mcode == -1)
{
DEBUG_CLIPRDR("error: clipboard thread GetMessage failed.");
break;
2013-11-21 09:45:16 +04:00
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
OleUninitialize();
return 0;
}
static void clear_file_array(wfClipboard* clipboard)
{
2015-10-22 10:31:47 +03:00
size_t i;
if (!clipboard)
return;
/* clear file_names array */
if (clipboard->file_names)
{
for (i = 0; i < clipboard->nFiles; i++)
{
2015-05-11 10:07:39 +03:00
free(clipboard->file_names[i]);
clipboard->file_names[i] = NULL;
}
2015-10-22 10:31:47 +03:00
2016-08-03 13:09:24 +03:00
free(clipboard->file_names);
2015-10-22 10:31:47 +03:00
clipboard->file_names = NULL;
}
/* clear fileDescriptor array */
if (clipboard->fileDescriptor)
{
for (i = 0; i < clipboard->nFiles; i++)
{
2015-05-11 10:07:39 +03:00
free(clipboard->fileDescriptor[i]);
clipboard->fileDescriptor[i] = NULL;
}
2016-08-03 13:09:24 +03:00
free(clipboard->fileDescriptor);
2015-10-22 10:31:47 +03:00
clipboard->fileDescriptor = NULL;
}
2015-10-22 10:31:47 +03:00
clipboard->file_array_size = 0;
clipboard->nFiles = 0;
}
2019-11-06 17:24:51 +03:00
static BOOL wf_cliprdr_get_file_contents(WCHAR* file_name, BYTE* buffer, LONG positionLow,
LONG positionHigh, DWORD nRequested, DWORD* puSize)
{
2015-10-22 10:31:47 +03:00
BOOL res = FALSE;
HANDLE hFile;
2015-10-22 10:31:47 +03:00
DWORD nGet, rc;
2014-10-23 06:32:55 +04:00
if (!file_name || !buffer || !puSize)
{
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "get file contents Invalid Arguments.");
return FALSE;
}
2015-10-22 10:31:47 +03:00
2019-11-06 17:24:51 +03:00
hFile = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
2016-08-03 13:09:24 +03:00
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL);
2015-10-22 10:31:47 +03:00
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
2015-10-22 10:31:47 +03:00
rc = SetFilePointer(hFile, positionLow, &positionHigh, FILE_BEGIN);
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (rc == INVALID_SET_FILE_POINTER)
goto error;
if (!ReadFile(hFile, buffer, nRequested, &nGet, NULL))
{
DEBUG_CLIPRDR("ReadFile failed with 0x%08lX.", GetLastError());
2015-10-22 10:31:47 +03:00
goto error;
}
2014-10-23 06:32:55 +04:00
2015-10-22 10:31:47 +03:00
res = TRUE;
error:
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (!CloseHandle(hFile))
res = FALSE;
2015-10-22 10:31:47 +03:00
if (res)
*puSize = nGet;
2015-10-22 10:31:47 +03:00
return res;
}
/* path_name has a '\' at the end. e.g. c:\newfolder\, file_name is c:\newfolder\new.txt */
2019-11-06 17:24:51 +03:00
static FILEDESCRIPTORW* wf_cliprdr_get_file_descriptor(WCHAR* file_name, size_t pathLen)
{
HANDLE hFile;
2014-10-23 06:32:55 +04:00
FILEDESCRIPTORW* fd;
2019-11-06 17:24:51 +03:00
fd = (FILEDESCRIPTORW*)calloc(1, sizeof(FILEDESCRIPTORW));
2014-05-10 17:50:36 +04:00
if (!fd)
return NULL;
2019-11-06 17:24:51 +03:00
hFile = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL);
2014-05-10 17:50:36 +04:00
if (hFile == INVALID_HANDLE_VALUE)
{
free(fd);
return NULL;
}
fd->dwFlags = FD_ATTRIBUTES | FD_FILESIZE | FD_WRITESTIME | FD_PROGRESSUI;
fd->dwFileAttributes = GetFileAttributes(file_name);
2014-05-10 17:50:36 +04:00
if (!GetFileTime(hFile, NULL, NULL, &fd->ftLastWriteTime))
{
fd->dwFlags &= ~FD_WRITESTIME;
}
2014-05-10 17:50:36 +04:00
fd->nFileSizeLow = GetFileSize(hFile, &fd->nFileSizeHigh);
2014-05-10 17:50:36 +04:00
wcscpy_s(fd->cFileName, sizeof(fd->cFileName) / 2, file_name + pathLen);
CloseHandle(hFile);
return fd;
}
2015-10-22 10:31:47 +03:00
static BOOL wf_cliprdr_array_ensure_capacity(wfClipboard* clipboard)
{
2015-10-22 10:31:47 +03:00
if (!clipboard)
return FALSE;
if (clipboard->nFiles == clipboard->file_array_size)
{
2015-10-22 10:31:47 +03:00
size_t new_size;
2016-08-03 13:09:24 +03:00
FILEDESCRIPTORW** new_fd;
WCHAR** new_name;
2015-10-22 10:31:47 +03:00
new_size = (clipboard->file_array_size + 1) * 2;
2019-11-06 17:24:51 +03:00
new_fd = (FILEDESCRIPTORW**)realloc(clipboard->fileDescriptor,
new_size * sizeof(FILEDESCRIPTORW*));
2016-08-03 13:09:24 +03:00
if (new_fd)
clipboard->fileDescriptor = new_fd;
2019-11-06 17:24:51 +03:00
new_name = (WCHAR**)realloc(clipboard->file_names, new_size * sizeof(WCHAR*));
2016-08-03 13:09:24 +03:00
if (new_name)
clipboard->file_names = new_name;
if (!new_fd || !new_name)
2015-10-22 10:31:47 +03:00
return FALSE;
2015-10-22 10:31:47 +03:00
clipboard->file_array_size = new_size;
}
2015-10-22 10:31:47 +03:00
return TRUE;
}
2019-11-06 17:24:51 +03:00
static BOOL wf_cliprdr_add_to_file_arrays(wfClipboard* clipboard, WCHAR* full_file_name,
size_t pathLen)
{
2015-10-22 10:31:47 +03:00
if (!wf_cliprdr_array_ensure_capacity(clipboard))
return FALSE;
/* add to name array */
2019-11-06 17:24:51 +03:00
clipboard->file_names[clipboard->nFiles] = (LPWSTR)malloc(MAX_PATH * 2);
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (!clipboard->file_names[clipboard->nFiles])
return FALSE;
wcscpy_s(clipboard->file_names[clipboard->nFiles], MAX_PATH, full_file_name);
/* add to descriptor array */
2015-10-22 10:31:47 +03:00
clipboard->fileDescriptor[clipboard->nFiles] =
2016-08-03 13:09:24 +03:00
wf_cliprdr_get_file_descriptor(full_file_name, pathLen);
2015-10-22 10:31:47 +03:00
if (!clipboard->fileDescriptor[clipboard->nFiles])
{
2016-08-03 13:09:24 +03:00
free(clipboard->file_names[clipboard->nFiles]);
2015-10-22 10:31:47 +03:00
return FALSE;
}
clipboard->nFiles++;
2015-10-22 10:31:47 +03:00
return TRUE;
}
2019-11-06 17:24:51 +03:00
static BOOL wf_cliprdr_traverse_directory(wfClipboard* clipboard, WCHAR* Dir, size_t pathLen)
{
HANDLE hFind;
2014-10-23 06:32:55 +04:00
WCHAR DirSpec[MAX_PATH];
WIN32_FIND_DATA FindFileData;
2015-10-22 10:31:47 +03:00
if (!clipboard || !Dir)
return FALSE;
2014-10-23 21:11:20 +04:00
StringCchCopy(DirSpec, MAX_PATH, Dir);
StringCchCat(DirSpec, MAX_PATH, TEXT("\\*"));
2014-10-23 06:32:55 +04:00
hFind = FindFirstFile(DirSpec, &FindFileData);
2014-10-23 06:32:55 +04:00
if (hFind == INVALID_HANDLE_VALUE)
{
DEBUG_CLIPRDR("FindFirstFile failed with 0x%x.", GetLastError());
2015-10-22 10:31:47 +03:00
return FALSE;
}
2014-10-23 06:32:55 +04:00
while (FindNextFile(hFind, &FindFileData))
{
2019-11-06 17:24:51 +03:00
if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 &&
wcscmp(FindFileData.cFileName, _T(".")) == 0 ||
wcscmp(FindFileData.cFileName, _T("..")) == 0)
{
continue;
}
2016-08-03 13:09:24 +03:00
if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
{
2014-10-23 06:32:55 +04:00
WCHAR DirAdd[MAX_PATH];
2014-10-23 21:11:20 +04:00
StringCchCopy(DirAdd, MAX_PATH, Dir);
StringCchCat(DirAdd, MAX_PATH, _T("\\"));
2014-10-23 21:11:20 +04:00
StringCchCat(DirAdd, MAX_PATH, FindFileData.cFileName);
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (!wf_cliprdr_add_to_file_arrays(clipboard, DirAdd, pathLen))
return FALSE;
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (!wf_cliprdr_traverse_directory(clipboard, DirAdd, pathLen))
return FALSE;
}
else
{
WCHAR fileName[MAX_PATH];
2014-10-23 21:11:20 +04:00
StringCchCopy(fileName, MAX_PATH, Dir);
StringCchCat(fileName, MAX_PATH, _T("\\"));
2014-10-23 21:11:20 +04:00
StringCchCat(fileName, MAX_PATH, FindFileData.cFileName);
2015-10-22 10:31:47 +03:00
if (!wf_cliprdr_add_to_file_arrays(clipboard, fileName, pathLen))
return FALSE;
}
}
FindClose(hFind);
2015-10-22 10:31:47 +03:00
return TRUE;
}
2015-10-22 10:31:47 +03:00
static UINT wf_cliprdr_send_client_capabilities(wfClipboard* clipboard)
{
CLIPRDR_CAPABILITIES capabilities;
CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet;
2019-11-06 17:24:51 +03:00
if (!clipboard || !clipboard->context || !clipboard->context->ClientCapabilities)
2015-10-22 10:31:47 +03:00
return ERROR_INTERNAL_ERROR;
capabilities.cCapabilitiesSets = 1;
2019-11-06 17:24:51 +03:00
capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*)&(generalCapabilitySet);
generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL;
generalCapabilitySet.capabilitySetLength = 12;
generalCapabilitySet.version = CB_CAPS_VERSION_2;
2015-10-22 10:31:47 +03:00
generalCapabilitySet.generalFlags =
2019-11-06 17:24:51 +03:00
CB_USE_LONG_FORMAT_NAMES | CB_STREAM_FILECLIP_ENABLED | CB_FILECLIP_NO_FILE_PATHS;
return clipboard->context->ClientCapabilities(clipboard->context, &capabilities);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
2015-10-22 10:31:47 +03:00
static UINT wf_cliprdr_monitor_ready(CliprdrClientContext* context,
const CLIPRDR_MONITOR_READY* monitorReady)
{
2015-10-22 10:31:47 +03:00
UINT rc;
2019-11-06 17:24:51 +03:00
wfClipboard* clipboard = (wfClipboard*)context->custom;
2015-10-22 10:31:47 +03:00
if (!context || !monitorReady)
return ERROR_INTERNAL_ERROR;
clipboard->sync = TRUE;
2015-10-22 10:31:47 +03:00
rc = wf_cliprdr_send_client_capabilities(clipboard);
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (rc != CHANNEL_RC_OK)
return rc;
2015-10-22 10:31:47 +03:00
return cliprdr_send_format_list(clipboard);
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
2015-10-22 10:31:47 +03:00
static UINT wf_cliprdr_server_capabilities(CliprdrClientContext* context,
2019-11-06 17:24:51 +03:00
const CLIPRDR_CAPABILITIES* capabilities)
{
UINT32 index;
CLIPRDR_CAPABILITY_SET* capabilitySet;
2019-11-06 17:24:51 +03:00
wfClipboard* clipboard = (wfClipboard*)context->custom;
2015-10-22 10:31:47 +03:00
if (!context || !capabilities)
return ERROR_INTERNAL_ERROR;
for (index = 0; index < capabilities->cCapabilitiesSets; index++)
{
capabilitySet = &(capabilities->capabilitySets[index]);
if ((capabilitySet->capabilitySetType == CB_CAPSTYPE_GENERAL) &&
2016-08-03 13:09:24 +03:00
(capabilitySet->capabilitySetLength >= CB_CAPSTYPE_GENERAL_LEN))
{
2019-11-06 17:24:51 +03:00
CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet =
(CLIPRDR_GENERAL_CAPABILITY_SET*)capabilitySet;
clipboard->capabilities = generalCapabilitySet->generalFlags;
break;
}
}
2015-10-22 10:31:47 +03:00
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
2015-10-22 10:31:47 +03:00
static UINT wf_cliprdr_server_format_list(CliprdrClientContext* context,
2019-11-06 17:24:51 +03:00
const CLIPRDR_FORMAT_LIST* formatList)
{
2015-10-22 10:31:47 +03:00
UINT rc = ERROR_INTERNAL_ERROR;
UINT32 i;
formatMapping* mapping;
CLIPRDR_FORMAT* format;
2019-11-06 17:24:51 +03:00
wfClipboard* clipboard = (wfClipboard*)context->custom;
2015-10-22 10:31:47 +03:00
if (!clear_format_map(clipboard))
return ERROR_INTERNAL_ERROR;
2015-10-22 10:31:47 +03:00
for (i = 0; i < formatList->numFormats; i++)
{
format = &(formatList->formats[i]);
2015-10-22 10:31:47 +03:00
mapping = &(clipboard->format_mappings[i]);
mapping->remote_format_id = format->formatId;
if (format->formatName)
{
2016-08-03 13:09:24 +03:00
int size = MultiByteToWideChar(CP_UTF8, 0, format->formatName,
2019-11-06 17:24:51 +03:00
strlen(format->formatName), NULL, 0);
2015-10-22 10:31:47 +03:00
mapping->name = calloc(size + 1, sizeof(WCHAR));
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (mapping->name)
{
MultiByteToWideChar(CP_UTF8, 0, format->formatName, strlen(format->formatName),
2016-08-03 13:09:24 +03:00
mapping->name, size);
2019-11-06 17:24:51 +03:00
mapping->local_format_id = RegisterClipboardFormatW((LPWSTR)mapping->name);
2015-10-22 10:31:47 +03:00
}
}
else
{
mapping->name = NULL;
mapping->local_format_id = mapping->remote_format_id;
}
clipboard->map_size++;
map_ensure_capacity(clipboard);
}
if (file_transferring(clipboard))
2013-11-21 09:45:16 +04:00
{
2015-10-22 10:31:47 +03:00
if (PostMessage(clipboard->hwnd, WM_CLIPRDR_MESSAGE, OLE_SETCLIPBOARD, 0))
rc = CHANNEL_RC_OK;
2013-11-21 09:45:16 +04:00
}
else
2013-11-21 09:45:16 +04:00
{
if (!try_open_clipboard(clipboard->hwnd))
return CHANNEL_RC_OK; /* Ignore, other app holding clipboard */
if (EmptyClipboard())
{
2019-11-06 17:24:51 +03:00
for (i = 0; i < (UINT32)clipboard->map_size; i++)
SetClipboardData(clipboard->format_mappings[i].local_format_id, NULL);
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
rc = CHANNEL_RC_OK;
}
2015-10-22 10:31:47 +03:00
if (!CloseClipboard() && GetLastError())
return ERROR_INTERNAL_ERROR;
2013-11-21 09:45:16 +04:00
}
2015-10-22 10:31:47 +03:00
return rc;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
2019-11-06 17:24:51 +03:00
static UINT
wf_cliprdr_server_format_list_response(CliprdrClientContext* context,
const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
{
2015-10-22 10:31:47 +03:00
(void)context;
(void)formatListResponse;
2022-07-01 12:04:22 +03:00
if (formatListResponse->common.msgFlags != CB_RESPONSE_OK)
return E_FAIL;
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
2019-11-06 17:24:51 +03:00
static UINT
wf_cliprdr_server_lock_clipboard_data(CliprdrClientContext* context,
const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData)
{
2015-10-22 10:31:47 +03:00
(void)context;
(void)lockClipboardData;
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
2019-11-06 17:24:51 +03:00
static UINT
wf_cliprdr_server_unlock_clipboard_data(CliprdrClientContext* context,
const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData)
{
2015-10-22 10:31:47 +03:00
(void)context;
(void)unlockClipboardData;
return CHANNEL_RC_OK;
}
2019-11-06 17:24:51 +03:00
static BOOL wf_cliprdr_process_filename(wfClipboard* clipboard, WCHAR* wFileName, size_t str_len)
2015-10-22 10:31:47 +03:00
{
size_t pathLen;
size_t offset = str_len;
if (!clipboard || !wFileName)
return FALSE;
/* find the last '\' in full file name */
2016-08-03 13:09:24 +03:00
while (offset > 0)
2015-10-22 10:31:47 +03:00
{
if (wFileName[offset] == L'\\')
break;
else
offset--;
}
pathLen = offset + 1;
if (!wf_cliprdr_add_to_file_arrays(clipboard, wFileName, pathLen))
return FALSE;
2019-11-06 17:24:51 +03:00
if ((clipboard->fileDescriptor[clipboard->nFiles - 1]->dwFileAttributes &
2016-08-03 13:09:24 +03:00
FILE_ATTRIBUTE_DIRECTORY) != 0)
2015-10-22 10:31:47 +03:00
{
/* this is a directory */
if (!wf_cliprdr_traverse_directory(clipboard, wFileName, pathLen))
return FALSE;
}
return TRUE;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
2019-11-06 17:24:51 +03:00
static UINT
wf_cliprdr_server_format_data_request(CliprdrClientContext* context,
const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
{
2015-10-22 10:31:47 +03:00
UINT rc;
size_t size = 0;
void* buff = NULL;
char* globlemem = NULL;
HANDLE hClipdata = NULL;
UINT32 requestedFormatId;
CLIPRDR_FORMAT_DATA_RESPONSE response;
2015-10-22 10:31:47 +03:00
wfClipboard* clipboard;
if (!context || !formatDataRequest)
return ERROR_INTERNAL_ERROR;
2019-11-06 17:24:51 +03:00
clipboard = (wfClipboard*)context->custom;
2015-10-22 10:31:47 +03:00
if (!clipboard)
return ERROR_INTERNAL_ERROR;
requestedFormatId = formatDataRequest->requestedFormatId;
2015-10-22 10:31:47 +03:00
if (requestedFormatId == RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW))
2013-11-21 09:45:16 +04:00
{
2015-10-22 10:31:47 +03:00
size_t len;
size_t i;
2014-10-23 06:32:55 +04:00
WCHAR* wFileName;
HRESULT result;
LPDATAOBJECT dataObj;
FORMATETC format_etc;
STGMEDIUM stg_medium;
2014-10-23 06:32:55 +04:00
DROPFILES* dropFiles;
2015-10-22 10:31:47 +03:00
FILEGROUPDESCRIPTORW* groupDsc;
result = OleGetClipboard(&dataObj);
2014-10-23 06:32:55 +04:00
if (FAILED(result))
return ERROR_INTERNAL_ERROR;
ZeroMemory(&format_etc, sizeof(FORMATETC));
ZeroMemory(&stg_medium, sizeof(STGMEDIUM));
2015-10-22 10:31:47 +03:00
/* get DROPFILES struct from OLE */
format_etc.cfFormat = CF_HDROP;
format_etc.tymed = TYMED_HGLOBAL;
format_etc.dwAspect = 1;
format_etc.lindex = -1;
result = IDataObject_GetData(dataObj, &format_etc, &stg_medium);
2016-08-03 13:09:24 +03:00
if (FAILED(result))
{
2015-10-22 10:31:47 +03:00
DEBUG_CLIPRDR("dataObj->GetData failed.");
goto exit;
}
2019-11-06 17:24:51 +03:00
dropFiles = (DROPFILES*)GlobalLock(stg_medium.hGlobal);
2015-10-22 10:31:47 +03:00
if (!dropFiles)
{
GlobalUnlock(stg_medium.hGlobal);
ReleaseStgMedium(&stg_medium);
2015-10-22 10:31:47 +03:00
clipboard->nFiles = 0;
goto exit;
}
2015-10-22 10:31:47 +03:00
clear_file_array(clipboard);
2015-10-22 10:31:47 +03:00
if (dropFiles->fWide)
{
/* dropFiles contains file names */
for (wFileName = (WCHAR*)((char*)dropFiles + dropFiles->pFiles);
2016-08-03 13:09:24 +03:00
(len = wcslen(wFileName)) > 0; wFileName += len + 1)
{
2015-10-22 10:31:47 +03:00
wf_cliprdr_process_filename(clipboard, wFileName, wcslen(wFileName));
}
2015-10-22 10:31:47 +03:00
}
else
{
char* p;
2019-11-06 17:24:51 +03:00
for (p = (char*)((char*)dropFiles + dropFiles->pFiles); (len = strlen(p)) > 0;
p += len + 1, clipboard->nFiles++)
{
2015-10-22 10:31:47 +03:00
int cchWideChar;
2016-08-03 13:09:24 +03:00
WCHAR* wFileName;
2015-10-22 10:31:47 +03:00
cchWideChar = MultiByteToWideChar(CP_ACP, MB_COMPOSITE, p, len, NULL, 0);
2019-11-06 17:24:51 +03:00
wFileName = (LPWSTR)calloc(cchWideChar, sizeof(WCHAR));
2015-10-22 10:31:47 +03:00
MultiByteToWideChar(CP_ACP, MB_COMPOSITE, p, len, wFileName, cchWideChar);
wf_cliprdr_process_filename(clipboard, wFileName, cchWideChar);
}
2015-10-22 10:31:47 +03:00
}
2015-10-22 10:31:47 +03:00
GlobalUnlock(stg_medium.hGlobal);
ReleaseStgMedium(&stg_medium);
2016-08-03 13:09:24 +03:00
exit:
2015-10-22 10:31:47 +03:00
size = 4 + clipboard->nFiles * sizeof(FILEDESCRIPTORW);
2019-11-06 17:24:51 +03:00
groupDsc = (FILEGROUPDESCRIPTORW*)malloc(size);
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (groupDsc)
{
groupDsc->cItems = clipboard->nFiles;
2016-08-03 13:09:24 +03:00
for (i = 0; i < clipboard->nFiles; i++)
{
if (clipboard->fileDescriptor[i])
2015-10-22 10:31:47 +03:00
groupDsc->fgd[i] = *clipboard->fileDescriptor[i];
}
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
buff = groupDsc;
}
2016-08-03 13:09:24 +03:00
IDataObject_Release(dataObj);
}
else
{
/* Ignore if other app is holding the clipboard */
if (try_open_clipboard(clipboard->hwnd))
{
hClipdata = GetClipboardData(requestedFormatId);
if (!hClipdata)
{
CloseClipboard();
return ERROR_INTERNAL_ERROR;
}
globlemem = (char*)GlobalLock(hClipdata);
size = (int)GlobalSize(hClipdata);
buff = malloc(size);
CopyMemory(buff, globlemem, size);
GlobalUnlock(hClipdata);
CloseClipboard();
}
}
2022-07-01 12:04:22 +03:00
response.common.msgFlags = CB_RESPONSE_OK;
response.common.dataLen = size;
2019-11-06 17:24:51 +03:00
response.requestedFormatData = (BYTE*)buff;
rc = clipboard->context->ClientFormatDataResponse(clipboard->context, &response);
free(buff);
2015-10-22 10:31:47 +03:00
return rc;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
2019-11-06 17:24:51 +03:00
static UINT
wf_cliprdr_server_format_data_response(CliprdrClientContext* context,
const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
{
BYTE* data;
HANDLE hMem;
2015-10-22 10:31:47 +03:00
wfClipboard* clipboard;
if (!context || !formatDataResponse)
return ERROR_INTERNAL_ERROR;
2022-07-01 12:04:22 +03:00
if (formatDataResponse->common.msgFlags != CB_RESPONSE_OK)
make cppcheck even more happier: [channels/tsmf/client/gstreamer/tsmf_X11.c:317] -> [channels/tsmf/client/gstreamer/tsmf_X11.c:322]: (warning) Either the condition '!decoder' is redundant or there is possible null pointer dereference: decoder. [channels/tsmf/client/gstreamer/tsmf_X11.c:470] -> [channels/tsmf/client/gstreamer/tsmf_X11.c:475]: (warning) Either the condition '!decoder' is redundant or there is possible null pointer dereference: decoder. [channels/tsmf/client/gstreamer/tsmf_X11.c:472] -> [channels/tsmf/client/gstreamer/tsmf_X11.c:475]: (warning) Either the condition '!decoder' is redundant or there is possible null pointer dereference: decoder. [channels/tsmf/client/tsmf_media.c:179] -> [channels/tsmf/client/tsmf_media.c:181]: (warning) Either the condition '!stream' is redundant or there is possible null pointer dereference: stream. [client/Windows/wf_cliprdr.c:2219] -> [client/Windows/wf_cliprdr.c:2222]: (warning) Either the condition '!formatDataResponse' is redundant or there is possible null pointer dereference: formatDataResponse [client/Windows/wf_cliprdr.c:2445] -> [client/Windows/wf_cliprdr.c:2448]: (warning) Either the condition '!fileContentsResponse' is redundant or there is possible null pointer dereference: fileContentsResponse. [client/X11/xf_cliprdr.c:911] -> [client/X11/xf_cliprdr.c:913]: (warning) Either the condition '!clipboard' is redundant or there is possible null pointer dereference: clipboard. [client/X11/xf_graphics.c:504] -> [client/X11/xf_graphics.c:506]: (warning) Either the condition '!xfc' is redundant or there is possible null pointer dereference: xfc. [libfreerdp/core/transport.c:861] -> [libfreerdp/core/transport.c:863]: (warning) Either the condition '!transport' is redundant or there is possible null pointer dereference: transport. [server/shadow/shadow_server.c:777] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:778] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:779] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:781] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:782] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:783] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:784] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:785] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:787] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:789] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server.
2017-01-26 12:44:19 +03:00
return E_FAIL;
2019-11-06 17:24:51 +03:00
clipboard = (wfClipboard*)context->custom;
2015-10-22 10:31:47 +03:00
if (!clipboard)
return ERROR_INTERNAL_ERROR;
2022-07-01 12:04:22 +03:00
hMem = GlobalAlloc(GMEM_MOVEABLE, formatDataResponse->common.dataLen);
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (!hMem)
return ERROR_INTERNAL_ERROR;
2019-11-06 17:24:51 +03:00
data = (BYTE*)GlobalLock(hMem);
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (!data)
{
GlobalFree(hMem);
return ERROR_INTERNAL_ERROR;
}
2022-07-01 12:04:22 +03:00
CopyMemory(data, formatDataResponse->requestedFormatData, formatDataResponse->common.dataLen);
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (!GlobalUnlock(hMem) && GetLastError())
{
GlobalFree(hMem);
return ERROR_INTERNAL_ERROR;
}
clipboard->hmem = hMem;
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (!SetEvent(clipboard->response_data_event))
return ERROR_INTERNAL_ERROR;
return CHANNEL_RC_OK;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
2019-11-06 17:24:51 +03:00
static UINT
wf_cliprdr_server_file_contents_request(CliprdrClientContext* context,
const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
{
2015-10-22 10:31:47 +03:00
DWORD uSize = 0;
BYTE* pData = NULL;
2019-11-06 17:24:51 +03:00
HRESULT hRet = S_OK;
FORMATETC vFormatEtc;
LPDATAOBJECT pDataObj = NULL;
STGMEDIUM vStgMedium;
BOOL bIsStreamFile = TRUE;
2019-11-06 17:24:51 +03:00
static LPSTREAM pStreamStc = NULL;
static UINT32 uStreamIdStc = 0;
2015-10-22 10:31:47 +03:00
wfClipboard* clipboard;
UINT rc = ERROR_INTERNAL_ERROR;
UINT sRc;
UINT32 cbRequested;
2015-10-22 10:31:47 +03:00
if (!context || !fileContentsRequest)
return ERROR_INTERNAL_ERROR;
2019-11-06 17:24:51 +03:00
clipboard = (wfClipboard*)context->custom;
2015-10-22 10:31:47 +03:00
if (!clipboard)
return ERROR_INTERNAL_ERROR;
cbRequested = fileContentsRequest->cbRequested;
if (fileContentsRequest->dwFlags == FILECONTENTS_SIZE)
cbRequested = sizeof(UINT64);
2019-11-06 17:24:51 +03:00
pData = (BYTE*)calloc(1, cbRequested);
2015-10-22 10:31:47 +03:00
if (!pData)
goto error;
hRet = OleGetClipboard(&pDataObj);
if (FAILED(hRet))
{
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "filecontents: get ole clipboard failed.");
goto error;
}
2015-10-22 10:31:47 +03:00
ZeroMemory(&vFormatEtc, sizeof(FORMATETC));
ZeroMemory(&vStgMedium, sizeof(STGMEDIUM));
2015-10-22 10:31:47 +03:00
vFormatEtc.cfFormat = RegisterClipboardFormat(CFSTR_FILECONTENTS);
vFormatEtc.tymed = TYMED_ISTREAM;
vFormatEtc.dwAspect = 1;
vFormatEtc.lindex = fileContentsRequest->listIndex;
vFormatEtc.ptd = NULL;
if ((uStreamIdStc != fileContentsRequest->streamId) || !pStreamStc)
{
LPENUMFORMATETC pEnumFormatEtc;
ULONG CeltFetched;
FORMATETC vFormatEtc2;
if (pStreamStc)
{
IStream_Release(pStreamStc);
pStreamStc = NULL;
}
bIsStreamFile = FALSE;
hRet = IDataObject_EnumFormatEtc(pDataObj, DATADIR_GET, &pEnumFormatEtc);
if (hRet == S_OK)
{
do
{
hRet = IEnumFORMATETC_Next(pEnumFormatEtc, 1, &vFormatEtc2, &CeltFetched);
if (hRet == S_OK)
{
2015-10-22 10:31:47 +03:00
if (vFormatEtc2.cfFormat == RegisterClipboardFormat(CFSTR_FILECONTENTS))
{
hRet = IDataObject_GetData(pDataObj, &vFormatEtc, &vStgMedium);
if (hRet == S_OK)
{
pStreamStc = vStgMedium.pstm;
uStreamIdStc = fileContentsRequest->streamId;
bIsStreamFile = TRUE;
}
2016-08-03 13:09:24 +03:00
break;
}
}
2019-11-06 17:24:51 +03:00
} while (hRet == S_OK);
}
}
if (bIsStreamFile == TRUE)
{
if (fileContentsRequest->dwFlags == FILECONTENTS_SIZE)
{
STATSTG vStatStg;
ZeroMemory(&vStatStg, sizeof(STATSTG));
hRet = IStream_Stat(pStreamStc, &vStatStg, STATFLAG_NONAME);
if (hRet == S_OK)
{
2019-11-06 17:24:51 +03:00
*((UINT32*)&pData[0]) = vStatStg.cbSize.LowPart;
*((UINT32*)&pData[4]) = vStatStg.cbSize.HighPart;
uSize = cbRequested;
}
}
else if (fileContentsRequest->dwFlags == FILECONTENTS_RANGE)
{
LARGE_INTEGER dlibMove;
ULARGE_INTEGER dlibNewPosition;
dlibMove.HighPart = fileContentsRequest->nPositionHigh;
dlibMove.LowPart = fileContentsRequest->nPositionLow;
hRet = IStream_Seek(pStreamStc, dlibMove, STREAM_SEEK_SET, &dlibNewPosition);
if (SUCCEEDED(hRet))
2019-11-06 17:24:51 +03:00
hRet = IStream_Read(pStreamStc, pData, cbRequested, (PULONG)&uSize);
}
}
else
{
if (fileContentsRequest->dwFlags == FILECONTENTS_SIZE)
{
if (clipboard->nFiles <= fileContentsRequest->listIndex)
goto error;
2019-11-06 17:24:51 +03:00
*((UINT32*)&pData[0]) =
2016-08-03 13:09:24 +03:00
clipboard->fileDescriptor[fileContentsRequest->listIndex]->nFileSizeLow;
2019-11-06 17:24:51 +03:00
*((UINT32*)&pData[4]) =
2016-08-03 13:09:24 +03:00
clipboard->fileDescriptor[fileContentsRequest->listIndex]->nFileSizeHigh;
uSize = cbRequested;
}
else if (fileContentsRequest->dwFlags == FILECONTENTS_RANGE)
{
BOOL bRet;
if (clipboard->nFiles <= fileContentsRequest->listIndex)
goto error;
2016-08-03 13:09:24 +03:00
bRet = wf_cliprdr_get_file_contents(
2019-11-06 17:24:51 +03:00
clipboard->file_names[fileContentsRequest->listIndex], pData,
fileContentsRequest->nPositionLow, fileContentsRequest->nPositionHigh, cbRequested,
&uSize);
if (bRet == FALSE)
{
WLog_ERR(TAG, "get file contents failed.");
uSize = 0;
goto error;
}
}
}
2015-10-22 10:31:47 +03:00
rc = CHANNEL_RC_OK;
error:
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (pDataObj)
IDataObject_Release(pDataObj);
if (uSize == 0)
{
free(pData);
pData = NULL;
}
2019-11-06 17:24:51 +03:00
sRc =
cliprdr_send_response_filecontents(clipboard, fileContentsRequest->streamId, uSize, pData);
free(pData);
2015-10-22 10:31:47 +03:00
if (sRc != CHANNEL_RC_OK)
return sRc;
2015-10-22 10:31:47 +03:00
return rc;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
2019-11-06 17:24:51 +03:00
static UINT
wf_cliprdr_server_file_contents_response(CliprdrClientContext* context,
const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse)
{
2015-10-22 10:31:47 +03:00
wfClipboard* clipboard;
if (!context || !fileContentsResponse)
return ERROR_INTERNAL_ERROR;
2022-07-01 12:04:22 +03:00
if (fileContentsResponse->common.msgFlags != CB_RESPONSE_OK)
make cppcheck even more happier: [channels/tsmf/client/gstreamer/tsmf_X11.c:317] -> [channels/tsmf/client/gstreamer/tsmf_X11.c:322]: (warning) Either the condition '!decoder' is redundant or there is possible null pointer dereference: decoder. [channels/tsmf/client/gstreamer/tsmf_X11.c:470] -> [channels/tsmf/client/gstreamer/tsmf_X11.c:475]: (warning) Either the condition '!decoder' is redundant or there is possible null pointer dereference: decoder. [channels/tsmf/client/gstreamer/tsmf_X11.c:472] -> [channels/tsmf/client/gstreamer/tsmf_X11.c:475]: (warning) Either the condition '!decoder' is redundant or there is possible null pointer dereference: decoder. [channels/tsmf/client/tsmf_media.c:179] -> [channels/tsmf/client/tsmf_media.c:181]: (warning) Either the condition '!stream' is redundant or there is possible null pointer dereference: stream. [client/Windows/wf_cliprdr.c:2219] -> [client/Windows/wf_cliprdr.c:2222]: (warning) Either the condition '!formatDataResponse' is redundant or there is possible null pointer dereference: formatDataResponse [client/Windows/wf_cliprdr.c:2445] -> [client/Windows/wf_cliprdr.c:2448]: (warning) Either the condition '!fileContentsResponse' is redundant or there is possible null pointer dereference: fileContentsResponse. [client/X11/xf_cliprdr.c:911] -> [client/X11/xf_cliprdr.c:913]: (warning) Either the condition '!clipboard' is redundant or there is possible null pointer dereference: clipboard. [client/X11/xf_graphics.c:504] -> [client/X11/xf_graphics.c:506]: (warning) Either the condition '!xfc' is redundant or there is possible null pointer dereference: xfc. [libfreerdp/core/transport.c:861] -> [libfreerdp/core/transport.c:863]: (warning) Either the condition '!transport' is redundant or there is possible null pointer dereference: transport. [server/shadow/shadow_server.c:777] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:778] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:779] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:781] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:782] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:783] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:784] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:785] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:787] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server. [server/shadow/shadow_server.c:789] -> [server/shadow/shadow_server.c:791]: (warning) Either the condition '!server' is redundant or there is possible null pointer dereference: server.
2017-01-26 12:44:19 +03:00
return E_FAIL;
2019-11-06 17:24:51 +03:00
clipboard = (wfClipboard*)context->custom;
2015-10-22 10:31:47 +03:00
if (!clipboard)
return ERROR_INTERNAL_ERROR;
clipboard->req_fsize = fileContentsResponse->cbRequested;
2019-11-06 17:24:51 +03:00
clipboard->req_fdata = (char*)malloc(fileContentsResponse->cbRequested);
2016-08-03 13:09:24 +03:00
2015-10-22 10:31:47 +03:00
if (!clipboard->req_fdata)
return ERROR_INTERNAL_ERROR;
2016-08-03 13:09:24 +03:00
CopyMemory(clipboard->req_fdata, fileContentsResponse->requestedData,
fileContentsResponse->cbRequested);
2015-10-22 10:31:47 +03:00
if (!SetEvent(clipboard->req_fevent))
{
2016-08-03 13:09:24 +03:00
free(clipboard->req_fdata);
2015-10-22 10:31:47 +03:00
return ERROR_INTERNAL_ERROR;
}
return CHANNEL_RC_OK;
}
2015-10-22 10:31:47 +03:00
BOOL wf_cliprdr_init(wfContext* wfc, CliprdrClientContext* cliprdr)
{
wfClipboard* clipboard;
2019-11-06 17:24:51 +03:00
rdpContext* context = (rdpContext*)wfc;
2015-10-22 10:31:47 +03:00
if (!context || !cliprdr)
return FALSE;
2019-11-06 17:24:51 +03:00
wfc->clipboard = (wfClipboard*)calloc(1, sizeof(wfClipboard));
if (!wfc->clipboard)
2015-10-22 10:31:47 +03:00
return FALSE;
clipboard = wfc->clipboard;
clipboard->wfc = wfc;
clipboard->context = cliprdr;
clipboard->channels = context->channels;
clipboard->sync = FALSE;
clipboard->map_capacity = 32;
clipboard->map_size = 0;
clipboard->hUser32 = LoadLibraryA("user32.dll");
if (clipboard->hUser32)
{
2019-11-06 17:24:51 +03:00
clipboard->AddClipboardFormatListener = (fnAddClipboardFormatListener)GetProcAddress(
clipboard->hUser32, "AddClipboardFormatListener");
clipboard->RemoveClipboardFormatListener = (fnRemoveClipboardFormatListener)GetProcAddress(
clipboard->hUser32, "RemoveClipboardFormatListener");
clipboard->GetUpdatedClipboardFormats = (fnGetUpdatedClipboardFormats)GetProcAddress(
clipboard->hUser32, "GetUpdatedClipboardFormats");
}
2019-11-06 17:24:51 +03:00
if (!(clipboard->hUser32 && clipboard->AddClipboardFormatListener &&
clipboard->RemoveClipboardFormatListener && clipboard->GetUpdatedClipboardFormats))
clipboard->legacyApi = TRUE;
2019-11-06 17:24:51 +03:00
if (!(clipboard->format_mappings =
(formatMapping*)calloc(clipboard->map_capacity, sizeof(formatMapping))))
2015-10-22 10:31:47 +03:00
goto error;
if (!(clipboard->response_data_event = CreateEvent(NULL, TRUE, FALSE, NULL)))
2015-10-22 10:31:47 +03:00
goto error;
if (!(clipboard->req_fevent = CreateEvent(NULL, TRUE, FALSE, NULL)))
2015-10-22 10:31:47 +03:00
goto error;
if (!(clipboard->thread = CreateThread(NULL, 0, cliprdr_thread_func, clipboard, 0, NULL)))
2015-10-22 10:31:47 +03:00
goto error;
cliprdr->MonitorReady = wf_cliprdr_monitor_ready;
cliprdr->ServerCapabilities = wf_cliprdr_server_capabilities;
cliprdr->ServerFormatList = wf_cliprdr_server_format_list;
cliprdr->ServerFormatListResponse = wf_cliprdr_server_format_list_response;
cliprdr->ServerLockClipboardData = wf_cliprdr_server_lock_clipboard_data;
cliprdr->ServerUnlockClipboardData = wf_cliprdr_server_unlock_clipboard_data;
cliprdr->ServerFormatDataRequest = wf_cliprdr_server_format_data_request;
cliprdr->ServerFormatDataResponse = wf_cliprdr_server_format_data_response;
cliprdr->ServerFileContentsRequest = wf_cliprdr_server_file_contents_request;
cliprdr->ServerFileContentsResponse = wf_cliprdr_server_file_contents_response;
2019-11-06 17:24:51 +03:00
cliprdr->custom = (void*)wfc->clipboard;
2015-10-22 10:31:47 +03:00
return TRUE;
error:
wf_cliprdr_uninit(wfc, cliprdr);
return FALSE;
}
2015-10-22 10:31:47 +03:00
BOOL wf_cliprdr_uninit(wfContext* wfc, CliprdrClientContext* cliprdr)
{
2015-10-22 10:31:47 +03:00
wfClipboard* clipboard;
if (!wfc || !cliprdr)
return FALSE;
clipboard = wfc->clipboard;
if (!clipboard)
return FALSE;
cliprdr->custom = NULL;
if (clipboard->hwnd)
PostMessage(clipboard->hwnd, WM_QUIT, 0, 0);
if (clipboard->thread)
{
WaitForSingleObject(clipboard->thread, INFINITE);
CloseHandle(clipboard->thread);
}
if (clipboard->response_data_event)
CloseHandle(clipboard->response_data_event);
2018-11-28 16:44:26 +03:00
if (clipboard->req_fevent)
CloseHandle(clipboard->req_fevent);
clear_file_array(clipboard);
clear_format_map(clipboard);
2015-05-11 10:07:39 +03:00
free(clipboard->format_mappings);
free(clipboard);
2015-10-22 10:31:47 +03:00
return TRUE;
}