Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwindowswindowclassregistry.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#include <QtCore/qlibraryinfo.h>
8#include <QtCore/quuid.h>
9
12
13QT_BEGIN_NAMESPACE
14
15using namespace Qt::StringLiterals;
16
17Q_LOGGING_CATEGORY(lcQpaWindowClass, "qt.qpa.windowclass")
18
20
21QWindowsWindowClassRegistry::QWindowsWindowClassRegistry(WNDPROC defaultProcedure)
22 : m_defaultProcedure(defaultProcedure)
23{
24 m_instance = this;
25}
26
28{
29 unregisterWindowClasses();
30
31 m_instance = nullptr;
32}
33
38
39QString QWindowsWindowClassRegistry::classNamePrefix()
40{
41 static QString result;
42 if (result.isEmpty()) {
43 QTextStream str(&result);
44 str << "Qt" << QT_VERSION_MAJOR << QT_VERSION_MINOR << QT_VERSION_PATCH;
45 if (QLibraryInfo::isDebugBuild())
46 str << 'd';
47#ifdef QT_NAMESPACE
48# define xstr(s) str(s)
49# define str(s) #s
50 str << xstr(QT_NAMESPACE);
51# undef str
52# undef xstr
53#endif
54 }
55 return result;
56}
57
59{
60 QString className = description.name;
61
62 if (description.shouldAddPrefix)
63 className = classNamePrefix() + className;
64
65 // since multiple Qt versions can be used in one process
66 // each one has to have window class names with a unique name
67 // The first instance gets the unmodified name; if the class
68 // has already been registered by another instance of Qt then
69 // add a UUID. The check needs to be performed for each name
70 // in case new message windows are added (QTBUG-81347).
71 // Note: GetClassInfo() returns != 0 when a class exists.
72 if (shouldDecorateWindowClassName(className, description.procedure))
73 className += QUuid::createUuid().toString();
74
75 if (m_registeredWindowClasses.contains(className)) // already registered in our list
76 return className;
77
78 const auto appInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr));
79
80 WNDCLASSEX wc{};
81 wc.cbSize = sizeof(WNDCLASSEX);
82 wc.style = description.style;
83 wc.lpfnWndProc = description.procedure;
84 wc.hInstance = appInstance;
85 wc.hbrBackground = description.brush;
86 WindowClassIcons icons;
87 if (description.hasIcon) {
88 // Icons loaded from the application resources without LR_SHARED are owned by
89 // the caller and have to be destroyed with DestroyIcon() once the class is
90 // unregistered. The fallback is a shared system icon, which must not be destroyed.
91 icons.icon = static_cast<HICON>(LoadImage(appInstance, L"IDI_ICON1", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE));
92 if (icons.icon) {
93 int sw = GetSystemMetrics(SM_CXSMICON);
94 int sh = GetSystemMetrics(SM_CYSMICON);
95 icons.iconSmall = static_cast<HICON>(LoadImage(appInstance, L"IDI_ICON1", IMAGE_ICON, sw, sh, 0));
96 wc.hIcon = icons.icon;
97 wc.hIconSm = icons.iconSmall;
98 } else {
99 wc.hIcon = static_cast<HICON>(LoadImage(nullptr, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED));
100 }
101 }
102
103 wc.lpszClassName = reinterpret_cast<LPCWSTR>(className.utf16());
104 ATOM atom = RegisterClassEx(&wc);
105 if (!atom) {
106 qCWarning(lcQpaWindowClass) << "Failed to register window class" << className
107 << "(" << qt_error_string(-1) << ")";
108 if (icons.icon)
109 DestroyIcon(icons.icon);
110 if (icons.iconSmall)
111 DestroyIcon(icons.iconSmall);
112 icons = {};
113 }
114
115 m_registeredWindowClasses.insert(className, icons);
116
117 qCDebug(lcQpaWindowClass).nospace() << __FUNCTION__ << ' ' << className << ' ' << description << " atom=" << atom;
118
119 return className;
120}
121
123{
124 return registerWindowClass(QWindowsWindowClassDescription::fromWindow(window, m_defaultProcedure));
125}
126
128{
129 return registerWindowClass(QWindowsWindowClassDescription::fromName(name, procedure));
130}
131
132bool QWindowsWindowClassRegistry::shouldDecorateWindowClassName(const QString &name, WNDPROC procedure) const
133{
134 const auto appInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr));
135
136 WNDCLASS wc{};
137
138 return GetClassInfo(appInstance, reinterpret_cast<LPCWSTR>(name.utf16()), &wc) != FALSE
139 && wc.lpfnWndProc != procedure;
140}
141
142void QWindowsWindowClassRegistry::unregisterWindowClasses()
143{
144 const auto appInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr));
145
146 for (auto it = m_registeredWindowClasses.cbegin(), end = m_registeredWindowClasses.cend(); it != end; ++it) {
147 if (!UnregisterClass(reinterpret_cast<LPCWSTR>(it.key().utf16()), appInstance)) {
149 qCWarning(lcQpaWindowClass) << "Failed to unregister window class" << it.key()
150 << "(" << qt_error_string(-1) << ")";
151 continue; // the class is still in use and keeps referencing its icons
152 }
153 if (it->icon)
154 DestroyIcon(it->icon);
155 if (it->iconSmall)
156 DestroyIcon(it->iconSmall);
157 }
158 m_registeredWindowClasses.clear();
159}
160
161QT_END_NAMESPACE
Singleton container for all relevant information.
QString registerWindowClass(const QWindowsWindowClassDescription &description)
static QWindowsWindowClassRegistry * instance()
QString registerWindowClass(QString name, WNDPROC procedure)
QString registerWindowClass(const QWindow *window)
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")