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