- Rewrite clipboard to match Windows implementation
- Clipboard uses window stations instead of global variables
- Data is saved in clipboard data user objects
- Memory is no longer leaked when winsta is destroyed
- Data is synthesized on demand
- Make internal functions static
- Fix possible memory corruption in IntGetAtomName
- More winetests are passed

svn path=/trunk/; revision=53644
This commit is contained in:
Rafal Harabien
2011-09-08 16:32:54 +00:00
parent d7f5b33e0d
commit 6a2bccb41c
10 changed files with 1221 additions and 1268 deletions
+172 -103
View File
@@ -43,40 +43,6 @@ EnumClipboardFormats(UINT format)
return NtUserxEnumClipboardFormats(format);
}
/*
* @implemented
*/
HANDLE
WINAPI
GetClipboardData(UINT uFormat)
{
HGLOBAL hGlobal = NULL;
PVOID pGlobal = NULL;
DWORD_PTR size = 0;
/* dealing with bitmap object */
if (uFormat != CF_BITMAP)
{
size = (DWORD_PTR)NtUserGetClipboardData(uFormat, NULL);
if (size)
{
hGlobal = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, size);
pGlobal = GlobalLock(hGlobal);
size = (DWORD_PTR)NtUserGetClipboardData(uFormat, pGlobal);
GlobalUnlock(hGlobal);
}
}
else
{
hGlobal = NtUserGetClipboardData(CF_BITMAP, NULL);
}
return hGlobal;
}
/*
* @implemented
*/
@@ -87,7 +53,6 @@ GetClipboardFormatNameA(UINT format,
int cchMaxCount)
{
LPWSTR lpBuffer;
UNICODE_STRING FormatName;
INT Length;
lpBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, cchMaxCount * sizeof(WCHAR));
@@ -97,12 +62,8 @@ GetClipboardFormatNameA(UINT format,
return 0;
}
FormatName.Length = 0;
FormatName.MaximumLength = cchMaxCount * sizeof(WCHAR);
FormatName.Buffer = lpBuffer;
/* we need a UNICODE string */
Length = NtUserGetClipboardFormatName(format, &FormatName, cchMaxCount);
Length = NtUserGetClipboardFormatName(format, lpBuffer, cchMaxCount);
if (Length != 0)
{
@@ -123,25 +84,16 @@ GetClipboardFormatNameA(UINT format,
*/
INT
WINAPI
GetClipboardFormatNameW(UINT format,
GetClipboardFormatNameW(UINT uFormat,
LPWSTR lpszFormatName,
INT cchMaxCount)
{
UNICODE_STRING FormatName;
ULONG Ret;
FormatName.Length = 0;
FormatName.MaximumLength = cchMaxCount * sizeof(WCHAR);
FormatName.Buffer = (PWSTR)lpszFormatName;
Ret = NtUserGetClipboardFormatName(format, &FormatName, cchMaxCount);
return Ret;
return NtUserGetClipboardFormatName(uFormat, lpszFormatName, cchMaxCount);
}
/*
* @implemented
*/
UINT
WINAPI
RegisterClipboardFormatA(LPCSTR lpszFormat)
@@ -201,26 +153,132 @@ RegisterClipboardFormatW(LPCWSTR lpszFormat)
return ret;
}
HGLOBAL
renderLocale(DWORD Locale)
PVOID static WINAPI
IntSynthesizeMultiByte(PVOID pwStr, DWORD cbStr, BOOL bOem)
{
DWORD* pLocale;
HGLOBAL hGlobal;
HANDLE hGlobal;
PVOID pGlobal;
INT cbGlobal;
hGlobal = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(DWORD));
cbGlobal = WideCharToMultiByte(bOem ? CP_OEMCP : CP_ACP,
0, pwStr, cbStr / sizeof(WCHAR),
NULL, 0, NULL, NULL);
hGlobal = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, cbGlobal);
if (!hGlobal)
return NULL;
if(!hGlobal)
pGlobal = GlobalLock(hGlobal);
WideCharToMultiByte(bOem ? CP_OEMCP : CP_ACP,
0, pwStr, cbStr / sizeof(WCHAR),
pGlobal, cbGlobal, NULL, NULL);
return pGlobal;
}
PVOID static WINAPI
IntSynthesizeWideChar(PVOID pwStr, DWORD cbStr, BOOL bOem)
{
HANDLE hGlobal;
PVOID pGlobal;
INT cbGlobal;
cbGlobal = MultiByteToWideChar(bOem ? CP_OEMCP : CP_ACP,
0, pwStr, cbStr, NULL, 0) * sizeof(WCHAR);
hGlobal = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, cbGlobal);
if (!hGlobal)
return NULL;
pGlobal = GlobalLock(hGlobal);
MultiByteToWideChar(bOem ? CP_OEMCP : CP_ACP,
0, pwStr, cbStr, pGlobal, cbGlobal);
return pGlobal;
}
/*
* @implemented
*/
HANDLE
WINAPI
GetClipboardData(UINT uFormat)
{
HANDLE hData = NULL;
PVOID pData = NULL;
DWORD cbData = 0;
GETCLIPBDATA gcd;
hData = NtUserGetClipboardData(uFormat, &gcd);
if (gcd.fGlobalHandle)
{
return hGlobal;
HANDLE hGlobal;
NtUserCreateLocalMemHandle(hData, NULL, 0, &cbData);
hGlobal = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, cbData);
pData = GlobalLock(hGlobal);
NtUserCreateLocalMemHandle(hData, pData, cbData, NULL);
hData = hGlobal;
}
pLocale = (DWORD*)GlobalLock(hGlobal);
if (gcd.uFmtRet != uFormat)
{
SETCLIPBDATA scd = {FALSE, FALSE};
HANDLE hNewData = NULL;
PVOID pNewData = NULL;
*pLocale = Locale;
/* Synthesize requested format */
switch (uFormat)
{
case CF_TEXT:
if (gcd.uFmtRet == CF_UNICODETEXT)
pNewData = IntSynthesizeMultiByte(pData, cbData, uFormat == CF_OEMTEXT);
else // CF_OEMTEXT
OemToCharBuffA(pData, pData, cbData);
break;
case CF_OEMTEXT:
if (gcd.uFmtRet == CF_UNICODETEXT)
pNewData = IntSynthesizeMultiByte(pData, cbData, uFormat == CF_OEMTEXT);
else
CharToOemBuffA(pData, pData, cbData);
break;
case CF_UNICODETEXT:
pNewData = IntSynthesizeWideChar(pData, cbData, gcd.uFmtRet == CF_OEMTEXT);
break;
default:
FIXME("Format: %u\n", uFormat);
}
GlobalUnlock(hGlobal);
/* Is it a global handle? */
if (pNewData)
hNewData = GlobalHandle(pNewData);
return hGlobal;
if (hNewData)
{
/* Free old data */
if (pData)
{
GlobalUnlock(hData);
GlobalFree(hData);
}
hData = hNewData;
pData = pNewData;
}
/* Save synthesized format in clibboard */
if (pData)
{
HANDLE hMem;
scd.fGlobalHandle = TRUE;
hMem = NtUserConvertMemHandle(pData, GlobalSize(hData));
NtUserSetClipboardData(uFormat, hMem, &scd);
}
else if (hData)
NtUserSetClipboardData(uFormat, hData, &scd);
}
/* Unlock global handle */
if (pData)
GlobalUnlock(hData);
return hData;
}
/*
@@ -230,60 +288,71 @@ HANDLE
WINAPI
SetClipboardData(UINT uFormat, HANDLE hMem)
{
DWORD size;
DWORD dwSize;
HANDLE hGlobal;
LPVOID pMem;
HANDLE ret = NULL;
HANDLE hRet = NULL;
SETCLIPBDATA scd = {FALSE, FALSE};
/* Check if this is delayed render */
if (hMem == NULL)
{
return NtUserSetClipboardData(uFormat, 0, 0);
}
return NtUserSetClipboardData(uFormat, NULL, &scd);
if (uFormat == CF_BITMAP)
if (hMem <= (HANDLE)4)
SetLastError(ERROR_INVALID_PARAMETER);
/* Bitmaps and palette does not use global handles */
else if (uFormat == CF_BITMAP || uFormat == CF_DSPBITMAP || uFormat == CF_PALETTE)
hRet = NtUserSetClipboardData(uFormat, hMem, &scd);
/* Meta files are probably checked for validity */
else if (uFormat == CF_DSPMETAFILEPICT || uFormat == CF_METAFILEPICT ||
uFormat == CF_DSPENHMETAFILE || uFormat == CF_ENHMETAFILE)
hRet = NULL; // not supported yet
else
{
/* GlobalLock should return 0 for GDI handles
/* Some formats accept only global handles, other accept global handles or integer values */
pMem = GlobalLock(hMem);
if (pMem)
dwSize = GlobalSize(hMem);
if (pMem || uFormat == CF_DIB || uFormat == CF_DIBV5 ||
uFormat == CF_DSPTEXT || uFormat == CF_LOCALE ||
uFormat == CF_OEMTEXT || uFormat == CF_TEXT ||
uFormat == CF_UNICODETEXT)
{
// not a GDI handle
GlobalUnlock(hMem);
return ret;
if (pMem)
{
/* This is a local memory. Make global memory object */
hGlobal = NtUserConvertMemHandle(pMem, dwSize);
/* Unlock memory */
GlobalUnlock(hMem);
/* FIXME: free hMem when CloseClipboard is called */
if (hGlobal)
{
/* Save data */
scd.fGlobalHandle = TRUE;
hRet = NtUserSetClipboardData(uFormat, hGlobal, &scd);
}
/* On success NtUserSetClipboardData returns pMem
however caller expects us to return hMem */
if (hRet == hGlobal)
hRet = hMem;
}
else
SetLastError(ERROR_INVALID_HANDLE);
}
else
{
*/
/* check if this GDI handle is a HBITMAP */
/* GetObject for HBITMAP not implemented in ReactOS */
//if (GetObject(hMem, 0, NULL) == sifeof(BITMAP))
//{
return NtUserSetClipboardData(CF_BITMAP, hMem, 0);
//}
/*}*/
/* Save a number */
hRet = NtUserSetClipboardData(uFormat, hMem, &scd);
}
}
size = GlobalSize(hMem);
pMem = GlobalLock(hMem);
if ((pMem) && (size))
{
size = GlobalSize(hMem);
ret = NtUserSetClipboardData(uFormat, pMem, size);
//On success NtUserSetClipboardData returns pMem
//however caller expects us to return hMem
if (ret == pMem)
ret = hMem;
//should i unlock hMem?
GlobalUnlock(hMem);
}
else
{
ERR("SetClipboardData failed\n");
}
return ret;
if (!hRet)
ERR("SetClipboardData(%u, %p) failed\n", uFormat, hMem);
return hRet;
}
/*
+41 -17
View File
@@ -205,6 +205,13 @@ typedef struct tagHOOK
UNICODE_STRING ModuleName; /* Module name for global hooks */
} HOOK, *PHOOK;
typedef struct tagCLIPBOARDDATA
{
HEAD head;
DWORD cbData;
BYTE Data[0];
} CLIPBOARDDATA, *PCLIPBOARDDATA;
/* THREADINFO Flags */
#define TIF_INCLEANUP 0x00000001
#define TIF_16BIT 0x00000002
@@ -909,6 +916,23 @@ typedef struct _USERCONNECT
SHAREDINFO siClient;
} USERCONNECT, *PUSERCONNECT;
typedef struct tagGETCLIPBDATA
{
UINT uFmtRet;
BOOL fGlobalHandle;
union
{
HANDLE hLocale;
HANDLE hPalette;
};
} GETCLIPBDATA, *PGETCLIPBDATA;
typedef struct tagSETCLIPBDATA
{
BOOL fGlobalHandle;
BOOL fIncSerialNumber;
} SETCLIPBDATA, *PSETCLIPBDATA;
DWORD
NTAPI
NtUserAssociateInputContext(
@@ -1010,8 +1034,8 @@ NtUserGetSystemMenu(
BOOL
NTAPI
NtUserHiliteMenuItem(
HWND hwnd,
HMENU hmenu,
HWND hWnd,
HMENU hMenu,
UINT uItemHilite,
UINT uHilite);
@@ -1464,11 +1488,11 @@ NtUserConsoleControl(
DWORD dwUnknown2,
DWORD dwUnknown3);
DWORD
HANDLE
NTAPI
NtUserConvertMemHandle(
DWORD Unknown0,
DWORD Unknown1);
PVOID pData,
DWORD cbData);
int
NTAPI
@@ -1509,13 +1533,13 @@ NTAPI
NtUserCreateInputContext(
DWORD dwUnknown1);
DWORD
NTSTATUS
NTAPI
NtUserCreateLocalMemHandle(
DWORD Unknown0,
DWORD Unknown1,
DWORD Unknown2,
DWORD Unknown3);
HANDLE hMem,
PVOID pData,
DWORD cbData,
DWORD *pcbData);
HWND
NTAPI
@@ -1678,7 +1702,7 @@ NtUserDrawIconEx(
BOOL bMetaHDC,
PVOID pDIXData);
DWORD
BOOL
NTAPI
NtUserEmptyClipboard(VOID);
@@ -1828,14 +1852,14 @@ NtUserGetClassName(HWND hWnd,
HANDLE
NTAPI
NtUserGetClipboardData(
UINT uFormat,
PVOID pBuffer);
UINT fmt,
PGETCLIPBDATA pgcd);
INT
NTAPI
NtUserGetClipboardFormatName(
UINT format,
PUNICODE_STRING FormatName,
UINT uFormat,
LPWSTR lpszFormatName,
INT cchMaxCount);
HWND
@@ -2634,9 +2658,9 @@ NtUserSetClassWord(
HANDLE
NTAPI
NtUserSetClipboardData(
UINT uFormat,
UINT fmt,
HANDLE hMem,
DWORD Unknown2);
PSETCLIPBDATA scd);
HWND
NTAPI
@@ -1,40 +1,22 @@
#pragma once
typedef struct _ClipboardChainElement
#include "window.h"
#include <include/win32.h>
typedef struct _CLIP
{
PWND window;
struct _ClipboardChainElement *next;
} CLIPBOARDCHAINELEMENT, *PCLIPBOARDCHAINELEMENT;
UINT fmt;
HANDLE hData;
BOOL fGlobalHandle;
} CLIP, *PCLIP;
typedef struct _ClipboardElement
{
UINT format;
HANDLE hData;
DWORD size; // data may be delayed o synth render
struct _ClipboardElement *next;
} CLIPBOARDELEMENT, *PCLIPBOARDELEMENT;
UINT APIENTRY
UserEnumClipboardFormats(UINT uFormat);
typedef struct _CLIPBOARDSYSTEM
{
PTHREADINFO ClipboardThread;
PTHREADINFO ClipboardOwnerThread;
PWND ClipboardWindow;
PWND ClipboardViewerWindow;
PWND ClipboardOwnerWindow;
BOOL sendDrawClipboardMsg;
BOOL recentlySetClipboard;
BOOL delayedRender;
UINT lastEnumClipboardFormats;
DWORD ClipboardSequenceNumber;
VOID FASTCALL
UserClipboardFreeWindow(PWND pWindow);
PCLIPBOARDCHAINELEMENT WindowsChain;
PCLIPBOARDELEMENT ClipboardData;
struct _WINSTATION_OBJECT;
PCHAR synthesizedData;
DWORD synthesizedDataSize;
} CLIPBOARDSYSTEM, *PCLIPBOARDSYSTEM;
VOID FASTCALL IntClipboardFreeWindow(PWND window);
UINT APIENTRY IntEnumClipboardFormats(UINT format);
VOID FASTCALL IntIncrementSequenceNumber(VOID);
VOID NTAPI
UserEmptyClipboardData(struct _WINSTATION_OBJECT *pWinSta);
@@ -39,7 +39,7 @@ typedef struct _WINSTATION_OBJECT
/* ScreenSaver */
BOOL ScreenSaverRunning;
UINT ScreenSaverTimeOut;
UINT ScreenSaverTimeOut;
/* Should this be on each desktop ? */
BOOL ScreenSaverActive;
@@ -51,8 +51,17 @@ typedef struct _WINSTATION_OBJECT
ULONG Flags;
struct _DESKTOP* ActiveDesktop;
PCLIPBOARDSYSTEM Clipboard;
DWORD ClipboardSequenceNumber;
PTHREADINFO ptiClipLock;
PTHREADINFO ptiDrawingClipboard;
PWND spwndClipOpen;
PWND spwndClipViewer;
PWND spwndClipOwner;
PCLIP pClipBase; // Not a clip object.
DWORD cNumClipFormats;
INT iClipSerialNumber;
INT iClipSequenceNumber;
INT fClipboardChanged : 1;
INT fInDelayedRendering : 1;
} WINSTATION_OBJECT, *PWINSTATION_OBJECT;
File diff suppressed because it is too large Load Diff
@@ -108,30 +108,6 @@ NtUserBuildHimcList(
return 0;
}
DWORD
APIENTRY
NtUserConvertMemHandle(
DWORD Unknown0,
DWORD Unknown1)
{
STUB
return 0;
}
DWORD
APIENTRY
NtUserCreateLocalMemHandle(
DWORD Unknown0,
DWORD Unknown1,
DWORD Unknown2,
DWORD Unknown3)
{
STUB
return 0;
}
BOOL
APIENTRY
NtUserDdeGetQualityOfService(
@@ -313,7 +313,7 @@ NtUserCallOneParam(
}
case ONEPARAM_ROUTINE_ENUMCLIPBOARDFORMATS:
/* FIXME: Should use UserEnterShared */
RETURN(IntEnumClipboardFormats(Param));
RETURN(UserEnumClipboardFormats(Param));
case ONEPARAM_ROUTINE_CSRSS_GUICHECK:
IntUserManualGuiCheck(Param);
@@ -69,7 +69,7 @@ IntGetAtomName(RTL_ATOM nAtom, LPWSTR lpBuffer, ULONG nSize)
Status = RtlQueryAtomInAtomTable(gAtomTable, nAtom, NULL, NULL, lpBuffer, &Size);
if (Size < nSize)
*(lpBuffer + Size) = 0;
*(lpBuffer + Size/sizeof(WCHAR)) = 0;
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
@@ -482,7 +482,7 @@ static LRESULT co_UserFreeWindow(PWND Window,
UserDereferenceObject(Window);
IntClipboardFreeWindow(Window);
UserClipboardFreeWindow(Window);
return 0;
}
@@ -97,18 +97,6 @@ CleanupWindowStationImpl(VOID)
return STATUS_SUCCESS;
}
BOOL FASTCALL
IntSetupClipboard(PWINSTATION_OBJECT WinStaObj)
{
WinStaObj->Clipboard = ExAllocatePoolWithTag(PagedPool, sizeof(CLIPBOARDSYSTEM), TAG_WINSTA);
if (WinStaObj->Clipboard)
{
RtlZeroMemory(WinStaObj->Clipboard, sizeof(CLIPBOARDSYSTEM));
return TRUE;
}
return FALSE;
}
/* OBJECT CALLBACKS **********************************************************/
VOID APIENTRY
@@ -118,6 +106,8 @@ IntWinStaObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters)
TRACE("Deleting window station (0x%X)\n", WinSta);
UserEmptyClipboardData(WinSta);
RtlDestroyAtomTable(WinSta->AtomTable);
RtlFreeUnicodeString(&WinSta->Name);
@@ -240,14 +230,14 @@ IntGetFullWindowStationName(
Buffer += WINSTA_ROOT_NAME_LENGTH;
if (WinStaName != NULL)
{
memcpy(Buffer, L"\\", sizeof(WCHAR));
*Buffer = L'\\';
Buffer ++;
memcpy(Buffer, WinStaName->Buffer, WinStaName->Length);
if (DesktopName != NULL)
{
Buffer += WinStaName->Length / sizeof(WCHAR);
memcpy(Buffer, L"\\", sizeof(WCHAR));
*Buffer = L'\\';
Buffer ++;
memcpy(Buffer, DesktopName->Buffer, DesktopName->Length);
}
@@ -504,11 +494,6 @@ NtUserCreateWindowStation(
WindowStationObject->ScreenSaverRunning = FALSE;
WindowStationObject->FlatMenu = FALSE;
if (!IntSetupClipboard(WindowStationObject))
{
ERR("WindowStation: Error Setting up the clipboard!!!\n");
}
if (InputWindowStation == NULL)
{
InputWindowStation = WindowStationObject;