[WIN32K]
authorRafal Harabien <rafalh@reactos.org>
Thu, 8 Sep 2011 16:32:54 +0000 (16:32 +0000)
committerRafal Harabien <rafalh@reactos.org>
Thu, 8 Sep 2011 16:32:54 +0000 (16:32 +0000)
- 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

reactos/dll/win32/user32/windows/clipboard.c
reactos/include/reactos/win32k/ntuser.h
reactos/subsystems/win32/win32k/include/clipboard.h
reactos/subsystems/win32/win32k/include/winsta.h
reactos/subsystems/win32/win32k/ntuser/clipboard.c
reactos/subsystems/win32/win32k/ntuser/ntstubs.c
reactos/subsystems/win32/win32k/ntuser/simplecall.c
reactos/subsystems/win32/win32k/ntuser/useratom.c
reactos/subsystems/win32/win32k/ntuser/window.c
reactos/subsystems/win32/win32k/ntuser/winsta.c

index bcabcdb..ad72168 100644 (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;
+
+    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;
+
+    pGlobal = GlobalLock(hGlobal);
+    WideCharToMultiByte(bOem ? CP_OEMCP : CP_ACP,
+                        0, pwStr, cbStr / sizeof(WCHAR),
+                        pGlobal, cbGlobal, NULL, NULL);
+    return pGlobal;
+}
 
-    hGlobal = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(DWORD));
+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;
+}
 
-    if(!hGlobal)
+/*
+ * @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;
+
+        /* 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);
+        }
+
+        /* Is it a global handle? */
+        if (pNewData)
+            hNewData = GlobalHandle(pNewData);
+
+        if (hNewData)
+        {
+            /* Free old data */
+            if (pData)
+            {
+                GlobalUnlock(hData);
+                GlobalFree(hData);
+            }
+            hData = hNewData;
+            pData = pNewData;
+        }
+
+        /* Save synthesized format in clibboard */
+        if (pData)
+        {
+            HANDLE hMem;
 
-    *pLocale = Locale;
+            scd.fGlobalHandle = TRUE;
+            hMem = NtUserConvertMemHandle(pData, GlobalSize(hData));
+            NtUserSetClipboardData(uFormat, hMem, &scd);
+        }
+        else if (hData)
+            NtUserSetClipboardData(uFormat, hData, &scd);
+    }
 
-    GlobalUnlock(hGlobal);
+    /* Unlock global handle */
+    if (pData)
+        GlobalUnlock(hData);
 
-    return hGlobal;
+    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);
-            //}
-        /*}*/
-    }
-
-    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");
+            /* Save a number */
+            hRet = NtUserSetClipboardData(uFormat, hMem, &scd);
+        }
     }
 
-    return ret;
+    if (!hRet)
+        ERR("SetClipboardData(%u, %p) failed\n", uFormat, hMem);
 
+    return hRet;
 }
 
 /*
index 2e11ee5..e73c436 100644 (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
index 3d7754b..7825e11 100644 (file)
@@ -1,40 +1,22 @@
 #pragma once
 
-typedef struct _ClipboardChainElement
-{
-    PWND                 window;
-    struct _ClipboardChainElement *next;
-} CLIPBOARDCHAINELEMENT, *PCLIPBOARDCHAINELEMENT;
-
-typedef struct _ClipboardElement
-{
-    UINT                        format;
-    HANDLE                      hData;
-    DWORD                       size;   // data may be delayed o synth render
-    struct _ClipboardElement   *next;
-} CLIPBOARDELEMENT, *PCLIPBOARDELEMENT;
+#include "window.h"
+#include <include/win32.h>
 
-typedef struct _CLIPBOARDSYSTEM
+typedef struct _CLIP
 {
-    PTHREADINFO     ClipboardThread;
-    PTHREADINFO     ClipboardOwnerThread;
-    PWND  ClipboardWindow;
-    PWND  ClipboardViewerWindow;
-    PWND  ClipboardOwnerWindow;
-    BOOL            sendDrawClipboardMsg;
-    BOOL            recentlySetClipboard;
-    BOOL            delayedRender;
-    UINT            lastEnumClipboardFormats;
-    DWORD           ClipboardSequenceNumber;
+    UINT   fmt;
+    HANDLE hData;
+    BOOL   fGlobalHandle;
+} CLIP, *PCLIP;
 
-    PCLIPBOARDCHAINELEMENT WindowsChain;
-    PCLIPBOARDELEMENT      ClipboardData;
+UINT APIENTRY
+UserEnumClipboardFormats(UINT uFormat);
 
-    PCHAR synthesizedData;
-    DWORD synthesizedDataSize;
+VOID FASTCALL
+UserClipboardFreeWindow(PWND pWindow);
 
-} CLIPBOARDSYSTEM, *PCLIPBOARDSYSTEM;
+struct _WINSTATION_OBJECT;
 
-VOID FASTCALL IntClipboardFreeWindow(PWND window);
-UINT APIENTRY IntEnumClipboardFormats(UINT format);
-VOID FASTCALL IntIncrementSequenceNumber(VOID);
+VOID NTAPI
+UserEmptyClipboardData(struct _WINSTATION_OBJECT *pWinSta);
index 067c7eb..40599d6 100644 (file)
@@ -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;
 
index 9d0cde9..f4f2284 100644 (file)
  * FILE:             subsys/win32k/ntuser/clipboard.c
  * PROGRAMER:        Filip Navara <xnavara@volny.cz>
  *                   Pablo Borobia <pborobia@gmail.com>
+ *                   Rafal Harabien <rafalh@reactos.org>
  */
 
 #include <win32k.h>
 
 DBG_DEFAULT_CHANNEL(UserClipbrd);
 
-#define DATA_DELAYED_RENDER  0
-#define DATA_SYNTHESIZED_RENDER -1
+#define DATA_DELAYED     (HANDLE)0
+#define DATA_SYNTH_USER  (HANDLE)1
+#define DATA_SYNTH_KRNL  (HANDLE)2
+#define IS_DATA_DELAYED(ce)     ((ce)->hData == DATA_DELAYED)
+#define IS_DATA_SYNTHESIZED(ce) ((ce)->hData == DATA_SYNTH_USER || (ce)->hData == DATA_SYNTH_KRNL)
 
-PTHREADINFO      ClipboardThread;
-PTHREADINFO      ClipboardOwnerThread;
-PWND  ClipboardWindow;
-PWND  ClipboardViewerWindow;
-PWND  ClipboardOwnerWindow;
-BOOL            sendDrawClipboardMsg;
-BOOL            recentlySetClipboard;
-BOOL            delayedRender;
-UINT            lastEnumClipboardFormats;
-DWORD           ClipboardSequenceNumber = 0;
-
-PCLIPBOARDCHAINELEMENT WindowsChain = NULL;
-PCLIPBOARDELEMENT      ClipboardData = NULL;
-
-PCHAR synthesizedData;
-DWORD synthesizedDataSize;
-
-
-/*==============================================================*/
-
-/* return the pointer to the prev window of the finded window,
-   if NULL does not exists in the chain */
-PCLIPBOARDCHAINELEMENT FASTCALL
-IntIsWindowInChain(PWND window)
+PWINSTATION_OBJECT static FASTCALL
+IntGetWinStaForCbAccess()
 {
-    PCLIPBOARDCHAINELEMENT wce = WindowsChain;
+    HWINSTA hWinSta;
+    PWINSTATION_OBJECT pWinStaObj;
+    NTSTATUS Status;
 
-    while (wce)
+    hWinSta = UserGetProcessWindowStation();
+    Status = IntValidateWindowStationHandle(hWinSta, KernelMode, WINSTA_ACCESSCLIPBOARD, &pWinStaObj);
+    if (!NT_SUCCESS(Status))
     {
-        if (wce->window == window)
-        {
-            break;
-        }
-        wce = wce->next;
+        ERR("Cannot open winsta\n");
+        SetLastNtError(Status);
+        return NULL;
     }
 
-    return wce;
+    return pWinStaObj;
 }
 
-VOID FASTCALL printChain(VOID)
+/* if format exists, returns a non zero value (pointing to formated object) */
+PCLIP static FASTCALL
+IntIsFormatAvailable(PWINSTATION_OBJECT pWinStaObj, UINT fmt)
 {
-    /*test*/
-    PCLIPBOARDCHAINELEMENT wce2 = WindowsChain;
-    while (wce2)
+    unsigned i = 0;
+
+    for (i = 0; i < pWinStaObj->cNumClipFormats; ++i)
     {
-        ERR("chain: %p\n", wce2->window->head.h);
-        wce2 = wce2->next;
+           if (pWinStaObj->pClipBase[i].fmt == fmt)
+            return &pWinStaObj->pClipBase[i];
     }
+
+    return NULL;
 }
 
