* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PURPOSE: Clipboard routines
- * FILE: subsys/win32k/ntuser/clipboard.c
+ * FILE: win32ss/user/ntuser/clipboard.c
* PROGRAMER: Filip Navara <xnavara@volny.cz>
* Pablo Borobia <pborobia@gmail.com>
* Rafal Harabien <rafalh@reactos.org>
NTSTATUS Status;
hWinSta = UserGetProcessWindowStation();
- Status = IntValidateWindowStationHandle(hWinSta, KernelMode, WINSTA_ACCESSCLIPBOARD, &pWinStaObj);
+ Status = IntValidateWindowStationHandle(hWinSta, UserMode, WINSTA_ACCESSCLIPBOARD, &pWinStaObj, 0);
if (!NT_SUCCESS(Status))
{
ERR("Cannot open winsta\n");
return pWinStaObj;
}
-/* If format exists, returns a non zero value (pointing to formated object) */
+/* If format exists, returns a non-null value (pointing to formated object) */
static PCLIP FASTCALL
-IntIsFormatAvailable(PWINSTATION_OBJECT pWinStaObj, UINT fmt)
+IntGetFormatElement(PWINSTATION_OBJECT pWinStaObj, UINT fmt)
{
- unsigned i = 0;
+ DWORD i;
for (i = 0; i < pWinStaObj->cNumClipFormats; ++i)
{
- if (pWinStaObj->pClipBase[i].fmt == fmt)
+ if (pWinStaObj->pClipBase[i].fmt == fmt)
return &pWinStaObj->pClipBase[i];
}
return NULL;
}
+static BOOL FASTCALL
+IntIsFormatAvailable(PWINSTATION_OBJECT pWinStaObj, UINT fmt)
+{
+ return IntGetFormatElement(pWinStaObj, fmt) != NULL;
+}
+
static VOID FASTCALL
IntFreeElementData(PCLIP pElement)
{
{
PCLIP pElement = NULL;
- /* Use exisiting entry with specified format */
+ /* Use existing entry with specified format */
if (!bEnd)
- pElement = IntIsFormatAvailable(pWinStaObj, fmt);
+ pElement = IntGetFormatElement(pWinStaObj, fmt);
/* Put new entry at the end if nothing was found */
if (!pElement)
static BOOL FASTCALL
IntIsClipboardOpenByMe(PWINSTATION_OBJECT pWinSta)
{
- /* Check if current thread has opened the clipboard */
- if (pWinSta->ptiClipLock &&
- pWinSta->ptiClipLock == PsGetCurrentThreadWin32Thread())
- {
- return TRUE;
- }
-
- return FALSE;
+ /* Check if the current thread has opened the clipboard */
+ return (pWinSta->ptiClipLock &&
+ pWinSta->ptiClipLock == PsGetCurrentThreadWin32Thread());
}
static VOID NTAPI
}
/* Get information about the bitmap format */
+ pbmi->bmiHeader.biSize = sizeof(bmiBuffer.bmih);
iResult = GreGetDIBitsInternal(hdc,
hbm,
0,
NULL,
&hMem,
TYPE_CLIPDATA,
- cjDataSize);
+ sizeof(CLIPBOARDDATA) + cjDataSize);
if (!pClipboardData)
{
goto cleanup;
TRACE("IntSynthesizeBitmap(%p, %p)\n", pWinStaObj, pBmEl);
- pDibEl = IntIsFormatAvailable(pWinStaObj, CF_DIB);
+ pDibEl = IntGetFormatElement(pWinStaObj, CF_DIB);
ASSERT(pDibEl && !IS_DATA_SYNTHESIZED(pDibEl));
- if(!pDibEl->fGlobalHandle)
+ if (!pDibEl->fGlobalHandle)
return;
pMemObj = (PCLIPBOARDDATA)UserGetObject(gHandleTable, pDibEl->hData, TYPE_CLIPDATA);
if (!pMemObj)
return;
- pBmi = (BITMAPINFO*)pMemObj->Data;
+ pBmi = (BITMAPINFO*)pMemObj->Data;
if (pMemObj->cbData < sizeof(DWORD) && pMemObj->cbData < pBmi->bmiHeader.biSize)
goto cleanup;
static VOID NTAPI
IntAddSynthesizedFormats(PWINSTATION_OBJECT pWinStaObj)
{
- PCLIP pTextEl, pUniTextEl, pOemTextEl, pLocaleEl, pBmEl, pDibEl;
+ BOOL bHaveText, bHaveUniText, bHaveOemText, bHaveLocale, bHaveBm, bHaveDib;
- 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);
+ bHaveText = IntIsFormatAvailable(pWinStaObj, CF_TEXT);
+ bHaveOemText = IntIsFormatAvailable(pWinStaObj, CF_OEMTEXT);
+ bHaveUniText = IntIsFormatAvailable(pWinStaObj, CF_UNICODETEXT);
+ bHaveLocale = IntIsFormatAvailable(pWinStaObj, CF_LOCALE);
+ bHaveBm = IntIsFormatAvailable(pWinStaObj, CF_BITMAP);
+ bHaveDib = IntIsFormatAvailable(pWinStaObj, CF_DIB);
/* Add CF_LOCALE format if we have CF_TEXT */
- if (!pLocaleEl && pTextEl)
+ if (!bHaveLocale && bHaveText)
{
PCLIPBOARDDATA pMemObj;
HANDLE hMem;
}
/* Add CF_TEXT. Note: it is synthesized in user32.dll */
- if (!pTextEl && (pUniTextEl || pOemTextEl))
+ if (!bHaveText && (bHaveUniText || bHaveOemText))
IntAddFormatedData(pWinStaObj, CF_TEXT, DATA_SYNTH_USER, FALSE, TRUE);
/* Add CF_OEMTEXT. Note: it is synthesized in user32.dll */
- if (!pOemTextEl && (pUniTextEl || pTextEl))
+ if (!bHaveOemText && (bHaveUniText || bHaveText))
IntAddFormatedData(pWinStaObj, CF_OEMTEXT, DATA_SYNTH_USER, FALSE, TRUE);
/* Add CF_UNICODETEXT. Note: it is synthesized in user32.dll */
- if (!pUniTextEl && (pTextEl || pOemTextEl))
+ if (!bHaveUniText && (bHaveText || bHaveOemText))
IntAddFormatedData(pWinStaObj, CF_UNICODETEXT, DATA_SYNTH_USER, FALSE, TRUE);
/* Add CF_BITMAP. Note: it is synthesized on demand */
- if (!pBmEl && pDibEl)
+ if (!bHaveBm && bHaveDib)
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);
+ if (!bHaveDib && bHaveBm)
+ IntSynthesizeDib(pWinStaObj, IntGetFormatElement(pWinStaObj, CF_BITMAP)->hData);
}
VOID NTAPI
UserEmptyClipboardData(PWINSTATION_OBJECT pWinSta)
{
- unsigned i;
+ DWORD i;
PCLIP pElement;
for (i = 0; i < pWinSta->cNumClipFormats; ++i)
{
pElement = &pWinSta->pClipBase[i];
- IntFreeElementData(pElement);
+ IntFreeElementData(pElement);
}
- if(pWinSta->pClipBase)
+ if (pWinSta->pClipBase)
ExFreePoolWithTag(pWinSta->pClipBase, USERTAG_CLIPBOARD);
+
pWinSta->pClipBase = NULL;
pWinSta->cNumClipFormats = 0;
}
+/* UserClipboardRelease is called from IntSendDestroyMsg in window.c */
+VOID FASTCALL
+UserClipboardRelease(PWND pWindow)
+{
+ PWINSTATION_OBJECT pWinStaObj;
+
+ pWinStaObj = IntGetWinStaForCbAccess();
+ if (!pWinStaObj)
+ return;
+
+ co_IntSendMessage(pWinStaObj->spwndClipOwner->head.h, WM_RENDERALLFORMATS, 0, 0);
+
+ /* If the window being destroyed is the current clipboard owner... */
+ if (pWindow == pWinStaObj->spwndClipOwner)
+ {
+ /* ... make it release the clipboard */
+ pWinStaObj->spwndClipOwner = NULL;
+ }
+
+ if (pWinStaObj->fClipboardChanged)
+ {
+ /* Add synthesized formats - they are rendered later */
+ IntAddSynthesizedFormats(pWinStaObj);
+
+ /* Notify viewer windows in chain */
+ pWinStaObj->fClipboardChanged = FALSE;
+ if (pWinStaObj->spwndClipViewer)
+ {
+ TRACE("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", pWinStaObj->spwndClipViewer->head.h);
+ // For 32-bit applications this message is sent as a notification
+ co_IntSendMessageNoWait(pWinStaObj->spwndClipViewer->head.h, WM_DRAWCLIPBOARD, 0, 0);
+ }
+ }
+
+ ObDereferenceObject(pWinStaObj);
+}
+
/* UserClipboardFreeWindow is called from co_UserFreeWindow in window.c */
VOID FASTCALL
UserClipboardFreeWindow(PWND pWindow)
if (!pWinStaObj)
return;
+ if (pWindow == pWinStaObj->spwndClipOwner)
+ {
+ /* The owner window was destroyed */
+ pWinStaObj->spwndClipOwner = NULL;
+ }
+
/* Check if clipboard is not locked by this window, if yes, unlock it */
if (pWindow == pWinStaObj->spwndClipOpen)
{
pWinStaObj->spwndClipOpen = NULL;
pWinStaObj->ptiClipLock = NULL;
}
- if (pWindow == pWinStaObj->spwndClipOwner)
- {
- /* The owner window was destroyed */
- pWinStaObj->spwndClipOwner = NULL;
- }
/* Remove window from window chain */
if (pWindow == pWinStaObj->spwndClipViewer)
pWinStaObj->spwndClipViewer = NULL;
{
UINT Ret = 0;
PCLIP pElement;
- PWINSTATION_OBJECT pWinStaObj = NULL;
+ PWINSTATION_OBJECT pWinStaObj;
pWinStaObj = IntGetWinStaForCbAccess();
if (!pWinStaObj)
goto cleanup;
- /* Check if clipboard has been opened */
+ /* Check if the clipboard has been opened */
if (!IntIsClipboardOpenByMe(pWinStaObj))
{
EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
else
{
/* Return next format */
- pElement = IntIsFormatAvailable(pWinStaObj, fmt);
- ++pElement;
- if (pElement < &pWinStaObj->pClipBase[pWinStaObj->cNumClipFormats])
- Ret = pElement->fmt;
+ pElement = IntGetFormatElement(pWinStaObj, fmt);
+ if (pElement != NULL)
+ {
+ ++pElement;
+ if (pElement < &pWinStaObj->pClipBase[pWinStaObj->cNumClipFormats])
+ {
+ Ret = pElement->fmt;
+ }
+ }
}
cleanup:
- if(pWinStaObj)
+ if (pWinStaObj)
ObDereferenceObject(pWinStaObj);
return Ret;
if (!pWinStaObj)
goto cleanup;
- if (pWinStaObj->ptiClipLock)
+ /* Check if we already opened the clipboard */
+ if ((pWindow == pWinStaObj->spwndClipOpen) && IntIsClipboardOpenByMe(pWinStaObj))
{
- /* Clipboard is already open */
- if (pWinStaObj->spwndClipOpen != pWindow)
- {
- EngSetLastError(ERROR_ACCESS_DENIED);
- ERR("Access denied!\n");
- goto cleanup;
- }
+ bRet = TRUE;
+ goto cleanup;
}
- /* Open clipboard */
+ /* If the clipboard was already opened by somebody else, bail out */
+ if ((pWindow != pWinStaObj->spwndClipOpen) && pWinStaObj->ptiClipLock)
+ {
+ ERR("Access denied!\n");
+ EngSetLastError(ERROR_ACCESS_DENIED);
+ goto cleanup;
+ }
+
+ /* Open the clipboard */
pWinStaObj->spwndClipOpen = pWindow;
pWinStaObj->ptiClipLock = PsGetCurrentThreadWin32Thread();
bRet = TRUE;
UserCloseClipboard(VOID)
{
BOOL bRet = FALSE;
- PWINSTATION_OBJECT pWinStaObj = NULL;
+ PWINSTATION_OBJECT pWinStaObj;
pWinStaObj = IntGetWinStaForCbAccess();
if (!pWinStaObj)
goto cleanup;
+ /* Check if the clipboard has been opened */
if (!IntIsClipboardOpenByMe(pWinStaObj))
{
EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
IntAddSynthesizedFormats(pWinStaObj);
/* Notify viewer windows in chain */
+ pWinStaObj->fClipboardChanged = FALSE;
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);
+ // For 32-bit applications this message is sent as a notification
+ co_IntSendMessageNoWait(pWinStaObj->spwndClipViewer->head.h, WM_DRAWCLIPBOARD, 0, 0);
}
-
- pWinStaObj->fClipboardChanged = FALSE;
}
cleanup:
if (pWindowRemove && pWinStaObj->spwndClipViewer)
{
- if(pWindowRemove == pWinStaObj->spwndClipViewer)
+ if (pWindowRemove == pWinStaObj->spwndClipViewer)
pWinStaObj->spwndClipViewer = UserGetWindowObject(hWndNewNext);
- if(pWinStaObj->spwndClipViewer)
+ if (pWinStaObj->spwndClipViewer)
bRet = (BOOL)co_IntSendMessage(pWinStaObj->spwndClipViewer->head.h, WM_CHANGECBCHAIN, (WPARAM)hWndRemove, (LPARAM)hWndNewNext);
}
NtUserCountClipboardFormats(VOID)
{
DWORD cFormats = 0;
- PWINSTATION_OBJECT pWinStaObj = NULL;
+ PWINSTATION_OBJECT pWinStaObj;
UserEnterShared();
if (!pWinStaObj)
return FALSE;
- if (IntIsClipboardOpenByMe(pWinStaObj))
+ /* Check if the clipboard has been opened */
+ if (!IntIsClipboardOpenByMe(pWinStaObj))
{
- UserEmptyClipboardData(pWinStaObj);
-
- if (pWinStaObj->spwndClipOwner)
- {
- TRACE("Clipboard: WM_DESTROYCLIPBOARD to %p", pWinStaObj->spwndClipOwner->head.h);
- co_IntSendMessageNoWait(pWinStaObj->spwndClipOwner->head.h, WM_DESTROYCLIPBOARD, 0, 0);
- }
-
- pWinStaObj->spwndClipOwner = pWinStaObj->spwndClipOpen;
+ EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
+ goto cleanup;
+ }
- pWinStaObj->iClipSequenceNumber++;
+ UserEmptyClipboardData(pWinStaObj);
- bRet = TRUE;
- }
- else
+ if (pWinStaObj->spwndClipOwner)
{
- EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
- ERR("Access denied!\n");
+ TRACE("Clipboard: WM_DESTROYCLIPBOARD to %p\n", pWinStaObj->spwndClipOwner->head.h);
+ // For 32-bit applications this message is sent as a notification
+ co_IntSendMessage(pWinStaObj->spwndClipOwner->head.h, WM_DESTROYCLIPBOARD, 0, 0);
}
- ObDereferenceObject(pWinStaObj);
+ pWinStaObj->spwndClipOwner = pWinStaObj->spwndClipOpen;
+
+ pWinStaObj->iClipSerialNumber++;
+ pWinStaObj->iClipSequenceNumber++;
+ pWinStaObj->fClipboardChanged = TRUE;
+ pWinStaObj->fInDelayedRendering = FALSE;
+
+ bRet = TRUE;
+
+cleanup:
+ if (pWinStaObj)
+ ObDereferenceObject(pWinStaObj);
return bRet;
}
UserEnterShared();
/* If the format is built-in we fail */
- if (fmt < 0xc000)
+ if (fmt < 0xc000 || fmt > 0xffff)
{
/* Registetrated formats are >= 0xc000 */
goto cleanup;
UserEnterShared();
pWinStaObj = IntGetWinStaForCbAccess();
- if(!pWinStaObj)
+ if (!pWinStaObj)
goto cleanup;
if (pWinStaObj->spwndClipViewer)
{
HANDLE hRet = NULL;
PCLIP pElement;
- PWINSTATION_OBJECT pWinStaObj = NULL;
+ PWINSTATION_OBJECT pWinStaObj;
TRACE("NtUserGetClipboardData(%x, %p)\n", fmt, pgcd);
if (!pWinStaObj)
goto cleanup;
+ /* Check if the clipboard has been opened */
if (!IntIsClipboardOpenByMe(pWinStaObj))
{
EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
goto cleanup;
}
- pElement = IntIsFormatAvailable(pWinStaObj, fmt);
+ pElement = IntGetFormatElement(pWinStaObj, fmt);
if (pElement && IS_DATA_DELAYED(pElement) && pWinStaObj->spwndClipOwner)
{
/* Send WM_RENDERFORMAT message */
pWinStaObj->fInDelayedRendering = FALSE;
/* Data should be in clipboard now */
- pElement = IntIsFormatAvailable(pWinStaObj, fmt);
+ pElement = IntGetFormatElement(pWinStaObj, fmt);
}
if (!pElement || IS_DATA_DELAYED(pElement))
goto cleanup;
-
if (IS_DATA_SYNTHESIZED(pElement))
{
/* Note: Data is synthesized in usermode */
case CF_UNICODETEXT:
case CF_TEXT:
case CF_OEMTEXT:
- pElement = IntIsFormatAvailable(pWinStaObj, CF_UNICODETEXT);
+ pElement = IntGetFormatElement(pWinStaObj, CF_UNICODETEXT);
if (IS_DATA_SYNTHESIZED(pElement))
- pElement = IntIsFormatAvailable(pWinStaObj, CF_TEXT);
+ pElement = IntGetFormatElement(pWinStaObj, CF_TEXT);
if (IS_DATA_SYNTHESIZED(pElement))
- pElement = IntIsFormatAvailable(pWinStaObj, CF_OEMTEXT);
+ pElement = IntGetFormatElement(pWinStaObj, CF_OEMTEXT);
break;
case CF_BITMAP:
IntSynthesizeBitmap(pWinStaObj, pElement);
{
PCLIP pLocaleEl;
- pLocaleEl = IntIsFormatAvailable(pWinStaObj, CF_LOCALE);
+ pLocaleEl = IntGetFormatElement(pWinStaObj, CF_LOCALE);
if (pLocaleEl && !IS_DATA_DELAYED(pLocaleEl))
pgcd->hLocale = pLocaleEl->hData;
}
{
PCLIP pPaletteEl;
- pPaletteEl = IntIsFormatAvailable(pWinStaObj, CF_PALETTE);
+ pPaletteEl = IntGetFormatElement(pWinStaObj, CF_PALETTE);
if (pPaletteEl && !IS_DATA_DELAYED(pPaletteEl))
pgcd->hPalette = pPaletteEl->hData;
}
_SEH2_END;
cleanup:
- if(pWinStaObj)
+ if (pWinStaObj)
ObDereferenceObject(pWinStaObj);
UserLeave();
UserSetClipboardData(UINT fmt, HANDLE hData, PSETCLIPBDATA scd)
{
HANDLE hRet = NULL;
- PWINSTATION_OBJECT pWinStaObj = NULL;
+ PWINSTATION_OBJECT pWinStaObj;
pWinStaObj = IntGetWinStaForCbAccess();
if (!pWinStaObj)
goto cleanup;
- /* If it's delayed rendering we don't have to open clipboard */
- if ((pWinStaObj->fInDelayedRendering &&
- pWinStaObj->spwndClipOwner->head.pti != PsGetCurrentThreadWin32Thread()) ||
- !IntIsClipboardOpenByMe(pWinStaObj))
+ if (!fmt || !pWinStaObj->ptiClipLock)
{
ERR("Access denied!\n");
EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
if (scd->fIncSerialNumber)
pWinStaObj->iClipSerialNumber++;
- /* Is it a delayed render? */
+ /* Is it a delayed rendering? */
if (hData)
{
/* Is it a bitmap? */
IntAddFormatedData(pWinStaObj, fmt, hData, scd->fGlobalHandle, FALSE);
TRACE("hData stored\n");
- pWinStaObj->iClipSequenceNumber++;
+ /* If the serial number was increased, increase also the sequence number */
+ if (scd->fIncSerialNumber)
+ pWinStaObj->iClipSequenceNumber++;
+
pWinStaObj->fClipboardChanged = TRUE;
/* Note: Synthesized formats are added in NtUserCloseClipboard */
}
else
{
- /* This is a delayed render */
+ /* This is a delayed rendering */
IntAddFormatedData(pWinStaObj, fmt, DATA_DELAYED, FALSE, FALSE);
TRACE("SetClipboardData delayed format: %u\n", fmt);
}
cleanup:
TRACE("NtUserSetClipboardData returns: %p\n", hRet);
- if(pWinStaObj)
+ if (pWinStaObj)
ObDereferenceObject(pWinStaObj);
return hRet;
NtUserSetClipboardViewer(HWND hWndNewViewer)
{
HWND hWndNext = NULL;
- PWINSTATION_OBJECT pWinStaObj = NULL;
+ PWINSTATION_OBJECT pWinStaObj;
PWND pWindow;
UserEnterExclusive();
/* Set new viewer window */
pWinStaObj->spwndClipViewer = pWindow;
+ /* Notify viewer windows in chain */
+ pWinStaObj->fClipboardChanged = FALSE;
+ if (pWinStaObj->spwndClipViewer)
+ {
+ TRACE("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", pWinStaObj->spwndClipViewer->head.h);
+ // For 32-bit applications this message is sent as a notification
+ co_IntSendMessageNoWait(pWinStaObj->spwndClipViewer->head.h, WM_DRAWCLIPBOARD, 0, 0);
+ }
+
cleanup:
- if(pWinStaObj)
+ if (pWinStaObj)
ObDereferenceObject(pWinStaObj);
UserLeave();