[PATCH] winex11.drv: Use GMEM_FIXED memory for storing clipboard data.

Rafał Harabień rafalh1992 at o2.pl
Tue Apr 19 09:16:18 CDT 2016


Tested behavior in Win 10. MSDN says clipboard uses GMEM_SHARED handles but its not true.
Some applications depends on GetClipboardData returning valid pointer to data instead of handle.
Commit fixes pasting from clipboard in Multi Theft Auto: San Andreas.

Signed-off-by: Rafał Harabień <rafalh1992 at o2.pl>
---
 dlls/user32/tests/clipboard.c | 58 ++++++++++++++++++++++++++++++++
 dlls/winex11.drv/clipboard.c  | 77 +++++++++++++++++++++++++++++++++----------
 2 files changed, 117 insertions(+), 18 deletions(-)

diff --git a/dlls/user32/tests/clipboard.c b/dlls/user32/tests/clipboard.c
index be6c9bf..7660590 100644
--- a/dlls/user32/tests/clipboard.c
+++ b/dlls/user32/tests/clipboard.c
@@ -402,6 +402,63 @@ static void test_synthesized(void)
     ok(r, "gle %d\n", GetLastError());
 }
 
+static void test_fixed_mem(void)
+{
+    HGLOBAL h, htext, htext2;
+    BOOL r;
+    HANDLE data;
+    PVOID data_ptr;
+    DWORD format_id;
+
+    htext = create_text();
+    htext2 = create_text();
+
+    r = OpenClipboard(NULL);
+    ok(r, "gle %d\n", GetLastError());
+    r = EmptyClipboard();
+    ok(r, "gle %d\n", GetLastError());
+    h = SetClipboardData(CF_TEXT, htext);
+    ok(h == htext, "got %p\n", h);
+    format_id = RegisterClipboardFormatA("my_cool_clipboard_format");
+	h = SetClipboardData(format_id, htext2);
+    ok(h == htext2, "got %p\n", h);
+    r = CloseClipboard();
+    ok(r, "gle %d\n", GetLastError());
+
+    r = OpenClipboard(NULL);
+    ok(r, "gle %d\n", GetLastError());
+
+    data = GetClipboardData(CF_TEXT);
+    ok(data != NULL, "couldn't get data\n");
+    data_ptr = GlobalLock(data);
+    ok(data == data_ptr, "expected fixed mem, data %p ptr %p\n", data, data_ptr);
+    GlobalUnlock(data_ptr);
+
+    data = GetClipboardData(CF_OEMTEXT);
+    ok(data != NULL, "couldn't get data\n");
+    data_ptr = GlobalLock(data);
+    ok(data == data_ptr, "expected fixed mem, data %p ptr %p\n", data, data_ptr);
+    GlobalUnlock(data_ptr);
+
+    data = GetClipboardData(CF_UNICODETEXT);
+    ok(data != NULL, "couldn't get data\n");
+    data_ptr = GlobalLock(data);
+    ok(data == data_ptr, "expected fixed mem, data %p ptr %p\n", data, data_ptr);
+    GlobalUnlock(data_ptr);
+
+    data = GetClipboardData(format_id);
+    ok(data != NULL, "couldn't get data, cf %08x\n", format_id);
+    data_ptr = GlobalLock(data);
+    ok(data == data_ptr, "expected fixed mem, data %p ptr %p\n", data, data_ptr);
+    GlobalUnlock(data_ptr);
+
+    r = EmptyClipboard();
+    ok(r, "gle %d\n", GetLastError());
+
+    r = CloseClipboard();
+    ok(r, "gle %d\n", GetLastError());
+}
+
 static CRITICAL_SECTION clipboard_cs;
 static HWND next_wnd;
 static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
@@ -693,4 +750,5 @@ START_TEST(clipboard)
     test_ClipboardOwner();
     test_synthesized();
     test_messages();
+    test_fixed_mem();
 }
diff --git a/dlls/winex11.drv/clipboard.c b/dlls/winex11.drv/clipboard.c
index 5dc5e3c..9da2d24 100644
--- a/dlls/winex11.drv/clipboard.c
+++ b/dlls/winex11.drv/clipboard.c
@@ -871,8 +871,7 @@ static BOOL X11DRV_CLIPBOARD_RenderSynthesizedText(Display *display, UINT wForma
     else
         alloc_size = dst_chars;
 
-    hData = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE |
-        GMEM_DDESHARE, alloc_size);
+    hData = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, alloc_size);
 
     lpstrT = GlobalLock(hData);
 
@@ -949,7 +948,7 @@ static HGLOBAL create_dib_from_bitmap(HBITMAP hBmp)
 
     /* Allocate the packed DIB */
     TRACE("\tAllocating packed DIB of size %d\n", cPackedSize);
