Skip to content

Commit

Permalink
[client,windows] clean up clipboard
Browse files Browse the repository at this point in the history
  • Loading branch information
Armin Novak authored and akallabeth committed Apr 3, 2024
1 parent be50010 commit ff92ef4
Showing 1 changed file with 137 additions and 111 deletions.
248 changes: 137 additions & 111 deletions client/Windows/wf_cliprdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -2006,146 +2006,172 @@ static BOOL wf_cliprdr_process_filename(wfClipboard* clipboard, WCHAR* wFileName
return TRUE;
}

/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT
wf_cliprdr_server_format_data_request(CliprdrClientContext* context,
const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
static SSIZE_T wf_cliprdr_tryopen(wfClipboard* clipboard, UINT32 requestedFormatId, void** pData)
{
UINT rc;
size_t size = 0;
void* buff = NULL;
char* globlemem = NULL;
HANDLE hClipdata = NULL;
UINT32 requestedFormatId;
CLIPRDR_FORMAT_DATA_RESPONSE response;
wfClipboard* clipboard;
SSIZE_T rc = -1;
WINPR_ASSERT(clipboard);
WINPR_ASSERT(pData);

if (!context || !formatDataRequest)
return ERROR_INTERNAL_ERROR;
*pData = NULL;

clipboard = (wfClipboard*)context->custom;
/* Ignore if other app is holding the clipboard */
if (!try_open_clipboard(clipboard->hwnd))
return 0;

if (!clipboard)
return ERROR_INTERNAL_ERROR;
HANDLE hClipdata = GetClipboardData(requestedFormatId);

requestedFormatId = formatDataRequest->requestedFormatId;
if (!hClipdata)
goto fail;

if (requestedFormatId == RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW))
{
size_t len;
HRESULT result;
LPDATAOBJECT dataObj = NULL;
FORMATETC format_etc = { 0 };
STGMEDIUM stg_medium = { 0 };
DROPFILES* dropFiles = NULL;
FILEGROUPDESCRIPTORW* groupDsc;
result = OleGetClipboard(&dataObj);
char* globlemem = (char*)GlobalLock(hClipdata);
const SSIZE_T size = GlobalSize(hClipdata);
if (size <= 0)
goto unlock;

if (FAILED(result))
return ERROR_INTERNAL_ERROR;
BYTE* buff = malloc(size);
if (buff == NULL)
goto fail;
CopyMemory(buff, globlemem, size);
*pData = buff;
rc = size;

/* 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);
unlock:
GlobalUnlock(hClipdata);

if (FAILED(result))
{
DEBUG_CLIPRDR("dataObj->GetData failed.");
goto exit;
}
fail:
CloseClipboard();

dropFiles = (DROPFILES*)GlobalLock(stg_medium.hGlobal);
return rc;
}

if (!dropFiles)
{
GlobalUnlock(stg_medium.hGlobal);
ReleaseStgMedium(&stg_medium);
clipboard->nFiles = 0;
goto exit;
}
static SSIZE_T wf_cliprdr_get_filedescriptor(wfClipboard* clipboard, void** pData)
{
WINPR_ASSERT(clipboard);
WINPR_ASSERT(pData);

SSIZE_T rc = -1;
LPDATAOBJECT dataObj = NULL;
FORMATETC format_etc = { 0 };
STGMEDIUM stg_medium = { 0 };

clear_file_array(clipboard);
*pData = NULL;

HRESULT result = OleGetClipboard(&dataObj);
if (FAILED(result))
return -1;

/* 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);

if (FAILED(result))
{
DEBUG_CLIPRDR("dataObj->GetData failed.");
goto exit;
}

if (dropFiles->fWide)
DROPFILES* dropFiles = (DROPFILES*)GlobalLock(stg_medium.hGlobal);

if (!dropFiles)
{
ReleaseStgMedium(&stg_medium);
clipboard->nFiles = 0;
goto exit;
}

clear_file_array(clipboard);

if (dropFiles->fWide)
{
/* dropFiles contains file names */
size_t len = 0;
for (WCHAR* wFileName = (WCHAR*)((char*)dropFiles + dropFiles->pFiles);
(len = wcslen(wFileName)) > 0; wFileName += len + 1)
{
/* dropFiles contains file names */
for (WCHAR* wFileName = (WCHAR*)((char*)dropFiles + dropFiles->pFiles);
(len = wcslen(wFileName)) > 0; wFileName += len + 1)
{
wf_cliprdr_process_filename(clipboard, wFileName, wcslen(wFileName));
}
wf_cliprdr_process_filename(clipboard, wFileName, wcslen(wFileName));
}
else
}
else
{
size_t len = 0;
for (char* p = (char*)((char*)dropFiles + dropFiles->pFiles); (len = strlen(p)) > 0;
p += len + 1, clipboard->nFiles++)
{
for (char* p = (char*)((char*)dropFiles + dropFiles->pFiles); (len = strlen(p)) > 0;
p += len + 1, clipboard->nFiles++)
{
int cchWideChar;
WCHAR* wFileName;
cchWideChar = MultiByteToWideChar(CP_ACP, MB_COMPOSITE, p, len, NULL, 0);
wFileName = (LPWSTR)calloc(cchWideChar, sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, MB_COMPOSITE, p, len, wFileName, cchWideChar);
wf_cliprdr_process_filename(clipboard, wFileName, cchWideChar);
}
const int cchWideChar = MultiByteToWideChar(CP_ACP, MB_COMPOSITE, p, len, NULL, 0);
WCHAR* wFileName = (LPWSTR)calloc(cchWideChar, sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, MB_COMPOSITE, p, len, wFileName, cchWideChar);
wf_cliprdr_process_filename(clipboard, wFileName, cchWideChar);
free(wFileName);
}
}

GlobalUnlock(stg_medium.hGlobal);
ReleaseStgMedium(&stg_medium);
exit:
size = 4 + clipboard->nFiles * sizeof(FILEDESCRIPTORW);
groupDsc = (FILEGROUPDESCRIPTORW*)malloc(size);
GlobalUnlock(stg_medium.hGlobal);
ReleaseStgMedium(&stg_medium);
exit:
const size_t size = 4 + clipboard->nFiles * sizeof(FILEDESCRIPTORW);
FILEGROUPDESCRIPTORW* groupDsc = (FILEGROUPDESCRIPTORW*)calloc(size, 1);

if (groupDsc)
{
groupDsc->cItems = clipboard->nFiles;

if (groupDsc)
for (size_t i = 0; i < clipboard->nFiles; i++)
{
groupDsc->cItems = clipboard->nFiles;
if (clipboard->fileDescriptor[i])
groupDsc->fgd[i] = *clipboard->fileDescriptor[i];
}

for (size_t i = 0; i < clipboard->nFiles; i++)
{
if (clipboard->fileDescriptor[i])
groupDsc->fgd[i] = *clipboard->fileDescriptor[i];
}
*pData = groupDsc;
rc = size;
}

buff = groupDsc;
}
IDataObject_Release(dataObj);
return rc;
}

