message_window.cc 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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. #include "base/win/message_window.h"
  5. #include <windows.h>
  6. #include <utility>
  7. #include "base/lazy_instance.h"
  8. #include "base/logging.h"
  9. #include "base/strings/string_util.h"
  10. #include "base/win/current_module.h"
  11. #include "base/win/wrapped_window_proc.h"
  12. // To avoid conflicts with the macro from the Windows SDK...
  13. #undef FindWindow
  14. const wchar_t kMessageWindowClassName[] = L"Chrome_MessageWindow";
  15. namespace base {
  16. namespace win {
  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(const WindowClass&) = delete;
  23. WindowClass& operator=(const WindowClass&) = delete;
  24. ~WindowClass();
  25. ATOM atom() { return atom_; }
  26. HINSTANCE instance() { return instance_; }
  27. private:
  28. ATOM atom_ = 0;
  29. HINSTANCE instance_ = CURRENT_MODULE();
  30. };
  31. static LazyInstance<MessageWindow::WindowClass>::DestructorAtExit
  32. g_window_class = LAZY_INSTANCE_INITIALIZER;
  33. MessageWindow::WindowClass::WindowClass() {
  34. WNDCLASSEX window_class;
  35. window_class.cbSize = sizeof(window_class);
  36. window_class.style = 0;
  37. window_class.lpfnWndProc = &WrappedWindowProc<WindowProc>;
  38. window_class.cbClsExtra = 0;
  39. window_class.cbWndExtra = 0;
  40. window_class.hInstance = instance_;
  41. window_class.hIcon = nullptr;
  42. window_class.hCursor = nullptr;
  43. window_class.hbrBackground = nullptr;
  44. window_class.lpszMenuName = nullptr;
  45. window_class.lpszClassName = kMessageWindowClassName;
  46. window_class.hIconSm = nullptr;
  47. atom_ = RegisterClassEx(&window_class);
  48. if (atom_ == 0) {
  49. PLOG(ERROR)
  50. << "Failed to register the window class for a message-only window";
  51. }
  52. }
  53. MessageWindow::WindowClass::~WindowClass() {
  54. if (atom_ != 0) {
  55. BOOL result = UnregisterClass(MAKEINTATOM(atom_), instance_);
  56. // Hitting this DCHECK usually means that some MessageWindow objects were
  57. // leaked. For example not calling
  58. // ui::Clipboard::DestroyClipboardForCurrentThread() results in a leaked
  59. // MessageWindow.
  60. DCHECK(result);
  61. }
  62. }
  63. MessageWindow::MessageWindow() = default;
  64. MessageWindow::~MessageWindow() {
  65. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  66. if (window_ != nullptr) {
  67. BOOL result = DestroyWindow(window_);
  68. DCHECK(result);
  69. }
  70. }
  71. bool MessageWindow::Create(MessageCallback message_callback) {
  72. return DoCreate(std::move(message_callback), nullptr);
  73. }
  74. bool MessageWindow::CreateNamed(MessageCallback message_callback,
  75. const std::wstring& window_name) {
  76. return DoCreate(std::move(message_callback), window_name.c_str());
  77. }
  78. // static
  79. HWND MessageWindow::FindWindow(const std::wstring& window_name) {
  80. return FindWindowEx(HWND_MESSAGE, nullptr, kMessageWindowClassName,
  81. window_name.c_str());
  82. }
  83. bool MessageWindow::DoCreate(MessageCallback message_callback,
  84. const wchar_t* window_name) {
  85. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  86. DCHECK(message_callback_.is_null());
  87. DCHECK(!window_);
  88. message_callback_ = std::move(message_callback);
  89. WindowClass& window_class = g_window_class.Get();
  90. window_ =
  91. CreateWindow(MAKEINTATOM(window_class.atom()), window_name, 0, 0, 0, 0, 0,
  92. HWND_MESSAGE, nullptr, window_class.instance(), this);
  93. if (!window_) {
  94. PLOG(ERROR) << "Failed to create a message-only window";
  95. return false;
  96. }
  97. return true;
  98. }
  99. // static
  100. LRESULT CALLBACK MessageWindow::WindowProc(HWND hwnd,
  101. UINT message,
  102. WPARAM wparam,
  103. LPARAM lparam) {
  104. MessageWindow* self =
  105. reinterpret_cast<MessageWindow*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
  106. switch (message) {
  107. // Set up the self before handling WM_CREATE.
  108. case WM_CREATE: {
  109. CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lparam);
  110. self = reinterpret_cast<MessageWindow*>(cs->lpCreateParams);
  111. // Make |hwnd| available to the message handler. At this point the control
  112. // hasn't returned from CreateWindow() yet.
  113. self->window_ = hwnd;
  114. // Store pointer to the self to the window's user data.
  115. SetLastError(ERROR_SUCCESS);
  116. LONG_PTR result = SetWindowLongPtr(hwnd, GWLP_USERDATA,
  117. reinterpret_cast<LONG_PTR>(self));
  118. CHECK(result != 0 || GetLastError() == ERROR_SUCCESS);
  119. break;
  120. }
  121. // Clear the pointer to stop calling the self once WM_DESTROY is
  122. // received.
  123. case WM_DESTROY: {
  124. SetLastError(ERROR_SUCCESS);
  125. LONG_PTR result = SetWindowLongPtr(hwnd, GWLP_USERDATA, NULL);
  126. CHECK(result != 0 || GetLastError() == ERROR_SUCCESS);
  127. break;
  128. }
  129. }
  130. // Handle the message.
  131. if (self) {
  132. LRESULT message_result;
  133. if (self->message_callback_.Run(message, wparam, lparam, &message_result))
  134. return message_result;
  135. }
  136. return DefWindowProc(hwnd, message, wparam, lparam);
  137. }
  138. } // namespace win
  139. } // namespace base