Fix #5749: Retry to open the clipboard.
authorArmin Novak <armin.novak@thincast.com>
Tue, 26 Nov 2019 06:57:32 +0000 (07:57 +0100)
committerArmin Novak <armin.novak@thincast.com>
Tue, 26 Nov 2019 06:57:32 +0000 (07:57 +0100)
On windows the clipboard is shared and other applications
or windows might lock the clipboard.
For this reason, retry opening if it fails and ignore
failure to open during normal operation.

client/Windows/wf_cliprdr.c

index d182417..166b241 100644 (file)
@@ -166,6 +166,18 @@ 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;
+}
+
 /**
  * IStream
  */
@@ -1190,10 +1202,13 @@ static BOOL cliprdr_GetUpdatedClipboardFormats(wfClipboard* clipboard, PUINT lpu
        if (!clipboard->legacyApi)
                return clipboard->GetUpdatedClipboardFormats(lpuiFormats, cFormats, pcFormatsOut);
 
-       clipboardOpen = OpenClipboard(clipboard->hwnd);
+       clipboardOpen = try_open_clipboard(clipboard->hwnd);
 
        if (!clipboardOpen)
-               return FALSE;
+       {
+               *pcFormatsOut = 0;
+               return TRUE; /* Other app holding clipboard */
+       }
 
        while (index < cFormats)
        {
@@ -1214,12 +1229,12 @@ static BOOL cliprdr_GetUpdatedClipboardFormats(wfClipboard* clipboard, PUINT lpu
 static UINT cliprdr_send_format_list(wfClipboard* clipboard)
 {
        UINT rc;
-       int count;
+       int count = 0;
        UINT32 index;
-       UINT32 numFormats;
+       UINT32 numFormats = 0;
        UINT32 formatId = 0;
        char formatName[1024];
-       CLIPRDR_FORMAT* formats;
+       CLIPRDR_FORMAT* formats = NULL;
        CLIPRDR_FORMAT_LIST formatList;
 
        if (!clipboard)
@@ -1227,45 +1242,46 @@ static UINT cliprdr_send_format_list(wfClipboard* clipboard)
 
        ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST));
 
-       if (!OpenClipboard(clipboard->hwnd))
-               return ERROR_INTERNAL_ERROR;
-
-       count = CountClipboardFormats();
-       numFormats = (UINT32)count;
-       formats = (CLIPRDR_FORMAT*)calloc(numFormats, sizeof(CLIPRDR_FORMAT));
-
-       if (!formats)
+       /* Ignore if other app is holding clipboard */
+       if (try_open_clipboard(clipboard->hwnd))
        {
-               CloseClipboard();
-               return CHANNEL_RC_NO_MEMORY;
-       }
+               count = CountClipboardFormats();
+               numFormats = (UINT32)count;
+               formats = (CLIPRDR_FORMAT*)calloc(numFormats, sizeof(CLIPRDR_FORMAT));
 
-       index = 0;
+               if (!formats)
+               {
+                       CloseClipboard();
+                       return CHANNEL_RC_NO_MEMORY;
+               }
 
-       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;
-       }
+               index = 0;
 
-       numFormats = index;
+               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;
+               }
 
-       if (!CloseClipboard())
-       {
-               free(formats);
-               return ERROR_INTERNAL_ERROR;
-       }
+               numFormats = index;
 
-       for (index = 0; index < numFormats; index++)
-       {
-               if (GetClipboardFormatNameA(formats[index].formatId, formatName, sizeof(formatName)))
+               if (!CloseClipboard())
+               {
+                       free(formats);
+                       return ERROR_INTERNAL_ERROR;
+               }
+
+               for (index = 0; index < numFormats; index++)
                {
-                       formats[index].formatName = _strdup(formatName);
+                       if (GetClipboardFormatNameA(formats[index].formatId, formatName, sizeof(formatName)))
+                       {
+                               formats[index].formatName = _strdup(formatName);
+                       }
                }
        }
 
@@ -1400,7 +1416,7 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM
                        DEBUG_CLIPRDR("info: WM_RENDERALLFORMATS");
 
                        /* discard all contexts in clipboard */
-                       if (!OpenClipboard(clipboard->hwnd))
+                       if (!try_open_clipboard(clipboard->hwnd))
                        {
                                DEBUG_CLIPRDR("OpenClipboard failed with 0x%x", GetLastError());
                                break;
@@ -1917,8 +1933,8 @@ static UINT wf_cliprdr_server_format_list(CliprdrClientContext* context,
        }
        else
        {
-               if (!OpenClipboard(clipboard->hwnd))
-                       return ERROR_INTERNAL_ERROR;
+               if (!try_open_clipboard(clipboard->hwnd))
+                       return CHANNEL_RC_OK; /* Ignore, other app holding clipboard */
 
                if (EmptyClipboard())
                {
@@ -2133,23 +2149,24 @@ wf_cliprdr_server_format_data_request(CliprdrClientContext* context,
        }
        else
        {
-               if (!OpenClipboard(clipboard->hwnd))
-                       return ERROR_INTERNAL_ERROR;
+               /* Ignore if other app is holding the clipboard */
+               if (try_open_clipboard(clipboard->hwnd))
+               {
+                       hClipdata = GetClipboardData(requestedFormatId);
 
-               hClipdata = GetClipboardData(requestedFormatId);
+                       if (!hClipdata)
+                       {
+                               CloseClipboard();
+                               return ERROR_INTERNAL_ERROR;
+                       }
 
-               if (!hClipdata)
-               {
+                       globlemem = (char*)GlobalLock(hClipdata);
+                       size = (int)GlobalSize(hClipdata);
+                       buff = malloc(size);
+                       CopyMemory(buff, globlemem, size);
+                       GlobalUnlock(hClipdata);
                        CloseClipboard();
-                       return ERROR_INTERNAL_ERROR;
                }
-
-               globlemem = (char*)GlobalLock(hClipdata);
-               size = (int)GlobalSize(hClipdata);
-               buff = malloc(size);
-               CopyMemory(buff, globlemem, size);
-               GlobalUnlock(hClipdata);
-               CloseClipboard();
        }
 
        response.msgFlags = CB_RESPONSE_OK;