From 4cf04bb7b4082903880aaa85d4a7d63803fa36d5 Mon Sep 17 00:00:00 2001 From: "alexeypa@chromium.org" Date: Thu, 11 Jul 2013 09:22:38 +0000 Subject: ProcessSingleton now uses base::win::MessageWindow to create a message-only window. Collateral changes: - base::win::MessageWindow registes a single window class used by all message-only windows it creates. The class is registered via base::LazyInstance. - Added base::win::MessageWindow::FindWindow() wrapper used to find other message-only windows, including the other created by a different process. - Removed chrome::kMessageWindowClass constant. - chrome_frame_test::ContextMenuTest destroys the clipboard during the test teardown. Review URL: https://chromiumcodereview.appspot.com/18348025 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@211049 0039d316-1c4b-4281-b951-d872f2087c98 --- base/win/message_window.cc | 107 ++++++++++++++++++++++-------------- base/win/message_window.h | 13 ++++- base/win/message_window_unittest.cc | 13 +++++ 3 files changed, 90 insertions(+), 43 deletions(-) (limited to 'base') diff --git a/base/win/message_window.cc b/base/win/message_window.cc index 8a9c287..eb5e069 100644 --- a/base/win/message_window.cc +++ b/base/win/message_window.cc @@ -4,20 +4,72 @@ #include "base/win/message_window.h" +#include "base/lazy_instance.h" #include "base/logging.h" #include "base/process_util.h" -#include "base/strings/string16.h" -#include "base/strings/stringprintf.h" #include "base/win/wrapped_window_proc.h" -const wchar_t kClassNameFormat[] = L"Chrome_MessageWindow_%p"; +const wchar_t kMessageWindowClassName[] = L"Chrome_MessageWindow"; namespace base { namespace win { -MessageWindow::MessageWindow() +// Used along with LazyInstance to register a window class for message-only +// windows created by MessageWindow. +class MessageWindow::WindowClass { + public: + WindowClass(); + ~WindowClass(); + + ATOM atom() { return atom_; } + HINSTANCE instance() { return instance_; } + + private: + ATOM atom_; + HINSTANCE instance_; + + DISALLOW_COPY_AND_ASSIGN(WindowClass); +}; + +static LazyInstance g_window_class = + LAZY_INSTANCE_INITIALIZER; + +MessageWindow::WindowClass::WindowClass() : atom_(0), - window_(NULL) { + instance_(base::GetModuleFromAddress(&MessageWindow::WindowProc)) { + WNDCLASSEX window_class; + window_class.cbSize = sizeof(window_class); + window_class.style = 0; + window_class.lpfnWndProc = &base::win::WrappedWindowProc; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = instance_; + window_class.hIcon = NULL; + window_class.hCursor = NULL; + window_class.hbrBackground = NULL; + window_class.lpszMenuName = NULL; + window_class.lpszClassName = kMessageWindowClassName; + window_class.hIconSm = NULL; + atom_ = RegisterClassEx(&window_class); + if (atom_ == 0) { + LOG_GETLASTERROR(ERROR) + << "Failed to register the window class for a message-only window"; + } +} + +MessageWindow::WindowClass::~WindowClass() { + if (atom_ != 0) { + BOOL result = UnregisterClass(MAKEINTATOM(atom_), instance_); + // Hitting this DCHECK usually means that some MessageWindow objects were + // leaked. For example not calling + // ui::Clipboard::DestroyClipboardForCurrentThread() results in a leaked + // MessageWindow. + DCHECK(result); + } +} + +MessageWindow::MessageWindow() + : window_(NULL) { } MessageWindow::~MessageWindow() { @@ -27,13 +79,6 @@ MessageWindow::~MessageWindow() { BOOL result = DestroyWindow(window_); DCHECK(result); } - - if (atom_ != 0) { - BOOL result = UnregisterClass( - MAKEINTATOM(atom_), - base::GetModuleFromAddress(&MessageWindow::WindowProc)); - DCHECK(result); - } } bool MessageWindow::Create(const MessageCallback& message_callback) { @@ -45,41 +90,23 @@ bool MessageWindow::CreateNamed(const MessageCallback& message_callback, return DoCreate(message_callback, window_name.c_str()); } +// static +HWND MessageWindow::FindWindow(const string16& window_name) { + return FindWindowEx(HWND_MESSAGE, NULL, kMessageWindowClassName, + window_name.c_str()); +} + bool MessageWindow::DoCreate(const MessageCallback& message_callback, - const wchar_t* window_name) { + const wchar_t* window_name) { DCHECK(CalledOnValidThread()); - DCHECK(!atom_); DCHECK(message_callback_.is_null()); DCHECK(!window_); message_callback_ = message_callback; - // Register a separate window class for each instance of |MessageWindow|. - string16 class_name = base::StringPrintf(kClassNameFormat, this); - HINSTANCE instance = base::GetModuleFromAddress(&MessageWindow::WindowProc); - - WNDCLASSEX window_class; - window_class.cbSize = sizeof(window_class); - window_class.style = 0; - window_class.lpfnWndProc = &base::win::WrappedWindowProc; - window_class.cbClsExtra = 0; - window_class.cbWndExtra = 0; - window_class.hInstance = instance; - window_class.hIcon = NULL; - window_class.hCursor = NULL; - window_class.hbrBackground = NULL; - window_class.lpszMenuName = NULL; - window_class.lpszClassName = class_name.c_str(); - window_class.hIconSm = NULL; - atom_ = RegisterClassEx(&window_class); - if (atom_ == 0) { - LOG_GETLASTERROR(ERROR) - << "Failed to register the window class for a message-only window"; - return false; - } - - window_ = CreateWindow(MAKEINTATOM(atom_), window_name, 0, 0, 0, 0, 0, - HWND_MESSAGE, 0, instance, this); + WindowClass& window_class = g_window_class.Get(); + window_ = CreateWindow(MAKEINTATOM(window_class.atom()), window_name, 0, 0, 0, + 0, 0, HWND_MESSAGE, 0, window_class.instance(), this); if (!window_) { LOG_GETLASTERROR(ERROR) << "Failed to create a message-only window"; return false; diff --git a/base/win/message_window.h b/base/win/message_window.h index 4fd5074..ae0c6f0 100644 --- a/base/win/message_window.h +++ b/base/win/message_window.h @@ -20,6 +20,9 @@ namespace win { // Implements a message-only window. class BASE_EXPORT MessageWindow : public base::NonThreadSafe { public: + // Used to register a process-wide message window class. + class WindowClass; + // Implement this callback to handle messages received by the message window. // If the callback returns |false|, the first four parameters are passed to // DefWindowProc(). Otherwise, |*result| is returned by the window procedure. @@ -41,7 +44,14 @@ class BASE_EXPORT MessageWindow : public base::NonThreadSafe { HWND hwnd() const { return window_; } + // Retrieves a handle of the first message-only window with matching + // |window_name|. + static HWND FindWindow(const string16& window_name); + private: + // Give |WindowClass| access to WindowProc(). + friend class WindowClass; + // Contains the actual window creation code. bool DoCreate(const MessageCallback& message_callback, const wchar_t* window_name); @@ -50,9 +60,6 @@ class BASE_EXPORT MessageWindow : public base::NonThreadSafe { static LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); - // Atom representing the registered window class. - ATOM atom_; - // Invoked to handle messages received by the window. MessageCallback message_callback_; diff --git a/base/win/message_window_unittest.cc b/base/win/message_window_unittest.cc index c933ef7..00248bf 100644 --- a/base/win/message_window_unittest.cc +++ b/base/win/message_window_unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/bind.h" +#include "base/guid.h" #include "base/strings/utf_string_conversions.h" #include "base/win/message_window.h" #include "testing/gmock/include/gmock/gmock.h" @@ -31,6 +32,7 @@ TEST(MessageWindowTest, Create) { EXPECT_TRUE(window.Create(base::Bind(&HandleMessage))); } +// Checks that a named window can be created. TEST(MessageWindowTest, CreateNamed) { win::MessageWindow window; EXPECT_TRUE(window.CreateNamed(base::Bind(&HandleMessage), @@ -45,4 +47,15 @@ TEST(MessageWindowTest, SendMessage) { EXPECT_EQ(SendMessage(window.hwnd(), WM_USER, 100, 0), 100); } +// Verifies that a named window can be found by name. +TEST(MessageWindowTest, FindWindow) { + string16 name = UTF8ToUTF16(base::GenerateGUID()); + win::MessageWindow window; + EXPECT_TRUE(window.CreateNamed(base::Bind(&HandleMessage), name)); + + HWND hwnd = win::MessageWindow::FindWindow(name); + EXPECT_TRUE(hwnd != NULL); + EXPECT_EQ(SendMessage(hwnd, WM_USER, 200, 0), 200); +} + } // namespace base -- cgit v1.1