-/* the new window always have to be the first in the chain */
-PCLIPBOARDCHAINELEMENT FASTCALL
-IntAddWindowToChain(PWND window)
+VOID static FASTCALL
+IntFreeElementData(PCLIP pElement)
 {
-    PCLIPBOARDCHAINELEMENT wce = NULL;
-
-    if (!IntIsWindowInChain(window))
+    if (!IS_DATA_DELAYED(pElement) &&
+        !IS_DATA_SYNTHESIZED(pElement))
     {
-        wce = WindowsChain;
-
-        wce = ExAllocatePoolWithTag(PagedPool, sizeof(CLIPBOARDCHAINELEMENT), USERTAG_CLIPBOARD);
-        if (wce == NULL)
+        if (pElement->fGlobalHandle)
+            UserDeleteObject(pElement->hData, otClipBoardData);
+        else if (pElement->fmt == CF_BITMAP || pElement->fmt == CF_PALETTE ||
+                 pElement->fmt == CF_DSPBITMAP)
         {
-            EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            goto exit_addChain;
+            GreDeleteObject(pElement->hData);
         }
-
-        wce->window = window;
-        wce->next = WindowsChain;
-
-        WindowsChain = wce;
-
-        //printChain();
     }
-exit_addChain:
-
-    /* return the next window to beremoved later */
-    return wce;
 }
 
-PCLIPBOARDCHAINELEMENT FASTCALL
-IntRemoveWindowFromChain(PWND window)
+/* adds a new format and data to the clipboard */
+PCLIP static NTAPI
+IntAddFormatedData(PWINSTATION_OBJECT pWinStaObj, UINT fmt, HANDLE hData, BOOLEAN fGlobalHandle, BOOL bEnd)
 {
-    PCLIPBOARDCHAINELEMENT wce = WindowsChain;
-       PCLIPBOARDCHAINELEMENT *link = &WindowsChain;
+    PCLIP pElement = NULL;
+
+    /* Use exisiting entry with specified format */
+    if (!bEnd)
+        pElement = IntIsFormatAvailable(pWinStaObj, fmt);
 
-    if (IntIsWindowInChain(window))
+    /* Put new entry at the end if nothing was found */
+    if (!pElement)
     {
-        while (wce != NULL)
+        /* Allocate bigger clipboard if needed. We could use lists but Windows uses array */
+        if (pWinStaObj->cNumClipFormats % 4 == 0)
         {
-            if (wce->window == window)
+            PCLIP pNewClip;
+
+            /* Allocate new clipboard */
+            pNewClip = ExAllocatePoolWithTag(PagedPool,
+                                             (pWinStaObj->cNumClipFormats + 4) * sizeof(CLIP),
+                                             USERTAG_CLIPBOARD);
+            if (!pNewClip)
             {
-                *link = wce->next;
-                break;
+                EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                return NULL;
             }
 
-            link = &wce->next;
-            wce = wce->next;
-        }
+            /* Copy data */
+            memcpy(pNewClip, pWinStaObj->pClipBase, pWinStaObj->cNumClipFormats * sizeof(CLIP));
 
-        //printChain();
+            /* Free old clipboard */
+            if (pWinStaObj->pClipBase)
+                ExFreePoolWithTag(pWinStaObj->pClipBase, USERTAG_CLIPBOARD);
 
-        return wce;
+            /* Update WinSta */
+            pWinStaObj->pClipBase = pNewClip;
+        }
+
+        /* New element is at the end */
+        pElement = &pWinStaObj->pClipBase[pWinStaObj->cNumClipFormats];
+        pElement->fmt = fmt;
+        pWinStaObj->cNumClipFormats++;
     }
     else
-    {
-        return NULL;
-    }
-}
+        IntFreeElementData(pElement);
 
+    pElement->hData = hData;
+    pElement->fGlobalHandle = fGlobalHandle;
 
-/*==============================================================*/
-/* if format exists, returns a non zero value (pointing to format object) */
-PCLIPBOARDELEMENT FASTCALL
-intIsFormatAvailable(UINT format)
-{
-    PCLIPBOARDELEMENT ret = NULL;
-    PCLIPBOARDELEMENT ce = ClipboardData;
+    return pElement;
+}
 
-    while(ce)
+BOOL static FASTCALL
+IntIsClipboardOpenByMe(PWINSTATION_OBJECT pWinSta)
+{
+    /* check if current thread has opened the clipboard */
+    if (pWinSta->ptiClipLock &&
+        pWinSta->ptiClipLock == PsGetCurrentThreadWin32Thread())
     {
-           if (ce->format == format)
-           {
-               ret = ce;
-               break;
-           }
-           ce = ce->next;
+        return TRUE;
     }
-    return ret;
+
+    return FALSE;
 }
 
-/* counts how many distinct format were are in the clipboard */
-DWORD FASTCALL
-IntCountClipboardFormats(VOID)
+VOID static NTAPI
+IntSynthesizeDib(PWINSTATION_OBJECT pWinStaObj, HBITMAP hBm)
 {
-    DWORD ret = 0;
-    PCLIPBOARDELEMENT ce = ClipboardData;
-
-    while(ce)
+    HDC hdc;
+    BITMAP bm;
+    BITMAPINFO bi;
+    SURFACE *psurf;
+    PCLIPBOARDDATA pMemObj;
+    HANDLE hMem;
+
+    hdc = UserGetDCEx(NULL, NULL, DCX_USESTYLE);
+    if (!hdc)
+        return;
+
+    psurf = SURFACE_ShareLockSurface(hBm);
+    if (!psurf)
+        goto cleanup;
+    BITMAP_GetObject(psurf, sizeof(BITMAP), (PVOID)&bm);
+    SURFACE_ShareUnlockSurface(psurf);
+
+    bi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
+    bi.bmiHeader.biWidth = bm.bmWidth;
+    bi.bmiHeader.biHeight = bm.bmHeight;
+    bi.bmiHeader.biPlanes = bm.bmPlanes;
+    bi.bmiHeader.biBitCount    = bm.bmBitsPixel;
+    bi.bmiHeader.biCompression = BI_RGB;
+    bi.bmiHeader.biSizeImage = 0;
+    bi.bmiHeader.biXPelsPerMeter = 0;
+    bi.bmiHeader.biYPelsPerMeter = 0;
+    bi.bmiHeader.biClrUsed = 0;
+
+    NtGdiGetDIBitsInternal(hdc, hBm, 0, bm.bmHeight, NULL, &bi, DIB_RGB_COLORS, 0, 0);
+
+    pMemObj = (PCLIPBOARDDATA)UserCreateObject(gHandleTable, NULL, &hMem, otClipBoardData,
+                                               sizeof(BITMAPINFOHEADER) + bi.bmiHeader.biSizeImage);
+    if(pMemObj)
     {
-        ret++;
-           ce = ce->next;
+        pMemObj->cbData = sizeof(BITMAPINFOHEADER) + bi.bmiHeader.biSizeImage;
+        memcpy(pMemObj->Data, &bi, sizeof(BITMAPINFOHEADER));
+        NtGdiGetDIBitsInternal(hdc, pMemObj->Data, 0, bm.bmHeight, (LPBYTE)pMemObj->Data + sizeof(BITMAPINFOHEADER), &bi, DIB_RGB_COLORS, 0, 0);
+        IntAddFormatedData(pWinStaObj, CF_DIB, hMem, TRUE, TRUE);
     }
-    return ret;
+
+cleanup:
+    UserReleaseDC(NULL, hdc, FALSE);
 }
 
-/* adds a new format and data to the clipboard */
-PCLIPBOARDELEMENT FASTCALL
-intAddFormatedData(UINT format, HANDLE hData, DWORD size)
+VOID static WINAPI
+IntSynthesizeBitmap(PWINSTATION_OBJECT pWinStaObj, PCLIP pBmEl)
 {
-    PCLIPBOARDELEMENT ce = NULL;
+    HDC hdc = NULL;
+    PBITMAPINFO pBmi, pConvertedBmi = NULL;
+    HBITMAP hBm = NULL;
+    PCLIPBOARDDATA pMemObj;
+    PCLIP pDibEl;
+    ULONG Offset;
 
-    ce = ExAllocatePoolWithTag(PagedPool, sizeof(CLIPBOARDELEMENT), USERTAG_CLIPBOARD);
-    if (ce == NULL)
-    {
-        EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
-    }
-    else
-    {
-        ce->format = format;
-        ce->size = size;
-        ce->hData = hData;
-        ce->next = ClipboardData;
+    TRACE("IntSynthesizeBitmap(%p, %p)\n", pWinStaObj, pBmEl);
 
-        ClipboardData = ce;
+    pDibEl = IntIsFormatAvailable(pWinStaObj, CF_DIB);
+    ASSERT(pDibEl && !IS_DATA_SYNTHESIZED(pDibEl));
+    if(!pDibEl->fGlobalHandle)
+        return;
 
-        IntIncrementSequenceNumber();
-    }
+    pMemObj = (PCLIPBOARDDATA)UserGetObject(gHandleTable, pDibEl->hData, otClipBoardData);
+    if (!pMemObj)
+        return;
 
-    return ce;
-}
+       pBmi = (BITMAPINFO*)pMemObj->Data;
 
-/* removes a format and its data from the clipboard */
-BOOL FASTCALL
-intRemoveFormatedData(UINT format)
-{
-    BOOL ret = FALSE;
-    PCLIPBOARDELEMENT ce = ClipboardData;
-    PCLIPBOARDELEMENT *link = &ClipboardData;
+    if (pMemObj->cbData < sizeof(DWORD) && pMemObj->cbData < pBmi->bmiHeader.biSize)
+        goto cleanup;
 
-    if (intIsFormatAvailable(format))
-    {
-        while (ce != NULL)
-        {
-            if (ce->format == format)
-            {
-                *link = ce->next;
-                break;
-            }
+    pConvertedBmi = DIB_ConvertBitmapInfo(pBmi, DIB_RGB_COLORS);
+    if (!pConvertedBmi)
+        goto cleanup;
 
-            link = &ce->next;
-            ce = ce->next;
-        }
+    Offset = DIB_BitmapInfoSize(pBmi, DIB_RGB_COLORS);
 
-        if (ce->hData)
-        {
-            ExFreePool(ce->hData);
-        }
-        ExFreePool(ce);
-        ret = TRUE;
-    }
+    hdc = UserGetDCEx(NULL, NULL, DCX_USESTYLE);
+    if (!hdc)
+        goto cleanup;
 
-    return ret;
-}
+    hBm = GreCreateDIBitmapInternal(hdc,
+                                    pConvertedBmi->bmiHeader.biWidth,
+                                    pConvertedBmi->bmiHeader.biHeight,
+                                    CBM_INIT,
+                                    pMemObj->Data + Offset,
+                                    pConvertedBmi,
+                                    DIB_RGB_COLORS,
+                                    0,
+                                    0);
 
-VOID FASTCALL
-IntEmptyClipboardData(VOID)
-{
-    PCLIPBOARDELEMENT ce = ClipboardData;
-    PCLIPBOARDELEMENT tmp;
-
-    while(ce)
+    if (hBm)
     {
-        tmp = ce->next;
-               if (ce->hData)
-               {
-            ExFreePool(ce->hData);
-        }
-           ExFreePool(ce);
-           ce = tmp;
+        GreSetObjectOwner(hBm, GDI_OBJ_HMGR_PUBLIC);
+        pBmEl->hData = hBm;
     }
 
-    ClipboardData = NULL;
-}
+cleanup:
+    if (hdc)
+        UserReleaseDC(NULL, hdc, FALSE);
 
-/*==============================================================*/
+    if (pConvertedBmi)
+        DIB_FreeConvertedBitmapInfo(pConvertedBmi, pBmi);
+}
 
-HANDLE FASTCALL
-renderBITMAPfromDIB(LPBYTE pDIB)
+VOID static NTAPI
+IntAddSynthesizedFormats(PWINSTATION_OBJECT pWinStaObj)
 {
-    HDC hdc;
-    HBITMAP hbitmap;
-    PBITMAPINFO pBmi, pConvertedBmi = NULL;
-    NTSTATUS Status ;
-       UINT offset = 0; /* Stupid compiler */
+    PCLIP pTextEl, pUniTextEl, pOemTextEl, pLocaleEl, pBmEl, pDibEl;
 
-       pBmi = (BITMAPINFO*)pDIB;
+    pTextEl = IntIsFormatAvailable(pWinStaObj, CF_TEXT);
+    pOemTextEl = IntIsFormatAvailable(pWinStaObj, CF_OEMTEXT);
+    pUniTextEl = IntIsFormatAvailable(pWinStaObj, CF_UNICODETEXT);
+    pLocaleEl = IntIsFormatAvailable(pWinStaObj, CF_LOCALE);
+    pBmEl = IntIsFormatAvailable(pWinStaObj, CF_BITMAP);
+    pDibEl = IntIsFormatAvailable(pWinStaObj, CF_DIB);
 
-    //hdc = UserGetDCEx(NULL, NULL, DCX_USESTYLE);
-    hdc = UserGetDCEx(ClipboardWindow, NULL, DCX_USESTYLE);
-
-    /* Probe it */
-    _SEH2_TRY
+    /* Add CF_LOCALE format if we have CF_TEXT */
+    if (!pLocaleEl && pTextEl)
     {
-        ProbeForRead(&pBmi->bmiHeader.biSize, sizeof(DWORD), 1);
-               ProbeForRead(pBmi, pBmi->bmiHeader.biSize, 1);
-               ProbeForRead(pBmi, DIB_BitmapInfoSize(pBmi, DIB_RGB_COLORS), 1);
-               pConvertedBmi = DIB_ConvertBitmapInfo(pBmi, DIB_RGB_COLORS);
-               if(!pConvertedBmi)
-               {
-                       Status = STATUS_INVALID_PARAMETER;
-               }
-               else
-               {
-                       offset = DIB_BitmapInfoSize((BITMAPINFO*)pBmi, DIB_RGB_COLORS);
-                       ProbeForRead(pDIB + offset, pConvertedBmi->bmiHeader.biSizeImage, 1);
-               }
-    }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-    {
-        Status = _SEH2_GetExceptionCode();
-    }
-    _SEH2_END
+        PCLIPBOARDDATA pMemObj;
+        HANDLE hMem;
 
-    if(!NT_SUCCESS(Status))
-    {
-        UserReleaseDC(ClipboardWindow, hdc, FALSE);
-        return NULL;
+        pMemObj = (PCLIPBOARDDATA)UserCreateObject(gHandleTable, NULL, &hMem, otClipBoardData,
+                                                   sizeof(CLIPBOARDDATA) + sizeof(LCID));
+        if (pMemObj)
+        {
+            pMemObj->cbData = sizeof(LCID);
+            *((LCID*)pMemObj->Data) = NtCurrentTeb()->CurrentLocale;
+            IntAddFormatedData(pWinStaObj, CF_LOCALE, hMem, TRUE, TRUE);
+        }
     }
 
-    hbitmap = GreCreateDIBitmapInternal(hdc,
-                                        pConvertedBmi->bmiHeader.biWidth,
-                                        pConvertedBmi->bmiHeader.biHeight,
-                                        CBM_INIT,
-                                        pDIB+offset,
-                                        pConvertedBmi,
-                                        DIB_RGB_COLORS,
-                                        0,
-                                        0);
-    //UserReleaseDC(NULL, hdc, FALSE);
-    UserReleaseDC(ClipboardWindow, hdc, FALSE);
-
-       DIB_FreeConvertedBitmapInfo(pConvertedBmi, pBmi);
-
-    return hbitmap;
+    /* Add CF_TEXT. Note: it is synthesized in user32.dll */
+    if (!pTextEl && (pUniTextEl || pOemTextEl))
+        IntAddFormatedData(pWinStaObj, CF_TEXT, DATA_SYNTH_USER, FALSE, TRUE);
+
+    /* Add CF_OEMTEXT. Note: it is synthesized in user32.dll */
+    if (!pOemTextEl && (pUniTextEl || pTextEl))
+        IntAddFormatedData(pWinStaObj, CF_OEMTEXT, DATA_SYNTH_USER, FALSE, TRUE);
+
+    /* Add CF_UNICODETEXT. Note: it is synthesized in user32.dll */
+    if (!pUniTextEl && (pTextEl || pOemTextEl))
+        IntAddFormatedData(pWinStaObj, CF_UNICODETEXT, DATA_SYNTH_USER, FALSE, TRUE);
+
+    /* Add CF_BITMAP. Note: it is synthesized on demand */
+    if (!pBmEl && pDibEl)
+        IntAddFormatedData(pWinStaObj, CF_BITMAP, DATA_SYNTH_KRNL, FALSE, TRUE);
+
+    /* Note: we need to render the DIB or DIBV5 format as soon as possible
+       because pallette information may change */
+    if (!pDibEl && pBmEl)
+        IntSynthesizeDib(pWinStaObj, pBmEl->hData);
 }
 
-BOOL FASTCALL
-canSinthesize(UINT format)
+VOID NTAPI
+UserEmptyClipboardData(PWINSTATION_OBJECT pWinSta)
 {
-    BOOL ret = FALSE;
+    unsigned i;
+    PCLIP pElement;
 
-    switch(format)
+    for (i = 0; i < pWinSta->cNumClipFormats; ++i)
     {
-        case CF_BITMAP:
-        case CF_METAFILEPICT:
-            ret = TRUE;
+        pElement = &pWinSta->pClipBase[i];
+               IntFreeElementData(pElement);
     }
 
-    return ret;
+    if(pWinSta->pClipBase)
+        ExFreePoolWithTag(pWinSta->pClipBase, USERTAG_CLIPBOARD);
+    pWinSta->pClipBase = NULL;
+    pWinSta->cNumClipFormats = 0;
 }
 
-/* returns the size of the sinthesized data */
-DWORD FASTCALL
-synthesizeData(UINT format)
+/* UserClipboardFreeWindow is called from co_UserFreeWindow in window.c */
+VOID FASTCALL
+UserClipboardFreeWindow(PWND pWindow)
 {
-    DWORD ret = 0;
+    PWINSTATION_OBJECT pWinStaObj;
 
-    synthesizedData = NULL;
-    synthesizedDataSize = 0;
+    pWinStaObj = IntGetWinStaForCbAccess();
+    if (!pWinStaObj)
+        return;
 
-    if (!canSinthesize(format))
+    /* check if clipboard is not locked by this window, if yes, unlock it */
+    if (pWindow == pWinStaObj->spwndClipOpen)
     {
-        return 0;
+        /* the window that opens the clipboard was destroyed */
+        pWinStaObj->spwndClipOpen = NULL;
+        pWinStaObj->ptiClipLock = NULL;
     }
-
-    switch (format)
+    if (pWindow == pWinStaObj->spwndClipOwner)
     {
-        case CF_BITMAP:
-        {
-            break;
-        }
-
-        case CF_METAFILEPICT:
-        {
-            break;
-        }
+        /* the owner window was destroyed */
+        pWinStaObj->spwndClipOwner = NULL;
     }
+    /* remove window from window chain */
+    if (pWindow == pWinStaObj->spwndClipViewer)
+        pWinStaObj->spwndClipViewer = NULL;
 
-    ret = 1;
-
-    return ret;
+    ObDereferenceObject(pWinStaObj);
 }
 
-VOID FASTCALL
-freeSynthesizedData(VOID)
+UINT APIENTRY
+UserEnumClipboardFormats(UINT fmt)
 {
-    ExFreePool(synthesizedData);
-}
+    UINT Ret = 0;
+    PCLIP pElement;
+    PWINSTATION_OBJECT pWinStaObj = NULL;
 
-/*==============================================================*/
+    pWinStaObj = IntGetWinStaForCbAccess();
+    if (!pWinStaObj)
+        goto cleanup;
 
-BOOL FASTCALL
-intIsClipboardOpenByMe(VOID)
-{
-    /* check if we open the clipboard */
-    if (ClipboardThread && ClipboardThread == PsGetCurrentThreadWin32Thread())
+    /* Check if clipboard has been opened */
+    if (!IntIsClipboardOpenByMe(pWinStaObj))
     {
-        /* yes, we got a thread and its the same that opens the clipboard */
-        return TRUE;
-
+        EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
+        goto cleanup;
     }
-    /* will fail if not thread (closed) or not open by me*/
-    return FALSE;
-}
 
