From 83579c82860b186bf81a7865cce51fc149ff9683 Mon Sep 17 00:00:00 2001 From: Noel Borthwick Date: Sat, 24 Jul 1999 12:18:04 +0000 Subject: [PATCH] Fix bug with pasting Wine clipboard content to external applications, by storing clipboard data on the shared system heap. --- include/clipboard.h | 1 + memory/global.c | 86 ++++++++++++++++++++++++---------- windows/clipboard.c | 109 ++++++++++++++++++++++++++++++++++++-------- 3 files changed, 154 insertions(+), 42 deletions(-) diff --git a/include/clipboard.h b/include/clipboard.h index 16496d3170f..7aebde970b4 100644 --- a/include/clipboard.h +++ b/include/clipboard.h @@ -10,6 +10,7 @@ typedef struct tagWINE_CLIPFORMAT { WORD wRefCount; WORD wDataPresent; LPSTR Name; + HANDLE hDataSrc32; HANDLE hData32; DWORD BufSize; struct tagWINE_CLIPFORMAT *PrevFormat; diff --git a/memory/global.c b/memory/global.c index 764d22641be..89a530865dc 100644 --- a/memory/global.c +++ b/memory/global.c @@ -72,7 +72,6 @@ static GLOBALARENA *GLOBAL_GetArena( WORD sel, WORD selcount ) return pGlobalArena + (sel >> __AHSHIFT); } - void debug_handles(void) { int printed=0; @@ -973,6 +972,34 @@ typedef struct __GLOBAL32_INTERN BYTE LockCount; } GLOBAL32_INTERN, *PGLOBAL32_INTERN; +/*********************************************************************** + * GLOBAL_GetHeap + * + * Returns the appropriate heap to be used. If the object was created + * With GMEM_DDESHARE we allocated it on the system heap. + */ +static HANDLE GLOBAL_GetHeap( HGLOBAL hmem ) +{ + HANDLE heap; + + TRACE("() hmem=%x\n", hmem); + + /* Get the appropriate heap to be used for this object */ + if (ISPOINTER(hmem)) + heap = GetProcessHeap(); + else + { + PGLOBAL32_INTERN pintern; + pintern=HANDLE_TO_INTERN(hmem); + + /* If it was DDESHARE it was created on the shared system heap */ + pintern=HANDLE_TO_INTERN(hmem); + heap = ( pintern->Flags & (GMEM_DDESHARE >> 8) ) + ? SystemHeap : GetProcessHeap(); + } + + return heap; +} /*********************************************************************** * GlobalAlloc32 (KERNEL32.315) @@ -993,6 +1020,8 @@ HGLOBAL WINAPI GlobalAlloc( else hpflags=0; + TRACE("() flags=%04x\n", flags ); + if((flags & GMEM_MOVEABLE)==0) /* POINTER */ { palloc=HeapAlloc(GetProcessHeap(), hpflags, size); @@ -1000,12 +1029,17 @@ HGLOBAL WINAPI GlobalAlloc( } else /* HANDLE */ { - /* HeapLock(GetProcessHeap()); */ + HANDLE heap; + + /* If DDESHARE is set, create on the shared system heap */ + heap = (flags & GMEM_DDESHARE) ? SystemHeap : GetProcessHeap(); - pintern=HeapAlloc(GetProcessHeap(), 0, sizeof(GLOBAL32_INTERN)); + /* HeapLock(heap); */ + + pintern=HeapAlloc(heap, 0, sizeof(GLOBAL32_INTERN)); if(size) { - palloc=HeapAlloc(GetProcessHeap(), hpflags, size+sizeof(HGLOBAL)); + palloc=HeapAlloc(heap, hpflags, size+sizeof(HGLOBAL)); *(HGLOBAL *)palloc=INTERN_TO_HANDLE(pintern); pintern->Pointer=(char *) palloc+sizeof(HGLOBAL); } @@ -1015,7 +1049,7 @@ HGLOBAL WINAPI GlobalAlloc( pintern->Flags=flags>>8; pintern->LockCount=0; - /* HeapUnlock(GetProcessHeap()); */ + /* HeapUnlock(heap); */ return INTERN_TO_HANDLE(pintern); } @@ -1107,16 +1141,17 @@ HGLOBAL WINAPI GlobalHandle( LPCVOID pmem /* [in] Pointer to global memory block */ ) { HGLOBAL handle; + HANDLE heap = GLOBAL_GetHeap( POINTER_TO_HANDLE(pmem) ); - if (!HEAP_IsInsideHeap( GetProcessHeap(), 0, pmem )) goto error; + if (!HEAP_IsInsideHeap( heap, 0, pmem )) goto error; handle = POINTER_TO_HANDLE(pmem); - if (HEAP_IsInsideHeap( GetProcessHeap(), 0, (LPCVOID)handle )) + if (HEAP_IsInsideHeap( heap, 0, (LPCVOID)handle )) { if (HANDLE_TO_INTERN(handle)->Magic == MAGIC_GLOBAL_USED) return handle; /* valid moveable block */ } /* maybe FIXED block */ - if (HeapValidate( GetProcessHeap(), 0, pmem )) + if (HeapValidate( heap, 0, pmem )) return (HGLOBAL)pmem; /* valid fixed block */ error: @@ -1139,9 +1174,10 @@ HGLOBAL WINAPI GlobalReAlloc( LPVOID palloc; HGLOBAL hnew; PGLOBAL32_INTERN pintern; + HANDLE heap = GLOBAL_GetHeap( hmem ); hnew = 0; - /* HeapLock(GetProcessHeap()); */ + /* HeapLock(heap); */ if(flags & GMEM_MODIFY) /* modify flags */ { if( ISPOINTER(hmem) && (flags & GMEM_MOVEABLE)) @@ -1155,7 +1191,7 @@ HGLOBAL WINAPI GlobalReAlloc( SetLastError( ERROR_NOACCESS ); return 0; } - size=HeapSize(GetProcessHeap(), 0, (LPVOID) hmem); + size=HeapSize(heap, 0, (LPVOID) hmem); hnew=GlobalAlloc( flags, size); palloc=GlobalLock(hnew); memcpy(palloc, (LPVOID) hmem, size); @@ -1180,7 +1216,7 @@ HGLOBAL WINAPI GlobalReAlloc( if(ISPOINTER(hmem)) { /* reallocate fixed memory */ - hnew=(HGLOBAL)HeapReAlloc(GetProcessHeap(), 0, (LPVOID) hmem, size); + hnew=(HGLOBAL)HeapReAlloc(heap, 0, (LPVOID) hmem, size); } else { @@ -1194,14 +1230,14 @@ HGLOBAL WINAPI GlobalReAlloc( hnew=hmem; if(pintern->Pointer) { - palloc=HeapReAlloc(GetProcessHeap(), 0, + palloc=HeapReAlloc(heap, 0, (char *) pintern->Pointer-sizeof(HGLOBAL), size+sizeof(HGLOBAL) ); pintern->Pointer=(char *) palloc+sizeof(HGLOBAL); } else { - palloc=HeapAlloc(GetProcessHeap(), 0, size+sizeof(HGLOBAL)); + palloc=HeapAlloc(heap, 0, size+sizeof(HGLOBAL)); *(HGLOBAL *)palloc=hmem; pintern->Pointer=(char *) palloc+sizeof(HGLOBAL); } @@ -1210,13 +1246,13 @@ HGLOBAL WINAPI GlobalReAlloc( { if(pintern->Pointer) { - HeapFree(GetProcessHeap(), 0, (char *) pintern->Pointer-sizeof(HGLOBAL)); + HeapFree(heap, 0, (char *) pintern->Pointer-sizeof(HGLOBAL)); pintern->Pointer=NULL; } } } } - /* HeapUnlock(GetProcessHeap()); */ + /* HeapUnlock(heap); */ return hnew; } @@ -1232,14 +1268,15 @@ HGLOBAL WINAPI GlobalFree( ) { PGLOBAL32_INTERN pintern; HGLOBAL hreturned = 0; + HANDLE heap = GLOBAL_GetHeap( hmem ); if(ISPOINTER(hmem)) /* POINTER */ { - if(!HeapFree(GetProcessHeap(), 0, (LPVOID) hmem)) hmem = 0; + if(!HeapFree(heap, 0, (LPVOID) hmem)) hmem = 0; } else /* HANDLE */ { - /* HeapLock(GetProcessHeap()); */ + /* HeapLock(heap); */ pintern=HANDLE_TO_INTERN(hmem); if(pintern->Magic==MAGIC_GLOBAL_USED) @@ -1247,13 +1284,13 @@ HGLOBAL WINAPI GlobalFree( if(pintern->LockCount!=0) SetLastError(ERROR_INVALID_HANDLE); if(pintern->Pointer) - if(!HeapFree(GetProcessHeap(), 0, + if(!HeapFree(heap, 0, (char *)(pintern->Pointer)-sizeof(HGLOBAL))) hreturned=hmem; - if(!HeapFree(GetProcessHeap(), 0, pintern)) + if(!HeapFree(heap, 0, pintern)) hreturned=hmem; } - /* HeapUnlock(GetProcessHeap()); */ + /* HeapUnlock(heap); */ } return hreturned; } @@ -1270,21 +1307,22 @@ DWORD WINAPI GlobalSize( ) { DWORD retval; PGLOBAL32_INTERN pintern; + HANDLE heap = GLOBAL_GetHeap( hmem ); if(ISPOINTER(hmem)) { - retval=HeapSize(GetProcessHeap(), 0, (LPVOID) hmem); + retval=HeapSize(heap, 0, (LPVOID) hmem); } else { - /* HeapLock(GetProcessHeap()); */ + /* HeapLock(heap); */ pintern=HANDLE_TO_INTERN(hmem); if(pintern->Magic==MAGIC_GLOBAL_USED) { if (!pintern->Pointer) /* handle case of GlobalAlloc( ??,0) */ return 0; - retval=HeapSize(GetProcessHeap(), 0, + retval=HeapSize(heap, 0, (char *)(pintern->Pointer)-sizeof(HGLOBAL))-4; if (retval == 0xffffffff-4) retval = 0; } @@ -1293,7 +1331,7 @@ DWORD WINAPI GlobalSize( WARN("invalid handle\n"); retval=0; } - /* HeapUnlock(GetProcessHeap()); */ + /* HeapUnlock(heap); */ } /* HeapSize returns 0xffffffff on failure */ if (retval == 0xffffffff) retval = 0; diff --git a/windows/clipboard.c b/windows/clipboard.c index dde5d698091..542b02c715b 100644 --- a/windows/clipboard.c +++ b/windows/clipboard.c @@ -41,22 +41,22 @@ static HWND hWndViewer = 0; /* start of viewers chain */ static WORD LastRegFormat = CF_REGFORMATBASE; WINE_CLIPFORMAT ClipFormats[16] = { - { CF_TEXT, 1, 0, "Text", (HANDLE)NULL, 0, NULL, &ClipFormats[1] , (HANDLE16)NULL}, - { CF_BITMAP, 1, 0, "Bitmap", (HANDLE)NULL, 0, &ClipFormats[0], &ClipFormats[2] , (HANDLE16)NULL}, - { CF_METAFILEPICT, 1, 0, "MetaFile Picture", (HANDLE)NULL, 0, &ClipFormats[1], &ClipFormats[3] , (HANDLE16)NULL}, - { CF_SYLK, 1, 0, "Sylk", (HANDLE)NULL, 0, &ClipFormats[2], &ClipFormats[4] , (HANDLE16)NULL}, - { CF_DIF, 1, 0, "DIF", (HANDLE)NULL, 0, &ClipFormats[3], &ClipFormats[5] , (HANDLE16)NULL}, - { CF_TIFF, 1, 0, "TIFF", (HANDLE)NULL, 0, &ClipFormats[4], &ClipFormats[6] , (HANDLE16)NULL}, - { CF_OEMTEXT, 1, 0, "OEM Text", (HANDLE)NULL, 0, &ClipFormats[5], &ClipFormats[7] , (HANDLE16)NULL}, - { CF_DIB, 1, 0, "DIB", (HANDLE)NULL, 0, &ClipFormats[6], &ClipFormats[8] , (HANDLE16)NULL}, - { CF_PALETTE, 1, 0, "Palette", (HANDLE)NULL, 0, &ClipFormats[7], &ClipFormats[9] , (HANDLE16)NULL}, - { CF_PENDATA, 1, 0, "PenData", (HANDLE)NULL, 0, &ClipFormats[8], &ClipFormats[10] , (HANDLE16)NULL}, - { CF_RIFF, 1, 0, "RIFF", (HANDLE)NULL, 0, &ClipFormats[9], &ClipFormats[11] , (HANDLE16)NULL}, - { CF_WAVE, 1, 0, "Wave", (HANDLE)NULL, 0, &ClipFormats[10], &ClipFormats[12] , (HANDLE16)NULL}, - { CF_OWNERDISPLAY, 1, 0, "Owner Display", (HANDLE)NULL, 0, &ClipFormats[11], &ClipFormats[13] , (HANDLE16)NULL}, - { CF_DSPTEXT, 1, 0, "DSPText", (HANDLE)NULL, 0, &ClipFormats[12], &ClipFormats[14] , (HANDLE16)NULL}, - { CF_DSPMETAFILEPICT, 1, 0, "DSPMetaFile Picture", (HANDLE)NULL, 0, &ClipFormats[13], &ClipFormats[15] , (HANDLE16)NULL}, - { CF_DSPBITMAP, 1, 0, "DSPBitmap", (HANDLE)NULL, 0, &ClipFormats[14], NULL , (HANDLE16)NULL} + { CF_TEXT, 1, 0, "Text", (HANDLE)NULL, (HANDLE)NULL, 0, NULL, &ClipFormats[1] , (HANDLE16)NULL}, + { CF_BITMAP, 1, 0, "Bitmap", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[0], &ClipFormats[2] , (HANDLE16)NULL}, + { CF_METAFILEPICT, 1, 0, "MetaFile Picture", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[1], &ClipFormats[3] , (HANDLE16)NULL}, + { CF_SYLK, 1, 0, "Sylk", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[2], &ClipFormats[4] , (HANDLE16)NULL}, + { CF_DIF, 1, 0, "DIF", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[3], &ClipFormats[5] , (HANDLE16)NULL}, + { CF_TIFF, 1, 0, "TIFF", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[4], &ClipFormats[6] , (HANDLE16)NULL}, + { CF_OEMTEXT, 1, 0, "OEM Text", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[5], &ClipFormats[7] , (HANDLE16)NULL}, + { CF_DIB, 1, 0, "DIB", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[6], &ClipFormats[8] , (HANDLE16)NULL}, + { CF_PALETTE, 1, 0, "Palette", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[7], &ClipFormats[9] , (HANDLE16)NULL}, + { CF_PENDATA, 1, 0, "PenData", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[8], &ClipFormats[10] , (HANDLE16)NULL}, + { CF_RIFF, 1, 0, "RIFF", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[9], &ClipFormats[11] , (HANDLE16)NULL}, + { CF_WAVE, 1, 0, "Wave", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[10], &ClipFormats[12] , (HANDLE16)NULL}, + { CF_OWNERDISPLAY, 1, 0, "Owner Display", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[11], &ClipFormats[13] , (HANDLE16)NULL}, + { CF_DSPTEXT, 1, 0, "DSPText", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[12], &ClipFormats[14] , (HANDLE16)NULL}, + { CF_DSPMETAFILEPICT, 1, 0, "DSPMetaFile Picture", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[13], &ClipFormats[15] , (HANDLE16)NULL}, + { CF_DSPBITMAP, 1, 0, "DSPBitmap", (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[14], NULL , (HANDLE16)NULL} }; static LPWINE_CLIPFORMAT __lookup_format( LPWINE_CLIPFORMAT lpFormat, WORD wID ) @@ -109,6 +109,8 @@ void CLIPBOARD_DeleteRecord(LPWINE_CLIPFORMAT lpFormat, BOOL bChange) { DeleteMetaFile( ((METAFILEPICT *)GlobalLock( lpFormat->hData32 ))->hMF ); GlobalFree(lpFormat->hData32); + if (lpFormat->hDataSrc32) + GlobalFree(lpFormat->hDataSrc32); if (lpFormat->hData16) /* HMETAFILE16 and HMETAFILE32 are apparently the same thing, and a shallow copy is enough to share a METAFILEPICT @@ -116,7 +118,7 @@ void CLIPBOARD_DeleteRecord(LPWINE_CLIPFORMAT lpFormat, BOOL bChange) should of course only be deleted once. */ GlobalFree16(lpFormat->hData16); } - else if (lpFormat->hData16) + if (lpFormat->hData16) { DeleteMetaFile16( ((METAFILEPICT16 *)GlobalLock16( lpFormat->hData16 ))->hMF ); GlobalFree16(lpFormat->hData16); @@ -126,6 +128,8 @@ void CLIPBOARD_DeleteRecord(LPWINE_CLIPFORMAT lpFormat, BOOL bChange) { if (lpFormat->hData32) GlobalFree(lpFormat->hData32); + if (lpFormat->hDataSrc32) + GlobalFree(lpFormat->hDataSrc32); if (lpFormat->hData16) GlobalFree16(lpFormat->hData16); } @@ -155,6 +159,63 @@ BOOL CLIPBOARD_IsPresent(WORD wFormat) return FALSE; } +/************************************************************************** + * CLIPBOARD_IsMemoryObject + * Tests if the clipboard format specifies a memory object + */ +BOOL CLIPBOARD_IsMemoryObject( WORD wFormat ) +{ + switch(wFormat) + { + case CF_BITMAP: + case CF_METAFILEPICT: + case CF_DSPTEXT: + case CF_ENHMETAFILE: + case CF_HDROP: + case CF_PALETTE: + case CF_PENDATA: + return FALSE; + default: + return TRUE; + } +} + +/*********************************************************************** + * CLIPBOARD_GlobalDupMem( HGLOBAL ) + * Helper method to duplicate an HGLOBAL chunk of memory into shared memory + */ +HGLOBAL CLIPBOARD_GlobalDupMem( HGLOBAL hGlobalSrc ) +{ + HGLOBAL hGlobalDest; + PVOID pGlobalSrc, pGlobalDest; + DWORD cBytes; + + if ( !hGlobalSrc ) + return 0; + + cBytes = GlobalSize(hGlobalSrc); + if ( 0 == cBytes ) + return 0; + + /* Turn on the DDESHARE and _MOVEABLE flags explicitly */ + hGlobalDest = GlobalAlloc( GlobalFlags(hGlobalSrc) | GMEM_DDESHARE | GMEM_MOVEABLE, + cBytes ); + if ( !hGlobalDest ) + return 0; + + pGlobalSrc = GlobalLock(hGlobalSrc); + pGlobalDest = GlobalLock(hGlobalDest); + if ( !pGlobalSrc || !pGlobalDest ) + return 0; + + memcpy(pGlobalDest, pGlobalSrc, cBytes); + + GlobalUnlock(hGlobalSrc); + GlobalUnlock(hGlobalDest); + + return hGlobalDest; +} + /************************************************************************** * OpenClipboard16 (USER.137) */ @@ -365,7 +426,17 @@ HANDLE WINAPI SetClipboardData( UINT wFormat, HANDLE hData ) bCBHasChanged = TRUE; lpFormat->wDataPresent = 1; + lpFormat->hDataSrc32 = hData; /* Save the source handle */ + + /* + * Make a shared duplicate if the memory is not shared + * TODO: What should be done for non-memory objects + */ + if ( CLIPBOARD_IsMemoryObject(wFormat) && hData && !(GlobalFlags(hData) & GMEM_DDESHARE) ) + lpFormat->hData32 = CLIPBOARD_GlobalDupMem( hData ); + else lpFormat->hData32 = hData; /* 0 is legal, see WM_RENDERFORMAT */ + lpFormat->hData16 = 0; return lpFormat->hData32; @@ -569,7 +640,8 @@ HANDLE WINAPI GetClipboardData( UINT wFormat ) size = sizeof( METAFILEPICT ); else size = GlobalSize16(lpUpdate->hData16); - lpUpdate->hData32 = GlobalAlloc(GMEM_ZEROINIT, size); + lpUpdate->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, + size); if( lpUpdate->wFormatID == CF_METAFILEPICT ) { FIXME("\timplement function CopyMetaFilePict16to32\n"); @@ -729,6 +801,7 @@ UINT16 WINAPI RegisterClipboardFormat16( LPCSTR FormatName ) lpNewFormat->wDataPresent = 0; lpNewFormat->hData16 = 0; + lpNewFormat->hDataSrc32 = 0; lpNewFormat->hData32 = 0; lpNewFormat->BufSize = 0; lpNewFormat->PrevFormat = lpFormat;