Home | History | Annotate | Download | only in win
      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     PLOG(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     PLOG(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