-/* IntClipboardFreeWindow it's called when a window was destroyed */
-VOID FASTCALL
-IntClipboardFreeWindow(PWND window)
-{
-    /* called from co_UserFreeWindow in window.c */
-    /* check if clipboard is not locked by this window, if yes, unlock it */
-    if (ClipboardThread == PsGetCurrentThreadWin32Thread())
+    if (fmt == 0)
     {
-        /* the window that opens the clipboard was destroyed */
-        ClipboardThread = NULL;
-        ClipboardWindow = NULL;
-        //TODO: free clipboard
+        /* Return first format */
+        if (pWinStaObj->pClipBase)
+            Ret = pWinStaObj->pClipBase[0].fmt;
     }
-    if (window == ClipboardOwnerWindow)
-    {
-        /* the owner window was destroyed */
-        ClipboardOwnerWindow = NULL;
-        ClipboardOwnerThread = NULL;
-    }
-    /* remove window from window chain */
-    if (IntIsWindowInChain(window))
+    else
     {
-               PCLIPBOARDCHAINELEMENT w = IntRemoveWindowFromChain(window);
-               if (w)
-               {
-            ExFreePool(w);
-               }
+        /* Return next format */
+        pElement = IntIsFormatAvailable(pWinStaObj, fmt);
+        ++pElement;
+        if (pElement < &pWinStaObj->pClipBase[pWinStaObj->cNumClipFormats])
+            Ret = pElement->fmt;
     }
+
+cleanup:
+    if(pWinStaObj)
+        ObDereferenceObject(pWinStaObj);
+
+    return Ret;
 }
 
 BOOL APIENTRY
 NtUserOpenClipboard(HWND hWnd, DWORD Unknown1)
 {
-
-    PWND Window;
-    BOOL ret = FALSE;
+    PWND pWindow = NULL;
+    BOOL bRet = FALSE;
+    PWINSTATION_OBJECT pWinStaObj = NULL;
 
     UserEnterExclusive();
 
-    sendDrawClipboardMsg = FALSE;
-    recentlySetClipboard = FALSE;
-
-    if (ClipboardThread)
+    if (hWnd)
     {
-        /* clipboard is already open */
-        if (ClipboardThread == PsGetCurrentThreadWin32Thread())
+        pWindow = UserGetWindowObject(hWnd);
+        if (!pWindow)
         {
-            if  (ClipboardOwnerWindow)
-            {
-                if (ClipboardOwnerWindow->head.h == hWnd)
-                {
-                    ret = TRUE;
-                }
-            }
-            else
-            {
-                 if (hWnd == NULL)
-                 {
-                    ret = TRUE;
-                 }
-            }
+            EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
+            goto cleanup;
         }
     }
-    else
-    {
 
-        if (hWnd != NULL)
-        {
-            Window = UserGetWindowObject(hWnd);
+    pWinStaObj = IntGetWinStaForCbAccess();
+    if (!pWinStaObj)
+        goto cleanup;
 
-            if (Window != NULL)
-            {
-                ClipboardWindow =  Window;
-                ClipboardThread = PsGetCurrentThreadWin32Thread();
-                ret = TRUE;
-            }
-            else
-            {
-                ClipboardWindow = NULL;
-                ClipboardThread = NULL;
-                ClipboardOwnerWindow = NULL;
-                ClipboardOwnerThread = NULL;
-            }
-        }
-        else
+    if (pWinStaObj->ptiClipLock)
+    {
+        /* Clipboard is already open */
+        if (pWinStaObj->spwndClipOpen != pWindow)
         {
-            ClipboardWindow =  NULL;
-            ClipboardThread = PsGetCurrentThreadWin32Thread();
-            ret = TRUE;
+            EngSetLastError(ERROR_ACCESS_DENIED);
+            goto cleanup;
         }
     }
 
+    /* Open clipboard */
+    pWinStaObj->spwndClipOpen = pWindow;
+    pWinStaObj->ptiClipLock = PsGetCurrentThreadWin32Thread();
+    bRet = TRUE;
+
+cleanup:
+    if (pWinStaObj)
+        ObDereferenceObject(pWinStaObj);
+
     UserLeave();
 
-    return ret;
+    return bRet;
 }
 
 BOOL APIENTRY
 NtUserCloseClipboard(VOID)
 {
-    BOOL ret = FALSE;
+    BOOL bRet = FALSE;
+    PWINSTATION_OBJECT pWinStaObj = NULL;
 
     UserEnterExclusive();
 
-    if (intIsClipboardOpenByMe())
-    {
-        ClipboardWindow = NULL;
-        ClipboardThread = NULL;
-        ret = TRUE;
-    }
-    else
+    pWinStaObj = IntGetWinStaForCbAccess();
+    if (!pWinStaObj)
+        goto cleanup;
+
+    if (!IntIsClipboardOpenByMe(pWinStaObj))
     {
         EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
+        goto cleanup;
     }
 
-    recentlySetClipboard = FALSE;
+    /* Clipboard is no longer open */
+    pWinStaObj->spwndClipOpen = NULL;
+    pWinStaObj->ptiClipLock = NULL;
+    bRet = TRUE;
 
-    UserLeave();
-
-    if (sendDrawClipboardMsg && WindowsChain)
+    if (pWinStaObj->fClipboardChanged)
     {
-        /* only send message to the first window in the chain, then they'll do the chain */
-        /* commented because it makes a crash in co_MsqSendMessage
-        ASSERT(WindowsChain->window);
-        ASSERT(WindowsChain->window->hSelf);
-        ERR("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", WindowsChain->window->hSelf);
-        co_IntSendMessage(WindowsChain->window->hSelf, WM_DRAWCLIPBOARD, 0, 0);
-        */
+        /* Add synthesized formats - they are rendered later */
+        IntAddSynthesizedFormats(pWinStaObj);
+
+        /* Notify viewer windows in chain */
+        if (pWinStaObj->spwndClipViewer)
+        {
+            TRACE("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", pWinStaObj->spwndClipViewer->head.h);
+            co_IntSendMessage(pWinStaObj->spwndClipViewer->head.h, WM_DRAWCLIPBOARD, 0, 0);
+        }
+
+        pWinStaObj->fClipboardChanged = FALSE;
     }
 
-    return ret;
+cleanup:
+    if (pWinStaObj)
+        ObDereferenceObject(pWinStaObj);
+
+    UserLeave();
+
+    return bRet;
 }
 
 HWND APIENTRY
 NtUserGetOpenClipboardWindow(VOID)
 {
-    HWND ret = NULL;
+    HWND hWnd = NULL;
+    PWINSTATION_OBJECT pWinStaObj;
 
     UserEnterShared();
 
-    if (ClipboardWindow)
-    {
-        ret = ClipboardWindow->head.h;
-    }
+    pWinStaObj = IntGetWinStaForCbAccess();
+    if (!pWinStaObj)
+        goto cleanup;
 
+    if (pWinStaObj->spwndClipOpen)
+        hWnd = pWinStaObj->spwndClipOpen->head.h;
+
+    ObDereferenceObject(pWinStaObj);
+
+cleanup:
     UserLeave();
 
-    return ret;
+    return hWnd;
 }
 
 BOOL APIENTRY
 NtUserChangeClipboardChain(HWND hWndRemove, HWND hWndNewNext)
 {
-    BOOL ret = FALSE;
-    PCLIPBOARDCHAINELEMENT w = NULL;
-    PWND removeWindow;
+    BOOL bRet = FALSE;
+    PWND pWindowRemove;
+    PWINSTATION_OBJECT pWinStaObj;
+
+    TRACE("NtUserChangeClipboardChain(%p, %p)\n", hWndRemove, hWndNewNext);
+
     UserEnterExclusive();
 
-    removeWindow = UserGetWindowObject(hWndRemove);
+    pWinStaObj = IntGetWinStaForCbAccess();
+    if (!pWinStaObj)
+        goto cleanup;
 
-    if (removeWindow)
-    {
-        if ((ret = !!IntIsWindowInChain(removeWindow)))
-        {
-            w = IntRemoveWindowFromChain(removeWindow);
-            if (w)
-            {
-                ExFreePool(w);
-            }
-        }
-    }
+    pWindowRemove = UserGetWindowObject(hWndRemove);
 
-    if (ret && WindowsChain)
+    if (pWindowRemove && pWinStaObj->spwndClipViewer)
     {
-        // only send message to the first window in the chain,
-        // then they do the chain
+        if(pWindowRemove == pWinStaObj->spwndClipViewer)
+            pWinStaObj->spwndClipViewer = UserGetWindowObject(hWndNewNext);
 
-        /* WindowsChain->window may be NULL */
-        LPARAM lparam = WindowsChain->window == NULL ? 0 : (LPARAM)WindowsChain->window->head.h;
-        ERR("Message: WM_CHANGECBCHAIN to %p", WindowsChain->window->head.h);
-        co_IntSendMessage(WindowsChain->window->head.h, WM_CHANGECBCHAIN, (WPARAM)hWndRemove, lparam);
+        if(pWinStaObj->spwndClipViewer)
+            bRet = (BOOL)co_IntSendMessage(pWinStaObj->spwndClipViewer->head.h, WM_CHANGECBCHAIN, (WPARAM)hWndRemove, (LPARAM)hWndNewNext);
     }
 
+    ObDereferenceObject(pWinStaObj);
+
+cleanup:
     UserLeave();
 
-    return ret;
+    return bRet;
 }
 
 DWORD APIENTRY
 NtUserCountClipboardFormats(VOID)
 {
-    DWORD ret = 0;
-
-    if (ClipboardData)
-    {
-       ret = IntCountClipboardFormats();
-    }
-
-    return ret;
-}
-
-DWORD APIENTRY
-NtUserEmptyClipboard(VOID)
-{
-    BOOL ret = FALSE;
-
-    UserEnterExclusive();
+    DWORD cFormats = 0;
+    PWINSTATION_OBJECT pWinStaObj = NULL;
 
-    if (intIsClipboardOpenByMe())
-    {
-        if (ClipboardData)
-        {
-            IntEmptyClipboardData();
-        }
+    UserEnterShared();
 
-        ClipboardOwnerWindow = ClipboardWindow;
-        ClipboardOwnerThread = ClipboardThread;
+    pWinStaObj = IntGetWinStaForCbAccess();
+    if (!pWinStaObj)
+        goto cleanup;
 
-        IntIncrementSequenceNumber();
+    cFormats = pWinStaObj->cNumClipFormats;
 
-        ret = TRUE;
-    }
-    else
-    {
-        EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
-    }
-
-    if (ret && ClipboardOwnerWindow)
-    {
-        TRACE("Clipboard: WM_DESTROYCLIPBOARD to %p", ClipboardOwnerWindow->head.h);
-        co_IntSendMessageNoWait( ClipboardOwnerWindow->head.h, WM_DESTROYCLIPBOARD, 0, 0);
-    }
+    ObDereferenceObject(pWinStaObj);
 
+cleanup:
     UserLeave();
 
-    return ret;
+    return cFormats;
 }
 
-HANDLE APIENTRY
-NtUserGetClipboardData(UINT uFormat, PVOID pBuffer)
+BOOL APIENTRY
+NtUserEmptyClipboard(VOID)
 {
-    HANDLE ret = NULL;
+    BOOL bRet = FALSE;
+    PWINSTATION_OBJECT pWinStaObj;
 
-    UserEnterShared();
+    TRACE("NtUserEmptyClipboard()\n");
 
-    if (intIsClipboardOpenByMe())
-    {
-        /* when Unknown1 is zero, we returns to user32 the data size */
-        if (!pBuffer)
-        {
-            PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
+    UserEnterExclusive();
 
-            if (data)
-            {
-                /* format exists in clipboard */
-                if (data->size == DATA_DELAYED_RENDER)
-                {
-                    /* tell owner what data needs to be rendered */
-                    if (ClipboardOwnerWindow)
-                    {
-                        ASSERT(ClipboardOwnerWindow->head.h);
-                        co_IntSendMessage(ClipboardOwnerWindow->head.h, WM_RENDERFORMAT, (WPARAM)uFormat, 0);
-                        data = intIsFormatAvailable(uFormat);
-                        ASSERT(data->size);
-                        ret = (HANDLE)(ULONG_PTR)data->size;
-                    }
-                }
-                else
-                {
-                    if (data->size == DATA_SYNTHESIZED_RENDER)
-                    {
-                        data->size = synthesizeData(uFormat);
-                    }
+    pWinStaObj = IntGetWinStaForCbAccess();
+    if (!pWinStaObj)
+        goto cleanup;
 
-                }
-                ret = (HANDLE)(ULONG_PTR)data->size;
-            }
-            else
-            {
-                /* there is no data in this format */
-                //ret = (HANDLE)FALSE;
-            }
-        }
-        else
+    if (IntIsClipboardOpenByMe(pWinStaObj))
+    {
+        UserEmptyClipboardData(pWinStaObj);
+
+        if (pWinStaObj->spwndClipOwner)
         {
-            PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
+            TRACE("Clipboard: WM_DESTROYCLIPBOARD to %p", pWinStaObj->spwndClipOwner->head.h);
+            co_IntSendMessageNoWait(pWinStaObj->spwndClipOwner->head.h, WM_DESTROYCLIPBOARD, 0, 0);
+        }
 
-            if (data)
-            {
-                if (data->size == DATA_DELAYED_RENDER)
-                {
-                    // we rendered it in 1st call of getclipboard data
-                }
-                else
-                {
-                    if (data->size == DATA_SYNTHESIZED_RENDER)
-                    {
-                        if (uFormat == CF_BITMAP)
-                        {
-                            /* BITMAP & METAFILEs returns a GDI handle */
-                            PCLIPBOARDELEMENT data = intIsFormatAvailable(CF_DIB);
-                            if (data)
-                            {
-                                ret = renderBITMAPfromDIB(data->hData);
-                            }
-                        }
-                        else
-                        {
-                            ret = (HANDLE)pBuffer;
-
-                            _SEH2_TRY
-                            {
-                                ProbeForWrite(pBuffer, synthesizedDataSize, 1);
-                                memcpy(pBuffer, (PCHAR)synthesizedData, synthesizedDataSize);
-                            }
-                            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-                            {
-                                ret = NULL;
-                            }
-                            _SEH2_END
-
-                            freeSynthesizedData();
-                        }
-                    }
-                    else
-                    {
-                        ret = (HANDLE)pBuffer;
-
-                        _SEH2_TRY
-                        {
-                            ProbeForWrite(pBuffer, data->size, 1);
-                            memcpy(pBuffer, (PCHAR)data->hData, data->size);
-                        }
-                        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-                        {
-                            ret = NULL;
-                        }
-                        _SEH2_END
-                    }
-                }
+        pWinStaObj->spwndClipOwner = pWinStaObj->spwndClipOpen;
 
-            }
+        pWinStaObj->iClipSequenceNumber++;
 
-        }
+        bRet = TRUE;
     }
     else
     {
         EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
+        ERR("Access denied!\n");
     }
 
+    ObDereferenceObject(pWinStaObj);
+
+cleanup:
     UserLeave();
 
-    return ret;
+    return bRet;
 }
 
 INT APIENTRY
-NtUserGetClipboardFormatName(UINT format, PUNICODE_STRING FormatName,
-                             INT cchMaxCount)
+NtUserGetClipboardFormatName(UINT fmt, LPWSTR lpszFormatName, INT cchMaxCount)
 {
-    UNICODE_STRING sFormatName;
-    INT ret = 0;
+    INT iRet = 0;
+
+    UserEnterShared();
 
     /* if the format is built-in we fail */
-    if (format < 0xc000)
+    if (fmt < 0xc000)
     {
         /* registetrated formats are >= 0xc000 */
-        return 0;
+        goto cleanup;
     }
 
-    if((cchMaxCount < 1) || !FormatName)
+    if (cchMaxCount < 1 || !lpszFormatName)
     {
         EngSetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
+        goto cleanup;
     }
 
     _SEH2_TRY
     {
-        ProbeForWriteUnicodeString(FormatName);
-        sFormatName = *(volatile UNICODE_STRING *)FormatName;
-        ProbeForWrite(sFormatName.Buffer, sFormatName.MaximumLength, 1);
+        ProbeForWrite(lpszFormatName, cchMaxCount * sizeof(WCHAR), 1);
 
-        ret = IntGetAtomName((RTL_ATOM)format, sFormatName.Buffer, cchMaxCount * sizeof(WCHAR));
-
-        if (ret >= 0)
-        {
-            ret = ret / sizeof(WCHAR);
-            sFormatName.Length = ret;
-        }
-        else
-        {
-            ret = 0;
-        }
+        iRet = IntGetAtomName((RTL_ATOM)fmt,
+                              lpszFormatName,
+                              cchMaxCount * sizeof(WCHAR));
+        iRet /= sizeof(WCHAR);
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
@@ -769,432 +630,479 @@ NtUserGetClipboardFormatName(UINT format, PUNICODE_STRING FormatName,
     }
     _SEH2_END;
 
-    return ret;
+cleanup:
+    UserLeave();
+
+    return iRet;
 }
 
 HWND APIENTRY
 NtUserGetClipboardOwner(VOID)
 {
-    HWND ret = NULL;
+    HWND hWnd = NULL;
+    PWINSTATION_OBJECT pWinStaObj;
 
     UserEnterShared();
 
-    if (ClipboardOwnerWindow)
-    {
-        ret = ClipboardOwnerWindow->head.h;
-    }
+    pWinStaObj = IntGetWinStaForCbAccess();
+    if (!pWinStaObj)
+        goto cleanup;
 
+    if (pWinStaObj->spwndClipOwner)
+        hWnd = pWinStaObj->spwndClipOwner->head.h;
+
+    ObDereferenceObject(pWinStaObj);
+
+cleanup:
     UserLeave();
 
-    return ret;
+    return hWnd;
 }
 
 HWND APIENTRY
 NtUserGetClipboardViewer(VOID)
 {
-    HWND ret = NULL;
+    HWND hWnd = NULL;
+    PWINSTATION_OBJECT pWinStaObj;
 
     UserEnterShared();
 
-    if (WindowsChain)
-    {
-        ret = WindowsChain->window->head.h;
-    }
+    pWinStaObj = IntGetWinStaForCbAccess();
+    if(!pWinStaObj)
+        goto cleanup;
+
+    if (pWinStaObj->spwndClipViewer)
+        hWnd = pWinStaObj->spwndClipViewer->head.h;
 
+    ObDereferenceObject(pWinStaObj);
+
+cleanup:
     UserLeave();
 
-    return ret;
+    return hWnd;
 }
 
 INT APIENTRY
 NtUserGetPriorityClipboardFormat(UINT *paFormatPriorityList, INT cFormats)
 {
-    INT i;
-    UINT *priorityList;
-    INT ret = 0;
+    INT i, iRet = 0;
+    PWINSTATION_OBJECT pWinStaObj;
 
-    UserEnterExclusive();
+    UserEnterShared();
 
-    _SEH2_TRY
+    pWinStaObj = IntGetWinStaForCbAccess();
+    if (!pWinStaObj)
+        goto cleanup;
+    
+    if (pWinStaObj->pClipBase == NULL)
     {
-        if (IntCountClipboardFormats() == 0)
-        {
-            ret = 0;
-        }
-        else
+        iRet = 0;
+    }
+    else
+    {
+        _SEH2_TRY
         {
-            ProbeForRead(paFormatPriorityList, cFormats, sizeof(UINT));
-
-            priorityList = paFormatPriorityList;
+            ProbeForRead(paFormatPriorityList, cFormats * sizeof(UINT), sizeof(UINT));
 
-            ret = -1;
+            iRet = -1;
 
-            for (i = 0; i < cFormats; i++)
+            for (i = 0; i < cFormats; ++i)
             {
-                if (intIsFormatAvailable(priorityList[i]))
+                if (IntIsFormatAvailable(pWinStaObj, paFormatPriorityList[i]))
                 {
-                    ret = priorityList[i];
+                    iRet = paFormatPriorityList[i];
                     break;
                 }
             }
-
         }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            SetLastNtError(_SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
     }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-    {
-        SetLastNtError(_SEH2_GetExceptionCode());
-    }
-    _SEH2_END;
 
+    ObDereferenceObject(pWinStaObj);
+
+cleanup:
     UserLeave();
 
-    return ret;
+    return iRet;
 
 }
 
 BOOL APIENTRY
-NtUserIsClipboardFormatAvailable(UINT format)
+NtUserIsClipboardFormatAvailable(UINT fmt)
 {
-    BOOL ret = FALSE;
+    BOOL bRet = FALSE;
+    PWINSTATION_OBJECT pWinStaObj;
+
+    TRACE("NtUserIsClipboardFormatAvailable(%x)\n", fmt);
 
     UserEnterShared();
 
-    ret = (intIsFormatAvailable(format) != NULL);
+    pWinStaObj = IntGetWinStaForCbAccess();
+    if (!pWinStaObj)
+        goto cleanup;
 
-    UserLeave();
+    if (IntIsFormatAvailable(pWinStaObj, fmt))
+        bRet = TRUE;
 
-    return ret;
-}
+    ObDereferenceObject(pWinStaObj);
 
+cleanup:
+    UserLeave();
 
+    return bRet;
+}
 
 HANDLE APIENTRY
-NtUserSetClipboardData(UINT uFormat, HANDLE hMem, DWORD size)
+NtUserGetClipboardData(UINT fmt, PGETCLIPBDATA pgcd)
 {
-    HANDLE hCBData = NULL;
-    UNICODE_STRING unicodeString;
-    OEM_STRING oemString;
-    ANSI_STRING ansiString;
+    NTSTATUS Status = STATUS_SUCCESS;
+    HANDLE hRet = NULL;
+    PCLIP pElement;
+    PWINSTATION_OBJECT pWinStaObj = NULL;
 
-    UserEnterExclusive();
+    TRACE("NtUserGetClipboardData(%x, %p)\n", fmt, pgcd);
+
+    UserEnterShared();
+
+    pWinStaObj = IntGetWinStaForCbAccess();
+    if (!pWinStaObj)
+        goto cleanup;
 
-    /* to place data here the we need to be the owner */
-    if (ClipboardOwnerThread == PsGetCurrentThreadWin32Thread())
+    if (!IntIsClipboardOpenByMe(pWinStaObj))
     {
-        PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
-        if (data)
-        {
+        EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
+        goto cleanup;
+    }
 
-            if (data->size == DATA_DELAYED_RENDER)
-            {
-                intRemoveFormatedData(uFormat);
-            }
-            else
-            {
-                // we already have this format on clipboard
-                goto exit_setCB;
-            }
-        }
+    pElement = IntIsFormatAvailable(pWinStaObj, fmt);
+    if (pElement && IS_DATA_DELAYED(pElement) && pWinStaObj->spwndClipOwner)
+    {
+        /* send WM_RENDERFORMAT message */
+        pWinStaObj->fInDelayedRendering = TRUE;
+        co_IntSendMessage(pWinStaObj->spwndClipOwner->head.h, WM_RENDERFORMAT, (WPARAM)fmt, 0);
+        pWinStaObj->fInDelayedRendering = FALSE;
 
-        if (hMem)
-        {
-            _SEH2_TRY
-            {
-                ProbeForRead(hMem, size, 1);
-            }
-            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-            {
-                SetLastNtError(_SEH2_GetExceptionCode());
-                _SEH2_YIELD(goto exit_setCB);
-            }
-            _SEH2_END;
+        /* data should be in clipboard now */
+        pElement = IntIsFormatAvailable(pWinStaObj, fmt);
+    }
 
-            if (intIsClipboardOpenByMe())
-            {
-                delayedRender = FALSE;
-            }
+    if (!pElement || IS_DATA_DELAYED(pElement))
+        goto cleanup;
 
-            if (!canSinthesize(uFormat))
-            {
-                hCBData = ExAllocatePoolWithTag(PagedPool, size, USERTAG_CLIPBOARD);
-                memcpy(hCBData, hMem, size);
-                intAddFormatedData(uFormat, hCBData, size);
-                ERR("Data stored\n");
-            }
 
-            sendDrawClipboardMsg = TRUE;
-            recentlySetClipboard = TRUE;
-            lastEnumClipboardFormats = uFormat;
+    if (IS_DATA_SYNTHESIZED(pElement))
+    {
+        /* Note: data is synthesized in usermode */
+        /* TODO: Add more formats */
+        switch (fmt)
+        {
+            case CF_UNICODETEXT:
+            case CF_TEXT:
+            case CF_OEMTEXT:
+                pElement = IntIsFormatAvailable(pWinStaObj, CF_UNICODETEXT);
+                if (IS_DATA_SYNTHESIZED(pElement))
+                    pElement = IntIsFormatAvailable(pWinStaObj, CF_TEXT);
+                if (IS_DATA_SYNTHESIZED(pElement))
+                    pElement = IntIsFormatAvailable(pWinStaObj, CF_OEMTEXT);
+                break;
+            case CF_BITMAP:
+                IntSynthesizeBitmap(pWinStaObj, pElement);
+                break;
+            default:
+                ASSERT(FALSE);
+        }
+    }
 
-            /* conversions */
-            switch (uFormat)
-            {
-                case CF_TEXT:
-                    {
-                        //TODO : sinthesize CF_UNICODETEXT & CF_OEMTEXT
-                        // CF_TEXT -> CF_UNICODETEXT
-                        ansiString.Buffer = hCBData;
-                        ansiString.Length = size;
-                        RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
-                        intAddFormatedData(CF_UNICODETEXT, unicodeString.Buffer, unicodeString.Length * sizeof(WCHAR));
-                        // CF_TEXT -> CF_OEMTEXT
-                        RtlUnicodeStringToOemString(&oemString, &unicodeString, TRUE);
-                        intAddFormatedData(CF_OEMTEXT, oemString.Buffer, oemString.Length);
-                        //HKCU\Control Panel\International\Locale
-                        //intAddFormatedData(CF_LOCALE, oemString.Buffer, oemString.Length);
-                        break;
-                    }
-                case CF_UNICODETEXT:
-                {
-                    //TODO : sinthesize CF_TEXT & CF_OEMTEXT
-                    //CF_UNICODETEXT -> CF_TEXT
-                    unicodeString.Buffer = hCBData;
-                    unicodeString.Length = size;
-                    RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE);
-                    intAddFormatedData(CF_TEXT, ansiString.Buffer, ansiString.Length);
-                    //CF_UNICODETEXT -> CF_OEMTEXT
-                    RtlUnicodeStringToOemString(&oemString, &unicodeString, TRUE);
-                    intAddFormatedData(CF_OEMTEXT, oemString.Buffer, oemString.Length);
-                    break;
-                }
-                case CF_OEMTEXT:
-                {
-                    //TODO : sinthesize CF_TEXT & CF_UNICODETEXT
-                    //CF_OEMTEXT -> CF_UNICODETEXT
-                    oemString.Buffer = hCBData;
-                    oemString.Length = size;
-                    RtlOemStringToUnicodeString(&unicodeString, &oemString, TRUE);
-                    intAddFormatedData(CF_UNICODETEXT, unicodeString.Buffer, unicodeString.Length * sizeof(WCHAR));
-                    //CF_OEMTEXT -> CF_TEXT
-                    RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE);
-                    intAddFormatedData(CF_TEXT, ansiString.Buffer, ansiString.Length);
-                    break;
-                }
-                case CF_BITMAP:
-                {
-                    // we need to render the DIB or DIBV5 format as soon as possible
-                    // because pallette information may change
+    _SEH2_TRY
+    {
+        ProbeForWrite(pgcd, sizeof(*pgcd), 1);
+        pgcd->uFmtRet = pElement->fmt;
+        pgcd->fGlobalHandle = pElement->fGlobalHandle;
 
-                    HDC hdc;
-                    BITMAP bm;
-                    BITMAPINFO bi;
-                    SURFACE *psurf;
+        /* Text and bitmap needs more data */
+        if (fmt == CF_TEXT)
+        {
+            PCLIP pLocaleEl;
+            
+            pLocaleEl = IntIsFormatAvailable(pWinStaObj, CF_LOCALE);
+            if (pLocaleEl && !IS_DATA_DELAYED(pLocaleEl))
+                pgcd->hLocale = pLocaleEl->hData;
+        }
+        else if (fmt == CF_BITMAP)
+        {
+            PCLIP pPaletteEl;
+            
+            pPaletteEl = IntIsFormatAvailable(pWinStaObj, CF_PALETTE);
+            if (pPaletteEl && !IS_DATA_DELAYED(pPaletteEl))
+                pgcd->hPalette = pPaletteEl->hData;
+        }
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END
 
-                    hdc = UserGetDCEx(NULL, NULL, DCX_USESTYLE);
+    if (!NT_SUCCESS(Status))
+    {
+        SetLastNtError(Status);
+        goto cleanup;
+    }
 
+    hRet = pElement->hData;
 
-                    psurf = SURFACE_ShareLockSurface(hMem);
-                    BITMAP_GetObject(psurf, sizeof(BITMAP), (PVOID)&bm);
-                    if(psurf)
-                    {
-                        SURFACE_ShareUnlockSurface(psurf);
-                    }
+cleanup:
+    if(pWinStaObj)
+        ObDereferenceObject(pWinStaObj);
 
-                    bi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
-                    bi.bmiHeader.biWidth = bm.bmWidth;
-                    bi.bmiHeader.biHeight = bm.bmHeight;
-                    bi.bmiHeader.biPlanes = 1;
-                    bi.bmiHeader.biBitCount    = bm.bmPlanes * bm.bmBitsPixel;
-                    bi.bmiHeader.biCompression = BI_RGB;
-                    bi.bmiHeader.biSizeImage = 0;
-                    bi.bmiHeader.biXPelsPerMeter = 0;
-                    bi.bmiHeader.biYPelsPerMeter = 0;
-                    bi.bmiHeader.biClrUsed = 0;
+    UserLeave();
 
-                    NtGdiGetDIBitsInternal(hdc, hMem, 0, bm.bmHeight,  NULL, &bi, DIB_RGB_COLORS, 0, 0);
+    TRACE("Ret: %p\n", hRet);
 
-                    size = bi.bmiHeader.biSizeImage + sizeof(BITMAPINFOHEADER);
+    return hRet;
+}
 
-                    hCBData = ExAllocatePoolWithTag(PagedPool, size, USERTAG_CLIPBOARD);
-                    memcpy(hCBData, &bi, sizeof(BITMAPINFOHEADER));
+HANDLE APIENTRY
+NtUserSetClipboardData(UINT fmt, HANDLE hData, PSETCLIPBDATA scd)
+{
+    HANDLE hRet = NULL;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PWINSTATION_OBJECT pWinStaObj = NULL;
+    BOOLEAN fGlobalHandle = FALSE;
 
-                    NtGdiGetDIBitsInternal(hdc, hMem, 0, bm.bmHeight, (LPBYTE)hCBData + sizeof(BITMAPINFOHEADER), &bi, DIB_RGB_COLORS, 0, 0);
+    TRACE("NtUserSetClipboardData(%x %p %p)\n", fmt, hData, scd);
 
-                    UserReleaseDC(NULL, hdc, FALSE);
+    UserEnterExclusive();
 
-                    intAddFormatedData(CF_DIB, hCBData, size);
-                    intAddFormatedData(CF_BITMAP, 0, DATA_SYNTHESIZED_RENDER);
-                    // intAddFormatedData(CF_DIBV5, hCBData, size);
+    pWinStaObj = IntGetWinStaForCbAccess();
+    if (!pWinStaObj)
+        goto cleanup;
 
-                    break;
-                }
-                case CF_DIB:
-                {
-                    intAddFormatedData(CF_BITMAP, 0, DATA_SYNTHESIZED_RENDER);
-                    // intAddFormatedData(CF_DIBV5, hCBData, size);
-                    /* investigate */
-                    // intAddFormatedData(CF_PALETTE, hCBData, size);
-                    break;
-                }
-                case CF_DIBV5:
-                    // intAddFormatedData(CF_BITMAP, hCBData, size);
-                    // intAddFormatedData(CF_PALETTE, hCBData, size);
-                    // intAddFormatedData(CF_DIB, hCBData, size);
-                    break;
-                case CF_ENHMETAFILE:
-                    // intAddFormatedData(CF_METAFILEPICT, hCBData, size);
-                    break;
-                case CF_METAFILEPICT:
-                    // intAddFormatedData(CF_ENHMETAFILE, hCBData, size);
-                    break;
-            }
+    /* If it's delayed rendering we don't have to open clipboard */
+    if ((pWinStaObj->fInDelayedRendering &&
+        pWinStaObj->spwndClipOwner->head.pti != PsGetCurrentThreadWin32Thread()) ||
+        !IntIsClipboardOpenByMe(pWinStaObj))
+    {
+        ERR("Access denied!\n");
+        EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
+        goto cleanup;
+    }
 
-        }
-        else
+    _SEH2_TRY
+    {
+        ProbeForRead(scd, sizeof(*scd), 1);
+        fGlobalHandle = scd->fGlobalHandle;
+        if (scd->fIncSerialNumber)
+            pWinStaObj->iClipSerialNumber++;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END
+
+    if (!NT_SUCCESS(Status))
+    {
+        SetLastNtError(Status);
+        goto cleanup;
+    }
+
+    /* Is it a delayed render? */
+    if (hData)
+    {
+        /* Is it a bitmap? */
+        if (fmt == CF_BITMAP)
         {
-            // the window provides data in the specified format
-            delayedRender = TRUE;
-            sendDrawClipboardMsg = TRUE;
-            intAddFormatedData(uFormat, NULL, 0);
-            ERR("SetClipboardData delayed format: %d\n", uFormat);
+            /* Make bitmap public */
+            GreSetObjectOwner(hData, GDI_OBJ_HMGR_PUBLIC);
         }
 
+        /* Save data in the clipboard */
+        IntAddFormatedData(pWinStaObj, fmt, hData, fGlobalHandle, FALSE);
+        TRACE("hData stored\n");
+
+        pWinStaObj->iClipSequenceNumber++;
+        pWinStaObj->fClipboardChanged = TRUE;
 
+        /* Note: synthesized formats are added in NtUserCloseClipboard */
+    }
+    else
+    {
+        /* This is a delayed render */
+        IntAddFormatedData(pWinStaObj, fmt, DATA_DELAYED, FALSE, FALSE);
+        TRACE("SetClipboardData delayed format: %u\n", fmt);
     }
 
-exit_setCB:
+    /* Return hData on success */
+    hRet = hData;
+
+cleanup:
+    TRACE("NtUserSetClipboardData returns: %p\n", hRet);
+
+    if(pWinStaObj)
+        ObDereferenceObject(pWinStaObj);
 
     UserLeave();
 
-    return hMem;
+    return hRet;
 }
 
 HWND APIENTRY
 NtUserSetClipboardViewer(HWND hWndNewViewer)
 {
-    HWND ret = NULL;
-    PCLIPBOARDCHAINELEMENT newWC = NULL;
-    PWND window;
+    HWND hWndNext = NULL;
+    PWINSTATION_OBJECT pWinStaObj = NULL;
+    PWND pWindow;
 
     UserEnterExclusive();
 
-    window = UserGetWindowObject(hWndNewViewer);
+    pWinStaObj = IntGetWinStaForCbAccess();
+    if (!pWinStaObj)
+        goto cleanup;
 
-    if (window)
+    pWindow = UserGetWindowObject(hWndNewViewer);
+    if (!pWindow)
     {
-        if ((newWC = IntAddWindowToChain(window)))
-        {
-            if (newWC)
-            {
-                // newWC->next may be NULL if we are the first window in the chain
-                if (newWC->next)
-                {
-                    // return the next HWND available window in the chain
-                    ret = newWC->next->window->head.h;
-                }
-            }
-        }
+        EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
+        goto cleanup;
     }
 
+    /* Return previous viewer. New viever window should
+       send messages to rest of the chain */
+    if (pWinStaObj->spwndClipViewer)
+        hWndNext = pWinStaObj->spwndClipViewer->head.h;
+
+    /* Set new viewer window */
+    pWinStaObj->spwndClipViewer = pWindow;
+
+cleanup:
+    if(pWinStaObj)
+        ObDereferenceObject(pWinStaObj);
+    
     UserLeave();
 
-    return ret;
+    return hWndNext;
 }
 
-UINT APIENTRY
-IntEnumClipboardFormats(UINT uFormat)
+// Sequence number is incremented whenever the contents of the clipboard change
+// or the clipboard is emptied. If clipboard rendering is delayed,
+// the sequence number is not incremented until the changes are rendered.
+
+DWORD APIENTRY
+NtUserGetClipboardSequenceNumber(VOID)
 {
-    UINT ret = 0;
+    DWORD dwRet = 0;
+    PWINSTATION_OBJECT pWinStaObj;
 
-    if (intIsClipboardOpenByMe())
-    {
-            if (uFormat == 0)
-            {
-                if (recentlySetClipboard)
-                {
-                    ret = lastEnumClipboardFormats;
-                }
-                else
-                {
-                    /* return the first available format */
-                    if (ClipboardData)
-                    {
-                        ret = ClipboardData->format;
-                    }
-                }
-            }
-            else
-            {
-                if (recentlySetClipboard)
-                {
-                    ret = 0;
-                }
-                else
-                {
-                    /* querying nextt available format */
-                    PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
-
-                    if (data)
-                    {
-                        if (data->next)
-                        {
-                            ret = data->next->format;
-                        }
-                        else
-                        {
-                            /* reached the end */
-                            ret = 0;
-                        }
-                    }
-                }
+    UserEnterShared();
 
-            }
-    }
-    else
-    {
-        EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
-    }
+    pWinStaObj = IntGetWinStaForCbAccess();
+    if (!pWinStaObj)
+        goto cleanup;
 
-    return ret;
-}
+    /* Get windowstation sequence number */
+    dwRet = (DWORD)pWinStaObj->iClipSequenceNumber;
 
-// This number is incremented whenever the contents of the clipboard change
-// or the clipboard is emptied.
-// If clipboard rendering is delayed,
-// the sequence number is not incremented until the changes are rendered.
-VOID FASTCALL
-IntIncrementSequenceNumber(VOID)
-{
-    PTHREADINFO pti;
-    PWINSTATION_OBJECT WinStaObj;
+    ObDereferenceObject(pWinStaObj);
 
-    pti = PsGetCurrentThreadWin32Thread();
-    WinStaObj = pti->rpdesk->rpwinstaParent;
+cleanup:
+    UserLeave();
 
-    WinStaObj->Clipboard->ClipboardSequenceNumber++;
+    return dwRet;
 }
 
-DWORD APIENTRY
-NtUserGetClipboardSequenceNumber(VOID)
+HANDLE APIENTRY
+NtUserConvertMemHandle(
+   PVOID pData,
+   DWORD cbData)
 {
-    //windowstation sequence number
-    //if no WINSTA_ACCESSCLIPBOARD access to the window station,
-    //the function returns zero.
-    DWORD sn;
+    HANDLE hMem = NULL;
+    PCLIPBOARDDATA pMemObj;
 
-    HWINSTA WinSta;
-    PWINSTATION_OBJECT WinStaObj;
-    NTSTATUS Status;
+    UserEnterExclusive();
 
-    WinSta = UserGetProcessWindowStation();
+    /* Create Clipboard data object */
+    pMemObj = UserCreateObject(gHandleTable, NULL, &hMem, otClipBoardData, sizeof(CLIPBOARDDATA) + cbData);
+    if (!pMemObj)
+        goto cleanup;
 
-    Status = IntValidateWindowStationHandle(WinSta, KernelMode, WINSTA_ACCESSCLIPBOARD, &WinStaObj);
+    pMemObj->cbData = cbData;
 
-    if (!NT_SUCCESS(Status))
+    /* Copy data */
+    _SEH2_TRY
     {
-        ERR("No WINSTA_ACCESSCLIPBOARD access\n");
-        SetLastNtError(Status);
-        return 0;
+        ProbeForRead(pData, cbData, 1);
+        memcpy(pMemObj->Data, pData, cbData);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        pMemObj = NULL;
+    }
+    _SEH2_END;
+
+    /* If we failed to copy data, remove handle */
+    if (!pMemObj)
+    {
+        UserDeleteObject(hMem, otClipBoardData);
+        hMem = NULL;
+    }
+
+cleanup:
+    UserLeave();
+
+    return hMem;
+}
+
+NTSTATUS APIENTRY
+NtUserCreateLocalMemHandle(
+   HANDLE hMem,
+   PVOID pData,
+   DWORD cbData,
+   DWORD *pcbData)
+{
+    PCLIPBOARDDATA pMemObj;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    UserEnterShared();
+
+    /* Get Clipboard data object */
+    pMemObj = (PCLIPBOARDDATA)UserGetObject(gHandleTable, hMem, otClipBoardData);
+    if (!pMemObj)
+    {
+        Status = STATUS_INVALID_HANDLE;
+        goto cleanup;
     }
 
-    sn = WinStaObj->ClipboardSequenceNumber;
+    /* Don't overrun */
+    if (cbData > pMemObj->cbData)
+        cbData = pMemObj->cbData;
 
-    ObDereferenceObject(WinStaObj);
+    /* Copy data to usermode */
+    _SEH2_TRY
+    {
+        if (pcbData)
+        {
+            ProbeForWrite(pcbData, sizeof(*pcbData), 1);
+            *pcbData = pMemObj->cbData;
+        }
 
-    //local copy
-    //sn = ClipboardSequenceNumber;
+        ProbeForWrite(pData, cbData, 1);
+        memcpy(pData, pMemObj->Data, cbData);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
+
+cleanup:
+    UserLeave();
 
-    return sn;
+    return Status;
 }
 
 /* EOF */
index d4d3fd1..8205feb 100644 (file)
@@ -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(
index e7053ad..e156006 100644 (file)
@@ -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);
index 2c52e55..99db868 100644 (file)
@@ -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);
index f7b2d09..bd39a17 100644 (file)
@@ -482,7 +482,7 @@ static LRESULT co_UserFreeWindow(PWND Window,
 
    UserDereferenceObject(Window);
 
-   IntClipboardFreeWindow(Window);
+   UserClipboardFreeWindow(Window);
 
    return 0;
 }
index 73318e6..93e2704 100644 (file)
@@ -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;