1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright 2013 The Chromium Authors. All rights reserved. 2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// found in the LICENSE file. 4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/win/message_window.h" 6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 77dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/lazy_instance.h" 8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/logging.h" 958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch#include "base/process/memory.h" 10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/win/wrapped_window_proc.h" 11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochconst wchar_t kMessageWindowClassName[] = L"Chrome_MessageWindow"; 13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace base { 15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace win { 16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Used along with LazyInstance to register a window class for message-only 187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// windows created by MessageWindow. 197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochclass MessageWindow::WindowClass { 207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch public: 217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch WindowClass(); 227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch ~WindowClass(); 237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch ATOM atom() { return atom_; } 257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch HINSTANCE instance() { return instance_; } 267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch private: 287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch ATOM atom_; 297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch HINSTANCE instance_; 307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch DISALLOW_COPY_AND_ASSIGN(WindowClass); 327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}; 337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochstatic LazyInstance<MessageWindow::WindowClass> g_window_class = 357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch LAZY_INSTANCE_INITIALIZER; 367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 377dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochMessageWindow::WindowClass::WindowClass() 38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch : atom_(0), 397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch instance_(base::GetModuleFromAddress(&MessageWindow::WindowProc)) { 407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch WNDCLASSEX window_class; 417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch window_class.cbSize = sizeof(window_class); 427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch window_class.style = 0; 437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch window_class.lpfnWndProc = &base::win::WrappedWindowProc<WindowProc>; 447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch window_class.cbClsExtra = 0; 457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch window_class.cbWndExtra = 0; 467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch window_class.hInstance = instance_; 477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch window_class.hIcon = NULL; 487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch window_class.hCursor = NULL; 497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch window_class.hbrBackground = NULL; 507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch window_class.lpszMenuName = NULL; 517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch window_class.lpszClassName = kMessageWindowClassName; 527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch window_class.hIconSm = NULL; 537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch atom_ = RegisterClassEx(&window_class); 547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (atom_ == 0) { 557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch LOG_GETLASTERROR(ERROR) 567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch << "Failed to register the window class for a message-only window"; 577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } 587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch} 597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 607dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochMessageWindow::WindowClass::~WindowClass() { 617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (atom_ != 0) { 627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch BOOL result = UnregisterClass(MAKEINTATOM(atom_), instance_); 637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // Hitting this DCHECK usually means that some MessageWindow objects were 647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // leaked. For example not calling 657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // ui::Clipboard::DestroyClipboardForCurrentThread() results in a leaked 667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // MessageWindow. 677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch DCHECK(result); 687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } 697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch} 707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 717dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochMessageWindow::MessageWindow() 727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch : window_(NULL) { 73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochMessageWindow::~MessageWindow() { 76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(CalledOnValidThread()); 77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (window_ != NULL) { 79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch BOOL result = DestroyWindow(window_); 80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(result); 81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool MessageWindow::Create(const MessageCallback& message_callback) { 85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return DoCreate(message_callback, NULL); 86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool MessageWindow::CreateNamed(const MessageCallback& message_callback, 89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const string16& window_name) { 90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return DoCreate(message_callback, window_name.c_str()); 91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// static 947dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochHWND MessageWindow::FindWindow(const string16& window_name) { 957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return FindWindowEx(HWND_MESSAGE, NULL, kMessageWindowClassName, 967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch window_name.c_str()); 977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch} 987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool MessageWindow::DoCreate(const MessageCallback& message_callback, 1007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch const wchar_t* window_name) { 101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(CalledOnValidThread()); 102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(message_callback_.is_null()); 103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(!window_); 104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch message_callback_ = message_callback; 106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 1077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch WindowClass& window_class = g_window_class.Get(); 1087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch window_ = CreateWindow(MAKEINTATOM(window_class.atom()), window_name, 0, 0, 0, 1097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 0, 0, HWND_MESSAGE, 0, window_class.instance(), this); 110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!window_) { 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch LOG_GETLASTERROR(ERROR) << "Failed to create a message-only window"; 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// static 119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochLRESULT CALLBACK MessageWindow::WindowProc(HWND hwnd, 120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch UINT message, 121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch WPARAM wparam, 122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch LPARAM lparam) { 123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch MessageWindow* self = reinterpret_cast<MessageWindow*>( 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch GetWindowLongPtr(hwnd, GWLP_USERDATA)); 125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch switch (message) { 127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Set up the self before handling WM_CREATE. 128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch case WM_CREATE: { 129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lparam); 130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch self = reinterpret_cast<MessageWindow*>(cs->lpCreateParams); 131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Make |hwnd| available to the message handler. At this point the control 133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // hasn't returned from CreateWindow() yet. 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch self->window_ = hwnd; 135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Store pointer to the self to the window's user data. 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SetLastError(ERROR_SUCCESS); 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch LONG_PTR result = SetWindowLongPtr( 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(self)); 140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CHECK(result != 0 || GetLastError() == ERROR_SUCCESS); 141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch break; 142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Clear the pointer to stop calling the self once WM_DESTROY is 145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // received. 146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch case WM_DESTROY: { 147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SetLastError(ERROR_SUCCESS); 148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch LONG_PTR result = SetWindowLongPtr(hwnd, GWLP_USERDATA, NULL); 149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CHECK(result != 0 || GetLastError() == ERROR_SUCCESS); 150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch break; 151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Handle the message. 155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (self) { 156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch LRESULT message_result; 157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (self->message_callback_.Run(message, wparam, lparam, &message_result)) 158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return message_result; 159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return DefWindowProc(hwnd, message, wparam, lparam); 162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} // namespace win 165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} // namespace base 166