/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright 2012-2019 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This software 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ // -=- Clipboard.cxx #include #include #include #include using namespace rfb; using namespace rfb::win32; static LogWriter vlog("Clipboard"); // // -=- Clipboard object // Clipboard::Clipboard() : MsgWindow(_T("Clipboard")), notifier(0), next_window(0) { next_window = SetClipboardViewer(getHandle()); vlog.debug("registered clipboard handler"); } Clipboard::~Clipboard() { vlog.debug("removing %p from chain (next is %p)", getHandle(), next_window); ChangeClipboardChain(getHandle(), next_window); } LRESULT Clipboard::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_CHANGECBCHAIN: vlog.debug("change clipboard chain (%I64x, %I64x)", (long long)wParam, (long long)lParam); if ((HWND) wParam == next_window) next_window = (HWND) lParam; else if (next_window != 0) SendMessage(next_window, msg, wParam, lParam); else vlog.error("bad clipboard chain change!"); break; case WM_DRAWCLIPBOARD: { HWND owner = GetClipboardOwner(); if (owner == getHandle()) { vlog.debug("local clipboard changed by me"); } else { vlog.debug("local clipboard changed by %p", owner); if (notifier == NULL) vlog.debug("no clipboard notifier registered"); else notifier->notifyClipboardChanged(IsClipboardFormatAvailable(CF_UNICODETEXT)); } } if (next_window) SendMessage(next_window, msg, wParam, lParam); return 0; }; return MsgWindow::processMessage(msg, wParam, lParam); }; char* Clipboard::getClipText() { HGLOBAL cliphandle; wchar_t* clipdata; CharArray utf8; // Open the clipboard if (!OpenClipboard(getHandle())) return NULL; // Get the clipboard data cliphandle = GetClipboardData(CF_UNICODETEXT); if (!cliphandle) { CloseClipboard(); return NULL; } clipdata = (wchar_t*) GlobalLock(cliphandle); if (!clipdata) { CloseClipboard(); return NULL; } // Convert it to UTF-8 utf8.replaceBuf(utf16ToUTF8(clipdata)); // Release the buffer and close the clipboard GlobalUnlock(cliphandle); CloseClipboard(); return convertLF(utf8.buf); } void Clipboard::setClipText(const char* text) { HANDLE clip_handle = 0; try { // - Firstly, we must open the clipboard if (!OpenClipboard(getHandle())) throw rdr::SystemException("unable to open Win32 clipboard", GetLastError()); // - Convert the supplied clipboard text into UTF-16 format with CRLF CharArray filtered(convertCRLF(text)); wchar_t* utf16; utf16 = utf8ToUTF16(filtered.buf); // - Allocate global memory for the data clip_handle = ::GlobalAlloc(GMEM_MOVEABLE, (wcslen(utf16) + 1) * 2); wchar_t* data = (wchar_t*) GlobalLock(clip_handle); wcscpy(data, utf16); GlobalUnlock(clip_handle); strFree(utf16); // - Next, we must clear out any existing data if (!EmptyClipboard()) throw rdr::SystemException("unable to empty Win32 clipboard", GetLastError()); // - Set the new clipboard data if (!SetClipboardData(CF_UNICODETEXT, clip_handle)) throw rdr::SystemException("unable to set Win32 clipboard", GetLastError()); clip_handle = 0; vlog.debug("set clipboard"); } catch (rdr::Exception& e) { vlog.debug("%s", e.str()); } // - Close the clipboard if (!CloseClipboard()) vlog.debug("unable to close Win32 clipboard: %lu", GetLastError()); else vlog.debug("closed clipboard"); if (clip_handle) { vlog.debug("freeing clipboard handle"); GlobalFree(clip_handle); } }