-    hPackedDIB = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE /*| GMEM_ZEROINIT*/,
+    hPackedDIB = GlobalAlloc(GMEM_FIXED /*| GMEM_ZEROINIT*/,
                              cPackedSize );
     if ( !hPackedDIB )
     {
@@ -1241,7 +1240,7 @@ static HANDLE X11DRV_CLIPBOARD_ImportXAString(Display *display, Window w, Atom p
             inlcount++;
     }
 
-    if ((hText = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cbytes + inlcount + 1)))
+    if ((hText = GlobalAlloc(GMEM_FIXED, cbytes + inlcount + 1)))
     {
         lpstr = GlobalLock(hText);
 
@@ -1298,7 +1297,7 @@ static HANDLE X11DRV_CLIPBOARD_ImportUTF8(Display *display, Window w, Atom prop)
         }
 
         count = MultiByteToWideChar(CP_UTF8, 0, lpstr, -1, NULL, 0);
-        hUnicodeText = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, count * sizeof(WCHAR));
+        hUnicodeText = GlobalAlloc(GMEM_FIXED, count * sizeof(WCHAR));
 
         if (hUnicodeText)
         {
@@ -1356,7 +1355,7 @@ static HANDLE X11DRV_CLIPBOARD_ImportCompoundText(Display *display, Window w, At
 
     TRACE("lcount = %d, destlen=%d, srcstr %s\n", lcount, destlen, srcstr[0]);
 
-    if ((hUnicodeText = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (destlen + lcount + 1) * sizeof(WCHAR))))
+    if ((hUnicodeText = GlobalAlloc(GMEM_FIXED, (destlen + lcount + 1) * sizeof(WCHAR))))
     {
         WCHAR *deststr = GlobalLock(hUnicodeText);
         MultiByteToWideChar(CP_UNIXCP, 0, srcstr[0], -1, deststr, destlen);
@@ -1440,7 +1439,7 @@ static HANDLE X11DRV_CLIPBOARD_ImportXAPIXMAP(Display *display, Window w, Atom p
             DWORD info_size = bitmap_info_size( info, DIB_RGB_COLORS );
             BYTE *ptr;
 
-            hClipData = GlobalAlloc( GMEM_MOVEABLE | GMEM_DDESHARE,
+            hClipData = GlobalAlloc( GMEM_FIXED,
                                      info_size + info->bmiHeader.biSizeImage );
             if (hClipData)
             {
@@ -1622,7 +1621,7 @@ static HANDLE X11DRV_CLIPBOARD_ImportTextUriList(Display *display, Window w, Ato
     if (out && end >= len)
     {
         DROPFILES *dropFiles;
-        handle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(DROPFILES) + (size + 1)*sizeof(WCHAR));
+        handle = GlobalAlloc(GMEM_FIXED, sizeof(DROPFILES) + (size + 1)*sizeof(WCHAR));
         if (handle)
         {
             dropFiles = (DROPFILES*) GlobalLock(handle);
@@ -1658,8 +1657,7 @@ static HANDLE X11DRV_CLIPBOARD_ImportClipboardData(Display *display, Window w, A
     {
         if (cbytes)
         {
-            /* Turn on the DDESHARE flag to enable shared 32 bit memory */
-            hClipData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cbytes);
+            hClipData = GlobalAlloc(GMEM_FIXED, cbytes);
             if (hClipData == 0)
             {
                 HeapFree(GetProcessHeap(), 0, lpdata);
@@ -1724,7 +1722,7 @@ static HANDLE X11DRV_CLIPBOARD_ExportClipboardData(Display *display, Window requ
     {
         datasize = GlobalSize(lpData->hData);
 
-        hClipData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, datasize);
+        hClipData = GlobalAlloc(GMEM_FIXED, datasize);
         if (hClipData == 0) return NULL;
 
         if ((lpClipData = GlobalLock(hClipData)))
@@ -1949,7 +1947,7 @@ static HANDLE X11DRV_CLIPBOARD_ExportXAPIXMAP(Display *display, Window requestor
     *lpBytes = sizeof(Pixmap); /* pixmap is a 32bit value */
 
     /* Wrap pixmap so we can return a handle */
-    hData = GlobalAlloc(0, *lpBytes);
+    hData = GlobalAlloc(GMEM_FIXED, *lpBytes);
     lpData = GlobalLock(hData);
     memcpy(lpData, &lpdata->drvData, *lpBytes);
     GlobalUnlock(hData);
@@ -1992,7 +1990,7 @@ static HANDLE X11DRV_CLIPBOARD_ExportImageBmp(Display *display, Window requestor
 
     bmpsize = sizeof(BITMAPFILEHEADER) + GlobalSize(hpackeddib);
 
-    hbmpdata = GlobalAlloc(0, bmpsize);
+    hbmpdata = GlobalAlloc(GMEM_FIXED, bmpsize);
 
     if (hbmpdata)
     {
@@ -2138,7 +2136,7 @@ static HANDLE X11DRV_CLIPBOARD_ExportTextHtml(Display *display, Window requestor
     /* export only the fragment */
     htmlsize = fragmentend - fragmentstart + 1;
 
-    hhtmldata = GlobalAlloc(0, htmlsize);
+    hhtmldata = GlobalAlloc(GMEM_FIXED, htmlsize);
 
     if (hhtmldata)
     {
@@ -2190,7 +2188,7 @@ static HANDLE X11DRV_CLIPBOARD_ExportHDROP(Display *display, Window requestor, A
         ERR("Failed to export %04x format\n", lpdata->wFormatID);
         return 0;
     }
-    hClipData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, textUriListSize);
+    hClipData = GlobalAlloc(GMEM_FIXED, textUriListSize);
     if (hClipData == NULL)
         return 0;
     hDrop = (HDROP) lpdata->hData;
@@ -2754,7 +2752,7 @@ static HANDLE X11DRV_CLIPBOARD_SerializeMetafile(INT wformat, HANDLE hdata, LPDW
             LPMETAFILEPICT lpmfp = GlobalLock(hdata);
             unsigned int size = GetMetaFileBitsEx(lpmfp->hMF, 0, NULL);
 
-            h = GlobalAlloc(0, size + sizeof(METAFILEPICT));
+            h = GlobalAlloc(GMEM_FIXED, size + sizeof(METAFILEPICT));
             if (h)
             {
                 char *pdata = GlobalLock(h);
@@ -2773,7 +2771,7 @@ static HANDLE X11DRV_CLIPBOARD_SerializeMetafile(INT wformat, HANDLE hdata, LPDW
         {
             int size = GetEnhMetaFileBits(hdata, 0, NULL);
 
-            h = GlobalAlloc(0, size);
+            h = GlobalAlloc(GMEM_FIXED, size);
             if (h)
             {
                 LPVOID pdata = GlobalLock(h);
@@ -2789,7 +2787,7 @@ static HANDLE X11DRV_CLIPBOARD_SerializeMetafile(INT wformat, HANDLE hdata, LPDW
     {
         if (wformat == CF_METAFILEPICT)
         {
-            h = GlobalAlloc(0, sizeof(METAFILEPICT));
+            h = GlobalAlloc(GMEM_FIXED, sizeof(METAFILEPICT));
             if (h)
             {
                 unsigned int wiresize;
@@ -3015,6 +3013,24 @@ void CDECL X11DRV_EmptyClipboard(void)
     empty_clipboard( FALSE );
 }
 
+static BOOLEAN is_global_mem_format(UINT wFormatID)
+{
+    if ((wFormatID >= CF_GDIOBJFIRST &&
+        wFormatID <= CF_GDIOBJLAST) ||
+        wFormatID == CF_BITMAP ||
+        wFormatID == CF_DIB ||
+        wFormatID == CF_PALETTE ||
+        wFormatID == CF_METAFILEPICT ||
+        wFormatID == CF_ENHMETAFILE ||
+        (wFormatID >= CF_PRIVATEFIRST &&
+         wFormatID <= CF_PRIVATELAST))
+    {
+      return FALSE;
+    }
+
+    return TRUE;
+}
+
 /**************************************************************************
  *		X11DRV_SetClipboardData
  */
@@ -3022,6 +3038,8 @@ BOOL CDECL X11DRV_SetClipboardData(UINT wFormat, HANDLE hData, BOOL owner)
 {
     DWORD flags = 0;
     BOOL bResult = TRUE;
+    LPVOID pData, pData2;
+    SIZE_T size;
 
     /* If it's not owned, data can only be set if the format data is not already owned
        and its rendering is not delayed */
@@ -3039,6 +3057,29 @@ BOOL CDECL X11DRV_SetClipboardData(UINT wFormat, HANDLE hData, BOOL owner)
             flags = CF_FLAG_UNOWNED;
     }
 
+    if (is_global_mem_format(wFormat) && hData)
+    {
+        /* Check if memory was allocated with GMEM_FIXED flag */
+        pData = GlobalLock(hData);
+        if (pData != (LPVOID)hData)
+        {
+            /* Convert handle to GMEM_FIXED (GetClipboardData always returns pointer) */
+            size = GlobalSize(hData);
+            pData2 = (LPVOID)GlobalAlloc(GMEM_FIXED, size);
+            if (pData2)
+            {
+                memcpy(pData2, pData, size);
+                GlobalUnlock(hData);
+                GlobalFree(hData);
+                hData = (HANDLE)pData2;
+            }
+            else
+                GlobalUnlock(hData);
+        }
+        else
+            GlobalUnlock(hData);
+    }
+
     bResult &= X11DRV_CLIPBOARD_InsertClipboardData(wFormat, hData, flags, NULL, TRUE);
 
     return bResult;
-- 
1.9.1




More information about the wine-patches mailing list