Fix bug with pasting Wine clipboard content to external applications,

by storing clipboard data on the shared system heap.
This commit is contained in:
Noel Borthwick 1999-07-24 12:18:04 +00:00 committed by Alexandre Julliard
parent 564b784402
commit 83579c8286
3 changed files with 154 additions and 42 deletions

View File

@ -10,6 +10,7 @@ typedef struct tagWINE_CLIPFORMAT {
WORD wRefCount;
WORD wDataPresent;
LPSTR Name;
HANDLE hDataSrc32;
HANDLE hData32;
DWORD BufSize;
struct tagWINE_CLIPFORMAT *PrevFormat;

View File

@ -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;

View File

@ -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;