From ff92ef4331310b4aa773a010bf1c465415a4c92c Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 3 Apr 2024 08:53:20 +0200 Subject: [PATCH] [client,windows] clean up clipboard --- client/Windows/wf_cliprdr.c | 254 ++++++++++++++++++++---------------- 1 file changed, 140 insertions(+), 114 deletions(-) diff --git a/client/Windows/wf_cliprdr.c b/client/Windows/wf_cliprdr.c index 7593be523..78c63204b 100644 --- a/client/Windows/wf_cliprdr.c +++ b/client/Windows/wf_cliprdr.c @@ -2006,6 +2006,132 @@ static BOOL wf_cliprdr_process_filename(wfClipboard* clipboard, WCHAR* wFileName return TRUE; } +static SSIZE_T wf_cliprdr_tryopen(wfClipboard* clipboard, UINT32 requestedFormatId, void** pData) +{ + SSIZE_T rc = -1; + WINPR_ASSERT(clipboard); + WINPR_ASSERT(pData); + + *pData = NULL; + + /* Ignore if other app is holding the clipboard */ + if (!try_open_clipboard(clipboard->hwnd)) + return 0; + + HANDLE hClipdata = GetClipboardData(requestedFormatId); + + if (!hClipdata) + goto fail; + + char* globlemem = (char*)GlobalLock(hClipdata); + const SSIZE_T size = GlobalSize(hClipdata); + if (size <= 0) + goto unlock; + + BYTE* buff = malloc(size); + if (buff == NULL) + goto fail; + CopyMemory(buff, globlemem, size); + *pData = buff; + rc = size; + +unlock: + GlobalUnlock(hClipdata); + +fail: + CloseClipboard(); + + return rc; +} + +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 }; + + *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; + } + + 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) + { + wf_cliprdr_process_filename(clipboard, wFileName, wcslen(wFileName)); + } + } + else + { + size_t len = 0; + for (char* p = (char*)((char*)dropFiles + dropFiles->pFiles); (len = strlen(p)) > 0; + p += len + 1, clipboard->nFiles++) + { + 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: + const size_t size = 4 + clipboard->nFiles * sizeof(FILEDESCRIPTORW); + FILEGROUPDESCRIPTORW* groupDsc = (FILEGROUPDESCRIPTORW*)calloc(size, 1); + + if (groupDsc) + { + groupDsc->cItems = clipboard->nFiles; + + for (size_t i = 0; i < clipboard->nFiles; i++) + { + if (clipboard->fileDescriptor[i]) + groupDsc->fgd[i] = *clipboard->fileDescriptor[i]; + } + + *pData = groupDsc; + rc = size; + } + + IDataObject_Release(dataObj); + return rc; +} + /** * Function description * @@ -2015,137 +2141,37 @@ static UINT wf_cliprdr_server_format_data_request(CliprdrClientContext* context, const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) { - UINT rc; - size_t size = 0; - void* buff = NULL; - char* globlemem = NULL; - HANDLE hClipdata = NULL; - UINT32 requestedFormatId; - CLIPRDR_FORMAT_DATA_RESPONSE response; - wfClipboard* clipboard; + CLIPRDR_FORMAT_DATA_RESPONSE response = { 0 }; if (!context || !formatDataRequest) return ERROR_INTERNAL_ERROR; - clipboard = (wfClipboard*)context->custom; + wfClipboard* clipboard = (wfClipboard*)context->custom; if (!clipboard) return ERROR_INTERNAL_ERROR; - requestedFormatId = formatDataRequest->requestedFormatId; + const UINT32 requestedFormatId = formatDataRequest->requestedFormatId; 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); - - if (FAILED(result)) - return ERROR_INTERNAL_ERROR; - - /* 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; - } - - dropFiles = (DROPFILES*)GlobalLock(stg_medium.hGlobal); - - if (!dropFiles) - { - GlobalUnlock(stg_medium.hGlobal); - ReleaseStgMedium(&stg_medium); - clipboard->nFiles = 0; - goto exit; - } - - clear_file_array(clipboard); - - if (dropFiles->fWide) - { - /* 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)); - } - } - else - { - 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); - } - } - - GlobalUnlock(stg_medium.hGlobal); - ReleaseStgMedium(&stg_medium); - exit: - size = 4 + clipboard->nFiles * sizeof(FILEDESCRIPTORW); - groupDsc = (FILEGROUPDESCRIPTORW*)malloc(size); - - if (groupDsc) - { - groupDsc->cItems = clipboard->nFiles; - - for (size_t i = 0; i < clipboard->nFiles; i++) - { - if (clipboard->fileDescriptor[i]) - groupDsc->fgd[i] = *clipboard->fileDescriptor[i]; - } - - buff = groupDsc; - } - - IDataObject_Release(dataObj); + 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; }