• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4 
5 #include "tests/cefclient/browser/main_message_loop_multithreaded_win.h"
6 
7 #include "include/base/cef_callback.h"
8 #include "include/base/cef_logging.h"
9 #include "include/cef_app.h"
10 #include "tests/cefclient/browser/resource.h"
11 #include "tests/shared/browser/util_win.h"
12 
13 namespace client {
14 
15 namespace {
16 
17 const wchar_t kWndClass[] = L"Client_MessageWindow";
18 const wchar_t kTaskMessageName[] = L"Client_CustomTask";
19 
20 }  // namespace
21 
MainMessageLoopMultithreadedWin()22 MainMessageLoopMultithreadedWin::MainMessageLoopMultithreadedWin()
23     : thread_id_(base::PlatformThread::CurrentId()),
24       task_message_id_(RegisterWindowMessage(kTaskMessageName)),
25       dialog_hwnd_(nullptr),
26       message_hwnd_(nullptr) {}
27 
~MainMessageLoopMultithreadedWin()28 MainMessageLoopMultithreadedWin::~MainMessageLoopMultithreadedWin() {
29   DCHECK(RunsTasksOnCurrentThread());
30   DCHECK(!message_hwnd_);
31   DCHECK(queued_tasks_.empty());
32 }
33 
Run()34 int MainMessageLoopMultithreadedWin::Run() {
35   DCHECK(RunsTasksOnCurrentThread());
36 
37   HINSTANCE hInstance = ::GetModuleHandle(nullptr);
38 
39   {
40     base::AutoLock lock_scope(lock_);
41 
42     // Create the hidden window for message processing.
43     message_hwnd_ = CreateMessageWindow(hInstance);
44     CHECK(message_hwnd_);
45 
46     // Store a pointer to |this| in the window's user data.
47     SetUserDataPtr(message_hwnd_, this);
48 
49     // Execute any tasks that are currently queued.
50     while (!queued_tasks_.empty()) {
51       PostTaskInternal(queued_tasks_.front());
52       queued_tasks_.pop();
53     }
54   }
55 
56   HACCEL hAccelTable =
57       LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CEFCLIENT));
58 
59   MSG msg;
60 
61   // Run the application message loop.
62   while (GetMessage(&msg, nullptr, 0, 0)) {
63     // Allow processing of dialog messages.
64     if (dialog_hwnd_ && IsDialogMessage(dialog_hwnd_, &msg))
65       continue;
66 
67     if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
68       TranslateMessage(&msg);
69       DispatchMessage(&msg);
70     }
71   }
72 
73   {
74     base::AutoLock lock_scope(lock_);
75 
76     // Destroy the message window.
77     DestroyWindow(message_hwnd_);
78     message_hwnd_ = nullptr;
79   }
80 
81   return static_cast<int>(msg.wParam);
82 }
83 
Quit()84 void MainMessageLoopMultithreadedWin::Quit() {
85   // Execute PostQuitMessage(0) on the main thread.
86   PostClosure(base::BindOnce(::PostQuitMessage, 0));
87 }
88 
PostTask(CefRefPtr<CefTask> task)89 void MainMessageLoopMultithreadedWin::PostTask(CefRefPtr<CefTask> task) {
90   base::AutoLock lock_scope(lock_);
91   PostTaskInternal(task);
92 }
93 
RunsTasksOnCurrentThread() const94 bool MainMessageLoopMultithreadedWin::RunsTasksOnCurrentThread() const {
95   return (thread_id_ == base::PlatformThread::CurrentId());
96 }
97 
SetCurrentModelessDialog(HWND hWndDialog)98 void MainMessageLoopMultithreadedWin::SetCurrentModelessDialog(
99     HWND hWndDialog) {
100   DCHECK(RunsTasksOnCurrentThread());
101 
102 #if DCHECK_IS_ON()
103   if (hWndDialog) {
104     // A new dialog reference should not be set while one is currently set.
105     DCHECK(!dialog_hwnd_);
106   }
107 #endif
108   dialog_hwnd_ = hWndDialog;
109 }
110 
111 // static
CreateMessageWindow(HINSTANCE hInstance)112 HWND MainMessageLoopMultithreadedWin::CreateMessageWindow(HINSTANCE hInstance) {
113   WNDCLASSEX wc = {0};
114   wc.cbSize = sizeof(wc);
115   wc.lpfnWndProc = MessageWndProc;
116   wc.hInstance = hInstance;
117   wc.lpszClassName = kWndClass;
118   RegisterClassEx(&wc);
119 
120   return CreateWindow(kWndClass, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hInstance,
121                       0);
122 }
123 
124 // static
125 LRESULT CALLBACK
MessageWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)126 MainMessageLoopMultithreadedWin::MessageWndProc(HWND hWnd,
127                                                 UINT message,
128                                                 WPARAM wParam,
129                                                 LPARAM lParam) {
130   MainMessageLoopMultithreadedWin* self =
131       GetUserDataPtr<MainMessageLoopMultithreadedWin*>(hWnd);
132 
133   if (self && message == self->task_message_id_) {
134     // Execute the task.
135     CefTask* task = reinterpret_cast<CefTask*>(wParam);
136     task->Execute();
137 
138     // Release the reference added in PostTaskInternal. This will likely result
139     // in |task| being deleted.
140     task->Release();
141   } else {
142     switch (message) {
143       case WM_NCDESTROY:
144         // Clear the reference to |self|.
145         SetUserDataPtr(hWnd, nullptr);
146         break;
147     }
148   }
149 
150   return DefWindowProc(hWnd, message, wParam, lParam);
151 }
152 
PostTaskInternal(CefRefPtr<CefTask> task)153 void MainMessageLoopMultithreadedWin::PostTaskInternal(
154     CefRefPtr<CefTask> task) {
155   lock_.AssertAcquired();
156 
157   if (!message_hwnd_) {
158     // Queue the task until the message loop starts running.
159     queued_tasks_.push(task);
160     return;
161   }
162 
163   // Add a reference that will be released in MessageWndProc.
164   task->AddRef();
165 
166   // Post the task for execution by the message window.
167   PostMessage(message_hwnd_, task_message_id_,
168               reinterpret_cast<WPARAM>(task.get()), 0);
169 }
170 
171 }  // namespace client
172