Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(60)

Side by Side Diff: remoting/host/clipboard_win.cc

Issue 10381115: [Chromoting] The Windows IT2Me host gets any new text items it finds on the clipboard. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Review. Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « remoting/host/chromoting_host_context.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/host/clipboard.h" 5 #include "remoting/host/clipboard.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 8
9 #include "base/basictypes.h" 9 #include "base/basictypes.h"
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/process_util.h" 12 #include "base/process_util.h"
13 #include "base/string16.h" 13 #include "base/string16.h"
14 #include "base/utf_string_conversions.h" 14 #include "base/utf_string_conversions.h"
15 #include "base/win/scoped_hglobal.h"
16 #include "base/win/windows_version.h"
15 #include "base/win/wrapped_window_proc.h" 17 #include "base/win/wrapped_window_proc.h"
16 #include "remoting/base/constants.h" 18 #include "remoting/base/constants.h"
17 #include "remoting/proto/event.pb.h" 19 #include "remoting/proto/event.pb.h"
18 20
19 namespace { 21 namespace {
20 22
21 const WCHAR kWindowClassName[] = L"clipboardWindowClass"; 23 const WCHAR kWindowClassName[] = L"clipboardWindowClass";
22 const WCHAR kWindowName[] = L"clipboardWindow"; 24 const WCHAR kWindowName[] = L"clipboardWindow";
23 25
24 // A scoper class that opens and closes the clipboard. 26 // A scoper class that opens and closes the clipboard.
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
68 70
69 void SetData(UINT uFormat, HANDLE hMem) { 71 void SetData(UINT uFormat, HANDLE hMem) {
70 if (!opened_) { 72 if (!opened_) {
71 NOTREACHED(); 73 NOTREACHED();
72 return; 74 return;
73 } 75 }
74 // The caller must not close the handle that ::SetClipboardData returns. 76 // The caller must not close the handle that ::SetClipboardData returns.
75 ::SetClipboardData(uFormat, hMem); 77 ::SetClipboardData(uFormat, hMem);
76 } 78 }
77 79
80 // The caller must not free the handle. The caller should lock the handle,
81 // copy the clipboard data, and unlock the handle. All this must be done
82 // before this ScopedClipboard is destroyed.
83 HANDLE GetData(UINT format) {
84 if (!opened_) {
85 NOTREACHED();
86 return NULL;
87 }
88 return ::GetClipboardData(format);
89 }
90
78 private: 91 private:
79 bool opened_; 92 bool opened_;
80 }; 93 };
81 94
95 typedef BOOL (WINAPI AddClipboardFormatListenerFn)(HWND);
96 typedef BOOL (WINAPI RemoveClipboardFormatListenerFn)(HWND);
97
82 } // namespace 98 } // namespace
83 99
84 namespace remoting { 100 namespace remoting {
85 101
86 class ClipboardWin : public Clipboard { 102 class ClipboardWin : public Clipboard {
87 public: 103 public:
88 ClipboardWin(); 104 ClipboardWin();
89 105
90 virtual void Start() OVERRIDE; 106 virtual void Start() OVERRIDE;
91 virtual void InjectClipboardEvent( 107 virtual void InjectClipboardEvent(
92 const protocol::ClipboardEvent& event) OVERRIDE; 108 const protocol::ClipboardEvent& event) OVERRIDE;
93 virtual void Stop() OVERRIDE; 109 virtual void Stop() OVERRIDE;
94 110
95 private: 111 private:
112 void OnClipboardUpdate();
113
114 static bool RegisterWindowClass();
96 static LRESULT CALLBACK WndProc(HWND hwmd, UINT msg, WPARAM wParam, 115 static LRESULT CALLBACK WndProc(HWND hwmd, UINT msg, WPARAM wParam,
97 LPARAM lParam); 116 LPARAM lParam);
98 117
99 static bool RegisterWindowClass();
100
101 HWND hwnd_; 118 HWND hwnd_;
119 AddClipboardFormatListenerFn* add_clipboard_format_listener_;
120 RemoveClipboardFormatListenerFn* remove_clipboard_format_listener_;
121 bool load_functions_tried_;
102 122
103 DISALLOW_COPY_AND_ASSIGN(ClipboardWin); 123 DISALLOW_COPY_AND_ASSIGN(ClipboardWin);
104 }; 124 };
105 125
106 ClipboardWin::ClipboardWin() : hwnd_(NULL) { 126 ClipboardWin::ClipboardWin()
127 : hwnd_(NULL),
128 add_clipboard_format_listener_(NULL),
129 remove_clipboard_format_listener_(NULL),
130 load_functions_tried_(false) {
107 } 131 }
108 132
109 void ClipboardWin::Start() { 133 void ClipboardWin::Start() {
134 if (!load_functions_tried_) {
135 load_functions_tried_ = true;
136 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
137 if (!user32_module) {
138 LOG(WARNING) << "Couldn't find user32.dll.";
139 } else {
140 add_clipboard_format_listener_ =
141 reinterpret_cast<AddClipboardFormatListenerFn*>(
142 ::GetProcAddress(user32_module, "AddClipboardFormatListener"));
143 remove_clipboard_format_listener_ =
144 reinterpret_cast<RemoveClipboardFormatListenerFn*>(
145 ::GetProcAddress(user32_module, "RemoveClipboardFormatListener"));
146 // 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.
147 if (!add_clipboard_format_listener_ ||
148 !remove_clipboard_format_listener_) {
149 add_clipboard_format_listener_ = NULL;
150 remove_clipboard_format_listener_ = NULL;
151 }
152 // We don't expect to load these functions for OS versions before Vista.
153 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.
154 if (!add_clipboard_format_listener_) {
155 LOG(WARNING) << "Couldn't load AddClipboardFormatListener or "
156 << "RemoveClipboardFormatListener.";
157 }
158 }
159 }
160 }
161
110 if (!RegisterWindowClass()) { 162 if (!RegisterWindowClass()) {
111 LOG(FATAL) << "Couldn't register clipboard window class."; 163 LOG(FATAL) << "Couldn't register clipboard window class.";
112 return; 164 return;
113 } 165 }
114 hwnd_ = ::CreateWindow(kWindowClassName, 166 hwnd_ = ::CreateWindow(kWindowClassName,
115 kWindowName, 167 kWindowName,
116 0, 0, 0, 0, 0, 168 0, 0, 0, 0, 0,
117 HWND_MESSAGE, 169 HWND_MESSAGE,
118 NULL, 170 NULL,
119 base::GetModuleFromAddress(&WndProc), 171 base::GetModuleFromAddress(&WndProc),
120 this); 172 this);
121 if (!hwnd_) { 173 if (!hwnd_) {
122 LOG(FATAL) << "Couldn't create clipboard window."; 174 LOG(FATAL) << "Couldn't create clipboard window.";
123 return; 175 return;
124 } 176 }
177
178 if (add_clipboard_format_listener_) {
179 if (!(*add_clipboard_format_listener_)(hwnd_)) {
180 LOG(WARNING) << "AddClipboardFormatListener() failed: " << GetLastError();
181 }
182 }
125 } 183 }
126 184
127 void ClipboardWin::Stop() { 185 void ClipboardWin::Stop() {
128 if (hwnd_) { 186 if (hwnd_) {
187 if (remove_clipboard_format_listener_) {
188 (*remove_clipboard_format_listener_)(hwnd_);
189 }
129 ::DestroyWindow(hwnd_); 190 ::DestroyWindow(hwnd_);
130 hwnd_ = NULL; 191 hwnd_ = NULL;
131 } 192 }
132 } 193 }
133 194
134 void ClipboardWin::InjectClipboardEvent( 195 void ClipboardWin::InjectClipboardEvent(
135 const protocol::ClipboardEvent& event) { 196 const protocol::ClipboardEvent& event) {
136 if (!hwnd_) { 197 if (!hwnd_) {
137 return; 198 return;
138 } 199 }
(...skipping 20 matching lines...) Expand all
159 220
160 LPWSTR text_global_locked = 221 LPWSTR text_global_locked =
161 reinterpret_cast<LPWSTR>(::GlobalLock(text_global)); 222 reinterpret_cast<LPWSTR>(::GlobalLock(text_global));
162 memcpy(text_global_locked, text.data(), text.size() * sizeof(WCHAR)); 223 memcpy(text_global_locked, text.data(), text.size() * sizeof(WCHAR));
163 text_global_locked[text.size()] = (WCHAR)0; 224 text_global_locked[text.size()] = (WCHAR)0;
164 ::GlobalUnlock(text_global); 225 ::GlobalUnlock(text_global);
165 226
166 clipboard.SetData(CF_UNICODETEXT, text_global); 227 clipboard.SetData(CF_UNICODETEXT, text_global);
167 } 228 }
168 229
169 LRESULT CALLBACK ClipboardWin::WndProc(HWND hwnd, UINT msg, WPARAM wParam, 230 void ClipboardWin::OnClipboardUpdate() {
170 LPARAM lParam) { 231 DCHECK(hwnd_);
171 return ::DefWindowProc(hwnd, msg, wParam, lParam); 232
233 if (::IsClipboardFormatAvailable(CF_UNICODETEXT)) {
234 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
235 // Add a scope, so that we keep the clipboard open for as short a time as
236 // possible.
237 {
238 ScopedClipboard clipboard;
239 if (!clipboard.Init(hwnd_)) {
240 LOG(WARNING) << "Couldn't open the clipboard." << GetLastError();
241 return;
242 }
243
244 HGLOBAL text_global = clipboard.GetData(CF_UNICODETEXT);
245 if (!text_global) {
246 LOG(WARNING) << "Couldn't get data from the clipboard: "
247 << GetLastError();
248 return;
249 }
250
251 base::win::ScopedHGlobal<WCHAR> text_lock(text_global);
252 if (!text_lock.get()) {
253 LOG(WARNING) << "Couldn't lock clipboard data: " << GetLastError();
254 return;
255 }
256 text.assign(text_lock.get());
257 }
258
259 protocol::ClipboardEvent event;
260 event.set_mime_type(kMimeTypeTextUtf8);
261 event.set_data(UTF16ToUTF8(text));
262
263 // TODO(simonmorris): Send the event to the client.
264 }
172 } 265 }
173 266
174 bool ClipboardWin::RegisterWindowClass() { 267 bool ClipboardWin::RegisterWindowClass() {
175 // This method is only called on the desktop thread, so it doesn't matter 268 // This method is only called on the desktop thread, so it doesn't matter
176 // that the following test is not thread-safe. 269 // that the following test is not thread-safe.
177 static bool registered = false; 270 static bool registered = false;
178 if (registered) { 271 if (registered) {
179 return true; 272 return true;
180 } 273 }
181 274
182 WNDCLASSEX window_class; 275 WNDCLASSEX window_class;
183 base::win::InitializeWindowClass( 276 base::win::InitializeWindowClass(
184 kWindowClassName, 277 kWindowClassName,
185 base::win::WrappedWindowProc<WndProc>, 278 base::win::WrappedWindowProc<WndProc>,
186 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 279 0, 0, 0, NULL, NULL, NULL, NULL, NULL,
187 &window_class); 280 &window_class);
188 if (!::RegisterClassEx(&window_class)) { 281 if (!::RegisterClassEx(&window_class)) {
189 return false; 282 return false;
190 } 283 }
191 284
192 registered = true; 285 registered = true;
193 return true; 286 return true;
194 } 287 }
195 288
289 LRESULT CALLBACK ClipboardWin::WndProc(HWND hwnd, UINT msg, WPARAM wparam,
290 LPARAM lparam) {
291 if (msg == WM_CREATE) {
292 CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lparam);
293 ::SetWindowLongPtr(hwnd,
294 GWLP_USERDATA,
295 reinterpret_cast<LONG_PTR>(cs->lpCreateParams));
296 return 0;
297 }
298 ClipboardWin* clipboard =
299 reinterpret_cast<ClipboardWin*>(::GetWindowLongPtr(hwnd, GWLP_USERDATA));
300 switch (msg) {
301 case WM_CLIPBOARDUPDATE:
302 clipboard->OnClipboardUpdate();
303 return 0;
304 }
305 return ::DefWindowProc(hwnd, msg, wparam, lparam);
306 }
307
196 scoped_ptr<Clipboard> Clipboard::Create() { 308 scoped_ptr<Clipboard> Clipboard::Create() {
197 return scoped_ptr<Clipboard>(new ClipboardWin()); 309 return scoped_ptr<Clipboard>(new ClipboardWin());
198 } 310 }
199 311
200 } // namespace remoting 312 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/chromoting_host_context.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698