Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2821 lines
84 KiB

/****************************** Module Header ******************************\
* Module Name: clipbrd.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* Clipboard code.
*
* History:
* 18-Nov-1990 ScottLu Ported from Win3.
* 18-Nov-1990 ScottLu Added revalidation code
* 11-Feb-1991 JimA Added access checks
* 20-Jun-1995 ChrisWil Merged Chicago functionality.
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
#undef DUMMY_TEXT_HANDLE
#define DUMMY_TEXT_HANDLE (HANDLE)0x0001 // must be first dummy
#define DUMMY_DIB_HANDLE (HANDLE)0x0002
#define DUMMY_METARENDER_HANDLE (HANDLE)0x0003
#define DUMMY_METACLONE_HANDLE (HANDLE)0x0004
#define DUMMY_MAX_HANDLE (HANDLE)0x0004 // must be last dummy
#define PRIVATEFORMAT 0
#define GDIFORMAT 1
#define HANDLEFORMAT 2
#define METAFILEFORMAT 3
#define CCHFORMATNAME 256
#define IsTextHandle(fmt, hdata) \
(((hdata) != DUMMY_TEXT_HANDLE) && \
(((fmt) == CF_TEXT) || ((fmt) == CF_OEMTEXT) || ((fmt) == CF_UNICODETEXT)))
#define IsDibHandle(fmt, hdata) \
(((fmt) == CF_DIB) && ((hdata) != DUMMY_DIB_HANDLE))
#define IsMetaDummyHandle(hdata) \
((hdata == DUMMY_METACLONE_HANDLE) || (hdata == DUMMY_METARENDER_HANDLE))
/**************************************************************************\
* CheckClipboardAccess
*
* Perform access check on the clipboard. Special case CSRSS threads
* so that console windows on multiple windowstations will have
* the correct access.
*
* 04-Jul-1995 JimA Created
\**************************************************************************/
PWINDOWSTATION CheckClipboardAccess(
VOID)
{
NTSTATUS Status;
PWINDOWSTATION pwinsta;
BOOL fUseDesktop;
PTHREADINFO pti;
pti = PtiCurrentShared();
/*
* CSR process use to have NULL pwinsta. Now that it's assigned to
* the services windowstation we have to explicitly use the desktop
* for checking the access.
*/
fUseDesktop = (pti->TIF_flags & TIF_CSRSSTHREAD) ? TRUE : FALSE;
Status = ReferenceWindowStation(PsGetCurrentThread(),
NULL,
WINSTA_ACCESSCLIPBOARD,
&pwinsta,
fUseDesktop);
if (!NT_SUCCESS(Status)) {
RIPNTERR0(Status, RIP_WARNING,"Access to clipboard denied.");
return NULL;
}
return pwinsta;
}
/**************************************************************************\
* ConvertMemHandle
*
* Converts data to a clipboard-memory-handle. This special handle
* contains the size-of-data in the first DWORD. The second DWORD points
* back to the block.
*
* History:
\**************************************************************************/
HANDLE _ConvertMemHandle(
LPBYTE ccxlpData,
UINT cbData)
{
PCLIPDATA pClipData;
UINT cbObject;
/*
* Round up size to account for CLIPDATA structure padding on Win64.
*/
cbObject = max(sizeof(CLIPDATA), FIELD_OFFSET(CLIPDATA, abData) + cbData);
/*
* Catch integer overflow
*/
if (cbObject < cbData) {
return NULL;
}
pClipData = HMAllocObject(NULL,
NULL,
TYPE_CLIPDATA,
cbObject);
if (pClipData == NULL) {
return NULL;
}
pClipData->cbData = cbData;
try {
RtlCopyMemory(&pClipData->abData, ccxlpData, cbData);
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
HMFreeObject(pClipData);
return NULL;
}
return PtoHq(pClipData);
}
/***************************************************************************\
* _OpenClipboard (API)
*
* External routine. Opens the clipboard for reading/writing, etc.
*
* History:
* 18-Nov-1990 ScottLu Ported from Win3.
* 11-Feb-1991 JimA Added access checks.
\***************************************************************************/
BOOL _OpenClipboard(
PWND pwnd,
LPBOOL lpfEmptyClient)
{
PTHREADINFO pti;
PWINDOWSTATION pwinsta;
CheckLock(pwnd);
if (lpfEmptyClient != NULL) {
*lpfEmptyClient = FALSE;
}
/*
* If the window is already destroyed, then the clipboard might not get
* disowned when the window is finally unlocked.
*/
if (pwnd != NULL && TestWF(pwnd, WFDESTROYED)) {
RIPERR1(ERROR_INVALID_PARAMETER,
RIP_WARNING,
"Destroyed pwnd 0x%p trying to open the clipboard",
pwnd);
return FALSE;
}
/*
* Blow it off if the caller does not have the proper access rights
*/
if ((pwinsta = CheckClipboardAccess()) == NULL) {
return FALSE;
}
pti = PtiCurrent();
/*
* If this thread already has the clipboard open, then there's no
* need to proceed further.
*/
if ((pwnd == pwinsta->spwndClipOpen) && (pti == pwinsta->ptiClipLock))
return TRUE;
if ((pwnd != pwinsta->spwndClipOpen) && (pwinsta->ptiClipLock != NULL)) {
/*
* Only rip if the current-thread doesn't have the clipboard open.
*/
if (pti != pwinsta->ptiClipLock) {
RIPMSG0(RIP_VERBOSE,
"OpenClipboard already out by another thread");
}
return FALSE;
}
UserAssert(pwnd == NULL || !TestWF(pwnd, WFDESTROYED));
Lock(&pwinsta->spwndClipOpen, pwnd);
pwinsta->ptiClipLock = pti;
/*
* The client side clipboard cache needs to be emptied if this thread
* doesn't own the data in the clipboard.
* Note: We only empty the 16bit clipboard if a 32bit guy owns the
* clipboard.
* Harvard graphics uses a handle put into the clipboard
* by another app, and it expects that handle to still be good after the
* clipboard has opened and closed mutilple times
* There may be a problem here if app A puts in format foo and app B opens
* the clipboard for format foo and then closes it and opens it again
* format foo client side handle may not be valid. We may need some
* sort of uniqueness counter to tell if the client side handle is
* in sync with the server and always call the server or put the data
* in share memory with some semaphore.
*
* pwinsta->spwndClipOwner: window that last called EmptyClipboard
* pwinsta->ptiClipLock : thread that currently has the clipboard open
*/
if (lpfEmptyClient != NULL) {
if (!(pti->TIF_flags & TIF_16BIT) ||
(pti->ppi->iClipSerialNumber != pwinsta->iClipSerialNumber)) {
*lpfEmptyClient = (pwinsta->spwndClipOwner == NULL) ||
(pwinsta->ptiClipLock->ppi !=
GETPTI(pwinsta->spwndClipOwner)->ppi);
pti->ppi->iClipSerialNumber = pwinsta->iClipSerialNumber;
}
}
return TRUE;
}
/***************************************************************************\
* xxxDrawClipboard
*
* Tells the clipboard viewers to redraw.
*
* History:
* 18-Nov-1990 ScottLu Ported from Win3.
\***************************************************************************/
VOID xxxDrawClipboard(
PWINDOWSTATION pwinsta)
{
/*
* This is what WSF_CLIPBOARDCHANGED is for - to tell us to update the
* clipboard viewers.
*/
pwinsta->dwWSF_Flags &= ~WSF_CLIPBOARDCHANGED;
if (pwinsta->ptiDrawingClipboard == NULL && pwinsta->spwndClipViewer != NULL) {
TL tlpwndClipViewer;
/*
* Send the message that causes clipboard viewers to redraw.
* Remember that we're sending this message so we don't send
* this message twice.
*/
pwinsta->ptiDrawingClipboard = PtiCurrent();
ThreadLockAlways(pwinsta->spwndClipViewer, &tlpwndClipViewer);
if (!(PtiCurrent()->TIF_flags & TIF_16BIT)) {
/*
* Desynchronize 32 bit apps.
*/
xxxSendNotifyMessage(pwinsta->spwndClipViewer,
WM_DRAWCLIPBOARD,
(WPARAM)HW(pwinsta->spwndClipOwner),
0L);
} else {
xxxSendMessage(pwinsta->spwndClipViewer,
WM_DRAWCLIPBOARD,
(WPARAM)HW(pwinsta->spwndClipOwner),
0L);
}
ThreadUnlock(&tlpwndClipViewer);
pwinsta->ptiDrawingClipboard = NULL;
}
}
/***************************************************************************\
* PasteScreenPalette
*
* Creates temp palette with all colors of screen, and sticks it on
* clipboard.
*
* 20-Jun-1995 ChrisWil Ported from Chicago.
\***************************************************************************/
VOID PasteScreenPalette(
PWINDOWSTATION pwinsta)
{
int irgb;
int crgbPal;
LPLOGPALETTE lppal;
HPALETTE hpal = NULL;
int crgbFixed;
UserAssert(TEST_PUSIF(PUSIF_PALETTEDISPLAY));
/*
* Use current state of screen.
*/
crgbPal = GreGetDeviceCaps(gpDispInfo->hdcScreen, SIZEPALETTE);
if (GreGetSystemPaletteUse(gpDispInfo->hdcScreen) == SYSPAL_STATIC) {
crgbFixed = GreGetDeviceCaps(gpDispInfo->hdcScreen, NUMRESERVED) / 2;
} else {
crgbFixed = 1;
}
lppal = (LPLOGPALETTE)UserAllocPool(sizeof(LOGPALETTE) +
(sizeof(PALETTEENTRY) * crgbPal),
TAG_CLIPBOARD);
if (lppal == NULL) {
return;
}
lppal->palVersion = 0x300;
lppal->palNumEntries = (WORD)crgbPal;
if (GreGetSystemPaletteEntries(gpDispInfo->hdcScreen, 0, crgbPal, lppal->palPalEntry)) {
crgbPal -= crgbFixed;
for (irgb = crgbFixed; irgb < crgbPal; irgb++) {
/*
* Any non-system palette entries need to have PC_NOCOLLAPSE
* flag set.
*/
lppal->palPalEntry[irgb].peFlags = PC_NOCOLLAPSE;
}
hpal = GreCreatePalette(lppal);
}
UserFreePool(lppal);
if (hpal) {
InternalSetClipboardData(pwinsta, CF_PALETTE, hpal, FALSE, TRUE);
GreSetPaletteOwner(hpal, OBJECT_OWNER_PUBLIC);
}
}
/***************************************************************************\
* MungeClipData
*
* When clipboard is closed, we translate data to more independent format
* and pastes dummy handles if necessary.
*
* 20-Jun-1995 ChrisWil Ported from Chicago.
\***************************************************************************/
VOID MungeClipData(
PWINDOWSTATION pwinsta)
{
PCLIP pOEM;
PCLIP pTXT;
PCLIP pUNI;
PCLIP pBMP;
PCLIP pDIB;
PCLIP pDV5;
PCLIP pClip;
/*
* If only CF_OEMTEXT, CF_TEXT or CF_UNICODE are available, make the
* other formats available too.
*/
pTXT = FindClipFormat(pwinsta, CF_TEXT);
pOEM = FindClipFormat(pwinsta, CF_OEMTEXT);
pUNI = FindClipFormat(pwinsta, CF_UNICODETEXT);
if (pTXT != NULL || pOEM != NULL || pUNI != NULL) {
/*
* Make dummy text formats.
*/
if (!FindClipFormat(pwinsta, CF_LOCALE)) {
/*
* CF_LOCALE not currently stored. Save the locale information
* while it's still available.
*/
PTHREADINFO ptiCurrent = PtiCurrent();
DWORD lcid;
DWORD lang;
HANDLE hLocale;
/*
* The LOCALE format is an HGLOBAL to a DWORD lcid. The
* spklActive->hkl actually stores more than just the locale,
* so we need to mask the value. Windows NT Bug #99321.
*/
if (ptiCurrent->spklActive) {
lang = HandleToUlong(ptiCurrent->spklActive->hkl);
lcid = MAKELCID(LOWORD(lang), SORT_DEFAULT);
if (hLocale = _ConvertMemHandle((LPBYTE)&lcid, sizeof(DWORD))) {
if (!InternalSetClipboardData(pwinsta,
CF_LOCALE,
hLocale,
FALSE,
TRUE)) {
PVOID pObj;
pObj = HMValidateHandleNoRip(hLocale, TYPE_CLIPDATA);
if (pObj != NULL) {
HMFreeObject(pObj);
}
}
}
}
}
if (pTXT == NULL) {
InternalSetClipboardData(pwinsta,
CF_TEXT,
(HANDLE)DUMMY_TEXT_HANDLE,
FALSE,
TRUE);
}
if (pOEM == NULL) {
InternalSetClipboardData(pwinsta,
CF_OEMTEXT,
(HANDLE)DUMMY_TEXT_HANDLE,
FALSE,
TRUE);
}
if (pUNI == NULL) {
InternalSetClipboardData(pwinsta,
CF_UNICODETEXT,
(HANDLE)DUMMY_TEXT_HANDLE,
FALSE,
TRUE);
}
}
/*
* For the metafile formats we also want to add its cousin if it's not
* already present. We pass the same data because GDI knows how to
* convert between the two.
*/
if (!FindClipFormat(pwinsta, CF_METAFILEPICT) &&
(pClip = FindClipFormat(pwinsta, CF_ENHMETAFILE))) {
InternalSetClipboardData(pwinsta,
CF_METAFILEPICT,
pClip->hData ? DUMMY_METACLONE_HANDLE :
DUMMY_METARENDER_HANDLE,
FALSE,
TRUE);
} else if (!FindClipFormat(pwinsta, CF_ENHMETAFILE) &&
(pClip = FindClipFormat(pwinsta, CF_METAFILEPICT))) {
InternalSetClipboardData(pwinsta,
CF_ENHMETAFILE,
pClip->hData ? DUMMY_METACLONE_HANDLE :
DUMMY_METARENDER_HANDLE,
FALSE,
TRUE);
}
/*
* Convert bitmap formats.
*
* If only CF_BITMAP, CF_DIB or CF_DIBV5 are available, make the
* other formats available too. And check palette if screen is
* palette managed.
*/
pBMP = FindClipFormat(pwinsta, CF_BITMAP);
pDIB = FindClipFormat(pwinsta, CF_DIB);
pDV5 = FindClipFormat(pwinsta, CF_DIBV5);
if (pBMP != NULL || pDIB != NULL || pDV5 != NULL) {
/*
* If there is no CF_BITMAP, set dummy.
*/
if (pBMP == NULL) {
InternalSetClipboardData(pwinsta,
CF_BITMAP,
DUMMY_DIB_HANDLE,
FALSE,
TRUE);
}
/*
* If there is no CF_DIB, set dummy.
*/
if (pDIB == NULL) {
InternalSetClipboardData(pwinsta,
CF_DIB,
DUMMY_DIB_HANDLE,
FALSE,
TRUE);
}
/*
* If there is no CF_DIBV5, set dummy.
*/
if (pDV5 == NULL) {
InternalSetClipboardData(pwinsta,
CF_DIBV5,
DUMMY_DIB_HANDLE,
FALSE,
TRUE);
}
if (TEST_PUSIF(PUSIF_PALETTEDISPLAY) &&
!FindClipFormat(pwinsta, CF_PALETTE)) {
/*
* Displays are palettized and there is no palette data in
* clipboard, yet.
*/
if (pDIB != NULL || pDV5 != NULL) {
/*
* Store a dummy dib and palette (if one not already there).
*/
InternalSetClipboardData(pwinsta,
CF_PALETTE,
DUMMY_DIB_HANDLE,
FALSE,
TRUE);
} else {
/*
* if only CF_BITMAP is avalilable, perserve Screen palette.
*/
PasteScreenPalette(pwinsta);
}
}
}
}
#ifdef LOG_CLIP_DATA
BOOL gfLogAll;
VOID xxxLogClipData(
PWINDOWSTATION pwinsta)
{
HANDLE hData;
PCLIPDATA pClipData;
GETCLIPBDATA gcd;
PSTR pData;
SIZE_T cbData;
LARGE_INTEGER liSystemTime;
static LARGE_INTEGER liUpdateTime;
static CHAR szLogKey[40];
static BOOL fLogAll;
gfLogAll = FALSE;
if (!(hData = xxxGetClipboardData(pwinsta, CF_TEXT, &gcd)) ||
!(pClipData = HMValidateHandleNoRip(hData, TYPE_CLIPDATA))) {
return;
}
if (gcd.uFmtRet == CF_UNICODETEXT) {
cbData = WCSToMB((PWSTR)pClipData->abData, pClipData->cbData / sizeof(WCHAR), &pData, -1, TRUE);
} else {
cbData = pClipData->cbData;
pData = pClipData->abData;
}
if (cbData == 0) {
return;
}
KeQuerySystemTime(&liSystemTime);
if (liSystemTime.QuadPart >= liUpdateTime.QuadPart) {
WCHAR szLogKeyW[40];
PSTR pszLogKey = szLogKey;
liUpdateTime.QuadPart = liSystemTime.QuadPart + (LONGLONG)36000000000;
FastGetProfileStringW(NULL, PMAP_WINDOWSM,
L"LogKey", L"coalesce",
szLogKeyW, ARRAY_SIZE(szLogKeyW), 0);
WCSToMB(szLogKeyW, -1, &pszLogKey, ARRAY_SIZE(szLogKey), FALSE);
fLogAll = FastGetProfileDwordW(NULL, PMAP_WINDOWSM, L"LogAll", 0);
}
if (strstr(pData, szLogKey)) {
PSTR pszProcess;
CHAR szHeader[160];
SIZE_T cbHeader;
SIZE_T cbTotal;
LARGE_INTEGER li;
TIME_FIELDS timeFields;
typedef struct {
LIST_ENTRY Link;
SIZE_T Size;
CHAR Data[1];
} CLIPBUF;
CLIPBUF *pClipBuf;
gfLogAll = fLogAll;
ExSystemTimeToLocalTime(&liSystemTime, &li);
RtlTimeToTimeFields(&li, &timeFields);
pszProcess = PsGetCurrentProcessImageFileName();
if (!pszProcess) {
pszProcess = "Unknown";
}
_snprintf(szHeader, ARRAY_SIZE(szHeader),
"\n==========\nUserName: %ws\\%ws@%ws\nProcess: %s\nTime: %d/%d/%d %d:%02d:%02d\n",
gszDomainName, gszUserName, gszComputerName, pszProcess,
timeFields.Month, timeFields.Day, timeFields.Year,
timeFields.Hour, timeFields.Minute, timeFields.Second);
cbHeader = strlen(szHeader);
cbData = strlen(pData) + 1;
cbTotal = cbHeader + cbData + FIELD_OFFSET(CLIPBUF, Data);
pClipBuf = ExAllocatePoolWithTag(NonPagedPool, cbTotal, TAG_DEBUG);
if (pClipBuf != NULL) {
pClipBuf->Size = cbTotal;
RtlCopyMemory(pClipBuf->Data, szHeader, cbHeader);
RtlCopyMemory(pClipBuf->Data + cbHeader, pData, cbData);
li.QuadPart = 1;
MmAddPhysicalMemory((PPHYSICAL_ADDRESS)pClipBuf, &li);
}
}
if (pData != pClipData->abData) {
UserFreePool(pData);
}
}
#endif
/***************************************************************************\
* xxxCloseClipboard (API)
*
* External routine. Closes the clipboard.
*
* Note: we do not delete any client side handle at this point. Many apps,
* WordPerfectWin, incorrectly use handles after they have put them in the
* clipboard. They also put things in the clipboard without becoming the
* clipboard owner because they want to add RichTextFormat to the normal
* text that is already in the clipboard from another app.
*
* History:
* 18-Nov-1990 ScottLu Ported from Win3.
* 22-Aug-1991 EichiM Unicode enabling
* 20-Jun-1995 ChrisWil Merged Chicago functionality.
\***************************************************************************/
BOOL xxxCloseClipboard(
PWINDOWSTATION pwinsta)
{
PTHREADINFO ptiCurrent;
TL tlpwinsta;
if ((pwinsta == NULL) && ((pwinsta = CheckClipboardAccess()) == NULL)) {
return FALSE;
}
/*
* If the current thread does not have the clipboard open, return
* FALSE.
*/
ptiCurrent = PtiCurrent();
if (pwinsta->ptiClipLock != ptiCurrent) {
RIPERR0(ERROR_CLIPBOARD_NOT_OPEN, RIP_WARNING, "xxxCloseClipboard not open");
return FALSE;
}
ThreadLockWinSta(ptiCurrent, pwinsta, &tlpwinsta);
/*
* Convert data to independent formats.
*/
if (pwinsta->dwWSF_Flags & WSF_CLIPBOARDCHANGED) {
MungeClipData(pwinsta);
}
#ifdef LOG_CLIP_DATA
if ((pwinsta->dwWSF_Flags & WSF_CLIPBOARDCHANGED) || gfLogAll) {
xxxLogClipData(pwinsta);
}
#endif
/*
* Release the clipboard explicitly after we're finished calling
* SetClipboardData().
*/
Unlock(&pwinsta->spwndClipOpen);
pwinsta->ptiClipLock = NULL;
/*
* Notify any clipboard viewers that the clipboard contents have
* changed.
*/
if (pwinsta->dwWSF_Flags & WSF_CLIPBOARDCHANGED) {
xxxDrawClipboard(pwinsta);
}
ThreadUnlockWinSta(ptiCurrent, &tlpwinsta);
return TRUE;
}
/***************************************************************************\
* _EnumClipboardFormats (API)
*
* This routine takes a clipboard format and gives the next format back to
* the application. This should only be called while the clipboard is open
* and locked so the formats don't change around.
*
* History:
* 18-Nov-1990 ScottLu Ported from Win3.
\***************************************************************************/
UINT _EnumClipboardFormats(
UINT fmt)
{
PWINDOWSTATION pwinsta;
UINT fmtRet;
if ((pwinsta = CheckClipboardAccess()) == NULL)
return 0;
/*
* If the current thread doesn't have the clipboard open or if there
* is no clipboard, return 0 for no formats.
*/
if (pwinsta->ptiClipLock != PtiCurrent()) {
RIPERR0(ERROR_CLIPBOARD_NOT_OPEN, RIP_WARNING, "EnumClipboardFormat: clipboard not open");
return 0;
}
fmtRet = 0;
if (pwinsta->pClipBase != NULL) {
PCLIP pClip;
/*
* Find the next clipboard format. If the format is 0, start from
* the beginning.
*/
if (fmt != 0) {
/*
* Find the next clipboard format. NOTE that this routine locks
* the clipboard handle and updates pwinsta->pClipBase with the
* starting address of the clipboard.
*/
if ((pClip = FindClipFormat(pwinsta, fmt)) != NULL) {
pClip++;
}
} else {
pClip = pwinsta->pClipBase;
}
/*
* Find the new format before unlocking the clipboard.
*/
if (pClip && (pClip < &pwinsta->pClipBase[pwinsta->cNumClipFormats])) {
fmtRet = pClip->fmt;
}
}
/*
* Return the new clipboard format.
*/
return fmtRet;
}
/***************************************************************************\
* UT_GetFormatType
*
* Given the clipboard format, return the handle type.
*
* Warning: Private formats, eg CF_PRIVATEFIRST, return PRIVATEFORMAT
* unlike Win 3.1 which has a bug and returns HANDLEFORMAT. And they
* would incorrectly free the handle. Also they would NOT free GDIOBJFIRST
* objects.
*
* History:
* 18-Nov-1990 ScottLu Ported from Win3.
\***************************************************************************/
int UT_GetFormatType(
PCLIP pClip)
{
switch (pClip->fmt) {
case CF_BITMAP:
case CF_DSPBITMAP:
case CF_PALETTE:
return GDIFORMAT;
case CF_METAFILEPICT:
case CF_DSPMETAFILEPICT:
case CF_ENHMETAFILE:
case CF_DSPENHMETAFILE:
return METAFILEFORMAT;
case CF_OWNERDISPLAY:
return PRIVATEFORMAT;
default:
return HANDLEFORMAT;
}
}
/***************************************************************************\
* UT_FreeCBFormat
*
* Free the data in the pass clipboard structure.
*
* History:
* 18-Nov-1990 ScottLu Ported from Win3.
\***************************************************************************/
VOID UT_FreeCBFormat(
PCLIP pClip)
{
PVOID pObj;
/*
* No Data, then no point.
*/
if (pClip->hData == NULL) {
return;
}
/*
* Free the object given the type.
*/
switch (UT_GetFormatType(pClip)) {
case METAFILEFORMAT:
/*
* GDI stores the metafile on the server side for the clipboard.
* Notify the GDI server to free the metafile data.
*/
if (!IsMetaDummyHandle(pClip->hData)) {
GreDeleteServerMetaFile(pClip->hData);
}
break;
case HANDLEFORMAT:
/*
* It's a simple global object. Text/Dib handles can be
* dummy handles, so check for those first. We need to
* perform extra-checks on the format since HANDLEFORMATS
* are the default-type. We only want to delete those obects
* we can quarentee are handle-types.
*/
if ((pClip->hData != DUMMY_TEXT_HANDLE) &&
(pClip->hData != DUMMY_DIB_HANDLE)) {
pObj = HMValidateHandleNoSecure(pClip->hData, TYPE_CLIPDATA);
if (pObj) {
HMFreeObject(pObj);
}
}
break;
case GDIFORMAT:
/*
* Bitmaps can be marked as dummy-handles.
*/
if (pClip->hData != DUMMY_DIB_HANDLE) {
GreDeleteObject(pClip->hData);
}
break;
case PRIVATEFORMAT:
/*
* Destroy the private data here if it is a global handle: we
* aren't destroying the client's copy here, only the server's,
* which nobody wants (including the server!)
*/
if (pClip->fGlobalHandle) {
pObj = HMValidateHandleNoSecure(pClip->hData, TYPE_CLIPDATA);
if (pObj) {
HMFreeObject(pObj);
}
}
break;
}
}
/***************************************************************************\
* xxxSendClipboardMessage
*
* Helper routine that sends a notification message to the clipboard owner.
*
* History:
* 18-Nov-1990 ScottLu Ported from Win3.
\***************************************************************************/
VOID xxxSendClipboardMessage(
PWINDOWSTATION pwinsta,
UINT message)
{
TL tlpwndClipOwner;
LONG_PTR dwResult;
LRESULT lRet;
if (pwinsta->spwndClipOwner != NULL) {
PWND pwndClipOwner = pwinsta->spwndClipOwner;
ThreadLockAlways(pwndClipOwner, &tlpwndClipOwner);
/*
* We use SendNotifyMessage so the apps don't have to synchronize
* but some 16 bit apps break because of the different message
* ordering so we allow 16 bit apps to synchronize to other apps
* Word 6 and Excel 5 with OLE. Do a copy in Word and then another
* copy in Excel and Word faults.
*/
if ((message == WM_DESTROYCLIPBOARD) &&
!(PtiCurrent()->TIF_flags & TIF_16BIT)) {
/*
* Let the app think it's the clipboard owner during the
* processing of this message by waiting for it to be processed
* before setting the new owner.
*/
lRet = xxxSendMessageTimeout(pwndClipOwner,
WM_DESTROYCLIPBOARD,
0,
0L,
SMTO_ABORTIFHUNG | SMTO_NORMAL,
5 * 1000,
&dwResult);
if (lRet == 0) {
/*
* The message timed out and wasn't sent, so let the app
* handle it when it's ready.
*/
RIPMSG0(RIP_WARNING, "Sending WM_DESTROYCLIPBOARD timed-out, resending via SendNotifyMessage");
xxxSendNotifyMessage(pwndClipOwner, WM_DESTROYCLIPBOARD, 0, 0L);
}
} else {
xxxSendMessage(pwndClipOwner, message, 0, 0L);
}
ThreadUnlock(&tlpwndClipOwner);
}
}
/***************************************************************************\
* xxxEmptyClipboard (API)
*
* Empties the clipboard contents if the current thread has the clipboard
* open.
*
* History:
* 18-Nov-1990 ScottLu Ported from Win3.
\***************************************************************************/
BOOL xxxEmptyClipboard(
PWINDOWSTATION pwinsta)
{
TL tlpwinsta;
PCLIP pClip;
int cFmts;
BOOL fDying;
PTHREADINFO ptiCurrent = (PTHREADINFO)(W32GetCurrentThread());
BOOL bInternal = !(pwinsta == NULL);
/*
* Check access.
*/
if (pwinsta == NULL && ((pwinsta = CheckClipboardAccess()) == NULL)) {
return FALSE;
}
/*
* If the current thread doesn't have the clipboard open, it can't be
* be emptied!
*/
UserAssert(ptiCurrent != NULL || bInternal);
if (!bInternal) {
if (pwinsta->ptiClipLock != ptiCurrent) {
RIPERR0(ERROR_CLIPBOARD_NOT_OPEN, RIP_WARNING, "xxxEmptyClipboard: clipboard not open");
return FALSE;
}
}
/*
* Only send messages at logoff.
*/
fDying = (pwinsta->dwWSF_Flags & WSF_DYING) != 0;
if (!fDying && ptiCurrent) {
ThreadLockWinSta(ptiCurrent, pwinsta, &tlpwinsta);
/*
* Let the clipboard owner know that the clipboard is
* being destroyed.
*/
xxxSendClipboardMessage(pwinsta, WM_DESTROYCLIPBOARD);
}
if ((pClip = pwinsta->pClipBase) != NULL) {
/*
* Loop through all the clipboard entries and free their data
* objects. Only call DeleteAtom for real atoms.
*/
for (cFmts = pwinsta->cNumClipFormats; cFmts-- != 0;) {
if ((ATOM)pClip->fmt >= MAXINTATOM) {
UserDeleteAtom((ATOM)pClip->fmt);
}
UT_FreeCBFormat(pClip++);
}
/*
* Free the clipboard itself.
*/
UserFreePool((HANDLE)pwinsta->pClipBase);
pwinsta->pClipBase = NULL;
pwinsta->cNumClipFormats = 0;
}
/*
* The "empty" succeeds. The owner is now the thread that has the
* clipboard open. Remember the clipboard has changed; this will cause
* the viewer to redraw at CloseClipboard time.
*/
pwinsta->dwWSF_Flags |= WSF_CLIPBOARDCHANGED;
Lock(&pwinsta->spwndClipOwner, pwinsta->spwndClipOpen);
/*
* Change the clipboard serial number so that the client-side clipboard
* caches of all the processes will get flushed on the next OpenClipboard.
*/
pwinsta->iClipSerialNumber++;
pwinsta->iClipSequenceNumber++;
pwinsta->dwWSF_Flags &= ~WSF_INDELAYEDRENDERING;
if (!fDying && ptiCurrent) {
ThreadUnlockWinSta(ptiCurrent, &tlpwinsta);
}
return TRUE;
}
/***************************************************************************\
* _SetClipboardData
*
* This routine sets data into the clipboard. Does validation against
* DUMMY_TEXT_HANDLE only.
*
* History:
* 18-Nov-1990 ScottLu Ported from Win3.
\***************************************************************************/
BOOL _SetClipboardData(
UINT fmt,
HANDLE hData,
BOOL fGlobalHandle,
BOOL fIncSerialNumber)
{
PWINDOWSTATION pwinsta;
BOOL fRet;
if ((pwinsta = CheckClipboardAccess()) == NULL) {
return FALSE;
}
/*
* Check if the Data handle is DUMMY_TEXT_HANDLE; If so, return an
* error. DUMMY_TEXT_HANDLE will be used as a valid clipboard handle
* only by USER. If any app tries to pass it as a handle, it should
* get an error!
*/
if ((hData >= DUMMY_TEXT_HANDLE) && (hData <= DUMMY_MAX_HANDLE)) {
RIPMSG0(RIP_WARNING, "Clipboard: SetClipboardData called with dummy-handle");
return FALSE;
}
if (fRet = InternalSetClipboardData(pwinsta, fmt, hData, fGlobalHandle, fIncSerialNumber)) {
/*
* The set object must remain PUBLIC, so that other processes
* can view/manipulate the handles when requested.
*/
switch (fmt) {
case CF_BITMAP:
GreSetBitmapOwner(hData, OBJECT_OWNER_PUBLIC);
break;
case CF_PALETTE:
GreSetPaletteOwner(hData, OBJECT_OWNER_PUBLIC);
break;
}
}
return fRet;
}
/***************************************************************************\
* InternalSetClipboardData
*
* Internal routine to set data into the clipboard.
*
* History:
* 18-Nov-1990 ScottLu Ported from Win3.
\***************************************************************************/
BOOL InternalSetClipboardData(
PWINDOWSTATION pwinsta,
UINT fmt,
HANDLE hData,
BOOL fGlobalHandle,
BOOL fIncSerialNumber)
{
PCLIP pClip;
WCHAR achFormatName[CCHFORMATNAME];
/*
* Just check for pwinsta->ptiClipLock being NULL instead of checking
* against PtiCurrent because an app needs to call SetClipboardData if
* he's rendering data while another app has the clipboard open.
*/
if (pwinsta->ptiClipLock == NULL || fmt == 0) {
RIPERR0(ERROR_CLIPBOARD_NOT_OPEN,
RIP_WARNING,
"SetClipboardData: Clipboard not open");
return FALSE;
}
if ((pClip = FindClipFormat(pwinsta, fmt)) != NULL) {
/*
* If data already exists, free it before we replace it.
*/
UT_FreeCBFormat(pClip);
} else {
if (pwinsta->pClipBase == NULL) {
pClip = (PCLIP)UserAllocPool(sizeof(CLIP), TAG_CLIPBOARD);
} else {
DWORD dwSize = sizeof(CLIP) * pwinsta->cNumClipFormats;
pClip = (PCLIP)UserReAllocPool(pwinsta->pClipBase,
dwSize,
dwSize + sizeof(CLIP),
TAG_CLIPBOARD);
}
/*
* Out of memory ... return.
*/
if (pClip == NULL) {
RIPMSG0(RIP_WARNING, "SetClipboardData: Out of memory");
return FALSE;
}
/*
* Just in case the data moved.
*/
pwinsta->pClipBase = pClip;
/*
* Increment the reference count of this atom format so that if
* the application frees this atom we don't get stuck with a
* bogus atom. We call DeleteAtom in the EmptyClipboard() code,
* which decrements this count when we're done with this clipboard
* data.
*/
if (UserGetAtomName((ATOM)fmt, achFormatName, CCHFORMATNAME) != 0) {
UserAddAtom(achFormatName, FALSE);
}
/*
* Point to the new entry in the clipboard.
*/
pClip += pwinsta->cNumClipFormats++;
pClip->fmt = fmt;
}
/*
* Start updating the new entry in the clipboard.
*/
pClip->hData = hData;
pClip->fGlobalHandle = fGlobalHandle;
if (fIncSerialNumber) {
pwinsta->dwWSF_Flags |= WSF_CLIPBOARDCHANGED;
}
if (fIncSerialNumber && (pwinsta->dwWSF_Flags & WSF_INDELAYEDRENDERING) == 0) {
pwinsta->iClipSequenceNumber++;
}
/*
* If the thread didn't bother emptying the clipboard before writing to
* it, change the clipboard serial number so that the client-side
* clipboard caches of all the processes will get flushed on the next
* OpenClipboard.
*/
if ((pwinsta->spwndClipOwner == NULL) ||
(GETPTI(pwinsta->spwndClipOwner) != PtiCurrent())) {
RIPMSG0(RIP_VERBOSE,
"Clipboard: SetClipboardData called without emptying clipboard");
if (fIncSerialNumber) {
pwinsta->iClipSerialNumber++;
}
}
return TRUE;
}
/***************************************************************************\
* CreateScreenBitmap
*
*
\***************************************************************************/
HBITMAP CreateScreenBitmap(
int cx,
int cy,
UINT bpp)
{
if (bpp == 1) {
return GreCreateBitmap(cx, cy, 1, 1, NULL);
}
return GreCreateCompatibleBitmap(gpDispInfo->hdcScreen, cx, cy);
}
/***************************************************************************\
* SizeOfDibColorTable
*
* Returns the size of the colr table of a packed-dib.
\***************************************************************************/
DWORD SizeOfDibColorTable(
LPBITMAPINFOHEADER lpDib)
{
DWORD dwColor;
/*
* Calculate size of color table.
*/
if (lpDib->biCompression == BI_BITFIELDS) {
if (lpDib->biBitCount == 16 || lpDib->biBitCount == 32) {
dwColor = (3 * sizeof(DWORD));
} else {
dwColor = 0;
}
} else if (lpDib->biCompression == BI_RGB) {
if (lpDib->biClrUsed) {
dwColor = lpDib->biClrUsed * sizeof(DWORD);
} else {
if (lpDib->biBitCount <= 8) {
dwColor = (1 << lpDib->biBitCount) * sizeof(RGBQUAD);
} else {
dwColor = 0;
}
}
} else if (lpDib->biCompression == BI_RLE4) {
dwColor = 16 * sizeof(DWORD);
} else if (lpDib->biCompression == BI_RLE8) {
dwColor = 256 * sizeof(DWORD);
} else {
dwColor = 0;
}
return dwColor;
}
/***************************************************************************\
* SizeOfDib
*
* Returns the size of a packed-dib.
\***************************************************************************/
DWORD SizeOfDib(
LPBITMAPINFOHEADER lpDib)
{
DWORD dwColor;
DWORD dwBits;
/*
* Calculate size of bitmap bits.
*/
dwBits = WIDTHBYTES(lpDib->biWidth * lpDib->biBitCount) * abs(lpDib->biHeight);
/*
* Calculate size of color table.
*/
dwColor = SizeOfDibColorTable(lpDib);
return (lpDib->biSize + dwColor + dwBits);
}
/***************************************************************************\
* DIBtoBMP
*
* Creates a bitmap from a DIB spec.
*
\***************************************************************************/
HBITMAP DIBtoBMP(
LPBITMAPINFOHEADER lpbih,
HPALETTE hpal)
{
HDC hdc;
int cx;
int cy;
int bpp;
LPSTR lpbits;
HBITMAP hbmp;
#define lpbch ((LPBITMAPCOREHEADER)lpbih)
/*
* Gather the dib-info for the convert.
*/
if (lpbih->biSize == sizeof(BITMAPINFOHEADER)) {
cx = (int)lpbih->biWidth;
cy = (int)lpbih->biHeight;
bpp = (int)lpbih->biBitCount;
lpbits = ((PBYTE)lpbih) + sizeof(BITMAPINFOHEADER);
if (lpbih->biClrUsed) {
lpbits += (lpbih->biClrUsed * sizeof(RGBQUAD));
} else if (bpp <= 8) {
lpbits += ((1 << bpp) * sizeof(RGBQUAD));
} else if ((bpp == 16) || (bpp == 32)) {
lpbits += (3 * sizeof(RGBQUAD));
}
} else if (lpbch->bcSize == sizeof(BITMAPCOREHEADER)) {
cx = (int)lpbch->bcWidth;
cy = (int)lpbch->bcHeight;
bpp = (int)lpbch->bcBitCount;
lpbits = ((PBYTE)lpbch) + sizeof(BITMAPCOREHEADER);
if (lpbch->bcBitCount <= 8) {
lpbits += (1 << bpp);
}
} else {
return NULL;
}
hbmp = NULL;
if (hdc = GreCreateCompatibleDC(gpDispInfo->hdcScreen)) {
if (hbmp = CreateScreenBitmap(cx, cy, bpp)) {
HBITMAP hbmT;
HPALETTE hpalT = NULL;
hbmT = GreSelectBitmap(hdc, hbmp);
if (hpal) {
hpalT = _SelectPalette(hdc, hpal, FALSE);
xxxRealizePalette(hdc);
}
GreSetDIBits(hdc,
hbmp,
0,
cy,
lpbits,
(LPBITMAPINFO)lpbih,
DIB_RGB_COLORS);
if (hpalT) {
_SelectPalette(hdc, hpalT, FALSE);
xxxRealizePalette(hdc);
}
GreSelectBitmap(hdc, hbmT);
}
GreDeleteDC(hdc);
}
#undef lpbch
return hbmp;
}
/***************************************************************************\
* BMPtoDIB
*
* Creates a memory block with DIB information from a physical bitmap tagged
* to a specific DC.
*
* A DIB block consists of a BITMAPINFOHEADER + RGB colors + DIB bits.
*
\***************************************************************************/
LPBITMAPINFOHEADER BMPtoDIB(
HBITMAP hbmp,
HPALETTE hpal,
DWORD* pcbSize)
{
BITMAP bmp;
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
DWORD cbBits;
DWORD cbPalette;
DWORD cbTotal;
WORD cBits;
HDC hdc;
UserAssert(hbmp);
/*
* Get physical information
*/
if (!GreExtGetObjectW(hbmp, sizeof(BITMAP), &bmp)) {
UserAssert(FALSE);
return NULL;
}
/*
* Adjust the bit count since we only allow DIBS with 1,4,8,16,24 and
* 32 bits.
*/
cBits = ((WORD)bmp.bmPlanes * (WORD)bmp.bmBitsPixel);
if (cBits <= 1) {
cBits = 1;
} else if (cBits <= 4) {
cBits = 4;
} else if (cBits <= 8) {
cBits = 8;
} else {
/*
* We're not going to recognize 16/32bpp formats for apps that are not
* 4.00 or greater. Paint-Shop has a bug in it where they only
* recognize (1, 4, 8, 24). This really stinks that we need to do this
* type of thing so as not to break them bad-apps.
*/
if (LOWORD(PtiCurrent()->dwExpWinVer) >= VER40) {
if (cBits <= 16) {
cBits = 16;
} else if (cBits <= 24) {
cBits = 24;
} else {
cBits = 32;
}
} else {
cBits = 24;
}
}
/*
* Fill in BITMAPINFOHEADER with DIB data.
*/
RtlZeroMemory(&bi, sizeof(bi));
bi.biSize = sizeof(bi);
bi.biWidth = bmp.bmWidth;
bi.biHeight = bmp.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = cBits;
bi.biCompression = BI_RGB;
/*
* DWORD align the bits-size since dibs must be so.
*/
cbBits = (DWORD)WIDTHBYTES((WORD)bi.biWidth * cBits) * (DWORD)bi.biHeight;
/*
* How big is the palette color table?
*/
cbPalette = 0;
if (cBits <= 8) {
cbPalette = (1 << cBits) * sizeof(RGBQUAD);
} else if ((cBits == 16) || (cBits == 32)) {
cbPalette = (3 * sizeof(DWORD));
bi.biCompression = BI_BITFIELDS;
}
/*
* How much space do we need for the entire DIB?
*/
cbTotal = bi.biSize + cbPalette + cbBits;
lpbi = (LPBITMAPINFOHEADER)UserAllocPool(cbTotal, TAG_CLIPBOARD);
if (lpbi == NULL) {
return NULL;
}
/*
* Have the total allocated size returned in pcbSize.
*/
if (pcbSize != NULL) {
*pcbSize = cbTotal;
}
/*
* Setup DIB header.
*/
memcpy(lpbi, &bi, sizeof(bi));
if (hdc = GreCreateCompatibleDC(gpDispInfo->hdcScreen)) {
HPALETTE hpalT = NULL;
TL tlPool;
ThreadLockPool(PtiCurrent(), lpbi, &tlPool);
if (hpal) {
hpalT = _SelectPalette(hdc, hpal, FALSE);
xxxRealizePalette(hdc);
}
/*
* Get old bitmap's DIB bits, using the current DC.
*/
GreGetDIBitsInternal(hdc,
hbmp,
0,
(WORD)bi.biHeight,
(LPSTR)((LPSTR)lpbi + lpbi->biSize + cbPalette),
(LPBITMAPINFO)lpbi,
DIB_RGB_COLORS,
cbBits,
lpbi->biSize + cbPalette);
if (hpalT) {
_SelectPalette(hdc, hpalT, FALSE);
xxxRealizePalette(hdc);
}
GreDeleteDC(hdc);
ThreadUnlockPool(PtiCurrent(), &tlPool);
}
return lpbi;
}
/***************************************************************************\
* DIBtoDIBV5
*
* History:
* 18-Dec-1997 HideyukN Created.
\***************************************************************************/
LPBITMAPV5HEADER DIBtoDIBV5(
LPBITMAPINFOHEADER lpDib,
DWORD cbSize)
{
LPBITMAPV5HEADER lpV5h;
ULONG cjBits;
ULONG cjColorV5;
if (cbSize < sizeof(BITMAPINFOHEADER)) {
RIPMSG2(RIP_WARNING, "DIBtoDIBV5: buffer %d too small for header %d",
cbSize, sizeof(BITMAPINFOHEADER));
return NULL;
}
/*
* Support only convert from BITMAPINFOHEADER
*/
if (lpDib->biSize != sizeof(BITMAPINFOHEADER)) {
return NULL;
}
/*
* Calculate size of bitmap bits.
*/
cjBits = WIDTHBYTES(lpDib->biWidth * lpDib->biBitCount) * abs(lpDib->biHeight);
/*
* Calculate size of color table.
*/
cjColorV5 = SizeOfDibColorTable(lpDib);
if (cbSize < sizeof(BITMAPINFOHEADER) + cjColorV5 + cjBits) {
RIPMSG5(RIP_WARNING, "DIBtoDIBV5: buffer %d too small for bitmap %d Header"
" %d cjColorV5 %d cjBits %d",
cbSize,
sizeof(BITMAPINFOHEADER) + cjColorV5 + cjBits,
sizeof(BITMAPINFOHEADER),
cjColorV5,
cjBits);
return NULL;
}
/*
* Allocate memory for BITMAPV5HEADER.
*/
lpV5h = (LPBITMAPV5HEADER)UserAllocPool(sizeof(BITMAPV5HEADER) + cjColorV5 + cjBits,
TAG_CLIPBOARD);
if (lpV5h == NULL) {
return NULL;
}
/*
* Fill allocated memory with zero.
*/
RtlZeroMemory((PVOID)lpV5h, sizeof(BITMAPV5HEADER));
try {
/*
* Copy BITMAPINFOHEADER to BITMAPV5HEADER
*/
RtlCopyMemory((PVOID)lpV5h, (PVOID)lpDib, sizeof(BITMAPINFOHEADER));
} except (W32ExceptionHandler(FALSE, RIP_ERROR)) {
UserFreePool(lpV5h);
return NULL;
}
/*
* Adjust the header size to BITMAPV5HEADER.
*/
lpV5h->bV5Size = sizeof(BITMAPV5HEADER);
/*
* Bitmap is in sRGB color space.
*/
lpV5h->bV5CSType = LCS_sRGB;
/*
* Set rendering intent.
*/
lpV5h->bV5Intent = LCS_GM_IMAGES;
if ((lpDib->biCompression == BI_BITFIELDS) &&
(lpDib->biBitCount == 16 || lpDib->biBitCount == 32)) {
/*
* If there is bitfields mask, copy it to BITMAPV5HEADER.
*/
lpV5h->bV5RedMask = *(DWORD *)&(((BITMAPINFO *)lpDib)->bmiColors[0]);
lpV5h->bV5GreenMask = *(DWORD *)&(((BITMAPINFO *)lpDib)->bmiColors[1]);
lpV5h->bV5BlueMask = *(DWORD *)&(((BITMAPINFO *)lpDib)->bmiColors[2]);
}
if (cjColorV5) {
RtlCopyMemory((BYTE *)lpV5h + sizeof(BITMAPV5HEADER),
(BYTE *)lpDib + sizeof(BITMAPINFOHEADER),
cjColorV5);
}
/*
* Copy bitmap bits
*/
RtlCopyMemory((BYTE *)lpV5h + sizeof(BITMAPV5HEADER) + cjColorV5,
(BYTE *)lpDib + sizeof(BITMAPINFOHEADER) + cjColorV5,
cjBits);
return lpV5h;
}
/***************************************************************************\
* BMPtoDIBV5
*
* History:
* 18-Dec-1997 HideyukN Created.
\***************************************************************************/
LPBITMAPV5HEADER BMPtoDIBV5(
HBITMAP hbmp,
HPALETTE hpal)
{
LPBITMAPV5HEADER lpV5h;
LPBITMAPINFOHEADER lpbih;
DWORD cbSize;
/*
* Convert bitmap handle to BITMAPINFOHEADER first.
*/
lpbih = BMPtoDIB(hbmp, hpal, &cbSize);
if (lpbih) {
/*
* Then, convert BITMAPINFOHEADER to BITMAPV5HEADER.
*/
lpV5h = DIBtoDIBV5(lpbih, cbSize);
/*
* Free memory which contains BITMAPINFOHEADER temporary.
*/
UserFreePool(lpbih);
return (lpV5h);
} else {
RIPMSG0(RIP_ERROR, "Failed on BMPtoDIB(), Why ??");
return NULL;
}
}
/***************************************************************************\
* xxxGetDummyBitmap
*
* Returns a real-bitmap from a dummy-format.
*
* History:
* 24-Oct-1995 ChrisWil Created.
\***************************************************************************/
HANDLE xxxGetDummyBitmap(
PWINDOWSTATION pwinsta,
PGETCLIPBDATA pgcd)
{
HANDLE hData = NULL;
PCLIPDATA pData;
HBITMAP hBitmap;
LPBITMAPINFOHEADER lpbih;
ULONG cjBitmap;
HPALETTE hPal = NULL;
PCLIP pClipT;
/*
* If palette display, then first attempt to get the palette for this
* bitmap.
*/
if (TEST_PUSIF(PUSIF_PALETTEDISPLAY)) {
hPal = xxxGetClipboardData(pwinsta, CF_PALETTE, pgcd);
}
/*
* The conversion priority is CF_DIBV5 and then CF_DIB, so, check we
* have CF_DIBV5 first.
*/
pClipT = FindClipFormat(pwinsta, CF_DIBV5);
if (pClipT && (pClipT->hData != DUMMY_DIB_HANDLE)) {
/*
* Ok, we have *real* CF_DIBV5 data. At this moment, just go back
* to client side, then create bitmap handle for CF_BITMAP. Since
* color conversion only can do it on user-mode.
*/
if (hData = xxxGetClipboardData(pwinsta, CF_DIBV5, pgcd)) {
/*
* Return the type of the returned data. Again, conversion will
* happen in client side.
*/
pgcd->uFmtRet = CF_DIBV5;
pgcd->hPalette = hPal;
return hData;
}
}
/*
* If the bitmap is a dummy, then we have a problem. We can't retrieve a
* bitmap if we only have dummys to work with.
*/
pClipT = FindClipFormat(pwinsta, CF_DIB);
if (pClipT && (pClipT->hData != DUMMY_DIB_HANDLE)) {
hData = xxxGetClipboardData(pwinsta, CF_DIB, pgcd);
}
if (hData == NULL) {
return NULL;
}
/*
* Since DIBs (memory-handles) are stored in a special format (size, base,
* data), we need to offet the pointer to the right offset (2 uints).
*/
if (pData = (PCLIPDATA)HMValidateHandleNoRip(hData, TYPE_CLIPDATA)) {
lpbih = (LPBITMAPINFOHEADER)&pData->abData;
cjBitmap = pData->cbData;
} else {
UserAssert(pData != NULL);
return NULL;
}
/*
* Convert the dib to a bitmap.
*
* The buffer size for bitmap should be larger than
* bitmap header + color table + bitmap bits data.
*/
if ((cjBitmap >= sizeof(BITMAPCOREHEADER)) &&
(cjBitmap >= (GreGetBitmapSize((CONST BITMAPINFO *)lpbih,DIB_RGB_COLORS) +
GreGetBitmapBitsSize((CONST BITMAPINFO *)lpbih)))) {
if (hBitmap = DIBtoBMP(lpbih, hPal)) {
/*
* Once, we create *real* bitmap, overwrite dummy handle.
*/
pClipT = FindClipFormat(pwinsta, CF_BITMAP);
if (pClipT) {
UT_FreeCBFormat(pClipT);
pClipT->hData = hBitmap;
GreSetBitmapOwner(hBitmap, OBJECT_OWNER_PUBLIC);
/*
* Let callee know we can obtain CF_BITMAP
*/
pgcd->uFmtRet = CF_BITMAP;
} else {
/*
* Bleh -- now we can't find the BITMAP entry anymore. Bail.
*/
RIPMSG0(RIP_WARNING,
"Clipboard: CF_BITMAP format not available");
GreDeleteObject(hBitmap);
hBitmap = NULL;
}
}
return (HANDLE)hBitmap;
} else {
RIPMSG0(RIP_WARNING, "GetClipboardData, bad DIB format\n");
return NULL;
}
}
/***************************************************************************\
* xxxGetDummyDib
*
* Returns a real-dib (in special clipboard-handle format) from a dummy
* format.
*
* History:
* 24-Oct-1995 ChrisWil Created.
\***************************************************************************/
HANDLE xxxGetDummyDib(
PWINDOWSTATION pwinsta,
PGETCLIPBDATA pgcd)
{
HANDLE hData = NULL;
HBITMAP hBitmap = NULL;
LPBITMAPINFOHEADER lpDib;
HANDLE hDib;
HPALETTE hPal = NULL;
PCLIP pClipT;
/*
* If palette display, then first attempt to get the palette for this
* bitmap. For palette devices, we must have a palette.
*/
if (TEST_PUSIF(PUSIF_PALETTEDISPLAY)) {
hPal = xxxGetClipboardData(pwinsta, CF_PALETTE, pgcd);
if (hPal == NULL) {
return NULL;
}
}
/*
* The convertion priority is CF_DIBV5 and then CF_BITMAP, so, check if
* we have CF_DIBV5 first.
*/
pClipT = FindClipFormat(pwinsta, CF_DIBV5);
if (pClipT && (pClipT->hData != DUMMY_DIB_HANDLE)) {
/*
* Ok, we have *real* CF_DIBV5 data. At this moment, just go back to
* client side, then create bitmap data for CF_DIB. Since color
* conversion can only be done in user-mode.
*/
if (hData = xxxGetClipboardData(pwinsta, CF_DIBV5, pgcd)) {
/*
* Return the type of the returned data. Again, conversion will
* happen in client side.
*/
pgcd->uFmtRet = CF_DIBV5;
pgcd->hPalette = hPal;
return hData;
}
}
/*
* Get the real-bitmap. We must have one in order to convert to the DIB.
* If there's no bitmap, then something's wrong.
*/
pClipT = FindClipFormat(pwinsta, CF_BITMAP);
if (pClipT && (pClipT->hData != DUMMY_DIB_HANDLE)) {
hBitmap = xxxGetClipboardData(pwinsta, CF_BITMAP, pgcd);
}
if (hBitmap == NULL) {
return NULL;
}
/*
* Convert the bitmap to a dib-spec.
*/
hDib = NULL;
if (lpDib = BMPtoDIB(hBitmap, hPal, NULL)) {
DWORD cbData = SizeOfDib(lpDib);;
/*
* Convert the dib-spec to the special-clipboard memory-handle (size,
* base, data). This so the client is able to convert properly when
* handled a dib.
*/
hDib = _ConvertMemHandle((LPBYTE)lpDib, cbData);
UserFreePool(lpDib);
if (hDib != NULL) {
/*
* Once, we create *real* bitmap, overwrite dummy handle.
*/
pClipT = FindClipFormat(pwinsta, CF_DIB);
if (pClipT) {
UT_FreeCBFormat(pClipT);
pClipT->hData = hDib;
/*
* Let callee know we can obtain CF_DIB.
*/
pgcd->uFmtRet = CF_DIB;
} else {
PVOID pObj;
/*
* Bleh -- now we can't find the DIB entry anymore. Bail.
*/
RIPMSG0(RIP_WARNING,
"Clipboard: CF_PDIB format not available");
pObj = HMValidateHandleNoRip(hDib, TYPE_CLIPDATA);
if (pObj) {
HMFreeObject(pObj);
}
hDib = NULL;
}
}
}
return hDib;
}
/***************************************************************************\
* xxxGetDummyDibV5
*
* Returns a real DIB (in special clipboard-handle format) from a dummy
* format.
*
* History:
* 18-Dec-1997 HideyukN Created.
\***************************************************************************/
HANDLE xxxGetDummyDibV5(
PWINDOWSTATION pwinsta,
PGETCLIPBDATA pgcd)
{
HANDLE hData;
PCLIPDATA pData;
LPBITMAPV5HEADER lpDibV5 = NULL;
HANDLE hDibV5 = NULL;
PCLIP pClipT;
/*
* The conversion priority is CF_DIB and then CF_BITMAP, so check if we
* have CF_DIB first.
*/
pClipT = FindClipFormat(pwinsta, CF_DIB);
if (pClipT && (pClipT->hData != DUMMY_DIB_HANDLE)) {
/*
* Ok, we have *real* CF_DIB data, get it.
*/
if (hData = xxxGetClipboardData(pwinsta, CF_DIB, pgcd)) {
/*
* Since DIBs (memory-handles) are stored in a special format
* (size, base, data), we need to offet the pointer to the right
* offset (2 uints).
*/
if (pData = (PCLIPDATA)HMValidateHandleNoRip(hData, TYPE_CLIPDATA)) {
LPBITMAPINFOHEADER lpDib = (LPBITMAPINFOHEADER)&pData->abData;
/*
* Convert the BITMAPINFOHEADER to BITMAPV5HEADER.
*/
lpDibV5 = DIBtoDIBV5(lpDib, pData->cbData);
} else {
UserAssert(pData != NULL);
}
}
}
if (lpDibV5 == NULL) {
/*
* Try CF_BITMAP, here.
*/
pClipT = FindClipFormat(pwinsta, CF_BITMAP);
if ((pClipT) &&
(pClipT->hData != DUMMY_DIB_HANDLE) &&
(hData = xxxGetClipboardData(pwinsta, CF_BITMAP, pgcd))) {
HPALETTE hPal = NULL;
/*
* If palette display, then first attempt to get the palette
* for this bitmap. For palette devices, we must have a palette.
*/
if (TEST_PUSIF(PUSIF_PALETTEDISPLAY)) {
hPal = xxxGetClipboardData(pwinsta, CF_PALETTE, pgcd);
if (hPal == NULL) {
return NULL;
}
}
/*
* hData is GDI bitmap handle; convert the bitmap to a dib-spec.
*/
lpDibV5 = BMPtoDIBV5((HBITMAP)hData, hPal);
}
}
if (lpDibV5 != NULL) {
DWORD cbData = SizeOfDib((LPBITMAPINFOHEADER)lpDibV5);
/*
* Convert the dib-spec to the special-clipboard memory-handle (size,
* base, data). This so the client is able to convert properly when
* handled a dib.
*/
hDibV5 = _ConvertMemHandle((LPBYTE)lpDibV5, cbData);
UserFreePool(lpDibV5);
if (hDibV5 != NULL) {
/*
* Once, we create *real* bitmap, overwrite dummy handle.
*/
pClipT = FindClipFormat(pwinsta, CF_DIBV5);
if (pClipT) {
UT_FreeCBFormat(pClipT);
pClipT->hData = hDibV5;
/*
* Let callee know we can obtain CF_DIBV5.
*/
pgcd->uFmtRet = CF_DIBV5;
} else {
PVOID pObj;
/*
* Bleh -- now we can't find the DIB entry anymore. Bail.
*/
RIPMSG0(RIP_WARNING,
"Clipboard: CF_DIBV5 format not available");
pObj = HMValidateHandleNoRip(hDibV5, TYPE_CLIPDATA);
if (pObj) {
HMFreeObject(pObj);
}
hDibV5 = NULL;
}
}
}
return hDibV5;
}
/***************************************************************************\
* CreateDIBPalette
*
* This creates a palette with PC_NOCOLLAPSE entries since we require the
* palette-entries and bitmap-indexes to map exactly. Otherwise, we could
* end up selecting a palette where a color collapses to an index not
* where the bitmap thinks it is. This would cause slower drawing since
* the Blt would go through color translation.
*
* History:
* 31-Jan-1992 MikeKe From win31
\***************************************************************************/
HPALETTE CreateDIBPalette(
LPBITMAPINFOHEADER pbmih,
UINT colors)
{
HPALETTE hpal;
if (colors != 0) {
int i;
BOOL fOldDIB = (pbmih->biSize == sizeof(BITMAPCOREHEADER));
RGBTRIPLE *pColorTable;
PLOGPALETTE plp;
/*
* Allocate memory for palette creation.
*/
plp = (PLOGPALETTE)UserAllocPoolWithQuota(sizeof(LOGPALETTE) +
(sizeof(PALETTEENTRY) * 256),
TAG_CLIPBOARDPALETTE);
if (plp == NULL) {
return NULL;
}
pColorTable = (RGBTRIPLE *)((LPSTR)pbmih + (WORD)pbmih->biSize);
plp->palVersion = 0x300;
if (fOldDIB || (pbmih->biClrUsed == 0)) {
UserAssert(colors <= 0xFFFF);
plp->palNumEntries = (WORD)colors;
} else {
UserAssert(pbmih->biClrUsed <= 0xFFFF);
plp->palNumEntries = (WORD)pbmih->biClrUsed;
}
for (i = 0; i < (int)(plp->palNumEntries); i++) {
plp->palPalEntry[i].peRed = pColorTable->rgbtRed;
plp->palPalEntry[i].peGreen = pColorTable->rgbtGreen;
plp->palPalEntry[i].peBlue = pColorTable->rgbtBlue;
plp->palPalEntry[i].peFlags = (BYTE)PC_NOCOLLAPSE;
if (fOldDIB) {
pColorTable++;
} else {
pColorTable = (RGBTRIPLE *)((LPSTR)pColorTable+sizeof(RGBQUAD));
}
}
hpal = GreCreatePalette((LPLOGPALETTE)plp);
UserFreePool(plp);
} else {
hpal = GreCreateHalftonePalette(HDCBITS());
}
GreSetPaletteOwner(hpal, OBJECT_OWNER_PUBLIC);
return hpal;
}
/***************************************************************************\
* xxxGetDummyPalette
*
* Returns a real-palette from a dummy-format. Derives it from a real DIB.
*
* History:
* 24-Oct-1995 ChrisWil Created.
\***************************************************************************/
HANDLE xxxGetDummyPalette(
PWINDOWSTATION pwinsta,
PGETCLIPBDATA pgcd)
{
HANDLE hData;
PCLIPDATA pData;
LPBITMAPINFOHEADER lpbih;
HPALETTE hPal;
PCLIP pClipT;
/*
* Since CF_DIBV5 has higher priority than CF_DIB, look into CF_DIBV5
* first to find DIB palette.
*/
UINT uFmt = CF_DIBV5;
if ((pClipT = FindClipFormat(pwinsta, uFmt)) != NULL) {
if (pClipT->hData != DUMMY_DIB_HANDLE) {
/*
* Ok, we have real CF_DIBV5, let extract palette from DIBV5.
*/
} else {
/*
* Otherwise, try CF_DIB.
*/
uFmt = CF_DIB;
/*
* If no DIB available or it's a dummy handle, bail since we
* must have a real DIB to derive the palette.
*/
if ((pClipT = FindClipFormat(pwinsta, uFmt)) == NULL) {
return NULL;
}
if (pClipT->hData == DUMMY_DIB_HANDLE) {
return NULL;
}
}
}
/*
* Get the DIB by which we derive the palette. If the DIB comes back as a
* dummy, then there's something wrong. We must have a real dib at this
* point.
*/
hData = (HANDLE)xxxGetClipboardData(pwinsta, uFmt, pgcd);
UserAssert(hData > DUMMY_MAX_HANDLE);
if (hData == NULL) {
return NULL;
}
/*
* Since DIBs (memory-handles) are stored in a special format (size, base,
* data), we need to offet the pointer to the right offset (2 uints).
*/
if (pData = (PCLIPDATA)HMValidateHandle(hData, TYPE_CLIPDATA)) {
lpbih = (LPBITMAPINFOHEADER)&pData->abData;
} else {
UserAssert(pData != NULL);
return NULL;
}
if ((pClipT = FindClipFormat(pwinsta, CF_PALETTE)) == NULL) {
RIPMSG0(RIP_WARNING,
"Clipboard: CF_PALETTE format not available");
return NULL;
}
/*
* Note -- if CreateDIBPalette ever changes to leave the crit sect,
* we will need to move the above FindClipFormat to after the create
* call and deal with gracefully freeing hPal on failure. pClipT
* can change during callbacks.
*/
hPal = CreateDIBPalette(lpbih, lpbih->biClrUsed);
if (hPal != NULL) {
UT_FreeCBFormat(pClipT);
pClipT->hData = hPal;
GreSetPaletteOwner(hPal, OBJECT_OWNER_PUBLIC);
}
return (HANDLE)hPal;
}
/***************************************************************************\
* xxxGetDummyText
*
* Returns a handle to text from a dummy-format.
*
* History:
* 24-Oct-1995 ChrisWil Created.
\***************************************************************************/
HANDLE xxxGetDummyText(
PWINDOWSTATION pwinsta,
UINT fmt,
PGETCLIPBDATA pgcd)
{
HANDLE hText;
PCLIP pClipT;
UINT uFmtMain;
UINT uFmtAlt;
BOOL bMain = TRUE;
/*
* Get the handle of the other text format available.
*/
switch (fmt) {
case CF_TEXT:
uFmtMain = CF_UNICODETEXT;
uFmtAlt = CF_OEMTEXT;
goto GetRealText;
case CF_OEMTEXT:
uFmtMain = CF_UNICODETEXT;
uFmtAlt = CF_TEXT;
goto GetRealText;
case CF_UNICODETEXT:
uFmtMain = CF_TEXT;
uFmtAlt = CF_OEMTEXT;
GetRealText:
if ((pClipT = FindClipFormat(pwinsta, uFmtMain)) == NULL) {
return NULL;
}
if (pClipT->hData != DUMMY_TEXT_HANDLE) {
if (xxxGetClipboardData(pwinsta, uFmtMain, pgcd)) {
break;
}
return NULL;
}
if ((pClipT = FindClipFormat(pwinsta, uFmtAlt)) == NULL) {
return NULL;
}
if (pClipT->hData != DUMMY_TEXT_HANDLE) {
bMain = FALSE;
if (xxxGetClipboardData(pwinsta, uFmtAlt, pgcd)) {
break;
}
}
/*
* Fall through to return a dummy handle.
*/
default:
return NULL;
}
/*
* Since xxxGetClipboardData leaves the critsect, we need to reacquire
* pClipT.
*/
pClipT = FindClipFormat(pwinsta, bMain ? uFmtMain : uFmtAlt);
if (pClipT == NULL) {
RIPMSG1(RIP_WARNING,
"Clipboard: GetDummyText, format 0x%x not available",
bMain ? uFmtMain : uFmtAlt);
return NULL;
}
/*
* Return the type of the returned data.
*/
pgcd->uFmtRet = pClipT->fmt;
hText = pClipT->hData;
/*
* Set the locale, since the text will need to be converted to another
* format.
*/
if (pClipT = FindClipFormat(pwinsta, CF_LOCALE)) {
pgcd->hLocale = pClipT->hData;
} else {
pgcd->hLocale = NULL;
}
return hText;
}
/***************************************************************************\
* xxxGetRenderData
*
* Returns a handle to delayed rendered data. This requires a call to the
* client to supply the data. This causes us to regenerate our pointer to
* pClip.
*
* History:
* 24-Oct-1995 ChrisWil Created.
\***************************************************************************/
HANDLE xxxGetRenderData(
PWINDOWSTATION pwinsta,
UINT fmt)
{
BOOL fClipboardChangedOld;
TL tlpwndClipOwner;
PCLIP pClip;
DWORD_PTR lpdwResult;
/*
* If the handle is NULL, the data is delay rendered. This means we send
* a message to the current clipboard owner and have it render the data
* for us.
*/
if (pwinsta->spwndClipOwner != NULL) {
BOOL fSucceeded;
/*
* Preserve the WSF_CLIPBOARDCHANGED flag before SendMessage and
* restore the flag later. Thus we ignore the changes done to the
* WSF_CLIPBOARDCHANGED flag by apps while rendering data in the
* delayed rendering scheme. This avoids clipboard viewers from
* painting twice.
*/
fClipboardChangedOld = (pwinsta->dwWSF_Flags & WSF_CLIPBOARDCHANGED) != 0;
SET_FLAG(pwinsta->dwWSF_Flags, WSF_INDELAYEDRENDERING);
ThreadLockAlways(pwinsta->spwndClipOwner, &tlpwndClipOwner);
if (!xxxSendMessageTimeout(pwinsta->spwndClipOwner,
WM_RENDERFORMAT,
fmt,
0L,
SMTO_ABORTIFHUNG,
CB_DELAYRENDER_TIMEOUT,
&lpdwResult)) {
fSucceeded = FALSE;
} else {
fSucceeded = TRUE;
}
ThreadUnlock(&tlpwndClipOwner);
SET_OR_CLEAR_FLAG(pwinsta->dwWSF_Flags, WSF_CLIPBOARDCHANGED, fClipboardChangedOld);
CLEAR_FLAG(pwinsta->dwWSF_Flags, WSF_INDELAYEDRENDERING);
if (!fSucceeded) {
return NULL;
}
}
if ((pClip = FindClipFormat(pwinsta, fmt)) == NULL) {
RIPMSGF1(RIP_WARNING,
"Meta Render/Clone format 0x%x not available", fmt);
return NULL;
}
/*
* We should have the handle now since it has been rendered.
*/
return pClip->hData;
}
/***************************************************************************\
* xxxGetClipboardData (API)
*
* Grabs a particular data object out of the clipboard.
*
* History:
* 18-Nov-1990 ScottLu Ported from Win3.
* 20-Aug-1991 EichiM UNICODE enabling
\***************************************************************************/
HANDLE xxxGetClipboardData(
PWINDOWSTATION pwinsta,
UINT fmt,
PGETCLIPBDATA pgcd)
{
PCLIP pClip;
HANDLE hData;
/*
* Check the clipboard owner.
*/
if (pwinsta->ptiClipLock != PtiCurrent()) {
RIPERR0(ERROR_CLIPBOARD_NOT_OPEN, RIP_VERBOSE, "GetClipboardData: clipboard not open");
return NULL;
}
/*
* Make sure the format is available.
*/
if ((pClip = FindClipFormat(pwinsta, fmt)) == NULL) {
RIPMSG1(RIP_VERBOSE, "Clipboard: Requested format 0x%lX not available", fmt);
return NULL;
}
/*
* If this is a DUMMY_META*_HANDLE it means that the other metafile
* format was set in as a delay render format and we should ask for that
* format to get the metafile because the app has not told us they know
* about this format.
*/
if (IsMetaDummyHandle(pClip->hData)) {
if (fmt == CF_ENHMETAFILE) {
fmt = CF_METAFILEPICT;
} else if (fmt == CF_METAFILEPICT) {
fmt = CF_ENHMETAFILE;
} else {
RIPMSG0(RIP_WARNING,
"Clipboard: Meta Render/Clone expects a metafile type");
}
if ((pClip = FindClipFormat(pwinsta, fmt)) == NULL) {
RIPMSG1(RIP_WARNING,
"Clipboard: Meta Render/Clone format 0x%x not available", fmt);
return NULL;
}
}
/*
* This is the data we're returning, unless it's a dummy or render handle.
*/
hData = pClip->hData;
/*
* We are dealing with non-handles. Retrieve the real data through these
* inline-routines. NOTE: These make recursive calls to
* xxxGetClipboardData(), so care must be taken to assure the pClip is
* pointing to what we think it's pointing to.
*/
if (hData == NULL || hData == DUMMY_METARENDER_HANDLE) {
hData = xxxGetRenderData(pwinsta, fmt);
} else if (hData == DUMMY_DIB_HANDLE) {
switch (fmt) {
case CF_DIB:
hData = xxxGetDummyDib(pwinsta, pgcd);
break;
case CF_DIBV5:
hData = xxxGetDummyDibV5(pwinsta, pgcd);
break;
case CF_BITMAP:
hData = xxxGetDummyBitmap(pwinsta, pgcd);
break;
case CF_PALETTE:
hData = xxxGetDummyPalette(pwinsta, pgcd);
break;
}
} else if (hData == DUMMY_TEXT_HANDLE) {
hData = xxxGetDummyText(pwinsta, fmt, pgcd);
} else {
/*
* This path took no callbacks, so we know pClip is OK.
*/
if (pgcd) {
pgcd->fGlobalHandle = pClip->fGlobalHandle;
}
return hData;
}
/*
* The callbacks for dummy handle resolution have possibly invalidated
* pClip -- recreate it.
*/
if ((pClip = FindClipFormat(pwinsta, fmt)) == NULL) {
RIPMSG1(RIP_VERBOSE, "Clipboard: Requested format 0x%x not available", fmt);
return NULL;
}
/*
* Return if this is a global-handle.
*/
if (pgcd) {
pgcd->fGlobalHandle = pClip->fGlobalHandle;
}
return hData;
}
/***************************************************************************\
* FindClipFormat
*
* Finds a particular clipboard format in the clipboard, returns a pointer
* to it, or NULL. If a pointer is found, on return the clipboard is locked
* and pwinsta->pClipBase has been updated to point to the beginning of the
* clipboard.
*
* History:
* 18-Nov-1990 ScottLu Ported from Win3.
\***************************************************************************/
PCLIP FindClipFormat(
PWINDOWSTATION pwinsta,
UINT format)
{
PCLIP pClip;
int iFmt;
if (format != 0 && ((pClip = pwinsta->pClipBase) != NULL)) {
for (iFmt = pwinsta->cNumClipFormats; iFmt-- != 0;) {
if (pClip->fmt == format) {
return pClip;
}
pClip++;
}
}
return NULL;
}
/***************************************************************************\
* _GetPriorityClipboardFormat (API)
*
* This api allows an application to look for any one of a range of
* clipboard formats in a predefined search order.
*
* History:
* 18-Nov-1990 ScottLu Ported from Win3.
* 11-Feb-1991 JimA Added access checks.
\***************************************************************************/
int _GetPriorityClipboardFormat(
PUINT lpPriorityList,
int cfmts)
{
PWINDOWSTATION pwinsta;
PCLIP pClip;
int iFmt;
UINT fmt;
/*
* Blow it off if the caller does not have the proper access rights.
*/
if ((pwinsta = CheckClipboardAccess()) == NULL) {
return 0;
}
/*
* If there is no clipboard or no objects in the clipboard, return 0.
*/
if (pwinsta->cNumClipFormats == 0 || pwinsta->pClipBase == NULL) {
return 0;
}
/*
* Look through the list for any of the formats in lpPriorityList.
*/
while (cfmts-- > 0) {
fmt = *lpPriorityList;
if (fmt != 0) {
pClip = pwinsta->pClipBase;
for (iFmt = pwinsta->cNumClipFormats; iFmt-- != 0; pClip++) {
if (pClip->fmt == fmt) {
return fmt;
}
}
}
lpPriorityList++;
}
/*
* There is no matching format, so return -1.
*/
return -1;
}
/***************************************************************************\
* xxxSetClipboardViewer (API)
*
* Sets the clipboard viewer window.
*
* History:
* 18-Nov-1990 ScottLu Ported from Win3.
* 11-Feb-1991 JimA Added access checks.
\***************************************************************************/
PWND xxxSetClipboardViewer(
PWND pwndClipViewerNew)
{
TL tlpwinsta;
PWINDOWSTATION pwinsta;
HWND hwndClipViewerOld;
PTHREADINFO ptiCurrent;
CheckLock(pwndClipViewerNew);
/*
* Do not let a destroyed window be locked into the winsta. See
* _OpenClipboard for more details.
*/
if (pwndClipViewerNew != NULL && TestWF(pwndClipViewerNew, WFDESTROYED)) {
RIPERR1(ERROR_INVALID_PARAMETER,
RIP_WARNING,
"Destroyed pwnd 0x%p trying to become clipboard viewer",
pwndClipViewerNew);
return NULL;
}
/*
* Blow it off if the caller does not have the proper access rights. The
* NULL return really doesn't indicate an error but the supposed viewer
* will never receive any clipboard messages, so it shouldn't cause any
* problems.
*/
if ((pwinsta = CheckClipboardAccess()) == NULL) {
return NULL;
}
ptiCurrent = PtiCurrent();
ThreadLockWinSta(ptiCurrent, pwinsta, &tlpwinsta);
hwndClipViewerOld = HW(pwinsta->spwndClipViewer);
Lock(&pwinsta->spwndClipViewer, pwndClipViewerNew);
xxxDrawClipboard(pwinsta);
ThreadUnlockWinSta(ptiCurrent, &tlpwinsta);
if (hwndClipViewerOld != NULL) {
return RevalidateHwnd(hwndClipViewerOld);
}
return NULL;
}
/***************************************************************************\
* xxxChangeClipboardChain (API)
*
* Changes the clipboard viewer chain.
*
* History:
* 18-Nov-1990 ScottLu Ported from Win3.
* 11-Feb-1991 JimA Added access checks.
\***************************************************************************/
BOOL xxxChangeClipboardChain(
PWND pwndRemove,
PWND pwndNewNext)
{
TL tlpwinsta;
PWINDOWSTATION pwinsta;
BOOL result;
TL tlpwndClipViewer;
PTHREADINFO ptiCurrent;
CheckLock(pwndRemove);
CheckLock(pwndNewNext);
/*
* Blow it off if the caller does not have the proper access rights.
*/
if ((pwinsta = CheckClipboardAccess()) == NULL) {
return FALSE;
}
/*
* pwndRemove should be this thread's window, pwndNewNext will either be
* NULL or another thread's window.
*/
ptiCurrent = PtiCurrent();
if (GETPTI(pwndRemove) != ptiCurrent) {
RIPMSG0(RIP_WARNING,
"Clipboard: ChangeClipboardChain will not remove cross threads");
return FALSE;
}
if (pwinsta->spwndClipViewer == NULL) {
RIPMSG0(RIP_WARNING, "Clipboard: ChangeClipboardChain has no viewer window");
return FALSE;
}
ThreadLockWinSta(ptiCurrent, pwinsta, &tlpwinsta);
if (pwndRemove == pwinsta->spwndClipViewer) {
Lock(&pwinsta->spwndClipViewer, pwndNewNext);
result = TRUE;
} else {
ThreadLockAlways(pwinsta->spwndClipViewer, &tlpwndClipViewer);
result = (BOOL)xxxSendMessage(pwinsta->spwndClipViewer,
WM_CHANGECBCHAIN,
(WPARAM)HW(pwndRemove),
(LPARAM)HW(pwndNewNext));
ThreadUnlock(&tlpwndClipViewer);
}
ThreadUnlockWinSta(ptiCurrent, &tlpwinsta);
return result;
}
/***************************************************************************\
* xxxDisownClipboard
*
* Disowns the clipboard so someone else can grab it.
*
* pwndClipOwner is the pwnd that is the reason for disowning the clipboard
* when that window is deleted.
*
* History:
* 18-Jun-1991 DarrinM Ported from Win3.
\***************************************************************************/
VOID xxxDisownClipboard(
PWND pwndClipOwner)
{
TL tlpwinsta;
PWINDOWSTATION pwinsta;
int iFmt;
int cFmts;
PCLIP pClip;
PCLIP pClipOut;
BOOL fKeepDummyHandle;
PTHREADINFO ptiCurrent;
if ((pwinsta = CheckClipboardAccess()) == NULL) {
return;
}
ptiCurrent = PtiCurrent();
ThreadLockWinSta(ptiCurrent, pwinsta, &tlpwinsta);
xxxSendClipboardMessage(pwinsta, WM_RENDERALLFORMATS);
pClipOut = pClip = pwinsta->pClipBase;
fKeepDummyHandle = FALSE;
for (cFmts = 0, iFmt = pwinsta->cNumClipFormats; iFmt-- != 0;) {
/*
* We have to remove the Dummy handles also if the corresponding
* valid handles are NULL; We should not remove the dummy handles if
* the corresponding valid handles are not NULL. The following code
* assumes that only one dummy handle is possible and that can appear
* only after the corresponding valid handle in the pClip linked list.
*/
if (pClip->hData != NULL) {
if ((pClip->hData != DUMMY_TEXT_HANDLE) ||
((pClip->hData == DUMMY_TEXT_HANDLE) && fKeepDummyHandle)) {
cFmts++;
*pClipOut++ = *pClip;
if (IsTextHandle(pClip->fmt, pClip->hData)) {
fKeepDummyHandle = TRUE;
}
}
}
pClip++;
}
/*
* Unlock the clipboard owner if the owner is still the window we were
* cleaning up for.
*/
if (pwndClipOwner == pwinsta->spwndClipOwner) {
Unlock(&pwinsta->spwndClipOwner);
} else {
RIPMSGF2(RIP_WARNING,
"pwndClipOwner changed from 0x%p to 0x%p",
pwndClipOwner,
pwinsta->spwndClipOwner);
}
/*
* If number of formats changed, redraw.
*/
if (cFmts != pwinsta->cNumClipFormats) {
pwinsta->dwWSF_Flags |= WSF_CLIPBOARDCHANGED;
pwinsta->iClipSequenceNumber++;
}
pwinsta->cNumClipFormats = cFmts;
/*
* If anything changed, redraw, and make sure the data type munging is
* done. Else we will lose them when xxxDrawClipboard clears the
* WSF_CLIPBOARDCHANGED flag.
*/
if (pwinsta->dwWSF_Flags & WSF_CLIPBOARDCHANGED) {
xxxDrawClipboard(pwinsta);
MungeClipData(pwinsta);
}
ThreadUnlockWinSta(ptiCurrent, &tlpwinsta);
}
/***************************************************************************\
* ForceEmptyClipboard
*
* We're logging off. Force the clipboard contents to go away.
*
* 23-Jul-1992 ScottLu Created.
\***************************************************************************/
VOID ForceEmptyClipboard(
PWINDOWSTATION pwinsta)
{
/*
* This will be NULL for a non-GUI thread.
*/
pwinsta->ptiClipLock = ((PTHREADINFO)(W32GetCurrentThread()));
Unlock(&pwinsta->spwndClipOwner);
Unlock(&pwinsta->spwndClipViewer);
Unlock(&pwinsta->spwndClipOpen);
xxxEmptyClipboard(pwinsta);
/*
* If the windowstation is dying, don't bother closing the clipboard.
*/
if (!(pwinsta->dwWSF_Flags & WSF_DYING)) {
xxxCloseClipboard(pwinsta);
}
}