Chromium Code Reviews| Index: remoting/host/clipboard_win.cc |
| diff --git a/remoting/host/clipboard_win.cc b/remoting/host/clipboard_win.cc |
| index d812d2f86ba71531f61e339cf41a2de64abf771c..e6b3919e0403756d557fede29c9677de973dc58f 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" |
| @@ -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,56 @@ class ClipboardWin : public Clipboard { |
| virtual void Stop() OVERRIDE; |
| private: |
| - static LRESULT CALLBACK WndProc(HWND hwmd, UINT msg, WPARAM wParam, |
| - LPARAM lParam); |
| + void OnClipboardUpdate(); |
| 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"); |
|
Wez
2012/05/15 18:50:07
Consider using base::LoadNativeLibrary/GetFunction
simonmorris
2012/05/15 21:47:48
Those try to load a library, whereas ::GetModuleHa
alexeypa (please no reviews)
2012/05/15 23:12:29
+1
|
| + 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 we can't load both functions, then store neither. |
|
Wez
2012/05/15 18:50:07
Rather than NULLing these here, consider a HaveCli
simonmorris
2012/05/15 21:47:48
Done.
|
| + if (!add_clipboard_format_listener_ || |
| + !remove_clipboard_format_listener_) { |
| + add_clipboard_format_listener_ = NULL; |
| + remove_clipboard_format_listener_ = NULL; |
| + } |
| + // We don't expect to load these functions for OS versions before Vista. |
| + if (base::win::GetVersion() >= base::win::VERSION_VISTA) { |
|
Wez
2012/05/15 18:50:07
nit: I'd either not bother logging a warning at al
simonmorris
2012/05/15 21:47:48
Done.
|
| + if (!add_clipboard_format_listener_) { |
| + LOG(WARNING) << "Couldn't load AddClipboardFormatListener or " |
| + << "RemoveClipboardFormatListener."; |
| + } |
| + } |
| + } |
| + } |
| + |
| if (!RegisterWindowClass()) { |
| LOG(FATAL) << "Couldn't register clipboard window class."; |
| return; |
| @@ -122,10 +174,19 @@ void ClipboardWin::Start() { |
| LOG(FATAL) << "Couldn't create clipboard window."; |
| return; |
| } |
| + |
| + if (add_clipboard_format_listener_) { |
| + if (!(*add_clipboard_format_listener_)(hwnd_)) { |
| + LOG(WARNING) << "AddClipboardFormatListener() failed: " << GetLastError(); |
| + } |
| + } |
| } |
| void ClipboardWin::Stop() { |
| if (hwnd_) { |
| + if (remove_clipboard_format_listener_) { |
| + (*remove_clipboard_format_listener_)(hwnd_); |
| + } |
| ::DestroyWindow(hwnd_); |
| hwnd_ = NULL; |
| } |
| @@ -166,9 +227,41 @@ 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; |
|
Wez
2012/05/15 18:50:07
nit: Move this after the comment, before the {?
simonmorris
2012/05/15 21:47:48
But then the comment would be separated from the c
|
| + // 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::RegisterWindowClass() { |
| @@ -193,6 +286,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()); |
| } |