| Index: remoting/host/clipboard_win.cc
|
| diff --git a/remoting/host/clipboard_win.cc b/remoting/host/clipboard_win.cc
|
| index d812d2f86ba71531f61e339cf41a2de64abf771c..b3fc0c10effe4a647f671110859bcb7c3b2ef430 100644
|
| --- a/remoting/host/clipboard_win.cc
|
| +++ b/remoting/host/clipboard_win.cc
|
| @@ -12,6 +12,8 @@
|
| #include "base/process_util.h"
|
| #include "base/string16.h"
|
| #include "base/utf_string_conversions.h"
|
| +#include "base/win/scoped_hglobal.h"
|
| +#include "base/win/windows_version.h"
|
| #include "base/win/wrapped_window_proc.h"
|
| #include "remoting/base/constants.h"
|
| #include "remoting/proto/event.pb.h"
|
| @@ -45,7 +47,7 @@ class ScopedClipboard {
|
| return true;
|
| }
|
|
|
| - // This code runs on the desktop thread, so blocking briefly is acceptable.
|
| + // This code runs on the UI thread, so we can block only very briefly.
|
| for (int attempt = 0; attempt < kMaxAttemptsToOpenClipboard; ++attempt) {
|
| if (attempt > 0) {
|
| base::PlatformThread::Sleep(kSleepTimeBetweenAttempts);
|
| @@ -75,10 +77,24 @@ class ScopedClipboard {
|
| ::SetClipboardData(uFormat, hMem);
|
| }
|
|
|
| + // The caller must not free the handle. The caller should lock the handle,
|
| + // copy the clipboard data, and unlock the handle. All this must be done
|
| + // before this ScopedClipboard is destroyed.
|
| + HANDLE GetData(UINT format) {
|
| + if (!opened_) {
|
| + NOTREACHED();
|
| + return NULL;
|
| + }
|
| + return ::GetClipboardData(format);
|
| + }
|
| +
|
| private:
|
| bool opened_;
|
| };
|
|
|
| +typedef BOOL (WINAPI AddClipboardFormatListenerFn)(HWND);
|
| +typedef BOOL (WINAPI RemoveClipboardFormatListenerFn)(HWND);
|
| +
|
| } // namespace
|
|
|
| namespace remoting {
|
| @@ -93,20 +109,48 @@ class ClipboardWin : public Clipboard {
|
| virtual void Stop() OVERRIDE;
|
|
|
| private:
|
| - static LRESULT CALLBACK WndProc(HWND hwmd, UINT msg, WPARAM wParam,
|
| - LPARAM lParam);
|
| + void OnClipboardUpdate();
|
| + bool HaveClipboardListenerApi();
|
|
|
| static bool RegisterWindowClass();
|
| + static LRESULT CALLBACK WndProc(HWND hwmd, UINT msg, WPARAM wParam,
|
| + LPARAM lParam);
|
|
|
| HWND hwnd_;
|
| + AddClipboardFormatListenerFn* add_clipboard_format_listener_;
|
| + RemoveClipboardFormatListenerFn* remove_clipboard_format_listener_;
|
| + bool load_functions_tried_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(ClipboardWin);
|
| };
|
|
|
| -ClipboardWin::ClipboardWin() : hwnd_(NULL) {
|
| +ClipboardWin::ClipboardWin()
|
| + : hwnd_(NULL),
|
| + add_clipboard_format_listener_(NULL),
|
| + remove_clipboard_format_listener_(NULL),
|
| + load_functions_tried_(false) {
|
| }
|
|
|
| void ClipboardWin::Start() {
|
| + if (!load_functions_tried_) {
|
| + load_functions_tried_ = true;
|
| + HMODULE user32_module = ::GetModuleHandle(L"user32.dll");
|
| + if (!user32_module) {
|
| + LOG(WARNING) << "Couldn't find user32.dll.";
|
| + } else {
|
| + add_clipboard_format_listener_ =
|
| + reinterpret_cast<AddClipboardFormatListenerFn*>(
|
| + ::GetProcAddress(user32_module, "AddClipboardFormatListener"));
|
| + remove_clipboard_format_listener_ =
|
| + reinterpret_cast<RemoveClipboardFormatListenerFn*>(
|
| + ::GetProcAddress(user32_module, "RemoveClipboardFormatListener"));
|
| + if (!HaveClipboardListenerApi()) {
|
| + LOG(WARNING) << "Couldn't load AddClipboardFormatListener or "
|
| + << "RemoveClipboardFormatListener.";
|
| + }
|
| + }
|
| + }
|
| +
|
| if (!RegisterWindowClass()) {
|
| LOG(FATAL) << "Couldn't register clipboard window class.";
|
| return;
|
| @@ -122,10 +166,19 @@ void ClipboardWin::Start() {
|
| LOG(FATAL) << "Couldn't create clipboard window.";
|
| return;
|
| }
|
| +
|
| + if (HaveClipboardListenerApi()) {
|
| + if (!(*add_clipboard_format_listener_)(hwnd_)) {
|
| + LOG(WARNING) << "AddClipboardFormatListener() failed: " << GetLastError();
|
| + }
|
| + }
|
| }
|
|
|
| void ClipboardWin::Stop() {
|
| if (hwnd_) {
|
| + if (HaveClipboardListenerApi()) {
|
| + (*remove_clipboard_format_listener_)(hwnd_);
|
| + }
|
| ::DestroyWindow(hwnd_);
|
| hwnd_ = NULL;
|
| }
|
| @@ -166,13 +219,49 @@ void ClipboardWin::InjectClipboardEvent(
|
| clipboard.SetData(CF_UNICODETEXT, text_global);
|
| }
|
|
|
| -LRESULT CALLBACK ClipboardWin::WndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
| - LPARAM lParam) {
|
| - return ::DefWindowProc(hwnd, msg, wParam, lParam);
|
| +void ClipboardWin::OnClipboardUpdate() {
|
| + DCHECK(hwnd_);
|
| +
|
| + if (::IsClipboardFormatAvailable(CF_UNICODETEXT)) {
|
| + string16 text;
|
| + // Add a scope, so that we keep the clipboard open for as short a time as
|
| + // possible.
|
| + {
|
| + ScopedClipboard clipboard;
|
| + if (!clipboard.Init(hwnd_)) {
|
| + LOG(WARNING) << "Couldn't open the clipboard." << GetLastError();
|
| + return;
|
| + }
|
| +
|
| + HGLOBAL text_global = clipboard.GetData(CF_UNICODETEXT);
|
| + if (!text_global) {
|
| + LOG(WARNING) << "Couldn't get data from the clipboard: "
|
| + << GetLastError();
|
| + return;
|
| + }
|
| +
|
| + base::win::ScopedHGlobal<WCHAR> text_lock(text_global);
|
| + if (!text_lock.get()) {
|
| + LOG(WARNING) << "Couldn't lock clipboard data: " << GetLastError();
|
| + return;
|
| + }
|
| + text.assign(text_lock.get());
|
| + }
|
| +
|
| + protocol::ClipboardEvent event;
|
| + event.set_mime_type(kMimeTypeTextUtf8);
|
| + event.set_data(UTF16ToUTF8(text));
|
| +
|
| + // TODO(simonmorris): Send the event to the client.
|
| + }
|
| +}
|
| +
|
| +bool ClipboardWin::HaveClipboardListenerApi() {
|
| + return add_clipboard_format_listener_ && remove_clipboard_format_listener_;
|
| }
|
|
|
| bool ClipboardWin::RegisterWindowClass() {
|
| - // This method is only called on the desktop thread, so it doesn't matter
|
| + // This method is only called on the UI thread, so it doesn't matter
|
| // that the following test is not thread-safe.
|
| static bool registered = false;
|
| if (registered) {
|
| @@ -193,6 +282,25 @@ bool ClipboardWin::RegisterWindowClass() {
|
| return true;
|
| }
|
|
|
| +LRESULT CALLBACK ClipboardWin::WndProc(HWND hwnd, UINT msg, WPARAM wparam,
|
| + LPARAM lparam) {
|
| + if (msg == WM_CREATE) {
|
| + CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lparam);
|
| + ::SetWindowLongPtr(hwnd,
|
| + GWLP_USERDATA,
|
| + reinterpret_cast<LONG_PTR>(cs->lpCreateParams));
|
| + return 0;
|
| + }
|
| + ClipboardWin* clipboard =
|
| + reinterpret_cast<ClipboardWin*>(::GetWindowLongPtr(hwnd, GWLP_USERDATA));
|
| + switch (msg) {
|
| + case WM_CLIPBOARDUPDATE:
|
| + clipboard->OnClipboardUpdate();
|
| + return 0;
|
| + }
|
| + return ::DefWindowProc(hwnd, msg, wparam, lparam);
|
| +}
|
| +
|
| scoped_ptr<Clipboard> Clipboard::Create() {
|
| return scoped_ptr<Clipboard>(new ClipboardWin());
|
| }
|
|
|