[Interest] Qt 6.11 QWindowsWindowClassRegistry regression? Window class de-dup now checks un-prefixed name

Nuno Santos nuno.santos at imaginando.pt
Tue Jul 28 18:31:43 CEST 2026


Tor,

Thanks for your reply.

I’ve just created the issue:

https://qt-project.atlassian.net/browse/QTBUG-148623

I’ve used Claude Code to generate the bug report, forgive me its not perfectly formatted.

Thank you!

Best,

Nuno

> On 28 Jul 2026, at 17:04, Tor Arne Vestbø <Tor.arne.Vestbo at qt.io> wrote:
> 
> This sounds like a bug, please file a JIRA issue, thanks!
> 
>> On 28 Jul 2026, at 17:33, Nuno Santos via Interest <interest at qt-project.org> wrote:
>> 
>> Hi all,
>> 
>> We ship several audio plug-ins (VST2/VST3/AU) that each statically link Qt, built with a custom namespace (configure -qtnamespace <ours>). Multiple such plug-ins are routinely loaded into the same host process (e.g. Ableton Live)
>> 
>> the classic "several independent static-Qt instances in one process" scenario that -qtnamespace exists to support.
>> This has worked on Windows for many years. After moving to Qt 6.11, the second Qt-based plug-in loaded into a host now comes up with a blank/white UI. The logs show its Win32 window classes failing to register:
>> 
>> qt.qpa.windowclass: Failed to register window class
>> "Qt6110d<namespace>QWindowIcon" ( "Class already exists." )
>> ...
>> QWindowsContext::windowsProc: No Qt Window found for event 0xf
>> (WM_PAINT), hwnd=0x...
>> i.e. the second instance reuses the first instance's already-registered class (and therefore its WNDPROC), its windows' messages are delivered to the wrong Qt instance, and it never paints.
>> 
>> WHAT CHANGED
>> 
>> Bisecting src/plugins/platforms/windows:
>> 
>> Up to Qt 6.10, QWindowsContext::registerWindowClass(QString cname, WNDPROC proc, ...) appended a UUID to the final, prefixed class name whenever it detected the class already existed with a different WNDPROC (i.e. another Qt instance in the process):
>> 
>> const bool classExists =
>>     GetClassInfo(appInstance, (LPCWSTR)cname.utf16(), &wcinfo) != FALSE
>>     && wcinfo.lpfnWndProc != proc;
>> if (classExists)
>>     cname += QUuid::createUuid().toString();
>> This is what let multiple same-namespace static-Qt plug-ins coexist for years.
>> 
>> Qt 6.11 extracted this into a new QWindowsWindowClassRegistry (commits 04f13038f5 "Extract window class registration into dedicated class", 2025-11-20, and b23b9c8265 "Add shouldDecorateWindowClassName to detect window class conflicts", 2025-11-28). In the new code the collision check runs against the un-prefixed description.name, while registration uses the prefixed classNamePrefix() + description.name:
>> 
>> QString className = description.name;
>> if (description.shouldAddPrefix)
>>     className = classNamePrefix() + className;
>>     // e.g. "Qt6110d<namespace>QWindowIcon"
>> 
>> if (shouldDecorateWindowClassName(description))
>>     // -> uses description.name (unprefixed!)
>>     className += QUuid::createUuid().toString();
>> ...
>> bool QWindowsWindowClassRegistry::shouldDecorateWindowClassName(
>>         const QWindowsWindowClassDescription &description) const
>> {
>>     return shouldDecorateWindowClassName(description.name,
>>                                           description.procedure);
>> }
>> 
>> bool QWindowsWindowClassRegistry::shouldDecorateWindowClassName(
>>         const QString &name, WNDPROC procedure) const
>> {
>>     const auto appInstance =
>>         static_cast<HINSTANCE>(GetModuleHandle(nullptr));
>>     WNDCLASS wc{};
>>     return GetClassInfo(appInstance, (LPCWSTR)name.utf16(), &wc) != FALSE
>>         && wc.lpfnWndProc != procedure;
>> }
>> Because nothing ever registers the bare QWindowIcon (the registered name is always the prefixed form), GetClassInfo on the un-prefixed name always returns FALSE, the UUID is never appended, and the second instance collides on the plain prefixed name. This still appears to be the case on the current dev branch, and there is no related entry in the 6.11.1 release notes.
>> 
>> THE QUESTION
>> 
>> Is this a deliberate change - i.e. is the expectation now that every independently-loaded static-Qt plug-in must be built with a unique QT_NAMESPACE, so the class-name prefix is already unique and the runtime UUID de-duplication is no longer meant to be relied upon?
>> 
>> Or is it an unintended regression, where the check should have been performed against the final (prefixed) className rather than the un-prefixed description.name? If the latter, the fix looks like a one-liner - decorate based on the prefixed name, e.g.:
>> 
>> if (description.shouldAddPrefix)
>>     className = classNamePrefix() + className;
>> 
>> if (shouldDecorateWindowClassName(className, description.procedure))
>>     // prefixed name
>>     className += QUuid::createUuid().toString(); 
>> We don't yet have a workaround in place, but we plan to try applying the same approach macOS already uses (mangling the Qt namespace to a unique value per binary at build time) as a stopgap. In the meantime we'd like to know whether we should rely on unique namespaces going forward, or whether a fix is expected upstream. Happy to file a bug report with a minimal reproducer if that helps.
>> 
>> Thank you!
>> 
>> Best regards,
>> 
>> 
>> _______________________________________________
>> Interest mailing list
>> Interest at qt-project.org
>> https://lists.qt-project.org/listinfo/interest
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/interest/attachments/20260728/75c19dfd/attachment.htm>


More information about the Interest mailing list