mirror of
https://github.com/reactos/reactos.git
synced 2024-11-09 08:08:38 +00:00
2d0dd58947
svn path=/branches/reactos-yarotows/; revision=47795
1217 lines
29 KiB
C
1217 lines
29 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* PURPOSE: Clipboard routines
|
|
* FILE: subsys/win32k/ntuser/clipboard.c
|
|
* PROGRAMER: Filip Navara <xnavara@volny.cz>
|
|
* Pablo Borobia <pborobia@gmail.com>
|
|
*/
|
|
|
|
#include <win32k.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
#define DATA_DELAYED_RENDER 0
|
|
#define DATA_SYNTHESIZED_RENDER -1
|
|
|
|
PTHREADINFO ClipboardThread;
|
|
PTHREADINFO ClipboardOwnerThread;
|
|
PWINDOW_OBJECT ClipboardWindow;
|
|
PWINDOW_OBJECT ClipboardViewerWindow;
|
|
PWINDOW_OBJECT 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(PWINDOW_OBJECT window)
|
|
{
|
|
PCLIPBOARDCHAINELEMENT wce = WindowsChain;
|
|
|
|
while (wce)
|
|
{
|
|
if (wce->window == window)
|
|
{
|
|
break;
|
|
}
|
|
wce = wce->next;
|
|
}
|
|
|
|
return wce;
|
|
}
|
|
|
|
VOID FASTCALL printChain(VOID)
|
|
{
|
|
/*test*/
|
|
PCLIPBOARDCHAINELEMENT wce2 = WindowsChain;
|
|
while (wce2)
|
|
{
|
|
DPRINT1("chain: %p\n", wce2->window->hSelf);
|
|
wce2 = wce2->next;
|
|
}
|
|
}
|
|
|
|
/* the new window always have to be the first in the chain */
|
|
PCLIPBOARDCHAINELEMENT FASTCALL
|
|
IntAddWindowToChain(PWINDOW_OBJECT window)
|
|
{
|
|
PCLIPBOARDCHAINELEMENT wce = NULL;
|
|
|
|
if (!IntIsWindowInChain(window))
|
|
{
|
|
wce = WindowsChain;
|
|
|
|
wce = ExAllocatePoolWithTag(PagedPool, sizeof(CLIPBOARDCHAINELEMENT), USERTAG_CLIPBOARD);
|
|
if (wce == NULL)
|
|
{
|
|
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto exit_addChain;
|
|
}
|
|
|
|
wce->window = window;
|
|
wce->next = WindowsChain;
|
|
|
|
WindowsChain = wce;
|
|
|
|
//printChain();
|
|
}
|
|
exit_addChain:
|
|
|
|
/* return the next window to beremoved later */
|
|
return wce;
|
|
}
|
|
|
|
PCLIPBOARDCHAINELEMENT FASTCALL
|
|
IntRemoveWindowFromChain(PWINDOW_OBJECT window)
|
|
{
|
|
PCLIPBOARDCHAINELEMENT wce = WindowsChain;
|
|
PCLIPBOARDCHAINELEMENT *link = &WindowsChain;
|
|
|
|
if (IntIsWindowInChain(window))
|
|
{
|
|
while (wce != NULL)
|
|
{
|
|
if (wce->window == window)
|
|
{
|
|
*link = wce->next;
|
|
break;
|
|
}
|
|
|
|
link = &wce->next;
|
|
wce = wce->next;
|
|
}
|
|
|
|
//printChain();
|
|
|
|
return wce;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*==============================================================*/
|
|
/* if format exists, returns a non zero value (pointing to format object) */
|
|
PCLIPBOARDELEMENT FASTCALL
|
|
intIsFormatAvailable(UINT format)
|
|
{
|
|
PCLIPBOARDELEMENT ret = NULL;
|
|
PCLIPBOARDELEMENT ce = ClipboardData;
|
|
|
|
while(ce)
|
|
{
|
|
if (ce->format == format)
|
|
{
|
|
ret = ce;
|
|
break;
|
|
}
|
|
ce = ce->next;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* counts how many distinct format were are in the clipboard */
|
|
DWORD FASTCALL
|
|
IntCountClipboardFormats(VOID)
|
|
{
|
|
DWORD ret = 0;
|
|
PCLIPBOARDELEMENT ce = ClipboardData;
|
|
|
|
while(ce)
|
|
{
|
|
ret++;
|
|
ce = ce->next;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* adds a new format and data to the clipboard */
|
|
PCLIPBOARDELEMENT FASTCALL
|
|
intAddFormatedData(UINT format, HANDLE hData, DWORD size)
|
|
{
|
|
PCLIPBOARDELEMENT ce = NULL;
|
|
|
|
ce = ExAllocatePoolWithTag(PagedPool, sizeof(CLIPBOARDELEMENT), USERTAG_CLIPBOARD);
|
|
if (ce == NULL)
|
|
{
|
|
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else
|
|
{
|
|
ce->format = format;
|
|
ce->size = size;
|
|
ce->hData = hData;
|
|
ce->next = ClipboardData;
|
|
|
|
ClipboardData = ce;
|
|
|
|
IntIncrementSequenceNumber();
|
|
}
|
|
|
|
return ce;
|
|
}
|
|
|
|
/* removes a format and its data from the clipboard */
|
|
BOOL FASTCALL
|
|
intRemoveFormatedData(UINT format)
|
|
{
|
|
BOOL ret = FALSE;
|
|
PCLIPBOARDELEMENT ce = ClipboardData;
|
|
PCLIPBOARDELEMENT *link = &ClipboardData;
|
|
|
|
if (intIsFormatAvailable(format))
|
|
{
|
|
while (ce != NULL)
|
|
{
|
|
if (ce->format == format)
|
|
{
|
|
*link = ce->next;
|
|
break;
|
|
}
|
|
|
|
link = &ce->next;
|
|
ce = ce->next;
|
|
}
|
|
|
|
if (ce->hData)
|
|
{
|
|
ExFreePool(ce->hData);
|
|
}
|
|
ExFreePool(ce);
|
|
ret = TRUE;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
VOID FASTCALL
|
|
IntEmptyClipboardData(VOID)
|
|
{
|
|
PCLIPBOARDELEMENT ce = ClipboardData;
|
|
PCLIPBOARDELEMENT tmp;
|
|
|
|
while(ce)
|
|
{
|
|
tmp = ce->next;
|
|
if (ce->hData)
|
|
{
|
|
ExFreePool(ce->hData);
|
|
}
|
|
ExFreePool(ce);
|
|
ce = tmp;
|
|
}
|
|
|
|
ClipboardData = NULL;
|
|
}
|
|
|
|
/*==============================================================*/
|
|
|
|
HANDLE FASTCALL
|
|
renderBITMAPfromDIB(LPBYTE pDIB)
|
|
{
|
|
HDC hdc;
|
|
HBITMAP hbitmap;
|
|
unsigned int offset;
|
|
BITMAPV5INFO bmi;
|
|
NTSTATUS Status ;
|
|
|
|
//hdc = UserGetDCEx(NULL, NULL, DCX_USESTYLE);
|
|
hdc = UserGetDCEx(ClipboardWindow, NULL, DCX_USESTYLE);
|
|
|
|
/* Probe it */
|
|
_SEH2_TRY
|
|
{
|
|
Status = ProbeAndConvertToBitmapV5Info(&bmi, (BITMAPINFO*)pDIB, DIB_RGB_COLORS, 0);
|
|
offset = DIB_BitmapInfoSize((BITMAPINFO*)pDIB, DIB_RGB_COLORS);
|
|
ProbeForRead(pDIB + offset, bmi.bmiHeader.bV5SizeImage, 1);
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END
|
|
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
UserReleaseDC(ClipboardWindow, hdc, FALSE);
|
|
return NULL;
|
|
}
|
|
|
|
hbitmap = GreCreateDIBitmapInternal(hdc,
|
|
bmi.bmiHeader.bV5Width,
|
|
bmi.bmiHeader.bV5Height,
|
|
CBM_INIT,
|
|
pDIB+offset,
|
|
&bmi,
|
|
DIB_RGB_COLORS,
|
|
0,
|
|
0);
|
|
//UserReleaseDC(NULL, hdc, FALSE);
|
|
UserReleaseDC(ClipboardWindow, hdc, FALSE);
|
|
|
|
return hbitmap;
|
|
}
|
|
|
|
BOOL FASTCALL
|
|
canSinthesize(UINT format)
|
|
{
|
|
BOOL ret = FALSE;
|
|
|
|
switch(format)
|
|
{
|
|
case CF_BITMAP:
|
|
case CF_METAFILEPICT:
|
|
ret = TRUE;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* returns the size of the sinthesized data */
|
|
DWORD FASTCALL
|
|
synthesizeData(UINT format)
|
|
{
|
|
DWORD ret = 0;
|
|
|
|
synthesizedData = NULL;
|
|
synthesizedDataSize = 0;
|
|
|
|
if (!canSinthesize(format))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
switch (format)
|
|
{
|
|
case CF_BITMAP:
|
|
{
|
|
break;
|
|
}
|
|
|
|
case CF_METAFILEPICT:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
ret = 1;
|
|
|
|
return ret;
|
|
}
|
|
|
|
VOID FASTCALL
|
|
freeSynthesizedData(VOID)
|
|
{
|
|
ExFreePool(synthesizedData);
|
|
}
|
|
|
|
/*==============================================================*/
|
|
|
|
BOOL FASTCALL
|
|
intIsClipboardOpenByMe(VOID)
|
|
{
|
|
/* check if we open the clipboard */
|
|
if (ClipboardThread && ClipboardThread == PsGetCurrentThreadWin32Thread())
|
|
{
|
|
/* yes, we got a thread and its the same that opens the clipboard */
|
|
return TRUE;
|
|
|
|
}
|
|
/* 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(PWINDOW_OBJECT window)
|
|
{
|
|
/* called from co_UserFreeWindow in window.c */
|
|
/* check if clipboard is not locked by this window, if yes, unlock it */
|
|
if (ClipboardThread == PsGetCurrentThreadWin32Thread())
|
|
{
|
|
/* the window that opens the clipboard was destroyed */
|
|
ClipboardThread = NULL;
|
|
ClipboardWindow = NULL;
|
|
//TODO: free clipboard
|
|
}
|
|
if (window == ClipboardOwnerWindow)
|
|
{
|
|
/* the owner window was destroyed */
|
|
ClipboardOwnerWindow = NULL;
|
|
ClipboardOwnerThread = NULL;
|
|
}
|
|
/* remove window from window chain */
|
|
if (IntIsWindowInChain(window))
|
|
{
|
|
PCLIPBOARDCHAINELEMENT w = IntRemoveWindowFromChain(window);
|
|
if (w)
|
|
{
|
|
ExFreePool(w);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL APIENTRY
|
|
NtUserOpenClipboard(HWND hWnd, DWORD Unknown1)
|
|
{
|
|
|
|
PWINDOW_OBJECT Window;
|
|
BOOL ret = FALSE;
|
|
|
|
UserEnterExclusive();
|
|
|
|
sendDrawClipboardMsg = FALSE;
|
|
recentlySetClipboard = FALSE;
|
|
|
|
if (ClipboardThread)
|
|
{
|
|
/* clipboard is already open */
|
|
if (ClipboardThread == PsGetCurrentThreadWin32Thread())
|
|
{
|
|
if (ClipboardOwnerWindow)
|
|
{
|
|
if (ClipboardOwnerWindow->hSelf == hWnd)
|
|
{
|
|
ret = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (hWnd == NULL)
|
|
{
|
|
ret = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
if (hWnd != NULL)
|
|
{
|
|
Window = UserGetWindowObject(hWnd);
|
|
|
|
if (Window != NULL)
|
|
{
|
|
ClipboardWindow = Window;
|
|
ClipboardThread = PsGetCurrentThreadWin32Thread();
|
|
ret = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ClipboardWindow = NULL;
|
|
ClipboardThread = NULL;
|
|
ClipboardOwnerWindow = NULL;
|
|
ClipboardOwnerThread = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ClipboardWindow = NULL;
|
|
ClipboardThread = PsGetCurrentThreadWin32Thread();
|
|
ret = TRUE;
|
|
}
|
|
}
|
|
|
|
UserLeave();
|
|
|
|
return ret;
|
|
}
|
|
|
|
BOOL APIENTRY
|
|
NtUserCloseClipboard(VOID)
|
|
{
|
|
BOOL ret = FALSE;
|
|
|
|
UserEnterExclusive();
|
|
|
|
if (intIsClipboardOpenByMe())
|
|
{
|
|
ClipboardWindow = NULL;
|
|
ClipboardThread = NULL;
|
|
ret = TRUE;
|
|
}
|
|
else
|
|
{
|
|
SetLastWin32Error(ERROR_CLIPBOARD_NOT_OPEN);
|
|
}
|
|
|
|
recentlySetClipboard = FALSE;
|
|
|
|
UserLeave();
|
|
|
|
if (sendDrawClipboardMsg && WindowsChain)
|
|
{
|
|
/* 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);
|
|
DPRINT1("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", WindowsChain->window->hSelf);
|
|
co_IntSendMessage(WindowsChain->window->hSelf, WM_DRAWCLIPBOARD, 0, 0);
|
|
*/
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
HWND APIENTRY
|
|
NtUserGetOpenClipboardWindow(VOID)
|
|
{
|
|
HWND ret = NULL;
|
|
|
|
UserEnterShared();
|
|
|
|
if (ClipboardWindow)
|
|
{
|
|
ret = ClipboardWindow->hSelf;
|
|
}
|
|
|
|
UserLeave();
|
|
|
|
return ret;
|
|
}
|
|
|
|
BOOL APIENTRY
|
|
NtUserChangeClipboardChain(HWND hWndRemove, HWND hWndNewNext)
|
|
{
|
|
BOOL ret = FALSE;
|
|
PCLIPBOARDCHAINELEMENT w = NULL;
|
|
PWINDOW_OBJECT removeWindow;
|
|
UserEnterExclusive();
|
|
|
|
removeWindow = UserGetWindowObject(hWndRemove);
|
|
|
|
if (removeWindow)
|
|
{
|
|
if ((ret = !!IntIsWindowInChain(removeWindow)))
|
|
{
|
|
w = IntRemoveWindowFromChain(removeWindow);
|
|
if (w)
|
|
{
|
|
ExFreePool(w);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ret && WindowsChain)
|
|
{
|
|
// only send message to the first window in the chain,
|
|
// then they do the chain
|
|
|
|
/* WindowsChain->window may be NULL */
|
|
LPARAM lparam = WindowsChain->window == NULL ? 0 : (LPARAM)WindowsChain->window->hSelf;
|
|
DPRINT1("Message: WM_CHANGECBCHAIN to %p", WindowsChain->window->hSelf);
|
|
co_IntSendMessage(WindowsChain->window->hSelf, WM_CHANGECBCHAIN, (WPARAM)hWndRemove, lparam);
|
|
}
|
|
|
|
UserLeave();
|
|
|
|
return ret;
|
|
}
|
|
|
|
DWORD APIENTRY
|
|
NtUserCountClipboardFormats(VOID)
|
|
{
|
|
DWORD ret = 0;
|
|
|
|
if (ClipboardData)
|
|
{
|
|
ret = IntCountClipboardFormats();
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
DWORD APIENTRY
|
|
NtUserEmptyClipboard(VOID)
|
|
{
|
|
BOOL ret = FALSE;
|
|
|
|
UserEnterExclusive();
|
|
|
|
if (intIsClipboardOpenByMe())
|
|
{
|
|
if (ClipboardData)
|
|
{
|
|
IntEmptyClipboardData();
|
|
}
|
|
|
|
ClipboardOwnerWindow = ClipboardWindow;
|
|
ClipboardOwnerThread = ClipboardThread;
|
|
|
|
IntIncrementSequenceNumber();
|
|
|
|
ret = TRUE;
|
|
}
|
|
else
|
|
{
|
|
SetLastWin32Error(ERROR_CLIPBOARD_NOT_OPEN);
|
|
}
|
|
|
|
if (ret && ClipboardOwnerWindow)
|
|
{
|
|
DPRINT("Clipboard: WM_DESTROYCLIPBOARD to %p", ClipboardOwnerWindow->hSelf);
|
|
co_IntSendMessage( ClipboardOwnerWindow->hSelf, WM_DESTROYCLIPBOARD, 0, 0);
|
|
}
|
|
|
|
UserLeave();
|
|
|
|
return ret;
|
|
}
|
|
|
|
HANDLE APIENTRY
|
|
NtUserGetClipboardData(UINT uFormat, PVOID pBuffer)
|
|
{
|
|
HANDLE ret = NULL;
|
|
|
|
UserEnterShared();
|
|
|
|
if (intIsClipboardOpenByMe())
|
|
{
|
|
/* when Unknown1 is zero, we returns to user32 the data size */
|
|
if (!pBuffer)
|
|
{
|
|
PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
|
|
|
|
if (data)
|
|
{
|
|
/* format exists in clipboard */
|
|
if (data->size == DATA_DELAYED_RENDER)
|
|
{
|
|
/* tell owner what data needs to be rendered */
|
|
if (ClipboardOwnerWindow)
|
|
{
|
|
ASSERT(ClipboardOwnerWindow->hSelf);
|
|
co_IntSendMessage(ClipboardOwnerWindow->hSelf, 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);
|
|
}
|
|
|
|
}
|
|
ret = (HANDLE)(ULONG_PTR)data->size;
|
|
}
|
|
else
|
|
{
|
|
/* there is no data in this format */
|
|
//ret = (HANDLE)FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
|
|
|
|
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
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetLastWin32Error(ERROR_CLIPBOARD_NOT_OPEN);
|
|
}
|
|
|
|
UserLeave();
|
|
|
|
return ret;
|
|
}
|
|
|
|
INT APIENTRY
|
|
NtUserGetClipboardFormatName(UINT format, PUNICODE_STRING FormatName,
|
|
INT cchMaxCount)
|
|
{
|
|
UNICODE_STRING sFormatName;
|
|
INT ret = 0;
|
|
|
|
/* if the format is built-in we fail */
|
|
if (format < 0xc000)
|
|
{
|
|
/* registetrated formats are >= 0xc000 */
|
|
return 0;
|
|
}
|
|
|
|
if((cchMaxCount < 1) || !FormatName)
|
|
{
|
|
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
_SEH2_TRY
|
|
{
|
|
ProbeForWriteUnicodeString(FormatName);
|
|
sFormatName = *(volatile UNICODE_STRING *)FormatName;
|
|
ProbeForWrite(sFormatName.Buffer, sFormatName.MaximumLength, 1);
|
|
|
|
ret = IntGetAtomName((RTL_ATOM)format, sFormatName.Buffer, cchMaxCount * sizeof(WCHAR));
|
|
|
|
if (ret >= 0)
|
|
{
|
|
ret = ret / sizeof(WCHAR);
|
|
sFormatName.Length = ret;
|
|
}
|
|
else
|
|
{
|
|
ret = 0;
|
|
}
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
SetLastNtError(_SEH2_GetExceptionCode());
|
|
}
|
|
_SEH2_END;
|
|
|
|
return ret;
|
|
}
|
|
|
|
HWND APIENTRY
|
|
NtUserGetClipboardOwner(VOID)
|
|
{
|
|
HWND ret = NULL;
|
|
|
|
UserEnterShared();
|
|
|
|
if (ClipboardOwnerWindow)
|
|
{
|
|
ret = ClipboardOwnerWindow->hSelf;
|
|
}
|
|
|
|
UserLeave();
|
|
|
|
return ret;
|
|
}
|
|
|
|
HWND APIENTRY
|
|
NtUserGetClipboardViewer(VOID)
|
|
{
|
|
HWND ret = NULL;
|
|
|
|
UserEnterShared();
|
|
|
|
if (WindowsChain)
|
|
{
|
|
ret = WindowsChain->window->hSelf;
|
|
}
|
|
|
|
UserLeave();
|
|
|
|
return ret;
|
|
}
|
|
|
|
INT APIENTRY
|
|
NtUserGetPriorityClipboardFormat(UINT *paFormatPriorityList, INT cFormats)
|
|
{
|
|
INT i;
|
|
UINT *priorityList;
|
|
INT ret = 0;
|
|
|
|
UserEnterExclusive();
|
|
|
|
_SEH2_TRY
|
|
{
|
|
if (IntCountClipboardFormats() == 0)
|
|
{
|
|
ret = 0;
|
|
}
|
|
else
|
|
{
|
|
ProbeForRead(paFormatPriorityList, cFormats, sizeof(UINT));
|
|
|
|
priorityList = paFormatPriorityList;
|
|
|
|
ret = -1;
|
|
|
|
for (i = 0; i < cFormats; i++)
|
|
{
|
|
if (intIsFormatAvailable(priorityList[i]))
|
|
{
|
|
ret = priorityList[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
SetLastNtError(_SEH2_GetExceptionCode());
|
|
}
|
|
_SEH2_END;
|
|
|
|
UserLeave();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
BOOL APIENTRY
|
|
NtUserIsClipboardFormatAvailable(UINT format)
|
|
{
|
|
BOOL ret = FALSE;
|
|
|
|
UserEnterShared();
|
|
|
|
ret = (intIsFormatAvailable(format) != NULL);
|
|
|
|
UserLeave();
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
HANDLE APIENTRY
|
|
NtUserSetClipboardData(UINT uFormat, HANDLE hMem, DWORD size)
|
|
{
|
|
HANDLE hCBData = NULL;
|
|
UNICODE_STRING unicodeString;
|
|
OEM_STRING oemString;
|
|
ANSI_STRING ansiString;
|
|
|
|
UserEnterExclusive();
|
|
|
|
/* to place data here the we need to be the owner */
|
|
if (ClipboardOwnerThread == PsGetCurrentThreadWin32Thread())
|
|
{
|
|
PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
|
|
if (data)
|
|
{
|
|
|
|
if (data->size == DATA_DELAYED_RENDER)
|
|
{
|
|
intRemoveFormatedData(uFormat);
|
|
}
|
|
else
|
|
{
|
|
// we already have this format on clipboard
|
|
goto exit_setCB;
|
|
}
|
|
}
|
|
|
|
if (hMem)
|
|
{
|
|
_SEH2_TRY
|
|
{
|
|
ProbeForRead(hMem, size, 1);
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
SetLastNtError(_SEH2_GetExceptionCode());
|
|
_SEH2_YIELD(goto exit_setCB);
|
|
}
|
|
_SEH2_END;
|
|
|
|
if (intIsClipboardOpenByMe())
|
|
{
|
|
delayedRender = FALSE;
|
|
}
|
|
|
|
if (!canSinthesize(uFormat))
|
|
{
|
|
hCBData = ExAllocatePoolWithTag(PagedPool, size, USERTAG_CLIPBOARD);
|
|
memcpy(hCBData, hMem, size);
|
|
intAddFormatedData(uFormat, hCBData, size);
|
|
DPRINT1("Data stored\n");
|
|
}
|
|
|
|
sendDrawClipboardMsg = TRUE;
|
|
recentlySetClipboard = TRUE;
|
|
lastEnumClipboardFormats = uFormat;
|
|
|
|
/* 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
|
|
|
|
HDC hdc;
|
|
INT ret;
|
|
BITMAP bm;
|
|
BITMAPINFO bi;
|
|
SURFACE *psurf;
|
|
|
|
hdc = UserGetDCEx(NULL, NULL, DCX_USESTYLE);
|
|
|
|
|
|
psurf = SURFACE_LockSurface(hMem);
|
|
BITMAP_GetObject(psurf, sizeof(BITMAP), (PVOID)&bm);
|
|
if(psurf)
|
|
{
|
|
SURFACE_UnlockSurface(psurf);
|
|
}
|
|
|
|
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;
|
|
|
|
ret = NtGdiGetDIBitsInternal(hdc, hMem, 0, bm.bmHeight, NULL, &bi, DIB_RGB_COLORS, 0, 0);
|
|
|
|
size = bi.bmiHeader.biSizeImage + sizeof(BITMAPINFOHEADER);
|
|
|
|
hCBData = ExAllocatePoolWithTag(PagedPool, size, USERTAG_CLIPBOARD);
|
|
memcpy(hCBData, &bi, sizeof(BITMAPINFOHEADER));
|
|
|
|
ret = NtGdiGetDIBitsInternal(hdc, hMem, 0, bm.bmHeight, (LPBYTE)hCBData + sizeof(BITMAPINFOHEADER), &bi, DIB_RGB_COLORS, 0, 0);
|
|
|
|
UserReleaseDC(NULL, hdc, FALSE);
|
|
|
|
intAddFormatedData(CF_DIB, hCBData, size);
|
|
intAddFormatedData(CF_BITMAP, 0, DATA_SYNTHESIZED_RENDER);
|
|
// intAddFormatedData(CF_DIBV5, hCBData, size);
|
|
|
|
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;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// the window provides data in the specified format
|
|
delayedRender = TRUE;
|
|
sendDrawClipboardMsg = TRUE;
|
|
intAddFormatedData(uFormat, NULL, 0);
|
|
DPRINT1("SetClipboardData delayed format: %d\n", uFormat);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
exit_setCB:
|
|
|
|
UserLeave();
|
|
|
|
return hMem;
|
|
}
|
|
|
|
HWND APIENTRY
|
|
NtUserSetClipboardViewer(HWND hWndNewViewer)
|
|
{
|
|
HWND ret = NULL;
|
|
PCLIPBOARDCHAINELEMENT newWC = NULL;
|
|
PWINDOW_OBJECT window;
|
|
|
|
UserEnterExclusive();
|
|
|
|
window = UserGetWindowObject(hWndNewViewer);
|
|
|
|
if (window)
|
|
{
|
|
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->hSelf;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
UserLeave();
|
|
|
|
return ret;
|
|
}
|
|
|
|
UINT APIENTRY
|
|
IntEnumClipboardFormats(UINT uFormat)
|
|
{
|
|
UINT ret = 0;
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetLastWin32Error(ERROR_CLIPBOARD_NOT_OPEN);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
// 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;
|
|
|
|
pti = PsGetCurrentThreadWin32Thread();
|
|
WinStaObj = pti->rpdesk->rpwinstaParent;
|
|
|
|
WinStaObj->Clipboard->ClipboardSequenceNumber++;
|
|
}
|
|
|
|
DWORD APIENTRY
|
|
NtUserGetClipboardSequenceNumber(VOID)
|
|
{
|
|
//windowstation sequence number
|
|
//if no WINSTA_ACCESSCLIPBOARD access to the window station,
|
|
//the function returns zero.
|
|
DWORD sn;
|
|
|
|
HWINSTA WinSta;
|
|
PWINSTATION_OBJECT WinStaObj;
|
|
NTSTATUS Status;
|
|
|
|
WinSta = UserGetProcessWindowStation();
|
|
|
|
Status = IntValidateWindowStationHandle(WinSta, KernelMode, WINSTA_ACCESSCLIPBOARD, &WinStaObj);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("No WINSTA_ACCESSCLIPBOARD access\n");
|
|
SetLastNtError(Status);
|
|
return 0;
|
|
}
|
|
|
|
sn = WinStaObj->ClipboardSequenceNumber;
|
|
|
|
ObDereferenceObject(WinStaObj);
|
|
|
|
//local copy
|
|
//sn = ClipboardSequenceNumber;
|
|
|
|
return sn;
|
|
}
|
|
|
|
|
|
/**************** VISTA FUNCTIONS******************/
|
|
|
|
BOOL APIENTRY NtUserAddClipboardFormatListener(
|
|
HWND hwnd
|
|
)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL APIENTRY NtUserRemoveClipboardFormatListener(
|
|
HWND hwnd
|
|
)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL APIENTRY NtUserGetUpdatedClipboardFormats(
|
|
PUINT lpuiFormats,
|
|
UINT cFormats,
|
|
PUINT pcFormatsOut
|
|
)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return FALSE;
|
|
}
|
|
|
|
/* EOF */
|