1 /*
2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "rtc_base/win32_window.h"
12 
13 #include "rtc_base/checks.h"
14 #include "rtc_base/logging.h"
15 
16 namespace rtc {
17 
18 ///////////////////////////////////////////////////////////////////////////////
19 // Win32Window
20 ///////////////////////////////////////////////////////////////////////////////
21 
22 static const wchar_t kWindowBaseClassName[] = L"RtcWindowBaseClass";
23 HINSTANCE Win32Window::instance_ = nullptr;
24 ATOM Win32Window::window_class_ = 0;
25 
Win32Window()26 Win32Window::Win32Window() : wnd_(nullptr) {}
27 
~Win32Window()28 Win32Window::~Win32Window() { RTC_DCHECK(nullptr == wnd_); }
29 
Create(HWND parent,const wchar_t * title,DWORD style,DWORD exstyle,int x,int y,int cx,int cy)30 bool Win32Window::Create(HWND parent, const wchar_t* title, DWORD style,
31                          DWORD exstyle, int x, int y, int cx, int cy) {
32   if (wnd_) {
33     // Window already exists.
34     return false;
35   }
36 
37   if (!window_class_) {
38     if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
39                                 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
40                             reinterpret_cast<LPCWSTR>(&Win32Window::WndProc),
41                             &instance_)) {
42       RTC_LOG_GLE(LS_ERROR) << "GetModuleHandleEx failed";
43       return false;
44     }
45 
46     // Register or reregister the class as necessary.  window_class_ == nullptr
47     // is not an infallible indicator that the class is unregistered.
48     WNDCLASSEXW wcex;
49     memset(&wcex, 0, sizeof(wcex));
50     wcex.cbSize = sizeof(wcex);
51     if (::GetClassInfoExW(instance_, kWindowBaseClassName, &wcex) &&
52         !::UnregisterClassW(kWindowBaseClassName, instance_)) {
53       RTC_LOG_GLE(LS_ERROR) << "UnregisterClass failed.";
54     }
55 
56     memset(&wcex, 0, sizeof(wcex));
57     wcex.cbSize = sizeof(wcex);
58     wcex.hInstance = instance_;
59     wcex.lpfnWndProc = &Win32Window::WndProc;
60     wcex.lpszClassName = kWindowBaseClassName;
61     window_class_ = ::RegisterClassExW(&wcex);
62     if (!window_class_) {
63       RTC_LOG_GLE(LS_ERROR) << "RegisterClassEx failed";
64       return false;
65     }
66   }
67   wnd_ = ::CreateWindowExW(exstyle, kWindowBaseClassName, title, style, x, y,
68                            cx, cy, parent, nullptr, instance_, this);
69   return (nullptr != wnd_);
70 }
71 
Destroy()72 void Win32Window::Destroy() {
73   const bool success = ::DestroyWindow(wnd_);
74   RTC_DCHECK(success);
75 }
76 
Shutdown()77 void Win32Window::Shutdown() {
78   if (window_class_) {
79     if (!::UnregisterClass(MAKEINTATOM(window_class_), instance_)) {
80       RTC_LOG_GLE(LS_ERROR) << "UnregisterClass failed.";
81     }
82     window_class_ = 0;
83   }
84 }
85 
OnMessage(UINT uMsg,WPARAM wParam,LPARAM lParam,LRESULT & result)86 bool Win32Window::OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam,
87                             LRESULT& result) {
88   switch (uMsg) {
89     case WM_CLOSE:
90       if (!OnClose()) {
91         result = 0;
92         return true;
93       }
94       break;
95   }
96   return false;
97 }
98 
OnClose()99 bool Win32Window::OnClose() { return true; }
100 
OnNcDestroy()101 void Win32Window::OnNcDestroy() {
102   // Do nothing. }
103 }
104 
WndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)105 LRESULT Win32Window::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
106                              LPARAM lParam) {
107   Win32Window* that =
108       reinterpret_cast<Win32Window*>(::GetWindowLongPtr(hwnd, GWLP_USERDATA));
109   if (!that && (WM_CREATE == uMsg)) {
110     CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lParam);
111     that = static_cast<Win32Window*>(cs->lpCreateParams);
112     that->wnd_ = hwnd;
113     ::SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(that));
114   }
115   if (that) {
116     LRESULT result;
117     bool handled = that->OnMessage(uMsg, wParam, lParam, result);
118     if (WM_DESTROY == uMsg) {
119       for (HWND child = ::GetWindow(hwnd, GW_CHILD); child;
120            child = ::GetWindow(child, GW_HWNDNEXT)) {
121         RTC_LOG(LS_INFO) << "Child window: " << static_cast<void*>(child);
122       }
123     }
124     if (WM_NCDESTROY == uMsg) {
125       ::SetWindowLongPtr(hwnd, GWLP_USERDATA, NULL);
126       that->wnd_ = nullptr;
127       that->OnNcDestroy();
128     }
129     if (handled) {
130       return result;
131     }
132   }
133   return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
134 }
135 
136 }  // namespace rtc
137