Commit 83579c82 authored by Noel Borthwick's avatar Noel Borthwick Committed by Alexandre Julliard

Fix bug with pasting Wine clipboard content to external applications,

by storing clipboard data on the shared system heap.
parent 564b7844
......@@ -10,6 +10,7 @@ typedef struct tagWINE_CLIPFORMAT {
WORD wRefCount;
WORD wDataPresent;
LPSTR Name;
HANDLE hDataSrc32;
HANDLE hData32;
DWORD BufSize;
struct tagWINE_CLIPFORMAT *PrevFormat;
......
......@@ -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();
/* HeapLock(heap); */
pintern=HeapAlloc(GetProcessHeap(), 0, sizeof(GLOBAL32_INTERN));
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;
......
......@@ -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);
}
......@@ -156,6 +160,63 @@ BOOL CLIPBOARD_IsPresent(WORD wFormat)
}
/**************************************************************************
* 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)
*/
BOOL16 WINAPI OpenClipboard16( HWND16 hWnd )
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment