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

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

Issue 13142002: Moved code implementing message-only windows to a dedicated class (Windows only). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 8 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
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/threading/platform_thread.h" 14 #include "base/threading/platform_thread.h"
15 #include "base/utf_string_conversions.h" 15 #include "base/utf_string_conversions.h"
16 #include "base/win/scoped_hglobal.h" 16 #include "base/win/scoped_hglobal.h"
17 #include "base/win/windows_version.h" 17 #include "base/win/windows_version.h"
18 #include "base/win/wrapped_window_proc.h" 18 #include "base/win/wrapped_window_proc.h"
19 #include "remoting/base/constants.h" 19 #include "remoting/base/constants.h"
20 #include "remoting/base/util.h" 20 #include "remoting/base/util.h"
21 #include "remoting/host/win/message_window.h"
21 #include "remoting/proto/event.pb.h" 22 #include "remoting/proto/event.pb.h"
22 #include "remoting/protocol/clipboard_stub.h" 23 #include "remoting/protocol/clipboard_stub.h"
23 24
24 namespace { 25 namespace {
25 26
26 const WCHAR kWindowClassName[] = L"clipboardWindowClass";
27 const WCHAR kWindowName[] = L"clipboardWindow";
28
29 // A scoper class that opens and closes the clipboard. 27 // A scoper class that opens and closes the clipboard.
30 // This class was adapted from the ScopedClipboard class in 28 // This class was adapted from the ScopedClipboard class in
31 // ui/base/clipboard/clipboard_win.cc. 29 // ui/base/clipboard/clipboard_win.cc.
32 class ScopedClipboard { 30 class ScopedClipboard {
33 public: 31 public:
34 ScopedClipboard() : opened_(false) { 32 ScopedClipboard() : opened_(false) {
35 } 33 }
36 34
37 ~ScopedClipboard() { 35 ~ScopedClipboard() {
38 if (opened_) { 36 if (opened_) {
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 bool opened_; 93 bool opened_;
96 }; 94 };
97 95
98 typedef BOOL (WINAPI AddClipboardFormatListenerFn)(HWND); 96 typedef BOOL (WINAPI AddClipboardFormatListenerFn)(HWND);
99 typedef BOOL (WINAPI RemoveClipboardFormatListenerFn)(HWND); 97 typedef BOOL (WINAPI RemoveClipboardFormatListenerFn)(HWND);
100 98
101 } // namespace 99 } // namespace
102 100
103 namespace remoting { 101 namespace remoting {
104 102
105 class ClipboardWin : public Clipboard { 103 class ClipboardWin : public Clipboard,
104 public win::MessageWindow::Delegate {
106 public: 105 public:
107 ClipboardWin(); 106 ClipboardWin();
108 107
109 virtual void Start( 108 virtual void Start(
110 scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE; 109 scoped_ptr<protocol::ClipboardStub> client_clipboard) OVERRIDE;
111 virtual void InjectClipboardEvent( 110 virtual void InjectClipboardEvent(
112 const protocol::ClipboardEvent& event) OVERRIDE; 111 const protocol::ClipboardEvent& event) OVERRIDE;
113 virtual void Stop() OVERRIDE; 112 virtual void Stop() OVERRIDE;
114 113
115 private: 114 private:
116 void OnClipboardUpdate(); 115 void OnClipboardUpdate();
117 bool HaveClipboardListenerApi();
118 116
119 static bool RegisterWindowClass(); 117 // win::MessageWindow::Delegate interface.
120 static LRESULT CALLBACK WndProc(HWND hwmd, UINT msg, WPARAM wParam, 118 virtual bool HandleMessage(UINT message, WPARAM wparam, LPARAM lparam,
121 LPARAM lParam); 119 LRESULT* result) OVERRIDE;
122 120
123 scoped_ptr<protocol::ClipboardStub> client_clipboard_; 121 scoped_ptr<protocol::ClipboardStub> client_clipboard_;
124 HWND hwnd_;
125 AddClipboardFormatListenerFn* add_clipboard_format_listener_; 122 AddClipboardFormatListenerFn* add_clipboard_format_listener_;
126 RemoveClipboardFormatListenerFn* remove_clipboard_format_listener_; 123 RemoveClipboardFormatListenerFn* remove_clipboard_format_listener_;
127 bool load_functions_tried_; 124
125 // Used to subsribe to WM_CLIPBOARDUPDATE messages.
dcaiafa 2013/03/28 23:25:35 nit: subscribe
alexeypa (please no reviews) 2013/03/29 16:57:01 Done.
126 scoped_ptr<win::MessageWindow> window_;
128 127
129 DISALLOW_COPY_AND_ASSIGN(ClipboardWin); 128 DISALLOW_COPY_AND_ASSIGN(ClipboardWin);
130 }; 129 };
131 130
132 ClipboardWin::ClipboardWin() 131 ClipboardWin::ClipboardWin()
133 : hwnd_(NULL), 132 : add_clipboard_format_listener_(NULL),
134 add_clipboard_format_listener_(NULL), 133 remove_clipboard_format_listener_(NULL) {
135 remove_clipboard_format_listener_(NULL),
136 load_functions_tried_(false) {
137 } 134 }
138 135
139 void ClipboardWin::Start( 136 void ClipboardWin::Start(
140 scoped_ptr<protocol::ClipboardStub> client_clipboard) { 137 scoped_ptr<protocol::ClipboardStub> client_clipboard) {
138 DCHECK(!add_clipboard_format_listener_);
139 DCHECK(!remove_clipboard_format_listener_);
140 DCHECK(!window_);
141
141 client_clipboard_.swap(client_clipboard); 142 client_clipboard_.swap(client_clipboard);
142 143
143 if (!load_functions_tried_) { 144 // user32.dll is statically linked.
144 load_functions_tried_ = true; 145 HMODULE user32 = GetModuleHandle(L"user32.dll");
145 HMODULE user32_module = ::GetModuleHandle(L"user32.dll"); 146 CHECK(user32);
146 if (!user32_module) { 147
147 LOG(WARNING) << "Couldn't find user32.dll."; 148 add_clipboard_format_listener_ =
148 } else { 149 reinterpret_cast<AddClipboardFormatListenerFn*>(
149 add_clipboard_format_listener_ = 150 GetProcAddress(user32, "AddClipboardFormatListener"));
150 reinterpret_cast<AddClipboardFormatListenerFn*>( 151 if (add_clipboard_format_listener_) {
151 ::GetProcAddress(user32_module, "AddClipboardFormatListener")); 152 remove_clipboard_format_listener_ =
152 remove_clipboard_format_listener_ = 153 reinterpret_cast<RemoveClipboardFormatListenerFn*>(
153 reinterpret_cast<RemoveClipboardFormatListenerFn*>( 154 GetProcAddress(user32, "RemoveClipboardFormatListener"));
154 ::GetProcAddress(user32_module, "RemoveClipboardFormatListener")); 155 // If AddClipboardFormatListener() present, RemoveClipboardFormatListener()
155 if (!HaveClipboardListenerApi()) { 156 // should be available too.
156 LOG(WARNING) << "Couldn't load AddClipboardFormatListener or " 157 CHECK(remove_clipboard_format_listener_);
157 << "RemoveClipboardFormatListener."; 158 } else {
158 } 159 LOG(WARNING) << "AddClipboardFormatListener() is not available.";
159 }
160 } 160 }
161 161
162 if (!RegisterWindowClass()) { 162 window_.reset(new win::MessageWindow());
163 LOG(ERROR) << "Couldn't register clipboard window class."; 163 if (!window_->Create(this)) {
164 return;
165 }
166 hwnd_ = ::CreateWindow(kWindowClassName,
167 kWindowName,
168 0, 0, 0, 0, 0,
169 HWND_MESSAGE,
170 NULL,
171 base::GetModuleFromAddress(&WndProc),
172 this);
173 if (!hwnd_) {
174 LOG(ERROR) << "Couldn't create clipboard window."; 164 LOG(ERROR) << "Couldn't create clipboard window.";
165 window_.reset();
175 return; 166 return;
176 } 167 }
177 168
178 if (HaveClipboardListenerApi()) { 169 if (add_clipboard_format_listener_) {
179 if (!(*add_clipboard_format_listener_)(hwnd_)) { 170 if (!(*add_clipboard_format_listener_)(window_->hwnd())) {
180 LOG(WARNING) << "AddClipboardFormatListener() failed: " << GetLastError(); 171 LOG(WARNING) << "AddClipboardFormatListener() failed: " << GetLastError();
181 } 172 }
182 } 173 }
183 } 174 }
184 175
185 void ClipboardWin::Stop() { 176 void ClipboardWin::Stop() {
186 client_clipboard_.reset(); 177 client_clipboard_.reset();
187 178
188 if (hwnd_) { 179 if (window_ && remove_clipboard_format_listener_)
189 if (HaveClipboardListenerApi()) { 180 (*remove_clipboard_format_listener_)(window_->hwnd());
190 (*remove_clipboard_format_listener_)(hwnd_); 181
191 } 182 window_.reset();
192 ::DestroyWindow(hwnd_);
193 hwnd_ = NULL;
194 }
195 } 183 }
196 184
197 void ClipboardWin::InjectClipboardEvent( 185 void ClipboardWin::InjectClipboardEvent(
198 const protocol::ClipboardEvent& event) { 186 const protocol::ClipboardEvent& event) {
199 if (!hwnd_) 187 if (!window_)
200 return; 188 return;
201 189
202 // Currently we only handle UTF-8 text. 190 // Currently we only handle UTF-8 text.
203 if (event.mime_type().compare(kMimeTypeTextUtf8) != 0) 191 if (event.mime_type().compare(kMimeTypeTextUtf8) != 0)
204 return; 192 return;
205 if (!StringIsUtf8(event.data().c_str(), event.data().length())) { 193 if (!StringIsUtf8(event.data().c_str(), event.data().length())) {
206 LOG(ERROR) << "ClipboardEvent: data is not UTF-8 encoded."; 194 LOG(ERROR) << "ClipboardEvent: data is not UTF-8 encoded.";
207 return; 195 return;
208 } 196 }
209 197
210 string16 text = UTF8ToUTF16(ReplaceLfByCrLf(event.data())); 198 string16 text = UTF8ToUTF16(ReplaceLfByCrLf(event.data()));
211 199
212 ScopedClipboard clipboard; 200 ScopedClipboard clipboard;
213 if (!clipboard.Init(hwnd_)) { 201 if (!clipboard.Init(window_->hwnd())) {
214 LOG(WARNING) << "Couldn't open the clipboard."; 202 LOG(WARNING) << "Couldn't open the clipboard.";
215 return; 203 return;
216 } 204 }
217 205
218 clipboard.Empty(); 206 clipboard.Empty();
219 207
220 HGLOBAL text_global = 208 HGLOBAL text_global =
221 ::GlobalAlloc(GMEM_MOVEABLE, (text.size() + 1) * sizeof(WCHAR)); 209 ::GlobalAlloc(GMEM_MOVEABLE, (text.size() + 1) * sizeof(WCHAR));
222 if (!text_global) { 210 if (!text_global) {
223 LOG(WARNING) << "Couldn't allocate global memory."; 211 LOG(WARNING) << "Couldn't allocate global memory.";
224 return; 212 return;
225 } 213 }
226 214
227 LPWSTR text_global_locked = 215 LPWSTR text_global_locked =
228 reinterpret_cast<LPWSTR>(::GlobalLock(text_global)); 216 reinterpret_cast<LPWSTR>(::GlobalLock(text_global));
229 memcpy(text_global_locked, text.data(), text.size() * sizeof(WCHAR)); 217 memcpy(text_global_locked, text.data(), text.size() * sizeof(WCHAR));
230 text_global_locked[text.size()] = (WCHAR)0; 218 text_global_locked[text.size()] = (WCHAR)0;
231 ::GlobalUnlock(text_global); 219 ::GlobalUnlock(text_global);
232 220
233 clipboard.SetData(CF_UNICODETEXT, text_global); 221 clipboard.SetData(CF_UNICODETEXT, text_global);
234 } 222 }
235 223
236 void ClipboardWin::OnClipboardUpdate() { 224 void ClipboardWin::OnClipboardUpdate() {
237 DCHECK(hwnd_); 225 DCHECK(window_);
238 226
239 if (::IsClipboardFormatAvailable(CF_UNICODETEXT)) { 227 if (::IsClipboardFormatAvailable(CF_UNICODETEXT)) {
240 string16 text; 228 string16 text;
241 // Add a scope, so that we keep the clipboard open for as short a time as 229 // Add a scope, so that we keep the clipboard open for as short a time as
242 // possible. 230 // possible.
243 { 231 {
244 ScopedClipboard clipboard; 232 ScopedClipboard clipboard;
245 if (!clipboard.Init(hwnd_)) { 233 if (!clipboard.Init(window_->hwnd())) {
246 LOG(WARNING) << "Couldn't open the clipboard." << GetLastError(); 234 LOG(WARNING) << "Couldn't open the clipboard." << GetLastError();
247 return; 235 return;
248 } 236 }
249 237
250 HGLOBAL text_global = clipboard.GetData(CF_UNICODETEXT); 238 HGLOBAL text_global = clipboard.GetData(CF_UNICODETEXT);
251 if (!text_global) { 239 if (!text_global) {
252 LOG(WARNING) << "Couldn't get data from the clipboard: " 240 LOG(WARNING) << "Couldn't get data from the clipboard: "
253 << GetLastError(); 241 << GetLastError();
254 return; 242 return;
255 } 243 }
256 244
257 base::win::ScopedHGlobal<WCHAR> text_lock(text_global); 245 base::win::ScopedHGlobal<WCHAR> text_lock(text_global);
258 if (!text_lock.get()) { 246 if (!text_lock.get()) {
259 LOG(WARNING) << "Couldn't lock clipboard data: " << GetLastError(); 247 LOG(WARNING) << "Couldn't lock clipboard data: " << GetLastError();
260 return; 248 return;
261 } 249 }
262 text.assign(text_lock.get()); 250 text.assign(text_lock.get());
263 } 251 }
264 252
265 protocol::ClipboardEvent event; 253 protocol::ClipboardEvent event;
266 event.set_mime_type(kMimeTypeTextUtf8); 254 event.set_mime_type(kMimeTypeTextUtf8);
267 event.set_data(ReplaceCrLfByLf(UTF16ToUTF8(text))); 255 event.set_data(ReplaceCrLfByLf(UTF16ToUTF8(text)));
268 256
269 if (client_clipboard_.get()) { 257 if (client_clipboard_.get()) {
270 client_clipboard_->InjectClipboardEvent(event); 258 client_clipboard_->InjectClipboardEvent(event);
271 } 259 }
272 } 260 }
273 } 261 }
274 262
275 bool ClipboardWin::HaveClipboardListenerApi() { 263 bool ClipboardWin::HandleMessage(
276 return add_clipboard_format_listener_ && remove_clipboard_format_listener_; 264 UINT message, WPARAM wparam, LPARAM lparam, LRESULT* result) {
277 } 265 if (message == WM_CLIPBOARDUPDATE) {
278 266 OnClipboardUpdate();
279 bool ClipboardWin::RegisterWindowClass() { 267 *result = 0;
280 // This method is only called on the UI thread, so it doesn't matter
281 // that the following test is not thread-safe.
282 static bool registered = false;
283 if (registered) {
284 return true; 268 return true;
285 } 269 }
286 270
287 WNDCLASSEX window_class; 271 return false;
288 base::win::InitializeWindowClass(
289 kWindowClassName,
290 base::win::WrappedWindowProc<WndProc>,
291 0, 0, 0, NULL, NULL, NULL, NULL, NULL,
292 &window_class);
293 if (!::RegisterClassEx(&window_class)) {
294 return false;
295 }
296
297 registered = true;
298 return true;
299 }
300
301 LRESULT CALLBACK ClipboardWin::WndProc(HWND hwnd, UINT msg, WPARAM wparam,
302 LPARAM lparam) {
303 if (msg == WM_CREATE) {
304 CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lparam);
305 ::SetWindowLongPtr(hwnd,
306 GWLP_USERDATA,
307 reinterpret_cast<LONG_PTR>(cs->lpCreateParams));
308 return 0;
309 }
310 ClipboardWin* clipboard =
311 reinterpret_cast<ClipboardWin*>(::GetWindowLongPtr(hwnd, GWLP_USERDATA));
312 switch (msg) {
313 case WM_CLIPBOARDUPDATE:
314 clipboard->OnClipboardUpdate();
315 return 0;
316 }
317 return ::DefWindowProc(hwnd, msg, wparam, lparam);
318 } 272 }
319 273
320 scoped_ptr<Clipboard> Clipboard::Create() { 274 scoped_ptr<Clipboard> Clipboard::Create() {
321 return scoped_ptr<Clipboard>(new ClipboardWin()); 275 return scoped_ptr<Clipboard>(new ClipboardWin());
322 } 276 }
323 277
324 } // namespace remoting 278 } // namespace remoting
OLDNEW
« no previous file with comments | « no previous file | remoting/host/local_input_monitor_win.cc » ('j') | remoting/host/local_input_monitor_win.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698