1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/win/message_window.h" 6 7 #include "base/lazy_instance.h" 8 #include "base/logging.h" 9 #include "base/process/memory.h" 10 #include "base/win/wrapped_window_proc.h" 11 12 const wchar_t kMessageWindowClassName[] = L"Chrome_MessageWindow"; 13 14 namespace base { 15 namespace win { 16 17 // Used along with LazyInstance to register a window class for message-only 18 // windows created by MessageWindow. 19 class MessageWindow::WindowClass { 20 public: 21 WindowClass(); 22 ~WindowClass(); 23 24 ATOM atom() { return atom_; } 25 HINSTANCE instance() { return instance_; } 26 27 private: 28 ATOM atom_; 29 HINSTANCE instance_; 30 31 DISALLOW_COPY_AND_ASSIGN(WindowClass); 32 }; 33 34 static LazyInstance<MessageWindow::WindowClass> g_window_class = 35 LAZY_INSTANCE_INITIALIZER; 36 37 MessageWindow::WindowClass::WindowClass() 38 : atom_(0), 39 instance_(base::GetModuleFromAddress(&MessageWindow::WindowProc)) { 40 WNDCLASSEX window_class; 41 window_class.cbSize = sizeof(window_class); 42 window_class.style = 0; 43 window_class.lpfnWndProc = &base::win::WrappedWindowProc<WindowProc>; 44 window_class.cbClsExtra = 0; 45 window_class.cbWndExtra = 0; 46 window_class.hInstance = instance_; 47 window_class.hIcon = NULL; 48 window_class.hCursor = NULL; 49 window_class.hbrBackground = NULL; 50 window_class.lpszMenuName = NULL; 51 window_class.lpszClassName = kMessageWindowClassName; 52 window_class.hIconSm = NULL; 53 atom_ = RegisterClassEx(&window_class); 54 if (atom_ == 0) { 55 LOG_GETLASTERROR(ERROR) 56 << "Failed to register the window class for a message-only window"; 57 } 58 } 59 60 MessageWindow::WindowClass::~WindowClass() { 61 if (atom_ != 0) { 62 BOOL result = UnregisterClass(MAKEINTATOM(atom_), instance_); 63 // Hitting this DCHECK usually means that some MessageWindow objects were 64 // leaked. For example not calling 65 // ui::Clipboard::DestroyClipboardForCurrentThread() results in a leaked 66 // MessageWindow. 67 DCHECK(result); 68 } 69 } 70 71 MessageWindow::MessageWindow() 72 : window_(NULL) { 73 } 74 75 MessageWindow::~MessageWindow() { 76 DCHECK(CalledOnValidThread()); 77 78 if (window_ != NULL) { 79 BOOL result = DestroyWindow(window_); 80 DCHECK(result); 81 } 82 } 83 84 bool MessageWindow::Create(const MessageCallback& message_callback) { 85 return DoCreate(message_callback, NULL); 86 } 87 88 bool MessageWindow::CreateNamed(const MessageCallback& message_callback, 89 const string16& window_name) { 90 return DoCreate(message_callback, window_name.c_str()); 91 } 92 93 // static 94 HWND MessageWindow::FindWindow(const string16& window_name) { 95 return FindWindowEx(HWND_MESSAGE, NULL, kMessageWindowClassName, 96 window_name.c_str()); 97 } 98 99 bool MessageWindow::DoCreate(const MessageCallback& message_callback, 100 const wchar_t* window_name) { 101 DCHECK(CalledOnValidThread()); 102 DCHECK(message_callback_.is_null()); 103 DCHECK(!window_); 104 105 message_callback_ = message_callback; 106 107 WindowClass& window_class = g_window_class.Get(); 108 window_ = CreateWindow(MAKEINTATOM(window_class.atom()), window_name, 0, 0, 0, 109 0, 0, HWND_MESSAGE, 0, window_class.instance(), this); 110 if (!window_) { 111 LOG_GETLASTERROR(ERROR) << "Failed to create a message-only window"; 112 return false; 113 } 114 115 return true; 116 } 117 118 // static 119 LRESULT CALLBACK MessageWindow::WindowProc(HWND hwnd, 120 UINT message, 121 WPARAM wparam, 122 LPARAM lparam) { 123 MessageWindow* self = reinterpret_cast<MessageWindow*>( 124 GetWindowLongPtr(hwnd, GWLP_USERDATA)); 125 126 switch (message) { 127 // Set up the self before handling WM_CREATE. 128 case WM_CREATE: { 129 CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lparam); 130 self = reinterpret_cast<MessageWindow*>(cs->lpCreateParams); 131 132 // Make |hwnd| available to the message handler. At this point the control 133 // hasn't returned from CreateWindow() yet. 134 self->window_ = hwnd; 135 136 // Store pointer to the self to the window's user data. 137 SetLastError(ERROR_SUCCESS); 138 LONG_PTR result = SetWindowLongPtr( 139 hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(self)); 140 CHECK(result != 0 || GetLastError() == ERROR_SUCCESS); 141 break; 142 } 143 144 // Clear the pointer to stop calling the self once WM_DESTROY is 145 // received. 146 case WM_DESTROY: { 147 SetLastError(ERROR_SUCCESS); 148 LONG_PTR result = SetWindowLongPtr(hwnd, GWLP_USERDATA, NULL); 149 CHECK(result != 0 || GetLastError() == ERROR_SUCCESS); 150 break; 151 } 152 } 153 154 // Handle the message. 155 if (self) { 156 LRESULT message_result; 157 if (self->message_callback_.Run(message, wparam, lparam, &message_result)) 158 return message_result; 159 } 160 161 return DefWindowProc(hwnd, message, wparam, lparam); 162 } 163 164 } // namespace win 165 } // namespace base 166