|  | /* | 
|  | * WIN32 clipboard implementation | 
|  | * | 
|  | * Copyright 1994 Martin Ayotte | 
|  | *	     1996 Alex Korobka | 
|  | *	     1999 Noel Borthwick | 
|  | *	     2003 Ulrich Czekalla for CodeWeavers | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | * | 
|  | * NOTES: | 
|  | *    This file contains the implementation for the WIN32 Clipboard API | 
|  | * and Wine's internal clipboard cache. | 
|  | * The actual contents of the clipboard are held in the clipboard cache. | 
|  | * The internal implementation talks to a "clipboard driver" to fill or | 
|  | * expose the cache to the native device. (Currently only the X11 and | 
|  | * TTY clipboard  driver are available) | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include "wine/port.h" | 
|  |  | 
|  | #include <stdarg.h> | 
|  | #include <stdlib.h> | 
|  | #include <sys/types.h> | 
|  | #include <fcntl.h> | 
|  | #ifdef HAVE_UNISTD_H | 
|  | # include <unistd.h> | 
|  | #endif | 
|  | #include <string.h> | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "wingdi.h" | 
|  | #include "winuser.h" | 
|  | #include "winerror.h" | 
|  | #include "wine/winbase16.h" | 
|  | #include "user_private.h" | 
|  | #include "win.h" | 
|  |  | 
|  | #include "wine/debug.h" | 
|  | #include "wine/unicode.h" | 
|  | #include "wine/server.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(clipboard); | 
|  |  | 
|  | #define  CF_REGFORMATBASE  0xC000 | 
|  |  | 
|  | typedef struct | 
|  | { | 
|  | HWND hWndOpen; | 
|  | HWND hWndOwner; | 
|  | HWND hWndViewer; | 
|  | UINT seqno; | 
|  | UINT flags; | 
|  | } CLIPBOARDINFO, *LPCLIPBOARDINFO; | 
|  |  | 
|  | /* | 
|  | * Indicates if data has changed since open. | 
|  | */ | 
|  | static BOOL bCBHasChanged = FALSE; | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *                      CLIPBOARD_SetClipboardOwner | 
|  | * | 
|  | * Set the global wineserver clipboard owner. The current process will | 
|  | * be the owner and <hWnd> will get the render notifications. | 
|  | */ | 
|  | static BOOL CLIPBOARD_SetClipboardOwner(HWND hWnd) | 
|  | { | 
|  | BOOL bRet = FALSE; | 
|  |  | 
|  | TRACE(" hWnd(%p)\n", hWnd); | 
|  |  | 
|  | SERVER_START_REQ( set_clipboard_info ) | 
|  | { | 
|  | req->flags = SET_CB_OWNER; | 
|  | req->owner = WIN_GetFullHandle( hWnd ); | 
|  |  | 
|  | if (wine_server_call_err( req )) | 
|  | { | 
|  | ERR("Failed to set clipboard owner to %p\n", hWnd); | 
|  | } | 
|  | else | 
|  | { | 
|  | bRet = TRUE; | 
|  | } | 
|  | } | 
|  | SERVER_END_REQ; | 
|  |  | 
|  | return bRet; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *                      CLIPBOARD_GetClipboardInfo | 
|  | */ | 
|  | static BOOL CLIPBOARD_GetClipboardInfo(LPCLIPBOARDINFO cbInfo) | 
|  | { | 
|  | BOOL bRet = FALSE; | 
|  |  | 
|  | SERVER_START_REQ( set_clipboard_info ) | 
|  | { | 
|  | req->flags = 0; | 
|  |  | 
|  | if (wine_server_call_err( req )) | 
|  | { | 
|  | ERR("Failed to get clipboard info\n"); | 
|  | } | 
|  | else | 
|  | { | 
|  | cbInfo->hWndOpen = reply->old_clipboard; | 
|  | cbInfo->hWndOwner = reply->old_owner; | 
|  | cbInfo->hWndViewer = reply->old_viewer; | 
|  | cbInfo->seqno = reply->seqno; | 
|  | cbInfo->flags = reply->flags; | 
|  |  | 
|  | bRet = TRUE; | 
|  | } | 
|  | } | 
|  | SERVER_END_REQ; | 
|  |  | 
|  | return bRet; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *	CLIPBOARD_ReleaseOwner | 
|  | */ | 
|  | BOOL CLIPBOARD_ReleaseOwner(void) | 
|  | { | 
|  | BOOL bRet = FALSE; | 
|  |  | 
|  | SERVER_START_REQ( set_clipboard_info ) | 
|  | { | 
|  | req->flags = SET_CB_RELOWNER | SET_CB_SEQNO; | 
|  |  | 
|  | if (wine_server_call_err( req )) | 
|  | { | 
|  | ERR("Failed to set clipboard.\n"); | 
|  | } | 
|  | else | 
|  | { | 
|  | bRet = TRUE; | 
|  | } | 
|  | } | 
|  | SERVER_END_REQ; | 
|  |  | 
|  | return bRet; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		CLIPBOARD_OpenClipboard | 
|  | */ | 
|  | static BOOL CLIPBOARD_OpenClipboard(HWND hWnd) | 
|  | { | 
|  | BOOL bRet = FALSE; | 
|  |  | 
|  | SERVER_START_REQ( set_clipboard_info ) | 
|  | { | 
|  | req->flags = SET_CB_OPEN; | 
|  | req->clipboard = WIN_GetFullHandle( hWnd ); | 
|  |  | 
|  | if (!wine_server_call( req )) | 
|  | bRet = TRUE; | 
|  | } | 
|  | SERVER_END_REQ; | 
|  |  | 
|  | return bRet; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		CLIPBOARD_CloseClipboard | 
|  | */ | 
|  | static BOOL CLIPBOARD_CloseClipboard(void) | 
|  | { | 
|  | BOOL bRet = FALSE; | 
|  |  | 
|  | TRACE(" Changed=%d\n", bCBHasChanged); | 
|  |  | 
|  | SERVER_START_REQ( set_clipboard_info ) | 
|  | { | 
|  | req->flags = SET_CB_CLOSE; | 
|  |  | 
|  | if (bCBHasChanged) | 
|  | { | 
|  | req->flags |= SET_CB_SEQNO; | 
|  | TRACE("Clipboard data changed\n"); | 
|  | } | 
|  |  | 
|  | if (wine_server_call_err( req )) | 
|  | { | 
|  | ERR("Failed to set clipboard.\n"); | 
|  | } | 
|  | else | 
|  | { | 
|  | bRet = TRUE; | 
|  | } | 
|  | } | 
|  | SERVER_END_REQ; | 
|  |  | 
|  | return bRet; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *                WIN32 Clipboard implementation | 
|  | **************************************************************************/ | 
|  |  | 
|  | /************************************************************************** | 
|  | *		RegisterClipboardFormatW (USER32.@) | 
|  | */ | 
|  | UINT WINAPI RegisterClipboardFormatW(LPCWSTR FormatName) | 
|  | { | 
|  | return USER_Driver->pRegisterClipboardFormat(FormatName); | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		RegisterClipboardFormatA (USER32.@) | 
|  | */ | 
|  | UINT WINAPI RegisterClipboardFormatA(LPCSTR formatName) | 
|  | { | 
|  | int len; | 
|  | LPWSTR wFormat; | 
|  | UINT ret; | 
|  |  | 
|  | len = MultiByteToWideChar(CP_ACP, 0, formatName, -1, NULL, 0); | 
|  | wFormat = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); | 
|  | MultiByteToWideChar(CP_ACP, 0, formatName, -1, wFormat, len); | 
|  |  | 
|  | ret = RegisterClipboardFormatW(wFormat); | 
|  | HeapFree(GetProcessHeap(), 0, wFormat); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		GetClipboardFormatNameW (USER32.@) | 
|  | */ | 
|  | INT WINAPI GetClipboardFormatNameW(UINT wFormat, LPWSTR retStr, INT maxlen) | 
|  | { | 
|  | return USER_Driver->pGetClipboardFormatName(wFormat, retStr, maxlen); | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		GetClipboardFormatNameA (USER32.@) | 
|  | */ | 
|  | INT WINAPI GetClipboardFormatNameA(UINT wFormat, LPSTR retStr, INT maxlen) | 
|  | { | 
|  | INT ret; | 
|  | LPWSTR p = HeapAlloc( GetProcessHeap(), 0, maxlen*sizeof(WCHAR) ); | 
|  | if(p == NULL) return 0; /* FIXME: is this the correct failure value? */ | 
|  |  | 
|  | ret = GetClipboardFormatNameW( wFormat, p, maxlen ); | 
|  |  | 
|  | if (ret && maxlen > 0 && !WideCharToMultiByte( CP_ACP, 0, p, -1, retStr, maxlen, 0, 0)) | 
|  | retStr[maxlen-1] = 0; | 
|  | HeapFree( GetProcessHeap(), 0, p ); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		OpenClipboard (USER32.@) | 
|  | * | 
|  | * Note: Netscape uses NULL hWnd to open the clipboard. | 
|  | */ | 
|  | BOOL WINAPI OpenClipboard( HWND hWnd ) | 
|  | { | 
|  | BOOL bRet; | 
|  |  | 
|  | TRACE("(%p)...\n", hWnd); | 
|  |  | 
|  | bRet = CLIPBOARD_OpenClipboard(hWnd); | 
|  |  | 
|  | TRACE(" returning %i\n", bRet); | 
|  |  | 
|  | return bRet; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		CloseClipboard (USER32.@) | 
|  | */ | 
|  | BOOL WINAPI CloseClipboard(void) | 
|  | { | 
|  | BOOL bRet = FALSE; | 
|  |  | 
|  | TRACE("(%d)\n", bCBHasChanged); | 
|  |  | 
|  | if (CLIPBOARD_CloseClipboard()) | 
|  | { | 
|  | if (bCBHasChanged) | 
|  | { | 
|  | HWND hWndViewer = GetClipboardViewer(); | 
|  |  | 
|  | USER_Driver->pEndClipboardUpdate(); | 
|  |  | 
|  | if (hWndViewer) | 
|  | SendMessageW(hWndViewer, WM_DRAWCLIPBOARD, 0, 0); | 
|  |  | 
|  | bCBHasChanged = FALSE; | 
|  | } | 
|  |  | 
|  | bRet = TRUE; | 
|  | } | 
|  |  | 
|  | return bRet; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		EmptyClipboard (USER32.@) | 
|  | * Empties and acquires ownership of the clipboard | 
|  | */ | 
|  | BOOL WINAPI EmptyClipboard(void) | 
|  | { | 
|  | CLIPBOARDINFO cbinfo; | 
|  |  | 
|  | TRACE("()\n"); | 
|  |  | 
|  | if (!CLIPBOARD_GetClipboardInfo(&cbinfo) || | 
|  | ~cbinfo.flags & CB_OPEN) | 
|  | { | 
|  | WARN("Clipboard not opened by calling task!\n"); | 
|  | SetLastError(ERROR_CLIPBOARD_NOT_OPEN); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /* Destroy private objects */ | 
|  | if (cbinfo.hWndOwner) | 
|  | SendMessageW(cbinfo.hWndOwner, WM_DESTROYCLIPBOARD, 0, 0); | 
|  |  | 
|  | /* Tell the driver to acquire the selection. The current owner | 
|  | * will be signaled to delete it's own cache. */ | 
|  |  | 
|  | /* Assign ownership of the clipboard to the current client. We do | 
|  | * this before acquiring the selection so that when we do acquire the | 
|  | * selection and the selection loser gets notified, it can check if | 
|  | * it has lost the Wine clipboard ownership. If it did then it knows | 
|  | * that a WM_DESTORYCLIPBOARD has already been sent. Otherwise it | 
|  | * lost the selection to a X app and it should send the | 
|  | * WM_DESTROYCLIPBOARD itself. */ | 
|  | CLIPBOARD_SetClipboardOwner(cbinfo.hWndOpen); | 
|  |  | 
|  | /* Acquire the selection. This will notify the previous owner | 
|  | * to clear it's cache. */ | 
|  | USER_Driver->pAcquireClipboard(cbinfo.hWndOpen); | 
|  |  | 
|  | /* Empty the local cache */ | 
|  | USER_Driver->pEmptyClipboard(FALSE); | 
|  |  | 
|  | bCBHasChanged = TRUE; | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		GetClipboardOwner (USER32.@) | 
|  | *  FIXME: Can't return the owner if the clipboard is owned by an external X-app | 
|  | */ | 
|  | HWND WINAPI GetClipboardOwner(void) | 
|  | { | 
|  | HWND hWndOwner = 0; | 
|  |  | 
|  | SERVER_START_REQ( set_clipboard_info ) | 
|  | { | 
|  | req->flags = 0; | 
|  | if (!wine_server_call_err( req )) hWndOwner = reply->old_owner; | 
|  | } | 
|  | SERVER_END_REQ; | 
|  |  | 
|  | TRACE(" hWndOwner(%p)\n", hWndOwner); | 
|  |  | 
|  | return hWndOwner; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		GetOpenClipboardWindow (USER32.@) | 
|  | */ | 
|  | HWND WINAPI GetOpenClipboardWindow(void) | 
|  | { | 
|  | HWND hWndOpen = 0; | 
|  |  | 
|  | SERVER_START_REQ( set_clipboard_info ) | 
|  | { | 
|  | req->flags = 0; | 
|  | if (!wine_server_call_err( req )) hWndOpen = reply->old_clipboard; | 
|  | } | 
|  | SERVER_END_REQ; | 
|  |  | 
|  | TRACE(" hWndClipWindow(%p)\n", hWndOpen); | 
|  |  | 
|  | return hWndOpen; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		SetClipboardViewer (USER32.@) | 
|  | */ | 
|  | HWND WINAPI SetClipboardViewer( HWND hWnd ) | 
|  | { | 
|  | HWND hwndPrev = 0; | 
|  |  | 
|  | SERVER_START_REQ( set_clipboard_info ) | 
|  | { | 
|  | req->flags = SET_CB_VIEWER; | 
|  | req->viewer = WIN_GetFullHandle(hWnd); | 
|  |  | 
|  | if (wine_server_call_err( req )) | 
|  | { | 
|  | ERR("Failed to set clipboard.\n"); | 
|  | } | 
|  | else | 
|  | { | 
|  | hwndPrev = reply->old_viewer; | 
|  | } | 
|  | } | 
|  | SERVER_END_REQ; | 
|  |  | 
|  | TRACE("(%p): returning %p\n", hWnd, hwndPrev); | 
|  |  | 
|  | return hwndPrev; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *              GetClipboardViewer (USER32.@) | 
|  | */ | 
|  | HWND WINAPI GetClipboardViewer(void) | 
|  | { | 
|  | HWND hWndViewer = 0; | 
|  |  | 
|  | SERVER_START_REQ( set_clipboard_info ) | 
|  | { | 
|  | req->flags = 0; | 
|  | if (!wine_server_call_err( req )) hWndViewer = reply->old_viewer; | 
|  | } | 
|  | SERVER_END_REQ; | 
|  |  | 
|  | TRACE(" hWndViewer=%p\n", hWndViewer); | 
|  |  | 
|  | return hWndViewer; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *              ChangeClipboardChain (USER32.@) | 
|  | */ | 
|  | BOOL WINAPI ChangeClipboardChain(HWND hWnd, HWND hWndNext) | 
|  | { | 
|  | BOOL bRet = TRUE; | 
|  | HWND hWndViewer = GetClipboardViewer(); | 
|  |  | 
|  | if (hWndViewer) | 
|  | { | 
|  | if (WIN_GetFullHandle(hWnd) == hWndViewer) | 
|  | SetClipboardViewer(WIN_GetFullHandle(hWndNext)); | 
|  | else | 
|  | bRet = !SendMessageW(hWndViewer, WM_CHANGECBCHAIN, (WPARAM)hWnd, (LPARAM)hWndNext); | 
|  | } | 
|  | else | 
|  | ERR("hWndViewer is lost\n"); | 
|  |  | 
|  | return bRet; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		SetClipboardData (USER.141) | 
|  | */ | 
|  | HANDLE16 WINAPI SetClipboardData16(UINT16 wFormat, HANDLE16 hData) | 
|  | { | 
|  | CLIPBOARDINFO cbinfo; | 
|  | HANDLE16 hResult = 0; | 
|  |  | 
|  | TRACE("(%04X, %04x) !\n", wFormat, hData); | 
|  |  | 
|  | /* If it's not owned, data can only be set if the format doesn't exists | 
|  | and its rendering is not delayed */ | 
|  | if (!CLIPBOARD_GetClipboardInfo(&cbinfo) || | 
|  | (!(cbinfo.flags & CB_OWNER) && !hData)) | 
|  | { | 
|  | WARN("Clipboard not owned by calling task. Operation failed.\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if (USER_Driver->pSetClipboardData(wFormat, hData, 0, cbinfo.flags & CB_OWNER)) | 
|  | { | 
|  | hResult = hData; | 
|  | bCBHasChanged = TRUE; | 
|  | } | 
|  |  | 
|  | return hResult; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		SetClipboardData (USER32.@) | 
|  | */ | 
|  | HANDLE WINAPI SetClipboardData(UINT wFormat, HANDLE hData) | 
|  | { | 
|  | CLIPBOARDINFO cbinfo; | 
|  | HANDLE hResult = 0; | 
|  |  | 
|  | TRACE("(%04X, %p) !\n", wFormat, hData); | 
|  |  | 
|  | /* If it's not owned, data can only be set if the format isn't | 
|  | available and its rendering is not delayed */ | 
|  | if (!CLIPBOARD_GetClipboardInfo(&cbinfo) || | 
|  | (!(cbinfo.flags & CB_OWNER) && !hData)) | 
|  | { | 
|  | WARN("Clipboard not owned by calling task. Operation failed.\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if (USER_Driver->pSetClipboardData(wFormat, 0, hData, cbinfo.flags & CB_OWNER)) | 
|  | { | 
|  | hResult = hData; | 
|  | bCBHasChanged = TRUE; | 
|  | } | 
|  |  | 
|  | return hResult; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		CountClipboardFormats (USER32.@) | 
|  | */ | 
|  | INT WINAPI CountClipboardFormats(void) | 
|  | { | 
|  | INT count = USER_Driver->pCountClipboardFormats(); | 
|  | TRACE("returning %d\n", count); | 
|  | return count; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		EnumClipboardFormats (USER32.@) | 
|  | */ | 
|  | UINT WINAPI EnumClipboardFormats(UINT wFormat) | 
|  | { | 
|  | CLIPBOARDINFO cbinfo; | 
|  |  | 
|  | TRACE("(%04X)\n", wFormat); | 
|  |  | 
|  | if (!CLIPBOARD_GetClipboardInfo(&cbinfo) || | 
|  | (~cbinfo.flags & CB_OPEN)) | 
|  | { | 
|  | WARN("Clipboard not opened by calling task.\n"); | 
|  | SetLastError(ERROR_CLIPBOARD_NOT_OPEN); | 
|  | return 0; | 
|  | } | 
|  | return USER_Driver->pEnumClipboardFormats(wFormat); | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		IsClipboardFormatAvailable (USER32.@) | 
|  | */ | 
|  | BOOL WINAPI IsClipboardFormatAvailable(UINT wFormat) | 
|  | { | 
|  | BOOL bret = USER_Driver->pIsClipboardFormatAvailable(wFormat); | 
|  | TRACE("%04x, returning %d\n", wFormat, bret); | 
|  | return bret; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		GetClipboardData (USER.142) | 
|  | */ | 
|  | HANDLE16 WINAPI GetClipboardData16(UINT16 wFormat) | 
|  | { | 
|  | HANDLE16 hData = 0; | 
|  | CLIPBOARDINFO cbinfo; | 
|  |  | 
|  | if (!CLIPBOARD_GetClipboardInfo(&cbinfo) || | 
|  | (~cbinfo.flags & CB_OPEN)) | 
|  | { | 
|  | WARN("Clipboard not opened by calling task.\n"); | 
|  | SetLastError(ERROR_CLIPBOARD_NOT_OPEN); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if (!USER_Driver->pGetClipboardData(wFormat, &hData, NULL)) hData = 0; | 
|  |  | 
|  | return hData; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		GetClipboardData (USER32.@) | 
|  | */ | 
|  | HANDLE WINAPI GetClipboardData(UINT wFormat) | 
|  | { | 
|  | HANDLE hData = 0; | 
|  | CLIPBOARDINFO cbinfo; | 
|  |  | 
|  | TRACE("%04x\n", wFormat); | 
|  |  | 
|  | if (!CLIPBOARD_GetClipboardInfo(&cbinfo) || | 
|  | (~cbinfo.flags & CB_OPEN)) | 
|  | { | 
|  | WARN("Clipboard not opened by calling task.\n"); | 
|  | SetLastError(ERROR_CLIPBOARD_NOT_OPEN); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if (!USER_Driver->pGetClipboardData(wFormat, NULL, &hData)) hData = 0; | 
|  |  | 
|  | TRACE("returning %p\n", hData); | 
|  | return hData; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		GetPriorityClipboardFormat (USER32.@) | 
|  | */ | 
|  | INT WINAPI GetPriorityClipboardFormat(UINT *list, INT nCount) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | TRACE("()\n"); | 
|  |  | 
|  | if(CountClipboardFormats() == 0) | 
|  | return 0; | 
|  |  | 
|  | for (i = 0; i < nCount; i++) | 
|  | if (IsClipboardFormatAvailable(list[i])) | 
|  | return list[i]; | 
|  |  | 
|  | return -1; | 
|  | } | 
|  |  | 
|  |  | 
|  | /************************************************************************** | 
|  | *		GetClipboardSequenceNumber (USER32.@) | 
|  | * Supported on Win2k/Win98 | 
|  | * MSDN: Windows clipboard code keeps a serial number for the clipboard | 
|  | * for each window station.  The number is incremented whenever the | 
|  | * contents change or are emptied. | 
|  | * If you do not have WINSTA_ACCESSCLIPBOARD then the function returns 0 | 
|  | */ | 
|  | DWORD WINAPI GetClipboardSequenceNumber(VOID) | 
|  | { | 
|  | DWORD seqno = 0; | 
|  |  | 
|  | SERVER_START_REQ( set_clipboard_info ) | 
|  | { | 
|  | req->flags = 0; | 
|  | if (!wine_server_call_err( req )) seqno = reply->seqno; | 
|  | } | 
|  | SERVER_END_REQ; | 
|  |  | 
|  | TRACE("returning %x\n", seqno); | 
|  | return seqno; | 
|  | } |