/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
static UINT
wf_cliprdr_server_format_data_request(CliprdrClientContext* context,
const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
{
CLIPRDR_FORMAT_DATA_RESPONSE response = { 0 };

if (!context || !formatDataRequest)
return ERROR_INTERNAL_ERROR;

wfClipboard* clipboard = (wfClipboard*)context->custom;

if (!clipboard)
return ERROR_INTERNAL_ERROR;

IDataObject_Release(dataObj);
const UINT32 requestedFormatId = formatDataRequest->requestedFormatId;

if (requestedFormatId == RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW))
{
const SSIZE_T res = wf_cliprdr_get_filedescriptor(clipboard, requestedFormatId,
&response.requestedFormatData);
if (res > 0)
response.common.dataLen = (UINT32)res;
}
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);
if (buff == NULL)
return ERROR_INTERNAL_ERROR;
CopyMemory(buff, globlemem, size);
GlobalUnlock(hClipdata);
CloseClipboard();
}
const SSIZE_T res =
wf_cliprdr_tryopen(clipboard, requestedFormatId, &response.requestedFormatData);
if (res > 0)
response.common.dataLen = (UINT32)res;
}

response.common.msgFlags = CB_RESPONSE_OK;
response.common.dataLen = size;
response.requestedFormatData = (BYTE*)buff;
rc = clipboard->context->ClientFormatDataResponse(clipboard->context, &response);
free(buff);

const UINT rc = clipboard->context->ClientFormatDataResponse(clipboard->context, &response);
free(response.requestedFormatData);
return rc;
}

Expand Down

0 comments on commit ff92ef4

Please sign in to comment.