From ca47896204482bf4a6979e3838bf7f09f61cebeb Mon Sep 17 00:00:00 2001
From: giy <giy@omp-system.ru>
Date: Fri, 02 Sep 2022 14:16:56 +0300
Subject: [PATCH] Обновление до версии 2.9.0

---
 vsconfig/2017.vsconfig                                                   |   48 
 Templates/quick/quick.vcxproj.filters                                    |    4 
 Templates/widgetsclass/Properties/AssemblyInfo.cs                        |   67 
 QtVsTools.Package/Legacy/FormProjectQtSettings.resx                      |  120 
 QtVsTools.Wizards/ProjectWizard/Server/ServerWizard.cs                   |  170 
 Templates/qtclass/qtclass.vstemplate_TT                                  |   71 
 GUIDELINES.using-directive.md                                            |   54 
 QtVsTools.Package/Package/QtHelpLinkChooser.xaml.cs                      |   28 
 QtVsTools.Core/Legacy/QtProject.cs                                       |  290 
 doc/images/qtvstools-quick-addressbook-mainwindow.png                    |    0 
 doc/images/qtvstools-remote-debugging.png                                |    0 
 Tests/Test_QtVsTools.Package/Test_QtVersionsPage.cs                      |  247 
 QtVsTools.Core/CommandLineParser.cs                                      |   35 
 Templates/widget/QtTemplate.Item.Widget.csproj                           |   49 
 Tests/BigSolution/template/StaticLib/StaticLib.vcxproj                   |   93 
 QtVsTools.Package/QML/Parser/QmlParserInterop.cs                         |   16 
 QtVsTools.Core/OutputWindowPane.cs                                       |  180 
 doc/images/front-help.png                                                |    0 
 Templates/widgetsclass/widget.cpp                                        |   11 
 QtVsTools.Core/QtModules.cs                                              |   66 
 Tests/ProjectFormats/304/QtProjectV304.cpp                               |   10 
 Templates/qtclass/Properties/AssemblyInfo.cs                             |   67 
 QtVsTools.Core/QrcPrefix.cs                                              |    2 
 QtVsTools.Core/LinkerToolWrapper.cs                                      |    4 
 doc/images/front-gs.png                                                  |    0 
 Templates/console/QtTemplate.Project.Console.csproj                      |   47 
 Templates/console/console.vcxproj.filters                                |    6 
 QtVsTools.Package/QtVsTools.Icons.pkgdef                                 |   20 
 Tests/ProjectFormats/304/QtProjectV304.vcxproj.filters                   |   48 
 Tests/BigSolution/template/loop_msbuild.bat                              |   36 
 Tests/Test_QtMsBuild.Tasks/Test_QtMsBuild.Tasks.csproj                   |   33 
 Tests/BigSolution/template/BigProjectNNN/BigProjectQtClassNNN.h          |    2 
 QtVsTools.Package/Legacy/ChangeFor.cs                                    |   32 
 Tests/ProjectFormats/100/QtProjectV100.qrc                               |    4 
 QtVsTools.Core/QtVSIPSettings.cs                                         |  477 
 QtVsTools.Package/QML/Classification/QmlExpressionEvalClassifier.cs      |   13 
 QtVsTools.Core/Common/QtVSIPSettingsShared.cs                            |  261 
 QtVsTools.Package/QtMsBuild/QtModulesPopup.xaml                          |    8 
 doc/images/qtvstools-msbuild-diagram.png                                 |    0 
 QtVsTools.Core/ProFileContent.cs                                         |   40 
 Templates/server/QtTemplate.Project.Server.csproj                        |   49 
 Tests/ProjectFormats/302/QtProjectV302.h                                 |   15 
 QtVsTools.Wizards/ProjectWizard/Library/LibraryClassPage.xaml            |  238 
 QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4JsObject.cs        |    1 
 QtVsTools.Wizards/ItemWizard/QtClass/QtClassWizard.cs                    |  193 
 Tests/ProjectFormats/300/main.cpp                                        |   10 
 QtVsTools.Package/Legacy/FormChangeQtVersion.cs                          |  107 
 QtVsTools.Core/QMakeQuery.cs                                             |   22 
 QtVsTools.RegExpr/Properties/AssemblyInfo.cs                             |    1 
 QtVsTools.Wizards/ProjectWizard/Server/ServerPage.xaml.cs                |   64 
 QtVsTools.Wizards/Common/WizardWindow.xaml                               |   44 
 Tests/Test_QtVsTools.Package/Properties/AssemblyInfo.cs                  |   20 
 Tests/ProjectFormats/301/QtProjectV301.ui                                |   29 
 doc/tutorial/QuickAddressBook/QuickAddressBookTypes/AddressBookItem.qml  |   59 
 QtVsTools.Package/Marketplace/Overview.html_TT                           |   39 
 QtVsTools.Core/MsBuildProject.cs                                         |  104 
 QtVsTools.Package/Legacy/FormProjectQtSettings.cs                        |  166 
 Tests/Test_QtVsTools.RegExpr/Properties/AssemblyInfo.cs                  |    1 
 Tests/ProjectFormats/303/QtProjectV303.vcxproj                           |  106 
 doc/tutorial/QuickAddressBook/main.qml                                   |   74 
 QtMSBuild/QtMsBuild/qt_settings.xml                                      |   52 
 Tests/ProjectFormats/100/QtProjectV100.cpp                               |   10 
 QtVsTools.Wizards/Util/FileNameValidationRule.cs                         |   55 
 Templates/lib/QtTemplate.Project.Lib.csproj                              |   49 
 QtVsTools.Package/QML/Syntax/QmlSyntax.cs                                |    2 
 QtVsTools.Core/VisualStudio/InfoBarMessage.cs                            |  166 
 Templates/widgetsclass/widgetsclass.ico                                  |    0 
 QtVsTools.Wizards/ProjectWizard/Designer/DesignerPage.xaml               |  310 
 Tests/Test_QtVsTools.RegExpr/Test_QtVsTools.RegExpr.csproj               |    6 
 Templates/qmldir/QtTemplate.Item.QMLDir.csproj                           |   49 
 QtVsTools.Package/Common/Timestamp.cs                                    |    9 
 QtVsTools.Package/Package/QtItemContextMenu.cs                           |   41 
 QtVsTools.Wizards/ProjectWizard/Designer/DesignerWizard.cs               |  179 
 Tests/Test_QtVsTools.Core/Test_LazyFactory.cs                            |   77 
 doc/qtvstools-online.qdocconf                                            |    2 
 QtMSBuild/QtMsBuild/qt6.natvis.xml                                       |  406 
 QtVsTools.Package/QML/Parser/QmlParserDiagnostics.cs                     |    4 
 QtVsTools.Core/Legacy/QtVersionManager.cs                                |   63 
 Templates/gui/gui.vcxproj.filters                                        |    2 
 Tests/ProjectFormats/100/QtProjectV100.ui                                |   28 
 Tests/BigSolution/template/BigProjectNNN/BigProjectNNN.vcxproj           |    8 
 Tests/ProjectFormats/200/QtProjectV200.vcxproj.filters                   |   75 
 QtVsTools.Package/Package/QtProjectContextMenu.cs                        |  128 
 QtVsTools.Package/QtMsBuild/QtVersionProvider.cs                         |    1 
 Tests/ProjectFormats/304/QtProjectV304.sln                               |   25 
 QtVsTools.Core/QMakeConf.cs                                              |   16 
 .github/ISSUE_TEMPLATE/feature.md                                        |   20 
 QtVsTools.Core/ProSolution.cs                                            |   23 
 doc/tutorial/AddressBook/adddialog.h                                     |    2 
 QtVsTools.Wizards/ProjectWizard/ConfigPage.xaml.cs                       |  489 +
 Tests/Test_QtVsTools.RegExpr/Test_SubTokens.cs                           |    1 
 Tests/Test_QtVsTools.Core/Properties/AssemblyInfo.cs                     |   20 
 doc/images/qtvstools-qt-translation-file-wizard.png                      |    0 
 Tests/ProjectFormats/303/QtProjectV303.ui                                |   28 
 Tests/ProjectFormats/302/QtProjectV302.sln                               |   25 
 QtVsTools.Package/QtVsTools.Package.csproj                               |  166 
 QtVsTools.Core/QtVsTools.Core.csproj                                     |   57 
 Tests/BigSolution/template/QtClassLibrary/QtClassLibrary.vcxproj         |  114 
 Tests/Test_QtMsBuild.Tasks/Test_Join.cs                                  |   25 
 QtVsTools.Core/QtMsBuild.cs                                              |   80 
 Tests/ProjectFormats/100/main.cpp                                        |   10 
 doc/tutorial/QuickAddressBook/QuickAddressBookTypes/NewAddressPopup.qml  |   88 
 Tests/ProjectFormats/100/QtProjectV100.vcxproj.filters                   |   95 
 QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Engine.cs                 |   46 
 QtVsTools.RegExpr/expression/RegExprToken.cs                             |   18 
 Templates/translation/translation.ico                                    |    0 
 QtVsTools.Wizards/ProjectWizard/ConfigPage.xaml                          |  298 
 doc/images/front-advanced.png                                            |    0 
 QtVsTools.Wizards/Util/NativeMethods.cs                                  |   41 
 Templates/widgetsclass/widget.ui                                         |   22 
 Templates/dialogbuttonright/QtTemplate.Item.DialogButtonRight.csproj     |   49 
 QtVsTools.Package/QML/Classification/QmlTag.cs                           |   18 
 Tests/BigSolution/template/QtClassLibrary/QtClassLibrary.cpp             |   33 
 Tests/BigSolution/generator/Program.cs                                   |  115 
 .github/ISSUE_TEMPLATE/bug.md                                            |   31 
 QtVsTools.Package/Package/Notifications.cs                               |  111 
 doc/tutorial/QuickAddressBook/main.cpp                                   |   45 
 QtVsTools.Wizards/ItemWizard/QtClass/QtClassPage.xaml.cs                 |   68 
 QtVsTools.Package/QML/Classification/QmlSyntaxClassifier.cs              |    4 
 doc/images/qtvstools-quick-addressbook-entries.png                       |    0 
 QtMSBuild/QtMsBuild/translation/qttranslation.targets                    |   16 
 QtVsTools.Package/QtMsBuild/QtProjectTracker.cs                          |  170 
 QtVsTools.Core/Resources.resx                                            |   40 
 QtVsTools.Package/Package/QtHelpLinkChooser.xaml                         |   60 
 Tests/BigSolution/template/QtClassLibrary/qtclasslibrary_global.h        |   41 
 Templates/mainwindow/QtTemplate.Item.MainWindow.csproj                   |   49 
 Templates/quick/QtTemplate.Project.Quick.csproj                          |   42 
 Tests/BigSolution/template/BigSolution.sln                               |   12 
 QtMSBuild/Tasks/QtRunTask.cs                                             |  246 
 QtVsTools.Package/Common/Json/DeferredObject.cs                          |    2 
 QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Continue.cs        |    3 
 version.targets                                                          |    2 
 QtMSBuild/QtMsBuild/qt_private.props                                     |  116 
 QtVsTools.Package/QtMenus.vsct_TT                                        |   93 
 QtVsTools.Package/Common/Prototyped.cs                                   |    9 
 QtVsTools.Package/qtmodules.xml                                          |   56 
 Tests/Test_QtVsTools.RegExpr/Test_MacroParser.cs                         |    3 
 QtVsTools.Package/Icons/prf32.png                                        |    0 
 QtVsTools.RegExpr/production/Production.cs                               |   14 
 QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Program.cs                |   80 
 QtVsTools.Package/Package/ExtLoader.cs                                   |   19 
 QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Expression.cs             |   11 
 QtVsTools.Wizards/Common/WizardIntroPage.xaml.cs                         |   39 
 QtVsTools.Package/Common/PriorityQueue.cs                                |   19 
 Tests/ProjectFormats/100/QtProjectV100.pro                               |    6 
 Templates/server/server.vcxproj.filters                                  |    2 
 Tests/ProjectFormats/302/QtProjectV302.ui                                |   28 
 Tests/ProjectFormats/303/QtProjectV303.cpp                               |    7 
 Templates/translation/translation.ts                                     |    4 
 .editorconfig                                                            |    2 
 QtVsTools.Package/QtMsBuild/QtModulesPopup.xaml.cs                       |    8 
 QtVsTools.Core/VisualStudio/VsSearch.cs                                  |  146 
 Templates/qml/QtTemplate.Item.QMLFile.csproj                             |   49 
 QtVsTools.Wizards/ItemWizard/Translation/TranslationPage.xaml.cs         |   91 
 QtVsTools.Wizards/Common/WizardIntroPage.xaml                            |  102 
 Templates/translation/translation.vstemplate_TT                          |   69 
 README.md                                                                |    2 
 QtVsTest/QtVsTest.cs                                                     |    4 
 QtVsTools.Wizards/Common/WizardWindow.xaml.cs                            |  133 
 QtVsTools.Wizards/ItemWizard/Translation/TranslationPage.xaml            |  149 
 QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Message.cs         |    6 
 Templates/translation/Properties/AssemblyInfo.cs                         |   67 
 QtVsTools.Package/qt6modules.xml                                         |  510 +
 QtVsTools.Package/Icons/qml32.png                                        |    0 
 QtVsTools.Wizards/Common/WizardData.cs                                   |   68 
 Tests/ProjectFormats/302/QtProjectV302.vcxproj                           |  102 
 Templates/qtclass/qtclass.ico                                            |    0 
 Tests/ProjectFormats/301/main.cpp                                        |   10 
 Tests/ProjectFormats/304/main.cpp                                        |   10 
 QtVsTools.Wizards/Common/WizardResult.cs                                 |   37 
 QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7InfoHelpers.cs            |   10 
 QtVsTools.Core/FakeFilter.cs                                             |    7 
 Tests/Test_QtMsBuild.Tasks/TestTaskLoggingHelper.cs                      |    4 
 QtVsTools.Package/Common/Json/Serializable.cs                            |    8 
 doc/tutorial/QuickAddressBook/QuickAddressBook.vcxproj.filters           |   45 
 Tests/ProjectFormats/300/QtProjectV300.qrc                               |    4 
 QtVsTools.Core/ProjectImporter.cs                                        |  112 
 QtVsTools.Core/ProFileOption.cs                                          |  100 
 QtVsTools.Core/Resources.cs                                              |    7 
 Tests/ProjectFormats/303/QtProjectV303.sln                               |   25 
 Tests/Test_QtVsTools.Core/Test_QtVsTools.Core.csproj                     |  129 
 QtVsTools.Core/RccOptions.cs                                             |   15 
 Tests/ProjectFormats/304/QtProjectV304.qrc                               |    4 
 Tests/BigSolution/template/StaticLib/StaticLib.vcxproj.filters           |   27 
 vstools.bat                                                              |   37 
 doc/images/front-projects.png                                            |    0 
 QtVsTools.Package/Icons/pri32.png                                        |    0 
 QtVsTools.Package/qt5.natvis.xml                                         |   51 
 QtVsTools.Wizards/ProjectWizard/Library/LibraryWizard.cs                 |  142 
 QtVsTools.Core/VisualStudio/VsShell.cs                                   |  107 
 QtVsTools.Wizards/ItemWizard/Translation/TranslationWizard.cs            |  119 
 QtMSBuild/QtMsBuild/qt_vars.targets                                      |   74 
 Templates/resource/QtTemplate.Item.Resource.csproj                       |   49 
 Tests/Test_QtMsBuild.Tasks/Properties/AssemblyInfo.cs                    |    1 
 Tests/Test_QtMsBuild.Tasks/Test_QtRunTask.cs                             |   90 
 vstools.sln                                                              |   99 
 Tests/ProjectFormats/304/QtProjectV304.h                                 |   16 
 doc/tutorial/QuickAddressBook/QuickAddressBook.sln                       |   25 
 QtVsTools.Package/QtVsToolsPackage.cs                                    |   82 
 Tests/ProjectFormats/300/QtProjectV300.cpp                               |    7 
 QtVsTools.Package/source.extension.vsixmanifest_TT                       |   18 
 Tests/ProjectFormats/ProjectFormats.md                                   | 1324 ++
 QtVsTools.Core/WaitDialog.cs                                             |   41 
 QtVsTools.Package/Resources.resx                                         |   39 
 QtVsTools.Package/Editors/Editor.QtDesigner.cs                           |   21 
 QtVsTools.Core/BuildConfig.cs                                            |    1 
 QtVsTools.RegExpr/expression/CharClassSet.cs                             |   13 
 Tests/BigSolution/template/QtClassLibrary/QtClassLibrary.h               |   37 
 Tests/ProjectFormats/100/QtProjectV100.vcxproj                           |  215 
 QtVsTools.Core/QMake.cs                                                  |   30 
 QtVsTools.Package/Icons/Monikers.imagemanifest                           |   54 
 QtVsTools.Package/Package/QMakeWrapper.cs                                |    2 
 Tests/ProjectFormats/200/QtProjectV200.h                                 |   15 
 QtVsTools.Core/HelperFunctions.cs                                        |  629 
 Tests/ProjectFormats/302/main.cpp                                        |   10 
 doc/tutorial/QuickAddressBook/QuickAddressBook.vcxproj                   |  135 
 QtVsTools.Core/ExportProjectDialog.cs                                    |    6 
 QtVsTools.Core/VisualStudio/VsServiceProvider.cs                         |    9 
 Templates/gui/gui.vstemplate_TT                                          |    2 
 Tests/ProjectFormats/200/QtProjectV200.sln                               |   22 
 QtMSBuild/QtMsBuild/qt_defaults.props                                    |    7 
 Templates/gui/widget.cpp                                                 |   10 
 doc/config/style/qt5-sidebar.html                                        |   51 
 QtVsTools.Package/QtMsBuild/QtProjectBuild.cs                            |  377 
 Tests/BigSolution/template/QtClassLibrary/QtClass.h                      |   41 
 QtVsTools.Package/Editors/Editor.cs                                      |  100 
 QtVsTools.Package/QML/Debugging/QmlDebugger.cs                           |   47 
 QtVsTools.Core/CompilerToolWrapper.cs                                    |   81 
 Templates/designer/widget.h                                              |    2 
 doc/images/qtvstools-qt-project-settings.png                             |    0 
 QtVsTools.Package/Legacy/Translation.cs                                  |  134 
 QtVsTools.Wizards/Common/UiClassInclusion.cs                             |   37 
 QtVsTools.Core/Common/LazyFactory.cs                                     |   57 
 Tests/BigSolution/template/StaticLib/StaticLib.cpp                       |   31 
 Templates/widgetsclass/widget.h                                          |   15 
 QtVsTools.Package/Common/ConcurrentStopwatch.cs                          |    2 
 QtVsTools.Package/Legacy/QtOptionsPage.cs                                |  161 
 QtVsTest/Macro.cs                                                        |  127 
 QtVsTools.Wizards/Common/GuiPage.xaml                                    |  307 
 QtVsTools.Package/Options/QtVersionsTable.xaml                           |   24 
 QtVsTools.Core/ProjectExporter.cs                                        |   85 
 Templates/server/header.h                                                |    2 
 QtVsTools.Core/Messages.cs                                               |  134 
 Сборка.md                                                                |    2 
 Templates/gui/widget.qrc                                                 |    4 
 QtVsTools.RegExpr/production/ProductionRule.cs                           |    5 
 Templates/translation/QtTemplate.Item.Translation.csproj                 |  155 
 QtVsTools.Wizards/QtVsTools.Wizards.csproj                               |  157 
 QtVsTools.Wizards/Util/ClassNameValidationRule.cs                        |   67 
 doc/images/qtvstools-qt-widget-class-wizard.png                          |    0 
 references.props                                                         |  163 
 QtVsTools.Package/Icons/pro32.png                                        |    0 
 Tests/ProjectFormats/100/QtProjectV100.h                                 |   16 
 Tests/ProjectFormats/304/QtProjectV304.vcxproj                           |  105 
 QtVsTools.Wizards/ItemWizard/WidgetsClass/WidgetsClassWizard.cs          |  245 
 QtVsTools.Package/QML/Syntax/QmlAst.cs                                   |    2 
 Tests/Test_QtVsTools.Package/QtVsTestClient.cs                           |  144 
 QtVsTools.Wizards/Util/VCRulePropertyStorageHelper.cs                    |   69 
 Tests/ProjectFormats/300/QtProjectV300.h                                 |   15 
 Templates/widgetsclass/widgetsclass.vstemplate_TT                        |   70 
 QtVsTest/QtVsTest.csproj                                                 |   94 
 QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Events.cs                 |   28 
 doc/images/front-coding.png                                              |    0 
 vsconfig/2019.vsconfig                                                   |   44 
 QtVsTools.RegExpr/expression/RegExprAssert.cs                            |    4 
 Tests/Test_QtVsTools.RegExpr/Test_XmlIntParser.cs                        |    3 
 doc/images/qtvstools-quick-addressbook-popup.png                         |    0 
 .gitignore                                                               |    6 
 QtVsTools.Core/CxxStreamReader.cs                                        |    4 
 QtVsTools.Core/MocCmdChecker.cs                                          |    4 
 Tests/BigSolution/template/StaticLib/Header.h                            |    4 
 QtVsTools.RegExpr/expression/RegExprRepeat.cs                            |    1 
 QtVsTools.Package/Common/Concurrent.cs                                   |    7 
 Tests/ProjectFormats/303/QtProjectV303.qrc                               |    4 
 Tests/ProjectFormats/200/QtProjectV200.cpp                               |    7 
 QtVsTools.Core/Extensions.cs                                             |    9 
 QtVsTools.Wizards/ProjectWizard/Server/ServerPage.xaml                   |  259 
 QtVsTools.RegExpr/production/ProductionRuleAction.cs                     |    6 
 QtVsTools.Wizards/ProjectWizard/ProjectTemplateWizard.cs                 |  722 +
 Tests/ProjectFormats/301/QtProjectV301.h                                 |   15 
 Tests/ProjectFormats/301/QtProjectV301.qrc                               |    4 
 QtVsTools.Package/Legacy/FormChangeQtVersion.resx                        |  120 
 QtVsTools.RegExpr/utils/Consts.cs                                        |   21 
 QtVsTools.Wizards/Util/UnsafeNativeMethods.cs                            |   41 
 vsconfig/2022.vsconfig                                                   |   42 
 doc/images/qtvstools-options-qt-general.png                              |    0 
 QtVsTools.Package/Common/Json/SerializableEnum.cs                        |    3 
 QtVsTools.Package/Options/QtOptionsPage.cs                               |   67 
 QtVsTools.Package/qt6.natvis.xml                                         |   33 
 QtVsTools.Package/Options/QtVersionsPage.cs                              |   92 
 Tests/ProjectFormats/300/QtProjectV300.sln                               |   25 
 QtVsTools.Package/QML/Classification/QmlErrorClassifier.cs               |    4 
 Templates/empty/QtTemplate.Project.Empty.csproj                          |   49 
 QtVsTools.Package/Legacy/FormChangeQtVersion.Designer.cs                 |   87 
 doc/images/front-preview.png                                             |    0 
 Templates/lib/lib.vcxproj.filters                                        |    6 
 Tests/ProjectFormats/303/QtProjectV303.h                                 |   15 
 Tests/ProjectFormats/301/QtProjectV301.vcxproj                           |  109 
 QtVsTools.Package/Icons/qrc32.png                                        |    0 
 QtVsTools.Package/QML/Classification/QmlAsyncClassifier.cs               |   42 
 Tests/ProjectFormats/200/QtProjectV200.ui                                |   29 
 QtVsTools.Package/QML/Debugging/QmlFileSystem.cs                         |   15 
 QtVsTools.Wizards/Common/GuiPage.xaml.cs                                 |   74 
 Tests/ProjectFormats/302/QtProjectV302.vcxproj.filters                   |   46 
 Tests/ProjectFormats/302/QtProjectV302.cpp                               |    7 
 QtVsTools.Package/Legacy/ProjectQtSettings.cs                            |  336 
 Tests/ProjectFormats/303/main.cpp                                        |   10 
 QtVsTools.Wizards/Common/WizardPage.cs                                   |  115 
 QtVsTools.Core/QtConfig.cs                                               |   17 
 QtVsTools.Core/QtVersionManager.cs                                       |  246 
 Tests/BigSolution/template/QtClassLibrary/QtClassLibrary.vcxproj.filters |   42 
 Tests/BigSolution/template/QtClassLibrary/QtClass.cpp                    |   38 
 Templates/qtclass/header.h                                               |    9 
 QtMSBuild/QtMsBuild/qt_globals.targets                                   |  259 
 Templates/designer/QtTemplate.Project.Designer.csproj                    |   49 
 QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Breakpoint.cs             |   19 
 Tests/Test_QtVsTools.PriorityQueue/Test_QtVsTools.PriorityQueue.csproj   |    6 
 Templates/designer/plugin.h                                              |    2 
 QtVsTools.Package/QtMsBuild/QtProjectIntelliSense.cs                     |   32 
 QtVsTools.Core/QtProject.cs                                              |  944 -
 QtVsTools.Package/QML/Debugging/QmlDebugLauncher.cs                      |   63 
 QtVsTools.Wizards/ProjectWizard/Gui/GuiWizard.cs                         |  365 
 Changelog                                                                |   31 
 QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Property.cs               |   46 
 Tests/Test_QtVsTools.PriorityQueue/Properties/AssemblyInfo.cs            |    1 
 QtVsTools.Core/MainWinWrapper.cs                                         |   20 
 Tests/ProjectFormats/200/main.cpp                                        |   10 
 QtVsTools.Core/Common/EnumExt.cs                                         |   12 
 QtVsTools.RegExpr/expression/Renderer.cs                                 |    1 
 QtVsTools.Wizards/ProjectWizard/Library/LibraryClassPage.xaml.cs         |   64 
 Tests/Test_QtVsTools.Package/Test_QtVsTools.Package.csproj               |  120 
 doc/images/qtvstools-qtquick-app-modules.png                             |    0 
 Templates/widgetsclass/QtTemplate.Item.WidgetsClass.csproj               |  157 
 QtVsTools.RegExpr/parser/Parser.cs                                       |   10 
 QtVsTools.Package/Package/QtSolutionContextMenu.cs                       |  107 
 Templates/qtclass/source.cpp                                             |    8 
 Templates/gui/main.cpp                                                   |    2 
 Tests/ProjectFormats/300/QtProjectV300.vcxproj                           |  106 
 QtVsTools.Core/Filters.cs                                                |   21 
 QtVsTools.Core/SR.cs                                                     |   29 
 QtVsTools.Package/Package/QtHelp.cs                                      |  113 
 QtVsTools.Wizards/Util/UiClassInclusionConverter.cs                      |   43 
 QtVsTools.Package/Icons/ts32.png                                         |    0 
 QMakeFileReader/evaluator/proitems.cpp                                   |    2 
 QtMSBuild/QtMsBuild/qt_inner.targets                                     |  138 
 QtVsTools.Package/QtMsBuild/QtModulesEditor.cs                           |   38 
 Tests/ProjectFormats/301/QtProjectV301.cpp                               |    7 
 QtMSBuild/Tasks/CriticalSection.cs                                       |    2 
 Templates/qtclass/QtTemplate.Item.QtClass.csproj                         |  157 
 Tests/ProjectFormats/200/QtProjectV200.vcxproj                           |  133 
 doc/tutorial/QuickAddressBook/qmldir                                     |    2 
 QtVsTools.Wizards/ItemWizard/QtClass/QtClassPage.xaml                    |  298 
 QtVsTools.Package/Common/NativeAPI.cs                                    |    8 
 QtVsTools.RegExpr/parser/ParseTree.cs                                    |   11 
 QtVsTools.Package/Icons/ui32.png                                         |    0 
 doc/config/qtvstools-project.qdocconf                                    |    8 
 QtVsTest/MacroParser.cs                                                  |    9 
 Tests/ProjectFormats/200/QtProjectV200.qrc                               |    4 
 QtVsTools.Wizards/Util/VCLanguageManagerValidationRule.cs                |   53 
 Templates/dialogbuttonbottom/QtTemplate.Item.DialogButtonBottom.csproj   |   49 
 QtVsTools.Package/Package/QtMainMenu.cs                                  |  115 
 QtVsTools.Wizards/Util/FileExistsInFilterValidationRule.cs               |   68 
 QtMSBuild/QtMsBuild/qt5.natvis.xml                                       |  835 +
 QtVsTools.Wizards/ProjectWizard/Quick/QuickWizard.cs                     |   75 
 Tests/ProjectFormats/303/QtProjectV303.vcxproj.filters                   |   49 
 QtVsTools.Core/QtModule.cs                                               |   12 
 doc/tutorial/QuickAddressBook/qml.qrc                                    |    8 
 Templates/designer/designer.vcxproj.filters                              |    6 
 Tests/Test_QtVsTools.PriorityQueue/Test_PriorityQueue.cs                 |   15 
 QtVsTools.Package/Package/DteEventsHandler.cs                            |  143 
 QtVsTools.RegExpr/QtVsTools.RegExpr.csproj                               |   11 
 Tests/ProjectFormats/300/QtProjectV300.vcxproj.filters                   |   50 
 QtVsTools.Package/QML/Debugging/V4/QmlDebugV4Client.cs                   |   32 
 Tests/ProjectFormats/300/QtProjectV300.ui                                |   29 
 QtVsTest/MacroServer.cs                                                  |   10 
 QtVsTools.Wizards/ProjectWizard/Console/ConsoleWizard.cs                 |   89 
 QtMSBuild/QtMSBuild.csproj                                               |   47 
 QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7StackFrame.cs             |   24 
 QtVsTools.Package/Package/Translation.cs                                 |  171 
 Tests/ProjectFormats/301/QtProjectV301.vcxproj.filters                   |   50 
 QtVsTools.Core/Legacy/QtVSIPSettings.cs                                  |  226 
 QtVsTools.Package/Legacy/QtMenu.cs                                       |  109 
 QtVsTools.Package/Legacy/FormProjectQtSettings.Designer.cs               |  159 
 Tests/ProjectFormats/302/QtProjectV302.qrc                               |    4 
 doc/src/qtvstools.qdoc                                                   |  868 +
 QtVsTools.Wizards/ProjectWizard/Empty/EmptyWizard.cs                     |   75 
 QtVsTools.Package/Common/Json/Serializer.cs                              |   28 
 QtVsTools.Package/Options/QtVersionsTable.cs                             |  348 
 QtVsTools.Core/VersionInformation.cs                                     |   25 
 QtVsTools.Package/Package/SR.cs                                          |   53 
 QtVsTools.Package/Editors/Editor.QtResourceEditor.cs                     |   13 
 Tests/ProjectFormats/301/QtProjectV301.sln                               |   25 
 QtVsTools.Package/QML/Debugging/V4/QmlDebugV4Protocol.cs                 |   16 
 Tests/ProjectFormats/304/QtProjectV304.ui                                |   28 
 QtVsTools.Package/Package/QtMsBuildConverter.cs                          |   33 
 QtVsTools.Wizards/ProjectWizard/Designer/DesignerPage.xaml.cs            |   70 
 Templates/gui/QtTemplate.Project.Gui.csproj                              |   55 
 Templates/gui/widget.h                                                   |   10 
 398 files changed, 23,085 insertions(+), 5,153 deletions(-)

diff --git a/.editorconfig b/.editorconfig
index e8c7721..5d522eb 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -19,7 +19,7 @@
 
 # Organize usings
 dotnet_separate_import_directive_groups = false
-dotnet_sort_system_directives_first = false
+dotnet_sort_system_directives_first = true
 file_header_template = unset
 
 # this. and Me. preferences
diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md
new file mode 100644
index 0000000..f7d109d
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug.md
@@ -0,0 +1,31 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Desktop (please complete the following information):**
+ - Qt VS Tool Version [e.g. 2.7.1, 2.8.1, 2.8.1 (Rev.06)]
+ - Visual Studio version [e.g. VS2017, VS2019, VS2022]
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature.md b/.github/ISSUE_TEMPLATE/feature.md
new file mode 100644
index 0000000..72718d5
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.gitignore b/.gitignore
index 30aff55..9b2efd8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -315,3 +315,9 @@
 QtNatvisPoC/*.txt
 Tests/BigSolution/generated/
 vstools.pri
+templates/widgetsclass/Properties/AssemblyInfo.tt.cs
+templates/widgetsclass/widgetsclass.vstemplate
+templates/qtclass/Properties/AssemblyInfo.tt.cs
+templates/qtclass/qtclass.vstemplate
+templates/translation/Properties/AssemblyInfo.tt.cs
+templates/translation/translation.vstemplate
diff --git a/Changelog b/Changelog
index 84198b6..811ebba 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,34 @@
+Qt Visual Studio Tools version 2.9.0:
+
+Changes
+-------
+ - Added QStringRef and QStringView debug visualizers
+ - Check if Qt translation tools are available
+ - New widget class wizards accessible from "Add New Item"
+ - New Qt class wizards accessible from "Add New Item"
+ - InfoBar notification of missing Qt installation
+ - InfoBar notification of recently installed new Qt VS Tools version
+ - Additional compiler options from Qt included in the build
+ - Enabled reporting issues and feature requests via GitHub
+ - Debug visualizer for Qt types added to PDB
+ - Improved intellisense performance for Qt projects
+- Fixed QTVSADDINBUG-626: Qt VS Tools does not generate the same code as Qt Creator
+- Fixed QTVSADDINBUG-707: Integrating the main window widget into the Qt Gui application wizard.
+- Fixed QTVSADDINBUG-884: QStringRef and QStringView have no natvis definitions
+- Fixed QTVSADDINBUG-925: Can't add an "add-on" module to project using GUI
+- Fixed QTVSADDINBUG-937: OpenGL Widgets module missing
+- Fixed QTVSADDINBUG-951: Can't build QT6 WebEngine example
+- Fixed QTVSADDINBUG-965: Pragma warning not working with "external header warning level" option
+- Fixed QTVSADDINBUG-966: Debug version of Qt Dlls are linked even if we asked for release mode
+- Fixed QTVSADDINBUG-970: Qt6 in Visual Studio plugin doesn't load qmake projects
+- Fixed QTVSADDINBUG-972: VS Plugin is ignoring module core5compat when loading project with QT6
+- Fixed QTVSADDINBUG-973: unable to add a new qt version with visual studio 2022
+- Fixed QTVSADDINBUG-979: Project Properties are overwritten by Qt Vs Tools
+- Fixed QTVSADDINBUG-980: The "Release Notes" link does not work
+- Fixed QTVSADDINBUG-982: Can't add new Qt Version
+
+
+
 Qt Visual Studio Tools version 2.8.1:
 
 Changes
diff --git a/GUIDELINES.using-directive.md b/GUIDELINES.using-directive.md
new file mode 100644
index 0000000..89c471b
--- /dev/null
+++ b/GUIDELINES.using-directive.md
@@ -0,0 +1,54 @@
+# Coding guidelines -- `using` directives
+
+Three kinds of `using` directives are available:
+  * **Reference**: `using <namespace>` -- _namespace_ can be omitted when referencing types.
+  * **Alias**: `using <alias> = <namespace|type>` -- _alias_ can be used in place of _namespace_
+    or _type_.
+  * **Static**: `using static <type>` -- all static members of _type_ are accessible without
+    having to specify the type name.
+
+The following conventions apply to `using` directives in the Qt VS Tools code:
+  * `using` directives are grouped by root namespace, and ordered alphabetically within each group.
+  * Directives that reference external namespaces are located at the start of the source file,
+    before the local namespace declaration.
+  * The order of external namespace groups is as follows:
+      1. `System*` namespaces.
+      2. `Microsoft*` namespaces.
+      3. `EnvDTE*` namespaces.
+      4. All other external namespaces.
+  * Directives referencing in-solution namespaces (i.e. `QtVsTools*` or `QtVsTest*` namespaces) are
+    nested within the local namespace block.
+  * In-solution reference directives will use an abbreviated form of the  namespace, whenever
+    possible.
+  * Alias and static directives can be specified either at top-level or nested in the local
+    namespace.
+  * Alias directives are specified after all reference directives.
+  * Static directives are specified after all reference directives and all alias directives.
+  * Optionally, directives of different kinds can be separated with an empty line.
+
+## Example
+```csharp
+using System;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text.RegularExpressions;
+using Microsoft.VisualStudio;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.VCProjectEngine;
+using EnvDTE;
+using EnvDTE80;
+
+using Task = System.Threading.Tasks.Task;
+
+namespace QtVsTools
+{
+    using Core;
+    using QtMsBuild;
+
+    using RegExprParser = SyntaxAnalysis.RegExpr.Parser;
+
+    using static SyntaxAnalysis.RegExpr;
+
+    class ...
+```
diff --git a/QMakeFileReader/evaluator/proitems.cpp b/QMakeFileReader/evaluator/proitems.cpp
index 4212155..59ab2e0 100644
--- a/QMakeFileReader/evaluator/proitems.cpp
+++ b/QMakeFileReader/evaluator/proitems.cpp
@@ -341,7 +341,7 @@
         totalLength += this_.at(i).size();
 
     if (sz)
-        totalLength += sepSize * (sz - 1);
+        totalLength += int(sepSize) * (sz - 1);
 
     QString res(totalLength, Qt::Uninitialized);
     QChar *ptr = (QChar *)res.constData();
diff --git a/QtMSBuild/QtMSBuild.csproj b/QtMSBuild/QtMSBuild.csproj
index 5898f7f..6f5d35c 100644
--- a/QtMSBuild/QtMSBuild.csproj
+++ b/QtMSBuild/QtMSBuild.csproj
@@ -67,24 +67,42 @@
   <ItemGroup>
     <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
     <Reference Include="System" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Runtime" />
     <Reference Include="$(VCTargetsPath)\Application Type\Linux\1.0\Microsoft.Build.Linux.Tasks.dll" />
     <Reference Include="$(VCTargetsPath)\Application Type\Linux\1.0\liblinux.dll" />
   </ItemGroup>
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
-  // Version specific references
+  // General package references
   // -->
   <Import Project="$(SolutionDir)\references.props" />
   <ItemGroup>
-    <PackageReference Include="Microsoft.Build"
-      Version="$(Version_Microsoft_Build)" />
-    <PackageReference Include="Microsoft.Build.Framework"
-      Version="$(Version_Microsoft_Build_Framework)" />
-    <PackageReference Include="Microsoft.Build.Tasks.Core"
-      Version="$(Version_Microsoft_Build_Tasks_Core)" />
-    <PackageReference Include="Microsoft.Bcl.AsyncInterfaces"
-      Version="$(Version_Microsoft_Bcl_AsyncInterfaces)" />
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+    <PackageReference Include="$(Name_Microsoft_Build)" Version="$(Version_Microsoft_Build)" />
+    <PackageReference Include="$(Name_Microsoft_Build_Tasks_Core)" Version="$(Version_Microsoft_Build_Tasks_Core)" />
   </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_RpcContracts)" Version="$(Version_Microsoft_VisualStudio_RpcContracts)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
   // Solution project references
@@ -112,6 +130,12 @@
       <DesignTime>True</DesignTime>
       <DependentUpon>AssemblyInfo.cs</DependentUpon>
     </Compile>
+    <Content Include="QtMSBuild\qt5.natvis.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="QtMSBuild\qt6.natvis.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
     <!--
     ///////////////////////////////////////////////////////////////////////////////////////////////
     // Qt/MSBuild common property pages and targets
@@ -145,6 +169,10 @@
       <CopyToOutputDirectory>Always</CopyToOutputDirectory>
     </Content>
     <Content Include="QtMSBuild\qt_vars.targets">
+      <SubType>Designer</SubType>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="QtMSBuild\qt_inner.targets">
       <SubType>Designer</SubType>
       <CopyToOutputDirectory>Always</CopyToOutputDirectory>
     </Content>
@@ -380,6 +408,7 @@
     // Inline tasks
     // -->
     <Compile Include="Tasks\CriticalSection.cs" />
+    <Compile Include="Tasks\QtRunTask.cs" />
     <Compile Include="Tasks\GetVarsFromMSBuild.cs" />
     <Compile Include="Tasks\HostExec_LinuxWSL_Error.cs" />
     <Compile Include="Tasks\HostTranslatePaths_LinuxWSL_Error.cs" />
diff --git a/QtMSBuild/QtMsBuild/qt5.natvis.xml b/QtMSBuild/QtMsBuild/qt5.natvis.xml
new file mode 100644
index 0000000..935d20b
--- /dev/null
+++ b/QtMSBuild/QtMsBuild/qt5.natvis.xml
@@ -0,0 +1,835 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    ****************************************************************************
+    **
+    ** Copyright (C) 2022 The Qt Company Ltd.
+    ** Contact: https://www.qt.io/licensing/
+    **
+    ** This file is part of the Qt VS Tools.
+    **
+    ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+    ** Commercial License Usage
+    ** Licensees holding valid commercial Qt licenses may use this file in
+    ** accordance with the commercial license agreement provided with the
+    ** Software or, alternatively, in accordance with the terms contained in
+    ** a written agreement between you and The Qt Company. For licensing terms
+    ** and conditions see https://www.qt.io/terms-conditions. For further
+    ** information use the contact form at https://www.qt.io/contact-us.
+    **
+    ** GNU General Public License Usage
+    ** Alternatively, this file may be used under the terms of the GNU
+    ** General Public License version 3 as published by the Free Software
+    ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+    ** included in the packaging of this file. Please review the following
+    ** information to ensure the GNU General Public License requirements will
+    ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+    **
+    ** $QT_END_LICENSE$
+    **
+    ****************************************************************************
+-->
+
+<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
+
+    <Type Name="##NAMESPACE##::QPoint">
+        <AlternativeType Name="##NAMESPACE##::QPointF"/>
+        <DisplayString>{{ x = {xp}, y = {yp} }}</DisplayString>
+        <Expand>
+            <Item Name="[x]">xp</Item>
+            <Item Name="[y]">yp</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QRect">
+        <DisplayString>{{ x = {x1}, y = {y1}, width = {x2 - x1 + 1}, height = {y2 - y1 + 1} }}</DisplayString>
+        <Expand>
+            <Item Name="[x]">x1</Item>
+            <Item Name="[y]">y1</Item>
+            <Item Name="[width]">x2 - x1 + 1</Item>
+            <Item Name="[height]">y2 - y1 + 1</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QRectF">
+        <DisplayString>{{ x = {xp}, y = {yp}, width = {w}, height = {h} }}</DisplayString>
+        <Expand>
+            <Item Name="[x]">xp</Item>
+            <Item Name="[y]">yp</Item>
+            <Item Name="[width]">w</Item>
+            <Item Name="[height]">h</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QSize">
+        <AlternativeType Name="##NAMESPACE##::QSizeF"/>
+        <DisplayString>{{ width = {wd}, height = {ht} }}</DisplayString>
+        <Expand>
+            <Item Name="[width]">wd</Item>
+            <Item Name="[height]">ht</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QLine">
+        <AlternativeType Name="##NAMESPACE##::QLineF"/>
+        <DisplayString>{{ start point = {pt1}, end point = {pt2} }}</DisplayString>
+        <Expand>
+            <Synthetic Name="[start point]">
+                <DisplayString>{pt1}</DisplayString>
+                <Expand>
+                    <ExpandedItem>pt1</ExpandedItem>
+                </Expand>
+            </Synthetic>
+            <Synthetic Name="[end point]">
+                <DisplayString>{pt2}</DisplayString>
+                <Expand>
+                    <ExpandedItem>pt2</ExpandedItem>
+                </Expand>
+            </Synthetic>
+
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QPolygon">
+        <DisplayString>{{ size = {d-&gt;size} }}</DisplayString>
+        <Expand>
+            <Item Name="[referenced]">d-&gt;ref.atomic._q_value</Item>
+            <ArrayItems>
+                <Size>d-&gt;size</Size>
+                <ValuePointer>(##NAMESPACE##::QPoint*)((reinterpret_cast&lt;char*&gt;(d)) + d-&gt;offset)</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QPolygonF">
+        <DisplayString>{{ size = {d-&gt;size} }}</DisplayString>
+        <Expand>
+            <Item Name="[closed]">
+                d-&gt;size &gt; 0
+                    &amp;&amp; ((((##NAMESPACE##::QPointF*)((reinterpret_cast&lt;char*&gt;(d)) + d-&gt;offset)[0]).xp
+                == (((##NAMESPACE##::QPointF*)((reinterpret_cast&lt;char*&gt;(d)) + d-&gt;offset)[d-&gt;size - 1]).xp)
+                    &amp;&amp; ((((##NAMESPACE##::QPointF*)((reinterpret_cast&lt;char*&gt;(d)) + d-&gt;offset)[0]).yp
+                == (((##NAMESPACE##::QPointF*)((reinterpret_cast&lt;char*&gt;(d)) + d-&gt;offset)[d-&gt;size - 1]).yp)
+            </Item>
+            <Item Name="[referenced]">d-&gt;ref.atomic._q_value</Item>
+            <ArrayItems>
+                <Size>d-&gt;size</Size>
+                <ValuePointer>(##NAMESPACE##::QPointF*)((reinterpret_cast&lt;char*&gt;(d)) + d-&gt;offset)</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+    <Type Name ="##NAMESPACE##::QVector2D">
+        <DisplayString>{{ x = {xp}, y = {yp} }}</DisplayString>
+        <Expand>
+            <Item Name="[x]">xp</Item>
+            <Item Name="[y]">yp</Item>
+        </Expand>
+    </Type>
+
+    <Type Name ="##NAMESPACE##::QVector3D">
+        <DisplayString>{{ x = {xp}, y = {yp}, z = {zp} }}</DisplayString>
+        <Expand>
+            <Item Name="[x]">xp</Item>
+            <Item Name="[y]">yp</Item>
+            <Item Name="[z]">zp</Item>
+        </Expand>
+    </Type>
+
+    <Type Name ="##NAMESPACE##::QVector4D">
+        <DisplayString>{{ x = {xp}, y = {yp}, z = {zp}, w = {wp} }}</DisplayString>
+        <Expand>
+            <Item Name="[x]">xp</Item>
+            <Item Name="[y]">yp</Item>
+            <Item Name="[z]">zp</Item>
+            <Item Name="[w]">wp</Item>
+        </Expand>
+    </Type>
+
+    <Type Name ="##NAMESPACE##::QMatrix">
+        <DisplayString>
+            {{ m11 = {_m11}, m12 = {_m12}, m21 = {_m21}, m22 = {_m22}, ... }}
+        </DisplayString>
+        <Expand>
+            <Item Name="[m11]">_m11</Item>
+            <Item Name="[m12]">_m12</Item>
+            <Item Name="[m21]">_m21</Item>
+            <Item Name="[m22]">_m22</Item>
+            <Item Name="[dx]">_dx</Item>
+            <Item Name="[dy]">_dy</Item>
+        </Expand>
+    </Type>
+
+    <Type Name ="##NAMESPACE##::QMatrix4x4">
+        <DisplayString>
+            {{ m11 = {m[0][0]}, m12 = {m[1][0]}, m13 = {m[2][0]}, m14 = {m[3][0]}, ... }}
+        </DisplayString>
+        <Expand>
+            <Item Name="[m11]">m[0][0]</Item>
+            <Item Name="[m12]">m[1][0]</Item>
+            <Item Name="[m13]">m[2][0]</Item>
+            <Item Name="[m14]">m[3][0]</Item>
+            <Item Name="[m21]">m[0][1]</Item>
+            <Item Name="[m22]">m[1][1]</Item>
+            <Item Name="[m23]">m[2][1]</Item>
+            <Item Name="[m24]">m[3][1]</Item>
+            <Item Name="[m31]">m[0][2]</Item>
+            <Item Name="[m32]">m[1][2]</Item>
+            <Item Name="[m33]">m[2][2]</Item>
+            <Item Name="[m34]">m[3][2]</Item>
+            <Item Name="[m41]">m[0][3]</Item>
+            <Item Name="[m42]">m[1][3]</Item>
+            <Item Name="[m43]">m[2][3]</Item>
+            <Item Name="[m44]">m[3][3]</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QSizePolicy">
+        <DisplayString>
+            {{ horizontal = {static_cast&lt;Policy&gt;(bits.horPolicy)}, vertical = {static_cast&lt;Policy&gt;(bits.verPolicy)}, type = {ControlType(1 &lt;&lt; bits.ctype)} }}
+        </DisplayString>
+        <Expand>
+            <Synthetic Name="[vertical policy]">
+                <DisplayString>##NAMESPACE##::QSizePolicy::Policy::{static_cast&lt;Policy&gt;(bits.verPolicy)}</DisplayString>
+            </Synthetic>
+            <Synthetic Name="[horizontal policy]">
+                <DisplayString>##NAMESPACE##::QSizePolicy::Policy::{static_cast&lt;Policy&gt;(bits.horPolicy)}</DisplayString>
+            </Synthetic>
+            <Synthetic Name="[control type]">
+                <DisplayString>##NAMESPACE##::QSizePolicy::ControlType::{ControlType(1 &lt;&lt; bits.ctype)}</DisplayString>
+            </Synthetic>
+            <Synthetic Name="[expanding directions]">
+                <DisplayString
+                    Condition="(static_cast&lt;Policy&gt;(bits.verPolicy) &amp; ExpandFlag)">
+                        ##NAMESPACE##::Qt::Vertical (2)
+                    </DisplayString>
+                <DisplayString
+                    Condition="(static_cast&lt;Policy&gt;(bits.horPolicy) &amp; ExpandFlag)">
+                        ##NAMESPACE##::Qt::Horizontal (1)
+                </DisplayString>
+            </Synthetic>
+            <Item Name="[vertical stretch]">static_cast&lt;int&gt;(bits.verStretch)</Item>
+            <Item Name="[horizontal stretch]">static_cast&lt;int&gt;(bits.horStretch)</Item>
+            <Item Name="[has height for width]">bits.hfw == 1</Item>
+            <Item Name="[has width for height]">bits.wfh == 1</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QChar">
+        <DisplayString>{ucs,c}</DisplayString>
+        <StringView>ucs,c</StringView>
+        <Expand>
+            <Item Name="[latin 1]">ucs > 0xff ? '\0' : char(ucs),c</Item>
+            <Item Name="[unicode]">ucs,c</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QString">
+        <DisplayString>{((reinterpret_cast&lt;unsigned short*&gt;(d)) + d-&gt;offset / 2),sub}</DisplayString>
+        <StringView>((reinterpret_cast&lt;unsigned short*&gt;(d)) + d-&gt;offset / 2),sub</StringView>
+        <Expand>
+            <Item Name="[size]">d-&gt;size</Item>
+            <Item Name="[referenced]">d-&gt;ref.atomic._q_value</Item>
+            <ArrayItems>
+                <Size>d-&gt;size</Size>
+                <ValuePointer>((reinterpret_cast&lt;unsigned short*&gt;(d)) + d-&gt;offset / 2),c</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QStringRef">
+        <Intrinsic Name="offset" Expression="(reinterpret_cast&lt;char16_t*&gt;(m_string-&gt;d))
+            + m_string-&gt;d->offset / 2" />
+        <DisplayString Condition="m_string == nullptr">{m_string,[m_size]} u""</DisplayString>
+        <DisplayString Condition="m_string != nullptr">{offset() + m_position,[m_size]}</DisplayString>
+        <Expand>
+            <Item Name="[position]" ExcludeView="simple">m_position</Item>
+            <Item Name="[size]" ExcludeView="simple">m_size</Item>
+            <ArrayItems Condition="m_string != nullptr">
+                <Size>m_size</Size>
+                <ValuePointer>offset()+m_position</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QStringView">
+        <DisplayString>{m_data,[m_size]}</DisplayString>
+        <StringView>m_data,[m_size]</StringView>
+        <Expand>
+            <Item Name="[size]" ExcludeView="simple">m_size</Item>
+            <ArrayItems>
+                <Size>m_size</Size>
+                <ValuePointer>m_data</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QByteArray">
+        <DisplayString>{((reinterpret_cast&lt;char*&gt;(d)) + d-&gt;offset),sb}</DisplayString>
+        <StringView>((reinterpret_cast&lt;char*&gt;(d)) + d-&gt;offset),sb</StringView>
+        <Expand>
+            <Item Name="[size]">d-&gt;size</Item>
+            <Item Name="[referenced]">d-&gt;ref.atomic._q_value</Item>
+            <ArrayItems>
+                <Size>d-&gt;size</Size>
+                <ValuePointer>((reinterpret_cast&lt;char*&gt;(d)) + d-&gt;offset),c</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QUrl">
+        <Intrinsic Name="isEmpty" Expression="size==0">
+            <Parameter Name="size" Type="int"/>
+        </Intrinsic>
+        <Intrinsic Name="memberOffset" Expression="sizeof(QAtomicInt) + sizeof(int) + (sizeof(QString) * count)">
+            <Parameter Name="count" Type="int"/>
+        </Intrinsic>
+        <Intrinsic Name="scheme" Expression="*((QString*)(((char*)(d) + memberOffset(0))))" />
+        <Intrinsic Name="username" Expression="*((QString*)(((char*)(d) + memberOffset(1))))" />
+        <Intrinsic Name="password" Expression="*((QString*)(((char*)(d) + memberOffset(2))))" />
+        <Intrinsic Name="host" Expression="*((QString*)(((char*)(d) + memberOffset(3))))" />
+        <Intrinsic Name="path" Expression="*((QString*)(((char*)(d) + memberOffset(4))))" />
+        <Intrinsic Name="query" Expression="*((QString*)(((char*)(d) + memberOffset(5))))" />
+        <Intrinsic Name="fragment" Expression="*((QString*)(((char*)(d) + memberOffset(6))))" />
+
+        <DisplayString Condition="!isEmpty(scheme().d-&gt;size)">{scheme()}://{host()}{path()}</DisplayString>
+        <DisplayString Condition="isEmpty(scheme().d-&gt;size)">{path()}</DisplayString>
+        <Expand>
+            <Item Name="[scheme]">scheme()</Item>
+            <Item Name="[username]">username()</Item>
+            <Item Name="[password]">password()</Item>
+            <Item Name="[host]">host()</Item>
+            <Item Name="[path]">path()</Item>
+            <Item Name="[query]">query()</Item>
+            <Item Name="[fragment]">fragment()</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QBitArray">
+        <DisplayString>{{ size = {(d.d-&gt;size &lt;&lt; 3) - *((reinterpret_cast&lt;char*&gt;(d.d)) + d.d-&gt;offset)} }}</DisplayString>
+        <Expand>
+            <Item Name="[referenced]">d.d-&gt;ref.atomic._q_value</Item>
+            <IndexListItems>
+                <Size>(d.d-&gt;size &lt;&lt; 3) - *((reinterpret_cast&lt;char*&gt;(d.d)) + d.d-&gt;offset)</Size>
+                <ValueNode>
+                    (*(reinterpret_cast&lt;const unsigned char*&gt;((reinterpret_cast&lt;char*&gt;(d.d)) + d.d-&gt;offset) + 1
+                        + ($i &gt;&gt; 3)) &amp; (1 &lt;&lt; ($i &amp; 7))) != 0
+                </ValueNode>
+            </IndexListItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QVarLengthArray&lt;*&gt;">
+        <AlternativeType Name="##NAMESPACE##::QVarLengthArray&lt;*, int&gt;"/>
+        <DisplayString>{{ size = {s} }}</DisplayString>
+        <Expand>
+            <Item Name="[capacity]">a</Item>
+            <ArrayItems>
+                <Size>s</Size>
+                <ValuePointer>ptr</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QDate">
+        <DisplayString>{{ julian day = {jd} }}</DisplayString>
+        <Expand></Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QTime">
+        <DisplayString
+            Condition="mds == 1">{{ millisecond = {mds} }}</DisplayString>
+        <DisplayString
+            Condition="mds != 1">{{ milliseconds = {mds} }}</DisplayString>
+        <Expand>
+            <Item Name="[hour]"
+                  Condition="(mds / 3600000) == 1">mds / 3600000, d</Item>
+            <Item Name="[hours]"
+                  Condition="(mds / 3600000) != 1">mds / 3600000, d</Item>
+            <Item Name="[minute]"
+                  Condition="((mds % 3600000) / 60000) == 1">(mds % 3600000) / 60000, d</Item>
+            <Item Name="[minutes]"
+                  Condition="((mds % 3600000) / 60000) != 1">(mds % 3600000) / 60000, d</Item>
+            <Item Name="[second]"
+                  Condition="((mds / 1000) % 60) == 1">(mds / 1000) % 60, d</Item>
+            <Item Name="[seconds]"
+                  Condition="((mds / 1000) % 60) != 1">(mds / 1000) % 60, d</Item>
+            <Item Name="[millisecond]"
+                  Condition="(mds % 1000) == 1">mds % 1000, d</Item>
+            <Item Name="[milliseconds]"
+                  Condition="(mds % 1000) != 1">mds % 1000, d</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QRegularExpression">
+        <DisplayString>{d.pattern}</DisplayString>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QSharedData">
+        <Expand>
+            <Item Name="[referenced]">ref._q_value</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QSharedPointer&lt;*&gt;">
+        <DisplayString>strong reference to shared pointer of type {"$T1"}</DisplayString>
+        <Expand>
+            <Item Name="[is null]">value == 0</Item>
+            <Item Name="[weak referenced]">d-&gt;weakref._q_value</Item>
+            <Item Name="[strong referenced]">d-&gt;strongref._q_value</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QSharedDataPointer&lt;*&gt;">
+        <DisplayString>pointer to implicit shared object of type {"$T1"}</DisplayString>
+        <Expand>
+            <ExpandedItem>d</ExpandedItem>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QExplicitlySharedDataPointer&lt;*&gt;">
+        <DisplayString>pointer to explicit shared object of type {"$T1"}</DisplayString>
+        <Expand>
+            <ExpandedItem>d</ExpandedItem>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QPointer&lt;*&gt;">
+        <DisplayString>guarded pointer to subclass of QObject of type {"$T1"}</DisplayString>
+        <Expand>
+            <Item Name="[is null]">wp.d == 0 || wp.d-&gt;strongref._q_value == 0 || wp.value == 0</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QWeakPointer&lt;*&gt;">
+        <DisplayString>weak reference to shared pointer of type {"$T1"}</DisplayString>
+        <Expand>
+            <Item Name="[is null]">d == 0 || d-&gt;strongref._q_value == 0 || value == 0</Item>
+            <Item Name="[weak referenced]">d-&gt;weakref._q_value</Item>
+            <Item Name="[strong referenced]">d-&gt;strongref._q_value</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QScopedPointer&lt;*&gt;">
+        <DisplayString>scoped pointer to a dynamically allocated object of type {"$T1"}</DisplayString>
+        <Expand>
+            <Item Name="[is null]">!d</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QScopedArrayPointer&lt;*&gt;">
+        <DisplayString>scoped pointer to dynamically allocated array of objects of type {"$T1"}</DisplayString>
+        <Expand>
+            <Item Name="[is null]">!d</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QPair&lt;*,*&gt;">
+        <DisplayString>({first}, {second})</DisplayString>
+        <Expand>
+            <Item Name="[first]">first</Item>
+            <Item Name="[second]">second</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QVector&lt;*&gt;">
+        <AlternativeType Name="##NAMESPACE##::QStack&lt;*&gt;"></AlternativeType>
+        <DisplayString>{{ size = {d-&gt;size} }}</DisplayString>
+        <Expand>
+            <Item Name="[referenced]">d-&gt;ref.atomic._q_value</Item>
+            <ArrayItems>
+                <Size>d-&gt;size</Size>
+                <ValuePointer>($T1*)((reinterpret_cast&lt;char*&gt;(d)) + d-&gt;offset)</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QList&lt;*&gt;">
+        <AlternativeType Name="##NAMESPACE##::QQueue&lt;*&gt;"></AlternativeType>
+        <DisplayString>{{ size = {d-&gt;end - d-&gt;begin} }}</DisplayString>
+        <Expand>
+            <Item Name="[referenced]">d-&gt;ref.atomic._q_value</Item>
+            <IndexListItems>
+                <Size>d-&gt;end - d-&gt;begin</Size>
+                <ValueNode>*reinterpret_cast&lt;$T1*&gt;((sizeof($T1) &gt; sizeof(void*))
+                    ? reinterpret_cast&lt;Node*&gt;(d-&gt;array + d-&gt;begin + $i)-&gt;v
+                    : reinterpret_cast&lt;$T1*&gt;(d-&gt;array + d-&gt;begin + $i))
+                </ValueNode>
+            </IndexListItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QStringList">
+        <DisplayString>{{ size = {d-&gt;end - d-&gt;begin} }}</DisplayString>
+        <Expand>
+            <Item Name="[referenced]">d-&gt;ref.atomic._q_value</Item>
+            <IndexListItems>
+                <Size>d-&gt;end - d-&gt;begin</Size>
+                <ValueNode>
+                    *reinterpret_cast&lt;QString*&gt;((sizeof(QString) &gt; sizeof(void*))
+                    ? reinterpret_cast&lt;Node*&gt;(d-&gt;array + d-&gt;begin + $i)-&gt;v
+                    : reinterpret_cast&lt;QString*&gt;(d-&gt;array + d-&gt;begin + $i))
+                </ValueNode>
+            </IndexListItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QList&lt;QVariant&gt;">
+        <DisplayString>{{ size = {d-&gt;end - d-&gt;begin} }}</DisplayString>
+        <Expand>
+            <Item Name="[referenced]">d-&gt;ref.atomic._q_value</Item>
+            <IndexListItems>
+                <Size>d-&gt;end - d-&gt;begin</Size>
+                <ValueNode>
+                    *reinterpret_cast&lt;QVariant*&gt;((sizeof(QVariant) &gt; sizeof(void*))
+                    ? reinterpret_cast&lt;Node*&gt;(d-&gt;array + d-&gt;begin + $i)-&gt;v
+                    : reinterpret_cast&lt;QVariant*&gt;(d-&gt;array + d-&gt;begin + $i))
+                </ValueNode>
+            </IndexListItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QLinkedList&lt;*&gt;">
+        <DisplayString>{{ size = {d-&gt;size} }}</DisplayString>
+        <Expand>
+            <Item Name="[referenced]">d-&gt;ref.atomic._q_value</Item>
+            <LinkedListItems>
+                <Size>d-&gt;size</Size>
+                <HeadPointer>d-&gt;n</HeadPointer>
+                <NextPointer>n</NextPointer>
+                <ValueNode>(*(##NAMESPACE##::QLinkedListNode&lt;$T1&gt;*)this).t</ValueNode>
+            </LinkedListItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QMapNode&lt;*,*&gt;">
+        <DisplayString>({key}, {value})</DisplayString>
+        <Expand>
+            <Item Name="[key]">key</Item>
+            <Item Name="[value]">value</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QMap&lt;*,*&gt;">
+        <AlternativeType Name="##NAMESPACE##::QMultiMap&lt;*,*&gt;"/>
+        <DisplayString>{{ size = {d-&gt;size} }}</DisplayString>
+        <Expand>
+            <Item Name="[referenced]">d-&gt;ref.atomic._q_value</Item>
+            <TreeItems>
+                <Size>d-&gt;size</Size>
+                <HeadPointer>d-&gt;header.left</HeadPointer>
+                <LeftPointer>left</LeftPointer>
+                <RightPointer>right</RightPointer>
+                <ValueNode>*((##NAMESPACE##::QMapNode&lt;$T1,$T2&gt;*)this)</ValueNode>
+            </TreeItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QHashNode&lt;*,*&gt;">
+        <DisplayString Condition="next == 0">(empty)</DisplayString>
+        <DisplayString Condition="next != 0">({key}, {value})</DisplayString>
+        <Expand>
+            <Item Name="[key]" Condition="next != 0">key</Item>
+            <Item Name="[value]" Condition="next != 0">value</Item>
+            <Item Name="[next]" Condition="next != 0">next</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QHash&lt;*,*&gt;">
+        <AlternativeType Name="##NAMESPACE##::QMultiHash&lt;*,*&gt;"/>
+        <DisplayString>{{ size = {d-&gt;size} }}</DisplayString>
+        <Expand>
+            <ArrayItems IncludeView="buckets">
+                <Size>d-&gt;numBuckets</Size>
+                <ValuePointer>reinterpret_cast&lt;Node **&gt;(d-&gt;buckets)</ValuePointer>
+            </ArrayItems>
+            <CustomListItems ExcludeView="buckets">
+                <Variable Name="n" InitialValue="d-&gt;numBuckets"/>
+                <Variable Name="bucket" InitialValue="d-&gt;buckets"/>
+                <Variable Name="node" InitialValue="d-&gt;buckets[0]"/>
+                <Variable Name="keyValuePair" InitialValue="reinterpret_cast&lt;Node *&gt;(0)"/>
+                <Size>d-&gt;size</Size>
+                <Loop>
+                    <Break Condition="n == 0"/>
+                    <Exec>node = *(bucket++)</Exec>
+                    <Exec>--n</Exec>
+                    <Loop>
+                        <Break Condition="!node || !node-&gt;next"/>
+                        <Exec>keyValuePair = reinterpret_cast&lt;Node *&gt;(node)</Exec>
+                        <Item Name="[{keyValuePair-&gt;key}]">keyValuePair-&gt;value</Item>
+                        <Exec>node = node-&gt;next</Exec>
+                    </Loop>
+                </Loop>
+            </CustomListItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QHashNode&lt;*,##NAMESPACE##::QHashDummyValue&gt;">
+        <DisplayString Condition="next == 0">(empty)</DisplayString>
+        <DisplayString Condition="next != 0">({key})</DisplayString>
+        <Expand>
+            <Item Name="[key]" Condition="next != 0">key</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QSet&lt;*&gt;">
+        <DisplayString>{{ size = {q_hash.d-&gt;size} }}</DisplayString>
+        <Expand>
+            <ExpandedItem>q_hash</ExpandedItem>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QCache&lt;*,*&gt;::Node">
+        <DisplayString>({*keyPtr}, {*t})</DisplayString>
+        <Expand>
+            <Item Name="[key]">*keyPtr</Item>
+            <Item Name="[value]">*t</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QCache&lt;*,*&gt;">
+        <DisplayString>{{ size = {hash.d-&gt;size} }}</DisplayString>
+        <Expand>
+            <Item Name="[max coast]">mx</Item>
+            <Item Name="[total coast]">total</Item>
+            <Item Name="[referenced]">hash.d-&gt;ref.atomic._q_value</Item>
+            <LinkedListItems>
+                <Size>hash.d-&gt;size</Size>
+                <HeadPointer>f</HeadPointer>
+                <NextPointer>n</NextPointer>
+                <ValueNode>*((Node*)this)</ValueNode>
+            </LinkedListItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QStandardItemPrivate">
+        <Intrinsic Name="memberOffset" Expression="sizeof(QStandardItemModel *)
+                                                 + sizeof(QStandardItem *)
+                                                 + sizeof(int *)
+                                                 + sizeof(int *)
+                                                 + (sizeof(int) * count)">
+            <Parameter Name="count" Type="int"/>
+        </Intrinsic>
+        <Intrinsic Name="rows" Expression="*((int*)(((char*)(this)) + memberOffset(0)))" />
+        <Intrinsic Name="columns" Expression="*((int*)(((char*)(this)) + memberOffset(1)))" />
+    </Type>
+
+    <Type Name="##NAMESPACE##::QStandardItem">
+        <DisplayString>{{ row count = {(*d_ptr.d).rows()}, column count = {(*d_ptr.d).columns()} }}</DisplayString>
+        <Expand>
+            <Item Name="[d]">d_ptr.d,!</Item>
+            <Item Name="[row count]">(*d_ptr.d).rows()</Item>
+            <Item Name="[column count]">(*d_ptr.d).columns()</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QVariant">
+        <!--Region DisplayString QVariant-->
+
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::UnknownType">Invalid</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::Bool">{d.data.b}</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::Int">{d.data.i}</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::UInt">{d.data.u}</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::LongLong">{d.data.ll}</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::ULongLong">{d.data.ull}</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::Double">{d.data.d}</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QChar">{d.data.c}</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QVariantMap">
+            {*((##NAMESPACE##::QMap&lt;##NAMESPACE##::QString,##NAMESPACE##::QVariant&gt;*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))}
+        </DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QVariantList">
+            {*((##NAMESPACE##::QList&lt;##NAMESPACE##::QVariant&gt;*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))}
+        </DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QString">
+            {*((##NAMESPACE##::QString*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))}
+        </DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QStringList">
+            {*((##NAMESPACE##::QStringList*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))}
+        </DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QByteArray">
+            {*((##NAMESPACE##::QByteArray*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))}
+        </DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QBitArray">
+            {*((##NAMESPACE##::QBitArray*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))}
+        </DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QDate">
+            {*((##NAMESPACE##::QDate*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))}
+        </DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QTime">
+            {*((##NAMESPACE##::QTime*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))}
+        </DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QDateTime">DateTime</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QUrl">Url</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QLocale">Locale</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QRect">
+            {*((##NAMESPACE##::QRect*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))}
+        </DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QRectF">
+            {*((##NAMESPACE##::QRectF*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))}
+        </DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QSize">
+            {*((##NAMESPACE##::QSize*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))}
+        </DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QSizeF">
+            {*((##NAMESPACE##::QSizeF*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))}
+        </DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QLine">
+            {*((##NAMESPACE##::QLine*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))}
+        </DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QLineF">
+            {*((##NAMESPACE##::QLineF*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))}
+        </DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QPoint">
+            {*((##NAMESPACE##::QPoint*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))}
+        </DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QPointF">
+            {*((##NAMESPACE##::QPointF*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))}
+        </DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QRegExp">RegExp</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QRegularExpression">RegularExpression</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QVariantHash">
+            {*((##NAMESPACE##::QHash&lt;##NAMESPACE##::QString,##NAMESPACE##::QVariant&gt;*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))}
+        </DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QEasingCurve">EasingCurve</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QUuid">Uuid</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QModelIndex">ModelIndex</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::LastCoreType">LastCoreType</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QFont">Font</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QPixmap">Pixmap</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QBrush">Brush</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QColor">Color</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QPalette">Palette</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QImage">Image</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QPolygon">Polygon</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QRegion">Region</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QBitmap">Bitmap</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QCursor">Cursor</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QKeySequence">KeySequence</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QPen">Pen</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QTextLength">TextLength</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QTextFormat">TextFormat</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QMatrix">Matrix</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QTransform">Transform</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QMatrix4x4">Matrix4x4</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QVector2D">Vector2D</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QVector3D">Vector3D</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QVector4D">Vector4D</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QQuaternion">Quaternion</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QPolygonF">PolygonF</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QIcon">Icon</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::LastGuiType">LastGuiType</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::QSizePolicy">SizePolicy</DisplayString>
+        <DisplayString Condition="d.type == ##NAMESPACE##::QMetaType::User">UserType</DisplayString>
+        <DisplayString Condition="d.type == 0xffffffff">LastType</DisplayString>
+
+        <!--End region DisplayString QVariant-->
+
+        <!--Region DisplayView QVariant-->
+
+        <StringView Condition="d.type == ##NAMESPACE##::QMetaType::QChar">d.data.c</StringView>
+
+        <StringView Condition="d.type == ##NAMESPACE##::QMetaType::QString">
+            *((##NAMESPACE##::QString*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))
+        </StringView>
+
+        <StringView Condition="d.type == ##NAMESPACE##::QMetaType::QByteArray">
+            *((##NAMESPACE##::QByteArray*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))
+        </StringView>
+
+        <!--End region DisplayView QVariant-->
+
+        <!--Region Expand QVariant-->
+
+        <Expand>
+            <ExpandedItem Condition="d.type == ##NAMESPACE##::QMetaType::QVariantMap">
+                *((##NAMESPACE##::QMap&lt;##NAMESPACE##::QString,##NAMESPACE##::QVariant&gt;*)(d.is_shared ? d.data.shared-&gt;ptr
+                    : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))
+            </ExpandedItem>
+            <ExpandedItem Condition="d.type == ##NAMESPACE##::QMetaType::QVariantList">
+                *((##NAMESPACE##::QList&lt;##NAMESPACE##::QVariant&gt;*)(d.is_shared ? d.data.shared-&gt;ptr
+                    : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))
+            </ExpandedItem>
+            <ExpandedItem Condition="d.type == ##NAMESPACE##::QMetaType::QString">
+                *((##NAMESPACE##::QString*)(d.is_shared ? d.data.shared-&gt;ptr
+                    : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))
+            </ExpandedItem>
+            <ExpandedItem Condition="d.type == ##NAMESPACE##::QMetaType::QStringList">
+                *((##NAMESPACE##::QStringList*)(d.is_shared ? d.data.shared-&gt;ptr
+                    : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))
+            </ExpandedItem>
+            <ExpandedItem Condition="d.type == ##NAMESPACE##::QMetaType::QByteArray">
+                *((##NAMESPACE##::QByteArray*)(d.is_shared ? d.data.shared-&gt;ptr
+                    : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))
+            </ExpandedItem>
+            <ExpandedItem Condition="d.type == ##NAMESPACE##::QMetaType::QBitArray">
+                *((##NAMESPACE##::QBitArray*)(d.is_shared ? d.data.shared-&gt;ptr
+                    : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))
+            </ExpandedItem>
+            <ExpandedItem Condition="d.type == ##NAMESPACE##::QMetaType::QDate">
+                *((##NAMESPACE##::QDate*)(d.is_shared ? d.data.shared-&gt;ptr
+                    : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))
+            </ExpandedItem>
+            <ExpandedItem Condition="d.type == ##NAMESPACE##::QMetaType::QTime">
+                *((##NAMESPACE##::QTime*)(d.is_shared ? d.data.shared-&gt;ptr
+                    : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))
+            </ExpandedItem>
+            <ExpandedItem Condition="d.type == ##NAMESPACE##::QMetaType::QRect">
+                *((##NAMESPACE##::QRect*)(d.is_shared ? d.data.shared-&gt;ptr
+                    : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))
+            </ExpandedItem>
+            <ExpandedItem Condition="d.type == ##NAMESPACE##::QMetaType::QRectF">
+                *((##NAMESPACE##::QRectF*)(d.is_shared ? d.data.shared-&gt;ptr
+                    : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))
+            </ExpandedItem>
+            <ExpandedItem Condition="d.type == ##NAMESPACE##::QMetaType::QSize">
+                *((##NAMESPACE##::QSize*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))
+            </ExpandedItem>
+            <ExpandedItem Condition="d.type == ##NAMESPACE##::QMetaType::QSizeF">
+                *((##NAMESPACE##::QSizeF*)(d.is_shared ? d.data.shared-&gt;ptr
+                : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))
+            </ExpandedItem>
+            <ExpandedItem Condition="d.type == ##NAMESPACE##::QMetaType::QLine">
+                *((##NAMESPACE##::QLine*)(d.is_shared ? d.data.shared-&gt;ptr
+                    : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))
+            </ExpandedItem>
+            <ExpandedItem Condition="d.type == ##NAMESPACE##::QMetaType::QLineF">
+                *((##NAMESPACE##::QLineF*)(d.is_shared ? d.data.shared-&gt;ptr
+                    : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))
+            </ExpandedItem>
+            <ExpandedItem Condition="d.type == ##NAMESPACE##::QMetaType::QPoint">
+                *((##NAMESPACE##::QPoint*)(d.is_shared ? d.data.shared-&gt;ptr
+                    : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))
+            </ExpandedItem>
+            <ExpandedItem Condition="d.type == ##NAMESPACE##::QMetaType::QPointF">
+                *((##NAMESPACE##::QPointF*)(d.is_shared ? d.data.shared-&gt;ptr
+                    : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))
+            </ExpandedItem>
+            <ExpandedItem Condition="d.type == ##NAMESPACE##::QMetaType::QVariantHash">
+                *((##NAMESPACE##::QHash&lt;##NAMESPACE##::QString,##NAMESPACE##::QVariant&gt;*)(d.is_shared ? d.data.shared-&gt;ptr
+                    : reinterpret_cast&lt;const void *&gt;(&amp;d.data.ptr)))
+            </ExpandedItem>
+        </Expand>
+
+        <!--End region Expand QVariant-->
+    </Type>
+
+</AutoVisualizer>
diff --git a/QtMSBuild/QtMsBuild/qt6.natvis.xml b/QtMSBuild/QtMsBuild/qt6.natvis.xml
new file mode 100644
index 0000000..6f4a131
--- /dev/null
+++ b/QtMSBuild/QtMsBuild/qt6.natvis.xml
@@ -0,0 +1,406 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    ****************************************************************************
+    **
+    ** Copyright (C) 2022 The Qt Company Ltd.
+    ** Contact: https://www.qt.io/licensing/
+    **
+    ** This file is part of the Qt VS Tools.
+    **
+    ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+    ** Commercial License Usage
+    ** Licensees holding valid commercial Qt licenses may use this file in
+    ** accordance with the commercial license agreement provided with the
+    ** Software or, alternatively, in accordance with the terms contained in
+    ** a written agreement between you and The Qt Company. For licensing terms
+    ** and conditions see https://www.qt.io/terms-conditions. For further
+    ** information use the contact form at https://www.qt.io/contact-us.
+    **
+    ** GNU General Public License Usage
+    ** Alternatively, this file may be used under the terms of the GNU
+    ** General Public License version 3 as published by the Free Software
+    ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+    ** included in the packaging of this file. Please review the following
+    ** information to ensure the GNU General Public License requirements will
+    ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+    **
+    ** $QT_END_LICENSE$
+    **
+    ****************************************************************************
+-->
+
+<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
+
+   <Type Name="##NAMESPACE##::QSpecialInteger&lt;*&gt;">
+        <DisplayString>{val}</DisplayString>
+        <Expand>
+            <Item Name="[value]">val</Item>
+        </Expand>
+    </Type>
+
+   <Type Name="##NAMESPACE##::QBasicAtomicInteger&lt;*&gt;">
+        <DisplayString>{_q_value}</DisplayString>
+        <Expand>
+            <Item Name="[value]">_q_value</Item>
+        </Expand>
+    </Type>
+
+   <Type Name="##NAMESPACE##::QBasicAtomicPointer&lt;*&gt;">
+        <Intrinsic Name="isNull" Expression="value()==0" />
+        <Intrinsic Name="value" Expression="_q_value.value()" />
+        <DisplayString Condition="isNull()">empty</DisplayString>
+        <DisplayString Condition="!isNull()">{_q_value}</DisplayString>
+        <Expand>
+            <Item Name=" " Condition="!isNull()">*value()</Item>
+        </Expand>
+    </Type>
+
+   <Type Name="##NAMESPACE##::QPoint">
+        <AlternativeType Name="##NAMESPACE##::QPointF"/>
+        <DisplayString>{{ x = {xp}, y = {yp} }}</DisplayString>
+        <Expand>
+            <Item Name="[x]">xp</Item>
+            <Item Name="[y]">yp</Item>
+        </Expand>
+    </Type>
+
+   <Type Name="##NAMESPACE##::QRect">
+        <DisplayString>{{ x = {x1}, y = {y1}, width = {x2 - x1 + 1}, height = {y2 - y1 + 1} }}</DisplayString>
+        <Expand>
+            <Item Name="[x]">x1</Item>
+            <Item Name="[y]">y1</Item>
+            <Item Name="[width]">x2 - x1 + 1</Item>
+            <Item Name="[height]">y2 - y1 + 1</Item>
+        </Expand>
+    </Type>
+
+   <Type Name="##NAMESPACE##::QRectF">
+        <DisplayString>{{ x = {xp}, y = {yp}, width = {w}, height = {h} }}</DisplayString>
+        <Expand>
+            <Item Name="[x]">xp</Item>
+            <Item Name="[y]">yp</Item>
+            <Item Name="[width]">w</Item>
+            <Item Name="[height]">h</Item>
+        </Expand>
+    </Type>
+
+   <Type Name="##NAMESPACE##::QSize">
+        <AlternativeType Name="##NAMESPACE##::QSizeF"/>
+        <DisplayString>{{ width = {wd}, height = {ht} }}</DisplayString>
+        <Expand>
+            <Item Name="[width]">wd</Item>
+            <Item Name="[height]">ht</Item>
+        </Expand>
+    </Type>
+
+   <Type Name="##NAMESPACE##::QLine">
+        <AlternativeType Name="##NAMESPACE##::QLineF"/>
+        <DisplayString>{{ start point = {pt1}, end point = {pt2} }}</DisplayString>
+        <Expand>
+            <Synthetic Name="[start point]">
+                <DisplayString>{pt1}</DisplayString>
+                <Expand>
+                    <ExpandedItem>pt1</ExpandedItem>
+                </Expand>
+            </Synthetic>
+            <Synthetic Name="[end point]">
+                <DisplayString>{pt2}</DisplayString>
+                <Expand>
+                    <ExpandedItem>pt2</ExpandedItem>
+                </Expand>
+            </Synthetic>
+
+        </Expand>
+    </Type>
+
+   <Type Name="##NAMESPACE##::QPolygon">
+        <DisplayString>{{ size={d-&gt;size} }}</DisplayString>
+        <Expand>
+            <Item Name="[referenced]">d-&gt;ref.atomic._q_value</Item>
+            <ArrayItems>
+                <Size>d-&gt;size</Size>
+                <ValuePointer>(QPoint*)((reinterpret_cast&lt;char*&gt;(d)) + d-&gt;offset)</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+   <Type Name="##NAMESPACE##::QPolygonF">
+        <DisplayString>{{ size={d-&gt;size} }}</DisplayString>
+        <Expand>
+            <Item Name="[closed]">
+                d-&gt;size &gt; 0
+                &amp;&amp; ((((QPointF*)((reinterpret_cast&lt;char*&gt;(d)) + d-&gt;offset)[0]).xp
+                == (((QPointF*)((reinterpret_cast&lt;char*&gt;(d)) + d-&gt;offset)[d-&gt;size - 1]).xp)
+                &amp;&amp; ((((QPointF*)((reinterpret_cast&lt;char*&gt;(d)) + d-&gt;offset)[0]).yp
+                == (((QPointF*)((reinterpret_cast&lt;char*&gt;(d)) + d-&gt;offset)[d-&gt;size - 1]).yp)
+            </Item>
+            <Item Name="[referenced]">d-&gt;ref.atomic._q_value</Item>
+            <ArrayItems>
+                <Size>d-&gt;size</Size>
+                <ValuePointer>(QPointF*)((reinterpret_cast&lt;char*&gt;(d)) + d-&gt;offset)</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QVector2D">
+        <DisplayString>{{ x = {xp}, y = {yp} }}</DisplayString>
+        <Expand>
+            <Item Name="[x]">xp</Item>
+            <Item Name="[y]">yp</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QVector3D">
+        <DisplayString>{{ x = {xp}, y = {yp}, z = {zp} }}</DisplayString>
+        <Expand>
+            <Item Name="[x]">xp</Item>
+            <Item Name="[y]">yp</Item>
+            <Item Name="[z]">zp</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QVector4D">
+        <DisplayString>{{ x = {xp}, y = {yp}, z = {zp}, w = {wp} }}</DisplayString>
+        <Expand>
+            <Item Name="[x]">xp</Item>
+            <Item Name="[y]">yp</Item>
+            <Item Name="[z]">zp</Item>
+            <Item Name="[w]">wp</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QMatrix">
+        <DisplayString>
+            {{ m11 = {_m11}, m12 = {_m12}, m21 = {_m21}, m22 = {_m22}, ... }}
+        </DisplayString>
+        <Expand>
+            <Item Name="[m11]">_m11</Item>
+            <Item Name="[m12]">_m12</Item>
+            <Item Name="[m21]">_m21</Item>
+            <Item Name="[m22]">_m22</Item>
+            <Item Name="[dx]">_dx</Item>
+            <Item Name="[dy]">_dy</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QMatrix4x4">
+        <DisplayString>
+            {{ m11 = {m[0][0]}, m12 = {m[1][0]}, m13 = {m[2][0]}, m14 = {m[3][0]}, ... }}
+        </DisplayString>
+        <Expand>
+            <Item Name="[m11]">m[0][0]</Item>
+            <Item Name="[m12]">m[1][0]</Item>
+            <Item Name="[m13]">m[2][0]</Item>
+            <Item Name="[m14]">m[3][0]</Item>
+            <Item Name="[m21]">m[0][1]</Item>
+            <Item Name="[m22]">m[1][1]</Item>
+            <Item Name="[m23]">m[2][1]</Item>
+            <Item Name="[m24]">m[3][1]</Item>
+            <Item Name="[m31]">m[0][2]</Item>
+            <Item Name="[m32]">m[1][2]</Item>
+            <Item Name="[m33]">m[2][2]</Item>
+            <Item Name="[m34]">m[3][2]</Item>
+            <Item Name="[m41]">m[0][3]</Item>
+            <Item Name="[m42]">m[1][3]</Item>
+            <Item Name="[m43]">m[2][3]</Item>
+            <Item Name="[m44]">m[3][3]</Item>
+        </Expand>
+    </Type>
+
+   <Type Name="##NAMESPACE##::QSizePolicy">
+        <DisplayString>
+            {{ horizontal = {static_cast&lt;Policy&gt;(bits.horPolicy)}, vertical = {static_cast&lt;Policy&gt;(bits.verPolicy)}, type = {ControlType(1 &lt;&lt; bits.ctype)} }}
+        </DisplayString>
+        <Expand>
+            <Synthetic Name="[vertical policy]">
+                <DisplayString>QSizePolicy::Policy::{static_cast&lt;Policy&gt;(bits.verPolicy)}</DisplayString>
+            </Synthetic>
+            <Synthetic Name="[horizontal policy]">
+                <DisplayString>QSizePolicy::Policy::{static_cast&lt;Policy&gt;(bits.horPolicy)}</DisplayString>
+            </Synthetic>
+            <Synthetic Name="[control type]">
+                <DisplayString>QSizePolicy::ControlType::{ControlType(1 &lt;&lt; bits.ctype)}</DisplayString>
+            </Synthetic>
+            <Synthetic Name="[expanding directions]">
+                <DisplayString
+                    Condition="(static_cast&lt;Policy&gt;(bits.verPolicy) &amp; ExpandFlag)">
+                    Qt::Vertical (2)
+                </DisplayString>
+                <DisplayString
+                    Condition="(static_cast&lt;Policy&gt;(bits.horPolicy) &amp; ExpandFlag)">
+                    Qt::Horizontal (1)
+                </DisplayString>
+            </Synthetic>
+            <Item Name="[vertical stretch]">static_cast&lt;int&gt;(bits.verStretch)</Item>
+            <Item Name="[horizontal stretch]">static_cast&lt;int&gt;(bits.horStretch)</Item>
+            <Item Name="[has height for width]">bits.hfw == 1</Item>
+            <Item Name="[has width for height]">bits.wfh == 1</Item>
+        </Expand>
+    </Type>
+
+   <Type Name="##NAMESPACE##::QChar">
+        <DisplayString>{ucs,c}</DisplayString>
+        <StringView>ucs,c</StringView>
+        <Expand>
+            <Item Name="[latin 1]">ucs > 0xff ? '\0' : char(ucs),c</Item>
+            <Item Name="[unicode]">ucs,c</Item>
+        </Expand>
+    </Type>
+
+   <Type Name="##NAMESPACE##::QString">
+        <DisplayString>&quot;{(reinterpret_cast&lt;unsigned short*&gt;(d.ptr)),sub}&quot;</DisplayString>
+        <StringView>(reinterpret_cast&lt;unsigned short*&gt;(d.ptr)),sub</StringView>
+        <Expand>
+            <Item Name="[size]">d.size</Item>
+            <ArrayItems>
+                <Size>d.size</Size>
+                <ValuePointer>d.ptr</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QStringRef">
+        <DisplayString Condition="m_string == nullptr">{m_string,[m_size]} u""</DisplayString>
+        <DisplayString Condition="m_string != nullptr">{m_string-&gt;d.ptr+m_position,[m_size]}</DisplayString>
+        <StringView Condition="m_string == nullptr">""</StringView>
+        <StringView Condition="m_string != nullptr">m_string,[m_position+m_size]</StringView>
+        <Expand>
+            <Item Name="[position]" ExcludeView="simple">m_position</Item>
+            <Item Name="[size]" ExcludeView="simple">m_size</Item>
+            <ArrayItems Condition="m_string != nullptr">
+                <Size>m_size</Size>
+                <ValuePointer>m_string-&gt;d.ptr+m_position</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QStringView">
+        <DisplayString>{m_data,[m_size]}</DisplayString>
+        <StringView>m_data,[m_size]</StringView>
+        <Expand>
+            <Item Name="[size]" ExcludeView="simple">m_size</Item>
+            <ArrayItems>
+                <Size>m_size</Size>
+                <ValuePointer>m_data</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QByteArray">
+        <DisplayString>&quot;{((reinterpret_cast&lt;char*&gt;(d.ptr))),sb}&quot;</DisplayString>
+        <StringView>((reinterpret_cast&lt;char*&gt;(d.ptr))),sb</StringView>
+        <Expand>
+            <Item Name="[size]">d.size</Item>
+            <ArrayItems>
+                <Size>d.size</Size>
+                <ValuePointer>d.ptr</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QUrl">
+        <Intrinsic Name="isEmpty" Expression="size==0">
+            <Parameter Name="size" Type="int"/>
+        </Intrinsic>
+        <Intrinsic Name="memberOffset" Expression="sizeof(QAtomicInt) + sizeof(int) + (sizeof(QString) * count)">
+            <Parameter Name="count" Type="int"/>
+        </Intrinsic>
+        <Intrinsic Name="scheme" Expression="*((QString*)(((char*)(d) + memberOffset(0))))" />
+        <Intrinsic Name="username" Expression="*((QString*)(((char*)(d) + memberOffset(1))))" />
+        <Intrinsic Name="password" Expression="*((QString*)(((char*)(d) + memberOffset(2))))" />
+        <Intrinsic Name="host" Expression="*((QString*)(((char*)(d) + memberOffset(3))))" />
+        <Intrinsic Name="path" Expression="*((QString*)(((char*)(d) + memberOffset(4))))" />
+        <Intrinsic Name="query" Expression="*((QString*)(((char*)(d) + memberOffset(5))))" />
+        <Intrinsic Name="fragment" Expression="*((QString*)(((char*)(d) + memberOffset(6))))" />
+
+        <DisplayString Condition="!isEmpty(scheme().d-&gt;size)">{scheme()}://{host()}{path()}</DisplayString>
+        <DisplayString Condition="isEmpty(scheme().d-&gt;size)">{path()}</DisplayString>
+        <Expand>
+            <Item Name="[scheme]">scheme()</Item>
+            <Item Name="[username]">username()</Item>
+            <Item Name="[password]">password()</Item>
+            <Item Name="[host]">host()</Item>
+            <Item Name="[path]">path()</Item>
+            <Item Name="[query]">query()</Item>
+            <Item Name="[fragment]">fragment()</Item>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QDate">
+        <DisplayString>{{ julian day = {jd} }}</DisplayString>
+    </Type>
+
+   <Type Name="##NAMESPACE##::QTime">
+        <Intrinsic Name="hour" Expression="mds / 3600000" />
+        <Intrinsic Name="minute" Expression="(mds % 3600000) / 60000" />
+        <Intrinsic Name="second" Expression="(mds / 1000) % 60" />
+        <Intrinsic Name="millisecond" Expression="mds % 1000" />
+        <DisplayString Condition="mds == 1">{{ millisecond = {mds} }}</DisplayString>
+        <DisplayString Condition="mds != 1">{{ milliseconds = {mds} }}</DisplayString>
+        <Expand>
+            <Item Name="[hour]"
+                  Condition="(mds / 3600000) == 1">hour(), d</Item>
+            <Item Name="[hours]"
+                  Condition="(mds / 3600000) != 1">hour(), d</Item>
+            <Item Name="[minute]"
+                  Condition="((mds % 3600000) / 60000) == 1">minute(), d</Item>
+            <Item Name="[minutes]"
+                  Condition="((mds % 3600000) / 60000) != 1">minute(), d</Item>
+            <Item Name="[second]"
+                  Condition="((mds / 1000) % 60) == 1">second(), d</Item>
+            <Item Name="[seconds]"
+                  Condition="((mds / 1000) % 60) != 1">second(), d</Item>
+            <Item Name="[millisecond]"
+                  Condition="(mds % 1000) == 1">millisecond(), d</Item>
+            <Item Name="[milliseconds]"
+                  Condition="(mds % 1000) != 1">millisecond(), d</Item>
+        </Expand>
+    </Type>
+
+   <Type Name="##NAMESPACE##::QPair&lt;*,*&gt;">
+        <DisplayString>({first}, {second})</DisplayString>
+        <Expand>
+            <Item Name="[first]">first</Item>
+            <Item Name="[second]">second</Item>
+        </Expand>
+    </Type>
+
+   <Type Name="##NAMESPACE##::QList&lt;*&gt;">
+        <AlternativeType Name="##NAMESPACE##::QVector&lt;*&gt;"/>
+        <DisplayString>{{ size={d.size} }}</DisplayString>
+        <Expand>
+            <ArrayItems>
+                <Size>d.size</Size>
+                <ValuePointer>reinterpret_cast&lt;$T1*&gt;(d.ptr)</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+   <Type Name="##NAMESPACE##::QVarLengthArray&lt;*&gt;">
+        <DisplayString>{{ size={s} }}</DisplayString>
+        <Expand>
+            <Item Name="[capacity]">a</Item>
+            <ArrayItems>
+                <Size>s</Size>
+                <ValuePointer>ptr</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+   <Type Name="##NAMESPACE##::QMap&lt;*,*&gt;">
+        <AlternativeType Name="##NAMESPACE##::QMultiMap&lt;*,*&gt;"/>
+        <DisplayString>{{ size={d.d-&gt;m._Mypair._Myval2._Myval2._Mysize} }}</DisplayString>
+        <Expand>
+            <Item Name="[std::map]">d.d-&gt;m</Item>
+        </Expand>
+    </Type>
+
+   <Type Name="##NAMESPACE##::QHash&lt;*,*&gt;">
+        <AlternativeType Name="##NAMESPACE##::QMultiHash&lt;*,*&gt;"/>
+        <DisplayString>{{ size = {d-&gt;size} }}</DisplayString>
+        <Expand>
+            <Item Name="[referenced]">d-&gt;ref.atomic._q_value</Item>
+        </Expand>
+    </Type>
+
+</AutoVisualizer>
diff --git a/QtMSBuild/QtMsBuild/qt_defaults.props b/QtMSBuild/QtMsBuild/qt_defaults.props
index d351b61..ee94d6b 100644
--- a/QtMSBuild/QtMsBuild/qt_defaults.props
+++ b/QtMSBuild/QtMsBuild/qt_defaults.props
@@ -71,6 +71,9 @@
     <QtPathBinaries>bin</QtPathBinaries>
     <QtPathLibraryExecutables>bin</QtPathLibraryExecutables>
 
+    <!--// Run Qt tools during design-time build -->
+    <QtToolsDesignTime>true</QtToolsDesignTime>
+
     <!--// qmake template -->
     <QtQMakeTemplate>vcapp</QtQMakeTemplate>
 
@@ -89,6 +92,7 @@
       DEFINES=/Project/ItemDefinitionGroup/ClCompile/PreprocessorDefinitions;
       INCLUDEPATH=/Project/ItemDefinitionGroup/ClCompile/AdditionalIncludeDirectories;
       STDCPP=/Project/ItemDefinitionGroup/ClCompile/LanguageStandard;
+      RUNTIME=/Project/ItemDefinitionGroup/ClCompile/RuntimeLibrary;
       CL_OPTIONS=/Project/ItemDefinitionGroup/ClCompile/AdditionalOptions;
       LIBS=/Project/ItemDefinitionGroup/Link/AdditionalDependencies;
       LINK_OPTIONS=/Project/ItemDefinitionGroup/Link/AdditionalOptions;
@@ -103,6 +107,9 @@
     <!--// Qt build config -->
     <QtBuildConfig Condition="'$(Configuration)' == 'Debug'">debug</QtBuildConfig>
     <QtBuildConfig Condition="'$(Configuration)' != 'Debug'">release</QtBuildConfig>
+
+    <!--// Qt Plugin default-->
+    <QtPlugin>false</QtPlugin>
   </PropertyGroup>
 
   <!--
diff --git a/QtMSBuild/QtMsBuild/qt_globals.targets b/QtMSBuild/QtMsBuild/qt_globals.targets
index a8cb31c..966a084 100644
--- a/QtMSBuild/QtMsBuild/qt_globals.targets
+++ b/QtMSBuild/QtMsBuild/qt_globals.targets
@@ -84,6 +84,29 @@
 
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Set up inner build if Qt vars property file is outdated
+  // -->
+  <PropertyGroup Condition="'$(QtInnerBuild)' == ''">
+    <QtVarsOutdated>false</QtVarsOutdated>
+    <QtVarsOutdated
+      Condition="!Exists('$(QtVarsFilePath)')
+        OR '$(QtBkup_QtInstall)'                != '$(QtInstall)'
+        OR '$(QtBkup_QtModules)'                != '$(QtModules)'
+        OR '$(QtBkup_QtPathBinaries)'           != '$(QtPathBinaries)'
+        OR '$(QtBkup_QtPathLibraryExecutables)' != '$(QtPathLibraryExecutables)'
+        OR '$(QtBkup_QtHeaderSearchPath)'       != '$(QtHeaderSearchPath)'
+        OR '$(QtBkup_QtLibrarySearchPath)'      != '$(QtLibrarySearchPath)'
+        OR '$(QtBkup_QtVars)'                   != '$(QtVars)'
+        OR '$(QtBkup_QMakeCodeLines)'           != '$(QMakeCodeLines)'
+        OR '$(QtBkup_QtBuildConfig)'            != '$(QtBuildConfig)'"
+    >true</QtVarsOutdated>
+  </PropertyGroup>
+
+  <!-- // Enable inner build targets -->
+  <Import Condition="'$(QtVarsOutdated)' == 'true'" Project="qt_inner.targets"/>
+
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
   /// TARGET QtGetDefaultClCompile
   /////////////////////////////////////////////////////////////////////////////////////////////////
   // Get default C++ properties
@@ -201,7 +224,8 @@
                OR ('$(project_changed)' == 'true' AND '$(log_hash)' != '$(work_hash)')"
         >true</do_work>
       <skip_work
-        Condition="'$(do_work)' != 'true' OR '$(DesignTimeBuild)' == 'true'"
+        Condition="'$(do_work)' != 'true'
+          OR ('$(QtDesignTimeBuild)' == 'true' AND '$(QtToolsDesignTime)' != 'true')"
         >true</skip_work>
     </PropertyGroup>
 
@@ -268,8 +292,7 @@
     // -->
     <QtRunWork
       Condition="'$(ApplicationType)' != 'Linux' AND '@(QtWork)' != ''
-        AND '%(QtWork.ParallelBuild)' == 'true'
-        AND '$(DesignTimeBuild)' != 'true'"
+        AND '%(QtWork.ParallelBuild)' == 'true'"
       QtWork="@(QtWork)" QtMaxProcs="$(QtMaxProcs)" QtDebug="$(QtDebug)">
       <Output TaskParameter="Result" ItemName="QtWorkResult" />
     </QtRunWork>
@@ -280,8 +303,7 @@
     // -->
     <QtRunWork
       Condition="'$(ApplicationType)' != 'Linux' AND '@(QtWork)' != ''
-        AND '%(QtWork.ParallelBuild)' != 'true'
-        AND '$(DesignTimeBuild)' != 'true'"
+        AND '%(QtWork.ParallelBuild)' != 'true'"
       QtWork="@(QtWork)" QtMaxProcs="1" QtDebug="$(QtDebug)">
       <Output TaskParameter="Result" ItemName="QtWorkResult" />
     </QtRunWork>
@@ -293,13 +315,13 @@
     <!-- // Translate local paths to host paths -->
     <Flatten
       Condition="'$(ApplicationType)' == 'Linux'
-        AND '@(QtWork)' != '' AND '$(DesignTimeBuild)' != 'true'"
+        AND '@(QtWork)' != '' AND '$(QtDesignTimeBuild)' != 'true'"
       Items="@(QtWork)" Metadata="ResourceFiles">
       <Output TaskParameter="Result" ItemName="ResourceFiles"/>
     </Flatten>
     <ItemGroup
       Condition="'$(ApplicationType)' == 'Linux'
-        AND '@(QtWork)' != '' AND '$(DesignTimeBuild)' != 'true'">
+        AND '@(QtWork)' != '' AND '$(QtDesignTimeBuild)' != 'true'">
       <LocalPath Include="%(QtWork.Identity)">
         <Name>InputPath</Name>
         <Item>%(QtWork.Identity)</Item>
@@ -320,7 +342,7 @@
     </ItemGroup>
     <HostTranslatePaths
       Condition="'$(ApplicationType)' == 'Linux'
-        AND '@(QtWork)' != '' AND '$(DesignTimeBuild)' != 'true'"
+        AND '@(QtWork)' != '' AND '$(QtDesignTimeBuild)' != 'true'"
       Items="@(LocalPath)" Names="InputPath;OutputPath">
       <Output TaskParameter="Result" ItemName="HostPath"/>
     </HostTranslatePaths>
@@ -332,7 +354,7 @@
     <!-- // Run command -->
     <HostExec
       Condition="'$(ApplicationType)' == 'Linux'
-        AND '%(Identity)' != '' AND '$(DesignTimeBuild)' != 'true'"
+        AND '%(Identity)' != '' AND '$(QtDesignTimeBuild)' != 'true'"
       Message="@(QtWork->'%(WorkType) %(Identity)')"
       Command="@(QtWork->'%(ToolPath) %(Options)')"
       Inputs="@(InputPath)"
@@ -344,7 +366,7 @@
     <!-- // Generate result item -->
     <ItemGroup
       Condition="'$(ApplicationType)' == 'Linux'
-        AND '@(QtWork)' != '' AND '$(DesignTimeBuild)' != 'true'">
+        AND '@(QtWork)' != '' AND '$(QtDesignTimeBuild)' != 'true'">
       <QtWorkResult Include="@(QtWork)">
         <ExitCode>0</ExitCode>
       </QtWorkResult>
@@ -354,9 +376,11 @@
     ///////////////////////////////////////////////////////////////////////////////////////////////
     // Save tracking log of files read during build; used by VS to check the up-to-date status
     // -->
-    <ItemGroup Condition="'$(DesignTimeBuild)' != 'true' AND '$(QtVSToolsBuild)' != 'true'">
+    <ItemGroup>
       <read_log Include="^%(QtWorkResult.FullPath);%(QtWorkResult.AdditionalDependencies)"
-        Condition="'%(QtWorkResult.ExitCode)' == '0' AND '%(QtWorkResult.DisableLog)' != 'true'">
+        Condition="'%(QtWorkResult.ExitCode)' == '0'
+               AND '%(QtWorkResult.DisableLog)' != 'true'
+               AND '%(QtWorkResult.Skipped)' != 'true'">
         <WorkType>%(QtWorkResult.WorkType)</WorkType>
       </read_log>
       <read_log>
@@ -377,9 +401,11 @@
     ///////////////////////////////////////////////////////////////////////////////////////////////
     // Save tracking log of files written during build; used by VS to check the up-to-date status
     // -->
-    <ItemGroup Condition="'$(DesignTimeBuild)' != 'true' AND '$(QtVSToolsBuild)' != 'true'">
+    <ItemGroup>
       <write_log Include="^%(QtWorkResult.FullPath);%(QtWorkResult.OutputFile)"
-        Condition="'%(QtWorkResult.ExitCode)' == '0' AND '%(QtWorkResult.DisableLog)' != 'true'">
+        Condition="'%(QtWorkResult.ExitCode)' == '0'
+               AND '%(QtWorkResult.DisableLog)' != 'true'
+               AND '%(QtWorkResult.Skipped)' != 'true'">
         <WorkType>%(QtWorkResult.WorkType)</WorkType>
       </write_log>
       <write_log>
@@ -398,7 +424,7 @@
     ///////////////////////////////////////////////////////////////////////////////////////////////
     // Log output files; this is used by VS to determine what files to delete on "Clean"
     // -->
-    <ItemGroup Condition="'$(DesignTimeBuild)' != 'true' AND '$(QtVSToolsBuild)' != 'true'">
+    <ItemGroup>
       <clean_log Include="%(QtWorkResult.OutputFile)"
         Condition="'%(QtWorkResult.ExitCode)' == '0'">
         <Source>@(QtWorkResult, '|')</Source>
@@ -414,7 +440,7 @@
     ///////////////////////////////////////////////////////////////////////////////////////////////
     // Log calls to Qt tools; used in QtWorkPrepare to detect changes to the options of Qt tools
     // -->
-    <WriteLinesToFile Condition="'@(QtWorkLog)' != '' AND '$(DesignTimeBuild)' != 'true'"
+    <WriteLinesToFile Condition="'@(QtWorkLog)' != ''"
       File="$(QtLogFilePath)"
       Lines="@(QtWorkLog->'%(Identity)|%(Hash)')"
       Overwrite="true" Encoding="Unicode"/>
@@ -425,8 +451,7 @@
     // -->
     <Error
       Condition="'%(QtWorkResult.ExitCode)' != ''
-        AND '%(QtWorkResult.ExitCode)' != '0'
-        AND '$(DesignTimeBuild)' != 'true'"
+        AND '%(QtWorkResult.ExitCode)' != '0'"
       File="%(QtWorkResult.Identity)" Code="%(QtWorkResult.ExitCode)"
       Text="%(QtWorkResult.WorkType) (%(QtWorkResult.ToolPath))"/>
 
@@ -513,6 +538,7 @@
     // Clean-up
     // -->
     <ItemGroup>
+      <ClCompile    Remove="DefaultClCompile" />
       <QtWork       Remove="@(QtWork)"/>
       <QtWorkResult Remove="@(QtWorkResult)"/>
       <QtWorkLog    Remove="@(QtWorkLog)"/>
@@ -524,51 +550,158 @@
 
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
-  /// TARGET Qt
+  /// TARGET QtSetAdditionalOptions
   /////////////////////////////////////////////////////////////////////////////////////////////////
-  // Root Qt target
+  // Adds additional compiler options flowing from Qt.
+  // Skips options that are already specified in the user project.
   // -->
-  <Target Name="Qt" DependsOnTargets="QtPrepare;QtWork" BeforeTargets="FixupCLCompileOptions">
+  <Target Name="QtSetAdditionalOptions" Condition="'@(ClCompile)' != ''">
+
+    <!-- Command line parser regex -->
+    <PropertyGroup>
+      <CmdLineParser>"[^"]*"|[^\s]+</CmdLineParser>
+    </PropertyGroup>
+
+    <!-- Parse compiler options from Qt -->
+    <PropertyGroup>
+      <QtCmdLine
+          >$([System.Text.RegularExpressions.Regex]::Matches(
+            '$(Qt_CL_OPTIONS_)', '$(CmdLineParser)'))</QtCmdLine>
+    </PropertyGroup>
+
+    <!-- Calculate command line for each source file in the project -->
+    <QtRunTask
+      Items="@(ClCompile)"
+      AssemblyPath="$(VCTargetsPath)\Microsoft.Build.CPPTasks.Common.dll"
+      TaskName="Microsoft.Build.CPPTasks.CLCommandLine"
+      TaskInput="Sources"
+      TaskOutput="CommandLines"
+      NewMetadata="ProjectOptions">
+      <Output TaskParameter="Result" ItemName="ClCompile_CmdLine" />
+    </QtRunTask>
+
+    <!-- Append excluded Qt options to calculated command line -->
     <ItemGroup>
-      <ClCompile Remove="DefaultClCompile" />
+      <ClCompile_CmdLine Condition="'$(QtExcludedOptions)' != ''">
+        <ProjectOptions>%(ProjectOptions) $(QtExcludedOptions)</ProjectOptions>
+      </ClCompile_CmdLine>
     </ItemGroup>
-    <CriticalSection Lock="false" Name="$(ProjectGuid)" />
-    <OnError ExecuteTargets="QtLeaveCriticalSection_OnError"/>
+
+    <!-- Parse compiler command line of each source file -->
+    <ItemGroup>
+      <ClCompile_CmdLine>
+        <ProjectOptions
+          >$([System.Text.RegularExpressions.Regex]::Matches(
+            '%(ProjectOptions)', '$(CmdLineParser)'))</ProjectOptions>
+      </ClCompile_CmdLine>
+    </ItemGroup>
+
+    <!-- Add (previously parsed) Qt options to each source file -->
+    <ItemGroup>
+      <ClCompile_CmdLine>
+        <QtOptions>$(QtCmdLine)</QtOptions>
+      </ClCompile_CmdLine>
+    </ItemGroup>
+
+    <!-- Result of parsing command lines, per source file:
+          * ClCompile_CmdLine ::= (Item x ProjectOptions x QtOptions), where:
+             * Item ::= source file
+             * ProjectOptions ::= list of tokens from the compiler command line for Item
+             * QtOptions ::= list of tokens from the Qt additional options -->
+
+    <!-- Flatten results into a list of tokens per source file:
+          * ClOptions ::= (Item x Name x Value), where:
+             * Item  ::= source file
+             * Name  ::= token origin: from compiler command line or from Qt
+             * Value ::= token value -->
+    <Flatten Items="@(ClCompile_CmdLine)" Metadata="ProjectOptions;QtOptions">
+      <Output TaskParameter="Result" ItemName="ClOptions" />
+    </Flatten>
+
+    <!-- Remove non-switch tokens, i.e. tokens that do not start with '/' or '-' -->
+    <ItemGroup>
+      <ClOptions
+        Remove="@(ClOptions)"
+        Condition="!$([System.String]::Copy('%(Value)').StartsWith('-'))
+               AND !$([System.String]::Copy('%(Value)').StartsWith('/'))"/>
+    </ItemGroup>
+
+    <!-- Calculate option id: token without leading '/' or '-', and without trailing '-' -->
+    <ItemGroup>
+      <ClOptions>
+        <OptionId>$([System.String]::Copy('%(Value)').Substring(1).TrimEnd('-'))</OptionId>
+      </ClOptions>
+    </ItemGroup>
+
+    <!-- Split into list of Qt options and list of project options -->
+    <ItemGroup>
+      <QtOptions
+        Include="@(ClOptions->'%(Item)')"
+        Condition="'%(ClOptions.Name)' == 'QtOptions'"/>
+      <ProjectOptions
+        Include="@(ClOptions->'%(Item)')"
+        Condition="'%(ClOptions.Name)' == 'ProjectOptions'"/>
+    </ItemGroup>
+
+    <!-- Find conflicting options, i.e. defined both in Qt options and project options -->
+    <ItemGroup>
+      <QtOptions
+        Condition="'@(QtOptions)' != ''
+               AND '@(ProjectOptions)' != ''
+               AND '%(Item)' != ''
+               AND '%(OptionId)' != ''">
+        <Conflict>true</Conflict>
+      </QtOptions>
+    </ItemGroup>
+
+    <!-- Set additional compiler options for all source files -->
+    <ItemGroup>
+      <ClCompile Condition="'%(Identity)' != '' AND '%(QtOptions.Conflict)' != 'true'">
+        <AdditionalOptions
+          >@(QtOptions->'%(Value)', ' ') @(ClCompile->'%(AdditionalOptions)')</AdditionalOptions>
+      </ClCompile>
+      <ClCompile Condition="'%(AdditionalOptions)' != ''">
+        <AdditionalOptions
+          >$([System.String]::Copy('%(AdditionalOptions)').Trim())</AdditionalOptions>
+      </ClCompile>
+    </ItemGroup>
+
+    <!-- Print result to build log, if requested -->
+    <Message
+      Condition="'$(QtOptionsBuildLog)' == 'true'"
+      Importance="High"
+      Text=" Qt - Additional Compiler Options"/>
+    <Message
+      Condition="'$(QtOptionsBuildLog)' == 'true'
+             AND '%(Identity)' != '' AND '%(QtOptions.Conflict)' != 'true'"
+      Importance="High"
+      Text="    [%(Identity)]: @(QtOptions->'%(Value)', ' ')"/>
+
+    <!-- Clean-up -->
+    <PropertyGroup>
+      <CmdLineParser/>
+      <QtCmdLine/>
+    </PropertyGroup>
+    <ItemGroup>
+      <ClCompile_CmdLine Remove="@(ClCompile_CmdLine)"/>
+      <ClOptions Remove="@(ClOptions)"/>
+      <ProjectOptions Remove="@(ProjectOptions)"/>
+      <QtOptions Remove="@(QtOptions)"/>
+    </ItemGroup>
   </Target>
 
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
-  /// TARGET QtOuterBuild
+  /// TARGET Qt
   /////////////////////////////////////////////////////////////////////////////////////////////////
-  // Run targets in $(QtOuterBuildDependsOn) and then recursively invoke build
+  // Root Qt target
   // -->
-  <Target Name="QtOuterBuild" DependsOnTargets="$(QtOuterBuildDependsOn)">
-    <!--// Invoke inner build: recursive build in second MSBuild instance -->
-    <MSBuild
-      Projects="$(MSBuildProjectFullPath)"
-      Targets="Build"
-      Properties="QtInnerBuild=$(MSBuildProjectFullPath);RandomFileName=$(RandomFileName);BuildProjectReferences=false">
-    </MSBuild>
+  <Target
+    Name="Qt"
+    DependsOnTargets="QtPrepare;QtWork;QtSetAdditionalOptions">
+    <CriticalSection Lock="false" Name="$(ProjectGuid)" />
     <OnError ExecuteTargets="QtLeaveCriticalSection_OnError"/>
   </Target>
-
-  <PropertyGroup
-    Condition="'$(QtInnerBuild)' == '' AND '$(DesignTimeBuild)' != 'true'">
-    <!--// Outer build: invoke inner build -->
-    <BuildDependsOn>
-      $(QtOuterBuildPrepare);
-      QtOuterBuild;
-      $(QtOuterBuildFinalize)
-    </BuildDependsOn>
-    <QtInnerBuild>$(MSBuildProjectFullPath)</QtInnerBuild>
-    <RandomFileName>$([System.IO.Path]::GetRandomFileName())</RandomFileName>
-  </PropertyGroup>
-
-  <PropertyGroup
-    Condition="'$(QtInnerBuild)' != '$(MSBuildProjectFullPath)' AND '$(DesignTimeBuild)' != 'true'">
-    <!--// Dependent project inner build: skip build -->
-    <BuildDependsOn>$(QtOuterBuildPrepare);$(QtOuterBuildFinalize)</BuildDependsOn>
-  </PropertyGroup>
 
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
@@ -633,4 +766,28 @@
   <Target Name="QtLeaveCriticalSection_OnError">
     <CriticalSection Lock="false" Name="$(ProjectGuid)" />
   </Target>
+
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  /// TARGET QtNatvis
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Copies the .natvis file matching the Qt version and replaces the namespace placeholder
+  // -->
+  <Target Name="QtNatvis" BeforeTargets="Link"
+          Condition="'$(Configuration)' == 'Debug' AND '$(LinkNatvisFile)' == 'true'"
+          Inputs="$(MSBuildProjectFile);$(QtMsBuild)\qt$(QtVersionMajor).natvis.xml"
+          Outputs="$(IntDir)\qt.natvis">
+    <PropertyGroup>
+      <InputFile>$(QtMsBuild)\qt$(QtVersionMajor).natvis.xml</InputFile>
+    </PropertyGroup>
+    <WriteLinesToFile Condition="'$(QtNamespace)' == ''"
+      Overwrite="true"
+      File="$(IntDir)\qt.natvis"
+      Lines="$([System.IO.File]::ReadAllText($(InputFile)).Replace('##NAMESPACE##::',''))" />
+    <WriteLinesToFile Condition="'$(QtNamespace)' != ''"
+      Overwrite="true"
+      File="$(IntDir)\qt.natvis"
+      Lines="$([System.IO.File]::ReadAllText($(InputFile)).Replace('##NAMESPACE##','$(QtNamespace)'))" />
+  </Target>
+
 </Project>
diff --git a/QtMSBuild/QtMsBuild/qt_inner.targets b/QtMSBuild/QtMsBuild/qt_inner.targets
new file mode 100644
index 0000000..06f88c7
--- /dev/null
+++ b/QtMSBuild/QtMsBuild/qt_inner.targets
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+-->
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+  <PropertyGroup
+    Condition="'$(QtInnerBuild)' == ''">
+    <!--// Outer build: invoke inner build -->
+    <BuildDependsOn>
+      $(QtOuterBuildPrepare);
+      QtOuterBuild;
+      $(QtOuterBuildFinalize)
+    </BuildDependsOn>
+    <QtInnerBuild>$(MSBuildProjectFullPath)</QtInnerBuild>
+    <RandomFileName>$([System.IO.Path]::GetRandomFileName())</RandomFileName>
+  </PropertyGroup>
+
+  <PropertyGroup
+    Condition="'$(QtInnerBuild)' != '$(MSBuildProjectFullPath)'">
+    <!--// Dependent project inner build: skip build -->
+    <BuildDependsOn>$(QtOuterBuildPrepare);$(QtOuterBuildFinalize)</BuildDependsOn>
+  </PropertyGroup>
+
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  /// TARGET QtOuterBuild
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Run targets in $(QtOuterBuildDependsOn) and then recursively invoke build
+  // -->
+  <Target Name="QtOuterBuild" DependsOnTargets="$(QtOuterBuildDependsOn)">
+    <!--// Invoke inner build: recursive build in second MSBuild instance -->
+    <MSBuild
+      Projects="$(MSBuildProjectFullPath)"
+      Targets="Build"
+      Properties="QtInnerBuild=$(MSBuildProjectFullPath);RandomFileName=$(RandomFileName);BuildProjectReferences=false">
+    </MSBuild>
+    <OnError ExecuteTargets="QtLeaveCriticalSection_OnError"/>
+  </Target>
+
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  /// TARGET GetClCommandLineForReference
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  //
+  // -->
+  <Target
+    Name="GetClCommandLineForReference"
+    DependsOnTargets="$(QtOuterBuildDependsOn)"
+    Returns="@(ClCommandLineForReference)">
+    <MSBuild
+      Projects="$(MSBuildProjectFullPath)"
+      Targets="GetClCommandLineForReference"
+      Properties="QtInnerBuild=$(MSBuildProjectFullPath);RandomFileName=$(RandomFileName);BuildProjectReferences=false">
+      <Output TaskParameter="TargetOutputs" ItemName="ClCommandLineForReference"/>
+    </MSBuild>
+  </Target>
+
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  /// TARGET GetGeneratedFiles
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  //
+  // -->
+  <Target
+    Name="GetGeneratedFiles"
+    DependsOnTargets="$(QtOuterBuildDependsOn)"
+    Returns="@(_GeneratedFiles)">
+    <MSBuild
+      Projects="$(MSBuildProjectFullPath)"
+      Targets="GetGeneratedFiles"
+      Properties="QtInnerBuild=$(MSBuildProjectFullPath);RandomFileName=$(RandomFileName);BuildProjectReferences=false">
+      <Output TaskParameter="TargetOutputs" ItemName="_GeneratedFiles"/>
+    </MSBuild>
+  </Target>
+
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  /// TARGET GetProjectReferencesInfo
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  //
+  // -->
+  <Target
+    Name="GetProjectReferencesInfo"
+    DependsOnTargets="$(QtOuterBuildDependsOn)"
+    Returns="@(_ProjectReferencesInfo)">
+    <MSBuild
+      Projects="$(MSBuildProjectFullPath)"
+      Targets="GetProjectReferencesInfo"
+      Properties="QtInnerBuild=$(MSBuildProjectFullPath);RandomFileName=$(RandomFileName);BuildProjectReferences=false">
+      <Output TaskParameter="TargetOutputs" ItemName="_ProjectReferencesInfo"/>
+    </MSBuild>
+  </Target>
+
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  /// TARGET GetClCommandLines
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  //
+  // -->
+  <Target
+    Name="GetClCommandLines"
+    DependsOnTargets="$(QtOuterBuildDependsOn)"
+    Returns="@(ClCommandLines)">
+    <MSBuild
+      Projects="$(MSBuildProjectFullPath)"
+      Targets="GetClCommandLines"
+      Properties="QtInnerBuild=$(MSBuildProjectFullPath);RandomFileName=$(RandomFileName);BuildProjectReferences=false">
+      <Output TaskParameter="TargetOutputs" ItemName="ClCommandLines"/>
+    </MSBuild>
+  </Target>
+</Project>
diff --git a/QtMSBuild/QtMsBuild/qt_private.props b/QtMSBuild/QtMsBuild/qt_private.props
index c1303e0..eb76f1f 100644
--- a/QtMSBuild/QtMsBuild/qt_private.props
+++ b/QtMSBuild/QtMsBuild/qt_private.props
@@ -57,6 +57,18 @@
 
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Check if design-time build
+  // -->
+  <PropertyGroup>
+    <QtDesignTimeBuild>false</QtDesignTimeBuild>
+    <QtDesignTimeBuild
+      Condition="'$(DesignTimeBuild)' == 'true'
+              OR '$(QtVSToolsBuild)'  == 'true'"
+      >true</QtDesignTimeBuild>
+  </PropertyGroup>
+
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
   // Setup Qt installation path
   // -->
   <PropertyGroup Condition="'$(QtVsProjectSettings)' == 'true'">
@@ -112,21 +124,29 @@
       >$([System.String]::Copy($([System.IO.File]::ReadAllText('$(QtVarsIndexPathDesignTime)'))).Replace('&#xD;&#xA;',''))</QtVarsDesignTime>
   </PropertyGroup>
 
-  <!--// Import Qt variables (full build) -->
-  <Import
-    Condition="'$(DesignTimeBuild)' != 'true' AND Exists('$(QtVarsFilePath)')"
-    Project="$(QtVarsFilePath)"/>
+  <PropertyGroup>
+    <!--// Path to Qt variables .props: full build -->
+    <QtVarsImportPath
+      Condition="'$(QtDesignTimeBuild)' != 'true'
+        AND Exists('$(QtVarsFilePath)')"
+      >$(QtVarsFilePath)</QtVarsImportPath>
 
-  <!--// Import Qt variables (design-time build) -->
-  <Import
-    Condition="'$(DesignTimeBuild)' == 'true' AND Exists('$(QtVarsDesignTime)')"
-    Project="$(QtVarsDesignTime)"/>
+    <!--// Path to Qt variables .props: design-time build -->
+    <QtVarsImportPath
+      Condition="'$(QtDesignTimeBuild)' == 'true'
+        AND Exists('$(QtVarsDesignTime)')"
+      >$(QtVarsDesignTime)</QtVarsImportPath>
 
-  <!--// Import Qt variables (fall-back) -->
-  <Import
-    Condition=
-"'$(DesignTimeBuild)' == 'true' AND !Exists('$(QtVarsDesignTime)') AND Exists('$(QtVarsFilePath)')"
-    Project="$(QtVarsFilePath)"/>
+    <!--// Path to Qt variables .props: fall-back -->
+    <QtVarsImportPath
+      Condition="'$(QtDesignTimeBuild)' == 'true'
+        AND !Exists('$(QtVarsDesignTime)')
+        AND  Exists('$(QtVarsFilePath)')"
+      >$(QtVarsFilePath)</QtVarsImportPath>
+  </PropertyGroup>
+
+  <!--// Import Qt vars property file -->
+  <Import Condition="Exists('$(QtVarsImportPath)')" Project="$(QtVarsImportPath)"/>
 
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
@@ -175,6 +195,61 @@
 
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Normalize QtVars (incl. backup)
+  // -->
+  <PropertyGroup>
+    <QtVars
+      Condition="'$(QtVars)' !=''"
+      >$(QtVars
+        .Replace(' ', '')
+        .Replace('%0a', '')
+        .Replace('%0d', '')
+        .Trim(';'))</QtVars>
+    <QtBkup_QtVars
+      Condition="'$(QtBkup_QtVars)' !=''"
+      >$(QtBkup_QtVars
+        .Replace(' ', '')
+        .Replace('%0a', '')
+        .Replace('%0d', '')
+        .Trim(';'))</QtBkup_QtVars>
+  </PropertyGroup>
+
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Figure out depending on the user settings if we need to link the .natvis file into the PDB
+  // file. Reads the content of qconfig.pri to find Qt's namespace if set. Predefines the path to
+  // the .natvis file used during link which corresponds to the final output generated by the
+  // QtNatvis target.
+  // Evaluation order: first look at the project settings, if empty take from the global settings.
+  // -->
+  <PropertyGroup>
+    <LinkNatvisFile>$(QtLinkNatvisFile)</LinkNatvisFile>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(QtLinkNatvisFile)' == ''">
+    <LinkNatvisRegValue>$([MSBuild]::GetRegistryValue(
+      'HKEY_CURRENT_USER\SOFTWARE\Digia\Qt5VS2017','LinkNatvis'
+      ))</LinkNatvisRegValue>
+    <LinkNatvisFile>true</LinkNatvisFile>
+    <LinkNatvisFile Condition="'$(LinkNatvisRegValue)' == '0'">false</LinkNatvisFile>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)' == 'Debug'
+                            AND '$(LinkNatvisFile)' == 'true' AND '$(QtInstallDir)' != ''">
+    <QConfigPriPath>$([System.IO.Path]::Combine('$(QtInstallDir)',
+        'mkspecs', 'qconfig.pri'
+      ))</QConfigPriPath>
+    <QConfigPriContent>$([MSBuild]::Unescape(
+      $([System.IO.File]::ReadAllText('$(QConfigPriPath)')
+        .Replace('&#xD;&#xA;', ';')
+        .Replace(' =', '=')
+        .Replace('= ', '='))
+      ))</QConfigPriContent>
+    <QtNamespace>$([System.Text.RegularExpressions.Regex]::Match($(QConfigPriContent),
+        'QT_NAMESPACE=([a-zA-Z0-9]+)').get_Groups().get_Item(1)
+      )</QtNamespace>
+  </PropertyGroup>
+
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
   // Default item metadata
   // -->
   <ItemDefinitionGroup>
@@ -186,24 +261,27 @@
       <PreprocessorDefinitions Condition="'$(QtQMLDebugEnable)' == 'true'"
         >QT_QML_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories Condition="'$(Qt_INCLUDEPATH_)' != ''"
-        >$(Qt_INCLUDEPATH_);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+        >%(AdditionalIncludeDirectories);$(Qt_INCLUDEPATH_)</AdditionalIncludeDirectories>
       <LanguageStandard Condition="'$(Qt_STDCPP_)' != ''"
         >$(Qt_STDCPP_)</LanguageStandard>
-      <AdditionalOptions Condition="'$(Qt_CL_OPTIONS_)' != ''"
-        >$(Qt_CL_OPTIONS_) %(AdditionalOptions)</AdditionalOptions>
+      <RuntimeLibrary Condition="'$(Qt_RUNTIME_)' != ''"
+        >$(Qt_RUNTIME_)</RuntimeLibrary>
     </ClCompile>
 
     <!--// Linker (.obj files) -->
     <Link>
       <AdditionalDependencies Condition="'$(Qt_LIBS_)' != ''"
-        >$(Qt_LIBS_);%(AdditionalDependencies)</AdditionalDependencies>
+        >%(AdditionalDependencies);$(Qt_LIBS_)</AdditionalDependencies>
       <AdditionalLibraryDirectories Condition="'$(Qt_LIBPATH_)' != ''"
-        >$(Qt_LIBPATH_);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+        >%(AdditionalLibraryDirectories);$(Qt_LIBPATH_)</AdditionalLibraryDirectories>
       <SharedLibrarySearchPath Condition="'$(Qt_LIBPATH_)' != ''"
-        >$(Qt_LIBPATH_);%(SharedLibrarySearchPath)</SharedLibrarySearchPath>
+        >%(SharedLibrarySearchPath);$(Qt_LIBPATH_)</SharedLibrarySearchPath>
       <AdditionalOptions Condition="'$(Qt_LINK_OPTIONS_)' != ''"
         >$(Qt_LINK_OPTIONS_) %(AdditionalOptions)</AdditionalOptions>
+      <AdditionalOptions Condition="'$(Configuration)' == 'Debug' AND '$(LinkNatvisFile)' == 'true'"
+        >/NATVIS:&quot;$(IntDir)\qt.natvis&quot; %(AdditionalOptions)</AdditionalOptions>
     </Link>
+
   </ItemDefinitionGroup>
 
   <!--
diff --git a/QtMSBuild/QtMsBuild/qt_settings.xml b/QtMSBuild/QtMsBuild/qt_settings.xml
index d078dc6..37ed382 100644
--- a/QtMSBuild/QtMsBuild/qt_settings.xml
+++ b/QtMSBuild/QtMsBuild/qt_settings.xml
@@ -43,6 +43,8 @@
     <Category Name="QtSettings_02_Paths" DisplayName="Paths"/>
     <Category Name="QtSettings_03_QMake" DisplayName="qmake"/>
     <Category Name="QtSettings_04_QML" DisplayName="QML"/>
+    <Category Name="QtSettings_05_AdditionalOptions" DisplayName="Qt Additional Compiler Options"/>
+    <Category Name="QtSettings_06_AdditionalLinkOptions" DisplayName="Qt Additional Linker Options"/>
   </Rule.Categories>
   <EnumProperty
     Name="Keyword"
@@ -85,6 +87,12 @@
       <ValueEditor EditorType="QtModulesEditor" DisplayName="&lt;Select Modules...&gt;" />
     </StringListProperty.ValueEditors>
   </StringListProperty>
+  <BoolProperty
+    Name="QtPlugin"
+    Category="QtSettings_01_General"
+    DisplayName="Qt Plugin"
+    Description="Select whether this project is used to generate a Qt plugin.">
+  </BoolProperty>
   <EnumProperty
     Name="QtBuildConfig"
     Category="QtSettings_01_General"
@@ -98,6 +106,14 @@
     Category="QtSettings_01_General"
     DisplayName="Run Deployment Tool"
     Description="Select whether Qt for Windows Deployment Tool (windeployqt) should be called after build."/>
+  <EnumProperty
+    Name="QtToolsDesignTime"
+    Category="QtSettings_01_General"
+    DisplayName="Design Time Build"
+    Description="Run Qt tools during IntelliSense builds.">
+    <EnumValue Name="true" DisplayName="Run Qt Tools"/>
+    <EnumValue Name="false" DisplayName="Skip Qt Tools"/>
+  </EnumProperty>
   <StringProperty
     Name="QtPathBinaries"
     Category="QtSettings_02_Paths"
@@ -145,4 +161,38 @@
     DisplayName="Enable QML Debugging"
     Description="Select whether to launch a QML session when debugging.">
   </BoolProperty>
-</Rule>
+  <StringProperty
+    Name="Qt_CL_OPTIONS_"
+    ReadOnly="true"
+    Category="QtSettings_05_AdditionalOptions"
+    DisplayName="Additional Options"
+    Description="
+Additional compiler options required by Qt. These options will be passed
+to the compiler, unless specifically excluded in the next field." />
+  <StringProperty
+    Name="QtExcludedOptions"
+    Category="QtSettings_05_AdditionalOptions"
+    DisplayName="Excluded Options"
+    Description="
+Options to exclude from the above compiler options required by Qt.
+These options will NOT be passed to the compiler. Prefix options
+with '/' or '-', and separate them with spaces." />
+  <BoolProperty
+    Name="QtOptionsBuildLog"
+    Category="QtSettings_05_AdditionalOptions"
+    DisplayName="Show in Build Log"
+    Description="
+Print to the build log the list of additional options passed to the compiler." />
+  <EnumProperty
+    Name="QtLinkNatvisFile"
+    Category="QtSettings_06_AdditionalLinkOptions"
+    DisplayName="Embed .natvis file into PDB"
+    Description=
+"Embeds the debugger visualizations (.natvis file) into the PDB file
+generated by LINK. While setting this option, the embedded Natvis file
+will take precedence over user-specific Natvis files (for example the
+files located in %USERPROFILE%\\Documents\\Visual Studio 2022\\Visualizers).">
+    <EnumValue Name="false" DisplayName="No" />
+    <EnumValue Name="true" DisplayName="Yes" />
+  </EnumProperty>
+  </Rule>
diff --git a/QtMSBuild/QtMsBuild/qt_vars.targets b/QtMSBuild/QtMsBuild/qt_vars.targets
index 80c141c..2ad7445 100644
--- a/QtMSBuild/QtMsBuild/qt_vars.targets
+++ b/QtMSBuild/QtMsBuild/qt_vars.targets
@@ -199,7 +199,8 @@
     <ItemGroup>
       <QMakeArgsList Condition="'$(QMakeOptionEarly)' == 'true'" Include="-early"/>
       <QMakeArgsList Include="CONFIG -= debug release debug_and_release"/>
-      <QMakeArgsList Include="CONFIG += $(QtBuildConfig)"/>
+      <QMakeArgsList Include="CONFIG += $(QtBuildConfig) warn_off"/>
+      <QMakeArgsList Condition="'$(QtPlugin)' == 'true'" Include="CONFIG += plugin"/>
       <QMakeArgsList Include="$(QMakeExtraArgs)"/>
     </ItemGroup>
     <ItemGroup>
@@ -281,7 +282,32 @@
         $(QtVarsProFileInput)
         DEFINES -= UNICODE _UNICODE
       </QtVarsProFileInput>
+      <!--
+# Add dummy QML object if needed -->
+      <QtVarsProFileInput Condition="$(QtModules.Contains('quick'))">
+        $(QtVarsProFileInput)
+        RESOURCES += qml.qrc
+      </QtVarsProFileInput>
     </PropertyGroup>
+
+    <!--// Write dummy QML and QRC files -->
+    <WriteLinesToFile
+      Condition="$(QtModules.Contains('quick'))"
+      File="$(QtVarsWorkDir)\main.qml"
+      Lines="
+import QtQuick
+DummyQmlObject { }
+"/>
+    <WriteLinesToFile
+      Condition="$(QtModules.Contains('quick'))"
+      File="$(QtVarsWorkDir)\qml.qrc"
+      Lines="
+&lt;RCC&gt;
+    &lt;qresource prefix=&quot;/&quot;&gt;
+        &lt;file&gt;main.qml&lt;/file&gt;
+    &lt;/qresource&gt;
+&lt;/RCC&gt;
+"/>
 
     <!--// Write .pro file to temp path -->
     <WriteLinesToFile
@@ -313,6 +339,7 @@
       <Cmd><![CDATA["$(QtToolsPath)/qmake" $(QMakeArgs) qtvars.pro]]></Cmd>
     </PropertyGroup>
     <HostExec
+      Condition="'$(ApplicationType)' == 'Linux'"
       Command="$(Cmd)" RedirectStdOut="qtvars.log" RedirectStdErr="STDOUT"
       WorkingDirectory="@(WorkDir->'%(HostPath)')"
       Inputs="@(QMakeProj)"
@@ -322,6 +349,45 @@
       IgnoreExitCode="true">
       <Output TaskParameter="ExitCode" PropertyName="ErrorLevel"/>
     </HostExec>
+
+    <!--// Run qmake in Windows: set %CD% to subfolder of %TEMP% -->
+    <PropertyGroup
+      Condition="'$(ApplicationType)' != 'Linux'">
+      <QMakeTempDir>$(Temp)\$([System.IO.Path]::GetRandomFileName())</QMakeTempDir>
+    </PropertyGroup>
+    <MakeDir
+      Condition="'$(ApplicationType)' != 'Linux'"
+      Directories="$(QMakeTempDir)" />
+    <Copy
+      Condition="'$(ApplicationType)' != 'Linux'"
+      SourceFiles="$(QtVarsWorkDir)\qtvars.pro"
+      DestinationFolder="$(QMakeTempDir)" />
+    <Copy
+      Condition="'$(ApplicationType)' != 'Linux' AND Exists('$(QtVarsWorkDir)\main.qml')"
+      SourceFiles="$(QtVarsWorkDir)\main.qml"
+      DestinationFolder="$(QMakeTempDir)" />
+    <Copy
+      Condition="'$(ApplicationType)' != 'Linux' AND Exists('$(QtVarsWorkDir)\qml.qrc')"
+      SourceFiles="$(QtVarsWorkDir)\qml.qrc"
+      DestinationFolder="$(QMakeTempDir)" />
+    <HostExec
+      Condition="'$(ApplicationType)' != 'Linux'"
+      Command="$(Cmd)" RedirectStdOut="qtvars.log" RedirectStdErr="STDOUT"
+      WorkingDirectory="$(QMakeTempDir)"
+      IgnoreExitCode="true">
+      <Output TaskParameter="ExitCode" PropertyName="ErrorLevel"/>
+    </HostExec>
+    <ItemGroup>
+      <QMakeGeneratedFiles Include="$(QMakeTempDir)\*" />
+    </ItemGroup>
+    <Copy
+      Condition="'$(ApplicationType)' != 'Linux'"
+      SkipUnchangedFiles="true"
+      SourceFiles="@(QMakeGeneratedFiles)"
+      DestinationFolder="$(QtVarsWorkDir)" />
+    <RemoveDir
+      Condition="'$(ApplicationType)' != 'Linux'"
+      Directories="$(QMakeTempDir)" />
 
     <!--// Check qmake result -->
     <PropertyGroup
@@ -501,15 +567,15 @@
     <!--// In design-time, copy generated .props to randomly named file -->
     <PropertyGroup>
       <QtVarsDesignTimeNew
-        Condition="'$(ErrorLevel)' == '0' AND '$(QtVSToolsBuild)' == 'true'"
+        Condition="'$(ErrorLevel)' == '0' AND '$(QtDesignTimeBuild)' == 'true'"
         >$([System.IO.Path]::Combine('$(TEMP)','$([System.IO.Path]::GetRandomFileName()).designtime.props'))
       </QtVarsDesignTimeNew>
     </PropertyGroup>
     <Copy
-      Condition="'$(ErrorLevel)' == '0' AND '$(QtVSToolsBuild)' == 'true'"
+      Condition="'$(ErrorLevel)' == '0' AND '$(QtDesignTimeBuild)' == 'true'"
       SourceFiles="$(QtVarsFilePath)" DestinationFiles="$(QtVarsDesignTimeNew)"/>
     <WriteLinesToFile
-      Condition="'$(ErrorLevel)' == '0' AND '$(QtVSToolsBuild)' == 'true'"
+      Condition="'$(ErrorLevel)' == '0' AND '$(QtDesignTimeBuild)' == 'true'"
       File="$(QtVarsIndexPathDesignTime)" Overwrite="true" Lines="$(QtVarsDesignTimeNew)"/>
 
     <!--// Clean-up -->
diff --git a/QtMSBuild/QtMsBuild/translation/qttranslation.targets b/QtMSBuild/QtMsBuild/translation/qttranslation.targets
index 6b599f9..4f15175 100644
--- a/QtMSBuild/QtMsBuild/translation/qttranslation.targets
+++ b/QtMSBuild/QtMsBuild/translation/qttranslation.targets
@@ -90,10 +90,14 @@
       <QtTranslation>
         <InputFiles
           >$(QtTranslationInput)</InputFiles>
-        <LUpdate
+        <LUpdate Condition="'$(ApplicationType)' == 'Linux'"
           >$(QtToolsPath)/lupdate</LUpdate>
-        <LRelease
+        <LRelease Condition="'$(ApplicationType)' == 'Linux'"
           >$(QtToolsPath)/lrelease</LRelease>
+        <LUpdate Condition="'$(ApplicationType)' != 'Linux'"
+          >$(QtToolsPath)/lupdate.exe</LUpdate>
+        <LRelease Condition="'$(ApplicationType)' != 'Linux'"
+          >$(QtToolsPath)/lrelease.exe</LRelease>
         <TsFile
           >%(Identity)</TsFile>
         <QmFile
@@ -395,6 +399,7 @@
       <Cmd>$(Cmd.Trim())</Cmd>
     </PropertyGroup>
     <HostExec
+      Condition="Exists(@(Options->'%(CmdExec)', ''))"
       Message="%(QtTranslationUpdate.UpdateDescription)"
       Command="$(Cmd)"
       Inputs="@(Options->'%(InputListFile)');@(Options->'%(InputFiles)')"
@@ -402,6 +407,9 @@
       RemoteTarget="$(ResolvedRemoteTarget)"
       RemoteProjectDir="$(_ResolvedRemoteProjectDir)">
     </HostExec>
+    <Warning
+      Condition="!Exists(@(Options->'%(CmdExec)', ''))"
+      File="%(QtTranslationUpdate.Identity)" Text="'lupdate' not found; skipping" />
 
     <!--
     ///////////////////////////////////////////////////////////////////////////////////////////////
@@ -556,6 +564,7 @@
       <Cmd>$(Cmd.Trim())</Cmd>
     </PropertyGroup>
     <HostExec
+      Condition="Exists(@(Options->'%(CmdExec)', ''))"
       Message="%(QtTranslationRelease.ReleaseDescription)"
       Command="$(Cmd)"
       Inputs="@(Options->'%(InputFile)')"
@@ -563,6 +572,9 @@
       RemoteTarget="$(ResolvedRemoteTarget)"
       RemoteProjectDir="$(_ResolvedRemoteProjectDir)">
     </HostExec>
+    <Warning
+      Condition="!Exists(@(Options->'%(CmdExec)', ''))"
+      File="%(QtTranslationRelease.Identity)" Text="'lrelease' not found; skipping" />
 
     <!--
     ///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/QtMSBuild/Tasks/CriticalSection.cs b/QtMSBuild/Tasks/CriticalSection.cs
index e2a44d6..53423f3 100644
--- a/QtMSBuild/Tasks/CriticalSection.cs
+++ b/QtMSBuild/Tasks/CriticalSection.cs
@@ -84,8 +84,6 @@
             if (Lock) {
                 // Wait until locked
                 if (!buildLock.WaitOne(1000)) {
-                    // Issue waiting warning
-                    Log.LogWarning("Qt::BuildLock[{0}]: Waiting...", Name);
                     var t = Stopwatch.StartNew();
                     do {
                         // Check for build errors
diff --git a/QtMSBuild/Tasks/QtRunTask.cs b/QtMSBuild/Tasks/QtRunTask.cs
new file mode 100644
index 0000000..447543e
--- /dev/null
+++ b/QtMSBuild/Tasks/QtRunTask.cs
@@ -0,0 +1,246 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#region Task TaskName="QtRunTask"
+
+#region Reference
+//System.Runtime
+#endregion
+
+#region Using
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+#endregion
+
+#region Comment
+/////////////////////////////////////////////////////////////////////////////////////////////////
+/// TASK QtRunTask
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Execute a task from the specified assembly, taking as input a list of items. Each item
+// metadata is copied to a task property with the same name. After the task is executed, the
+// result for each item is then stored in a new metadata for that item. The final output is the
+// list of modified items.
+// Parameters /////////////////////////////////////////////////////////////////////////////////
+//  in ITaskItem[]   Items........................List of source items.
+//  in String        AssemblyPath.................Path to assembly containing the task.
+//  in String        TaskName.....................Full name of task, including namespace.
+//  in String        TaskInput....................Name of task input property.
+//  in String        TaskOutput (optional)........Name of task output property.
+//    If unspecified, task output is ignored.
+//  in String        NewMetadata (optional).......Name of new item metadata to store result.
+//    If unspecified, defaults to TaskOutput.
+// out ITaskItem[]   Result.......................Output list of modified items.
+//    If TaskOutput is unspecified, Result will be empty.
+// Example //////////////////////////////////////////////////////////////////////////////////////
+//  Items = {
+//      ClCompile {
+//          Identity = "main.cpp",
+//          ...
+//          EnforceTypeConversionRules = False,
+//          ...
+//      }
+//  }
+//  AssemblyPath = "$(VCTargetsPath)\Microsoft.Build.CPPTasks.Common.dll"
+//  TaskName = "Microsoft.Build.CPPTasks.CLCommandLine"
+//  TaskInput = "Sources"
+//  TaskOutput = "CommandLines"
+//  NewMetadata = "CommandLine"
+//  Result = {
+//      ClCompile_Modified {
+//          Identity = "main.cpp",
+//          ...
+//          EnforceTypeConversionRules = False,
+//          ...
+//          CommandLine = "... /Zc:rvalueCast- ..."
+//      }
+//  }
+#endregion
+
+namespace QtVsTools.QtMsBuild.Tasks
+{
+    public static class QtRunTask
+    {
+        public static QtMSBuild.ITaskLoggingHelper Log { get; set; }
+        public static IBuildEngine BuildEngine { get; set; }
+        public static ITaskHost HostObject { get; set; }
+
+        public static bool Execute(
+        #region Parameters
+            Microsoft.Build.Framework.ITaskItem[] Items,
+            System.String AssemblyPath,
+            System.String TaskName,
+            System.String TaskInput,
+            out Microsoft.Build.Framework.ITaskItem[] Result,
+            System.String TaskOutput = null,
+            System.String NewMetadata = null)
+        #endregion
+        {
+            #region Code
+            var reserved = new HashSet<string>
+            {
+                "AccessedTime", "CreatedTime", "DefiningProjectDirectory",
+                "DefiningProjectExtension", "DefiningProjectFullPath", "DefiningProjectName",
+                "Directory", "Extension", "Filename", "FullPath", "Identity", "ModifiedTime",
+                "RecursiveDir", "RelativeDir", "RootDir",
+            };
+
+            // Output default values
+            Result = null;
+
+            // Load specified assembly
+            var taskAssembly = Assembly.LoadFile(AssemblyPath);
+            if (taskAssembly == null)
+                throw new ArgumentException("AssemblyPath");
+
+            // Access task type
+            var taskType = taskAssembly.GetType(TaskName);
+            if (taskType == null)
+                throw new ArgumentException("TaskName");
+
+            // Task type has the following requirements:
+            //  * Must be a descendant of the ToolTask type
+            //  * Cannot be an abstract class
+            //  * Cannot have generic type arguments
+            //  * Must have a public default constructor
+            if (!typeof(ToolTask).IsAssignableFrom(taskType))
+                throw new NotSupportedException("Not a ToolTask derived type");
+            if (taskType.IsAbstract)
+                throw new NotSupportedException("Abstract class");
+            if (taskType.ContainsGenericParameters)
+                throw new NotSupportedException("Generic class");
+            var ctorInfo = ((TypeInfo)taskType).DeclaredConstructors
+                .Where(x => x.GetParameters().Length == 0)
+                .FirstOrDefault();
+            if (ctorInfo == null)
+                throw new NotSupportedException("No default constructor");
+
+            // Access input property of task type
+            var inputProperty = taskType.GetProperty(TaskInput);
+            if (inputProperty == null)
+                throw new ArgumentException("TaskInput");
+            if (inputProperty.PropertyType != typeof(ITaskItem)
+                && inputProperty.PropertyType != typeof(ITaskItem[])) {
+                throw new NotSupportedException("Input property type is not supported");
+            }
+
+            // If output was specified, access corresponding property of task type
+            PropertyInfo outputProperty = null;
+            if (TaskOutput != null) {
+                outputProperty = taskType.GetProperty(TaskOutput);
+                if (outputProperty == null)
+                    throw new ArgumentException("TaskOutput");
+                if (outputProperty.PropertyType != typeof(string)
+                    && outputProperty.PropertyType != typeof(string[])
+                    && outputProperty.PropertyType != typeof(ITaskItem[])) {
+                    throw new NotSupportedException("Output property type is not supported");
+                }
+                if (NewMetadata == null)
+                    NewMetadata = TaskOutput;
+            }
+
+            var resultItems = new List<ITaskItem>();
+            foreach (var item in Items) {
+                // For each source item ...
+
+                // Instantiate task
+                var task = ctorInfo.Invoke(new object[0]) as ToolTask;
+                task.BuildEngine = BuildEngine;
+                task.HostObject = HostObject;
+
+                // Set task input property to the source item
+                var inputPropertyType = inputProperty.PropertyType;
+                if (inputPropertyType == typeof(ITaskItem)) {
+                    inputProperty.SetValue(task, item);
+                } else if (inputPropertyType == typeof(ITaskItem[])) {
+                    inputProperty.SetValue(task, new ITaskItem[] { item });
+                }
+
+                var names = item.MetadataNames.Cast<string>()
+                    .Where(x => !reserved.Contains(x));
+                foreach (var name in names) {
+                    // For each metadata in the source item ...
+
+                    // Try to obtain a task property with the same name
+                    var taskProperty = taskType.GetProperty(name);
+                    if (taskProperty != null) {
+                        // If the property exists, set it to the metadata value
+                        string metadataValue = item.GetMetadata(name);
+                        var propertyType = taskProperty.PropertyType;
+                        if (propertyType == typeof(bool)) {
+                            taskProperty.SetValue(task, metadataValue.Equals("true",
+                                StringComparison.InvariantCultureIgnoreCase));
+                        } else if (propertyType == typeof(string)) {
+                            taskProperty.SetValue(task, metadataValue);
+                        } else if (propertyType == typeof(string[])) {
+                            taskProperty.SetValue(task, metadataValue.Split(';'));
+                        }
+                    }
+                }
+
+                // Run task
+                if (!task.Execute())
+                    throw new Exception(string.Format("Task failed ({0})", item.ItemSpec));
+
+                // Record task output
+                if (TaskOutput != null) {
+                    // Create output item as copy of source item
+                    var resultItem = new TaskItem(item);
+
+                    // Set new metadata and add output item to the result list
+                    string outputValue;
+                    object propertyValue = outputProperty.GetValue(task);
+                    if (propertyValue == null)
+                        outputValue = string.Empty;
+                    else if (outputProperty.PropertyType == typeof(string))
+                        outputValue = propertyValue as string;
+                    else if (outputProperty.PropertyType == typeof(string[]))
+                        outputValue = (propertyValue as string[]).FirstOrDefault();
+                    else if (outputProperty.PropertyType == typeof(ITaskItem[]))
+                        outputValue = (propertyValue as ITaskItem[]).FirstOrDefault().ItemSpec;
+                    else
+                        outputValue = string.Empty;
+                    if (NewMetadata != null)
+                        resultItem.SetMetadata(NewMetadata, outputValue);
+                    resultItems.Add(resultItem);
+                }
+            }
+
+            // Return the list of output items
+            Result = resultItems.ToArray();
+
+            #endregion
+
+            return true;
+        }
+    }
+}
+#endregion
diff --git a/QtVsTest/Macro.cs b/QtVsTest/Macro.cs
index 1c1004d..e4477e8 100644
--- a/QtVsTest/Macro.cs
+++ b/QtVsTest/Macro.cs
@@ -82,7 +82,7 @@
         /// <summary>
         /// Name of reusable macro
         /// </summary>
-        public string Name { get; private set; }
+        private string Name { get; set; }
 
         /// <summary>
         /// True if macro compilation was successful
@@ -104,8 +104,9 @@
         /// </summary>
         public bool QuitWhenDone { get; private set; }
 
-        AsyncPackage Package { get; set; }
-        EnvDTE80.DTE2 Dte { get; set; }
+        AsyncPackage Package { get; }
+        EnvDTE80.DTE2 Dte { get; }
+        IntPtr MainWindowHWnd { get; }
 
         AutomationElement UiRoot => AutomationElement.RootElement;
 
@@ -115,65 +116,55 @@
             get
             {
                 if (_UiVsRoot == null)
-#if VS2022
-                    _UiVsRoot = AutomationElement.FromHandle(Dte.MainWindow.HWnd);
-#else
-                    _UiVsRoot = AutomationElement.FromHandle(new IntPtr(Dte.MainWindow.HWnd));
-#endif
+                    _UiVsRoot = AutomationElement.FromHandle(MainWindowHWnd);
                 return _UiVsRoot;
             }
         }
 
-        JoinableTaskFactory JoinableTaskFactory { get; set; }
-        CancellationToken ServerLoop { get; set; }
+        JoinableTaskFactory JoinableTaskFactory { get; }
+        CancellationToken ServerLoop { get; }
 
         string Message { get; set; }
 
         static MacroParser Parser { get; set; }
         MacroLines MacroLines { get; set; }
 
-        List<string> SelectedAssemblies { get { return _SelectedAssemblies; } }
-        List<string> _SelectedAssemblies =
-            new List<string>
-            {
-                "QtVsTest",
-                "System.Core",
-            };
+        private List<string> SelectedAssemblies { get; } = new List<string>
+        {
+            typeof(Macro).Assembly.FullName,
+            typeof(EnvDTE.DTE).Assembly.FullName,
+            typeof(AutomationElement).Assembly.FullName,
+            "System.Core",
+        };
 
         IEnumerable<string> RefAssemblies { get; set; }
 
-        List<string> Namespaces { get { return _Namespaces; } }
-        List<string> _Namespaces =
-            new List<string>
-            {
-                "System",
-                "System.Linq",
-                "System.Reflection",
-                "Task = System.Threading.Tasks.Task",
-                "System.Windows.Automation",
-                "EnvDTE",
-                "EnvDTE80",
-            };
+        private List<string> Namespaces { get; } = new List<string>
+        {
+            "System",
+            "System.Linq",
+            "System.Reflection",
+            "Task = System.Threading.Tasks.Task",
+            "System.Windows.Automation",
+            "EnvDTE",
+            "EnvDTE80",
+        };
 
-        Dictionary<string, VSServiceRef> ServiceRefs { get { return _ServiceRefs; } }
-        Dictionary<string, VSServiceRef> _ServiceRefs =
-            new Dictionary<string, VSServiceRef>
+        private Dictionary<string, VSServiceRef> ServiceRefs { get; } = new Dictionary<string, VSServiceRef>
+        {
             {
-                {
-                    "Dte", new VSServiceRef
+                "Dte", new VSServiceRef
                     { Name = "Dte", Interface = "DTE2", Type = "DTE" }
-                },
-            };
+            },
+        };
 
-        Dictionary<string, GlobalVar> GlobalVars { get { return _GlobalVars; } }
-        Dictionary<string, GlobalVar> _GlobalVars =
-            new Dictionary<string, GlobalVar>
+        private Dictionary<string, GlobalVar> GlobalVars { get; } = new Dictionary<string, GlobalVar>
+        {
             {
-                {
-                    "Result", new GlobalVar
+                "Result", new GlobalVar
                     { Type = "string", Name = "Result", InitialValueExpr = "string.Empty" }
-                },
-            };
+            },
+        };
 
         string CSharpMethodCode { get; set; }
         string CSharpClassCode { get; set; }
@@ -187,10 +178,10 @@
         const BindingFlags PUBLIC_STATIC = BindingFlags.Public | BindingFlags.Static;
         const StringComparison IGNORE_CASE = StringComparison.InvariantCultureIgnoreCase;
 
-        static ConcurrentDictionary<string, Macro> Macros
+        static readonly ConcurrentDictionary<string, Macro> Macros
             = new ConcurrentDictionary<string, Macro>();
 
-        static ConcurrentDictionary<string, object> Globals
+        static readonly ConcurrentDictionary<string, object> Globals
             = new ConcurrentDictionary<string, object>();
 
         /// <summary>
@@ -202,6 +193,7 @@
         public Macro(
             AsyncPackage package,
             EnvDTE80.DTE2 dte,
+            IntPtr mainWindowHWnd,
             JoinableTaskFactory joinableTaskFactory,
             CancellationToken serverLoop)
         {
@@ -209,6 +201,7 @@
             JoinableTaskFactory = joinableTaskFactory;
             ServerLoop = serverLoop;
             Dte = dte;
+            MainWindowHWnd = mainWindowHWnd;
             ErrorMsg("Uninitialized");
         }
 
@@ -510,6 +503,8 @@
                     return false;
                 break;
             }
+
+            csharp.AppendLine();
             return true;
         }
 
@@ -615,6 +610,38 @@
 
                 csharp.AppendFormat(@"
                     await WaitExpr({0}, () => UiContext = {1});", timeout, context);
+
+            } else if (s.Args[0].Equals("find", IGNORE_CASE)) {
+                //# ui find [all] [_var_name_] [_timeout_] => <_scope_>, <_condition_>
+
+                var args = new Queue<string>(s.Args.Skip(1));
+
+                bool findAll = false;
+                if (args.Any() && args.Peek().Equals("all", IGNORE_CASE)) {
+                    findAll = true;
+                    args.Dequeue();
+                }
+                string funcName = findAll ? "FindAll" : "FindFirst";
+                string varType = findAll ? "AutomationElementCollection" : "AutomationElement";
+
+                string varName = null;
+                if (args.Any() && !char.IsDigit(args.Peek()[0]))
+                    varName = args.Dequeue();
+                if (findAll && string.IsNullOrEmpty(varName))
+                    return ErrorMsg("Invalid #ui statement");
+
+                int timeout = 3000;
+                if (args.Any() && char.IsDigit(args.Peek()[0]))
+                    timeout = int.Parse(args.Dequeue());
+
+                if (varName == null) {
+                    varName = "UiContext";
+                } else {
+                    csharp.Append($@"
+                        {varType} {varName} = null;");
+                }
+                csharp.Append($@"
+                    await WaitExpr({timeout}, () => {varName} = UiContext.{funcName}({s.Code}));");
 
             } else if (s.Args[0].Equals("pattern", IGNORE_CASE)) {
                 //# ui pattern <_TypeName_> <_VarName_> [ => _string_ [, _string_, ... ] ]
@@ -790,7 +817,9 @@
                     File.Delete(macroDllPath);
                 return ErrorMsg(string.Join("\r\n",
                     CompilerResults.Errors.Cast<CompilerError>()
-                        .Select(x => x.ErrorText)));
+                        .Select(x => $"{x.Line}: {x.ErrorText}")
+                        .Append(CSharpClassCode)
+                        .Union(RefAssemblies)));
             }
 
             MacroAssembly = AppDomain.CurrentDomain.Load(File.ReadAllBytes(macroDllPath));
@@ -927,8 +956,7 @@
             foreach (var globalVar in GlobalVars.Values) {
                 string varName = globalVar.Name;
                 Type varType = globalVar.FieldInfo.FieldType;
-                object value;
-                if (Globals.TryGetValue(varName, out value)) {
+                if (Globals.TryGetValue(varName, out object value)) {
                     Type valueType = value.GetType();
                     if (!varType.IsAssignableFrom(valueType)) {
                         throw new InvalidCastException(string.Format(
@@ -968,8 +996,7 @@
 
         static Macro GetMacro(string name)
         {
-            Macro macro;
-            if (!Macros.TryGetValue(name, out macro))
+            if (!Macros.TryGetValue(name, out Macro macro))
                 return null;
             return macro;
         }
diff --git a/QtVsTest/MacroParser.cs b/QtVsTest/MacroParser.cs
index 4f8d240..3d67713 100644
--- a/QtVsTest/MacroParser.cs
+++ b/QtVsTest/MacroParser.cs
@@ -27,17 +27,18 @@
 ****************************************************************************/
 
 using System;
+using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
+using QtVsTools.SyntaxAnalysis;
 
 namespace QtVsTest.Macros
 {
-    using System.Collections;
-    using static QtVsTools.SyntaxAnalysis.RegExpr;
+    using static RegExpr;
 
     class MacroLines : IEnumerable<MacroLine>
     {
-        List<MacroLine> Lines = new List<MacroLine>();
+        readonly List<MacroLine> Lines = new List<MacroLine>();
 
         public void Add(MacroLine line) { Lines.Add(line); }
 
@@ -120,7 +121,7 @@
 
     public class CodeLine : MacroLine
     {
-        public string Code;
+        public readonly string Code;
         public CodeLine(string code)
         {
             Code = code;
diff --git a/QtVsTest/MacroServer.cs b/QtVsTest/MacroServer.cs
index 24f0033..b00fba5 100644
--- a/QtVsTest/MacroServer.cs
+++ b/QtVsTest/MacroServer.cs
@@ -46,10 +46,10 @@
     /// </summary>
     class MacroServer
     {
-        public CancellationTokenSource Loop { get; private set; }
+        public CancellationTokenSource Loop { get; }
 
-        AsyncPackage Package { get; set; }
-        JoinableTaskFactory JoinableTaskFactory { get; set; }
+        AsyncPackage Package { get; }
+        JoinableTaskFactory JoinableTaskFactory { get; }
 
         /// <summary>
         /// Macro server constructor
@@ -70,6 +70,7 @@
         {
             await JoinableTaskFactory.SwitchToMainThreadAsync(Loop.Token);
             var DTE = await Package.GetServiceAsync(typeof(DTE)) as DTE2;
+            var mainWindowHWnd = new IntPtr((long)DTE.MainWindow.HWnd);
             await TaskScheduler.Default;
 
             var pipeName = string.Format("QtVSTest_{0}", Process.GetCurrentProcess().Id);
@@ -97,7 +98,8 @@
                             if (Loop.Token.IsCancellationRequested)
                                 break;
 
-                            var macro = new Macro(Package, DTE, JoinableTaskFactory, Loop.Token);
+                            var macro = new Macro(
+                                Package, DTE, mainWindowHWnd, JoinableTaskFactory, Loop.Token);
                             await macro.CompileAsync(Encoding.UTF8.GetString(data));
                             if (macro.AutoRun)
                                 await macro.RunAsync();
diff --git a/QtVsTest/QtVsTest.cs b/QtVsTest/QtVsTest.cs
index 74a7939..15ed031 100644
--- a/QtVsTest/QtVsTest.cs
+++ b/QtVsTest/QtVsTest.cs
@@ -27,6 +27,7 @@
 ****************************************************************************/
 
 using System;
+using System.IO;
 using System.Runtime.InteropServices;
 using System.Threading;
 using Microsoft.VisualStudio.Shell;
@@ -38,7 +39,6 @@
 namespace QtVsTest
 {
     using Macros;
-    using System.IO;
 
     [Guid(PackageGuidString)]
     [InstalledProductRegistration(
@@ -53,7 +53,7 @@
     public sealed class QtVsTest : AsyncPackage
     {
         public const string PackageGuidString = "0e258dce-fc8a-49a2-81c5-c9e138bfe500";
-        MacroServer MacroServer { get; set; }
+        MacroServer MacroServer { get; }
 
         public QtVsTest()
         {
diff --git a/QtVsTest/QtVsTest.csproj b/QtVsTest/QtVsTest.csproj
index c1c2aa4..d9a4894 100644
--- a/QtVsTest/QtVsTest.csproj
+++ b/QtVsTest/QtVsTest.csproj
@@ -2,7 +2,7 @@
 <!--
 /****************************************************************************
 **
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -69,6 +69,8 @@
     <DefineConstants>DEBUG;TRACE</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
+    <PlatformTarget Condition="'$(VisualStudioVersion)' == '17.0'">x64</PlatformTarget>
+    <PlatformTarget Condition="'$(VisualStudioVersion)' != '17.0'">x86</PlatformTarget>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType>pdbonly</DebugType>
@@ -87,55 +89,36 @@
     <Reference Include="System" />
     <Reference Include="System.Design" />
     <Reference Include="System.Drawing" />
-    <Reference Include="Microsoft.VisualStudio.ProjectSystem">
-      <HintPath>$(VsInstallRoot)\Common7\IDE\CommonExtensions\Microsoft\Project\Microsoft.VisualStudio.ProjectSystem.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.VisualStudio.Composition">
-      <HintPath>$(VsInstallRoot)\Common7\IDE\PrivateAssemblies\Microsoft.VisualStudio.Composition.dll</HintPath>
-    </Reference>
   </ItemGroup>
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
-  // Version specific references
+  // General package references
   // -->
   <Import Project="$(SolutionDir)\references.props" />
   <ItemGroup>
-    <PackageReference Include="System.ComponentModel.Composition"
-      Version="$(Version_System_ComponentModel_Composition)" />
-    <PackageReference Include="Stub.System.Data.SQLite.Core.NetFramework"
-      Version="$(Version_Stub_System_Data_SQLite_Core_NetFramework)" />
-    <PackageReference Include="Newtonsoft.Json"
-      Version="$(Version_Newtonsoft_Json)" />
-    <PackageReference Include="Microsoft.Build"
-      Version="$(Version_Microsoft_Build)" />
-    <PackageReference Include="Microsoft.Build.Framework"
-      Version="$(Version_Microsoft_Build_Framework)" />
-    <PackageReference Include="Microsoft.Build.Tasks.Core"
-      Version="$(Version_Microsoft_Build_Tasks_Core)" />
-    <PackageReference Include="Microsoft.VisualStudio.SDK"
-      Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
-    <PackageReference Include="Microsoft.VSSDK.BuildTools"
-      Version="$(Version_Microsoft_VSSDK_BuildTools)" />
-    <PackageReference Include="Microsoft.VisualStudio.Shell.Framework"
-      Version="$(Version_Microsoft_VisualStudio_Shell_Framework)" />
-    <PackageReference Include="Microsoft.VisualStudio.Validation"
-      Version="$(Version_Microsoft_VisualStudio_Validation)" />
-    <PackageReference Include="$(Name_Microsoft_VisualStudio_Threading)"
-      Version="$(Version_Microsoft_VisualStudio_Threading)" />
-    <PackageReference Include="System.Collections.Immutable"
-      Version="$(Version_System_Collections_Immutable)" />
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_ProjectSystem)" Version="$(Version_Microsoft_VisualStudio_ProjectSystem)" />
   </ItemGroup>
-  <ItemGroup Condition="'$(VisualStudioVersion)'=='17.0'">
-    <PackageReference Include="$(Name_Microsoft_VisualStudio_VCProjectEngine)"
-      Version="$(Version_Microsoft_VisualStudio_VCProjectEngine)" />
-  </ItemGroup>
-  <ItemGroup Condition="'$(VisualStudioVersion)'=='16.0'">
-    <PackageReference Include="$(Name_Microsoft_VisualStudio_VCProjectEngine)"
-      Version="$(Version_Microsoft_VisualStudio_VCProjectEngine)" />
-  </ItemGroup>
-  <ItemGroup Condition="'$(VisualStudioVersion)'=='15.0'">
-    <Reference Include="Microsoft.VisualStudio.VCProjectEngine" />
-  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
   // Solution project references
@@ -210,6 +193,26 @@
     </Content>
   </ItemGroup>
   <Choose>
+    <When Condition="Exists('$(MSBuildProgramFiles32)\Windows Kits\10\bin\10.0.22000.0')">
+      <PropertyGroup>
+        <Win10SDKPath>$(MSBuildProgramFiles32)\Windows Kits\10\bin\10.0.22000.0</Win10SDKPath>
+      </PropertyGroup>
+    </When>
+    <When Condition="Exists('$(MSBuildProgramFiles32)\Windows Kits\10\bin\10.0.20348.0')">
+      <PropertyGroup>
+        <Win10SDKPath>$(MSBuildProgramFiles32)\Windows Kits\10\bin\10.0.20348.0</Win10SDKPath>
+      </PropertyGroup>
+    </When>
+    <When Condition="Exists('$(MSBuildProgramFiles32)\Windows Kits\10\bin\10.0.19041.0')">
+      <PropertyGroup>
+        <Win10SDKPath>$(MSBuildProgramFiles32)\Windows Kits\10\bin\10.0.19041.0</Win10SDKPath>
+      </PropertyGroup>
+    </When>
+    <When Condition="Exists('$(MSBuildProgramFiles32)\Windows Kits\10\bin\10.0.18362.0')">
+      <PropertyGroup>
+        <Win10SDKPath>$(MSBuildProgramFiles32)\Windows Kits\10\bin\10.0.18362.0</Win10SDKPath>
+      </PropertyGroup>
+    </When>
     <When Condition="Exists('$(MSBuildProgramFiles32)\Windows Kits\10\bin\10.0.17763.0')">
       <PropertyGroup>
         <Win10SDKPath>$(MSBuildProgramFiles32)\Windows Kits\10\bin\10.0.17763.0</Win10SDKPath>
@@ -232,7 +235,7 @@
     </When>
   </Choose>
   <PropertyGroup Condition="'$(Win10SDKPath)' != ''">
-    <UIAVerifyPath>$(Win10SDKPath)\x86\UIAVerify</UIAVerifyPath>
+    <UIAVerifyPath>$(Win10SDKPath)\$(PlatformTarget)\UIAVerify</UIAVerifyPath>
   </PropertyGroup>
   <ItemGroup Condition="'$(UIAVerifyPath)' != ''">
     <Reference Include="Interop.UIAutomationClient">
@@ -246,9 +249,6 @@
       <Aliases>global</Aliases>
       <EmbedInteropTypes>False</EmbedInteropTypes>
     </Reference>
-  </ItemGroup>
-  <ItemGroup>
-    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\transform.targets" />
diff --git a/QtVsTools.Core/BuildConfig.cs b/QtVsTools.Core/BuildConfig.cs
index 713e9f8..ac8647c 100644
--- a/QtVsTools.Core/BuildConfig.cs
+++ b/QtVsTools.Core/BuildConfig.cs
@@ -30,7 +30,6 @@
 {
     public struct BuildConfig
     {
-        public const uint Both = 0x03;
         public const uint Release = 0x01;
         public const uint Debug = 0x02;
 
diff --git a/QtVsTools.Core/CommandLineParser.cs b/QtVsTools.Core/CommandLineParser.cs
index 7380cc8..995d064 100644
--- a/QtVsTools.Core/CommandLineParser.cs
+++ b/QtVsTools.Core/CommandLineParser.cs
@@ -29,10 +29,10 @@
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
+using System.IO;
 using System.Linq;
 using System.Text;
 using System.Text.RegularExpressions;
-using System.IO;
 
 namespace QtVsTools.Core.CommandLine
 {
@@ -40,13 +40,12 @@
 
     public class Parser
     {
-
-        List<Option> commandLineOptionList = new List<Option>();
-        Dictionary<string, int> nameHash = new Dictionary<string, int>();
-        Dictionary<int, List<string>> optionValuesHash = new Dictionary<int, List<string>>();
-        List<string> optionNames = new List<string>();
-        List<string> positionalArgumentList = new List<string>();
-        List<string> unknownOptionNames = new List<string>();
+        readonly List<Option> commandLineOptionList = new List<Option>();
+        readonly Dictionary<string, int> nameHash = new Dictionary<string, int>();
+        readonly Dictionary<int, List<string>> optionValuesHash = new Dictionary<int, List<string>>();
+        readonly List<string> optionNames = new List<string>();
+        readonly List<string> positionalArgumentList = new List<string>();
+        readonly List<string> unknownOptionNames = new List<string>();
         bool needsParsing = true;
 
         public enum SingleDashWordOptionMode
@@ -118,8 +117,7 @@
 
         IEnumerable<string> Aliases(string optionName)
         {
-            int optionIndex;
-            if (!nameHash.TryGetValue(optionName, out optionIndex)) {
+            if (!nameHash.TryGetValue(optionName, out int optionIndex)) {
                 return new List<string>();
             }
             return commandLineOptionList[optionIndex].Names;
@@ -204,8 +202,7 @@
              IEnumerator<string> argumentEnumerator, ref bool atEnd)
         {
             const char assignChar = '=';
-            int optionOffset;
-            if (nameHash.TryGetValue(optionName, out optionOffset)) {
+            if (nameHash.TryGetValue(optionName, out int optionOffset)) {
                 int assignPos = argument.IndexOf(assignChar);
                 bool withValue = !string.IsNullOrEmpty(
                     commandLineOptionList[optionOffset].ValueName);
@@ -267,7 +264,7 @@
                             var optFilePath = macros.ExpandString(argData.Substring(1));
                             string[] additionalArgs = File.ReadAllLines(
                                 Path.Combine(workingDir, optFilePath));
-                            if (additionalArgs != null) {
+                            if (additionalArgs.Length != 0) {
                                 var additionalArgsString = string.Join(" ", additionalArgs
                                     .Select(x => "\"" + x.Replace("\"", "\\\"") + "\""));
                                 arguments.AddRange(TokenizeArgs(additionalArgsString, macros));
@@ -356,10 +353,9 @@
                             if (!RegisterFoundOption(optionName)) {
                                 error = true;
                             } else {
-                                int optionOffset;
                                 Trace.Assert(nameHash.TryGetValue(
                                     optionName,
-                                    out optionOffset));
+                                    out int optionOffset));
                                 bool withValue = !string.IsNullOrEmpty(
                                     commandLineOptionList[optionOffset].ValueName);
                                 if (withValue) {
@@ -397,10 +393,9 @@
                         if (argument.Length > 2) {
                             string possibleShortOptionStyleName = argument.Substring(1, 1);
 
-                            int shortOptionIdx;
                             if (nameHash.TryGetValue(
                                 possibleShortOptionStyleName,
-                                out shortOptionIdx)) {
+                                out int shortOptionIdx)) {
                                 var arg = commandLineOptionList[shortOptionIdx];
                                 if ((arg.Flags & Option.Flag.ShortOptionStyle) != 0) {
                                     RegisterFoundOption(possibleShortOptionStyleName);
@@ -466,8 +461,7 @@
         public IEnumerable<string> Values(string optionName)
         {
             CheckParsed("Values");
-            int optionOffset;
-            if (nameHash.TryGetValue(optionName, out optionOffset)) {
+            if (nameHash.TryGetValue(optionName, out int optionOffset)) {
                 var values = optionValuesHash[optionOffset];
                 return values;
             }
@@ -525,7 +519,6 @@
         public IEnumerable<string> Names
         {
             get;
-            private set;
         }
 
         public string ValueName
@@ -558,7 +551,7 @@
 
     static class Lexer
     {
-        static Regex lexer = new Regex(
+        static readonly Regex lexer = new Regex(
             /* Newline    */ @"(\n)" +
             /* Unquoted   */ @"|((?:(?:[^\s\""])|(?:(?<=\\)\""))+)" +
             /* Quoted     */ @"|(?:\""((?:(?:[^\""])|(?:(?<=\\)\""))+)\"")" +
diff --git a/QtVsTools.Core/Common/EnumExt.cs b/QtVsTools.Core/Common/EnumExt.cs
index 0406e2c..c05f7bc 100644
--- a/QtVsTools.Core/Common/EnumExt.cs
+++ b/QtVsTools.Core/Common/EnumExt.cs
@@ -40,6 +40,8 @@
     /// </summary>
     public static class EnumExt
     {
+        static LazyFactory StaticLazy { get; } = new LazyFactory();
+
         /// <summary>
         /// Wrapper for enum cast values.
         /// </summary>
@@ -64,7 +66,7 @@
         [AttributeUsage(AttributeTargets.All)]
         public sealed class StringAttribute : Attribute, ICast<string>
         {
-            public string Value { get; private set; }
+            public string Value { get; }
             public StringAttribute(string str) { Value = str; }
         }
 
@@ -128,8 +130,7 @@
         /// </summary>
         public static TEnum Cast<T, TEnum>(this T valueT, TEnum defaultValue) where TEnum : struct
         {
-            TEnum value;
-            return TryCast(valueT, out value) ? value : defaultValue;
+            return TryCast(valueT, out TEnum value) ? value : defaultValue;
         }
 
         /// <summary>
@@ -201,15 +202,14 @@
                 .FirstOrDefault();
         }
 
-        static IEnumerable<Type> _CastAttribTypes;
         /// <summary>
         /// List of cast attribute types.
         /// </summary>
         /// <remarks>
         /// Future cast attribute types need to be added to this list.
         /// </remarks>
-        static IEnumerable<Type> CastAttribTypes => _CastAttribTypes
-            ?? (_CastAttribTypes = new[]
+        static IEnumerable<Type> CastAttribTypes => StaticLazy.Get(() =>
+            CastAttribTypes, () => new[]
             {
                 typeof(StringAttribute)
             });
diff --git a/QtVsTools.Core/Common/LazyFactory.cs b/QtVsTools.Core/Common/LazyFactory.cs
new file mode 100644
index 0000000..c914cee
--- /dev/null
+++ b/QtVsTools.Core/Common/LazyFactory.cs
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Collections.Concurrent;
+using System.Diagnostics;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace QtVsTools.Common
+{
+    public class LazyFactory
+    {
+        private Lazy<ConcurrentDictionary<PropertyInfo, Lazy<object>>> LazyObjs { get; }
+        private ConcurrentDictionary<PropertyInfo, Lazy<object>> Objs => LazyObjs.Value;
+
+        public LazyFactory()
+        {
+            LazyObjs = new Lazy<ConcurrentDictionary<PropertyInfo, Lazy<object>>>();
+        }
+
+        public T Get<T>(Expression<Func<T>> propertyRef, Func<T> initFunc) where T : class
+        {
+            var lazyPropertyExpr = propertyRef?.Body as MemberExpression;
+            var lazyProperty = lazyPropertyExpr?.Member as PropertyInfo;
+            if (lazyProperty == null)
+                throw new ArgumentException("Invalid property reference", "propertyRef");
+            var lazyObj = Objs.GetOrAdd(lazyProperty, (_) => new Lazy<object>(() => initFunc()));
+            return lazyObj.Value as T;
+        }
+    }
+}
diff --git a/QtVsTools.Core/Common/QtVSIPSettingsShared.cs b/QtVsTools.Core/Common/QtVSIPSettingsShared.cs
new file mode 100644
index 0000000..5d86492
--- /dev/null
+++ b/QtVsTools.Core/Common/QtVSIPSettingsShared.cs
@@ -0,0 +1,261 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.VCProjectEngine;
+using Microsoft.Win32;
+using QtVsTools.Core;
+
+namespace QtVsTools.Common
+{
+    public static class QtVSIPSettingsShared
+    {
+        private static readonly Dictionary<string, string> mocDirCache
+            = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+        private static readonly Dictionary<string, string> uicDirCache
+            = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+        private static readonly Dictionary<string, string> rccDirCache
+            = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+
+        public static string GetDirectory(EnvDTE.Project project, string type)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            // check for directory in following order:
+            // - stored in project
+            // - stored in cache
+            // - retrieve from moc/uic steps
+            // - fall-back on hard-coded directory
+
+            var fullName = project?.FullName;
+            if (string.IsNullOrEmpty(fullName))
+                return GetDirectory(type); // - fall-back on hard-coded directory
+
+            if (project.Globals.get_VariablePersists(type)) // - stored in project
+                return HelperFunctions.NormalizeRelativeFilePath(project.Globals[type] as string);
+
+            switch (type) { // - stored in cache
+            case Resources.mocDirKeyword:
+                if (mocDirCache.ContainsKey(fullName))
+                    return mocDirCache[fullName];
+                break;
+            case Resources.uicDirKeyword:
+                if (uicDirCache.ContainsKey(fullName))
+                    return uicDirCache[fullName];
+                break;
+            case Resources.rccDirKeyword:
+                if (rccDirCache.ContainsKey(fullName))
+                    return rccDirCache[fullName];
+                break;
+            default:
+                return GetDirectory(type); // - fall-back on hard-coded directory
+            }
+
+            try {
+                string configName = null;
+                string platformName = null;
+                QtCustomBuildTool tool = null;
+                foreach (VCFile vcfile in (project.Object as VCProject).Files as IVCCollection) {
+                    var name = vcfile?.Name;
+                    if (string.IsNullOrEmpty(name))
+                        continue;
+                    if (!(HelperFunctions.IsHeaderFile(name) || HelperFunctions.IsMocFile(name)
+                        || HelperFunctions.IsUicFile(name) || HelperFunctions.IsQrcFile(name)))
+                        continue;
+
+                    foreach (VCFileConfiguration config in vcfile?.FileConfigurations as IVCCollection) {
+                        tool = new QtCustomBuildTool(config);
+                        if (tool == null)
+                            continue;
+                        configName = config.Name.Remove(config.Name.IndexOf('|'));
+                        var vcConfig = config.ProjectConfiguration as VCConfiguration;
+                        platformName = (vcConfig.Platform as VCPlatform).Name;
+                        var cmd = tool.CommandLine;
+                        if (cmd.Contains("moc.exe") || cmd.Contains("uic.exe") || cmd.Contains("rcc.exe"))
+                            break;
+                        tool = null;
+                    }
+
+                    if (tool != null)
+                        break;
+                }
+
+                if (tool == null)
+                    return GetDirectory(type); // - fall-back on hard-coded directory
+
+                var dir = ".";
+                var lastindex = tool.Outputs.LastIndexOf('\\');
+                if (tool.Outputs.LastIndexOf('/') > lastindex)
+                    lastindex = tool.Outputs.LastIndexOf('/');
+
+                if (lastindex != -1)
+                    dir = tool.Outputs.Substring(0, lastindex);
+                dir = dir.Replace("\"", "");
+
+                if (type == Resources.mocDirKeyword) {
+                    int index = dir.IndexOf(configName, StringComparison.OrdinalIgnoreCase);
+                    if (index != -1)
+                        dir = dir.Replace(dir.Substring(index, configName.Length), "$(ConfigurationName)");
+
+                    index = dir.IndexOf(platformName, StringComparison.OrdinalIgnoreCase);
+                    if (index != -1)
+                        dir = dir.Replace(dir.Substring(index, platformName.Length), "$(PlatformName)");
+                    dir = HelperFunctions.NormalizeRelativeFilePath(dir);
+
+                    mocDirCache.Add(fullName, dir);
+                } else if (type == Resources.uicDirKeyword) {
+                    dir = HelperFunctions.NormalizeRelativeFilePath(dir);
+                    uicDirCache.Add(fullName, dir);
+                } else if (type == Resources.rccDirKeyword) {
+                    dir = HelperFunctions.NormalizeRelativeFilePath(dir);
+                    rccDirCache.Add(fullName, dir);
+                } else {
+                    dir = HelperFunctions.NormalizeRelativeFilePath(dir);
+                }
+
+                CleanUpCache(project);
+                return dir; // - retrieved from moc/uic/rcc steps
+            } catch { }
+            return GetDirectory(type); // - fall-back on hard-coded directory
+        }
+
+        private const string registryPath = "SOFTWARE\\" + Resources.registryPackagePath;
+
+        public static string GetDirectory(string type)
+        {
+            try {
+                var key = Registry.CurrentUser.OpenSubKey(registryPath);
+                if (key != null) {
+                    if (key.GetValue(type, null) is string path)
+                        return HelperFunctions.NormalizeRelativeFilePath(path);
+                }
+            } catch { }
+            if (type == Resources.mocDirKeyword)
+                return Resources.generatedFilesDir + "\\$(ConfigurationName)";
+            return Resources.generatedFilesDir;
+        }
+
+        public static string GetOption(EnvDTE.Project project, string type)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            // check for directory in following order:
+            // - stored in project
+            // - globally defined default option
+            // - empty options
+            if (project != null && project.Globals.get_VariablePersists(type))
+                return project.Globals[type] as string;
+            return GetOption(type);
+        }
+
+        public static string GetOption(string type)
+        {
+            try {
+                var key = Registry.CurrentUser.OpenSubKey(registryPath);
+                if (key != null) {
+                    if (key.GetValue(type, null) is string opt)
+                        return opt;
+                }
+            } catch { }
+            return null;
+        }
+
+        public static bool GetBoolValue(EnvDTE.Project project, string type)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            // check for directory in following order:
+            // - stored in project
+            // - globally defined default option
+            // - empty options
+            if (project != null && project.Globals.get_VariablePersists(type))
+                return Convert.ToInt32(project.Globals[type] as string) > 0;
+            return GetBoolValue(type, false);
+        }
+
+        public static bool GetBoolValue(string key, bool defaultValue)
+        {
+            var regKey = Registry.CurrentUser.OpenSubKey(registryPath);
+            if (regKey == null)
+                return defaultValue;
+            return ((int)regKey.GetValue(key, defaultValue ? 1 : 0)) > 0;
+        }
+
+        public static bool ValueExists(string key)
+        {
+            var regKey = Registry.CurrentUser.OpenSubKey(registryPath);
+            if (regKey != null) {
+                foreach (var s in regKey.GetValueNames()) {
+                    if (s == key)
+                        return true;
+                }
+            }
+            return false;
+        }
+
+        public static string GetProjectQtSetting(EnvDTE.Project project, string propertyName)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            var activeConfig = project?.ConfigurationManager?.ActiveConfiguration;
+            if (activeConfig == null)
+                return null;
+            var activeConfigId = $"{activeConfig.ConfigurationName}|{activeConfig.PlatformName}";
+
+            try {
+                var props = project.Object as VCProject as IVCBuildPropertyStorage;
+                return props?.GetPropertyValue(propertyName, activeConfigId, "ProjectFile");
+            } catch {
+                return null;
+            }
+        }
+
+        public static void CleanUpCache(EnvDTE.Project project)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            var projects = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
+            foreach (var p in HelperFunctions.ProjectsInSolution(project.DTE))
+                projects.Add(p.FullName);
+
+            mocDirCache.RemoveValues(projects);
+            uicDirCache.RemoveValues(projects);
+            rccDirCache.RemoveValues(projects);
+        }
+
+        static void RemoveValues(this Dictionary<string, string> cache, HashSet<string> projects)
+        {
+            foreach (var key in cache.Keys) {
+                if (projects.Contains(key))
+                    cache.Remove(key);
+            }
+        }
+    }
+}
diff --git a/QtVsTools.Core/CompilerToolWrapper.cs b/QtVsTools.Core/CompilerToolWrapper.cs
index b9d95fc..f502f62 100644
--- a/QtVsTools.Core/CompilerToolWrapper.cs
+++ b/QtVsTools.Core/CompilerToolWrapper.cs
@@ -26,11 +26,11 @@
 **
 ****************************************************************************/
 
-using Microsoft.VisualStudio.VCProjectEngine;
 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Reflection;
+using Microsoft.VisualStudio.VCProjectEngine;
 
 namespace QtVsTools.Core
 {
@@ -44,7 +44,7 @@
     /// Using VCCLCompilerTool directly will break the VS integration for Win CE.
     class CompilerToolWrapper
     {
-        private VCCLCompilerTool compilerTool;
+        private readonly VCCLCompilerTool compilerTool;
         private readonly Object compilerObj;
         private readonly Type compilerType;
 
@@ -302,13 +302,6 @@
             return GetStringProperty("AdditionalIncludeDirectories");
         }
 
-        public string GetPrecompiledHeaderFile()
-        {
-            if (compilerTool != null)
-                return compilerTool.PrecompiledHeaderFile;
-            return GetStringProperty("PrecompiledHeaderFile");
-        }
-
         public string GetPrecompiledHeaderThrough()
         {
             if (compilerTool != null)
@@ -326,20 +319,6 @@
             if (obj == null)
                 return pchOption.pchNone;
             return (pchOption)obj;
-        }
-
-        public void SetDebugInformationFormat(debugOption value)
-        {
-            if (compilerTool != null) {
-                compilerTool.DebugInformationFormat = value;
-            } else {
-                compilerType.InvokeMember(
-                    "DebugInformationFormat",
-                    BindingFlags.SetProperty,
-                    null,
-                    compilerObj,
-                    new object[] { value });
-            }
         }
 
         public runtimeLibraryOption RuntimeLibrary
@@ -364,62 +343,6 @@
                 } else {
                     compilerTool.RuntimeLibrary = value;
                 }
-            }
-        }
-
-        public void SetOptimization(optimizeOption value)
-        {
-            if (compilerTool != null) {
-                compilerTool.Optimization = value;
-            } else {
-                compilerType.InvokeMember(
-                    "Optimization",
-                    BindingFlags.SetProperty,
-                    null,
-                    compilerObj,
-                    new object[] { value });
-            }
-        }
-
-        public void SetTreatWChar_tAsBuiltInType(bool value)
-        {
-            if (compilerTool != null) {
-                compilerTool.TreatWChar_tAsBuiltInType = value;
-            } else {
-                compilerType.InvokeMember(
-                    "TreatWChar_tAsBuiltInType",
-                    BindingFlags.SetProperty,
-                    null,
-                    compilerObj,
-                    new object[] { value });
-            }
-        }
-
-        public void SetPrecompiledHeaderFile(string file)
-        {
-            if (compilerTool != null) {
-                compilerTool.PrecompiledHeaderFile = file;
-            } else {
-                compilerType.InvokeMember(
-                    "PrecompiledHeaderFile",
-                    BindingFlags.SetProperty,
-                    null,
-                    compilerObj,
-                    new object[] { file });
-            }
-        }
-
-        public void SetPrecompiledHeaderThrough(string value)
-        {
-            if (compilerTool != null) {
-                compilerTool.PrecompiledHeaderThrough = value;
-            } else {
-                compilerType.InvokeMember(
-                    "PrecompiledHeaderThrough",
-                    BindingFlags.SetProperty,
-                    null,
-                    compilerObj,
-                    new object[] { value });
             }
         }
 
diff --git a/QtVsTools.Core/CxxStreamReader.cs b/QtVsTools.Core/CxxStreamReader.cs
index eb758eb..b3a6394 100644
--- a/QtVsTools.Core/CxxStreamReader.cs
+++ b/QtVsTools.Core/CxxStreamReader.cs
@@ -42,12 +42,12 @@
             Normal, Comment, String
         }
         private State state = State.Normal;
-        private StreamReader sr;
+        private readonly StreamReader sr;
         private string partialLine;
         bool disposed;
 
         int _lineNum;
-        string[] _lines;
+        readonly string[] _lines;
 
         public CxxStreamReader(string[] lines)
         {
diff --git a/QtVsTools.Core/ExportProjectDialog.cs b/QtVsTools.Core/ExportProjectDialog.cs
index 13aea35..2c5d3ad 100644
--- a/QtVsTools.Core/ExportProjectDialog.cs
+++ b/QtVsTools.Core/ExportProjectDialog.cs
@@ -68,11 +68,7 @@
             optionTextBox.Text = "";
             openCheckBox.Text = SR.GetString("ExportProjectDialog_Open");
             createPriFileCheckBox.Text = SR.GetString("ExportProjectDialog_CreatePri");
-
-            if (SR.LanguageName == "de")
-                Size = new Size(470, 300);
-            else
-                Size = new Size(400, 300);
+            Size = new Size(400, 300);
 
             ShowInTaskbar = false;
             Shown += ExportProjectDialog_Shown;
diff --git a/QtVsTools.Core/Extensions.cs b/QtVsTools.Core/Extensions.cs
index 4f14aa6..dee20a0 100644
--- a/QtVsTools.Core/Extensions.cs
+++ b/QtVsTools.Core/Extensions.cs
@@ -32,15 +32,6 @@
 {
     public static class Extensions
     {
-        public static string Quoute(this string input)
-        {
-            if (!input.StartsWith("\"", StringComparison.Ordinal))
-                input = "\"" + input;
-            if (!input.EndsWith("\"", StringComparison.Ordinal))
-                input += "\"";
-            return input;
-        }
-
         public static string Replace(this string original, string oldValue, string newValue,
             StringComparison comparison)
         {
diff --git a/QtVsTools.Core/FakeFilter.cs b/QtVsTools.Core/FakeFilter.cs
index 8851174..a557d09 100644
--- a/QtVsTools.Core/FakeFilter.cs
+++ b/QtVsTools.Core/FakeFilter.cs
@@ -34,11 +34,6 @@
         public string Filter { get; set; }
         public string UniqueIdentifier { get; set; }
 
-        private bool parseFiles = true;
-        public bool ParseFiles
-        {
-            get { return parseFiles; }
-            set { parseFiles = value; }
-        }
+        public bool ParseFiles { get; set; } = true;
     }
 }
diff --git a/QtVsTools.Core/Filters.cs b/QtVsTools.Core/Filters.cs
index ab55d55..7746152 100644
--- a/QtVsTools.Core/Filters.cs
+++ b/QtVsTools.Core/Filters.cs
@@ -71,17 +71,6 @@
             };
         }
 
-        public static FakeFilter TranslationFiles()
-        {
-            return new FakeFilter
-            {
-                UniqueIdentifier = "{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}",
-                Name = SR.GetString("Resources_TranslationFiles"),
-                Filter = "ts",
-                ParseFiles = false
-            };
-        }
-
         public static FakeFilter GeneratedFiles()
         {
             return new FakeFilter
@@ -89,16 +78,6 @@
                 UniqueIdentifier = "{71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}",
                 Name = SR.GetString("Resources_GeneratedFiles"),
                 Filter = "moc;h;cpp",
-            };
-        }
-
-        public static FakeFilter OtherFiles()
-        {
-            return new FakeFilter
-            {
-                UniqueIdentifier = "{B67473BF-9FA1-4674-831E-CB28F72D4791}",
-                Name = SR.GetString("Resources_OtherFiles"),
-                Filter = "*",
             };
         }
     }
diff --git a/QtVsTools.Core/HelperFunctions.cs b/QtVsTools.Core/HelperFunctions.cs
index b6fe0ff..a07fa89 100644
--- a/QtVsTools.Core/HelperFunctions.cs
+++ b/QtVsTools.Core/HelperFunctions.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -26,10 +26,6 @@
 **
 ****************************************************************************/
 
-using EnvDTE;
-using Microsoft.VisualStudio.VCProjectEngine;
-using Microsoft.Win32;
-using QtVsTools.Core.QtMsBuild;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
@@ -40,105 +36,31 @@
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Windows.Forms;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.VCProjectEngine;
+#if VS2017
+using Microsoft.Win32;
+#endif
+using EnvDTE;
 
 using Process = System.Diagnostics.Process;
 
 namespace QtVsTools.Core
 {
+    using QtMsBuild;
+
     public static class HelperFunctions
     {
-        public static string FindQtDirWithTools(Project project)
-        {
-            var versionManager = QtVersionManager.The();
-            string projectQtVersion = null;
-            if (IsQtProject(project))
-                projectQtVersion = versionManager.GetProjectQtVersion(project);
-            return FindQtDirWithTools(projectQtVersion);
-        }
-
-        public static string FindQtDirWithTools(string projectQtVersion)
-        {
-            string tool = null;
-            return FindQtDirWithTools(tool, projectQtVersion);
-        }
-
-        public static string FindQtDirWithTools(string tool, string projectQtVersion)
-        {
-            if (!string.IsNullOrEmpty(tool)) {
-                if (!tool.StartsWith("\\bin\\", StringComparison.OrdinalIgnoreCase))
-                    tool = "\\bin\\" + tool;
-                if (!tool.EndsWith(".exe", StringComparison.OrdinalIgnoreCase))
-                    tool += ".exe";
-            }
-
-            var versionManager = QtVersionManager.The();
-            string qtDir = null;
-            if (projectQtVersion != null)
-                qtDir = versionManager.GetInstallPath(projectQtVersion);
-
-            if (qtDir == null)
-                qtDir = Environment.GetEnvironmentVariable("QTDIR");
-
-            var found = false;
-            if (tool == null) {
-                found = File.Exists(qtDir + "\\bin\\designer.exe")
-                    && File.Exists(qtDir + "\\bin\\linguist.exe");
-            } else {
-                found = File.Exists(qtDir + tool);
-            }
-            if (!found) {
-                VersionInformation exactlyMatchingVersion = null;
-                VersionInformation matchingVersion = null;
-                VersionInformation somehowMatchingVersion = null;
-                var viProjectQtVersion = versionManager.GetVersionInfo(projectQtVersion);
-                foreach (var qtVersion in versionManager.GetVersions()) {
-                    var vi = versionManager.GetVersionInfo(qtVersion);
-                    if (tool == null) {
-                        found = File.Exists(vi.qtDir + "\\bin\\designer.exe")
-                            && File.Exists(vi.qtDir + "\\bin\\linguist.exe");
-                    } else {
-                        found = File.Exists(vi.qtDir + tool);
-                    }
-                    if (!found)
-                        continue;
-
-                    if (viProjectQtVersion != null
-                        && vi.qtMajor == viProjectQtVersion.qtMajor
-                        && vi.qtMinor == viProjectQtVersion.qtMinor) {
-                        exactlyMatchingVersion = vi;
-                        break;
-                    }
-                    if (matchingVersion == null
-                        && viProjectQtVersion != null
-                        && vi.qtMajor == viProjectQtVersion.qtMajor) {
-                        matchingVersion = vi;
-                    }
-                    if (somehowMatchingVersion == null)
-                        somehowMatchingVersion = vi;
-                }
-
-                if (exactlyMatchingVersion != null)
-                    qtDir = exactlyMatchingVersion.qtDir;
-                else if (matchingVersion != null)
-                    qtDir = matchingVersion.qtDir;
-                else if (somehowMatchingVersion != null)
-                    qtDir = somehowMatchingVersion.qtDir;
-                else
-                    qtDir = null;
-            }
-            return qtDir;
-        }
-
         static readonly HashSet<string> _sources = new HashSet<string>(new[] { ".c", ".cpp", ".cxx" },
             StringComparer.OrdinalIgnoreCase);
-        static public bool IsSourceFile(string fileName)
+        public static bool IsSourceFile(string fileName)
         {
             return _sources.Contains(Path.GetExtension(fileName));
         }
 
         static readonly HashSet<string> _headers = new HashSet<string>(new[] { ".h", ".hpp", ".hxx" },
             StringComparer.OrdinalIgnoreCase);
-        static public bool IsHeaderFile(string fileName)
+        public static bool IsHeaderFile(string fileName)
         {
             return _headers.Contains(Path.GetExtension(fileName));
         }
@@ -173,23 +95,28 @@
             return ".qml".Equals(Path.GetExtension(fileName), StringComparison.OrdinalIgnoreCase);
         }
 
-        static public void SetDebuggingEnvironment(Project prj)
+        public static void SetDebuggingEnvironment(Project prj)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
             SetDebuggingEnvironment(prj, string.Empty);
         }
 
-        static public void SetDebuggingEnvironment(Project prj, string solutionConfig)
+        public static void SetDebuggingEnvironment(Project prj, string solutionConfig)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
             SetDebuggingEnvironment(prj, "PATH=$(QTDIR)\\bin;$(PATH)", false, solutionConfig);
         }
 
-        static public void SetDebuggingEnvironment(Project prj, string envpath, bool overwrite)
+        public static void SetDebuggingEnvironment(Project prj, string envpath, bool overwrite)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
             SetDebuggingEnvironment(prj, envpath, overwrite, string.Empty);
         }
 
-        static public void SetDebuggingEnvironment(Project prj, string envpath, bool overwrite, string solutionConfig)
+        public static void SetDebuggingEnvironment(Project prj, string envpath, bool overwrite, string solutionConfig)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (QtProject.GetFormatVersion(prj) >= Resources.qtMinFormatVersion_Settings)
                 return;
 
@@ -252,28 +179,29 @@
             }
         }
 
-        public static bool IsProjectInSolution(DTE dteObject, string fullName)
+        public static Project ProjectFromSolution(DTE dteObject, string fullName)
         {
-            var fi = new FileInfo(fullName);
+            ThreadHelper.ThrowIfNotOnUIThread();
 
+            fullName = new FileInfo(fullName).FullName;
             foreach (var p in ProjectsInSolution(dteObject)) {
-                if (p.FullName.ToLower() == fi.FullName.ToLower())
-                    return true;
+                if (p.FullName.Equals(fullName, StringComparison.OrdinalIgnoreCase))
+                    return p;
             }
-            return false;
+            return null;
         }
 
         /// <summary>
         /// Returns the normalized file path of a given file.
         /// </summary>
         /// <param name="name">file name</param>
-        static public string NormalizeFilePath(string name)
+        public static string NormalizeFilePath(string name)
         {
             var fi = new FileInfo(name);
             return fi.FullName;
         }
 
-        static public string NormalizeRelativeFilePath(string path)
+        public static string NormalizeRelativeFilePath(string path)
         {
             if (path == null)
                 return ".\\";
@@ -299,7 +227,7 @@
             return path;
         }
 
-        static public bool IsAbsoluteFilePath(string path)
+        public static bool IsAbsoluteFilePath(string path)
         {
             path = path.Trim();
             if (path.Length >= 2 && path[1] == ':')
@@ -316,7 +244,7 @@
         /// </summary>
         /// <param name="streamReader"></param>
         /// <returns>the composite string</returns>
-        static private string ReadProFileLine(StreamReader streamReader)
+        private static string ReadProFileLine(StreamReader streamReader)
         {
             var line = streamReader.ReadLine();
             if (line == null)
@@ -337,7 +265,7 @@
         /// </summary>
         /// <param name="profile">full name of .pro file to read</param>
         /// <returns>true if this is a subdirs file</returns>
-        static public bool IsSubDirsFile(string profile)
+        public static bool IsSubDirsFile(string profile)
         {
             StreamReader sr = null;
             try {
@@ -407,55 +335,6 @@
         }
 
         /// <summary>
-        /// Replaces a string in the commandLine, description, outputs and additional dependencies
-        /// in all Custom build tools of the project
-        /// </summary>
-        /// <param name="project">Project</param>
-        /// <param name="oldString">String, which is going to be replaced</param>
-        /// <param name="oldString">String, which is going to replace the other one</param>
-        /// <returns></returns>
-        public static void ReplaceInCustomBuildTools(Project project, string oldString, string replaceString)
-        {
-            var vcPro = (VCProject)project.Object;
-            if (vcPro == null)
-                return;
-
-            var qtMsBuild = new QtMsBuildContainer(new VCPropertyStorageProvider());
-            qtMsBuild.BeginSetItemProperties();
-            foreach (VCFile vcfile in (IVCCollection)vcPro.Files) {
-                foreach (VCFileConfiguration config in (IVCCollection)vcfile.FileConfigurations) {
-                    try {
-                        if (vcfile.ItemType == "CustomBuild") {
-                            var tool = GetCustomBuildTool(config);
-                            if (tool == null)
-                                continue;
-
-                            tool.CommandLine = tool.CommandLine
-                                .Replace(oldString, replaceString,
-                                StringComparison.OrdinalIgnoreCase);
-                            tool.Description = tool.Description
-                                .Replace(oldString, replaceString,
-                                StringComparison.OrdinalIgnoreCase);
-                            tool.Outputs = tool.Outputs
-                                .Replace(oldString, replaceString,
-                                StringComparison.OrdinalIgnoreCase);
-                            tool.AdditionalDependencies = tool.AdditionalDependencies
-                                .Replace(oldString, replaceString,
-                                StringComparison.OrdinalIgnoreCase);
-                        } else {
-                            var tool = new QtCustomBuildTool(config, qtMsBuild);
-                            tool.CommandLine = tool.CommandLine
-                                .Replace(oldString, replaceString,
-                                StringComparison.OrdinalIgnoreCase);
-                        }
-                    } catch (Exception) {
-                    }
-                }
-            }
-            qtMsBuild.EndSetItemProperties();
-        }
-
-        /// <summary>
         /// Since VS2010 it is possible to have VCCustomBuildTools without commandlines
         /// for certain filetypes. We are not interested in them and thus try to read the
         /// tool's commandline. If this causes an exception, we ignore it.
@@ -463,23 +342,19 @@
         /// </summary>
         /// <param name="config">File configuration</param>
         /// <returns></returns>
-        static public VCCustomBuildTool GetCustomBuildTool(VCFileConfiguration config)
+        public static VCCustomBuildTool GetCustomBuildTool(VCFileConfiguration config)
         {
-            var file = config.File as VCFile;
-            if (file == null || file.ItemType != "CustomBuild")
-                return null;
-
-            var tool = config.Tool as VCCustomBuildTool;
-            if (tool == null)
-                return null;
-
-            try {
-                // TODO: The return value is not used at all?
-                var cmdLine = tool.CommandLine;
-            } catch {
-                return null;
+            if (config.File is VCFile file
+                && file.ItemType == "CustomBuild"
+                && config.Tool is VCCustomBuildTool tool) {
+                    try {
+                        _ = tool.CommandLine;
+                    } catch {
+                        return null;
+                    }
+                    return tool;
             }
-            return tool;
+            return null;
         }
 
         /// <summary>
@@ -488,8 +363,10 @@
         /// has to be "CustomBuild"
         /// </summary>
         /// <param name="projectItem">Project Item which needs to have custom build tool</param>
-        static public void EnsureCustomBuildToolAvailable(ProjectItem projectItem)
+        public static void EnsureCustomBuildToolAvailable(ProjectItem projectItem)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             foreach (Property prop in projectItem.Properties) {
                 if (prop.Name == "ItemType") {
                     if ((string)prop.Value != "CustomBuild")
@@ -499,169 +376,10 @@
             }
         }
 
-        /// <summary>
-        /// As Qmake -tp vc Adds the full path to the additional dependencies
-        /// we need to do the same when toggling project kind to qmake generated.
-        /// </summary>
-        /// <returns></returns>
-        private static string AddFullPathToAdditionalDependencies(string qtDir, string additionalDependencies)
-        {
-            var returnString = additionalDependencies;
-            returnString =
-                Regex.Replace(returnString, "Qt(\\S+5?)\\.lib", qtDir + "\\lib\\Qt${1}.lib");
-            returnString =
-                Regex.Replace(returnString, "(qtmaind?5?)\\.lib", qtDir + "\\lib\\${1}.lib");
-            returnString =
-                Regex.Replace(returnString, "(enginiod?5?)\\.lib", qtDir + "\\lib\\${1}.lib");
-            return returnString;
-        }
-
-        /// <summary>
-        /// Toggles the kind of a project. If the project is a QMake generated project (qmake -tp vc)
-        /// it is transformed to an Qt VS Tools project and vice versa.
-        /// </summary>
-        /// <param name="project">Project</param>
-        /// <returns></returns>
-        public static void ToggleProjectKind(Project project)
-        {
-            if (QtProject.GetFormatVersion(project) >= Resources.qtMinFormatVersion_Settings)
-                return;
-
-            string qtDir = null;
-            var vcPro = (VCProject)project.Object;
-            if (!IsQMakeProject(project))
-                return;
-            if (IsQtProject(project)) {
-                // TODO: qtPro is never used.
-                var qtPro = QtProject.Create(project);
-                var vm = QtVersionManager.The();
-                qtDir = vm.GetInstallPath(project);
-
-                foreach (var global in (string[])project.Globals.VariableNames) {
-                    if (global.StartsWith("Qt5Version", StringComparison.Ordinal))
-                        project.Globals.set_VariablePersists(global, false);
-                }
-
-                foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
-                    var compiler = CompilerToolWrapper.Create(config);
-                    var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
-                    var librarian = (VCLibrarianTool)((IVCCollection)config.Tools).Item("VCLibrarianTool");
-                    if (compiler != null) {
-                        var additionalIncludes = compiler.GetAdditionalIncludeDirectories();
-                        additionalIncludes = additionalIncludes.Replace("$(QTDIR)", qtDir,
-                            StringComparison.OrdinalIgnoreCase);
-                        compiler.SetAdditionalIncludeDirectories(additionalIncludes);
-                    }
-                    if (linker != null) {
-                        linker.AdditionalLibraryDirectories = linker.AdditionalLibraryDirectories.
-                            Replace("$(QTDIR)", qtDir, StringComparison.OrdinalIgnoreCase);
-                        linker.AdditionalDependencies = AddFullPathToAdditionalDependencies(qtDir, linker.AdditionalDependencies);
-                    } else {
-                        librarian.AdditionalLibraryDirectories = librarian.AdditionalLibraryDirectories
-                            .Replace("$(QTDIR)", qtDir, StringComparison.OrdinalIgnoreCase);
-                        librarian.AdditionalDependencies = AddFullPathToAdditionalDependencies(qtDir, librarian.AdditionalDependencies);
-                    }
-                }
-
-                ReplaceInCustomBuildTools(project, "$(QTDIR)", qtDir);
-            } else {
-                qtDir = GetQtDirFromQMakeProject(project);
-
-                var vm = QtVersionManager.The();
-                var qtVersion = vm.GetQtVersionFromInstallDir(qtDir);
-                if (qtVersion == null)
-                    qtVersion = vm.GetDefaultVersion();
-                if (qtDir == null)
-                    qtDir = vm.GetInstallPath(qtVersion);
-                var vi = vm.GetVersionInfo(qtVersion);
-                var platformName = vi.GetVSPlatformName();
-                vm.SaveProjectQtVersion(project, qtVersion, platformName);
-                var qtPro = QtProject.Create(project);
-                if (!qtPro.SelectSolutionPlatform(platformName) || !qtPro.HasPlatform(platformName)) {
-                    var newProject = false;
-                    qtPro.CreatePlatform("Win32", platformName, null, vi, ref newProject);
-                    if (!qtPro.SelectSolutionPlatform(platformName))
-                        Messages.Print("Can't select the platform " + platformName + ".");
-                }
-
-                var activeConfig = project.ConfigurationManager.ActiveConfiguration.ConfigurationName;
-                var activeVCConfig = (VCConfiguration)((IVCCollection)qtPro.VCProject.Configurations).Item(activeConfig);
-                if (activeVCConfig.ConfigurationType == ConfigurationTypes.typeDynamicLibrary) {
-                    var compiler = CompilerToolWrapper.Create(activeVCConfig);
-                    var linker = (VCLinkerTool)((IVCCollection)activeVCConfig.Tools).Item("VCLinkerTool");
-                    var ppdefs = compiler.GetPreprocessorDefinitions();
-                    if (ppdefs != null
-                        && ppdefs.IndexOf("QT_PLUGIN", StringComparison.Ordinal) > -1
-                        && ppdefs.IndexOf("QDESIGNER_EXPORT_WIDGETS", StringComparison.Ordinal) > -1
-                        && ppdefs.IndexOf("QtDesigner", StringComparison.Ordinal) > -1
-                        && linker.AdditionalDependencies != null
-                        && linker.AdditionalDependencies.IndexOf("QtDesigner", StringComparison.Ordinal) > -1) {
-                        qtPro.MarkAsDesignerPluginProject();
-                    }
-                }
-
-                CleanupQMakeDependencies(project);
-
-                foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
-                    var compiler = CompilerToolWrapper.Create(config);
-                    var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
-
-                    if (compiler != null) {
-                        var additionalIncludes = compiler.AdditionalIncludeDirectories;
-                        if (additionalIncludes != null) {
-                            ReplaceDirectory(ref additionalIncludes, qtDir, "$(QTDIR)", project);
-                            compiler.AdditionalIncludeDirectories = additionalIncludes;
-                        }
-                    }
-                    if (linker != null) {
-                        var linkerToolWrapper = new LinkerToolWrapper(linker);
-                        var paths = linkerToolWrapper.AdditionalLibraryDirectories;
-                        if (paths != null) {
-                            ReplaceDirectory(ref paths, qtDir, "$(QTDIR)", project);
-                            linkerToolWrapper.AdditionalLibraryDirectories = paths;
-                        }
-                    }
-                }
-
-                ReplaceInCustomBuildTools(project, qtDir, "$(QTDIR)");
-                qtPro.TranslateFilterNames();
-            }
-            project.Save(project.FullName);
-        }
-
-        /// <summary>
-        /// Replaces every occurrence of oldDirectory with replacement in the array of strings.
-        /// Parameter oldDirectory must be an absolute path.
-        /// This function converts relative directories to absolute paths internally
-        /// and replaces them, if necessary. If no replacement is done, the path isn't altered.
-        /// </summary>
-        /// <param name="project">The project is needed to convert relative paths to absolute paths.</param>
-        private static void ReplaceDirectory(ref List<string> paths, string oldDirectory, string replacement, Project project)
-        {
-            for (var i = 0; i < paths.Count; ++i) {
-                var dirName = paths[i];
-                if (dirName.StartsWith("\"", StringComparison.Ordinal) && dirName.EndsWith("\"", StringComparison.Ordinal)) {
-                    dirName = dirName.Substring(1, dirName.Length - 2);
-                }
-                if (!Path.IsPathRooted(dirName)) {
-                    // convert to absolute path
-                    dirName = Path.Combine(Path.GetDirectoryName(project.FullName), dirName);
-                    dirName = Path.GetFullPath(dirName);
-                    var alteredDirName = dirName.Replace(oldDirectory, replacement, StringComparison
-                        .OrdinalIgnoreCase);
-                    if (alteredDirName == dirName)
-                        continue;
-                    dirName = alteredDirName;
-                } else {
-                    dirName = dirName.Replace(oldDirectory, replacement, StringComparison
-                        .OrdinalIgnoreCase);
-                }
-                paths[i] = dirName;
-            }
-        }
-
         public static string GetQtDirFromQMakeProject(Project project)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var vcProject = project.Object as VCProject;
             if (vcProject == null)
                 return null;
@@ -742,13 +460,25 @@
         }
 
         /// <summary>
-        /// Return true if the project is a Qt project, otherwise false.
+        /// Return true if the project is a VS tools project; false otherwise.
         /// </summary>
         /// <param name="proj">project</param>
-        /// <returns></returns>
-        public static bool IsQtProject(VCProject proj)
+        public static bool IsVsToolsProject(Project proj)
         {
-            if (!IsQMakeProject(proj))
+            ThreadHelper.ThrowIfNotOnUIThread(); // C++ Project Type GUID
+            if (proj == null || proj.Kind != "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}")
+                return false;
+            return IsVsToolsProject(proj.Object as VCProject);
+        }
+
+        /// <summary>
+        /// Return true if the project is a VS tools project; false otherwise.
+        /// </summary>
+        /// <param name="proj">project</param>
+        public static bool IsVsToolsProject(VCProject proj)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+            if (!IsQtProject(proj))
                 return false;
 
             if (QtProject.GetFormatVersion(proj) >= Resources.qtMinFormatVersion_Settings)
@@ -759,95 +489,39 @@
                 return false;
 
             foreach (var global in envPro.Globals.VariableNames as string[]) {
-                if (global.StartsWith("Qt5Version", StringComparison.Ordinal) && envPro.Globals.get_VariablePersists(global))
+                if (global.StartsWith("Qt5Version", StringComparison.Ordinal)
+                    && envPro.Globals.get_VariablePersists(global)) {
                     return true;
+                }
             }
             return false;
         }
 
         /// <summary>
-        /// Returns true if the specified project is a Qt Project.
+        /// Return true if the project is a Qt project; false otherwise.
         /// </summary>
         /// <param name="proj">project</param>
         public static bool IsQtProject(Project proj)
         {
-            try {
-                if (proj != null && proj.Kind == "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}")
-                    return IsQtProject(proj.Object as VCProject);
-            } catch { }
-            return false;
+            ThreadHelper.ThrowIfNotOnUIThread(); //C++ Project Type GUID
+            if (proj == null || proj.Kind != "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}")
+                return false;
+            return IsQtProject(proj.Object as VCProject);
         }
 
         /// <summary>
-        /// Return true if the project is a QMake -tp vc project, otherwise false.
+        /// Return true if the project is a Qt project; false otherwise.
         /// </summary>
         /// <param name="proj">project</param>
-        /// <returns></returns>
-        public static bool IsQMakeProject(VCProject proj)
+        public static bool IsQtProject(VCProject proj)
         {
             if (proj == null)
                 return false;
             var keyword = proj.keyword;
-            if (keyword == null ||
-                (!keyword.StartsWith(Resources.qtProjectV2Keyword, StringComparison.Ordinal)
-                && !keyword.StartsWith(Resources.qtProjectKeyword, StringComparison.Ordinal))) {
+            if (string.IsNullOrEmpty(keyword))
                 return false;
-            }
-
-            return true;
-        }
-
-        /// <summary>
-        /// Returns true if the specified project is a QMake -tp vc Project.
-        /// </summary>
-        /// <param name="proj">project</param>
-        public static bool IsQMakeProject(Project proj)
-        {
-            try {
-                if (proj != null && proj.Kind == "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}")
-                    return IsQMakeProject(proj.Object as VCProject);
-            } catch { }
-            return false;
-        }
-
-        public static void CleanupQMakeDependencies(Project project)
-        {
-            var vcPro = (VCProject)project.Object;
-            // clean up qmake mess
-            var rxp1 = new Regex("\\bQt\\w+d?5?\\.lib\\b");
-            var rxp2 = new Regex("\\bQAx\\w+\\.lib\\b");
-            var rxp3 = new Regex("\\bqtmaind?.lib\\b");
-            var rxp4 = new Regex("\\benginiod?.lib\\b");
-            foreach (VCConfiguration cfg in (IVCCollection)vcPro.Configurations) {
-                var linker = (VCLinkerTool)((IVCCollection)cfg.Tools).Item("VCLinkerTool");
-                if (linker == null || linker.AdditionalDependencies == null)
-                    continue;
-                var linkerWrapper = new LinkerToolWrapper(linker);
-                var deps = linkerWrapper.AdditionalDependencies;
-                var newDeps = new List<string>();
-                foreach (var lib in deps) {
-                    var m1 = rxp1.Match(lib);
-                    var m2 = rxp2.Match(lib);
-                    var m3 = rxp3.Match(lib);
-                    var m4 = rxp4.Match(lib);
-                    if (m1.Success)
-                        newDeps.Add(m1.ToString());
-                    else if (m2.Success)
-                        newDeps.Add(m2.ToString());
-                    else if (m3.Success)
-                        newDeps.Add(m3.ToString());
-                    else if (m4.Success)
-                        newDeps.Add(m4.ToString());
-                    else
-                        newDeps.Add(lib);
-                }
-                // Remove Duplicates
-                var uniques = new Dictionary<string, int>();
-                foreach (var dep in newDeps)
-                    uniques[dep] = 1;
-                var uniqueList = new List<string>(uniques.Keys);
-                linkerWrapper.AdditionalDependencies = uniqueList;
-            }
+            return keyword.StartsWith(Resources.qtProjectKeyword, StringComparison.Ordinal)
+                || keyword.StartsWith(Resources.qtProjectV2Keyword, StringComparison.Ordinal);
         }
 
         /// <summary>
@@ -951,6 +625,30 @@
             }
         }
 
+        /// <summary>
+        /// Converts all directory separators of the path to the alternate character
+        /// directory separator. For instance, FromNativeSeparators("c:\\winnt\\system32")
+        /// returns "c:/winnt/system32".
+        /// </summary>
+        /// <param name="path">The path to convert.</param>
+        /// <returns>Returns path using '/' as file separator.</returns>
+        public static string FromNativeSeparators(string path)
+        {
+            return path.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
+        }
+
+        /// <summary>
+        /// Converts all alternate directory separators characters of the path to the native
+        /// directory separator. For instance, ToNativeSeparators("c:/winnt/system32")
+        /// returns "c:\\winnt\\system32".
+        /// </summary>
+        /// <param name="path">The path to convert.</param>
+        /// <returns>Returns path using '\' as file separator.</returns>
+        public static string ToNativeSeparator(string path)
+        {
+            return path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
+        }
+
         public static string ChangePathFormat(string path)
         {
             return path.Replace('\\', '/');
@@ -981,6 +679,8 @@
 
         public static void CollapseFilter(UIHierarchyItem item, UIHierarchy hierarchy, string nodeToCollapseFilter)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (string.IsNullOrEmpty(nodeToCollapseFilter))
                 return;
 
@@ -994,6 +694,8 @@
 
         public static void CollapseFilter(UIHierarchyItem item, UIHierarchy hierarchy)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var subItems = item.UIHierarchyItems;
             if (subItems != null) {
                 foreach (UIHierarchyItem innerItem in subItems) {
@@ -1042,7 +744,7 @@
 
         public static List<string> GetProjectFiles(Project pro, FilesToList filter)
         {
-            var fileList = new List<string>();
+            ThreadHelper.ThrowIfNotOnUIThread();
 
             VCProject vcpro;
             try {
@@ -1052,6 +754,7 @@
                 return null;
             }
 
+            var fileList = new List<string>();
             var configurationName = pro.ConfigurationManager.ActiveConfiguration.ConfigurationName;
 
             foreach (VCFile vcfile in (IVCCollection)vcpro.Files) {
@@ -1120,21 +823,24 @@
         /// <param name="fileName"></param>
         public static void RemoveFileInProject(VCProject vcpro, string fileName)
         {
-            var qtProj = QtProject.Create(vcpro);
-            var fi = new FileInfo(fileName);
+            ThreadHelper.ThrowIfNotOnUIThread();
 
+            fileName = new FileInfo(fileName).FullName;
             foreach (VCFile vcfile in (IVCCollection)vcpro.Files) {
-                if (vcfile.FullPath.ToLower() == fi.FullName.ToLower()) {
+                if (vcfile.FullPath.Equals(fileName, StringComparison.OrdinalIgnoreCase)) {
                     vcpro.RemoveFile(vcfile);
-                    qtProj.MoveFileToDeletedFolder(vcfile);
+                    QtProject.Create(vcpro)?.MoveFileToDeletedFolder(vcfile);
                 }
             }
         }
 
         public static Project GetSelectedProject(DTE dteObject)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (dteObject == null)
                 return null;
+
             Array prjs = null;
             try {
                 prjs = (Array)dteObject.ActiveSolutionProjects;
@@ -1146,30 +852,23 @@
                 return null;
 
             // don't handle multiple selection... use the first one
-            if (prjs.GetValue(0) is Project)
-                return (Project)prjs.GetValue(0);
+            if (prjs.GetValue(0) is Project project)
+                return project;
             return null;
         }
 
         public static Project GetActiveDocumentProject(DTE dteObject)
         {
-            if (dteObject == null)
-                return null;
-            var doc = dteObject.ActiveDocument;
-            if (doc == null)
-                return null;
-
-            if (doc.ProjectItem == null)
-                return null;
-
-            return doc.ProjectItem.ContainingProject;
+            ThreadHelper.ThrowIfNotOnUIThread();
+            return dteObject?.ActiveDocument?.ProjectItem?.ContainingProject;
         }
 
         public static Project GetSingleProjectInSolution(DTE dteObject)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var projectList = ProjectsInSolution(dteObject);
-            if (dteObject == null || dteObject.Solution == null ||
-                    projectList.Count != 1)
+            if (projectList.Count != 1)
                 return null; // no way to know which one to select
 
             return projectList[0];
@@ -1182,22 +881,24 @@
         /// </summary>
         public static Project GetSelectedQtProject(DTE dteObject)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             // can happen sometimes shortly after starting VS
-            if (dteObject == null || dteObject.Solution == null
-                || ProjectsInSolution(dteObject).Count == 0)
+            if (ProjectsInSolution(dteObject).Count == 0)
                 return null;
 
-            Project pro;
-
-            if ((pro = GetSelectedProject(dteObject)) == null) {
+            var pro = GetSelectedProject(dteObject);
+            if (pro == null) {
                 if ((pro = GetSingleProjectInSolution(dteObject)) == null)
                     pro = GetActiveDocumentProject(dteObject);
             }
-            return IsQtProject(pro) ? pro : null;
+            return IsVsToolsProject(pro) ? pro : null;
         }
 
         public static VCFile[] GetSelectedFiles(DTE dteObject)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (GetSelectedQtProject(dteObject) == null)
                 return null;
 
@@ -1239,6 +940,8 @@
 
         public static RccOptions ParseRccOptions(string cmdLine, VCFile qrcFile)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var pro = VCProjectToProject((VCProject)qrcFile.project);
 
             var rccOpts = new RccOptions(pro, qrcFile);
@@ -1261,11 +964,17 @@
 
         public static Project VCProjectToProject(VCProject vcproj)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
             return (Project)vcproj.Object;
         }
 
         public static List<Project> ProjectsInSolution(DTE dteObject)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            if (dteObject == null)
+                return new List<Project>();
+
             var projects = new List<Project>();
             var solution = dteObject.Solution;
             if (solution != null) {
@@ -1287,6 +996,8 @@
 
         private static void addSubProjects(Project prj, ref List<Project> projects)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             // If the actual object of the project is null then the project was probably unloaded.
             if (prj.Object == null)
                 return;
@@ -1303,6 +1014,8 @@
 
         private static void addSubProjects(ProjectItems subItems, ref List<Project> projects)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (subItems == null)
                 return;
 
@@ -1393,21 +1106,6 @@
             return true;
         }
 
-        public static string FindFileInPATH(string fileName)
-        {
-            var envPATH = Environment.ExpandEnvironmentVariables("%PATH%");
-            var directories = envPATH.Split(';');
-            foreach (var directory in directories) {
-                var fullFilePath = directory;
-                if (!fullFilePath.EndsWith("\\", StringComparison.Ordinal))
-                    fullFilePath += '\\';
-                fullFilePath += fileName;
-                if (File.Exists(fullFilePath))
-                    return fullFilePath;
-            }
-            return null;
-        }
-
         /// <summary>
         /// This method copies the specified directory and all its child directories and files to
         /// the specified destination. The destination directory is created if it does not exist.
@@ -1453,13 +1151,14 @@
             string platformName,
             string filePath = null)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (project == null
                 || string.IsNullOrEmpty(configName)
                 || string.IsNullOrEmpty(platformName))
                 return false;
 
             var vcProject = project.Object as VCProject;
-
             if (filePath == null) {
                 var vcConfig = (from VCConfiguration _config
                                 in (IVCCollection)vcProject.Configurations
@@ -1503,12 +1202,10 @@
             VCProject vcProj = null;
             VCFile vcFile = null;
             string configName = "", platformName = "";
-            var vcConfig = config as VCConfiguration;
-            if (vcConfig != null) {
+            if (config is VCConfiguration vcConfig) {
                 vcProj = vcConfig.project as VCProject;
                 configName = vcConfig.ConfigurationName;
-                var vcPlatform = vcConfig.Platform as VCPlatform;
-                if (vcPlatform != null)
+                if (vcConfig.Platform is VCPlatform vcPlatform)
                     platformName = vcPlatform.Name;
                 try {
                     expanded = vcConfig.Evaluate(expanded);
@@ -1520,11 +1217,9 @@
                 vcFile = vcFileConfig.File as VCFile;
                 if (vcFile != null)
                     vcProj = vcFile.project as VCProject;
-                var vcProjConfig = vcFileConfig.ProjectConfiguration as VCConfiguration;
-                if (vcProjConfig != null) {
+                if (vcFileConfig.ProjectConfiguration is VCConfiguration vcProjConfig) {
                     configName = vcProjConfig.ConfigurationName;
-                    var vcPlatform = vcProjConfig.Platform as VCPlatform;
-                    if (vcPlatform != null)
+                    if (vcProjConfig.Platform is VCPlatform vcPlatform)
                         platformName = vcPlatform.Name;
                 }
                 try {
@@ -1637,6 +1332,7 @@
             return true;
         }
 
+#if VS2017
         private static string GetRegistrySoftwareString(string subKeyName, string valueName)
         {
             var keyName = new StringBuilder();
@@ -1644,28 +1340,25 @@
             if (System.Environment.Is64BitOperatingSystem && IntPtr.Size == 4)
                 keyName.Append(@"WOW6432Node\");
             keyName.Append(subKeyName);
-
             try {
                 using (var key = Registry.LocalMachine.OpenSubKey(keyName.ToString(), false)) {
                     if (key == null)
                         return ""; //key not found
-
                     RegistryValueKind valueKind = key.GetValueKind(valueName);
                     if (valueKind != RegistryValueKind.String
                         && valueKind != RegistryValueKind.ExpandString) {
                         return ""; //wrong value kind
                     }
-
                     Object objValue = key.GetValue(valueName);
                     if (objValue == null)
                         return ""; //error getting value
-
                     return objValue.ToString();
                 }
             } catch {
                 return "";
             }
         }
+#endif
 
         public static string GetWindows10SDKVersion()
         {
@@ -1713,11 +1406,6 @@
             string vcPath = Path.Combine(vsPath, "VC");
 #endif
             return vcPath;
-        }
-
-        public static bool SetVCVars(ProcessStartInfo startInfo)
-        {
-            return SetVCVars(null, startInfo);
         }
 
         public static bool SetVCVars(VersionInformation VersionInfo, ProcessStartInfo startInfo)
@@ -1820,8 +1508,21 @@
                     }
                 }
             }
+
+            // Get PATH
             string envPath = startInfo.EnvironmentVariables["PATH"];
-            string clPath = envPath.Split(';')
+
+            // Remove invalid chars
+            envPath = string.Join("", envPath.Split(Path.GetInvalidPathChars()));
+
+            // Split into list of paths
+            var paths = envPath
+                .Split(';')
+                .Where(x => !string.IsNullOrEmpty(x))
+                .Select(x => x.Trim());
+
+            // Check if cl.exe is in PATH
+            string clPath = paths
                 .Select(path => Path.Combine(path, "cl.exe"))
                 .Where(pathToCl => File.Exists(pathToCl))
                 .FirstOrDefault();
@@ -1872,12 +1573,6 @@
             } else {
                 return canonicalPath;
             }
-        }
-
-        public static bool PathEquals(string path1, string path2)
-        {
-            return (CanonicalPath(path1).Equals(CanonicalPath(path2),
-                StringComparison.InvariantCultureIgnoreCase));
         }
 
         public static bool PathIsRelativeTo(string path, string subPath)
diff --git a/QtVsTools.Core/Legacy/QtProject.cs b/QtVsTools.Core/Legacy/QtProject.cs
new file mode 100644
index 0000000..0d02208
--- /dev/null
+++ b/QtVsTools.Core/Legacy/QtProject.cs
@@ -0,0 +1,290 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows.Forms;
+using EnvDTE;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.VCProjectEngine;
+
+namespace QtVsTools.Core.Legacy
+{
+    using Core;
+
+    public static class QtProject
+    {
+        public static void MarkAsDesignerPluginProject(Core.QtProject qtPro)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            qtPro.Project.Globals["IsDesignerPlugin"] = true.ToString();
+            if (!qtPro.Project.Globals.get_VariablePersists("IsDesignerPlugin"))
+                qtPro.Project.Globals.set_VariablePersists("IsDesignerPlugin", true);
+        }
+
+        public static bool PromptChangeQtVersion(Project project, string oldVersion, string newVersion)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            var versionManager = Core.QtVersionManager.The();
+            var viOld = versionManager.GetVersionInfo(oldVersion);
+            var viNew = versionManager.GetVersionInfo(newVersion);
+
+            if (viOld == null || viNew == null)
+                return true;
+
+            var oldIsWinRt = viOld.isWinRT();
+            var newIsWinRt = viNew.isWinRT();
+
+            if (newIsWinRt == oldIsWinRt || newIsWinRt == IsWinRT(project))
+                return true;
+
+            var caption = string.Format("Change Qt Version ({0})", project.Name);
+            var text = string.Format(
+                "Changing Qt version from {0} to {1}.\r\n" +
+                "Project might not build. Are you sure?",
+                newIsWinRt ? "Win32" : "WinRT",
+                newIsWinRt ? "WinRT" : "Win32"
+            );
+
+            return MessageBox.Show(text, caption, MessageBoxButtons.YesNo, MessageBoxIcon.Warning)
+                == DialogResult.Yes;
+        }
+
+        public static bool HasModule(Project project, int id, string qtVersion = null)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            var foundInIncludes = false;
+            var foundInLibs = false;
+
+            var vm = Core.QtVersionManager.The();
+            var versionInfo = qtVersion != null ? vm.GetVersionInfo(qtVersion)
+                : vm.GetVersionInfo(project);
+            if (versionInfo == null)
+                versionInfo = vm.GetVersionInfo(vm.GetDefaultVersion());
+            if (versionInfo == null)
+                return false; // neither a default or project Qt version
+            var info = QtModules.Instance.Module(id, versionInfo.qtMajor);
+            if (info == null)
+                return false;
+
+            var vcPro = project.Object as VCProject;
+            foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
+                var compiler = CompilerToolWrapper.Create(config);
+                var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
+
+                if (compiler != null) {
+                    if (compiler.GetAdditionalIncludeDirectories() == null)
+                        continue;
+                    var incPathList = info.GetIncludePath();
+                    var includeDirs = compiler.GetAdditionalIncludeDirectoriesList();
+                    foundInIncludes = (incPathList.Count > 0);
+                    foreach (var incPath in incPathList) {
+                        var fixedIncludeDir = FixFilePathForComparison(incPath);
+                        if (!includeDirs.Any(dir =>
+                            FixFilePathForComparison(dir) == fixedIncludeDir)) {
+                            foundInIncludes = false;
+                            break;
+                        }
+                    }
+                }
+
+                if (foundInIncludes)
+                    break;
+
+                List<string> libs = null;
+                if (linker != null) {
+                    var linkerWrapper = new LinkerToolWrapper(linker);
+                    libs = linkerWrapper.AdditionalDependencies;
+                }
+
+                if (libs != null) {
+                    var moduleLibs = info.GetLibs(IsDebugConfiguration(config), versionInfo);
+                    foundInLibs = moduleLibs.All(moduleLib => libs.Contains(moduleLib));
+                }
+            }
+            return foundInIncludes || foundInLibs;
+        }
+
+        public static void AddModule(Project project, int id)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            if (HasModule(project, id))
+                return;
+
+            var vm = Core.QtVersionManager.The();
+            var versionInfo = vm.GetVersionInfo(project);
+            if (versionInfo == null)
+                versionInfo = vm.GetVersionInfo(vm.GetDefaultVersion());
+
+            var vcPro = project.Object as VCProject;
+            foreach (VCConfiguration config in vcPro.Configurations as IVCCollection) {
+
+                var info = QtModules.Instance.Module(id, versionInfo.qtMajor);
+                if (Core.QtProject.GetFormatVersion(project) >= Resources.qtMinFormatVersion_Settings) {
+                    var config3 = config as VCConfiguration3;
+                    if (config3 == null)
+                        continue;
+                    if (!string.IsNullOrEmpty(info.proVarQT)) {
+                        var qtModulesValue = config.GetUnevaluatedPropertyValue("QtModules");
+                        var qtModules = new HashSet<string>(
+                            !string.IsNullOrEmpty(qtModulesValue)
+                                ? qtModulesValue.Split(';')
+                                : new string[] { });
+                        qtModules.UnionWith(info.proVarQT.Split(' '));
+                        config3.SetPropertyValue(Resources.projLabelQtSettings, true,
+                            "QtModules", string.Join(";", qtModules));
+                    }
+                    // In V3 project format, compiler and linker options
+                    // required by modules are set by Qt/MSBuild.
+                    continue;
+                }
+
+                var compiler = CompilerToolWrapper.Create(config);
+                var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
+
+                if (compiler != null) {
+                    foreach (var define in info.Defines)
+                        compiler.AddPreprocessorDefinition(define);
+
+                    var incPathList = info.GetIncludePath();
+                    foreach (var incPath in incPathList)
+                        compiler.AddAdditionalIncludeDirectories(incPath);
+                }
+                if (linker != null) {
+                    var moduleLibs = info.GetLibs(IsDebugConfiguration(config), versionInfo);
+                    var linkerWrapper = new LinkerToolWrapper(linker);
+                    var additionalDeps = linkerWrapper.AdditionalDependencies;
+                    var dependenciesChanged = false;
+                    if (additionalDeps == null || additionalDeps.Count == 0) {
+                        additionalDeps = moduleLibs;
+                        dependenciesChanged = true;
+                    } else {
+                        foreach (var moduleLib in moduleLibs) {
+                            if (!additionalDeps.Contains(moduleLib)) {
+                                additionalDeps.Add(moduleLib);
+                                dependenciesChanged = true;
+                            }
+                        }
+                    }
+                    if (dependenciesChanged)
+                        linkerWrapper.AdditionalDependencies = additionalDeps;
+                }
+            }
+        }
+
+        public static void RemoveModule(Project project, int id)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            var vm = Core.QtVersionManager.The();
+            var versionInfo = vm.GetVersionInfo(project);
+            if (versionInfo == null)
+                versionInfo = vm.GetVersionInfo(vm.GetDefaultVersion());
+
+            var vcPro = project.Object as VCProject;
+            foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
+                var compiler = CompilerToolWrapper.Create(config);
+                var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
+
+                var info = QtModules.Instance.Module(id, versionInfo.qtMajor);
+                if (compiler != null) {
+                    foreach (var define in info.Defines)
+                        compiler.RemovePreprocessorDefinition(define);
+                    var additionalIncludeDirs = compiler.AdditionalIncludeDirectories;
+                    if (additionalIncludeDirs != null) {
+                        var lst = new List<string>(additionalIncludeDirs);
+                        foreach (var includePath in info.IncludePath) {
+                            lst.Remove(includePath);
+                            lst.Remove('\"' + includePath + '\"');
+                        }
+                        compiler.AdditionalIncludeDirectories = lst;
+                    }
+                }
+                if (linker != null && linker.AdditionalDependencies != null) {
+                    var linkerWrapper = new LinkerToolWrapper(linker);
+                    var moduleLibs = info.GetLibs(IsDebugConfiguration(config), versionInfo);
+                    var additionalDependencies = linkerWrapper.AdditionalDependencies;
+                    var dependenciesChanged = false;
+                    foreach (var moduleLib in moduleLibs)
+                        dependenciesChanged |= additionalDependencies.Remove(moduleLib);
+                    if (dependenciesChanged)
+                        linkerWrapper.AdditionalDependencies = additionalDependencies;
+                }
+            }
+        }
+        
+        internal static bool IsDesignerPluginProject(Core.QtProject qtPro)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            var b = false;
+            if (qtPro.Project.Globals.get_VariablePersists("IsDesignerPlugin")) {
+                var s = qtPro.Project.Globals["IsDesignerPlugin"] as string;
+                try {
+                    b = bool.Parse(s);
+                } catch { }
+            }
+            return b;
+        }
+
+
+        private static bool IsWinRT(Project project)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            try {
+                var vcProject = project.Object as VCProject;
+                var vcConfigs = vcProject.Configurations as IVCCollection;
+                var vcConfig = vcConfigs.Item(1) as VCConfiguration;
+                var appType = vcConfig.GetEvaluatedPropertyValue("ApplicationType");
+                if (appType == "Windows Store")
+                    return true;
+            } catch { }
+            return false;
+        }
+
+        private static string FixFilePathForComparison(string path)
+        {
+            return HelperFunctions.NormalizeRelativeFilePath(path).ToLower();
+        }
+
+        private static bool IsDebugConfiguration(VCConfiguration conf)
+        {
+            var tool = CompilerToolWrapper.Create(conf);
+            if (tool != null) {
+                return tool.RuntimeLibrary == runtimeLibraryOption.rtMultiThreadedDebug
+                    || tool.RuntimeLibrary == runtimeLibraryOption.rtMultiThreadedDebugDLL;
+            }
+            return false;
+        }
+    }
+}
diff --git a/QtVsTools.Core/Legacy/QtVSIPSettings.cs b/QtVsTools.Core/Legacy/QtVSIPSettings.cs
new file mode 100644
index 0000000..b54940d
--- /dev/null
+++ b/QtVsTools.Core/Legacy/QtVSIPSettings.cs
@@ -0,0 +1,226 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using Microsoft.VisualStudio.Shell;
+using QtVsTools.Common;
+
+namespace QtVsTools.Core.Legacy
+{
+    public static class QtVSIPSettings
+    {
+        #region UIC
+
+        public static string GetUicDirectory(EnvDTE.Project project)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+            return QtVSIPSettingsShared.GetDirectory(project, Resources.uicDirKeyword);
+        }
+
+        public static void SaveUicDirectory(EnvDTE.Project project, string directory)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            if (directory == null)
+                directory = QtVSIPSettingsShared.GetDirectory(project, Resources.uicDirKeyword);
+            SaveDirectory(project, Resources.uicDirKeyword, directory);
+        }
+        #endregion
+
+        #region MOC
+
+        public static string GetMocDirectory(EnvDTE.Project project)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+            return QtVSIPSettingsShared.GetDirectory(project, Resources.mocDirKeyword);
+        }
+
+        public static void SaveMocDirectory(EnvDTE.Project project, string directory)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            if (directory == null)
+                directory = QtVSIPSettingsShared.GetDirectory(project, Resources.mocDirKeyword);
+            SaveDirectory(project, Resources.mocDirKeyword, directory);
+        }
+
+        public static string GetMocOptions()
+        {
+            return QtVSIPSettingsShared.GetOption(Resources.mocOptionsKeyword);
+        }
+
+        public static string GetMocOptions(EnvDTE.Project project)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+            return QtVSIPSettingsShared.GetOption(project, Resources.mocOptionsKeyword);
+        }
+
+        public static void SaveMocOptions(EnvDTE.Project project, string options)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            if (options == null)
+                options = GetMocOptions();
+
+            SaveOption(project, Resources.mocOptionsKeyword, options);
+        }
+        #endregion
+
+        #region LUpdate
+
+        public static bool GetLUpdateOnBuild(EnvDTE.Project project)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            if (QtVSIPSettingsShared.GetProjectQtSetting(project, "QtRunLUpdateOnBuild") == "true")
+                return true;
+            return QtVSIPSettingsShared.GetBoolValue(project, Resources.lupdateKeyword);
+        }
+
+        public static void SaveLUpdateOnBuild(EnvDTE.Project project, bool value)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+            SetBoolValue(project, Resources.lupdateKeyword, value);
+        }
+
+        public static string GetLUpdateOptions()
+        {
+            return QtVSIPSettingsShared.GetOption(Resources.lupdateOptionsKeyword);
+        }
+
+        public static string GetLUpdateOptions(EnvDTE.Project project)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            string qtLUpdateOptions = QtVSIPSettingsShared.GetProjectQtSetting(project, "QtLUpdateOptions");
+            if (!string.IsNullOrEmpty(qtLUpdateOptions))
+                return qtLUpdateOptions;
+            return QtVSIPSettingsShared.GetOption(project, Resources.lupdateOptionsKeyword);
+        }
+
+        public static void SaveLUpdateOptions(EnvDTE.Project project, string options)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            if (options == null)
+                options = GetLUpdateOptions();
+
+            SaveOption(project, Resources.lupdateOptionsKeyword, options);
+        }
+        #endregion
+
+        #region LRelease
+
+        public static string GetLReleaseOptions()
+        {
+            return QtVSIPSettingsShared.GetOption(Resources.lreleaseOptionsKeyword);
+        }
+
+        public static string GetLReleaseOptions(EnvDTE.Project project)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            string qtLReleaseOptions = QtVSIPSettingsShared.GetProjectQtSetting(project, "QtLReleaseOptions");
+            if (!string.IsNullOrEmpty(qtLReleaseOptions))
+                return qtLReleaseOptions;
+            return QtVSIPSettingsShared.GetOption(project, Resources.lreleaseOptionsKeyword);
+        }
+
+        public static void SaveLReleaseOptions(EnvDTE.Project project, string options)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            if (options == null)
+                options = GetLReleaseOptions();
+
+            SaveOption(project, Resources.lreleaseOptionsKeyword, options);
+        }
+        #endregion
+
+        #region RCC
+
+        public static string GetRccDirectory(EnvDTE.Project project)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+            return QtVSIPSettingsShared.GetDirectory(project, Resources.rccDirKeyword);
+        }
+
+        public static void SaveRccDirectory(EnvDTE.Project project, string directory)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            if (directory == null)
+                directory = QtVSIPSettingsShared.GetDirectory(project, Resources.rccDirKeyword);
+            SaveDirectory(project, Resources.rccDirKeyword, directory);
+        }
+        #endregion
+
+        #region QML
+
+        public static bool GetQmlDebug(EnvDTE.Project project)
+        {
+            return Core.QtProject.Create(project).QmlDebug;
+        }
+
+        public static void SaveQmlDebug(EnvDTE.Project project, bool enabled)
+        {
+            Core.QtProject.Create(project).QmlDebug = enabled;
+        }
+        #endregion
+
+        private static void SaveDirectory(EnvDTE.Project project, string type, string dir)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            dir = HelperFunctions.NormalizeRelativeFilePath(dir);
+            project.Globals[type] = dir;
+            if (!project.Globals.get_VariablePersists(type))
+                project.Globals.set_VariablePersists(type, true);
+
+            QtVSIPSettingsShared.CleanUpCache(project);
+        }
+
+        private static void SaveOption(EnvDTE.Project project, string type, string option)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            project.Globals[type] = option;
+            if (!project.Globals.get_VariablePersists(type))
+                project.Globals.set_VariablePersists(type, true);
+        }
+
+        private static void SetBoolValue(EnvDTE.Project project, string type, bool value)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            project.Globals[type] = Convert.ToInt32(value).ToString();
+            if (!project.Globals.get_VariablePersists(type))
+                project.Globals.set_VariablePersists(type, true);
+        }
+    }
+}
diff --git a/QtVsTools.Core/Legacy/QtVersionManager.cs b/QtVsTools.Core/Legacy/QtVersionManager.cs
new file mode 100644
index 0000000..940dbea
--- /dev/null
+++ b/QtVsTools.Core/Legacy/QtVersionManager.cs
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using Microsoft.VisualStudio.Shell;
+
+namespace QtVsTools.Core.Legacy
+{
+    public static class QtVersionManager
+    {
+        public static string GetSolutionQtVersion(EnvDTE.Solution solution)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            if (solution == null)
+                return null;
+
+            if (solution.Globals.get_VariableExists("Qt5Version")) {
+                var version = (string)solution.Globals["Qt5Version"];
+                return Core.QtVersionManager.The().VerifyIfQtVersionExists(version) ? version : null;
+            }
+
+            return null;
+        }
+
+        public static bool SaveSolutionQtVersion(EnvDTE.Solution solution, string version)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            if (!Core.QtVersionManager.The().IsVersionAvailable(version) && version != "$(DefaultQtVersion)")
+                return false;
+
+            solution.Globals["Qt5Version"] = version;
+            if (!solution.Globals.get_VariablePersists("Qt5Version"))
+                solution.Globals.set_VariablePersists("Qt5Version", true);
+            return true;
+        }
+    }
+}
diff --git a/QtVsTools.Core/LinkerToolWrapper.cs b/QtVsTools.Core/LinkerToolWrapper.cs
index cc57a34..7db3506 100644
--- a/QtVsTools.Core/LinkerToolWrapper.cs
+++ b/QtVsTools.Core/LinkerToolWrapper.cs
@@ -26,11 +26,11 @@
 **
 ****************************************************************************/
 
-using Microsoft.VisualStudio.VCProjectEngine;
 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Text.RegularExpressions;
+using Microsoft.VisualStudio.VCProjectEngine;
 
 namespace QtVsTools.Core
 {
@@ -39,7 +39,7 @@
     /// </summary>
     public class LinkerToolWrapper
     {
-        private VCLinkerTool linker;
+        private readonly VCLinkerTool linker;
 
         public LinkerToolWrapper(VCLinkerTool linkerTool)
         {
diff --git a/QtVsTools.Core/MainWinWrapper.cs b/QtVsTools.Core/MainWinWrapper.cs
index f42ca31..2da7105 100644
--- a/QtVsTools.Core/MainWinWrapper.cs
+++ b/QtVsTools.Core/MainWinWrapper.cs
@@ -28,30 +28,18 @@
 
 using System;
 using System.Windows.Forms;
+using Microsoft.VisualStudio.Shell;
 
 namespace QtVsTools.Core
 {
     public class MainWinWrapper : IWin32Window
     {
-        private readonly EnvDTE.DTE dteObject;
+        public IntPtr Handle { get; }
 
         public MainWinWrapper(EnvDTE.DTE dte)
         {
-            dteObject = dte;
-        }
-
-        public IntPtr Handle
-        {
-            get
-            {
-                if (dteObject != null)
-#if VS2022
-                    return dteObject.MainWindow.HWnd;
-#else
-                    return new IntPtr(dteObject.MainWindow.HWnd);
-#endif
-                return new IntPtr(0);
-            }
+            ThreadHelper.ThrowIfNotOnUIThread();
+            Handle = new IntPtr((long)dte.MainWindow.HWnd);
         }
     }
 }
diff --git a/QtVsTools.Core/Messages.cs b/QtVsTools.Core/Messages.cs
index c5eea32..507bcbb 100644
--- a/QtVsTools.Core/Messages.cs
+++ b/QtVsTools.Core/Messages.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -26,34 +26,25 @@
 **
 ****************************************************************************/
 
-using EnvDTE;
+using System;
 using System.Collections.Concurrent;
-using System.Diagnostics;
-using System.Linq;
 using System.Threading;
-using Thread = System.Threading.Thread;
 using System.Windows.Forms;
-using System.Threading.Tasks;
+using Microsoft.VisualStudio.Shell;
 using Microsoft.VisualStudio.Threading;
-using QtVsTools.VisualStudio;
+
+using Task = System.Threading.Tasks.Task;
 
 namespace QtVsTools.Core
 {
+    using VisualStudio;
+
     public static class Messages
     {
-        private static OutputWindow Window { get; set; }
         private static OutputWindowPane Pane { get; set; }
 
-        private static OutputWindowPane _BuildPane;
-        private static OutputWindowPane BuildPane
-        {
-            get
-            {
-                return _BuildPane ?? (_BuildPane = Window.OutputWindowPanes.Cast<OutputWindowPane>()
-                    .Where(pane => pane.Guid == "{1BD8A850-02D1-11D1-BEE7-00A0C913D1F8}")
-                    .FirstOrDefault());
-            }
-        }
+        private static readonly string PaneName = "Qt VS Tools";
+        private static readonly Guid PaneGuid = new Guid("8f6a1e44-fa0b-49e5-9934-1c050555350e");
 
         /// <summary>
         /// Show a message on the output pane.
@@ -69,13 +60,15 @@
             FlushMessages();
         }
 
-        static void OutputWindowPane_Print(string text)
+        public static void Log(this Exception exception, bool clear = false, bool activate = false)
         {
-            OutputWindowPane_Init();
-            Pane.OutputString(text + "\r\n");
-            // show buildPane if a build is in progress
-            if (Dte.Solution.SolutionBuild.BuildState == vsBuildState.vsBuildStateInProgress)
-                BuildPane?.Activate();
+            msgQueue.Enqueue(new Msg()
+            {
+                Clear = clear,
+                Text = ExceptionToString(exception),
+                Activate = activate
+            });
+            FlushMessages();
         }
 
         /// <summary>
@@ -90,50 +83,44 @@
             FlushMessages();
         }
 
-        static void OutputWindowPane_Activate()
+        static async Task OutputWindowPane_ActivateAsync()
         {
-            OutputWindowPane_Init();
-            Pane?.Activate();
+            await OutputWindowPane_InitAsync();
+            await Pane?.ActivateAsync();
         }
 
-        private static string ExceptionToString(System.Exception e)
+        private static string ExceptionToString(System.Exception exception)
         {
-            return e.Message + "\r\n" + "(" + e.StackTrace.Trim() + ")";
+            return $"An exception ({exception.GetType().Name}) occurred.\r\n"
+                   + $"Message:\r\n   {exception.Message}\r\n"
+                   + $"Stack Trace:\r\n   {exception.StackTrace.Trim()}\r\n";
         }
 
         private static readonly string ErrorString = SR.GetString("Messages_ErrorOccured");
         private static readonly string WarningString = SR.GetString("Messages_Warning");
         private static readonly string SolutionString = SR.GetString("Messages_SolveProblem");
 
-        static public void DisplayCriticalErrorMessage(System.Exception e)
-        {
-            MessageBox.Show(ErrorString +
-                ExceptionToString(e),
-                SR.GetString("Resources_QtVsTools"), MessageBoxButtons.OK, MessageBoxIcon.Error);
-        }
-
-        static public void DisplayCriticalErrorMessage(string msg)
+        public static void DisplayCriticalErrorMessage(string msg)
         {
             MessageBox.Show(ErrorString +
                 msg,
                 SR.GetString("Resources_QtVsTools"), MessageBoxButtons.OK, MessageBoxIcon.Error);
         }
 
-        static public void DisplayErrorMessage(System.Exception e)
+        public static void DisplayErrorMessage(System.Exception e)
         {
-            MessageBox.Show(ErrorString +
-                ExceptionToString(e),
+            MessageBox.Show(ExceptionToString(e),
                 SR.GetString("Resources_QtVsTools"), MessageBoxButtons.OK, MessageBoxIcon.Error);
         }
 
-        static public void DisplayErrorMessage(string msg)
+        public static void DisplayErrorMessage(string msg)
         {
             MessageBox.Show(ErrorString +
                 msg,
                 SR.GetString("Resources_QtVsTools"), MessageBoxButtons.OK, MessageBoxIcon.Error);
         }
 
-        static public void DisplayWarningMessage(System.Exception e, string solution)
+        public static void DisplayWarningMessage(System.Exception e, string solution)
         {
             MessageBox.Show(WarningString +
                 ExceptionToString(e) +
@@ -142,7 +129,7 @@
                 SR.GetString("Resources_QtVsTools"), MessageBoxButtons.OK, MessageBoxIcon.Warning);
         }
 
-        static public void DisplayWarningMessage(string msg)
+        public static void DisplayWarningMessage(string msg)
         {
             MessageBox.Show(WarningString +
                 msg,
@@ -158,10 +145,10 @@
             FlushMessages();
         }
 
-        static void OutputWindowPane_Clear()
+        static async Task OutputWindowPane_ClearAsync()
         {
-            OutputWindowPane_Init();
-            Pane?.Clear();
+            await OutputWindowPane_InitAsync();
+            await Pane?.ClearAsync();
         }
 
         class Msg
@@ -171,33 +158,20 @@
             public bool Activate { get; set; } = false;
         }
 
-        static bool shuttingDown = false;
-        static ConcurrentQueue<Msg> msgQueue = new ConcurrentQueue<Msg>();
-        static DTE Dte { get; set; } = null;
+        static readonly ConcurrentQueue<Msg> msgQueue = new ConcurrentQueue<Msg>();
 
-        private static void OnBeginShutdown()
+        private static async Task OutputWindowPane_InitAsync()
         {
-            shuttingDown = true;
-        }
-
-        private static void OutputWindowPane_Init()
-        {
-            if (Dte == null)
-                Dte = VsServiceProvider.GetService<DTE>();
-            var t = Stopwatch.StartNew();
-            while (Pane == null && t.ElapsedMilliseconds < 5000) {
-                try {
-                    Window = Dte.Windows.Item(Constants.vsWindowKindOutput).Object as OutputWindow;
-                    Pane = Window?.OutputWindowPanes.Add(SR.GetString("Resources_QtVsTools"));
-                } catch {
-                }
+            try {
                 if (Pane == null)
-                    Thread.Yield();
+                    Pane = await OutputWindowPane.CreateAsync(PaneName, PaneGuid);
+            } catch (Exception ex) {
+                System.Diagnostics.Debug.WriteLine(ex);
             }
-            Dte.Events.DTEEvents.OnBeginShutdown += OnBeginShutdown;
         }
 
         public static JoinableTaskFactory JoinableTaskFactory { get; set; }
+
         static readonly object staticCriticalSection = new object();
         static Task FlushTask { get; set; }
         static EventWaitHandle MessageReady { get; set; }
@@ -209,27 +183,21 @@
                     MessageReady = new EventWaitHandle(false, EventResetMode.AutoReset);
                     FlushTask = Task.Run(async () =>
                     {
-                        while (!shuttingDown) {
+                        var package = VsServiceProvider.Instance as Package;
+                        while (!package.Zombied) {
                             if (!await MessageReady.ToTask(3000))
                                 continue;
                             while (!msgQueue.IsEmpty) {
-                                Msg msg;
-                                if (!msgQueue.TryDequeue(out msg)) {
+                                if (!msgQueue.TryDequeue(out Msg msg)) {
                                     await Task.Yield();
                                     continue;
                                 }
-                                ////////////////////////////////////////////////////////////////////
-                                // Switch to main (UI) thread
-                                await JoinableTaskFactory.SwitchToMainThreadAsync();
                                 if (msg.Clear)
-                                    OutputWindowPane_Clear();
+                                    await OutputWindowPane_ClearAsync();
                                 if (msg.Text != null)
-                                    OutputWindowPane_Print(msg.Text);
+                                    await OutputWindowPane_PrintAsync(msg.Text);
                                 if (msg.Activate)
-                                    OutputWindowPane_Activate();
-                                ////////////////////////////////////////////////////////////////////
-                                // Switch to background thread
-                                await TaskScheduler.Default;
+                                    await OutputWindowPane_ActivateAsync();
                             }
                         }
                     });
@@ -237,5 +205,15 @@
             }
             MessageReady.Set();
         }
+
+        static async Task OutputWindowPane_PrintAsync(string text)
+        {
+            var active = await OutputWindowPane.GetActiveAsync();
+
+            await OutputWindowPane_InitAsync();
+            await Pane.PrintAsync(text);
+
+            (active?.ActivateAsync()).Forget();
+        }
     }
 }
diff --git a/QtVsTools.Core/MocCmdChecker.cs b/QtVsTools.Core/MocCmdChecker.cs
index dc0df1b..16ffaba 100644
--- a/QtVsTools.Core/MocCmdChecker.cs
+++ b/QtVsTools.Core/MocCmdChecker.cs
@@ -34,8 +34,8 @@
 {
     class MocCmdChecker
     {
-        private Regex backslashRegEx = new Regex(@"\\+\.?\\+");
-        private Regex endRegEx = new Regex(@"\\\.?$");
+        private readonly Regex backslashRegEx = new Regex(@"\\+\.?\\+");
+        private readonly Regex endRegEx = new Regex(@"\\\.?$");
 
         private string NormalizePath(string path)
         {
diff --git a/QtVsTools.Core/MsBuildProject.cs b/QtVsTools.Core/MsBuildProject.cs
index 3b11f34..3eff430 100644
--- a/QtVsTools.Core/MsBuildProject.cs
+++ b/QtVsTools.Core/MsBuildProject.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -30,22 +30,22 @@
 using System.IO;
 using System.Collections.Generic;
 using System.Text;
+using System.Text.RegularExpressions;
 using System.Linq;
 using System.Xml;
 using System.Xml.Linq;
-using QtVsTools.Core.QtMsBuild;
-using System.Text.RegularExpressions;
 using Microsoft.Build.Construction;
 using Microsoft.Build.Execution;
 using Microsoft.Build.Evaluation;
-using QtVsTools.VisualStudio;
-using QtVsTools.SyntaxAnalysis;
-using EnvDTE;
+using Microsoft.VisualStudio.Shell;
 
 namespace QtVsTools.Core
 {
+    using QtMsBuild;
+    using SyntaxAnalysis;
+
     using static HelperFunctions;
-    using static RegExpr;
+    using static SyntaxAnalysis.RegExpr;
 
     public class MsBuildProject
     {
@@ -65,7 +65,8 @@
             User,
             Count
         }
-        MsBuildXmlFile[] files = new MsBuildXmlFile[(int)Files.Count];
+
+        readonly MsBuildXmlFile[] files = new MsBuildXmlFile[(int)Files.Count];
 
         MsBuildProject()
         {
@@ -94,7 +95,7 @@
             }
         }
 
-        private static XNamespace ns = "http://schemas.microsoft.com/developer/msbuild/2003";
+        private static readonly XNamespace ns = "http://schemas.microsoft.com/developer/msbuild/2003";
 
         public static MsBuildProject Load(string pathToProject)
         {
@@ -293,12 +294,8 @@
             if (ConfigCondition == null)
                 return false;
 
-            // Get default Qt dir
-            string defaultQtDir = null;
             var defaultVersionName = QtVersionManager.The().GetDefaultVersion();
             var defaultVersion = QtVersionManager.The().GetVersionInfo(defaultVersionName);
-            if (defaultVersion != null)
-                defaultQtDir = defaultVersion.qtDir;
 
             // Get project configurations
             var configs = this[Files.Project].xml
@@ -314,15 +311,6 @@
                 .FirstOrDefault();
             if (globals == null)
                 return false;
-
-            // Get project configuration properties
-            var configProps = this[Files.Project].xml
-                .Elements(ns + "Project")
-                .Elements(ns + "PropertyGroup")
-                .Where(pg =>
-                    (string)pg.Attribute("Label") == "Configuration"
-                    && pg.Attribute("Condition") != null)
-                .ToDictionary(pg => (string)pg.Attribute("Condition"));
 
             // Set Qt project format version
             var projKeyword = globals
@@ -386,10 +374,8 @@
                 foreach (var pg in uncategorizedPropertyGroups) {
                     foreach (var p in pg.Elements().ToList()) {
                         var condition = p.Attribute("Condition") ?? pg.Attribute("Condition");
-                        XElement configPropertyGroup = null;
-                        if (condition != null)
-                            propertyGroups.TryGetValue((string)condition, out configPropertyGroup);
-                        if (configPropertyGroup != null) {
+                        if (condition != null && propertyGroups
+                            .TryGetValue((string)condition, out XElement configPropertyGroup)) {
                             p.Remove();
                             p.SetAttributeValue("Condition", null);
                             configPropertyGroup.Add(p);
@@ -535,12 +521,10 @@
                 foreach (var configQtSettings in qtSettings) {
                     var configCondition = (string)configQtSettings.Attribute("Condition");
 
-                    XElement oldConfigQtInstall;
-                    if (oldQtInstall.TryGetValue(configCondition, out oldConfigQtInstall))
+                    if (oldQtInstall.TryGetValue(configCondition, out XElement oldConfigQtInstall))
                         configQtSettings.Add(oldConfigQtInstall);
 
-                    XElement oldConfigQtSettings;
-                    if (oldQtSettings.TryGetValue(configCondition, out oldConfigQtSettings)) {
+                    if (oldQtSettings.TryGetValue(configCondition, out XElement oldConfigQtSettings)) {
                         foreach (var qtSetting in oldConfigQtSettings.Elements())
                             configQtSettings.Add(qtSetting);
                     }
@@ -600,6 +584,11 @@
                 .Elements(ns + "ItemDefinitionGroup")
                 .Elements(ns + "Link");
 
+            var resourceCompiler = this[Files.Project].xml
+                .Elements(ns + "Project")
+                .Elements(ns + "ItemDefinitionGroup")
+                .Elements(ns + "ResourceCompile");
+
             // Qt module names, to copy to QtModules property
             var moduleNames = new HashSet<string>();
 
@@ -613,9 +602,9 @@
             var moduleLibs = new HashSet<string>();
 
             // Go through all known Qt modules and check which ones are currently being used
-            foreach (var module in QtModules.Instance.GetAvailableModules()) {
+            foreach (var module in QtModules.Instance.GetAvailableModules(defaultVersion.qtMajor)) {
 
-                if (IsModuleUsed(module, compiler, linker)) {
+                if (IsModuleUsed(module, compiler, linker, resourceCompiler)) {
 
                     // Qt module names, to copy to QtModules property
                     if (!string.IsNullOrEmpty(module.proVarQT))
@@ -670,6 +659,12 @@
                     .Select(x => Unquote(x))
                     // Exclude paths rooted on $(QTDIR)
                     .Where(x => !x.StartsWith("$(QTDIR)", IGNORE_CASE))));
+            }
+
+            // Remove Qt module macros from resource compiler properties
+            foreach (var defines in resourceCompiler.Elements(ns + "PreprocessorDefinitions")) {
+                defines.SetValue(string.Join(";", defines.Value.Split(';')
+                    .Where(x => !moduleDefines.Contains(x))));
             }
 
             // Add Qt module names to QtModules project property
@@ -778,7 +773,8 @@
         bool IsModuleUsed(
             QtModule module,
             IEnumerable<XElement> compiler,
-            IEnumerable<XElement> linker)
+            IEnumerable<XElement> linker,
+            IEnumerable<XElement> resourceCompiler)
         {
             // Module .lib is present in linker additional dependencies
             if (linker.Elements(ns + "AdditionalDependencies")
@@ -788,8 +784,15 @@
                 return true;
             }
 
-            // Module macro is present in pre-processor definitions
+            // Module macro is present in the compiler pre-processor definitions
             if (compiler.Elements(ns + "PreprocessorDefinitions")
+                .SelectMany(x => x.Value.Split(';'))
+                .Any(x => module.Defines.Contains(x))) {
+                return true;
+            }
+
+            // Module macro is present in resource compiler pre-processor definitions
+            if (resourceCompiler.Elements(ns + "PreprocessorDefinitions")
                 .SelectMany(x => x.Value.Split(';'))
                 .Any(x => module.Defines.Contains(x))) {
                 return true;
@@ -958,9 +961,9 @@
                         commandLine = replace(row.itemName, commandLine);
                     //
                     //   * Configuration/platform, e.g. x64\Debug --> $(Platform)\$(Configuration)
-                    commandLine = commandLine
-                        .Replace(configName, "$(Configuration)",
-                            StringComparison.InvariantCultureIgnoreCase)
+                    //   * ignore any word other than the expected configuration, e.g. lrelease.exe
+                    commandLine = Regex.Replace(commandLine, @"\b" + configName + @"\b",
+                            "$(Configuration)", RegexOptions.IgnoreCase)
                         .Replace(platformName, "$(Platform)",
                             StringComparison.InvariantCultureIgnoreCase);
 
@@ -969,8 +972,7 @@
                         evaluator.Properties.Add(configProp.Name.LocalName, (string)configProp);
                     if (!qtMsBuild.SetCommandLine(itemType, item, commandLine, evaluator)) {
                         int lineNumber = 1;
-                        var errorLine = row.command as IXmlLineInfo;
-                        if (errorLine != null && errorLine.HasLineInfo())
+                        if (row.command is IXmlLineInfo errorLine && errorLine.HasLineInfo())
                             lineNumber = errorLine.LineNumber;
 
                         Messages.Print(string.Format(
@@ -1059,8 +1061,7 @@
                     return (string)cbt.Attribute("Include");
                 }
             }
-            string ouputFile;
-            if (!properties.TryGetValue(QtMoc.Property.InputFile, out ouputFile))
+            if (!properties.TryGetValue(QtMoc.Property.InputFile, out string ouputFile))
                 return (string)cbt.Attribute("Include");
             return ouputFile;
         }
@@ -1085,8 +1086,7 @@
                         Path.IsPathRooted(x) ? x : Path.Combine(projDir, x)));
                 var outputItems = new List<XElement>();
                 foreach (var outputFile in outputFiles) {
-                    List<XElement> mocOutput = null;
-                    if (projItemsByPath.TryGetValue(outputFile, out mocOutput)) {
+                    if (projItemsByPath.TryGetValue(outputFile, out List<XElement> mocOutput)) {
                         outputItems.AddRange(mocOutput);
                         hasGeneratedFiles |= hasGeneratedFiles ? true : mocOutput
                             .Where(x => !x.Elements(ns + "ExcludedFromBuild")
@@ -1469,17 +1469,16 @@
 
         class MSBuildEvaluator : IVSMacroExpander, IDisposable
         {
-            MsBuildXmlFile projFile;
-            string tempProjFilePath;
-            XElement evaluateTarget;
-            XElement evaluateProperty;
-            ProjectRootElement projRoot;
-            public Dictionary<string, string> expansionCache;
+            private readonly MsBuildXmlFile projFile;
+            private string tempProjFilePath;
+            private XElement evaluateTarget;
+            private XElement evaluateProperty;
+            private ProjectRootElement projRoot;
+            private readonly Dictionary<string, string> expansionCache;
 
             public Dictionary<string, string> Properties
             {
                 get;
-                private set;
             }
 
             public MSBuildEvaluator(MsBuildXmlFile projFile)
@@ -1522,8 +1521,7 @@
 
             public string ExpandString(string stringToExpand)
             {
-                string expandedString;
-                if (TryExpansionCache(stringToExpand, out expandedString))
+                if (TryExpansionCache(stringToExpand, out string expandedString))
                     return expandedString;
 
                 if (evaluateTarget == null) {
@@ -1649,7 +1647,7 @@
             return true;
         }
 
-        static Regex ConditionParser =
+        static readonly Regex ConditionParser =
             new Regex(@"\'\$\(Configuration[^\)]*\)\|\$\(Platform[^\)]*\)\'\=\=\'([^\']+)\'");
 
         class MsBuildConverterProvider : IPropertyStorageProvider
diff --git a/QtVsTools.Core/OutputWindowPane.cs b/QtVsTools.Core/OutputWindowPane.cs
new file mode 100644
index 0000000..1563acb
--- /dev/null
+++ b/QtVsTools.Core/OutputWindowPane.cs
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Threading.Tasks;
+using Microsoft.VisualStudio;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.Threading;
+
+using Task = System.Threading.Tasks.Task;
+
+namespace QtVsTools.Core
+{
+    using VisualStudio;
+
+    public class OutputWindowPane
+    {
+        public enum VSOutputWindowPane
+        {
+            General,
+            Build,
+            Debug,
+        }
+
+        public static Task<OutputWindowPane> GetVSOutputWindowPaneAsync(VSOutputWindowPane pane)
+        {
+            switch (pane) {
+            case VSOutputWindowPane.General:
+                return GetAsync(VSConstants.OutputWindowPaneGuid.GeneralPane_guid);
+            case VSOutputWindowPane.Build:
+                return GetAsync(VSConstants.OutputWindowPaneGuid.BuildOutputPane_guid);
+            case VSOutputWindowPane.Debug:
+                return GetAsync(VSConstants.OutputWindowPaneGuid.DebugPane_guid);
+            default:
+                throw new InvalidOperationException("Unsupported Visual Studio output pane");
+            };
+        }
+
+        public static async Task<OutputWindowPane> GetAsync(Guid guid)
+        {
+            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+            try {
+                IVsOutputWindow w = null;
+                if (guid == VSConstants.OutputWindowPaneGuid.GeneralPane_guid) {
+                    w = await VsServiceProvider.GetServiceAsync<SVsGeneralOutputWindowPane,
+                        IVsOutputWindow>();
+                } else {
+                    w = await VsServiceProvider.GetServiceAsync<SVsOutputWindow, IVsOutputWindow>();
+                }
+                ErrorHandler.ThrowOnFailure(w.GetPane(guid, out IVsOutputWindowPane pane));
+
+                return new OutputWindowPane(guid, pane);
+            } catch (Exception ex) {
+                System.Diagnostics.Debug.WriteLine(ex);
+                return null;
+            }
+        }
+
+        public static async Task<OutputWindowPane> CreateAsync(string name, Guid guid)
+        {
+            if (string.IsNullOrEmpty(name))
+                throw new ArgumentNullException($"{ nameof(name) } cannot be null");
+
+            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+            try {
+                var w = await VsServiceProvider.GetServiceAsync<SVsOutputWindow, IVsOutputWindow>();
+
+                const int visible = 1, clear = 1;
+                ErrorHandler.ThrowOnFailure(w.CreatePane(guid, name, visible, clear));
+                ErrorHandler.ThrowOnFailure(w.GetPane(guid, out IVsOutputWindowPane pane));
+
+                return new OutputWindowPane(guid, pane);
+            } catch (Exception ex) {
+                System.Diagnostics.Debug.WriteLine(ex);
+                return null;
+            }
+        }
+
+        public static async Task<OutputWindowPane> GetActiveAsync()
+        {
+            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+            try {
+                var w2 = await VsServiceProvider
+                    .GetServiceAsync<SVsOutputWindow, IVsOutputWindow>() as IVsOutputWindow2;
+                ErrorHandler.ThrowOnFailure(w2.GetActivePaneGUID(out Guid guid));
+
+                IVsOutputWindow w = w2 as IVsOutputWindow;
+                ErrorHandler.ThrowOnFailure(w.GetPane(guid, out IVsOutputWindowPane pane));
+
+                return new OutputWindowPane(guid, pane);
+            } catch (Exception ex) {
+                System.Diagnostics.Debug.WriteLine(ex);
+                return null;
+            }
+        }
+
+        private Guid Guid { get; }
+        private IVsOutputWindowPane Pane { get; set; } = null;
+
+        private OutputWindowPane(Guid guid, IVsOutputWindowPane pane)
+        {
+            Guid = guid;
+            Pane = pane;
+        }
+
+        public async Task ActivateAsync()
+        {
+            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+            if (Pane == null)
+                throw new InvalidOperationException($"{ nameof(Pane) } cannot be null");
+            Pane.Activate();
+        }
+
+        public async Task HideAsync()
+        {
+            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+            if (Pane == null)
+                throw new InvalidOperationException($"{ nameof(Pane) } cannot be null");
+            Pane.Hide();
+        }
+
+        public async Task ClearAsync()
+        {
+            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+            if (Pane == null)
+                throw new InvalidOperationException($"{ nameof(Pane) } cannot be null");
+            Pane.Clear();
+        }
+
+        public void Print()
+        {
+            ThreadHelper.JoinableTaskFactory.Run(async () => { await PrintAsync(""); });
+        }
+
+        public void Print(string value)
+        {
+            ThreadHelper.JoinableTaskFactory.Run(async () => { await PrintAsync(value); });
+        }
+
+        public Task PrintAsync()
+        {
+            return PrintAsync("");
+        }
+
+        public async Task PrintAsync(string value)
+        {
+            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+            if (Pane is IVsOutputWindowPaneNoPump noPumpPane)
+                noPumpPane.OutputStringNoPump(value + Environment.NewLine);
+            else
+                ErrorHandler.ThrowOnFailure(Pane.OutputStringThreadSafe(value + Environment.NewLine));
+        }
+    }
+}
diff --git a/QtVsTools.Core/ProFileContent.cs b/QtVsTools.Core/ProFileContent.cs
index 8bd3d2b..a505a16 100644
--- a/QtVsTools.Core/ProFileContent.cs
+++ b/QtVsTools.Core/ProFileContent.cs
@@ -35,46 +35,20 @@
     {
         public ProFileContent(VCProject proj)
         {
-            export = true;
-            vcproj = proj;
-            options = new List<ProFileOption>();
+            Export = true;
+            Project = proj;
+            Options = new List<ProFileOption>();
         }
 
         public override string ToString()
         {
-            return vcproj.Name;
+            return Project.Name;
         }
 
-        public VCProject Project
-        {
-            get
-            {
-                return vcproj;
-            }
-        }
+        public VCProject Project { get; }
 
-        public bool Export
-        {
-            get
-            {
-                return export;
-            }
-            set
-            {
-                export = value;
-            }
-        }
+        public bool Export { get; set; }
 
-        public List<ProFileOption> Options
-        {
-            get
-            {
-                return options;
-            }
-        }
-
-        private VCProject vcproj;
-        private bool export;
-        private List<ProFileOption> options;
+        public List<ProFileOption> Options { get; }
     }
 }
diff --git a/QtVsTools.Core/ProFileOption.cs b/QtVsTools.Core/ProFileOption.cs
index 54468ef..8a5ad3d 100644
--- a/QtVsTools.Core/ProFileOption.cs
+++ b/QtVsTools.Core/ProFileOption.cs
@@ -34,95 +34,33 @@
     {
         public ProFileOption(string optname)
         {
-            name = optname;
-            astype = AssignType.AT_PlusEquals;
-            comment = null;
-            shortComment = "Default";
-            incComment = false;
-            newOpt = " \\\r\n    ";
-            list = new List<string>();
+            Name = optname;
+            AssignSymbol = AssignType.AT_PlusEquals;
+            Comment = null;
+            ShortComment = "Default";
+            IncludeComment = false;
+            NewOption = " \\\r\n    ";
+            List = new List<string>();
         }
 
         public override string ToString()
         {
-            return shortComment;
+            return ShortComment;
         }
 
-        public string Comment
-        {
-            get
-            {
-                return comment;
-            }
-            set
-            {
-                comment = value;
-            }
-        }
+        public string Comment { get; set; }
 
-        public string ShortComment
-        {
-            get
-            {
-                return shortComment;
-            }
-            set
-            {
-                shortComment = value;
-            }
-        }
+        public string ShortComment { get; set; }
 
-        public AssignType AssignSymbol
-        {
-            get
-            {
-                return astype;
-            }
-            set
-            {
-                astype = value;
-            }
-        }
+        public AssignType AssignSymbol { get; set; }
 
-        public string NewOption
-        {
-            get
-            {
-                return newOpt;
-            }
-            set
-            {
-                newOpt = value;
-            }
-        }
+        public string NewOption { get; set; }
 
-        public string Name
-        {
-            get
-            {
-                return name;
-            }
-        }
+        public string Name { get; }
 
-        public List<string> List
-        {
-            get
-            {
-                return list;
-            }
-        }
+        public List<string> List { get; }
 
-        public bool IncludeComment
-        {
-            get
-            {
-                return incComment;
-            }
-            set
-            {
-                incComment = value;
-            }
-        }
+        public bool IncludeComment { get; set; }
 
         public enum AssignType
         {
@@ -131,13 +69,5 @@
             AT_MinusEquals = 3,
             AT_Function = 4
         }
-
-        private AssignType astype;
-        private string shortComment;
-        private bool incComment;
-        private string comment;
-        private string newOpt;
-        private string name;
-        private List<string> list;
     }
 }
diff --git a/QtVsTools.Core/ProSolution.cs b/QtVsTools.Core/ProSolution.cs
index 497f213..2eb9990 100644
--- a/QtVsTools.Core/ProSolution.cs
+++ b/QtVsTools.Core/ProSolution.cs
@@ -35,27 +35,12 @@
     {
         public ProSolution(Solution sln)
         {
-            prosln = sln;
-            proFiles = new List<ProFileContent>();
+            ProjectSolution = sln;
+            ProFiles = new List<ProFileContent>();
         }
 
-        public List<ProFileContent> ProFiles
-        {
-            get
-            {
-                return proFiles;
-            }
-        }
+        public List<ProFileContent> ProFiles { get; }
 
-        public Solution ProjectSolution
-        {
-            get
-            {
-                return prosln;
-            }
-        }
-
-        private List<ProFileContent> proFiles;
-        private Solution prosln;
+        public Solution ProjectSolution { get; }
     }
 }
diff --git a/QtVsTools.Core/ProjectExporter.cs b/QtVsTools.Core/ProjectExporter.cs
index 681bd33..357c713 100644
--- a/QtVsTools.Core/ProjectExporter.cs
+++ b/QtVsTools.Core/ProjectExporter.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -26,15 +26,16 @@
 **
 ****************************************************************************/
 
-using EnvDTE;
-using EnvDTE80;
-using Microsoft.VisualStudio.VCProjectEngine;
 using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.IO;
 using System.Text.RegularExpressions;
 using System.Windows.Forms;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.VCProjectEngine;
+using EnvDTE;
+using EnvDTE80;
 
 namespace QtVsTools.Core
 {
@@ -43,7 +44,7 @@
     /// </summary>
     public class ProjectExporter
     {
-        private DTE dteObject;
+        private readonly DTE dteObject;
 
         public ProjectExporter(DTE dte)
         {
@@ -91,13 +92,15 @@
 
         private ProSolution CreateProFileSolution(Solution sln)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             ProFileContent content;
             var prosln = new ProSolution(sln);
 
             foreach (var proj in HelperFunctions.ProjectsInSolution(sln.DTE)) {
                 try {
                     // only add qt projects
-                    if (HelperFunctions.IsQtProject(proj)) {
+                    if (HelperFunctions.IsVsToolsProject(proj)) {
                         content = CreateProFileContent(proj);
                         prosln.ProFiles.Add(content);
                     } else if (proj.Kind == ProjectKinds.vsProjectKindSolutionFolder) {
@@ -113,9 +116,11 @@
 
         private void addProjectsInFolder(Project solutionFolder, ProSolution sln)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             foreach (ProjectItem pi in solutionFolder.ProjectItems) {
                 var containedProject = pi.Object as Project;
-                if (HelperFunctions.IsQtProject(containedProject)) {
+                if (HelperFunctions.IsVsToolsProject(containedProject)) {
                     var content = CreateProFileContent(containedProject);
                     sln.ProFiles.Add(content);
                 } else if (containedProject.Kind == ProjectKinds.vsProjectKindSolutionFolder) {
@@ -126,6 +131,8 @@
 
         private static ProFileContent CreateProFileContent(Project project)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             ProFileOption option;
             var qtPro = QtProject.Create(project);
             var content = new ProFileContent(qtPro.VCProject);
@@ -192,8 +199,7 @@
             if (config.ConfigurationType == ConfigurationTypes.typeStaticLibrary)
                 option.List.Add("staticlib");
             if (linker != null) {
-                var linkerRule = linker as IVCRulePropertyStorage;
-                var generateDebugInformation = (linkerRule != null) ?
+                var generateDebugInformation = (linker is IVCRulePropertyStorage linkerRule) ?
                     linkerRule.GetUnevaluatedPropertyValue("GenerateDebugInformation") : null;
                 if (generateDebugInformation != "false")
                     option.List.Add("debug");
@@ -213,10 +219,12 @@
                 }
             }
 
-            if (qtPro.IsDesignerPluginProject()) {
-                option.List.Add("designer");
+            var legacyDesigner = Legacy.QtProject.IsDesignerPluginProject(qtPro);
+            var plugin = legacyDesigner | Core.QtProject.IsQtPlugin(qtPro);
+            if (plugin)
                 option.List.Add("plugin");
-            }
+            if (legacyDesigner)
+                option.List.Add("designer");
 
             // add defines
             option = new ProFileOption("DEFINES");
@@ -323,12 +331,18 @@
                 option.List.Add(project.Name + ".rc");
             }
 
-            if (qtPro.IsDesignerPluginProject()) {
+            if (plugin) {
                 option = new ProFileOption("target.path");
-                option.ShortComment = "Install the plugin in the designer plugins directory.";
+                if (legacyDesigner)
+                    option.ShortComment = "Installs the plugin in the designer plugins directory.";
+                else
+                    option.ShortComment = "Installs the plugin in the plugins directory.";
                 option.IncludeComment = true;
                 option.AssignSymbol = ProFileOption.AssignType.AT_Equals;
-                option.List.Add("$$[QT_INSTALL_PLUGINS]/designer");
+                if (legacyDesigner)
+                    option.List.Add("$$[QT_INSTALL_PLUGINS]/designer");
+                else
+                    option.List.Add("$$[QT_INSTALL_PLUGINS]");
                 content.Options.Add(option);
 
                 option = new ProFileOption("INSTALLS");
@@ -343,6 +357,8 @@
 
         private static ProFileContent CreatePriFileContent(Project project, string priFileDirectory)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             ProFileOption option;
             var qtPro = QtProject.Create(project);
             var content = new ProFileContent(qtPro.VCProject);
@@ -417,6 +433,8 @@
 
         private static void AddIncludePaths(Project project, ProFileOption option, string includePaths)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (QtProject.GetFormatVersion(project) >= Resources.qtMinFormatVersion_ClProperties)
                 return;
 
@@ -437,10 +455,7 @@
                 if (!d.StartsWith("$(qtdir)\\include", StringComparison.OrdinalIgnoreCase) &&
                     !d.StartsWith(qtDir + "\\include", StringComparison.OrdinalIgnoreCase) &&
                     !d.EndsWith("win32-msvc2005", StringComparison.OrdinalIgnoreCase)) {
-
-                    var vcConfig = project.ConfigurationManager.ActiveConfiguration.Object
-                        as VCConfiguration;
-                    if (vcConfig != null)
+                    if (project.ConfigurationManager.ActiveConfiguration.Object is VCConfiguration vcConfig)
                         HelperFunctions.ExpandString(ref d, vcConfig);
                     if (HelperFunctions.IsAbsoluteFilePath(d))
                         d = HelperFunctions.GetRelativePath(project.FullName, d);
@@ -461,8 +476,9 @@
                 qtDir = Environment.GetEnvironmentVariable("QTDIR");
             if (qtDir == null)
                 qtDir = "";
-
             qtDir = HelperFunctions.NormalizeRelativeFilePath(qtDir);
+
+            ThreadHelper.ThrowIfNotOnUIThread();
 
             if (paths != null) {
                 foreach (var s in paths.Split(';', ',')) {
@@ -491,7 +507,14 @@
 
         private static void AddModules(QtProject qtPrj, ProFileOption optionQT, ProFileOption optionCONFIG)
         {
-            foreach (var module in QtModules.Instance.GetAvailableModules()) {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            var vm = QtVersionManager.The();
+            var versionInfo = vm.GetVersionInfo(qtPrj.Project);
+            if (versionInfo == null)
+                versionInfo = vm.GetVersionInfo(vm.GetDefaultVersion());
+
+            foreach (var module in QtModules.Instance.GetAvailableModules(versionInfo.qtMajor)) {
                 if (!qtPrj.HasModule(module.Id))
                     continue;
 
@@ -504,6 +527,8 @@
 
         private void WriteProSolution(ProSolution prosln, bool openFile)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var sln = prosln.ProjectSolution;
             if (string.IsNullOrEmpty(sln.FileName))
                 return;
@@ -573,6 +598,8 @@
 
         private void WriteProFile(ProFileContent content, string proFile, string priFileToInclude, bool openFile)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             StreamWriter sw;
             if (File.Exists(proFile)) {
                 if (MessageBox.Show(SR.GetString("ExportProject_ExistsOverwriteQuestion", proFile),
@@ -605,8 +632,7 @@
                 WriteProFileOptions(sw, content.Options);
             }
 
-            // open the file in vs
-            if (openFile)
+            if (openFile) // open the file in vs
                 dteObject.OpenFile(Constants.vsViewKindTextView, proFile).Activate();
         }
 
@@ -705,6 +731,8 @@
         public static void SyncIncludeFiles(VCProject vcproj, List<string> priFiles,
             List<string> projFiles, DTE dte, bool flat, FakeFilter fakeFilter)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var cmpPriFiles = new List<string>(priFiles.Count);
             foreach (var s in priFiles)
                 cmpPriFiles.Add(HelperFunctions.NormalizeFilePath(s).ToLower());
@@ -779,7 +807,7 @@
 
         public void ExportToProFile()
         {
-            var expDlg = new ExportProjectDialog();
+            ThreadHelper.ThrowIfNotOnUIThread();
 
             var sln = dteObject.Solution;
             var prosln = CreateProFileSolution(sln);
@@ -789,6 +817,7 @@
                 return;
             }
 
+            var expDlg = new ExportProjectDialog();
             expDlg.ProFileSolution = prosln;
             expDlg.StartPosition = FormStartPosition.CenterParent;
             var ww = new MainWinWrapper(dteObject);
@@ -814,9 +843,10 @@
 
         public string ExportToPriFile(Project proj)
         {
-            VCProject vcproj;
+            ThreadHelper.ThrowIfNotOnUIThread();
 
-            if (HelperFunctions.IsQtProject(proj)) {
+            VCProject vcproj;
+            if (HelperFunctions.IsVsToolsProject(proj)) {
                 try {
                     vcproj = (VCProject)proj.Object;
                 } catch (Exception e) {
@@ -844,8 +874,9 @@
 
         public void ExportToPriFile(Project proj, string fileName)
         {
-            var priFile = new FileInfo(fileName);
+            ThreadHelper.ThrowIfNotOnUIThread();
 
+            var priFile = new FileInfo(fileName);
             var content = CreatePriFileContent(proj, priFile.DirectoryName);
             WritePriFile(content, priFile.FullName);
         }
diff --git a/QtVsTools.Core/ProjectImporter.cs b/QtVsTools.Core/ProjectImporter.cs
index bd5da86..8d14767 100644
--- a/QtVsTools.Core/ProjectImporter.cs
+++ b/QtVsTools.Core/ProjectImporter.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -26,18 +26,19 @@
 **
 ****************************************************************************/
 
-using EnvDTE;
-using Microsoft.VisualStudio.VCProjectEngine;
 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Windows.Forms;
+using Microsoft.VisualStudio.Shell;
+using EnvDTE;
+using Microsoft.VisualStudio.VCProjectEngine;
 
 namespace QtVsTools.Core
 {
     public class ProjectImporter
     {
-        private DTE dteObject;
+        private readonly DTE dteObject;
         const string projectFileExtension = ".vcxproj";
 
         public ProjectImporter(DTE dte)
@@ -47,6 +48,8 @@
 
         public void ImportProFile(string qtVersion)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             FileDialog toOpen = new OpenFileDialog();
             toOpen.FilterIndex = 1;
             toOpen.CheckFileExists = true;
@@ -78,6 +81,8 @@
 
         private void ImportSolution(FileInfo mainInfo, string qtVersion)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var versionInfo = QtVersionManager.The().GetVersionInfo(qtVersion);
             var VCInfo = RunQmake(mainInfo, ".sln", true, versionInfo);
             if (null == VCInfo)
@@ -88,7 +93,7 @@
                 if (CheckQtVersion(versionInfo)) {
                     dteObject.Solution.Open(VCInfo.FullName);
                     if (qtVersion != null) {
-                        QtVersionManager.The().SaveSolutionQtVersion(dteObject.Solution, qtVersion);
+                        Legacy.QtVersionManager.SaveSolutionQtVersion(dteObject.Solution, qtVersion);
                         foreach (var prj in HelperFunctions.ProjectsInSolution(dteObject)) {
                             QtVersionManager.The().SaveProjectQtVersion(prj, qtVersion);
                             var qtPro = QtProject.Create(prj);
@@ -100,12 +105,14 @@
 
                 Messages.Print("--- (Import): Finished opening " + VCInfo.Name);
             } catch (Exception e) {
-                Messages.DisplayCriticalErrorMessage(e);
+                Messages.DisplayErrorMessage(e);
             }
         }
 
         public void ImportProject(FileInfo mainInfo, string qtVersion)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var versionInfo = QtVersionManager.The().GetVersionInfo(qtVersion);
             var VCInfo = RunQmake(mainInfo, projectFileExtension, false, versionInfo);
             if (null == VCInfo)
@@ -116,9 +123,11 @@
             try {
                 if (CheckQtVersion(versionInfo)) {
                     // no need to add the project again if it's already there...
-                    if (!HelperFunctions.IsProjectInSolution(dteObject, VCInfo.FullName)) {
+                    var fullName = VCInfo.FullName;
+                    var pro = HelperFunctions.ProjectFromSolution(dteObject, fullName);
+                    if (pro == null) {
                         try {
-                            dteObject.Solution.AddFromFile(VCInfo.FullName, false);
+                            pro = dteObject.Solution.AddFromFile(fullName, false);
                         } catch (Exception /*exception*/) {
                             Messages.Print("--- (Import): Generated project could not be loaded.");
                             Messages.Print("--- (Import): Please look in the output above for errors and warnings.");
@@ -129,13 +138,6 @@
                         Messages.Print("Project already in Solution");
                     }
 
-                    Project pro = null;
-                    foreach (var p in HelperFunctions.ProjectsInSolution(dteObject)) {
-                        if (p.FullName.ToLower() == VCInfo.FullName.ToLower()) {
-                            pro = p;
-                            break;
-                        }
-                    }
                     if (pro != null) {
                         var qtPro = QtProject.Create(pro);
                         qtPro.SetQtEnvironment();
@@ -151,21 +153,16 @@
                                 Messages.Print("Can't select the platform " + platformName + ".");
                         }
 
-                        // try to figure out if the project is a plugin project
-                        try {
-                            var activeConfig = pro.ConfigurationManager.ActiveConfiguration.ConfigurationName;
-                            var config = (VCConfiguration)((IVCCollection)qtPro.VCProject.Configurations).Item(activeConfig);
-                            if (config.ConfigurationType == ConfigurationTypes.typeDynamicLibrary) {
-                                var compiler = CompilerToolWrapper.Create(config);
-                                var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
-                                if (compiler.GetPreprocessorDefinitions().IndexOf("QT_PLUGIN", StringComparison.Ordinal) > -1
-                                    && compiler.GetPreprocessorDefinitions().IndexOf("QDESIGNER_EXPORT_WIDGETS", StringComparison.Ordinal) > -1
-                                    && compiler.GetAdditionalIncludeDirectories().IndexOf("QtDesigner", StringComparison.Ordinal) > -1
-                                    && linker.AdditionalDependencies.IndexOf("QtDesigner", StringComparison.Ordinal) > -1) {
-                                    qtPro.MarkAsDesignerPluginProject();
-                                }
-                            }
-                        } catch (Exception) { }
+                        // figure out if the imported project is a plugin project
+                        var tmp = qtPro.Project.ConfigurationManager.ActiveConfiguration
+                            .ConfigurationName;
+                        var vcConfig = (qtPro.VCProject.Configurations as IVCCollection).Item(tmp)
+                            as VCConfiguration;
+                        var def = CompilerToolWrapper.Create(vcConfig)?.GetPreprocessorDefinitions();
+                        if (!string.IsNullOrEmpty(def)
+                            && def.IndexOf("QT_PLUGIN", StringComparison.Ordinal) > -1) {
+                            QtProject.MarkAsQtPlugin(qtPro);
+                        }
 
                         qtPro.SetQtEnvironment();
                         ApplyPostImportSteps(qtPro);
@@ -222,18 +219,19 @@
             if (ok)
                 ok = xmlProject.UpdateProjectFormatVersion();
 
-            if (!ok) {
-                Messages.Print(
-                    SR.GetString("ImportProject_CannotConvertProject", projectFile.Name));
+            if (ok) {
+                xmlProject.Save();
+                // Initialize Qt variables
+                xmlProject.BuildTarget("QtVarsDesignTime");
+            } else {
+                Messages.Print($"Could not convert project file {projectFile.Name} to Qt/MSBuild.");
             }
-            xmlProject.Save();
-
-            // Initialize Qt variables
-            xmlProject.BuildTarget("QtVarsDesignTime");
         }
 
         private static void ApplyPostImportSteps(QtProject qtProject)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             qtProject.RemoveResFilesFromGeneratedFilesFilter();
             qtProject.TranslateFilterNames();
 
@@ -249,32 +247,38 @@
 
         private FileInfo RunQmake(FileInfo mainInfo, string ext, bool recursive, VersionInformation vi)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var name = mainInfo.Name.Remove(mainInfo.Name.IndexOf('.'));
 
-            var VCInfo = new FileInfo(mainInfo.DirectoryName + "\\" + name + ext);
-
-            if (!VCInfo.Exists || DialogResult.Yes == MessageBox.Show(SR.GetString("ExportProject_ProjectExistsRegenerateOrReuse", VCInfo.Name),
-                SR.GetString("ProjectExists"), MessageBoxButtons.YesNo, MessageBoxIcon.Question)) {
-                Messages.Print("--- (Import): Generating new project of " + mainInfo.Name + " file");
-
-                var waitDialog = WaitDialog.Start(
-                    "Open Qt Project File",
-                    "Generating Visual Studio project...", delay: 2);
-
-                var qmake = new QMakeImport(vi, mainInfo.FullName, recursive, dteObject);
-                int exitCode = qmake.Run(setVCVars: true);
-                waitDialog.Stop();
-
-                if (exitCode == 0)
-                    return VCInfo;
+            var vcxproj = new FileInfo(mainInfo.DirectoryName + "\\" + name + ext);
+            if (vcxproj.Exists) {
+                var result = MessageBox.Show($@"{vcxproj.Name} already exists. Select 'OK' to " +
+                    "regenerate the file or 'Cancel' to quit importing the project.",
+                    "Project file already exists.",
+                    MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
+                if (result == DialogResult.Cancel)
+                    return null;
             }
 
+            Messages.Print("--- (Import): Generating new project of " + mainInfo.Name + " file");
+
+            var waitDialog = WaitDialog.Start("Open Qt Project File",
+                "Generating Visual Studio project...", delay: 2);
+
+            var qmake = new QMakeImport(vi, mainInfo.FullName, recursive, dteObject);
+            int exitCode = qmake.Run(setVCVars: true);
+
+            waitDialog.Stop();
+
+            if (exitCode == 0)
+                return vcxproj;
             return null;
         }
 
         private static bool CheckQtVersion(VersionInformation vi)
         {
-            if (!vi.qt5Version) {
+            if (vi.qtMajor < 5) {
                 Messages.DisplayWarningMessage(SR.GetString("ExportProject_EditProjectFileManually"));
                 return false;
             }
diff --git a/QtVsTools.Core/QMake.cs b/QtVsTools.Core/QMake.cs
index 4c0a985..3ee46d5 100644
--- a/QtVsTools.Core/QMake.cs
+++ b/QtVsTools.Core/QMake.cs
@@ -32,23 +32,24 @@
 using System.IO;
 using System.Linq;
 using System.Text;
-using QtVsTools.VisualStudio;
 
 namespace QtVsTools.Core
 {
+    using VisualStudio;
+
     public abstract class QMake
     {
         public Dictionary<string, string> Vars { get; protected set; }
         public string OutputFile { get; protected set; }
-        public uint DebugLevel { get; protected set; }
+        private uint DebugLevel { get; set; }
         public string TemplatePrefix { get; protected set; }
         public bool Recursive { get; protected set; }
         public string ProFile { get; protected set; }
         public string Query { get; protected set; }
         public bool DisableWarnings { get; set; }
 
-        protected VersionInformation QtVersion { get; private set; }
-        protected EnvDTE.DTE Dte { get; private set; }
+        protected VersionInformation QtVersion { get; }
+        private EnvDTE.DTE Dte { get; }
 
         public QMake(VersionInformation qtVersion, EnvDTE.DTE dte = null)
         {
@@ -196,14 +197,27 @@
                         exitCode = qmakeProc.ExitCode;
                         InfoExit(qmakeProc);
                     }
-                } catch (Exception e) {
-                    ErrMsg(string.Format("Exception \"{0}\":\r\n{1}",
-                        e.Message,
-                        e.StackTrace));
+                } catch (Exception exception) {
+                    exception.Log();
                 }
             }
             return exitCode;
         }
+
+        public static bool Exists(string path)
+        {
+            var possibleQMakePaths = new[] {
+                // Path points to qmake.exe
+                path,
+                // Path points to folder containing qmake.exe
+                Path.Combine(path, "qmake.exe"),
+                // Path points to folder containing bin\qmake.exe
+                Path.Combine(path, "bin", "qmake.exe"),
+            };
+            return possibleQMakePaths.Where(p => File.Exists(p)
+                && Path.GetFileName(p).Equals("qmake.exe", StringComparison.OrdinalIgnoreCase))
+                .Any();
+        }
     }
 
     public class QMakeImport : QMake
diff --git a/QtVsTools.Core/QMakeConf.cs b/QtVsTools.Core/QMakeConf.cs
index c66a6c6..c719314 100644
--- a/QtVsTools.Core/QMakeConf.cs
+++ b/QtVsTools.Core/QMakeConf.cs
@@ -29,13 +29,14 @@
 using System;
 using System.Collections;
 using System.IO;
+using Microsoft.VisualStudio.Shell;
 
 namespace QtVsTools.Core
 {
     public class QMakeConf
     {
-        public Hashtable Entries { get; private set; }
-        public string QMakeSpecDirectory { get; private set; }
+        public Hashtable Entries { get; }
+        public string QMakeSpecDirectory { get; }
 
         public QMakeConf(VersionInformation versionInfo, QMakeQuery qmakeQuery = null)
         {
@@ -64,6 +65,17 @@
 
                 qmakeConf = Path.Combine(qtPrefix, qtArchData, "mkspecs", qmakeXSpec, "qmake.conf");
 
+                if (!File.Exists(qmakeConf)) {
+                    // Check if this is a shadow build of Qt.
+                    qtPrefix = qmakeQuery["QT_INSTALL_PREFIX/src"];
+                    if (string.IsNullOrEmpty(qtPrefix))
+                        throw new QtVSException("qmake error: no value for QT_INSTALL_PREFIX/src");
+                    qtArchData = qmakeQuery["QT_INSTALL_ARCHDATA/src"];
+                    if (string.IsNullOrEmpty(qtArchData))
+                        throw new QtVSException("qmake error: no value for QT_INSTALL_ARCHDATA/src");
+
+                    qmakeConf = Path.Combine(qtPrefix, qtArchData, "mkspecs", qmakeXSpec, "qmake.conf");
+                }
                 if (!File.Exists(qmakeConf))
                     throw new QtVSException("qmake.conf expected at " + qmakeConf + " not found");
             }
diff --git a/QtVsTools.Core/QMakeQuery.cs b/QtVsTools.Core/QMakeQuery.cs
index 2dc1be5..1534deb 100644
--- a/QtVsTools.Core/QMakeQuery.cs
+++ b/QtVsTools.Core/QMakeQuery.cs
@@ -26,18 +26,15 @@
 **
 ****************************************************************************/
 
-using System;
 using System.Collections.Generic;
 using System.Diagnostics;
-using System.IO;
 using System.Linq;
 using System.Text;
-using System.Threading;
-using QtVsTools.SyntaxAnalysis;
+using Microsoft.VisualStudio.Shell;
 
 namespace QtVsTools.Core
 {
-    using static RegExpr;
+    using static SyntaxAnalysis.RegExpr;
 
     public class QMakeQuery : QMake
     {
@@ -58,7 +55,6 @@
 
         public Dictionary<string, string> QueryAllValues()
         {
-            string result = string.Empty;
             stdOutput = new StringBuilder();
             Query = " ";
 
@@ -78,16 +74,20 @@
         {
             get
             {
-                string value = string.Empty;
-                if (Properties.TryGetValue(name, out value))
+                if (Properties.TryGetValue(name, out string value))
                     return value;
-                else
-                    return null;
+                return null;
             }
         }
 
         Dictionary<string, string> _Properties;
-        Dictionary<string, string> Properties => _Properties ?? (_Properties = QueryAllValues());
+        Dictionary<string, string> Properties
+        {
+            get
+            {
+                return _Properties ?? (_Properties = QueryAllValues());
+            }
+        }
 
         Parser _PropertyParser;
         Parser PropertyParser
diff --git a/QtVsTools.Core/QrcPrefix.cs b/QtVsTools.Core/QrcPrefix.cs
index 79686a5..bb11eec 100644
--- a/QtVsTools.Core/QrcPrefix.cs
+++ b/QtVsTools.Core/QrcPrefix.cs
@@ -34,7 +34,7 @@
     {
         public string Prefix { get; set; }
         public string Language { get; set; }
-        public List<QrcItem> Items { get; private set; }
+        public List<QrcItem> Items { get; }
 
         public QrcPrefix()
         {
diff --git a/QtVsTools.Core/QtConfig.cs b/QtVsTools.Core/QtConfig.cs
index d3a3682..5cb6974 100644
--- a/QtVsTools.Core/QtConfig.cs
+++ b/QtVsTools.Core/QtConfig.cs
@@ -44,17 +44,18 @@
     /// </summary>
     class QtConfig
     {
-        public BuildType BuildType { get; private set; }
+        public BuildType BuildType { get; }
 
-        public string LibInfix { get; private set; }
+        public string LibInfix { get; }
 
-        public bool Is64Bit { get; private set; }
+        public bool Is64Bit { get; }
 
-        public string Namespace { get; private set; }
+        public string Namespace { get; }
 
-        public uint VersionMajor { get; private set; }
-        public uint VersionMinor { get; private set; }
-        public uint VersionPatch { get; private set; }
+        public uint VersionMajor { get; }
+        public uint VersionMinor { get; }
+        public uint VersionPatch { get; }
+        public string VersionString { get; }
 
         public QtConfig(string qtdir)
         {
@@ -110,6 +111,8 @@
                         Is64Bit = (data == "x86_64");
                     } else if (name == "QT_NAMESPACE") {
                         Namespace = data;
+                    } else if (name == "QT_VERSION") {
+                        VersionString = data;
                     } else if (name == "QT_MAJOR_VERSION") {
                         if (uint.TryParse(data, out uint versionMajor))
                             VersionMajor = versionMajor;
diff --git a/QtVsTools.Core/QtModule.cs b/QtVsTools.Core/QtModule.cs
index 812b6d5..d4ad594 100644
--- a/QtVsTools.Core/QtModule.cs
+++ b/QtVsTools.Core/QtModule.cs
@@ -28,7 +28,6 @@
 
 using System;
 using System.Collections.Generic;
-using System.IO;
 
 namespace QtVsTools.Core
 {
@@ -38,12 +37,12 @@
         public bool Selectable;
         public List<string> Defines = new List<string>();
         public string LibraryPrefix = string.Empty;
-        public bool HasDLL = true;
         public List<string> AdditionalLibraries = new List<string>();
         public List<string> AdditionalLibrariesDebug = new List<string>();
         public List<string> IncludePath = new List<string>();
         public string proVarQT;
         public string proVarCONFIG;
+        private string majorVersion;
 
         public string LibRelease
         {
@@ -51,7 +50,7 @@
             {
                 return
                     LibraryPrefix.StartsWith("Qt", StringComparison.Ordinal)
-                        ? "Qt5" + LibraryPrefix.Substring(2) + ".lib"
+                        ? "Qt" + majorVersion + LibraryPrefix.Substring(2) + ".lib"
                         : LibraryPrefix + ".lib";
             }
         }
@@ -62,14 +61,15 @@
             {
                 return
                     LibraryPrefix.StartsWith("Qt", StringComparison.Ordinal)
-                        ? "Qt5" + LibraryPrefix.Substring(2) + "d.lib"
+                        ? "Qt" + majorVersion + LibraryPrefix.Substring(2) + "d.lib"
                         : LibraryPrefix + "d.lib";
             }
         }
 
-        public QtModule(int id)
+        public QtModule(int id, string major)
         {
             Id = id;
+            majorVersion = major;
         }
 
         public int Id { get; } = -1;
@@ -90,7 +90,7 @@
             var libs = new List<string>();
             var libName = LibraryPrefix;
             if (libName.StartsWith("Qt", StringComparison.Ordinal))
-                libName = "Qt5" + libName.Substring(2);
+                libName = "Qt" + majorVersion + libName.Substring(2);
             libName += libInfix;
             if (isDebugCfg)
                 libName += "d";
diff --git a/QtVsTools.Core/QtModules.cs b/QtVsTools.Core/QtModules.cs
index 0b1bdde..8634ece 100644
--- a/QtVsTools.Core/QtModules.cs
+++ b/QtVsTools.Core/QtModules.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -38,37 +38,58 @@
 {
     public class QtModules
     {
-        private static QtModules instance = new QtModules();
-        private readonly Dictionary<int, QtModule> modules = new Dictionary<int, QtModule>();
+        public static QtModules Instance { get; } = new QtModules();
 
-        public static QtModules Instance
-        {
-            get { return instance; }
-        }
+        private List<QtModule> qt5list = null, qt6list = null;
+        private readonly Dictionary<int, QtModule> qt5modules = new Dictionary<int, QtModule>();
+        private readonly Dictionary<int, QtModule> qt6modules = new Dictionary<int, QtModule>();
 
-        public QtModule Module(int id)
+        public QtModule Module(int id, uint major)
         {
-            QtModule module;
-            modules.TryGetValue(id, out module);
+            QtModule module = null;
+            if (major < 6)
+                qt5modules.TryGetValue(id, out module);
+            if (major == 6)
+                qt6modules.TryGetValue(id, out module);
+            if (major > 6)
+                throw new QtVSException("Unsupported Qt version.");
             return module;
         }
 
-        public List<QtModule> GetAvailableModules()
+        public List<QtModule> GetAvailableModules(uint major)
         {
-            var lst = new List<QtModule>(modules.Count);
-            foreach (var entry in modules)
-                lst.Add(entry.Value);
-            return lst;
+            if (major < 6) {
+                if (qt5list == null) {
+                    qt5list = new List<QtModule>(qt5modules.Count);
+                    foreach (var entry in qt5modules)
+                        qt5list.Add(entry.Value);
+                }
+                return qt5list;
+            }
+            if (major == 6) {
+                if (qt6list == null) {
+                    qt6list = new List<QtModule>(qt6modules.Count);
+                    foreach (var entry in qt6modules)
+                        qt6list.Add(entry.Value);
+                }
+                return qt6list;
+            }
+            if (major > 6)
+                throw new QtVSException("Unsupported Qt version.");
+            return null;
         }
 
         private QtModules()
         {
-            var uri = new Uri(
-                System.Reflection.Assembly.GetExecutingAssembly().EscapedCodeBase);
-            var pkgInstallPath = Path.GetDirectoryName(
-                Uri.UnescapeDataString(uri.AbsolutePath)) + @"\";
+            var uri = new Uri(System.Reflection.Assembly.GetExecutingAssembly().EscapedCodeBase);
+            var pkgInstallPath = Path.GetDirectoryName(Uri.UnescapeDataString(uri.AbsolutePath));
 
-            var modulesFile = Path.Combine(pkgInstallPath, "qtmodules.xml");
+            FillModules(Path.Combine(pkgInstallPath, "qtmodules.xml"), "5", ref qt5modules);
+            FillModules(Path.Combine(pkgInstallPath, "qt6modules.xml"), "6", ref qt6modules);
+        }
+
+        private void FillModules(string modulesFile, string major, ref Dictionary<int, QtModule> dict)
+        {
             if (!File.Exists(modulesFile))
                 return;
 
@@ -85,11 +106,10 @@
 
             foreach (var xModule in xml.Elements("QtVsTools").Elements("Module")) {
                 int id = (int)xModule.Attribute("Id");
-                QtModule module = new QtModule(id);
+                QtModule module = new QtModule(id, major);
                 module.Name = (string)xModule.Element("Name");
                 module.Selectable = ((string)xModule.Element("Selectable") == "true");
                 module.LibraryPrefix = (string)xModule.Element("LibraryPrefix");
-                module.HasDLL = ((string)xModule.Element("HasDLL") == "true");
                 module.proVarQT = (string)xModule.Element("proVarQT");
                 module.proVarCONFIG = (string)xModule.Element("proVarCONFIG");
                 module.IncludePath = xModule.Elements("IncludePath")
@@ -106,7 +126,7 @@
                     Messages.Print("\r\nCritical error: incorrect format of qtmodules.xml");
                     throw new QtVSException("qtmodules.xml");
                 }
-                modules.Add(id, module);
+                dict.Add(id, module);
             }
         }
     }
diff --git a/QtVsTools.Core/QtMsBuild.cs b/QtVsTools.Core/QtMsBuild.cs
index 45ce0b9..02a1d99 100644
--- a/QtVsTools.Core/QtMsBuild.cs
+++ b/QtVsTools.Core/QtMsBuild.cs
@@ -26,17 +26,17 @@
 **
 ****************************************************************************/
 
+using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Text;
-using System;
-using System.IO;
-
-using CommandLineParser = QtVsTools.Core.CommandLine.Parser;
-using CommandLineOption = QtVsTools.Core.CommandLine.Option;
 
 namespace QtVsTools.Core.QtMsBuild
 {
+    using CommandLineParser = CommandLine.Parser;
+    using CommandLineOption = CommandLine.Option;
+
     public interface IVSMacroExpander
     {
         string ExpandString(string stringToExpand);
@@ -84,8 +84,7 @@
 
     public class QtMsBuildContainer
     {
-
-        IPropertyStorageProvider provider;
+        readonly IPropertyStorageProvider provider;
         public QtMsBuildContainer(IPropertyStorageProvider provider)
         {
             this.provider = provider;
@@ -198,16 +197,15 @@
             return provider.GetProjectConfiguration(GetProject(), configName);
         }
 
-        Dictionary<string, ItemPropertyChange> itemPropertyChanges
+        readonly Dictionary<string, ItemPropertyChange> itemPropertyChanges
             = new Dictionary<string, ItemPropertyChange>();
-        Dictionary<string, List<ItemPropertyChange>> itemPropertyChangesGrouped
+        readonly Dictionary<string, List<ItemPropertyChange>> itemPropertyChangesGrouped
             = new Dictionary<string, List<ItemPropertyChange>>();
         bool pendingChanges = false;
 
         void AddChange(ItemPropertyChange newChange)
         {
-            ItemPropertyChange oldChange;
-            if (itemPropertyChanges.TryGetValue(newChange.Key, out oldChange)) {
+            if (itemPropertyChanges.TryGetValue(newChange.Key, out ItemPropertyChange oldChange)) {
                 if (oldChange.GroupKey == newChange.GroupKey) {
                     oldChange.CopyFrom(newChange);
                     return;
@@ -509,7 +507,8 @@
 
         #region QtRcc
         static QtRcc qtRccInstance;
-        public static QtRcc QtRccInstance
+
+        private static QtRcc QtRccInstance
         {
             get
             {
@@ -558,7 +557,8 @@
 
         #region QtRepc
         static QtRepc qtRepcInstance;
-        public static QtRepc QtRepcInstance
+
+        private static QtRepc QtRepcInstance
         {
             get
             {
@@ -607,7 +607,8 @@
 
         #region QtUic
         static QtUic qtUicInstance;
-        public static QtUic QtUicInstance
+
+        private static QtUic QtUicInstance
         {
             get
             {
@@ -658,10 +659,10 @@
 
     public abstract class QtTool
     {
-        protected CommandLineParser parser;
-        protected CommandLineOption outputOption;
-        protected CommandLineOption helpOption;
-        protected CommandLineOption versionOption;
+        protected readonly CommandLineParser parser;
+        private readonly CommandLineOption outputOption;
+        private CommandLineOption helpOption;
+        private CommandLineOption versionOption;
 
         protected QtTool(bool defaultInputOutput = true)
         {
@@ -779,7 +780,7 @@
             AdditionalDependencies,
         }
 
-        Dictionary<Property, CommandLineOption> options
+        readonly Dictionary<Property, CommandLineOption> options
             = new Dictionary<Property, CommandLineOption>();
 
         public QtMoc() : base()
@@ -881,14 +882,13 @@
         {
             properties = new Dictionary<Property, string>();
 
-            string qtDir, inputPath, outputPath;
             if (!ParseCommandLine(
                 commandLine,
                 macros,
                 ToolExecName,
-                out qtDir,
-                out inputPath,
-                out outputPath)) {
+                out string qtDir,
+                out string inputPath,
+                out string outputPath)) {
                 return false;
             }
 
@@ -1078,7 +1078,7 @@
             AdditionalDependencies,
         }
 
-        Dictionary<Property, CommandLineOption> options
+        readonly Dictionary<Property, CommandLineOption> options
             = new Dictionary<Property, CommandLineOption>();
 
         public QtRcc() : base()
@@ -1130,14 +1130,13 @@
         {
             properties = new Dictionary<Property, string>();
 
-            string qtDir, inputPath, outputPath;
             if (!ParseCommandLine(
                 commandLine,
                 macros,
                 ToolExecName,
-                out qtDir,
-                out inputPath,
-                out outputPath)) {
+                out string qtDir,
+                out string inputPath,
+                out string outputPath)) {
                 return false;
             }
 
@@ -1157,8 +1156,7 @@
                 properties[Property.Root] = parser.Value(options[Property.Root]);
 
             if (parser.IsSet(options[Property.Compression])) {
-                int level;
-                if (!int.TryParse(parser.Value(options[Property.Compression]), out level))
+                if (!int.TryParse(parser.Value(options[Property.Compression]), out int level))
                     return false;
                 if (level < 1 || 9 < level)
                     return false;
@@ -1272,7 +1270,7 @@
             PrintDebug,
         }
 
-        Dictionary<Property, CommandLineOption> options
+        readonly Dictionary<Property, CommandLineOption> options
             = new Dictionary<Property, CommandLineOption>();
 
         public QtRepc() : base(defaultInputOutput: false)
@@ -1330,14 +1328,13 @@
         {
             properties = new Dictionary<Property, string>();
 
-            string qtDir, inputPath, outputPath;
             if (!ParseCommandLine(
                 commandLine,
                 macros,
                 ToolExecName,
-                out qtDir,
-                out inputPath,
-                out outputPath)) {
+                out string qtDir,
+                out string inputPath,
+                out string outputPath)) {
                 return false;
             }
 
@@ -1385,8 +1382,8 @@
                 GenerateCommandLineOption(cmd, options[Property.InputFileType], inputType);
 
             var outputType = container.GetPropertyValue(propertyStorage, Property.OutputFileType);
-            if (!string.IsNullOrEmpty(inputType))
-                GenerateCommandLineOption(cmd, options[Property.InputFileType], inputType);
+            if (!string.IsNullOrEmpty(outputType))
+                GenerateCommandLineOption(cmd, options[Property.OutputFileType], outputType);
 
             string value = container.GetPropertyValue(propertyStorage, Property.IncludePath);
             if (!string.IsNullOrEmpty(value))
@@ -1436,7 +1433,7 @@
             AdditionalDependencies,
         }
 
-        Dictionary<Property, CommandLineOption> options
+        readonly Dictionary<Property, CommandLineOption> options
             = new Dictionary<Property, CommandLineOption>();
 
         public QtUic() : base()
@@ -1473,14 +1470,13 @@
         {
             properties = new Dictionary<Property, string>();
 
-            string qtDir, inputPath, outputPath;
             if (!ParseCommandLine(
                 commandLine,
                 macros,
                 ToolExecName,
-                out qtDir,
-                out inputPath,
-                out outputPath)) {
+                out string qtDir,
+                out string inputPath,
+                out string outputPath)) {
                 return false;
             }
 
diff --git a/QtVsTools.Core/QtProject.cs b/QtVsTools.Core/QtProject.cs
index 613b4e5..a935f54 100644
--- a/QtVsTools.Core/QtProject.cs
+++ b/QtVsTools.Core/QtProject.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -26,22 +26,22 @@
 **
 ****************************************************************************/
 
-using EnvDTE;
-using Microsoft.VisualStudio.VCProjectEngine;
 using System;
-using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Text;
 using System.Text.RegularExpressions;
-using System.Threading.Tasks;
 using System.Windows.Forms;
 using System.Xml;
-using QtVsTools.Core.QtMsBuild;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.VCProjectEngine;
+using EnvDTE;
 
 namespace QtVsTools.Core
 {
+    using QtMsBuild;
+
     /// <summary>
     /// QtProject holds the Qt specific properties for a Visual Studio project.
     /// There exists at most one QtProject per EnvDTE.Project.
@@ -54,13 +54,14 @@
         private VCProject vcPro;
         private MocCmdChecker mocCmdChecker;
         private Array lastConfigurationRowNames;
-        private static Dictionary<Project, QtProject> instances = new Dictionary<Project, QtProject>();
-        private QtMsBuildContainer qtMsBuild;
+        private static readonly Dictionary<Project, QtProject> instances = new Dictionary<Project, QtProject>();
+        private readonly QtMsBuildContainer qtMsBuild;
 
         public static QtVsTools.VisualStudio.IProjectTracker ProjectTracker { get; set; }
 
         public static QtProject Create(VCProject vcProject)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
             return Create((Project)vcProject.Object);
         }
 
@@ -81,6 +82,8 @@
 
         private QtProject(Project project)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (project == null)
                 throw new QtVSException(SR.GetString("QtProject_CannotConstructWithoutValidProject"));
             envPro = project;
@@ -105,35 +108,10 @@
                 return string.Empty;
             try {
                 return config.GetEvaluatedPropertyValue(itemType + "RuleName");
-            } catch (Exception e) {
-                System.Diagnostics.Debug.WriteLine(
-                    e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
+            } catch (Exception exception) {
+                exception.Log();
                 return string.Empty;
             }
-        }
-
-        public static string GetRuleName(VCProject project, string itemType)
-        {
-            if (project == null)
-                return string.Empty;
-            var configs = project.Configurations as IVCCollection;
-            if (configs.Count == 0)
-                return string.Empty;
-            try {
-                var firstConfig = configs.Item(1) as VCConfiguration;
-                if (firstConfig == null)
-                    return string.Empty;
-                return GetRuleName(firstConfig, itemType);
-            } catch (Exception e) {
-                System.Diagnostics.Debug.WriteLine(
-                    e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
-                return string.Empty;
-            }
-        }
-
-        public string GetRuleName(string itemType)
-        {
-            return GetRuleName(vcPro, itemType);
         }
 
         public static bool IsQtMsBuildEnabled(VCProject project)
@@ -157,6 +135,8 @@
 
         public static bool IsQtMsBuildEnabled(Project project)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (project == null)
                 return false;
             return IsQtMsBuildEnabled(project.Object as VCProject);
@@ -165,6 +145,8 @@
         private bool? isQtMsBuildEnabled = null;
         public bool IsQtMsBuildEnabled()
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (!isQtMsBuildEnabled.HasValue) {
                 if (vcPro != null)
                     isQtMsBuildEnabled = IsQtMsBuildEnabled(vcPro);
@@ -192,6 +174,8 @@
         {
             get
             {
+                ThreadHelper.ThrowIfNotOnUIThread();
+
                 var ret = false;
                 if (lastConfigurationRowNames == null) {
                     lastConfigurationRowNames = envPro.ConfigurationManager.ConfigurationRowNames as Array;
@@ -213,6 +197,8 @@
         /// <param name="uiFile">name of the ui file</param>
         public string GetUiGeneratedFileName(string uiFile)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var fi = new FileInfo(uiFile);
             var file = fi.Name;
             if (HelperFunctions.IsUicFile(file)) {
@@ -248,8 +234,11 @@
         /// replaced by the value of configName.
         /// <param name="file">full file name of either the header or the source file</param>
         /// <returns></returns>
-        private string GetRelativeMocFilePath(string file, string configName, string platformName)
+        private string GetRelativeMocFilePath(string file, string configName = null,
+                                              string platformName = null)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var fileName = GetMocFileName(file);
             if (fileName == null)
                 return null;
@@ -260,65 +249,38 @@
             return mocDir;
         }
 
-        /// <summary>
-        /// Returns the file name of the generated moc file relative to the
-        /// project directory.
-        /// </summary>
-        /// The returned file path may contain the macros $(ConfigurationName) and $(PlatformName).
-        /// <param name="file">full file name of either the header or the source file</param>
-        /// <returns></returns>
-        private string GetRelativeMocFilePath(string file)
-        {
-            return GetRelativeMocFilePath(file, null, null);
-        }
-
-        /// <summary>
-        /// Marks the specified project as a Qt project.
-        /// </summary>
-        public void MarkAsQtProject()
-        {
-            vcPro.keyword = string.Format("{0}_v{1}",
-                Resources.qtProjectKeyword, Resources.qtProjectFormatVersion);
-        }
-
         public static int GetFormatVersion(VCProject vcPro)
         {
             if (vcPro == null)
                 return 0;
-            if (vcPro.keyword.StartsWith(Resources.qtProjectKeyword,
-                StringComparison.InvariantCultureIgnoreCase)) {
+            if (vcPro.keyword.StartsWith(Resources.qtProjectKeyword, StringComparison.Ordinal))
                 return Convert.ToInt32(vcPro.keyword.Substring(6));
-            } else if (vcPro.keyword.StartsWith(Resources.qtProjectV2Keyword,
-                StringComparison.InvariantCultureIgnoreCase)) {
+            if (vcPro.keyword.StartsWith(Resources.qtProjectV2Keyword, StringComparison.Ordinal))
                 return 200;
-            } else {
-                return 0;
-            }
+            return 0;
         }
 
         public static int GetFormatVersion(Project pro)
         {
-            if (pro == null)
-                return 0;
-            return GetFormatVersion(pro.Object as VCProject);
+            ThreadHelper.ThrowIfNotOnUIThread();
+            return GetFormatVersion(pro?.Object as VCProject);
         }
 
-        public int FormatVersion { get { return GetFormatVersion(Project); } }
-
-        public string GetPropertyValue(string propName)
+        public int FormatVersion
         {
-            return GetPropertyValue(Project, propName);
-        }
-
-        public string GetPropertyValue(string configName, string platformName, string propName)
-        {
-            return GetPropertyValue(Project, configName, platformName, propName);
+            get
+            {
+                ThreadHelper.ThrowIfNotOnUIThread();
+                return GetFormatVersion(Project);
+            }
         }
 
         public static string GetPropertyValue(
             EnvDTE.Project dteProject,
             string propName)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var activeConfig = dteProject.ConfigurationManager?.ActiveConfiguration;
             if (activeConfig == null)
                 return null;
@@ -331,6 +293,8 @@
             EnvDTE.Configuration dteConfig,
             string propName)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (dteProject == null || dteConfig == null)
                 return null;
             return GetPropertyValue(
@@ -338,16 +302,6 @@
                 dteConfig.ConfigurationName,
                 dteConfig.PlatformName,
                 propName);
-        }
-
-        public static string GetPropertyValue(
-            EnvDTE.Project dteProject,
-            string configName,
-            string platformName,
-            string propName)
-        {
-            return GetPropertyValue(
-                dteProject.Object as VCProject, configName, platformName, propName);
         }
 
         public static string GetPropertyValue(
@@ -374,123 +328,10 @@
             return vcConfig.GetEvaluatedPropertyValue(propName);
         }
 
-        public void AddDefine(string define, uint bldConf)
-        {
-            foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
-                var compiler = CompilerToolWrapper.Create(config);
-
-                if (((!IsDebugConfiguration(config)) && ((bldConf & BuildConfig.Release) != 0)) ||
-                    ((IsDebugConfiguration(config)) && ((bldConf & BuildConfig.Debug) != 0))) {
-                    compiler.AddPreprocessorDefinition(define);
-                }
-            }
-        }
-
-        public void AddModule(int id)
-        {
-            if (HasModule(id))
-                return;
-
-            var vm = QtVersionManager.The();
-            var versionInfo = vm.GetVersionInfo(Project);
-            if (versionInfo == null)
-                versionInfo = vm.GetVersionInfo(vm.GetDefaultVersion());
-
-            foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
-
-                var info = QtModules.Instance.Module(id);
-                if (FormatVersion >= Resources.qtMinFormatVersion_Settings) {
-                    var config3 = config as VCConfiguration3;
-                    if (config3 == null)
-                        continue;
-                    if (!string.IsNullOrEmpty(info.proVarQT)) {
-                        var qtModulesValue = config.GetUnevaluatedPropertyValue("QtModules");
-                        var qtModules = new HashSet<string>(
-                            !string.IsNullOrEmpty(qtModulesValue)
-                                ? qtModulesValue.Split(';')
-                                : new string[] { });
-                        qtModules.UnionWith(info.proVarQT.Split(' '));
-                        config3.SetPropertyValue(Resources.projLabelQtSettings, true,
-                            "QtModules", string.Join(";", qtModules));
-                    }
-                    // In V3 project format, compiler and linker options
-                    // required by modules are set by Qt/MSBuild.
-                    continue;
-                }
-
-                var compiler = CompilerToolWrapper.Create(config);
-                var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
-
-                if (compiler != null) {
-                    foreach (var define in info.Defines)
-                        compiler.AddPreprocessorDefinition(define);
-
-                    var incPathList = info.GetIncludePath();
-                    foreach (var incPath in incPathList)
-                        compiler.AddAdditionalIncludeDirectories(incPath);
-                }
-                if (linker != null) {
-                    var moduleLibs = info.GetLibs(IsDebugConfiguration(config), versionInfo);
-                    var linkerWrapper = new LinkerToolWrapper(linker);
-                    var additionalDeps = linkerWrapper.AdditionalDependencies;
-                    var dependenciesChanged = false;
-                    if (additionalDeps == null || additionalDeps.Count == 0) {
-                        additionalDeps = moduleLibs;
-                        dependenciesChanged = true;
-                    } else {
-                        foreach (var moduleLib in moduleLibs) {
-                            if (!additionalDeps.Contains(moduleLib)) {
-                                additionalDeps.Add(moduleLib);
-                                dependenciesChanged = true;
-                            }
-                        }
-                    }
-                    if (dependenciesChanged)
-                        linkerWrapper.AdditionalDependencies = additionalDeps;
-                }
-            }
-        }
-
-        public void RemoveModule(int id)
-        {
-            foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
-                var compiler = CompilerToolWrapper.Create(config);
-                var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
-
-                var info = QtModules.Instance.Module(id);
-                if (compiler != null) {
-                    foreach (var define in info.Defines)
-                        compiler.RemovePreprocessorDefinition(define);
-                    var additionalIncludeDirs = compiler.AdditionalIncludeDirectories;
-                    if (additionalIncludeDirs != null) {
-                        var lst = new List<string>(additionalIncludeDirs);
-                        foreach (var includePath in info.IncludePath) {
-                            lst.Remove(includePath);
-                            lst.Remove('\"' + includePath + '\"');
-                        }
-                        compiler.AdditionalIncludeDirectories = lst;
-                    }
-                }
-                if (linker != null && linker.AdditionalDependencies != null) {
-                    var linkerWrapper = new LinkerToolWrapper(linker);
-                    var vm = QtVersionManager.The();
-                    var versionInfo = vm.GetVersionInfo(Project);
-                    if (versionInfo == null)
-                        versionInfo = vm.GetVersionInfo(vm.GetDefaultVersion());
-
-                    var moduleLibs = info.GetLibs(IsDebugConfiguration(config), versionInfo);
-                    var additionalDependencies = linkerWrapper.AdditionalDependencies;
-                    var dependenciesChanged = false;
-                    foreach (var moduleLib in moduleLibs)
-                        dependenciesChanged |= additionalDependencies.Remove(moduleLib);
-                    if (dependenciesChanged)
-                        linkerWrapper.AdditionalDependencies = additionalDependencies;
-                }
-            }
-        }
-
         public void UpdateModules(VersionInformation oldVersion, VersionInformation newVersion)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
                 var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
 
@@ -500,7 +341,7 @@
                         var additionalDependencies = linkerWrapper.AdditionalDependencies;
 
                         var libsDesktop = new List<string>();
-                        foreach (var module in QtModules.Instance.GetAvailableModules()) {
+                        foreach (var module in QtModules.Instance.GetAvailableModules(newVersion.qtMajor)) {
                             if (HasModule(module.Id))
                                 libsDesktop.AddRange(module.AdditionalLibraries);
                         }
@@ -538,133 +379,11 @@
             }
         }
 
+        // TODO: remove once all callers are moved into Legacy namespace
         public bool HasModule(int id)
         {
-            var foundInIncludes = false;
-            var foundInLibs = false;
-
-            var vm = QtVersionManager.The();
-            var versionInfo = vm.GetVersionInfo(Project);
-            if (versionInfo == null)
-                versionInfo = vm.GetVersionInfo(vm.GetDefaultVersion());
-            if (versionInfo == null)
-                return false; // neither a default or project Qt version
-            var info = QtModules.Instance.Module(id);
-            if (info == null)
-                return false;
-
-            foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
-                var compiler = CompilerToolWrapper.Create(config);
-                var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
-
-                if (compiler != null) {
-                    if (compiler.GetAdditionalIncludeDirectories() == null)
-                        continue;
-                    var incPathList = info.GetIncludePath();
-                    var includeDirs = compiler.GetAdditionalIncludeDirectoriesList();
-                    foundInIncludes = (incPathList.Count > 0);
-                    foreach (var incPath in incPathList) {
-                        var fixedIncludeDir = FixFilePathForComparison(incPath);
-                        if (!includeDirs.Any(dir =>
-                            FixFilePathForComparison(dir) == fixedIncludeDir)) {
-                            foundInIncludes = false;
-                            break;
-                        }
-                    }
-                }
-
-                if (foundInIncludes)
-                    break;
-
-                List<string> libs = null;
-                if (linker != null) {
-                    var linkerWrapper = new LinkerToolWrapper(linker);
-                    libs = linkerWrapper.AdditionalDependencies;
-                }
-
-                if (libs != null) {
-                    var moduleLibs = info.GetLibs(IsDebugConfiguration(config), versionInfo);
-                    foundInLibs = moduleLibs.All(moduleLib => libs.Contains(moduleLib));
-                }
-            }
-            return foundInIncludes || foundInLibs;
-        }
-
-        public void WriteProjectBasicConfigurations(uint type, bool usePrecompiledHeader)
-        {
-            WriteProjectBasicConfigurations(type, usePrecompiledHeader, null);
-        }
-
-        public void WriteProjectBasicConfigurations(uint type, bool usePrecompiledHeader, VersionInformation vi)
-        {
-            var configType = ConfigurationTypes.typeApplication;
-            var targetExtension = ".exe";
-            string qtVersion = null;
-            var vm = QtVersionManager.The();
-            if (vi == null) {
-                qtVersion = vm.GetDefaultVersion();
-                vi = vm.GetVersionInfo(qtVersion);
-            }
-
-            switch (type & TemplateType.ProjectType) {
-            case TemplateType.DynamicLibrary:
-                configType = ConfigurationTypes.typeDynamicLibrary;
-                targetExtension = ".dll";
-                break;
-            case TemplateType.StaticLibrary:
-                configType = ConfigurationTypes.typeStaticLibrary;
-                targetExtension = ".lib";
-                break;
-            }
-
-            foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
-                config.ConfigurationType = configType;
-                var compiler = CompilerToolWrapper.Create(config);
-                var linker = (VCLinkerTool)((IVCCollection)config.Tools).Item("VCLinkerTool");
-                var librarian = (VCLibrarianTool)((IVCCollection)config.Tools).Item("VCLibrarianTool");
-
-                if (linker != null) {
-                    if ((type & TemplateType.ConsoleSystem) != 0)
-                        linker.SubSystem = subSystemOption.subSystemConsole;
-                    else
-                        linker.SubSystem = subSystemOption.subSystemWindows;
-
-                    linker.OutputFile = "$(OutDir)\\$(ProjectName)" + targetExtension;
-                } else {
-                    librarian.OutputFile = "$(OutDir)\\$(ProjectName)" + targetExtension;
-                }
-
-                if ((type & TemplateType.PluginProject) != 0)
-                    compiler.AddPreprocessorDefinition("QT_PLUGIN");
-
-                var isDebugConfiguration = false;
-                if (config.Name.StartsWith("Release", StringComparison.Ordinal)) {
-                    compiler.SetDebugInformationFormat(debugOption.debugDisabled);
-                    compiler.RuntimeLibrary = runtimeLibraryOption.rtMultiThreadedDLL;
-                } else if (config.Name.StartsWith("Debug", StringComparison.Ordinal)) {
-                    isDebugConfiguration = true;
-                    compiler.SetOptimization(optimizeOption.optimizeDisabled);
-                    compiler.SetDebugInformationFormat(debugOption.debugEnabled);
-                    compiler.RuntimeLibrary = runtimeLibraryOption.rtMultiThreadedDebugDLL;
-                }
-
-                compiler.SetTreatWChar_tAsBuiltInType(true);
-
-                if (linker != null)
-                    linker.GenerateDebugInformation = isDebugConfiguration;
-
-                if (usePrecompiledHeader)
-                    UsePrecompiledHeaders(config);
-            }
-            if ((type & TemplateType.PluginProject) != 0)
-                MarkAsDesignerPluginProject();
-        }
-
-        public void MarkAsDesignerPluginProject()
-        {
-            Project.Globals["IsDesignerPlugin"] = true.ToString();
-            if (!Project.Globals.get_VariablePersists("IsDesignerPlugin"))
-                Project.Globals.set_VariablePersists("IsDesignerPlugin", true);
+            ThreadHelper.ThrowIfNotOnUIThread();
+            return Legacy.QtProject.HasModule(envPro, id);
         }
 
         public void AddUic4BuildStepMsBuild(
@@ -672,8 +391,7 @@
             string description,
             string outputFile)
         {
-            var file = config.File as VCFile;
-            if (file != null)
+            if (config.File is VCFile file)
                 file.ItemType = QtUic.ItemTypeName;
             qtMsBuild.SetItemProperty(config, QtUic.Property.ExecutionDescription, description);
             qtMsBuild.SetItemProperty(config, QtUic.Property.OutputFile, outputFile);
@@ -701,6 +419,8 @@
         /// <param name="file">file</param>
         public void AddUic4BuildStep(VCFile file)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (GetFormatVersion(vcPro) >= Resources.qtMinFormatVersion_Settings) {
                 file.ItemType = QtUic.ItemTypeName;
                 return;
@@ -736,7 +456,7 @@
                     }
                 }
                 if (toolSettings == CustomTool.CustomBuildStep && !uiFileExists)
-                    AddFileInFilter(Filters.GeneratedFiles(), uiFile);
+                    AddFileInFilter(Filters.GeneratedFiles(), uiFile, false);
             } catch {
                 throw new QtVSException(SR.GetString("QtProject_CannotAddUicStep", file.FullPath));
             }
@@ -796,15 +516,15 @@
         public string GetDefines(VCFileConfiguration conf)
         {
             var defines = string.Empty;
-            var propsFile = conf.Tool as IVCRulePropertyStorage;
-            var projectConfig = conf.ProjectConfiguration as VCConfiguration;
-            var propsProject = projectConfig.Rules.Item("CL") as IVCRulePropertyStorage;
-            if (propsFile != null) {
+            if (conf.Tool is IVCRulePropertyStorage propsFile) {
                 try {
                     defines = propsFile.GetUnevaluatedPropertyValue("PreprocessorDefinitions");
                 } catch { }
             }
-            if (string.IsNullOrEmpty(defines) && propsProject != null) {
+
+            var projectConfig = conf.ProjectConfiguration as VCConfiguration;
+            if (string.IsNullOrEmpty(defines)
+                && projectConfig?.Rules.Item("CL") is IVCRulePropertyStorage propsProject) {
                 try {
                     defines = propsProject.GetUnevaluatedPropertyValue("PreprocessorDefinitions");
                 } catch { }
@@ -846,12 +566,11 @@
             var projectConfig = conf.ProjectConfiguration as VCConfiguration;
             includeList.AddRange(GetIncludesFromCompilerTool(CompilerToolWrapper.Create(projectConfig)));
 
-            var propertySheets = projectConfig.PropertySheets as IVCCollection;
-            if (propertySheets != null) {
+            if (projectConfig.PropertySheets is IVCCollection propertySheets) {
                 foreach (VCPropertySheet sheet in propertySheets)
                     includeList.AddRange(GetIncludesFromPropertySheet(sheet));
             }
-
+            
             var ompModified = new List<string>();
             string sDir = "$(SolutionDir)";
             foreach (string inc in includeList) {
@@ -884,8 +603,7 @@
         private List<string> GetIncludesFromPropertySheet(VCPropertySheet sheet)
         {
             var includeList = GetIncludesFromCompilerTool(CompilerToolWrapper.Create(sheet));
-            var propertySheets = sheet.PropertySheets as IVCCollection;
-            if (propertySheets != null) {
+            if (sheet.PropertySheets is IVCCollection propertySheets) {
                 foreach (VCPropertySheet subSheet in propertySheets)
                     includeList.AddRange(GetIncludesFromPropertySheet(subSheet));
             }
@@ -903,18 +621,10 @@
             return new List<string>();
         }
 
-        private static bool IsDebugConfiguration(VCConfiguration conf)
-        {
-            var tool = CompilerToolWrapper.Create(conf);
-            if (tool != null) {
-                return tool.RuntimeLibrary == runtimeLibraryOption.rtMultiThreadedDebug
-                    || tool.RuntimeLibrary == runtimeLibraryOption.rtMultiThreadedDebugDLL;
-            }
-            return false;
-        }
-
         private string GetPCHMocOptions(VCFile file, CompilerToolWrapper compiler)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             // As .moc files are included, we should not add anything there
             if (!HelperFunctions.IsHeaderFile(file.Name))
                 return string.Empty;
@@ -941,12 +651,13 @@
             VCFileConfiguration workFileConfig,
             VCFile mocFile)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var hasDifferentMocFilePerConfig =
                 QtVSIPSettings.HasDifferentMocFilePerConfig(envPro);
             var hasDifferentMocFilePerPlatform =
                 QtVSIPSettings.HasDifferentMocFilePerPlatform(envPro);
 
-            var workFile = workFileConfig.File as VCFile;
             var mocFileName = GetMocFileName(sourceFile.FullPath);
             var mocableIsCPP = HelperFunctions.IsMocFile(mocFileName);
             var vcConfig = workFileConfig.ProjectConfiguration as VCConfiguration;
@@ -1025,6 +736,8 @@
             string includes,
             string description)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var workFile = workFileConfig.File as VCFile;
             var mocFileName = GetMocFileName(sourceFile.FullPath);
             var mocableIsCPP = HelperFunctions.IsMocFile(mocFileName);
@@ -1068,6 +781,7 @@
                 + mocFileName + "))";
             var regExp = new Regex(pattern);
             var matchList = regExp.Matches(tool.Outputs.Replace(ProjectMacros.Name, baseFileName));
+
             if (matchList.Count > 0) {
                 if (matchList[0].Length > 0)
                     outputMocFile = matchList[0].ToString();
@@ -1202,6 +916,8 @@
             string includes,
             string description)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var baseFileName = sourceFile.Name.Remove(sourceFile.Name.LastIndexOf('.'));
             var outputMocFile = GetRelativeMocFilePath(sourceFile.FullPath);
             var outputMocPath = Path.GetDirectoryName(outputMocFile);
@@ -1233,7 +949,8 @@
             VCFileConfiguration workConfig,
             CustomTool toolSettings)
         {
-            var workFile = workConfig.File as VCFile;
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var mocFileName = GetMocFileName(sourceFile.FullPath);
             var mocableIsCPP = HelperFunctions.IsMocFile(mocFileName);
             var vcConfig = workConfig.ProjectConfiguration as VCConfiguration;
@@ -1316,6 +1033,8 @@
         /// <param name="file">file</param>
         public void AddMocStep(VCFile file)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (GetFormatVersion(vcPro) >= Resources.qtMinFormatVersion_Settings) {
                 file.ItemType = QtMoc.ItemTypeName;
                 if (HelperFunctions.IsSourceFile(file.FullPath)) {
@@ -1343,8 +1062,7 @@
                     File.WriteAllText(cbtFullPath, string.Format(
                         "This is a dummy file needed to create {0}", mocFileName));
                     file = AddFileInSubfilter(Filters.GeneratedFiles(), null, cbtFullPath, true);
-                    var mocFileItem = file.Object as ProjectItem;
-                    if (mocFileItem != null)
+                    if (file.Object is ProjectItem mocFileItem)
                         HelperFunctions.EnsureCustomBuildToolAvailable(mocFileItem);
                 }
 
@@ -1417,6 +1135,8 @@
 
         public bool HasMocStep(VCFile file, string mocOutDir = null)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (file.ItemType == QtMoc.ItemTypeName)
                 return true;
 
@@ -1452,6 +1172,8 @@
 
         public void RefreshRccSteps()
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             Messages.Print("\r\n=== Update rcc steps ===");
             var files = GetResourceFiles();
 
@@ -1482,6 +1204,8 @@
 
         public void RefreshRccSteps(string oldRccDir)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             RefreshRccSteps();
             UpdateCompilerIncludePaths(oldRccDir, QtVSIPSettings.GetRccDirectory(envPro));
         }
@@ -1493,8 +1217,7 @@
             string nameOnly,
             string qrcCppFile)
         {
-            var file = vfc.File as VCFile;
-            if (file != null)
+            if (vfc.File is VCFile file)
                 file.ItemType = QtRcc.ItemTypeName;
             qtMsBuild.SetItemProperty(vfc,
                 QtRcc.Property.ExecutionDescription, "Rcc'ing " + ProjectMacros.FileName + "...");
@@ -1509,16 +1232,15 @@
             string nameOnly,
             string qrcCppFile)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var qrcFile = vfc.File as VCFile;
             var rccOptsCfg = rccOpts;
             var cmdLine = string.Empty;
 
             var cbt = HelperFunctions.GetCustomBuildTool(vfc);
-
             cbt.AdditionalDependencies = filesInQrcFile;
-
             cbt.Description = "Rcc'ing " + ProjectMacros.FileName + "...";
-
             cbt.Outputs = qrcCppFile.Replace(nameOnly, ProjectMacros.Name);
 
             cmdLine += "\"" + Resources.rcc4Command + "\""
@@ -1539,6 +1261,8 @@
 
         public void UpdateRccStep(VCFile qrcFile, RccOptions rccOpts)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (GetFormatVersion(vcPro) >= Resources.qtMinFormatVersion_Settings) {
                 qrcFile.ItemType = QtRcc.ItemTypeName;
                 return;
@@ -1548,8 +1272,6 @@
                 IsQtMsBuildEnabled() ? CustomTool.MSBuildTarget : CustomTool.CustomBuildStep;
 
             var vcpro = (VCProject)qrcFile.project;
-            var dteObject = ((Project)vcpro.Object).DTE;
-
             var qtPro = Create(vcpro);
             var parser = new QrcParser(qrcFile.FullPath);
             var filesInQrcFile = ProjectMacros.Path;
@@ -1606,7 +1328,7 @@
             }
         }
 
-        static public void ExcludeFromAllBuilds(VCFile file)
+        public static void ExcludeFromAllBuilds(VCFile file)
         {
             if (file == null)
                 return;
@@ -1672,8 +1394,7 @@
         List<VCFile> GetCppMocFiles(VCFile cppFile)
         {
             List<VCFile> mocFiles = new List<VCFile>();
-            var vcProj = cppFile.project as VCProject;
-            if (vcProj != null) {
+            if (cppFile.project is VCProject vcProj) {
                 mocFiles.AddRange(from VCFile vcFile
                                   in (IVCCollection)vcProj.Files
                                   where vcFile.ItemType == "CustomBuild"
@@ -1697,27 +1418,29 @@
 
         bool HasCppMocFiles(VCFile cppFile)
         {
-            if (!IsQtMsBuildEnabled()) {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            if (!IsQtMsBuildEnabled())
                 return File.Exists(Path.ChangeExtension(cppFile.FullPath, ".cbt"));
-            } else {
-                var vcProj = cppFile.project as VCProject;
-                if (vcProj != null) {
-                    foreach (VCFile vcFile in (IVCCollection)vcProj.Files) {
-                        if (vcFile.ItemType == "CustomBuild") {
-                            if (IsCppMocFileCustomBuild(vcProj, vcFile, cppFile))
-                                return true;
-                        } else if (vcFile.ItemType == QtMoc.ItemTypeName) {
-                            if (IsCppMocFileQtMsBuild(vcProj, vcFile, cppFile))
-                                return true;
-                        }
+
+            if (cppFile.project is VCProject vcProj) {
+                foreach (VCFile vcFile in (IVCCollection)vcProj.Files) {
+                    if (vcFile.ItemType == "CustomBuild") {
+                        if (IsCppMocFileCustomBuild(vcProj, vcFile, cppFile))
+                            return true;
+                    } else if (vcFile.ItemType == QtMoc.ItemTypeName) {
+                        if (IsCppMocFileQtMsBuild(vcProj, vcFile, cppFile))
+                            return true;
                     }
                 }
-                return false;
             }
+            return false;
         }
 
         public void RemoveMocStep(VCFile file)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (file.ItemType == QtMoc.ItemTypeName) {
                 RemoveMocStepQtMsBuild(file);
             } else if (HelperFunctions.IsHeaderFile(file.Name)) {
@@ -1756,6 +1479,7 @@
         /// <param name="file">file</param>
         public void RemoveMocStepCustomBuild(VCFile file)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
             try {
                 if (!HasMocStep(file))
                     return;
@@ -1890,14 +1614,11 @@
         public VCFile GetFileFromProject(string fileName)
         {
             fileName = HelperFunctions.NormalizeRelativeFilePath(fileName);
-
-            var nf = fileName;
             if (!HelperFunctions.IsAbsoluteFilePath(fileName))
-                nf = HelperFunctions.NormalizeFilePath(vcPro.ProjectDirectory + "\\" + fileName);
-            nf = nf.ToLower();
+                fileName = HelperFunctions.NormalizeFilePath(vcPro.ProjectDirectory + "\\" + fileName);
 
             foreach (VCFile f in (IVCCollection)vcPro.Files) {
-                if (f.FullPath.ToLower() == nf)
+                if (f.FullPath.Equals(fileName, StringComparison.OrdinalIgnoreCase))
                     return f;
             }
             return null;
@@ -1913,7 +1634,7 @@
         {
             var fi = new FileInfo(HelperFunctions.NormalizeRelativeFilePath(fileName));
             foreach (VCFile f in (IVCCollection)vcPro.Files) {
-                if (string.Equals(f.Name, fi.Name, StringComparison.OrdinalIgnoreCase))
+                if (f.Name.Equals(fi.Name, StringComparison.OrdinalIgnoreCase))
                     yield return f;
             }
         }
@@ -1924,34 +1645,6 @@
             foreach (VCFilter subfilter in (IVCCollection)filter.Filters)
                 tmpList.AddRange(GetAllFilesFromFilter(subfilter));
             return tmpList;
-        }
-
-        /// <summary>
-        /// Adds a file to a filter. If the filter doesn't exist yet, it
-        /// will be created. (Doesn't check for duplicates)
-        /// </summary>
-        /// <param name="filter">fake filter</param>
-        /// <param name="fileName">relative file name</param>
-        /// <returns>A VCFile object of the added file.</returns>
-        public VCFile AddFileInFilter(FakeFilter filter, string fileName)
-        {
-            return AddFileInFilter(filter, fileName, false);
-        }
-
-        public void RemoveItem(ProjectItem item)
-        {
-            foreach (ProjectItem tmpFilter in Project.ProjectItems) {
-                if (tmpFilter.Name == item.Name) {
-                    tmpFilter.Remove();
-                    return;
-                }
-                foreach (ProjectItem tmpItem in tmpFilter.ProjectItems) {
-                    if (tmpItem.Name == item.Name) {
-                        tmpItem.Remove();
-                        return;
-                    }
-                }
-            }
         }
 
         /// <summary>
@@ -1972,7 +1665,8 @@
             return AddFileInSubfilter(filter, subfilterName, fileName, false);
         }
 
-        public VCFile AddFileInSubfilter(FakeFilter filter, string subfilterName, string fileName, bool checkForDuplicates)
+        public VCFile AddFileInSubfilter(FakeFilter filter, string subfilterName, string fileName,
+            bool checkForDuplicates)
         {
             try {
                 var vfilt = FindFilterFromGuid(filter.UniqueIdentifier);
@@ -1981,7 +1675,7 @@
                         // check if user already created this filter... then add guid
                         vfilt = FindFilterFromName(filter.Name);
                         if (vfilt == null)
-                            throw new QtVSException(SR.GetString("QtProject_CannotAddFilter", filter.Name));
+                            throw new QtVSException($"Project cannot add filter {filter.Name}");
                     } else {
                         vfilt = (VCFilter)vcPro.AddFilter(filter.Name);
                     }
@@ -2014,14 +1708,7 @@
                     }
                     if (!subfilterFound) {
                         if (!vfilt.CanAddFilter(subfilterName))
-                            throw new QtVSException(SR.GetString("QtProject_CannotAddFilter", filter.Name));
-
-#if !(VS2017 || VS2019 || VS2022)
-                        // TODO: Enable once the freeze gets fixed in VS.
-                        vfilt = (VCFilter)vfilt.AddFilter(subfilterName);
-                        vfilt.Filter = "cpp;moc";
-                        vfilt.SourceControlFiles = false;
-#endif
+                            throw new QtVSException($"Project cannot add filter {filter.Name}");
                     }
                 }
 
@@ -2034,10 +1721,13 @@
 
                 if (vfilt.CanAddFile(fileName))
                     return (VCFile)(vfilt.AddFile(fileName));
-                throw new QtVSException(SR.GetString("QtProject_CannotAddFile", fileName));
-            } catch {
-                throw new QtVSException(SR.GetString("QtProject_CannotAddFile", fileName));
+                throw new QtVSException($"Cannot add file {fileName} to filter.");
+            } catch (QtVSException) {
+                throw;
+            } catch (Exception e){
+                throw new QtVSException($"Cannot add file {fileName} to filter.", e);
             }
+
         }
 
         /// <summary>
@@ -2165,94 +1855,38 @@
             }
         }
 
-        public void AddDirectories()
+        public static bool IsQtPlugin(Core.QtProject qtPro)
         {
-            try {
-                // resource directory
-                var fi = new FileInfo(envPro.FullName);
-                var dfi = new DirectoryInfo(fi.DirectoryName + "\\" + Resources.resourceDir);
-                dfi.Create();
-            } catch {
-                throw new QtVSException(SR.GetString("QtProject_CannotCreateResourceDir"));
-            }
-            AddFilterToProject(Filters.ResourceFiles());
-        }
+            ThreadHelper.ThrowIfNotOnUIThread();
 
-        public void Finish()
-        {
-            try {
-                var solutionExplorer = dte.Windows.Item(Constants.vsWindowKindSolutionExplorer);
-                if (solutionExplorer != null) {
-                    var hierarchy = (UIHierarchy)solutionExplorer.Object;
-                    var projects = hierarchy.UIHierarchyItems.Item(1).UIHierarchyItems;
+            if (qtPro.FormatVersion < Resources.qtMinFormatVersion_Settings)
+                return false;
 
-                    foreach (UIHierarchyItem itm in projects) {
-                        if (itm.Name == envPro.Name) {
-                            foreach (UIHierarchyItem i in itm.UIHierarchyItems) {
-                                if (i.Name == Filters.GeneratedFiles().Name)
-                                    i.UIHierarchyItems.Expanded = false;
-                            }
-                            break;
-                        }
-                    }
-                }
-            } catch { }
-
-            ProjectTracker?.AddProject(envPro);
-        }
-
-        public bool IsDesignerPluginProject()
-        {
-            var b = false;
-            if (Project.Globals.get_VariablePersists("IsDesignerPlugin")) {
-                var s = (string)Project.Globals["IsDesignerPlugin"];
-                try {
-                    b = bool.Parse(s);
-                } catch { }
-            }
-            return b;
-        }
-
-        /// <summary>
-        /// Adds a file to a specified filter in a project.
-        /// </summary>
-        /// <param name="destName">name of the file in the project (relative to the project directory)</param>
-        /// <param name="filter">filter</param>
-        /// <returns>VCFile</returns>
-        public VCFile AddFileToProject(string destName, FakeFilter filter)
-        {
-            VCFile file = null;
-            if (filter != null)
-                file = AddFileInFilter(filter, destName);
-            else
-                file = (VCFile)vcPro.AddFile(destName);
-
-            if (file == null)
-                return null;
-
-            if (HelperFunctions.IsHeaderFile(file.Name)) {
-                foreach (VCConfiguration config in (IVCCollection)vcPro.Configurations) {
-                    var compiler = CompilerToolWrapper.Create(config);
-                    if (compiler == null)
-                        continue;
-
-                    var paths = compiler.GetAdditionalIncludeDirectoriesList();
-                    var fi = new FileInfo(file.FullPath);
-                    var relativePath = HelperFunctions.GetRelativePath(ProjectDir, fi.Directory.ToString());
-                    var fixedRelativePath = FixFilePathForComparison(relativePath);
-                    if (!paths.Any(p => FixFilePathForComparison(p) == fixedRelativePath))
-                        compiler.AddAdditionalIncludeDirectories(relativePath);
+            foreach (VCConfiguration config in qtPro.VCProject.Configurations as IVCCollection) {
+                if ((config.Rules.Item("QtRule10_Settings") as IVCRulePropertyStorage)
+                        .GetEvaluatedPropertyValue("QtPlugin") == "true") {
+                    return true;
                 }
             }
-            return file;
+            return false;
+        }
+
+        public static void MarkAsQtPlugin(Core.QtProject qtPro)
+        {
+            foreach (VCConfiguration config in qtPro.VCProject.Configurations as IVCCollection) {
+                (config.Rules.Item("QtRule10_Settings") as IVCRulePropertyStorage)
+                    .SetPropertyValue("QtPlugin", "true");
+            }
         }
 
         /// <summary>
         /// adjusts the whitespaces, tabs in the given file according to VS settings
         /// </summary>
         /// <param name="file"></param>
-        public void AdjustWhitespace(string file)
+        public static void AdjustWhitespace(DTE dte, string file)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (!File.Exists(file))
                 return;
 
@@ -2299,89 +1933,6 @@
             return whitespaces;
         }
 
-        /// <summary>
-        /// Copy a file to the projects folder. Does not add the file to the project.
-        /// </summary>
-        /// <param name="srcFile">full name of the file to add</param>
-        /// <param name="destFolder">the name of the project folder</param>
-        /// <param name="destName">name of the file in the project (relative to the project directory)</param>
-        /// <returns>full name of the destination file</returns>
-        public static string CopyFileToFolder(string srcFile, string destFolder, string destName)
-        {
-            var fullDestName = destFolder + "\\" + destName;
-            var fi = new FileInfo(fullDestName);
-
-            var replace = true;
-            if (File.Exists(fullDestName)) {
-                if (DialogResult.No == MessageBox.Show(SR.GetString("QtProject_FileExistsInProjectFolder", destName)
-                    , SR.GetString("Resources_QtVsTools"), MessageBoxButtons.YesNo, MessageBoxIcon.Question)) {
-                    replace = false;
-                }
-            }
-
-            if (replace) {
-                if (!fi.Directory.Exists)
-                    fi.Directory.Create();
-                File.Copy(srcFile, fullDestName, true);
-                var attribs = File.GetAttributes(fullDestName);
-                File.SetAttributes(fullDestName, attribs & (~FileAttributes.ReadOnly));
-            }
-            return fi.FullName;
-        }
-
-        public static void ReplaceTokenInFile(string file, string token, string replacement)
-        {
-            var text = string.Empty;
-            try {
-                var reader = new StreamReader(file);
-                text = reader.ReadToEnd();
-                reader.Close();
-            } catch (Exception e) {
-                Messages.DisplayErrorMessage(
-                    SR.GetString("QtProject_CannotReplaceTokenRead", token, replacement, e.ToString()));
-                return;
-            }
-
-            try {
-                if (token.ToUpper() == "%PRE_DEF%" && !Char.IsLetter(replacement[0]))
-                    replacement = "_" + replacement;
-
-                text = text.Replace(token, replacement);
-                var writer = new StreamWriter(file);
-                writer.Write(text);
-                writer.Close();
-            } catch (Exception e) {
-                Messages.DisplayErrorMessage(
-                    SR.GetString("QtProject_CannotReplaceTokenWrite", token, replacement, e.ToString()));
-            }
-        }
-
-        public void RepairGeneratedFilesStructure()
-        {
-            DeleteGeneratedFiles();
-
-            var files = new ConcurrentBag<VCFile>();
-            Task.WaitAll(
-                Task.Run(() =>
-                    Parallel.ForEach(((IVCCollection)vcPro.Files).Cast<VCFile>(), file =>
-                    {
-                        var name = file.Name;
-                        if (!HelperFunctions.IsHeaderFile(name) && !HelperFunctions.IsSourceFile(name))
-                            return;
-                        if (HelperFunctions.HasQObjectDeclaration(file))
-                            files.Add(file);
-                    })
-                )
-            );
-
-            qtMsBuild.BeginSetItemProperties();
-            foreach (var file in files) {
-                RemoveMocStep(file);
-                AddMocStep(file);
-            }
-            qtMsBuild.EndSetItemProperties();
-        }
-
         public void TranslateFilterNames()
         {
             var filters = vcPro.Filters as IVCCollection;
@@ -2402,37 +1953,10 @@
             }
         }
 
-        public static string CreateQrcFile(string projectDir, string className, string destName)
-        {
-            var fullDestName = projectDir + "\\" + destName;
-
-            if (!File.Exists(fullDestName)) {
-                FileStream s = null;
-                try {
-                    s = File.Open(fullDestName, FileMode.CreateNew);
-                    if (s.CanWrite) {
-                        using (var sw = new StreamWriter(s)) {
-                            s = null;
-                            sw.WriteLine("<RCC>");
-                            sw.WriteLine("    <qresource prefix=\"" + className + "\">");
-                            sw.WriteLine("    </qresource>");
-                            sw.WriteLine("</RCC>");
-                        }
-                    }
-                } finally {
-                    if (s != null)
-                        s.Dispose();
-                }
-                var attribs = File.GetAttributes(fullDestName);
-                File.SetAttributes(fullDestName, attribs & (~FileAttributes.ReadOnly));
-            }
-
-            var fi = new FileInfo(fullDestName);
-            return fi.FullName;
-        }
-
         public void AddActiveQtBuildStep(string version, string defFile = null)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (FormatVersion < Resources.qtMinFormatVersion_ClProperties)
                 return;
 
@@ -2463,6 +1987,8 @@
 
         private void UpdateCompilerIncludePaths(string oldDir, string newDir)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var fixedOldDir = FixFilePathForComparison(oldDir);
             var dirs = new[] {
                 FixFilePathForComparison(QtVSIPSettings.GetUicDirectory(envPro)),
@@ -2516,6 +2042,8 @@
 
         public void UpdateUicSteps(string oldUicDir, bool update_inc_path)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             Messages.Print("\r\n=== Update uic steps ===");
             var vcFilter = FindFilterFromGuid(Filters.GeneratedFiles().UniqueIdentifier);
             if (vcFilter != null) {
@@ -2538,7 +2066,7 @@
 
             qtMsBuild.BeginSetItemProperties();
             foreach (var file in files) {
-                if (HelperFunctions.IsUicFile(file.Name) && !IsUic3File(file)) {
+                if (HelperFunctions.IsUicFile(file.Name)) {
                     AddUic4BuildStep(file);
                     Messages.Print("Update uic step for " + file.Name + ".");
                     ++updatedFiles;
@@ -2549,42 +2077,6 @@
                 UpdateCompilerIncludePaths(oldUicDir, QtVSIPSettings.GetUicDirectory(envPro));
 
             Messages.Print("\r\n=== " + updatedFiles + " uic steps updated. ===\r\n");
-        }
-
-        private static bool IsUic3File(VCFile file)
-        {
-            foreach (VCFileConfiguration config in (IVCCollection)file.FileConfigurations) {
-                var tool = HelperFunctions.GetCustomBuildTool(config);
-                if (tool == null)
-                    return false;
-                if (tool.CommandLine.IndexOf("uic3.exe", StringComparison.OrdinalIgnoreCase) > -1)
-                    return true;
-            }
-            return false;
-        }
-
-        public bool UsePrecompiledHeaders(VCConfiguration config)
-        {
-            var compiler = CompilerToolWrapper.Create(config);
-            return UsePrecompiledHeaders(compiler);
-        }
-
-        private bool UsePrecompiledHeaders(CompilerToolWrapper compiler)
-        {
-            try {
-                compiler.SetUsePrecompiledHeader(pchOption.pchUseUsingSpecific);
-                var pcHeaderThrough = GetPrecompiledHeaderThrough();
-                if (string.IsNullOrEmpty(pcHeaderThrough))
-                    pcHeaderThrough = "stdafx.h";
-                compiler.SetPrecompiledHeaderThrough(pcHeaderThrough);
-                var pcHeaderFile = GetPrecompiledHeaderFile();
-                if (string.IsNullOrEmpty(pcHeaderFile))
-                    pcHeaderFile = ".\\$(ConfigurationName)/" + Project.Name + ".pch";
-                compiler.SetPrecompiledHeaderFile(pcHeaderFile);
-                return true;
-            } catch {
-                return false;
-            }
         }
 
         public bool UsesPrecompiledHeaders()
@@ -2637,32 +2129,6 @@
             return null;
         }
 
-        public string GetPrecompiledHeaderFile()
-        {
-            foreach (VCConfiguration config in vcPro.Configurations as IVCCollection) {
-                var file = GetPrecompiledHeaderFile(config);
-                if (!string.IsNullOrEmpty(file))
-                    return file;
-            }
-            return null;
-        }
-
-        public static string GetPrecompiledHeaderFile(VCConfiguration config)
-        {
-            var compiler = CompilerToolWrapper.Create(config);
-            return GetPrecompiledHeaderFile(compiler);
-        }
-
-        private static string GetPrecompiledHeaderFile(CompilerToolWrapper compiler)
-        {
-            try {
-                var file = compiler.GetPrecompiledHeaderFile();
-                if (!string.IsNullOrEmpty(file))
-                    return file;
-            } catch { }
-            return null;
-        }
-
         public static void SetPCHOption(VCFile vcFile, pchOption option)
         {
             foreach (VCFileConfiguration config in vcFile.FileConfigurations as IVCCollection) {
@@ -2692,6 +2158,8 @@
         /// <returns></returns>
         private VCFile GetGeneratedMocFile(string fileName, VCFileConfiguration fileConfig)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (QtVSIPSettings.HasDifferentMocFilePerConfig(envPro)
                 || QtVSIPSettings.HasDifferentMocFilePerPlatform(envPro)) {
                 var projectConfig = (VCConfiguration)fileConfig.ProjectConfiguration;
@@ -2763,6 +2231,8 @@
 
         public void RefreshMocSteps()
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             // Ignore when using shared compiler properties
             if (GetFormatVersion(vcPro) >= Resources.qtMinFormatVersion_ClProperties)
                 return;
@@ -2790,6 +2260,7 @@
 
         public void RefreshMocStep(VCFile vcfile)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
             RefreshMocStep(vcfile, true);
         }
 
@@ -2803,6 +2274,8 @@
         /// <param name="vcfile"></param>
         private void RefreshMocStep(VCFile vcfile, bool singleFile)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var isHeaderFile = HelperFunctions.IsHeaderFile(vcfile.FullPath);
             if (!isHeaderFile && !HelperFunctions.IsSourceFile(vcfile.FullPath))
                 return;
@@ -2942,6 +2415,8 @@
 
         public void OnExcludedFromBuildChanged(VCFile vcFile, VCFileConfiguration vcFileCfg)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             // Update the ExcludedFromBuild flags of the mocced file
             // according to the ExcludedFromBuild flag of the mocable source file.
             var moccedFileName = GetMocFileName(vcFile.Name);
@@ -3011,6 +2486,8 @@
 
         public void UpdateMocSteps(string oldMocDir)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             Messages.Print("\r\n=== Update moc steps ===");
             var orgFiles = new List<VCFile>();
             var abandonedMocFiles = new List<string>();
@@ -3053,8 +2530,8 @@
                 try {
                     RemoveMocStep(file);
                     AddMocStep(file);
-                } catch (QtVSException e) {
-                    Messages.Print(e.Message);
+                } catch (QtVSException exception) {
+                    exception.Log();
                     continue;
                 }
                 Messages.Print("Moc step updated successfully for " + file.Name + ".");
@@ -3073,6 +2550,8 @@
 
         private void Clean()
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var solutionConfigs = envPro.DTE.Solution.SolutionBuild.SolutionConfigurations;
             var backup = new List<KeyValuePair<SolutionContext, bool>>();
             foreach (SolutionConfiguration config in solutionConfigs) {
@@ -3125,47 +2604,6 @@
             }
         }
 
-        public bool isWinRT()
-        {
-            try {
-                var vcProject = Project.Object as VCProject;
-                var vcConfigs = vcProject.Configurations as IVCCollection;
-                var vcConfig = vcConfigs.Item(1) as VCConfiguration;
-                var appType = vcConfig.GetEvaluatedPropertyValue("ApplicationType");
-                if (appType == "Windows Store")
-                    return true;
-            } catch { }
-            return false;
-        }
-
-        public bool PromptChangeQtVersion(string oldVersion, string newVersion)
-        {
-            var versionManager = QtVersionManager.The();
-            var viOld = versionManager.GetVersionInfo(oldVersion);
-            var viNew = versionManager.GetVersionInfo(newVersion);
-
-            if (viOld == null || viNew == null)
-                return true;
-
-            var oldIsWinRt = viOld.isWinRT();
-            var newIsWinRt = viNew.isWinRT();
-
-            if (newIsWinRt == oldIsWinRt || newIsWinRt == isWinRT())
-                return true;
-
-            var promptCaption = string.Format("Change Qt Version ({0})", Project.Name);
-            var promptText = string.Format(
-                "Changing Qt version from {0} to {1}.\r\n" +
-                "Project might not build. Are you sure?",
-                newIsWinRt ? "Win32" : "WinRT",
-                newIsWinRt ? "WinRT" : "Win32"
-                );
-
-            return (MessageBox.Show(
-                promptText, promptCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Warning)
-                == DialogResult.Yes);
-        }
-
         /// <summary>
         /// Changes the Qt version of this project.
         /// </summary>
@@ -3175,6 +2613,8 @@
         /// <returns>true, if the operation performed successfully</returns>
         public bool ChangeQtVersion(string oldVersion, string newVersion, ref bool newProjectCreated)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             newProjectCreated = false;
             var versionManager = QtVersionManager.The();
             var viNew = versionManager.GetVersionInfo(newVersion);
@@ -3243,6 +2683,8 @@
 
         public bool SelectSolutionPlatform(string platformName)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             foreach (SolutionConfiguration solutionCfg in dte.Solution.SolutionBuild.SolutionConfigurations) {
                 var contexts = solutionCfg.SolutionContexts;
                 for (var i = 1; i <= contexts.Count; ++i) {
@@ -3268,6 +2710,8 @@
         public void CreatePlatform(string oldPlatform, string newPlatform,
                                    VersionInformation viOld, VersionInformation viNew, ref bool newProjectCreated)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             try {
                 var cfgMgr = envPro.ConfigurationManager;
                 cfgMgr.AddPlatform(newPlatform, oldPlatform, true);
@@ -3329,9 +2773,7 @@
             if (genVCFilter == null)
                 return;
 
-            var error = false;
-            error = DeleteFilesFromFilter(genVCFilter);
-            if (error)
+            if (DeleteFilesFromFilter(genVCFilter))
                 Messages.Print(SR.GetString("DeleteGeneratedFilesError"));
         }
 
@@ -3389,7 +2831,7 @@
                 resFile.Remove();
         }
 
-        static private void AddPlatformToVCProj(string projectFileName, string oldPlatformName, string newPlatformName)
+        private static void AddPlatformToVCProj(string projectFileName, string oldPlatformName, string newPlatformName)
         {
             var tempFileName = Path.GetTempFileName();
             var fi = new FileInfo(projectFileName);
@@ -3404,7 +2846,7 @@
             fi.Delete();
         }
 
-        static private void AddPlatformToVCProj(XmlDocument doc, string oldPlatformName, string newPlatformName)
+        private static void AddPlatformToVCProj(XmlDocument doc, string oldPlatformName, string newPlatformName)
         {
             var vsProj = doc.DocumentElement.SelectSingleNode("/VisualStudioProject");
             var platforms = vsProj.SelectSingleNode("Platforms");
@@ -3438,7 +2880,7 @@
             }
         }
 
-        static private void SetTargetMachine(VCLinkerTool linker, VersionInformation versionInfo)
+        private static void SetTargetMachine(VCLinkerTool linker, VersionInformation versionInfo)
         {
             var qMakeLFlagsWindows = versionInfo.GetQMakeConfEntry("QMAKE_LFLAGS_WINDOWS");
             var rex = new Regex("/MACHINE:(\\S+)");
@@ -3476,6 +2918,8 @@
 
         public void CollapseFilter(string filterName)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var solutionExplorer = (UIHierarchy)dte.Windows.Item(Constants.vsext_wk_SProjectWindow).Object;
             if (solutionExplorer.UIHierarchyItems.Count == 0)
                 return;
@@ -3489,6 +2933,8 @@
 
         private UIHierarchyItem FindProjectHierarchyItem(UIHierarchy hierarchy)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (hierarchy.UIHierarchyItems.Count == 0)
                 return null;
 
@@ -3504,6 +2950,8 @@
 
         private UIHierarchyItem FindProjectHierarchyItem(UIHierarchyItem root)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             UIHierarchyItem projectItem = null;
             try {
                 if (root.Name == envPro.Name)
@@ -3524,6 +2972,7 @@
         /// </summary>
         public string GetQtVersion()
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
             return QtVersionManager.The().GetProjectQtVersion(envPro);
         }
 
@@ -3532,6 +2981,7 @@
         /// </summary>
         public void SetQtEnvironment()
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
             SetQtEnvironment(QtVersionManager.The().GetProjectQtVersion(envPro));
         }
 
@@ -3540,6 +2990,7 @@
         /// </summary>
         public void SetQtEnvironment(string qtVersion)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
             SetQtEnvironment(qtVersion, string.Empty);
         }
 
@@ -3548,6 +2999,8 @@
         /// </summary>
         public void SetQtEnvironment(string qtVersion, string solutionConfig, bool build = false)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (string.IsNullOrEmpty(qtVersion))
                 return;
 
@@ -3558,6 +3011,7 @@
             if (qtVersion != "$(QTDIR)")
                 qtDir = QtVersionManager.The().GetInstallPath(qtVersion);
             HelperFunctions.SetEnvironmentVariableEx("QTDIR", qtDir);
+
             try {
                 var propertyAccess = (IVCBuildPropertyStorage)vcPro;
                 var vcprj = envPro.Object as VCProject;
@@ -3590,8 +3044,7 @@
                             debuggerEnv = propertyAccess.GetPropertyValue(
                                 "LocalDebuggerEnvironment", cur_solution, "UserFile");
                             if (!string.IsNullOrEmpty(debuggerEnv)) {
-                                var debugSettings = conf.DebugSettings as VCDebugSettings;
-                                if (debugSettings != null) {
+                                if (conf.DebugSettings is VCDebugSettings debugSettings) {
                                     //Get original value without expanded properties
                                     debuggerEnv = debugSettings.Environment;
                                 }
@@ -3624,9 +3077,8 @@
                 var projProps = vcProj as IVCBuildPropertyStorage;
                 try {
                     return projProps.GetPropertyValue(pszPropName, Config.Name, "UserFile");
-                } catch (Exception e) {
-                    System.Diagnostics.Debug.WriteLine(
-                        e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
+                } catch (Exception exception) {
+                    exception.Log();
                     return string.Empty;
                 }
             }
@@ -3637,9 +3089,8 @@
                 var projProps = vcProj as IVCBuildPropertyStorage;
                 try {
                     projProps.SetPropertyValue(pszPropName, Config.Name, "UserFile", pszPropValue);
-                } catch (Exception e) {
-                    System.Diagnostics.Debug.WriteLine(
-                        e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
+                } catch (Exception exception) {
+                    exception.Log();
                 }
             }
 
@@ -3649,9 +3100,8 @@
                 var projProps = vcProj as IVCBuildPropertyStorage;
                 try {
                     projProps.RemoveProperty(pszPropName, Config.Name, "UserFile");
-                } catch (Exception e) {
-                    System.Diagnostics.Debug.WriteLine(
-                        e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
+                } catch (Exception exception) {
+                    exception.Log();
                 }
             }
         }
@@ -3970,10 +3420,10 @@
         {
             if (propertyStorage == null)
                 return null;
-            if (propertyStorage is VCFileConfiguration)
-                return GetParentProject(propertyStorage as VCFileConfiguration);
-            else if (propertyStorage is VCConfiguration)
-                return GetParentProject(propertyStorage as VCConfiguration);
+            if (propertyStorage is VCFileConfiguration configuration)
+                return GetParentProject(configuration);
+            else if (propertyStorage is VCConfiguration storage)
+                return GetParentProject(storage);
             return null;
         }
 
@@ -4026,8 +3476,7 @@
 
     public class VCMacroExpander : IVSMacroExpander
     {
-        object config;
-
+        readonly object config;
         public VCMacroExpander(object config)
         {
             this.config = config;
@@ -4042,14 +3491,15 @@
 
     public class QtCustomBuildTool
     {
-        QtMsBuildContainer qtMsBuild;
-        VCFileConfiguration vcConfig;
-        VCFile vcFile;
-        VCCustomBuildTool tool;
-        VCMacroExpander macros;
+        readonly QtMsBuildContainer qtMsBuild;
+        readonly VCFileConfiguration vcConfig;
+        readonly VCFile vcFile;
+        readonly VCCustomBuildTool tool;
+        readonly VCMacroExpander macros;
 
         enum FileItemType { Other = 0, CustomBuild, QtMoc, QtRcc, QtRepc, QtUic };
-        FileItemType itemType = FileItemType.Other;
+        readonly FileItemType itemType = FileItemType.Other;
+
         public QtCustomBuildTool(VCFileConfiguration vcConfig, QtMsBuildContainer container = null)
         {
             if (container != null)
diff --git a/QtVsTools.Core/QtVSIPSettings.cs b/QtVsTools.Core/QtVSIPSettings.cs
index bbd3a45..7eb4146 100644
--- a/QtVsTools.Core/QtVSIPSettings.cs
+++ b/QtVsTools.Core/QtVSIPSettings.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -26,11 +26,9 @@
 **
 ****************************************************************************/
 
+using Microsoft.VisualStudio.Shell;
 using Microsoft.VisualStudio.VCProjectEngine;
-using Microsoft.Win32;
-using QtVsTools.Core.QtMsBuild;
-using System;
-using System.Collections;
+using QtVsTools.Common;
 
 namespace QtVsTools.Core
 {
@@ -46,41 +44,26 @@
     {
         public static IQtVsToolsOptions Options { get; set; }
 
-        static Hashtable mocDirCache = new Hashtable();
-        static Hashtable uicDirCache = new Hashtable();
-        static Hashtable rccDirCache = new Hashtable();
-
         public static bool GetDisableAutoMocStepsUpdate()
         {
-            return GetBoolValue(Resources.disableAutoMocStepsUpdateKeyword, false);
-        }
-
-        public static void SaveDisableAutoMocStepsUpdate(bool b)
-        {
-            SetBoolValue(Resources.disableAutoMocStepsUpdateKeyword, b);
+            return QtVSIPSettingsShared.GetBoolValue(Resources.disableAutoMocStepsUpdateKeyword, false);
         }
 
         public static string GetUicDirectory(EnvDTE.Project project)
         {
-            return GetDirectory(project, Resources.uicDirKeyword);
-        }
-
-        public static void SaveUicDirectory(EnvDTE.Project project, string directory)
-        {
-            if (directory == null)
-                SaveDirectory(project, Resources.uicDirKeyword, GetDirectory(project, Resources.uicDirKeyword));
-            else
-                SaveDirectory(project, Resources.uicDirKeyword, directory);
+            ThreadHelper.ThrowIfNotOnUIThread();
+            return QtVSIPSettingsShared.GetDirectory(project, Resources.uicDirKeyword);
         }
 
         public static string GetMocDirectory()
         {
-            return GetDirectory(Resources.mocDirKeyword);
+            return QtVSIPSettingsShared.GetDirectory(Resources.mocDirKeyword);
         }
 
         public static string GetMocDirectory(EnvDTE.Project project)
         {
-            return GetDirectory(project, Resources.mocDirKeyword);
+            ThreadHelper.ThrowIfNotOnUIThread();
+            return QtVSIPSettingsShared.GetDirectory(project, Resources.mocDirKeyword);
         }
 
         public static string GetMocDirectory(
@@ -88,6 +71,8 @@
             string configName,
             string platformName, VCFile vCFile)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             string filePath = null;
             if (vCFile != null)
                 filePath = vCFile.FullPath;
@@ -100,7 +85,9 @@
             string platformName,
             string filePath = null)
         {
-            var dir = GetDirectory(project, Resources.mocDirKeyword);
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            var dir = QtVSIPSettingsShared.GetDirectory(project, Resources.mocDirKeyword);
             if (!string.IsNullOrEmpty(configName)
                 && !string.IsNullOrEmpty(platformName))
                 HelperFunctions.ExpandString(ref dir, project, configName, platformName, filePath);
@@ -109,458 +96,56 @@
 
         public static bool HasDifferentMocFilePerConfig(EnvDTE.Project project)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var mocDir = GetMocDirectory(project);
             return mocDir.Contains("$(ConfigurationName)");
         }
 
         public static bool HasDifferentMocFilePerPlatform(EnvDTE.Project project)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var mocDir = GetMocDirectory(project);
             return mocDir.Contains("$(PlatformName)");
         }
 
-        public static string GetMocOptions()
-        {
-            return GetOption(Resources.mocOptionsKeyword);
-        }
-
         public static string GetMocOptions(EnvDTE.Project project)
         {
-            return GetOption(project, Resources.mocOptionsKeyword);
+            ThreadHelper.ThrowIfNotOnUIThread();
+            return QtVSIPSettingsShared.GetOption(project, Resources.mocOptionsKeyword);
         }
 
         public static bool GetLUpdateOnBuild(EnvDTE.Project project)
         {
-            if (GetProjectQtSetting(project, "QtRunLUpdateOnBuild") == "true")
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            if (QtVSIPSettingsShared.GetProjectQtSetting(project, "QtRunLUpdateOnBuild") == "true")
                 return true;
-            return GetBoolValue(project, Resources.lupdateKeyword);
-        }
-
-        public static string GetLUpdateOptions()
-        {
-            return GetOption(Resources.lupdateOptionsKeyword);
-        }
-
-        static string GetProjectQtSetting(EnvDTE.Project project, string propertyName)
-        {
-            var vcProject = project.Object as VCProject;
-            if (vcProject == null)
-                return null;
-
-            var vcConfigs = vcProject.Configurations as IVCCollection;
-            if (vcConfigs == null)
-                return null;
-
-            var activeConfig = project.ConfigurationManager.ActiveConfiguration;
-            if (activeConfig == null)
-                return null;
-
-            var activeConfigId = string.Format("{0}|{1}",
-                activeConfig.ConfigurationName, activeConfig.PlatformName);
-
-            var props = vcProject as IVCBuildPropertyStorage;
-            if (props == null)
-                return null;
-
-            try {
-                return props.GetPropertyValue(propertyName, activeConfigId, "ProjectFile");
-            } catch {
-                return null;
-            }
-        }
-
-        public static string GetLUpdateOptions(EnvDTE.Project project)
-        {
-            string qtLUpdateOptions = GetProjectQtSetting(project, "QtLUpdateOptions");
-            if (!string.IsNullOrEmpty(qtLUpdateOptions))
-                return qtLUpdateOptions;
-            return GetOption(project, Resources.lupdateOptionsKeyword);
-        }
-
-        public static string GetLReleaseOptions()
-        {
-            return GetOption(Resources.lreleaseOptionsKeyword);
-        }
-
-        public static string GetLReleaseOptions(EnvDTE.Project project)
-        {
-            string qtLReleaseOptions = GetProjectQtSetting(project, "QtLReleaseOptions");
-            if (!string.IsNullOrEmpty(qtLReleaseOptions))
-                return qtLReleaseOptions;
-            return GetOption(project, Resources.lreleaseOptionsKeyword);
-        }
-
-        public static bool GetAskBeforeCheckoutFile()
-        {
-            return GetBoolValue(Resources.askBeforeCheckoutFileKeyword, true);
-        }
-
-        public static void SaveAskBeforeCheckoutFile(bool value)
-        {
-            SetBoolValue(Resources.askBeforeCheckoutFileKeyword, value);
-        }
-
-        public static bool GetDisableCheckoutFiles()
-        {
-            return GetBoolValue(Resources.disableCheckoutFilesKeyword, false);
-        }
-
-        public static void SaveDisableCheckoutFiles(bool value)
-        {
-            SetBoolValue(Resources.disableCheckoutFilesKeyword, value);
-        }
-
-        public static void SaveMocDirectory(EnvDTE.Project project, string directory)
-        {
-            if (directory == null)
-                SaveDirectory(project, Resources.mocDirKeyword, GetDirectory(project, Resources.mocDirKeyword));
-            else
-                SaveDirectory(project, Resources.mocDirKeyword, directory);
-        }
-
-        public static void SaveMocOptions(EnvDTE.Project project, string options)
-        {
-            if (options == null)
-                options = GetMocOptions();
-            SaveOption(project, Resources.mocOptionsKeyword, options);
-        }
-
-        public static void SaveMocOptions(string options)
-        {
-            SaveOption(Resources.mocOptionsKeyword, options);
-        }
-
-        public static void SaveLUpdateOnBuild(EnvDTE.Project project)
-        {
-            SetBoolValue(project, Resources.lupdateKeyword, GetLUpdateOnBuild());
-        }
-
-        public static void SaveLUpdateOnBuild(EnvDTE.Project project, bool value)
-        {
-            SetBoolValue(project, Resources.lupdateKeyword, value);
-        }
-
-        public static void SaveLUpdateOptions(EnvDTE.Project project, string options)
-        {
-            if (options == null)
-                options = GetLUpdateOptions();
-
-            SaveOption(project, Resources.lupdateOptionsKeyword, options);
-        }
-
-        public static void SaveLUpdateOptions(string options)
-        {
-            SaveOption(Resources.lupdateOptionsKeyword, options);
-        }
-
-        public static void SaveLReleaseOptions(EnvDTE.Project project, string options)
-        {
-            if (options == null)
-                options = GetLReleaseOptions();
-            SaveOption(project, Resources.lreleaseOptionsKeyword, options);
-        }
-
-        public static void SaveLReleaseOptions(string options)
-        {
-            SaveOption(Resources.lreleaseOptionsKeyword, options);
+            return QtVSIPSettingsShared.GetBoolValue(project, Resources.lupdateKeyword);
         }
 
         public static string GetRccDirectory(EnvDTE.Project project)
         {
-            return GetDirectory(project, Resources.rccDirKeyword);
-        }
-
-        public static void SaveRccDirectory(string dir)
-        {
-            SaveDirectory(Resources.rccDirKeyword, dir);
-        }
-
-        public static void SaveRccDirectory(EnvDTE.Project project, string directory)
-        {
-            if (directory == null)
-                SaveDirectory(project, Resources.rccDirKeyword, GetDirectory(project, Resources.rccDirKeyword));
-            else
-                SaveDirectory(project, Resources.rccDirKeyword, directory);
-        }
-
-        private static string GetDirectory(string type)
-        {
-            try {
-                var key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\" + Resources.registryPackagePath);
-                if (key != null) {
-                    var path = (string)key.GetValue(type, null);
-                    if (path != null)
-                        return HelperFunctions.NormalizeRelativeFilePath(path);
-                }
-            } catch { }
-            if (type == Resources.mocDirKeyword)
-                return Resources.generatedFilesDir + "\\$(ConfigurationName)";
-            return Resources.generatedFilesDir;
-        }
-
-        private static string GetOption(string type)
-        {
-            try {
-                var key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\" + Resources.registryPackagePath);
-                if (key != null) {
-                    var opt = (string)key.GetValue(type, null);
-                    if (opt != null)
-                        return opt;
-                }
-            } catch { }
-            return null;
-        }
-
-        public static bool GetLUpdateOnBuild()
-        {
-            return GetBoolValue(Resources.lupdateKeyword, false);
+            ThreadHelper.ThrowIfNotOnUIThread();
+            return QtVSIPSettingsShared.GetDirectory(project, Resources.rccDirKeyword);
         }
 
         public static string GetRccDirectory()
         {
-            return GetDirectory(Resources.rccDirKeyword);
+            return QtVSIPSettingsShared.GetDirectory(Resources.rccDirKeyword);
         }
 
         public static string GetUicDirectory()
         {
-            return GetDirectory(Resources.uicDirKeyword);
-        }
-
-        private static string GetDirectory(EnvDTE.Project project, string type)
-        {
-            // check for directory in following order:
-            // - stored in project
-            // - stored in cache
-            // - retrieve from moc/uic steps
-            // - globally defined default directory
-            // - fallback on hardcoded directory
-            if (project != null) {
-                if (project.Globals.get_VariablePersists(type))
-                    return HelperFunctions.NormalizeRelativeFilePath((string)project.Globals[type]);
-
-                try {
-                    if (type == Resources.mocDirKeyword && mocDirCache.Contains(project.FullName))
-                        return (string)mocDirCache[project.FullName];
-                    if (type == Resources.uicDirKeyword && uicDirCache.Contains(project.FullName))
-                        return (string)uicDirCache[project.FullName];
-                    if (type == Resources.rccDirKeyword && rccDirCache.Contains(project.FullName))
-                        return (string)rccDirCache[project.FullName];
-
-                    QtCustomBuildTool tool = null;
-                    string configName = null;
-                    string platformName = null;
-                    var vcpro = (VCProject)project.Object;
-                    foreach (VCFile vcfile in (IVCCollection)vcpro.Files) {
-                        var name = vcfile.Name;
-                        if ((type == Resources.mocDirKeyword && HelperFunctions.IsHeaderFile(name))
-                            || (type == Resources.mocDirKeyword && HelperFunctions.IsMocFile(name))
-                            || (type == Resources.uicDirKeyword && HelperFunctions.IsUicFile(name))
-                            || (type == Resources.rccDirKeyword && HelperFunctions.IsQrcFile(name))) {
-                            foreach (VCFileConfiguration config in (IVCCollection)vcfile.FileConfigurations) {
-                                tool = new QtCustomBuildTool(config);
-                                configName = config.Name.Remove(config.Name.IndexOf('|'));
-                                var vcConfig = config.ProjectConfiguration as VCConfiguration;
-                                var platform = vcConfig.Platform as VCPlatform;
-                                platformName = platform.Name;
-                                if (tool != null && (tool.CommandLine.IndexOf("moc.exe", StringComparison.OrdinalIgnoreCase) != -1
-                                    || (tool.CommandLine.IndexOf("uic.exe", StringComparison.OrdinalIgnoreCase) != -1)
-                                    || (tool.CommandLine.IndexOf("rcc.exe", StringComparison.OrdinalIgnoreCase) != -1)))
-                                    break;
-                                tool = null;
-                            }
-
-                            if (tool != null)
-                                break;
-                        }
-                    }
-
-                    if (tool != null) {
-                        string dir = null;
-                        var lastindex = tool.Outputs.LastIndexOf('\\');
-                        if (tool.Outputs.LastIndexOf('/') > lastindex)
-                            lastindex = tool.Outputs.LastIndexOf('/');
-
-                        if (lastindex == -1)
-                            dir = ".";
-                        else
-                            dir = tool.Outputs.Substring(0, lastindex);
-                        dir = dir.Replace("\"", "");
-
-                        if (type == Resources.mocDirKeyword) {
-                            int index;
-                            if ((index = dir.IndexOf(configName, StringComparison.OrdinalIgnoreCase)) != -1)
-                                dir = dir.Replace(dir.Substring(index, configName.Length), "$(ConfigurationName)");
-                            if ((index = dir.IndexOf(platformName, StringComparison.OrdinalIgnoreCase)) != -1)
-                                dir = dir.Replace(dir.Substring(index, platformName.Length), "$(PlatformName)");
-
-                            mocDirCache.Add(project.FullName, HelperFunctions.NormalizeRelativeFilePath(dir));
-                        } else if (type == Resources.uicDirKeyword)
-                            uicDirCache.Add(project.FullName, HelperFunctions.NormalizeRelativeFilePath(dir));
-                        else if (type == Resources.rccDirKeyword)
-                            rccDirCache.Add(project.FullName, HelperFunctions.NormalizeRelativeFilePath(dir));
-
-                        cleanUpCache(project);
-
-                        return HelperFunctions.NormalizeRelativeFilePath(dir);
-                    }
-                } catch { }
-            }
-
-            return GetDirectory(type);
-        }
-
-        private static string GetOption(EnvDTE.Project project, string type)
-        {
-            // check for directory in following order:
-            // - stored in project
-            // - globally defined default option
-            // - empty options
-            if (project != null && project.Globals.get_VariablePersists(type))
-                return (string)project.Globals[type];
-            return GetOption(type);
-        }
-
-        private static bool GetBoolValue(EnvDTE.Project project, string type)
-        {
-            // check for directory in following order:
-            // - stored in project
-            // - globally defined default option
-            // - empty options
-            if (project != null && project.Globals.get_VariablePersists(type))
-                return Convert.ToInt32(project.Globals[type] as string) > 0;
-            return GetBoolValue(type, false);
-        }
-
-        private static void SaveDirectory(EnvDTE.Project project, string type, string dir)
-        {
-            dir = HelperFunctions.NormalizeRelativeFilePath(dir);
-            project.Globals[type] = dir;
-            if (!project.Globals.get_VariablePersists(type))
-                project.Globals.set_VariablePersists(type, true);
-
-            cleanUpCache(project);
-        }
-
-        private static void SaveOption(EnvDTE.Project project, string type, string option)
-        {
-            project.Globals[type] = option;
-            if (!project.Globals.get_VariablePersists(type))
-                project.Globals.set_VariablePersists(type, true);
-        }
-
-        private static void SetBoolValue(EnvDTE.Project project, string type, bool value)
-        {
-            project.Globals[type] = Convert.ToInt32(value).ToString();
-            if (!project.Globals.get_VariablePersists(type))
-                project.Globals.set_VariablePersists(type, true);
-        }
-
-        public static void SaveUicDirectory(string dir)
-        {
-            SaveDirectory(Resources.uicDirKeyword, dir);
-        }
-
-        public static void SaveMocDirectory(string dir)
-        {
-            SaveDirectory(Resources.mocDirKeyword, dir);
-        }
-
-        public static void SaveLUpdateOnBuild(bool val)
-        {
-            SetBoolValue(Resources.lupdateKeyword, val);
-        }
-
-        public static void cleanUpCache(EnvDTE.Project project)
-        {
-            try {
-                var mocEnumerator = mocDirCache.GetEnumerator();
-                while (mocEnumerator.MoveNext()) {
-                    if (!HelperFunctions.IsProjectInSolution(project.DTE, (string)mocEnumerator.Key)) {
-                        mocDirCache.Remove(mocEnumerator.Key);
-                        mocEnumerator = mocDirCache.GetEnumerator();
-                    }
-                }
-
-                var uicEnumerator = uicDirCache.GetEnumerator();
-                while (uicEnumerator.MoveNext()) {
-                    if (!HelperFunctions.IsProjectInSolution(project.DTE, (string)uicEnumerator.Key)) {
-                        uicDirCache.Remove(uicEnumerator.Key);
-                        uicEnumerator = uicDirCache.GetEnumerator();
-                    }
-                }
-
-                var rccEnumerator = rccDirCache.GetEnumerator();
-                while (rccEnumerator.MoveNext()) {
-                    if (!HelperFunctions.IsProjectInSolution(project.DTE, (string)rccEnumerator.Key)) {
-                        rccDirCache.Remove(rccEnumerator.Key);
-                        rccEnumerator = rccDirCache.GetEnumerator();
-                    }
-                }
-            } catch { }
-        }
-
-        private static void SaveDirectory(string type, string dir)
-        {
-            dir = HelperFunctions.NormalizeRelativeFilePath(dir);
-            var key = Registry.CurrentUser.CreateSubKey("SOFTWARE\\" + Resources.registryPackagePath);
-            if (key == null)
-                return;
-            key.SetValue(type, dir);
-        }
-
-        private static void SaveOption(string type, string option)
-        {
-            var key = Registry.CurrentUser.CreateSubKey("SOFTWARE\\" + Resources.registryPackagePath);
-            if (key == null)
-                return;
-            if (option == null)
-                option = "";
-            key.SetValue(type, option);
+            return QtVSIPSettingsShared.GetDirectory(Resources.uicDirKeyword);
         }
 
         public static bool AutoUpdateUicSteps()
         {
-            if (ValueExists("AutoUpdateUicSteps"))
-                return GetBoolValue("AutoUpdateUicSteps", true);
-            return GetBoolValue("AutoUpdateBuildSteps", true);
-        }
-
-        private static bool GetBoolValue(string key, bool defaultValue)
-        {
-            var regKey = Registry.CurrentUser.OpenSubKey("SOFTWARE\\" + Resources.registryPackagePath);
-            if (regKey == null)
-                return defaultValue;
-            return ((int)regKey.GetValue(key, defaultValue ? 1 : 0)) > 0;
-        }
-
-        private static bool ValueExists(string key)
-        {
-            var regKey = Registry.CurrentUser.OpenSubKey("SOFTWARE\\" + Resources.registryPackagePath);
-            if (regKey != null) {
-                foreach (var s in regKey.GetValueNames()) {
-                    if (s == key)
-                        return true;
-                }
-            }
-            return false;
-        }
-
-        private static void SetBoolValue(string key, bool val)
-        {
-            var regKey = Registry.CurrentUser.CreateSubKey("SOFTWARE\\" + Resources.registryPackagePath);
-            if (regKey == null)
-                return;
-            regKey.SetValue(key, val ? 1 : 0);
-        }
-
-        public static bool GetQmlDebug(EnvDTE.Project project)
-        {
-            return QtProject.Create(project).QmlDebug;
-        }
-
-        public static void SaveQmlDebug(EnvDTE.Project project, bool enabled)
-        {
-            QtProject.Create(project).QmlDebug = enabled;
+            if (QtVSIPSettingsShared.ValueExists("AutoUpdateUicSteps"))
+                return QtVSIPSettingsShared.GetBoolValue("AutoUpdateUicSteps", true);
+            return QtVSIPSettingsShared.GetBoolValue("AutoUpdateBuildSteps", true);
         }
     }
 }
diff --git a/QtVsTools.Core/QtVersionManager.cs b/QtVsTools.Core/QtVersionManager.cs
index 000a198..15a3ae2 100644
--- a/QtVsTools.Core/QtVersionManager.cs
+++ b/QtVsTools.Core/QtVersionManager.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -26,16 +26,14 @@
 **
 ****************************************************************************/
 
-using Microsoft.VisualStudio.VCProjectEngine;
-using Microsoft.Win32;
 using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.IO;
-using System.Linq;
 using System.Threading;
-using QtVsTools.VisualStudio;
-using EnvDTE;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.VCProjectEngine;
+using Microsoft.Win32;
 
 namespace QtVsTools.Core
 {
@@ -45,37 +43,20 @@
     public class QtVersionManager
     {
         private static QtVersionManager instance;
-        private string regVersionPath;
-        private string strVersionKey;
+        private readonly string regVersionPath;
+        private readonly string strVersionKey;
         private Hashtable versionCache;
 
         protected QtVersionManager()
         {
             strVersionKey = "Versions";
             regVersionPath = Resources.registryVersionPath;
-            RefreshVersionNames();
         }
 
-        void RefreshVersionNames()
-        {
-            var rootKeyPath = "SOFTWARE\\" + Resources.registryRootPath;
-            try {
-                using (var rootKey = Registry.CurrentUser.OpenSubKey(rootKeyPath, true))
-                using (var versionsKey = rootKey.OpenSubKey(strVersionKey, true)) {
-                    versionsKey.SetValue("VersionNames", string.Join(";", GetVersions()));
-                }
+        private static readonly EventWaitHandle packageInit = new EventWaitHandle(false, EventResetMode.ManualReset);
+        private static EventWaitHandle packageInitDone = null;
 
-            } catch (Exception e) {
-                Messages.Print(
-                    e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
-            }
-        }
-
-        static EventWaitHandle
-            packageInit = new EventWaitHandle(false, EventResetMode.ManualReset),
-            packageInitDone = null;
-
-        static public QtVersionManager The(EventWaitHandle initDone = null)
+        public static QtVersionManager The(EventWaitHandle initDone = null)
         {
             if (initDone == null) {
                 packageInit.WaitOne();
@@ -92,10 +73,10 @@
 
         public VersionInformation GetVersionInfo(string name)
         {
-            if (name == "$(DefaultQtVersion)")
-                name = GetDefaultVersion();
             if (name == null)
                 return null;
+            if (name == "$(DefaultQtVersion)")
+                name = GetDefaultVersion();
             if (versionCache == null)
                 versionCache = new Hashtable();
 
@@ -111,13 +92,8 @@
 
         public VersionInformation GetVersionInfo(EnvDTE.Project project)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
             return GetVersionInfo(GetProjectQtVersion(project));
-        }
-
-        public void ClearVersionCache()
-        {
-            if (versionCache != null)
-                versionCache.Clear();
         }
 
         public string[] GetVersions()
@@ -130,13 +106,12 @@
             if (qtDir == null)
                 return null;
 
-            qtDir = qtDir.ToLower();
             var versions = GetVersions();
             foreach (var version in versions) {
                 var installPath = GetInstallPath(version);
                 if (installPath == null)
                     continue;
-                if (installPath.ToLower() == qtDir)
+                if (installPath.Equals(qtDir, StringComparison.OrdinalIgnoreCase))
                     return version;
             }
 
@@ -157,84 +132,61 @@
         /// <summary>
         /// Check if all Qt versions are valid and readable.
         /// </summary>
-        /// Also sets the default Qt version to the newest version, if needed.
         /// <param name="errorMessage"></param>
-        /// <returns>true, if we found an invalid version</returns>
-        public bool HasInvalidVersions(out string errorMessage)
+        /// <returns>true, if there are one or more invalid Qt version</returns>
+        public bool HasInvalidVersions(out string errorMessage, out bool defaultVersionInvalid)
         {
-            var validVersions = new Dictionary<string, QtConfig>();
-            var invalidVersions = new List<string>();
+            var defaultVersion = GetDefaultVersionString();
+            defaultVersionInvalid = string.IsNullOrEmpty(defaultVersion);
 
-            foreach (var v in GetVersions()) {
-                if (v == "$(DefaultQtVersion)")
-                    continue;
-
-                var vPath = GetInstallPath(v);
-                if (string.IsNullOrEmpty(vPath)) {
-                    invalidVersions.Add(v);
-                    continue;
-                }
-
-                if (vPath.StartsWith("SSH:") || vPath.StartsWith("WSL:"))
-                    continue;
-
-                var qmakePath = Path.Combine(vPath, "bin", "qmake.exe");
-                if (!File.Exists(qmakePath))
-                    qmakePath = Path.Combine(vPath, "qmake.exe");
-                if (!File.Exists(qmakePath)) {
-                    invalidVersions.Add(v);
-                    continue;
-                }
-
-                validVersions[v] = new QtConfig(vPath);
-            }
-
-            if (invalidVersions.Count > 0) {
-                errorMessage = "These Qt version are inaccessible:\n";
-                foreach (var invalidVersion in invalidVersions)
-                    errorMessage += invalidVersion + " in " + GetInstallPath(invalidVersion) + "\n";
-                errorMessage += "Make sure that you have read access to all files in your Qt directories.";
-
-                // Is the default Qt version invalid?
-                var isDefaultQtVersionInvalid = false;
-                var defaultQtVersionName = GetDefaultVersion();
-                if (string.IsNullOrEmpty(defaultQtVersionName)) {
-                    isDefaultQtVersionInvalid = true;
-                } else {
-                    foreach (var name in invalidVersions) {
-                        if (name == defaultQtVersionName) {
-                            isDefaultQtVersionInvalid = true;
-                            break;
-                        }
-                    }
-                }
-
-                // find the newest valid Qt version that can be used as default version
-                if (isDefaultQtVersionInvalid && validVersions.Count > 0) {
-                    QtConfig defaultQtVersionConfig = null;
-                    foreach (var vNameConfig in validVersions) {
-                        var vName = vNameConfig.Key;
-                        var v = vNameConfig.Value;
-                        if (defaultQtVersionConfig == null) {
-                            defaultQtVersionConfig = v;
-                            defaultQtVersionName = vName;
-                            continue;
-                        }
-                        if (defaultQtVersionConfig.VersionMajor < v.VersionMajor ||
-                               (defaultQtVersionConfig.VersionMajor == v.VersionMajor && (defaultQtVersionConfig.VersionMinor < v.VersionMinor ||
-                                   (defaultQtVersionConfig.VersionMinor == v.VersionMinor && defaultQtVersionConfig.VersionPatch < v.VersionPatch)))) {
-                            defaultQtVersionConfig = v;
-                            defaultQtVersionName = vName;
-                        }
-                    }
-                    if (defaultQtVersionConfig != null)
-                        SaveDefaultVersion(defaultQtVersionName);
-                }
-
-                return true;
-            }
             errorMessage = null;
-            return false;
+            foreach (var version in GetVersions()) {
+                if (version == "$(DefaultQtVersion)")
+                    continue;
+
+                var path = GetInstallPath(version);
+                if (path != null && (path.StartsWith("SSH:") || path.StartsWith("WSL:")))
+                    continue;
+
+                if (string.IsNullOrEmpty(path) || !QMake.Exists(path)) {
+                    errorMessage += version + " in " + path + "\n";
+                    defaultVersionInvalid |= version == defaultVersion;
+                }
+
+                if (!string.IsNullOrEmpty(errorMessage)) {
+                    errorMessage = "These Qt version are inaccessible:\n"
+                        + errorMessage
+                        + "Make sure that you have read access to all files in your Qt directories.";
+                }
+            }
+            return errorMessage != null;
+        }
+
+        public void SetLatestQtVersionAsDefault()
+        {
+            var validVersions = new Dictionary<string, Version>();
+            foreach (var version in GetVersions()) {
+                if (version == "$(DefaultQtVersion)")
+                    continue;
+
+                var path = GetInstallPath(version);
+                if (!string.IsNullOrEmpty(path) && QMake.Exists(path))
+                    validVersions[version] = new Version(new QtConfig(path).VersionString);
+            }
+
+            if (validVersions.Count <= 0)
+                return;
+
+            var defaultName = "";
+            Version defaultVersion = null;
+            foreach (var tmp in validVersions) {
+                var version = tmp.Value;
+                if (defaultVersion == null || defaultVersion < version) {
+                    defaultName = tmp.Key;
+                    defaultVersion = version;
+                }
+            }
+            SaveDefaultVersion(defaultName);
         }
 
         public string GetInstallPath(string version)
@@ -252,16 +204,14 @@
                 return Environment.GetEnvironmentVariable("QTDIR");
 
             var key = root.OpenSubKey("SOFTWARE\\" + Resources.registryRootPath, false);
-            if (key == null)
-                return null;
-            var versionKey = key.OpenSubKey(strVersionKey + "\\" + version, false);
-            if (versionKey == null)
-                return null;
-            return (string)versionKey.GetValue("InstallDir");
+            var versionKey = key?.OpenSubKey(strVersionKey + "\\" + version, false);
+            return versionKey?.GetValue("InstallDir") as string;
         }
 
         public string GetInstallPath(EnvDTE.Project project)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var version = GetProjectQtVersion(project);
             if (version == "$(DefaultQtVersion)")
                 version = GetDefaultVersion();
@@ -309,7 +259,6 @@
                     versionKey.SetValue("InstallDir", dir);
                 }
             }
-            RefreshVersionNames();
             return true;
         }
 
@@ -320,10 +269,9 @@
                 return;
             key.DeleteSubKey(versionName);
             key.Close();
-            RefreshVersionNames();
         }
 
-        private bool IsVersionAvailable(string version)
+        internal bool IsVersionAvailable(string version)
         {
             var versionAvailable = false;
             var versions = GetVersions();
@@ -338,13 +286,17 @@
 
         public bool SaveProjectQtVersion(EnvDTE.Project project, string version)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
             return SaveProjectQtVersion(project, version, project.ConfigurationManager.ActiveConfiguration.PlatformName);
         }
 
         public bool SaveProjectQtVersion(EnvDTE.Project project, string version, string platform)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (!IsVersionAvailable(version) && version != "$(DefaultQtVersion)")
                 return false;
+
             if (QtProject.GetFormatVersion(project) >= Resources.qtMinFormatVersion_Settings) {
                 var vcPro = project.Object as VCProject;
                 if (vcPro == null)
@@ -365,6 +317,8 @@
 
         public string GetProjectQtVersion(EnvDTE.Project project)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             EnvDTE.Configuration config = null;
             try {
                 config = project.ConfigurationManager.ActiveConfiguration;
@@ -382,13 +336,15 @@
             }
 
             if (version == null)
-                version = GetSolutionQtVersion(project.DTE.Solution);
+                version = Legacy.QtVersionManager.GetSolutionQtVersion(project.DTE.Solution);
 
             return version;
         }
 
         public string GetProjectQtVersion(EnvDTE.Project project, EnvDTE.Configuration config)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (QtProject.GetFormatVersion(project) >= Resources.qtMinFormatVersion_Settings)
                 return QtProject.GetPropertyValue(project, config, "QtInstall");
 
@@ -402,6 +358,8 @@
 
         public string GetProjectQtVersion(EnvDTE.Project project, string platform)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (QtProject.GetFormatVersion(project) >= Resources.qtMinFormatVersion_Settings)
                 return GetProjectQtVersion(project);
 
@@ -426,29 +384,6 @@
                     version = Environment.GetEnvironmentVariable(env);
                 }
             }
-        }
-
-        public bool SaveSolutionQtVersion(EnvDTE.Solution solution, string version)
-        {
-            if (!IsVersionAvailable(version) && version != "$(DefaultQtVersion)")
-                return false;
-            solution.Globals["Qt5Version"] = version;
-            if (!solution.Globals.get_VariablePersists("Qt5Version"))
-                solution.Globals.set_VariablePersists("Qt5Version", true);
-            return true;
-        }
-
-        public string GetSolutionQtVersion(EnvDTE.Solution solution)
-        {
-            if (solution == null)
-                return null;
-
-            if (solution.Globals.get_VariableExists("Qt5Version")) {
-                var version = (string)solution.Globals["Qt5Version"];
-                return VerifyIfQtVersionExists(version) ? version : null;
-            }
-
-            return null;
         }
 
         public string GetDefaultVersion()
@@ -489,6 +424,25 @@
                 }
             }
             return VerifyIfQtVersionExists(defaultVersion) ? defaultVersion : null;
+        }
+
+        public string GetDefaultVersionString()
+        {
+            string defaultVersion = null;
+            try {
+                var key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\" + regVersionPath, false);
+                if (key != null)
+                    defaultVersion = key.GetValue("DefaultQtVersion") as string;
+            } catch {
+                Messages.Print("Cannot read the default Qt version from registry.");
+            }
+
+            if (defaultVersion == null) {
+                var qtDir = Environment.GetEnvironmentVariable("QTDIR");
+                if (string.IsNullOrEmpty(qtDir))
+                    return defaultVersion;
+            }
+            return defaultVersion;
         }
 
         public bool SaveDefaultVersion(string version)
@@ -540,7 +494,7 @@
             }
         }
 
-        private bool VerifyIfQtVersionExists(string version)
+        internal bool VerifyIfQtVersionExists(string version)
         {
             if (version == "$(DefaultQtVersion)")
                 version = GetDefaultVersion();
diff --git a/QtVsTools.Core/QtVsTools.Core.csproj b/QtVsTools.Core/QtVsTools.Core.csproj
index c436e03..19e3727 100644
--- a/QtVsTools.Core/QtVsTools.Core.csproj
+++ b/QtVsTools.Core/QtVsTools.Core.csproj
@@ -69,36 +69,45 @@
   // -->
   <ItemGroup>
     <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+    <Reference Include="PresentationFramework" />
     <Reference Include="System" />
     <Reference Include="System.Drawing" />
     <Reference Include="System.Xml" />
     <Reference Include="System.Xml.Linq" />
     <Reference Include="System.Windows.Forms" />
+    <Reference Include="WindowsBase" />
   </ItemGroup>
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
-  // Version specific references
+  // General package references
   // -->
   <Import Project="$(SolutionDir)\references.props" />
   <ItemGroup>
-    <PackageReference Include="Microsoft.VisualStudio.SDK"
-      Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
-    <PackageReference Include="Microsoft.VSSDK.BuildTools"
-      Version="$(Version_Microsoft_VSSDK_BuildTools)" />
-    <PackageReference Include="Microsoft.Build"
-      Version="$(Version_Microsoft_Build)" />
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+    <PackageReference Include="$(Name_Microsoft_Build)" Version="$(Version_Microsoft_Build)" />
   </ItemGroup>
-  <ItemGroup Condition="'$(VisualStudioVersion)'=='17.0'">
-    <PackageReference Include="$(Name_Microsoft_VisualStudio_VCProjectEngine)"
-      Version="$(Version_Microsoft_VisualStudio_VCProjectEngine)" />
-  </ItemGroup>
-  <ItemGroup Condition="'$(VisualStudioVersion)'=='16.0'">
-    <PackageReference Include="$(Name_Microsoft_VisualStudio_VCProjectEngine)"
-      Version="$(Version_Microsoft_VisualStudio_VCProjectEngine)" />
-  </ItemGroup>
-  <ItemGroup Condition="'$(VisualStudioVersion)'=='15.0'">
-    <Reference Include="Microsoft.VisualStudio.VCProjectEngine" />
-  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_VCProjectEngine)" Version="$(Version_Microsoft_VisualStudio_VCProjectEngine)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+        <Reference Include="$(Name_Microsoft_VisualStudio_VCProjectEngine)" />
+      </ItemGroup>
+    </When>
+  </Choose>
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
   // Solution project references
@@ -117,6 +126,8 @@
     <Compile Include="BuildConfig.cs" />
     <Compile Include="CommandLineParser.cs" />
     <Compile Include="Common\EnumExt.cs" />
+    <Compile Include="Common\LazyFactory.cs" />
+    <Compile Include="Common\QtVSIPSettingsShared.cs" />
     <Compile Include="CompilerToolWrapper.cs" />
     <Compile Include="CxxStreamReader.cs" />
     <Compile Include="ExportProjectDialog.cs">
@@ -130,12 +141,16 @@
     <Compile Include="ImageButton.cs">
       <SubType>Component</SubType>
     </Compile>
+    <Compile Include="Legacy\QtProject.cs" />
+    <Compile Include="Legacy\QtVersionManager.cs" />
+    <Compile Include="Legacy\QtVSIPSettings.cs" />
     <Compile Include="LinkerToolWrapper.cs" />
     <Compile Include="MainWinWrapper.cs" />
     <Compile Include="Messages.cs" />
     <Compile Include="MocCmdChecker.cs" />
     <Compile Include="MsBuildProject.cs" />
     <Compile Include="Observable.cs" />
+    <Compile Include="OutputWindowPane.cs" />
     <Compile Include="ProFileContent.cs" />
     <Compile Include="ProFileOption.cs" />
     <Compile Include="ProjectExporter.cs" />
@@ -170,10 +185,12 @@
     <Compile Include="RccOptions.cs" />
     <Compile Include="Resources.cs" />
     <Compile Include="SR.cs" />
-    <Compile Include="TemplateType.cs" />
     <Compile Include="VersionInformation.cs" />
+    <Compile Include="VisualStudio\InfoBarMessage.cs" />
     <Compile Include="VisualStudio\IProjectTracker.cs" />
+    <Compile Include="VisualStudio\VsSearch.cs" />
     <Compile Include="VisualStudio\VsServiceProvider.cs" />
+    <Compile Include="VisualStudio\VsShell.cs" />
     <Compile Include="WaitDialog.cs" />
     <EmbeddedResource Include="ExportProjectDialog.resx">
       <DependentUpon>ExportProjectDialog.cs</DependentUpon>
@@ -188,4 +205,4 @@
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\transform.targets" />
-</Project>
+</Project>
\ No newline at end of file
diff --git a/QtVsTools.Core/RccOptions.cs b/QtVsTools.Core/RccOptions.cs
index 44e8b2e..3d3dd48 100644
--- a/QtVsTools.Core/RccOptions.cs
+++ b/QtVsTools.Core/RccOptions.cs
@@ -26,8 +26,9 @@
 **
 ****************************************************************************/
 
-using Microsoft.VisualStudio.VCProjectEngine;
 using System;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.VCProjectEngine;
 
 namespace QtVsTools.Core
 {
@@ -57,6 +58,8 @@
         {
             get
             {
+                ThreadHelper.ThrowIfNotOnUIThread();
+
                 if (project.Globals.get_VariablePersists("RccCompressFiles" + id)
                     && (string)project.Globals["RccCompressFiles" + id] == "true")
                     return true;
@@ -64,6 +67,8 @@
             }
             set
             {
+                ThreadHelper.ThrowIfNotOnUIThread();
+
                 if (value)
                     project.Globals["RccCompressFiles" + id] = "true";
                 else
@@ -77,12 +82,16 @@
         {
             get
             {
+                ThreadHelper.ThrowIfNotOnUIThread();
+
                 if (project.Globals.get_VariablePersists("RccCompressLevel" + id))
                     return Convert.ToInt32((string)project.Globals["RccCompressLevel" + id], 10);
                 return 0;
             }
             set
             {
+                ThreadHelper.ThrowIfNotOnUIThread();
+
                 project.Globals["RccCompressLevel" + id] = value.ToString();
                 if (!project.Globals.get_VariablePersists("RccCompressLevel" + id))
                     project.Globals.set_VariablePersists("RccCompressLevel" + id, true);
@@ -93,12 +102,16 @@
         {
             get
             {
+                ThreadHelper.ThrowIfNotOnUIThread();
+
                 if (project.Globals.get_VariablePersists("RccCompressThreshold" + id))
                     return Convert.ToInt32((string)project.Globals["RccCompressThreshold" + id], 10);
                 return 0;
             }
             set
             {
+                ThreadHelper.ThrowIfNotOnUIThread();
+
                 project.Globals["RccCompressThreshold" + id] = value.ToString();
                 if (!project.Globals.get_VariablePersists("RccCompressThreshold" + id))
                     project.Globals.set_VariablePersists("RccCompressThreshold" + id, true);
diff --git a/QtVsTools.Core/Resources.cs b/QtVsTools.Core/Resources.cs
index c8db0c9..79e97a0 100644
--- a/QtVsTools.Core/Resources.cs
+++ b/QtVsTools.Core/Resources.cs
@@ -100,18 +100,11 @@
         public const int qtMinFormatVersion_PropertyEval = 303;
 
         // Project properties labels
-        public const string projLabelGlobals = "Globals";
         public const string projLabelQtSettings = "QtSettings";
 
         public const string uic4Command = "$(QTDIR)\\bin\\uic.exe";
         public const string moc4Command = "$(QTDIR)\\bin\\moc.exe";
         public const string rcc4Command = "$(QTDIR)\\bin\\rcc.exe";
-        public const string lupdateCommand = "\\bin\\lupdate.exe";
-        public const string lreleaseCommand = "\\bin\\lrelease.exe";
-
-        // All defined paths have to be relative to the project directory!!!
-
-        public const string resourceDir = "Resources";
 
         // If those directories do not equal to the project directory
         // they have to be added to the include directories for
diff --git a/QtVsTools.Core/Resources.resx b/QtVsTools.Core/Resources.resx
index 7861f15..ad354aa 100644
--- a/QtVsTools.Core/Resources.resx
+++ b/QtVsTools.Core/Resources.resx
@@ -123,9 +123,6 @@
   <data name="OpenSolution" xml:space="preserve">
     <value>Open Solution</value>
   </data>
-  <data name="ProjectExists" xml:space="preserve">
-    <value>Project file already exists.</value>
-  </data>
   <data name="ExportProject_EditProjectFileManually" xml:space="preserve">
     <value>qmake has generated a .vcproj file, but it needs to be converted.
 To do this you must open the .vcproj file manually.
@@ -140,17 +137,13 @@
     <value>Export to .pri File</value>
   </data>
   <data name="ExportProject_NoProjectsToExport" xml:space="preserve">
-    <value>Cannot find any Qt 4 projects to export.</value>
+    <value>Cannot find any Qt projects to export.</value>
   </data>
   <data name="ExportProject_PriFileContainsSpaces" xml:space="preserve">
     <value>The generated .pri file contains paths with spaces. You will not be able to import from this file.
 1. Manually edit the generated .pri file.
 2. Move your project to a location without spaces in the path.
 3. Place the .pri file in another directory.</value>
-  </data>
-  <data name="ExportProject_ProjectExistsRegenerateOrReuse" xml:space="preserve">
-    <value>{0} already exists.
-Select 'Yes' to regenerate the file, and 'No' to use the existing one.</value>
   </data>
   <data name="ExportProject_ProjectOrSolutionCorrupt" xml:space="preserve">
     <value>{0}
@@ -216,12 +209,6 @@
   <data name="QtProject_CannotRemoveMocStep" xml:space="preserve">
     <value>Cannot remove a moc step from file {0}</value>
   </data>
-  <data name="QtProject_CannotAddFilter" xml:space="preserve">
-    <value>Project cannot add filter {0}</value>
-  </data>
-  <data name="QtProject_CannotAddFile" xml:space="preserve">
-    <value>Cannot add file {0} to filter.</value>
-  </data>
   <data name="QtProject_CannotRemoveFile" xml:space="preserve">
     <value>Cannot remove file {0} from filter.</value>
   </data>
@@ -238,25 +225,9 @@
   <data name="QtProject_ProjectCannotAddResourceFilter" xml:space="preserve">
     <value>Cannot add a resource filter.</value>
   </data>
-  <data name="QtProject_CannotCreateResourceDir" xml:space="preserve">
-    <value>Cannot create a resource directory.</value>
-  </data>
   <data name="QtProject_CannotAdjustWhitespaces" xml:space="preserve">
     <value>Cannot adjust whitespace or tabs in file (write).
 ({0})</value>
-  </data>
-  <data name="QtProject_CannotReplaceTokenRead" xml:space="preserve">
-    <value>Cannot replace token ({0} -&gt; {1}) in file (read).
-({3})</value>
-  </data>
-  <data name="QtProject_CannotReplaceTokenWrite" xml:space="preserve">
-    <value>Cannot replace token ({0} -&gt; {1}) in file (write).
-({3})</value>
-  </data>
-  <data name="QtProject_FileExistsInProjectFolder" xml:space="preserve">
-    <value>The file {0} exists in your project folder. Qt VS Tools will overwrite the existing file.
-
-Select 'Yes' to overwrite, select 'No' to keep the existing file and automatically add it to the project.</value>
   </data>
   <data name="QtVersionManager_CannotLoadQtVersion" xml:space="preserve">
     <value>Cannot load the default Qt version.</value>
@@ -276,9 +247,6 @@
   <data name="Resources_ResourceFiles" xml:space="preserve">
     <value>Resource Files</value>
   </data>
-  <data name="Resources_TranslationFiles" xml:space="preserve">
-    <value>Translation Files</value>
-  </data>
   <data name="Resources_GeneratedFiles" xml:space="preserve">
     <value>Generated Files</value>
   </data>
@@ -287,12 +255,6 @@
   </data>
   <data name="QtProject_CannotAccessUserFile" xml:space="preserve">
     <value>Could not add QTDIR to {0}'s .user file.</value>
-  </data>
-  <data name="ImportProject_CannotConvertProject" xml:space="preserve">
-    <value>Could not convert project file {0} to Qt/MSBuild.</value>
-  </data>
-  <data name="Resources_OtherFiles" xml:space="preserve">
-    <value>Other Files</value>
   </data>
   <data name="WaitDialogRefreshMoc" xml:space="preserve">
     <value>Updating moc steps...</value>
diff --git a/QtVsTools.Core/SR.cs b/QtVsTools.Core/SR.cs
index ef66800..d5ed78b 100644
--- a/QtVsTools.Core/SR.cs
+++ b/QtVsTools.Core/SR.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -26,10 +26,7 @@
 **
 ****************************************************************************/
 
-using System;
-using System.Globalization;
 using System.Resources;
-using System.Threading;
 
 namespace QtVsTools.Core
 {
@@ -37,7 +34,7 @@
     {
         static SR loader;
         readonly ResourceManager resources;
-        static readonly Object obj = new Object();
+        static readonly object obj = new object();
 
         internal SR()
         {
@@ -52,20 +49,7 @@
                         loader = new SR();
                 }
             }
-
             return loader;
-        }
-
-        private static CultureInfo Culture
-        {
-            get { return null/*use ResourceManager default, CultureInfo.CurrentUICulture*/; }
-            //get { return new CultureInfo("de-DE"); }
-        }
-
-        public static string LanguageName
-        {
-            get { return Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName; }
-            //get { return Culture.TwoLetterISOLanguageName; }
         }
 
         public static string GetString(string name, params object[] args)
@@ -73,19 +57,16 @@
             var sys = GetLoader();
             if (sys == null)
                 return null;
-            var res = sys.resources.GetString(name, Culture);
 
-            if (args != null && args.Length > 0)
+            var res = sys.resources.GetString(name, null);
+            if (args != null && args.Length > 0 && !string.IsNullOrEmpty(res))
                 return string.Format(res, args);
             return res;
         }
 
         public static string GetString(string name)
         {
-            var sys = GetLoader();
-            if (sys == null)
-                return null;
-            return sys.resources.GetString(name, Culture);
+            return GetString(name, null);
         }
     }
 }
diff --git a/QtVsTools.Core/VersionInformation.cs b/QtVsTools.Core/VersionInformation.cs
index fd8cc1a..12d6c81 100644
--- a/QtVsTools.Core/VersionInformation.cs
+++ b/QtVsTools.Core/VersionInformation.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -34,6 +34,7 @@
 using System.Linq;
 using System.Text;
 using System.Text.RegularExpressions;
+using Microsoft.VisualStudio.Shell;
 
 namespace QtVsTools.Core
 {
@@ -42,11 +43,10 @@
     {
         //fields
         public string name;
-        public string qtDir;
+        public readonly string qtDir;
         public uint qtMajor; // X in version x.y.z
         public uint qtMinor; // Y in version x.y.z
         public uint qtPatch; // Z in version x.y.z
-        public bool qt5Version = true;
         private QtConfig qtConfig;
         private QMakeConf qmakeConf;
         private string vsPlatformName;
@@ -79,18 +79,18 @@
             _cache.Clear();
         }
 
-        Dictionary<string, bool> _IsModuleAvailable;
+        readonly Dictionary<string, bool> _IsModuleAvailable;
         public bool IsModuleAvailable(string module)
         {
             return _IsModuleAvailable?[module] ?? false;
         }
 
-        public string VC_MinimumVisualStudioVersion { get; private set; }
-        public string VC_ApplicationTypeRevision { get; private set; }
-        public string VC_WindowsTargetPlatformMinVersion { get; private set; }
-        public string VC_WindowsTargetPlatformVersion { get; private set; }
-        public string VC_Link_TargetMachine { get; private set; }
-        public string VC_PlatformToolset { get; private set; }
+        public string VC_MinimumVisualStudioVersion { get; }
+        public string VC_ApplicationTypeRevision { get; }
+        public string VC_WindowsTargetPlatformMinVersion { get; }
+        public string VC_WindowsTargetPlatformVersion { get; }
+        public string VC_Link_TargetMachine { get; }
+        private string VC_PlatformToolset { get; }
 
         private VersionInformation(string qtDirIn)
         {
@@ -128,7 +128,6 @@
                     qtMinor = (version >> 8) & 0xFF;
                     qtPatch = version & 0xFF;
                 }
-                qt5Version = (qtMajor == 5);
 
                 try {
                     QtInstallDocs = qmakeQuery["QT_INSTALL_DOCS"];
@@ -143,7 +142,7 @@
                 var tempProData = new StringBuilder();
                 tempProData.AppendLine("SOURCES = main.cpp");
 
-                var modules = QtModules.Instance.GetAvailableModules()
+                var modules = QtModules.Instance.GetAvailableModules(qtMajor)
                     .Where((QtModule mi) => mi.Selectable);
 
                 foreach (QtModule mi in modules) {
@@ -194,7 +193,7 @@
 
         public string QtInstallDocs
         {
-            get; private set;
+            get;
         }
 
         public string QMakeSpecDirectory
diff --git a/QtVsTools.Core/VisualStudio/InfoBarMessage.cs b/QtVsTools.Core/VisualStudio/InfoBarMessage.cs
new file mode 100644
index 0000000..b5572b0
--- /dev/null
+++ b/QtVsTools.Core/VisualStudio/InfoBarMessage.cs
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Diagnostics;
+using System.Linq;
+using Microsoft.VisualStudio.Imaging.Interop;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+
+namespace QtVsTools.VisualStudio
+{
+    using Common;
+
+    public abstract class InfoBarMessage
+    {
+        protected abstract ImageMoniker Icon { get; }
+        protected abstract TextSpan[] Text { get; }
+        protected abstract Hyperlink[] Hyperlinks { get; }
+
+        protected class TextSpan
+        {
+            public string Text { get; set; }
+            public bool Bold { get; set; }
+            public bool Italic { get; set; }
+            public bool Underline { get; set; }
+            public static implicit operator TextSpan(string text) => new TextSpan { Text = text };
+        }
+
+        protected class TextSpacer : TextSpan
+        {
+            public TextSpacer(int spaces)
+            {
+                Text = new string(' ', spaces);
+            }
+        }
+
+        protected class Hyperlink
+        {
+            public string Text { get; set; }
+            public bool CloseInfoBar { get; set; }
+            public Action OnClicked { get; set; }
+        }
+
+        private MessageUI UI { get; set; }
+
+        public InfoBarMessage()
+        {
+            UI = new MessageUI { Message = this };
+        }
+
+        public virtual void Show()
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+            UI.Show();
+        }
+
+        public virtual void Close()
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+            UI.Close();
+        }
+
+        public bool IsOpen => UI.IsOpen;
+
+        protected virtual void OnClosed()
+        { }
+
+        private class MessageUI : IVsInfoBarUIEvents
+        {
+            static LazyFactory StaticLazy { get; } = new LazyFactory();
+            static IVsInfoBarUIFactory Factory => StaticLazy.Get(() =>
+                Factory, () => VsServiceProvider
+                    .GetService<SVsInfoBarUIFactory, IVsInfoBarUIFactory>());
+
+            private IVsInfoBarUIElement UIElement { get; set; }
+            private uint eventNotificationCookie;
+
+            public bool IsOpen => UIElement != null;
+
+            public InfoBarMessage Message { get; set; }
+
+            public void Show()
+            {
+                ThreadHelper.ThrowIfNotOnUIThread();
+                if (Factory == null)
+                    return;
+                if (UIElement != null) // Message already shown
+                    return;
+                var textSpans = Enumerable.Empty<InfoBarTextSpan>();
+                if (Message.Text != null) {
+                    textSpans = Message.Text
+                        .Select(x => new InfoBarTextSpan(x.Text, x.Bold, x.Italic, x.Underline));
+                }
+                var hyperlinks = Enumerable.Empty<InfoBarHyperlink>();
+                if (Message.Hyperlinks != null) {
+                    hyperlinks = Message.Hyperlinks
+                        .Select(x => new InfoBarHyperlink(x.Text, x));
+                }
+                var model = new InfoBarModel(textSpans, hyperlinks, Message.Icon, true);
+                UIElement = Factory.CreateInfoBar(model);
+                if (UIElement != null) {
+                    UIElement.Advise(this, out eventNotificationCookie);
+                    VsShell.InfoBarHost?.AddInfoBar(UIElement);
+                }
+            }
+
+            public void Close()
+            {
+                ThreadHelper.ThrowIfNotOnUIThread();
+                UIElement?.Close();
+            }
+
+            void IVsInfoBarUIEvents.OnActionItemClicked(
+                IVsInfoBarUIElement infoBarUIElement,
+                IVsInfoBarActionItem actionItem)
+            {
+                ThreadHelper.ThrowIfNotOnUIThread();
+                Debug.Assert(infoBarUIElement == UIElement);
+                var hyperlink = actionItem.ActionContext as Hyperlink;
+                if (hyperlink == null)
+                    return;
+                if (hyperlink.CloseInfoBar)
+                    Close();
+                hyperlink.OnClicked();
+            }
+
+            void IVsInfoBarUIEvents.OnClosed(IVsInfoBarUIElement infoBarUIElement)
+            {
+                ThreadHelper.ThrowIfNotOnUIThread();
+                Debug.Assert(infoBarUIElement == UIElement);
+                if (UIElement != null) {
+                    UIElement.Unadvise(eventNotificationCookie);
+                    UIElement = null;
+                    eventNotificationCookie = 0;
+                    Message.OnClosed();
+                }
+            }
+        }
+    }
+}
diff --git a/QtVsTools.Core/VisualStudio/VsSearch.cs b/QtVsTools.Core/VisualStudio/VsSearch.cs
new file mode 100644
index 0000000..1a79603
--- /dev/null
+++ b/QtVsTools.Core/VisualStudio/VsSearch.cs
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows.Controls;
+using System.Windows.Data;
+using Microsoft.Internal.VisualStudio.PlatformUI;
+using Microsoft.VisualStudio;
+using Microsoft.VisualStudio.PlatformUI;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+
+namespace QtVsTools.VisualStudio
+{
+    public class SearchTask : VsSearchTask
+    {
+        private readonly Action _clearCallback = null;
+        private readonly Func<IEnumerable<string>, uint> _searchCallBack = null;
+
+        public SearchTask(uint cookie, IVsSearchQuery query, IVsSearchCallback callback,
+                Action clearCallback, Func<IEnumerable<string>, uint> searchCallBack)
+            : base(cookie, query, callback)
+        {
+            _clearCallback = clearCallback;
+            _searchCallBack = searchCallBack;
+        }
+
+        protected override void OnStartSearch()
+        {
+            ErrorCode = VSConstants.S_OK;
+            try {
+                _ = ThreadHelper.JoinableTaskFactory.RunAsync(async () =>
+                {
+                    await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+                    if (TaskStatus != VSConstants.VsSearchTaskStatus.Stopped) {
+                        SearchResults = _searchCallBack(
+                            SearchUtilities.ExtractSearchTokens(SearchQuery).Select(token =>
+                            {
+                                ThreadHelper.ThrowIfNotOnUIThread();
+                                return token.ParsedTokenText;
+                            })
+                        );
+                    } else if (TaskStatus == VSConstants.VsSearchTaskStatus.Stopped) {
+                        _clearCallback();
+                    }
+                });
+            } catch {
+                ErrorCode = VSConstants.E_FAIL;
+            }
+            base.OnStartSearch();
+        }
+
+        protected override void OnStopSearch()
+        {
+            SearchResults = 0;
+        }
+    }
+
+    public abstract class VsWindowSearch : IVsWindowSearch
+    {
+        public abstract IVsSearchTask CreateSearch(uint cookie, IVsSearchQuery query,
+                                                   IVsSearchCallback callback);
+
+        public virtual void ClearSearch()
+        {}
+
+        public virtual void ProvideSearchSettings(IVsUIDataSource settings)
+        {
+            Utilities.SetValue(settings, SearchSettingsDataSource.PropertyNames.ControlMaxWidth,
+                (uint)10000);
+            Utilities.SetValue(settings, SearchSettingsDataSource.PropertyNames.SearchStartType,
+                (uint)VSSEARCHSTARTTYPE.SST_INSTANT);
+        }
+
+        public virtual bool OnNavigationKeyDown(uint dwNavigationKey, uint dwModifiers) => false;
+
+        public virtual bool SearchEnabled => true;
+
+        public virtual Guid Category => Guid.Empty;
+
+        public virtual IVsEnumWindowSearchFilters SearchFiltersEnum => null;
+
+        public virtual IVsEnumWindowSearchOptions SearchOptionsEnum => null;
+    }
+
+    public class ListBoxSearch : VsWindowSearch
+    {
+        private readonly ListBox _listBox = null;
+        private Action<string> _setSearchText = null;
+
+        public ListBoxSearch(ListBox listBox, Action<string> action)
+        {
+            _listBox = listBox;
+            _setSearchText = action;
+        }
+
+        public override IVsSearchTask CreateSearch(uint cookie, IVsSearchQuery query,
+                                                   IVsSearchCallback callback)
+        {
+            return new SearchTask(cookie, query, callback, ClearSearch,
+                searchCallBack: (IEnumerable<string> tokens) =>
+                {
+                    _setSearchText(string.Join(" ", tokens));
+                    var view = CollectionViewSource.GetDefaultView(_listBox.ItemsSource);
+
+                    view.Refresh();
+                    if (_listBox.Items.Count == 1 || _listBox.SelectedItem == null)
+                        _listBox.SelectedIndex = 0;
+                    return (uint)view.Cast<object>().Count();
+                });
+        }
+
+        public override void ClearSearch()
+        {
+            _setSearchText(string.Empty);
+            CollectionViewSource.GetDefaultView(_listBox.ItemsSource).Refresh();
+        }
+    }
+}
diff --git a/QtVsTools.Core/VisualStudio/VsServiceProvider.cs b/QtVsTools.Core/VisualStudio/VsServiceProvider.cs
index ed53ed5..d9060ed 100644
--- a/QtVsTools.Core/VisualStudio/VsServiceProvider.cs
+++ b/QtVsTools.Core/VisualStudio/VsServiceProvider.cs
@@ -26,7 +26,6 @@
 **
 ****************************************************************************/
 
-using Microsoft.VisualStudio.Shell;
 using System;
 using System.Collections.Concurrent;
 using System.Threading.Tasks;
@@ -45,7 +44,7 @@
     {
         public static IVsServiceProvider Instance { get; set; }
 
-        static ConcurrentDictionary<ServiceType, object> services
+        static readonly ConcurrentDictionary<ServiceType, object> services
             = new ConcurrentDictionary<ServiceType, object>();
 
         public static I GetService<I>()
@@ -61,8 +60,7 @@
             if (Instance == null)
                 return null;
 
-            object serviceObj;
-            if (services.TryGetValue(new ServiceType(typeof(T), typeof(I)), out serviceObj))
+            if (services.TryGetValue(new ServiceType(typeof(T), typeof(I)), out object serviceObj))
                 return serviceObj as I;
 
             var serviceInterface = Instance.GetService<T, I>();
@@ -83,8 +81,7 @@
             if (Instance == null)
                 return null;
 
-            object serviceObj;
-            if (services.TryGetValue(new ServiceType(typeof(T), typeof(I)), out serviceObj))
+            if (services.TryGetValue(new ServiceType(typeof(T), typeof(I)), out object serviceObj))
                 return serviceObj as I;
 
             var serviceInterface = await Instance.GetServiceAsync<T, I>();
diff --git a/QtVsTools.Core/VisualStudio/VsShell.cs b/QtVsTools.Core/VisualStudio/VsShell.cs
new file mode 100644
index 0000000..1bccafc
--- /dev/null
+++ b/QtVsTools.Core/VisualStudio/VsShell.cs
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using Microsoft.VisualStudio;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+
+namespace QtVsTools.VisualStudio
+{
+    public static class VsShell
+    {
+        public static string InstallRootDir
+        {
+            get
+            {
+                ThreadHelper.ThrowIfNotOnUIThread();
+
+                Initialize();
+                return _InstallRootDir;
+            }
+        }
+
+        private static IVsShell vsShell;
+        private static string _InstallRootDir;
+
+        private static void Initialize()
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            if (vsShell != null)
+                return;
+            vsShell = VsServiceProvider.GetService<IVsShell>();
+
+            int res = vsShell.GetProperty((int)__VSSPROPID2.VSSPROPID_InstallRootDir, out object o);
+            if (res == VSConstants.S_OK && o is string property)
+                _InstallRootDir = property;
+        }
+
+        public static EnvDTE.Project GetProject(IVsHierarchy context)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            int res = context.GetProperty(
+                (uint)VSConstants.VSITEMID.Root, (int)__VSHPROPID.VSHPROPID_ExtObject, out object value);
+            if (res == VSConstants.S_OK && value is EnvDTE.Project project)
+                return project;
+            return null;
+        }
+
+        public static EnvDTE.ProjectItem GetProjectItem(IVsHierarchy context, uint itemid)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            int res = context.GetProperty(
+                itemid, (int)__VSHPROPID.VSHPROPID_ExtObject, out object value);
+            if (res == VSConstants.S_OK && value is EnvDTE.ProjectItem item)
+                return item;
+            return null;
+        }
+
+        public static EnvDTE.Document GetDocument(IVsHierarchy context, uint itemid)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+            return GetProjectItem(context, itemid)?.Document;
+        }
+
+        private static IVsInfoBarHost _InfoBarHost = null;
+        public static IVsInfoBarHost InfoBarHost
+        {
+            get
+            {
+                ThreadHelper.ThrowIfNotOnUIThread();
+                if (_InfoBarHost != null)
+                    return _InfoBarHost;
+                Initialize();
+                object host = null;
+                vsShell?.GetProperty((int)__VSSPROPID7.VSSPROPID_MainWindowInfoBarHost, out host);
+                return _InfoBarHost = host as IVsInfoBarHost;
+            }
+        }
+    }
+}
diff --git a/QtVsTools.Core/WaitDialog.cs b/QtVsTools.Core/WaitDialog.cs
index cff8851..60a6adc 100644
--- a/QtVsTools.Core/WaitDialog.cs
+++ b/QtVsTools.Core/WaitDialog.cs
@@ -27,25 +27,21 @@
 ****************************************************************************/
 
 using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Windows.Forms;
 using Microsoft.VisualStudio;
 using Microsoft.VisualStudio.Shell;
 using Microsoft.VisualStudio.Shell.Interop;
-using Microsoft.VisualStudio.VCProjectEngine;
-using QtVsTools.VisualStudio;
 
 namespace QtVsTools.Core
 {
+    using VisualStudio;
+
     public class WaitDialog : IDisposable
     {
         static IVsThreadedWaitDialogFactory factory = null;
 
-        public IVsThreadedWaitDialog2 VsWaitDialog { get; private set; }
+        private IVsThreadedWaitDialog2 VsWaitDialog { get; set; }
 
-        public bool Running { get; private set; }
+        private bool Running { get; set; }
 
         bool? vsDialogCanceled = null;
 
@@ -53,14 +49,15 @@
         {
             get
             {
+                ThreadHelper.ThrowIfNotOnUIThread();
+
                 if (vsDialogCanceled.HasValue)
                     return vsDialogCanceled.Value;
 
                 if (VsWaitDialog == null)
                     return false;
 
-                bool canceled = false;
-                int res = VsWaitDialog.HasCanceled(out canceled);
+                int res = VsWaitDialog.HasCanceled(out bool canceled);
                 if (res != VSConstants.S_OK)
                     return false;
 
@@ -76,6 +73,8 @@
 
         static WaitDialog Create(IVsThreadedWaitDialogFactory dialogFactory)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (factory == null) {
                 factory = dialogFactory ?? VsServiceProvider
                     .GetService<SVsThreadedWaitDialogFactory, IVsThreadedWaitDialogFactory>();
@@ -83,8 +82,7 @@
                     return null;
             }
 
-            IVsThreadedWaitDialog2 vsWaitDialog = null;
-            factory.CreateInstance(out vsWaitDialog);
+            factory.CreateInstance(out IVsThreadedWaitDialog2 vsWaitDialog);
             if (vsWaitDialog == null)
                 return null;
 
@@ -105,6 +103,8 @@
             bool showMarqueeProgress = true,
             IVsThreadedWaitDialogFactory dialogFactory = null)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var dialog = Create(dialogFactory);
             if (dialog == null)
                 return null;
@@ -129,6 +129,8 @@
             bool isCancelable = false,
             IVsThreadedWaitDialogFactory dialogFactory = null)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var dialog = Create(dialogFactory);
             if (dialog == null)
                 return null;
@@ -151,12 +153,13 @@
             string statusBarText = null,
             bool disableCancel = false)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (!Running)
                 return;
 
-            bool canceled = false;
             int res = VsWaitDialog.UpdateProgress(message, progressText,
-                statusBarText, currentStep, totalSteps, disableCancel, out canceled);
+                statusBarText, currentStep, totalSteps, disableCancel, out bool canceled);
 
             if (res != VSConstants.S_OK)
                 return;
@@ -167,18 +170,22 @@
 
         public void Stop()
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (!Running)
                 return;
 
             Running = false;
-            int canceled = 0;
-            VsWaitDialog.EndWaitDialog(out canceled);
+            VsWaitDialog.EndWaitDialog(out int canceled);
             Canceled = (canceled != 0);
         }
 
         void IDisposable.Dispose()
         {
-            Stop();
+            ThreadHelper.JoinableTaskFactory.Run(async () => {
+                await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+                Stop();
+            });
         }
     }
 }
diff --git a/QtVsTools.Package/Common/Concurrent.cs b/QtVsTools.Package/Common/Concurrent.cs
index d1426f4..c963968 100644
--- a/QtVsTools.Package/Common/Concurrent.cs
+++ b/QtVsTools.Package/Common/Concurrent.cs
@@ -40,12 +40,9 @@
     public abstract class Concurrent<TSubClass>
         where TSubClass : Concurrent<TSubClass>
     {
-        private static readonly object _StaticCriticalSection = new object();
-        protected static object StaticCriticalSection => _StaticCriticalSection;
+        protected static object StaticCriticalSection { get; } = new object();
 
-        private object _CriticalSection = null;
-        protected object CriticalSection =>
-            StaticThreadSafeInit(() => _CriticalSection, () => _CriticalSection = new object());
+        protected object CriticalSection { get; } = new object();
 
         protected T ThreadSafeInit<T>(Func<T> getValue, Action init)
             where T : class
diff --git a/QtVsTools.Package/Common/ConcurrentStopwatch.cs b/QtVsTools.Package/Common/ConcurrentStopwatch.cs
index 82547e0..35f78b3 100644
--- a/QtVsTools.Package/Common/ConcurrentStopwatch.cs
+++ b/QtVsTools.Package/Common/ConcurrentStopwatch.cs
@@ -33,7 +33,7 @@
 {
     public class ConcurrentStopwatch : Concurrent<ConcurrentStopwatch>
     {
-        Stopwatch Stopwatch { get; set; }
+        Stopwatch Stopwatch { get; }
 
         public ConcurrentStopwatch()
         {
diff --git a/QtVsTools.Package/Common/Json/DeferredObject.cs b/QtVsTools.Package/Common/Json/DeferredObject.cs
index 9ecc47b..d8c2a06 100644
--- a/QtVsTools.Package/Common/Json/DeferredObject.cs
+++ b/QtVsTools.Package/Common/Json/DeferredObject.cs
@@ -26,8 +26,6 @@
 **
 ****************************************************************************/
 
-using System;
-using System.Collections.Generic;
 using System.Runtime.Serialization;
 
 namespace QtVsTools.Json
diff --git a/QtVsTools.Package/Common/Json/Serializable.cs b/QtVsTools.Package/Common/Json/Serializable.cs
index 2d2b990..32e02b4 100644
--- a/QtVsTools.Package/Common/Json/Serializable.cs
+++ b/QtVsTools.Package/Common/Json/Serializable.cs
@@ -48,7 +48,7 @@
     {
         #region //////////////////// Prototype ////////////////////////////////////////////////////
 
-        protected Serializer Serializer { get; set; }
+        private Serializer Serializer { get; set; }
 
         protected Serializable()
         { }
@@ -192,9 +192,11 @@
                 var container = toDo.Dequeue();
                 foreach (var defObj in container.PendingObjects) {
                     defObj.Deserialize();
-                    var subContainer = defObj.Object as IDeferredObjectContainer;
-                    if (subContainer != null && subContainer.PendingObjects.Any())
+                    if (defObj.Object is IDeferredObjectContainer subContainer
+                        && subContainer.PendingObjects.Any()) {
                         toDo.Enqueue(subContainer);
+
+                    }
                 }
             }
             return obj;
diff --git a/QtVsTools.Package/Common/Json/SerializableEnum.cs b/QtVsTools.Package/Common/Json/SerializableEnum.cs
index 6493668..832c42c 100644
--- a/QtVsTools.Package/Common/Json/SerializableEnum.cs
+++ b/QtVsTools.Package/Common/Json/SerializableEnum.cs
@@ -27,7 +27,6 @@
 ****************************************************************************/
 
 using System;
-using System.ComponentModel;
 using System.Linq;
 using System.Reflection;
 
@@ -106,7 +105,7 @@
 
     class EnumStringAttribute : Attribute
     {
-        public string ValueString { get; private set; }
+        public string ValueString { get; }
 
         public EnumStringAttribute(string enumValueString)
         {
diff --git a/QtVsTools.Package/Common/Json/Serializer.cs b/QtVsTools.Package/Common/Json/Serializer.cs
index d263207..8121eed 100644
--- a/QtVsTools.Package/Common/Json/Serializer.cs
+++ b/QtVsTools.Package/Common/Json/Serializer.cs
@@ -36,6 +36,7 @@
 using System.Runtime.Serialization.Json;
 using System.Text;
 using System.Xml;
+using QtVsTools.Core;
 
 /// <summary>
 /// The classes in this namespace provide support to the serialization and deserialization of
@@ -127,11 +128,10 @@
                     serializer.WriteObject(writer, obj);
                     writer.Close();
                     return new JsonData() { Stream = stream };
-                } catch (Exception e) {
+                } catch (Exception exception) {
+                    exception.Log();
                     if (stream != null && stream.CanRead && stream.Length > 0)
                         stream.Dispose();
-                    System.Diagnostics.Debug.WriteLine(
-                        e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
                     return null;
                 }
             }
@@ -151,16 +151,14 @@
                     using (reader = XmlReader.Create(data.XmlStream)) {
                         var obj = serializer.ReadObject(reader, false);
 
-                        var container = obj as IDeferredObjectContainer;
-                        if (container != null)
+                        if (obj is IDeferredObjectContainer container)
                             deferredObjects.ForEach(x => container.Add(x));
 
                         return obj;
                     }
 
-                } catch (Exception e) {
-                    System.Diagnostics.Debug.WriteLine(
-                        e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
+                } catch (Exception exception) {
+                    exception.Log();
                     return null;
 
                 } finally {
@@ -206,9 +204,8 @@
                     data.XmlStream = new MemoryStream(xmlData);
                 }
                 return true;
-            } catch (Exception e) {
-                System.Diagnostics.Debug.WriteLine(
-                    e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
+            } catch (Exception exception) {
+                exception.Log();
                 return false;
             }
         }
@@ -245,9 +242,9 @@
 
         #region //////////////////// Data Contract Surrogate //////////////////////////////////////
 
-        static Exclusive<Serializer> sharedInstance = new Exclusive<Serializer>();
+        static readonly Exclusive<Serializer> sharedInstance = new Exclusive<Serializer>();
         private XmlReader reader = null;
-        private List<IDeferredObject> deferredObjects = new List<IDeferredObject>();
+        private readonly List<IDeferredObject> deferredObjects = new List<IDeferredObject>();
 
         public static IJsonData GetCurrentJsonData()
         {
@@ -260,9 +257,8 @@
                 root.Append("</root>");
                 var xmlData = Encoding.UTF8.GetBytes(root.ToString());
                 return new JsonData { XmlStream = new MemoryStream(xmlData) };
-            } catch (Exception e) {
-                System.Diagnostics.Debug.WriteLine(
-                    e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
+            } catch (Exception exception) {
+                exception.Log();
                 return null;
             }
         }
diff --git a/QtVsTools.Package/Common/NativeAPI.cs b/QtVsTools.Package/Common/NativeAPI.cs
index 155db09..4cf3ba9 100644
--- a/QtVsTools.Package/Common/NativeAPI.cs
+++ b/QtVsTools.Package/Common/NativeAPI.cs
@@ -127,12 +127,12 @@
                 szTypeName = "";
             }
             public IntPtr hIcon;
-            public int iIcon;
-            public uint dwAttributes;
+            private readonly int iIcon;
+            private readonly uint dwAttributes;
             [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
-            public string szDisplayName;
+            private readonly string szDisplayName;
             [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_TYPE)]
-            public string szTypeName;
+            private readonly string szTypeName;
         };
 
         [Flags]
diff --git a/QtVsTools.Package/Common/PriorityQueue.cs b/QtVsTools.Package/Common/PriorityQueue.cs
index cdc57e7..af8fffd 100644
--- a/QtVsTools.Package/Common/PriorityQueue.cs
+++ b/QtVsTools.Package/Common/PriorityQueue.cs
@@ -51,8 +51,8 @@
     public abstract class BasePriorityQueue<T, TPriority> : Concurrent, IEnumerable<T>
         where TPriority : IComparable<TPriority>
     {
-        SortedDictionary<TPriority, T> ItemsByPriority { get; set; }
-        Dictionary<object, TPriority> ItemPriority { get; set; }
+        SortedDictionary<TPriority, T> ItemsByPriority { get; }
+        Dictionary<object, TPriority> ItemPriority { get; }
         T Head { get; set; }
         public int Count { get; private set; }
         public bool IsEmpty => (Count == 0);
@@ -61,7 +61,7 @@
         IEnumerator<T> IEnumerable<T>.GetEnumerator() => Items.GetEnumerator();
         IEnumerator IEnumerable.GetEnumerator() => Items.GetEnumerator();
 
-        Func<T, object> GetItemKey { get; set; }
+        Func<T, object> GetItemKey { get; }
 
         public BasePriorityQueue() : this(x => x)
         { }
@@ -102,11 +102,10 @@
             if (item == null)
                 throw new InvalidOperationException("Item cannot be null.");
             lock (CriticalSection) {
-                T oldItem;
-                if (ItemsByPriority.TryGetValue(priority, out oldItem) && !item.Equals(oldItem))
+                if (ItemsByPriority.TryGetValue(priority, out T oldItem) && !item.Equals(oldItem))
                     throw new InvalidOperationException("An item with the same priority exists.");
-                TPriority oldPriority;
-                if (ItemPriority.TryGetValue(GetItemKey(item), out oldPriority)) {
+
+                if (ItemPriority.TryGetValue(GetItemKey(item), out TPriority oldPriority)) {
                     ItemsByPriority.Remove(oldPriority);
                     --Count;
                 }
@@ -128,8 +127,7 @@
         public T Peek()
         {
             lock (CriticalSection) {
-                T result;
-                if (!TryPeek(out result))
+                if (!TryPeek(out T result))
                     throw new InvalidOperationException("Queue is empty.");
                 return result;
             }
@@ -167,8 +165,7 @@
         public T Dequeue()
         {
             lock (CriticalSection) {
-                T result;
-                if (!TryDequeue(out result))
+                if (!TryDequeue(out T result))
                     throw new InvalidOperationException("Queue is empty.");
                 return result;
             }
diff --git a/QtVsTools.Package/Common/Prototyped.cs b/QtVsTools.Package/Common/Prototyped.cs
index cba7019..94bd14b 100644
--- a/QtVsTools.Package/Common/Prototyped.cs
+++ b/QtVsTools.Package/Common/Prototyped.cs
@@ -134,7 +134,7 @@
 
             static readonly object classCriticalSection = new object();
 
-            static Dictionary<Type, List<Type>> types = GetTypeHierarchy(typeof(TBase));
+            static readonly Dictionary<Type, List<Type>> types = GetTypeHierarchy(typeof(TBase));
 
             static Dictionary<Type, List<Type>> GetTypeHierarchy(Type baseType)
             {
@@ -174,7 +174,7 @@
                 return subTypes;
             }
 
-            static Dictionary<Type, SubClass> classes = types
+            static readonly Dictionary<Type, SubClass> classes = types
                 .ToDictionary(x => x.Key, x => Create(x.Key, x.Value));
 
             static SubClass Create(Type type, IEnumerable<Type> subTypes)
@@ -194,8 +194,7 @@
 
                 lock (classCriticalSection) {
 
-                    SubClass subClass = null;
-                    if (!classes.TryGetValue(type, out subClass)) {
+                    if (!classes.TryGetValue(type, out SubClass subClass)) {
 
                         var newTypes = GetTypeHierarchy(type)
                             .Where(x => !classes.ContainsKey(x.Key));
@@ -213,7 +212,7 @@
                 }
             }
 
-            public static SubClass baseClass = Get(typeof(TBase));
+            public static readonly SubClass baseClass = Get(typeof(TBase));
         }
 
         #endregion //////////////////// SubClass //////////////////////////////////////////////////
diff --git a/QtVsTools.Package/Common/Timestamp.cs b/QtVsTools.Package/Common/Timestamp.cs
index deaf18a..cf3155e 100644
--- a/QtVsTools.Package/Common/Timestamp.cs
+++ b/QtVsTools.Package/Common/Timestamp.cs
@@ -30,8 +30,12 @@
 
 namespace QtVsTools
 {
+    using Common;
+
     public class Timestamp : Concurrent<Timestamp>
     {
+        static LazyFactory StaticLazy { get; } = new LazyFactory();
+
         long LastTimestamp { get; set; }
         long GetStrictMonotonicTimestamp()
         {
@@ -43,9 +47,8 @@
             }
         }
 
-        static Timestamp _Instance;
-        static Timestamp Instance =>
-            StaticThreadSafeInit(() => _Instance, () => _Instance = new Timestamp());
+        static Timestamp Instance => StaticLazy.Get(() =>
+            Instance, () => new Timestamp());
 
         public static long Next()
         {
diff --git a/QtVsTools.Package/Editors/Editor.QtDesigner.cs b/QtVsTools.Package/Editors/Editor.QtDesigner.cs
index 518bd6c..73148b0 100644
--- a/QtVsTools.Package/Editors/Editor.QtDesigner.cs
+++ b/QtVsTools.Package/Editors/Editor.QtDesigner.cs
@@ -31,12 +31,15 @@
 using System.IO;
 using System.Runtime.InteropServices;
 using System.Threading.Tasks;
-using Microsoft.VisualStudio.Shell.Interop;
-using QtVsTools.QtMsBuild;
-using QtVsTools.VisualStudio;
+using Microsoft.VisualStudio.Shell;
+
+using Task = System.Threading.Tasks.Task;
 
 namespace QtVsTools.Editors
 {
+    using QtMsBuild;
+    using VisualStudio;
+
     [Guid(GuidString)]
     public class QtDesigner : Editor
     {
@@ -58,27 +61,31 @@
 
         protected override void OnStart(Process process)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             base.OnStart(process);
             var document = VsShell.GetDocument(Context, ItemId);
             if (document == null)
                 return;
+
             var project = document.ProjectItem?.ContainingProject;
-            if (project == null || !QtProjectTracker.IsTracked(project))
+            if (project == null || !QtProjectTracker.IsTracked(project.FullName))
                 return;
+            string projectPath = project.FullName;
             string filePath = document.FullName;
             string[] itemId = new[] { document.ProjectItem?.Name };
             var lastWriteTime = File.GetLastWriteTime(filePath);
-            Task.Run(() =>
+            _ = Task.Run(async () =>
             {
                 while (!process.WaitForExit(1000)) {
                     var latestWriteTime = File.GetLastWriteTime(filePath);
                     if (lastWriteTime != latestWriteTime) {
                         lastWriteTime = latestWriteTime;
-                        QtProjectIntellisense.Refresh(project, selectedFiles: itemId);
+                        await QtProjectIntellisense.RefreshAsync(project, projectPath);
                     }
                 }
                 if (lastWriteTime != File.GetLastWriteTime(filePath)) {
-                    QtProjectIntellisense.Refresh(project, selectedFiles: itemId);
+                    await QtProjectIntellisense.RefreshAsync(project, projectPath);
                 }
             });
         }
diff --git a/QtVsTools.Package/Editors/Editor.QtResourceEditor.cs b/QtVsTools.Package/Editors/Editor.QtResourceEditor.cs
index 6c159cd..0c38ad7 100644
--- a/QtVsTools.Package/Editors/Editor.QtResourceEditor.cs
+++ b/QtVsTools.Package/Editors/Editor.QtResourceEditor.cs
@@ -29,7 +29,7 @@
 using System;
 using System.Diagnostics;
 using System.Runtime.InteropServices;
-using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.Shell;
 
 namespace QtVsTools.Editors
 {
@@ -44,18 +44,13 @@
 
         public override string ExecutableName => "QrcEditor.exe";
 
-        protected override string GetToolsPath()
-        {
-            return QtVsToolsPackage.Instance?.PkgInstallPath;
-        }
+        protected override string GetToolsPath() =>
+            QtVsToolsPackage.Instance?.PkgInstallPath;
 
         public override Func<string, bool> WindowFilter =>
             caption => caption.StartsWith(Title);
 
-        protected override string GetTitle(Process editorProcess)
-        {
-            return Title;
-        }
+        protected override string GetTitle(Process editorProcess) => Title;
 
         protected override bool Detached => QtVsToolsPackage.Instance.Options.ResourceEditorDetached;
     }
diff --git a/QtVsTools.Package/Editors/Editor.cs b/QtVsTools.Package/Editors/Editor.cs
index 754f4ba..58db95a 100644
--- a/QtVsTools.Package/Editors/Editor.cs
+++ b/QtVsTools.Package/Editors/Editor.cs
@@ -40,11 +40,12 @@
 using Microsoft.VisualStudio.Shell;
 using Microsoft.VisualStudio.Shell.Interop;
 using Microsoft.VisualStudio.VCProjectEngine;
-using QtVsTools.Core;
-using QtVsTools.VisualStudio;
 
 namespace QtVsTools.Editors
 {
+    using Core;
+    using VisualStudio;
+
     using static Core.HelperFunctions;
 
     public abstract class Editor : IVsEditorFactory
@@ -61,6 +62,7 @@
 
         protected virtual string GetToolsPath()
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
             return GetQtToolsPath() ?? GetDefaultQtToolsPath();
         }
 
@@ -69,33 +71,37 @@
 
         string GetQtToolsPath()
         {
-            var project = VsShell.GetProject(Context);
-            if (project == null)
-                return null;
+            return ThreadHelper.JoinableTaskFactory.Run(async () =>
+            {
+                await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+                var project = VsShell.GetProject(Context);
+                if (project == null)
+                    return null;
 
-            var vcProject = project.Object as VCProject;
-            if (vcProject == null)
-                return null;
+                var vcProject = project.Object as VCProject;
+                if (vcProject == null)
+                    return null;
 
-            var vcConfigs = vcProject.Configurations as IVCCollection;
-            if (vcConfigs == null)
-                return null;
+                var vcConfigs = vcProject.Configurations as IVCCollection;
+                if (vcConfigs == null)
+                    return null;
 
-            var activeConfig = project.ConfigurationManager?.ActiveConfiguration;
-            if (activeConfig == null)
-                return null;
+                var activeConfig = project.ConfigurationManager?.ActiveConfiguration;
+                if (activeConfig == null)
+                    return null;
 
-            var activeConfigId = string.Format("{0}|{1}",
-                activeConfig.ConfigurationName, activeConfig.PlatformName);
-            var vcConfig = vcConfigs.Item(activeConfigId) as VCConfiguration;
-            if (vcConfig == null)
-                return null;
+                var activeConfigId = string.Format("{0}|{1}",
+                    activeConfig.ConfigurationName, activeConfig.PlatformName);
+                var vcConfig = vcConfigs.Item(activeConfigId) as VCConfiguration;
+                if (vcConfig == null)
+                    return null;
 
-            var qtToolsPath = vcConfig.GetEvaluatedPropertyValue("QtToolsPath");
-            if (string.IsNullOrEmpty(qtToolsPath))
-                return null;
+                var qtToolsPath = vcConfig.GetEvaluatedPropertyValue("QtToolsPath");
+                if (string.IsNullOrEmpty(qtToolsPath))
+                    return null;
 
-            return qtToolsPath;
+                return qtToolsPath;
+            });
         }
 
         string GetDefaultQtToolsPath()
@@ -126,6 +132,8 @@
             out Guid pguidCmdUI,
             out int pgrfCDW)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             // Initialize to null
             ppunkDocView = IntPtr.Zero;
             ppunkDocData = IntPtr.Zero;
@@ -202,11 +210,15 @@
         {
             if (string.IsNullOrEmpty(qtToolsPath))
                 qtToolsPath = GetDefaultQtToolsPath();
+            var st = GetStartInfo(filePath, qtToolsPath, hideWindow);
             try {
-                return Process.Start(GetStartInfo(filePath, qtToolsPath, hideWindow));
-            } catch (Exception e) {
-                Messages.Print(
-                    e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
+                return Process.Start(st);
+            } catch (Exception exception) {
+                exception.Log();
+                if (!File.Exists(st.Arguments))
+                    Messages.Print("The system cannot find the file: " + st.Arguments);
+                if (!File.Exists(st.FileName))
+                    Messages.Print("The system cannot find the file: " + st.FileName);
                 return null;
             }
         }
@@ -223,20 +235,20 @@
 
         private class EditorPane : WindowPane, IVsPersistDocData
         {
-            public Editor Editor { get; private set; }
-            public string QtToolsPath { get; private set; }
+            private Editor Editor { get; }
+            private string QtToolsPath { get; }
 
-            public TableLayoutPanel EditorContainer { get; private set; }
-            public Label EditorTitle { get; private set; }
-            public LinkLabel EditorDetachButton { get; private set; }
-            public Panel EditorControl { get; private set; }
+            private TableLayoutPanel EditorContainer { get; set; }
+            private Label EditorTitle { get; }
+            private LinkLabel EditorDetachButton { get; }
+            private Panel EditorControl { get; }
             public override IWin32Window Window => EditorContainer;
 
-            public Process EditorProcess { get; private set; }
-            public IntPtr EditorWindow { get; private set; }
-            public int EditorWindowStyle { get; private set; }
-            public int EditorWindowStyleExt { get; private set; }
-            public IntPtr EditorIcon { get; private set; }
+            private Process EditorProcess { get; set; }
+            private IntPtr EditorWindow { get; set; }
+            private int EditorWindowStyle { get; set; }
+            private int EditorWindowStyleExt { get; set; }
+            private IntPtr EditorIcon { get; set; }
 
             public EditorPane(Editor editor, string qtToolsPath)
             {
@@ -306,11 +318,11 @@
 
             int IVsPersistDocData.LoadDocData(string pszMkDocument)
             {
-                var solution = GetService(typeof(SVsSolution)) as IVsSolution;
                 EditorProcess = Editor.Start(pszMkDocument, QtToolsPath,
                     hideWindow: !Editor.Detached);
                 if (EditorProcess == null)
                     return VSConstants.E_FAIL;
+
                 if (Editor.Detached) {
                     Editor.OnStart(EditorProcess);
                     CloseParentFrame();
@@ -395,8 +407,12 @@
             {
                 EditorProcess = null;
                 EditorWindow = IntPtr.Zero;
-                var parentFrame = GetService(typeof(SVsWindowFrame)) as IVsWindowFrame;
-                parentFrame?.CloseFrame((uint)__FRAMECLOSE.FRAMECLOSE_NoSave);
+                ThreadHelper.JoinableTaskFactory.Run(async () =>
+                {
+                    await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+                    var parentFrame = GetService(typeof(SVsWindowFrame)) as IVsWindowFrame;
+                    parentFrame?.CloseFrame((uint)__FRAMECLOSE.FRAMECLOSE_NoSave);
+                });
             }
 
             private void EditorProcess_Exited(object sender, EventArgs e)
@@ -452,7 +468,7 @@
                     EditorWindow = IntPtr.Zero;
 
                     // Close editor window
-                    System.Threading.Tasks.Task.Run(() =>
+                    _ = System.Threading.Tasks.Task.Run(() =>
                     {
                         NativeAPI.SendMessage(editorWindow, NativeAPI.WM_CLOSE, 0, 0);
                         if (!editorProcess.WaitForExit(500)) {
diff --git a/QtVsTools.Package/Icons/Monikers.imagemanifest b/QtVsTools.Package/Icons/Monikers.imagemanifest
new file mode 100644
index 0000000..27e1e2b
--- /dev/null
+++ b/QtVsTools.Package/Icons/Monikers.imagemanifest
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ImageManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+               xmlns="http://schemas.microsoft.com/VisualStudio/ImageManifestSchema/2014">
+  <Symbols>
+    <String Name="Resources" Value="/QtVsTools;Component/Icons" />
+    <Guid Name="QtMonikersGuid" Value="{0d2e443f-6dbb-4001-99dc-9cd7d5c924e7}" />
+    <ID Name="prf" Value="0" />
+    <ID Name="pri" Value="1" />
+    <ID Name="pro" Value="2" />
+    <ID Name="qml" Value="3" />
+    <ID Name="qrc" Value="4" />
+    <ID Name="ts" Value="5" />
+    <ID Name="ui" Value="6" />
+  </Symbols>
+  <Images>
+    <Image Guid="$(QtMonikersGuid)" ID="$(prf)">
+      <Source Uri="$(Resources)/prf32.png">
+        <Size Value="32" />
+      </Source>
+    </Image>
+    <Image Guid="$(QtMonikersGuid)" ID="$(pri)">
+      <Source Uri="$(Resources)/pri32.png">
+        <Size Value="32" />
+      </Source>
+    </Image>
+    <Image Guid="$(QtMonikersGuid)" ID="$(pro)">
+      <Source Uri="$(Resources)/pro32.png">
+        <Size Value="32" />
+      </Source>
+    </Image>
+    <Image Guid="$(QtMonikersGuid)" ID="$(qml)">
+      <Source Uri="$(Resources)/qml32.png">
+        <Size Value="32" />
+      </Source>
+    </Image>
+    <Image Guid="$(QtMonikersGuid)" ID="$(qrc)">
+      <Source Uri="$(Resources)/qrc32.png">
+        <Size Value="32" />
+      </Source>
+    </Image>
+    <Image Guid="$(QtMonikersGuid)" ID="$(ts)">
+      <Source Uri="$(Resources)/ts32.png">
+        <Size Value="32" />
+      </Source>
+    </Image>
+    <Image Guid="$(QtMonikersGuid)" ID="$(ui)">
+      <Source Uri="$(Resources)/ui32.png">
+        <Size Value="32" />
+      </Source>
+    </Image>
+  </Images>
+  <ImageLists />
+</ImageManifest>
diff --git a/QtVsTools.Package/Icons/prf32.png b/QtVsTools.Package/Icons/prf32.png
new file mode 100644
index 0000000..359c5c8
--- /dev/null
+++ b/QtVsTools.Package/Icons/prf32.png
Binary files differ
diff --git a/QtVsTools.Package/Icons/pri32.png b/QtVsTools.Package/Icons/pri32.png
new file mode 100644
index 0000000..f82fea4
--- /dev/null
+++ b/QtVsTools.Package/Icons/pri32.png
Binary files differ
diff --git a/QtVsTools.Package/Icons/pro32.png b/QtVsTools.Package/Icons/pro32.png
new file mode 100644
index 0000000..13d8a84
--- /dev/null
+++ b/QtVsTools.Package/Icons/pro32.png
Binary files differ
diff --git a/QtVsTools.Package/Icons/qml32.png b/QtVsTools.Package/Icons/qml32.png
new file mode 100644
index 0000000..85ad155
--- /dev/null
+++ b/QtVsTools.Package/Icons/qml32.png
Binary files differ
diff --git a/QtVsTools.Package/Icons/qrc32.png b/QtVsTools.Package/Icons/qrc32.png
new file mode 100644
index 0000000..b4b70d8
--- /dev/null
+++ b/QtVsTools.Package/Icons/qrc32.png
Binary files differ
diff --git a/QtVsTools.Package/Icons/ts32.png b/QtVsTools.Package/Icons/ts32.png
new file mode 100644
index 0000000..9731b08
--- /dev/null
+++ b/QtVsTools.Package/Icons/ts32.png
Binary files differ
diff --git a/QtVsTools.Package/Icons/ui32.png b/QtVsTools.Package/Icons/ui32.png
new file mode 100644
index 0000000..5a40101
--- /dev/null
+++ b/QtVsTools.Package/Icons/ui32.png
Binary files differ
diff --git a/QtVsTools.Package/Legacy/ChangeFor.cs b/QtVsTools.Package/Legacy/ChangeFor.cs
new file mode 100644
index 0000000..8eb45fd
--- /dev/null
+++ b/QtVsTools.Package/Legacy/ChangeFor.cs
@@ -0,0 +1,32 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+namespace QtVsTools.Legacy
+{
+    internal enum ChangeFor { Solution, Project }
+}
diff --git a/QtVsTools.Package/Legacy/FormChangeQtVersion.Designer.cs b/QtVsTools.Package/Legacy/FormChangeQtVersion.Designer.cs
new file mode 100644
index 0000000..52fdac0
--- /dev/null
+++ b/QtVsTools.Package/Legacy/FormChangeQtVersion.Designer.cs
@@ -0,0 +1,87 @@
+namespace QtVsTools.Legacy
+{
+    partial class FormChangeQtVersion
+    {
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            btnOK = new System.Windows.Forms.Button();
+            btnCancel = new System.Windows.Forms.Button();
+            lbQtVersions = new System.Windows.Forms.ListBox();
+            lQtVersions = new System.Windows.Forms.Label();
+            SuspendLayout();
+            //
+            // btnOK
+            //
+            btnOK.DialogResult = System.Windows.Forms.DialogResult.OK;
+            btnOK.Location = new System.Drawing.Point(124, 231);
+            btnOK.Name = "btnOK";
+            btnOK.Size = new System.Drawing.Size(75, 23);
+            btnOK.TabIndex = 1;
+            btnOK.Text = "&OK";
+            btnOK.UseVisualStyleBackColor = true;
+            //
+            // btnCancel
+            //
+            btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            btnCancel.Location = new System.Drawing.Point(205, 231);
+            btnCancel.Name = "btnCancel";
+            btnCancel.Size = new System.Drawing.Size(75, 23);
+            btnCancel.TabIndex = 2;
+            btnCancel.Text = "&Cancel";
+            btnCancel.UseVisualStyleBackColor = true;
+            //
+            // lbQtVersions
+            //
+            lbQtVersions.FormattingEnabled = true;
+            lbQtVersions.Location = new System.Drawing.Point(13, 39);
+            lbQtVersions.Name = "lbQtVersions";
+            lbQtVersions.Size = new System.Drawing.Size(267, 173);
+            lbQtVersions.TabIndex = 0;
+            //
+            // lQtVersions
+            //
+            lQtVersions.AutoSize = true;
+            lQtVersions.Location = new System.Drawing.Point(13, 20);
+            lQtVersions.Name = "lQtVersions";
+            lQtVersions.Size = new System.Drawing.Size(103, 13);
+            lQtVersions.TabIndex = 3;
+            lQtVersions.Text = "Installed Qt Versions";
+            //
+            // FormChangeQtVersion
+            //
+            AcceptButton = btnOK;
+            AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            CancelButton = btnCancel;
+            ClientSize = new System.Drawing.Size(292, 266);
+            Controls.Add(lQtVersions);
+            Controls.Add(lbQtVersions);
+            Controls.Add(btnCancel);
+            Controls.Add(btnOK);
+            FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+            KeyPreview = true;
+            MaximizeBox = false;
+            MinimizeBox = false;
+            Name = "FormChangeQtVersion";
+            ShowInTaskbar = false;
+            Text = "FormChangeQtVersion";
+            ResumeLayout(false);
+            PerformLayout();
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Button btnOK;
+        private System.Windows.Forms.Button btnCancel;
+        private System.Windows.Forms.ListBox lbQtVersions;
+        private System.Windows.Forms.Label lQtVersions;
+    }
+}
diff --git a/QtVsTools.Package/Legacy/FormChangeQtVersion.cs b/QtVsTools.Package/Legacy/FormChangeQtVersion.cs
new file mode 100644
index 0000000..a001086
--- /dev/null
+++ b/QtVsTools.Package/Legacy/FormChangeQtVersion.cs
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Windows.Forms;
+using Microsoft.VisualStudio.Shell;
+
+namespace QtVsTools.Legacy
+{
+    using Core;
+    using Legacy = Core.Legacy;
+
+    public partial class FormChangeQtVersion : Form
+    {
+        public FormChangeQtVersion()
+        {
+            InitializeComponent();
+            btnOK.Text = "&OK";
+            btnCancel.Text = "&Cancel";
+            lQtVersions.Text = "Installed Qt Versions";
+            lbQtVersions.DoubleClick += OnQtVersions_DoubleClick;
+            KeyPress += FormChangeQtVersion_KeyPress;
+            Shown += FormChangeQtVersion_Shown;
+        }
+
+        private void FormChangeQtVersion_Shown(object sender, EventArgs e)
+        {
+            Text = "Set Solution's Qt Version";
+        }
+
+        void OnQtVersions_DoubleClick(object sender, EventArgs e)
+        {
+            DialogResult = DialogResult.OK;
+            Close();
+        }
+
+        void FormChangeQtVersion_KeyPress(object sender, KeyPressEventArgs e)
+        {
+            if (e.KeyChar == 27) {
+                DialogResult = DialogResult.Cancel;
+                Close();
+            }
+        }
+
+        internal void UpdateContent(ChangeFor change)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            lbQtVersions.Items.Clear();
+            var vm = QtVersionManager.The();
+            foreach (var versionName in vm.GetVersions())
+                lbQtVersions.Items.Add(versionName);
+
+            lbQtVersions.Items.Add("$(DefaultQtVersion)");
+            if (change == ChangeFor.Solution) {
+                var qtVer = Legacy.QtVersionManager
+                    .GetSolutionQtVersion(QtVsToolsPackage.Instance.Dte.Solution);
+                if (qtVer == null)
+                    qtVer = vm.GetDefaultVersion();
+                if (qtVer != null)
+                    lbQtVersions.SelectedItem = qtVer;
+                Text = "Set Solution's Qt Version";
+            } else {
+                var pro = Core.HelperFunctions.GetSelectedProject(QtVsToolsPackage.Instance.Dte);
+                var qtVer = vm.GetProjectQtVersion(pro);
+                if (qtVer == null)
+                    qtVer = vm.GetDefaultVersion();
+                if (qtVer != null)
+                    lbQtVersions.SelectedItem = qtVer;
+                Text = "Set Project's Qt Version";
+            }
+        }
+
+        public string GetSelectedQtVersion()
+        {
+            var idx = lbQtVersions.SelectedIndex;
+            if (idx < 0)
+                return null;
+            return lbQtVersions.Items[idx].ToString();
+        }
+    }
+}
diff --git a/QtVsTools.Package/Legacy/FormChangeQtVersion.resx b/QtVsTools.Package/Legacy/FormChangeQtVersion.resx
new file mode 100644
index 0000000..e0a4c98
--- /dev/null
+++ b/QtVsTools.Package/Legacy/FormChangeQtVersion.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!--
+    Microsoft ResX Schema
+
+    Version 2.0
+
+    The primary goals of this format is to allow a simple XML format
+    that is mostly human readable. The generation and parsing of the
+    various data types are done through the TypeConverter classes
+    associated with the data types.
+
+    Example:
+
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+
+    There are any number of "resheader" rows that contain simple
+    name/value pairs.
+
+    Each data row contains a name, and value. The row also contains a
+    type or mimetype. Type corresponds to a .NET class that support
+    text/value conversion through the TypeConverter architecture.
+    Classes that don't support this are serialized and stored with the
+    mimetype set.
+
+    The mimetype is used for serialized objects, and tells the
+    ResXResourceReader how to depersist the object. This is currently not
+    extensible. For a given mimetype the value must be set accordingly:
+
+    Note - application/x-microsoft.net.object.binary.base64 is the format
+    that the ResXResourceWriter will generate, however the reader can
+    read any of the formats listed below.
+
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file
diff --git a/QtVsTools.Package/Legacy/FormProjectQtSettings.Designer.cs b/QtVsTools.Package/Legacy/FormProjectQtSettings.Designer.cs
new file mode 100644
index 0000000..76265ea
--- /dev/null
+++ b/QtVsTools.Package/Legacy/FormProjectQtSettings.Designer.cs
@@ -0,0 +1,159 @@
+using System.Windows.Forms;
+
+namespace QtVsTools.Legacy
+{
+    partial class FormProjectQtSettings
+    {
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.OptionsPropertyGrid = new System.Windows.Forms.PropertyGrid();
+            this.panel1 = new System.Windows.Forms.Panel();
+            this.okButton = new System.Windows.Forms.Button();
+            this.cancelButton = new System.Windows.Forms.Button();
+            this.tabControl1 = new System.Windows.Forms.TabControl();
+            this.tabPage1 = new System.Windows.Forms.TabPage();
+            this.tabPage2 = new System.Windows.Forms.TabPage();
+            this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
+            this.panel1.SuspendLayout();
+            this.tabControl1.SuspendLayout();
+            this.tabPage1.SuspendLayout();
+            this.tabPage2.SuspendLayout();
+            this.SuspendLayout();
+            //
+            // OptionsPropertyGrid
+            //
+            this.OptionsPropertyGrid.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.OptionsPropertyGrid.HelpVisible = false;
+            this.OptionsPropertyGrid.Location = new System.Drawing.Point(6, 6);
+            this.OptionsPropertyGrid.Margin = new System.Windows.Forms.Padding(6);
+            this.OptionsPropertyGrid.Name = "OptionsPropertyGrid";
+            this.OptionsPropertyGrid.PropertySort = System.Windows.Forms.PropertySort.Alphabetical;
+            this.OptionsPropertyGrid.Size = new System.Drawing.Size(898, 603);
+            this.OptionsPropertyGrid.TabIndex = 8;
+            this.OptionsPropertyGrid.ToolbarVisible = false;
+            //
+            // panel1
+            //
+            this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+            this.panel1.Controls.Add(this.okButton);
+            this.panel1.Controls.Add(this.cancelButton);
+            this.panel1.Location = new System.Drawing.Point(620, 700);
+            this.panel1.Margin = new System.Windows.Forms.Padding(6);
+            this.panel1.Name = "panel1";
+            this.panel1.Size = new System.Drawing.Size(336, 73);
+            this.panel1.TabIndex = 9;
+            //
+            // okButton
+            //
+            this.okButton.Location = new System.Drawing.Point(16, 15);
+            this.okButton.Margin = new System.Windows.Forms.Padding(6);
+            this.okButton.Name = "okButton";
+            this.okButton.Size = new System.Drawing.Size(150, 44);
+            this.okButton.TabIndex = 0;
+            this.okButton.Click += new System.EventHandler(this.OkButton_Click);
+            this.okButton.Text = "&OK";
+            //
+            // cancelButton
+            //
+            this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            this.cancelButton.Location = new System.Drawing.Point(176, 15);
+            this.cancelButton.Margin = new System.Windows.Forms.Padding(6);
+            this.cancelButton.Name = "cancelButton";
+            this.cancelButton.Size = new System.Drawing.Size(150, 44);
+            this.cancelButton.TabIndex = 1;
+            this.cancelButton.Text = "Cancel";
+            //
+            // tabControl1
+            //
+            this.tabControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+            | System.Windows.Forms.AnchorStyles.Left)
+            | System.Windows.Forms.AnchorStyles.Right)));
+            this.tabControl1.Controls.Add(this.tabPage1);
+            this.tabControl1.Controls.Add(this.tabPage2);
+            this.tabControl1.Location = new System.Drawing.Point(24, 23);
+            this.tabControl1.Margin = new System.Windows.Forms.Padding(6);
+            this.tabControl1.Name = "tabControl1";
+            this.tabControl1.SelectedIndex = 0;
+            this.tabControl1.Size = new System.Drawing.Size(926, 662);
+            this.tabControl1.TabIndex = 10;
+            //
+            // tabPage1
+            //
+            this.tabPage1.BackColor = System.Drawing.SystemColors.Control;
+            this.tabPage1.Controls.Add(this.OptionsPropertyGrid);
+            this.tabPage1.Location = new System.Drawing.Point(8, 39);
+            this.tabPage1.Margin = new System.Windows.Forms.Padding(6);
+            this.tabPage1.Name = "tabPage1";
+            this.tabPage1.Padding = new System.Windows.Forms.Padding(6);
+            this.tabPage1.Size = new System.Drawing.Size(910, 615);
+            this.tabPage1.TabIndex = 0;
+            this.tabPage1.Text = "Properties";
+            //
+            // tabPage2
+            //
+            this.tabPage2.BackColor = System.Drawing.SystemColors.Control;
+            this.tabPage2.Controls.Add(this.flowLayoutPanel1);
+            this.tabPage2.Location = new System.Drawing.Point(8, 39);
+            this.tabPage2.Margin = new System.Windows.Forms.Padding(6);
+            this.tabPage2.Name = "tabPage2";
+            this.tabPage2.Padding = new System.Windows.Forms.Padding(6);
+            this.tabPage2.Size = new System.Drawing.Size(910, 615);
+            this.tabPage2.TabIndex = 1;
+            this.tabPage2.Text = "Qt Modules";
+            //
+            // flowLayoutPanel1
+            //
+            this.flowLayoutPanel1.AutoScroll = true;
+            this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
+            this.flowLayoutPanel1.Location = new System.Drawing.Point(6, 6);
+            this.flowLayoutPanel1.Name = "flowLayoutPanel1";
+            this.flowLayoutPanel1.Size = new System.Drawing.Size(898, 603);
+            this.flowLayoutPanel1.TabIndex = 66;
+            //
+            // FormProjectQtSettings
+            //
+            this.AcceptButton = this.okButton;
+            this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.CancelButton = this.cancelButton;
+            this.ClientSize = new System.Drawing.Size(962, 801);
+            this.Controls.Add(this.tabControl1);
+            this.Controls.Add(this.panel1);
+            this.KeyPreview = true;
+            this.Margin = new System.Windows.Forms.Padding(6);
+            this.MaximizeBox = false;
+            this.MinimizeBox = false;
+            this.MinimumSize = new System.Drawing.Size(988, 750);
+            this.Name = "FormProjectQtSettings";
+            this.ShowIcon = false;
+            this.ShowInTaskbar = false;
+            this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show;
+            this.Text = "Qt Project Settings";
+            this.panel1.ResumeLayout(false);
+            this.tabControl1.ResumeLayout(false);
+            this.tabPage1.ResumeLayout(false);
+            this.tabPage2.ResumeLayout(false);
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private PropertyGrid OptionsPropertyGrid;
+        private Panel panel1;
+        private Button okButton;
+        private Button cancelButton;
+        private TabControl tabControl1;
+        private TabPage tabPage1;
+        private TabPage tabPage2;
+        private FlowLayoutPanel flowLayoutPanel1;
+    }
+}
diff --git a/QtVsTools.Package/Legacy/FormProjectQtSettings.cs b/QtVsTools.Package/Legacy/FormProjectQtSettings.cs
new file mode 100644
index 0000000..93a7be0
--- /dev/null
+++ b/QtVsTools.Package/Legacy/FormProjectQtSettings.cs
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Windows.Forms;
+using System.IO;
+using EnvDTE;
+
+namespace QtVsTools.Legacy
+{
+    using Core;
+    using Legacy = Core.Legacy;
+
+    public partial class FormProjectQtSettings : Form
+    {
+        private readonly Project project;
+        private readonly ProjectQtSettings qtSettings;
+        private readonly List<ModuleItem> moduleMap = new List<ModuleItem>();
+
+        private struct ModuleItem
+        {
+            public readonly CheckBox checkbox;
+            public readonly int moduleId;
+            public bool initialValue;
+
+            public ModuleItem(CheckBox cb, int mid, bool init)
+            {
+                checkbox = cb;
+                moduleId = mid;
+                initialValue = init;
+            }
+        }
+
+        public FormProjectQtSettings(Project pro)
+        {
+            InitializeComponent();
+
+            project = pro;
+            qtSettings = new ProjectQtSettings(project);
+            qtSettings.PropertyChanged += OnPropertyChanged;
+            OptionsPropertyGrid.SelectedObject = qtSettings;
+
+            InitModules(QtVersionManager.The().GetProjectQtVersion(project));
+        }
+
+        protected override bool ProcessDialogKey(Keys keyData)
+        {
+            if (ModifierKeys == Keys.None && keyData == Keys.Escape) {
+                Close();
+                return true;
+            }
+            return base.ProcessDialogKey(keyData);
+        }
+
+        private void OkButton_Click(object sender, EventArgs e)
+        {
+            // Disable the buttons since some operations are quite expensive (e.g. changing
+            // the Qt version) and take some to finish. Keeping the buttons enabled allows to hit
+            // the buttons several times resulting in successive executions of these operations.
+            okButton.Enabled = false;
+            cancelButton.Enabled = false;
+
+            qtSettings.SaveSettings();
+            SaveModules();
+            okButton.DialogResult = DialogResult.OK;
+            Close();
+        }
+
+        private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
+        {
+            if (e.PropertyName != "Version")
+                throw new ArgumentException();
+            InitModules(qtSettings.Version);
+        }
+
+        private void InitModules(string qtVersion)
+        {
+            moduleMap.Clear();
+            flowLayoutPanel1.Controls.Clear();
+
+            var vm = QtVersionManager.The();
+            var versionInfo = vm.GetVersionInfo(qtVersion);
+            if (string.IsNullOrEmpty(qtVersion) || versionInfo == null) {
+                flowLayoutPanel1.Controls.Add(new Label
+                {
+                    Text = Environment.NewLine
+                        + "Please set a valid Qt version first.",
+                    AutoSize = true
+                });
+                return;
+            }
+
+            var installPath = vm.GetInstallPath(qtVersion) ?? string.Empty;
+            var modules = QtModules.Instance.GetAvailableModules(versionInfo.qtMajor)
+                .Where(x => x.Selectable)
+                .OrderBy(x => x.Name);
+            foreach (var module in modules) {
+                var checkBox = new CheckBox
+                {
+                    Margin = new Padding(6),
+                    Location = new System.Drawing.Point(150, 150),
+                    Name = module.LibraryPrefix,
+                    UseVisualStyleBackColor = true,
+                    AutoSize = true,
+                    Text = module.Name,
+                    Checked = Legacy.QtProject.HasModule(project, module.Id, qtVersion)
+                };
+                flowLayoutPanel1.Controls.Add(checkBox);
+                moduleMap.Add(new ModuleItem(checkBox, module.Id, checkBox.Checked));
+
+                var info = QtModules.Instance.Module(module.Id, versionInfo.qtMajor);
+                var libraryPrefix = info?.LibraryPrefix;
+                if (libraryPrefix.StartsWith("Qt", StringComparison.Ordinal))
+                    libraryPrefix = "Qt" + versionInfo.qtMajor + libraryPrefix.Substring(2);
+                checkBox.Enabled = new FileInfo(
+                    Path.Combine(installPath, "lib", $"{libraryPrefix}{versionInfo.LibInfix()}.lib")
+                ).Exists; // Disable the check-box if the module is not installed.
+                if (!checkBox.Enabled)
+                    checkBox.Checked = false; // Uncheck if the module is not installed.
+            }
+        }
+
+        private void SaveModules()
+        {
+            for (var i = 0; i < moduleMap.Count; ++i) {
+                var item = moduleMap[i];
+                var isModuleChecked = item.checkbox.Checked;
+                if (isModuleChecked != item.initialValue) {
+                    if (isModuleChecked)
+                        Legacy.QtProject.AddModule(project, item.moduleId);
+                    else
+                        Legacy.QtProject.RemoveModule(project, item.moduleId);
+                }
+            }
+        }
+
+    }
+}
diff --git a/QtVsTools.Package/Legacy/FormProjectQtSettings.resx b/QtVsTools.Package/Legacy/FormProjectQtSettings.resx
new file mode 100644
index 0000000..c7e0d4b
--- /dev/null
+++ b/QtVsTools.Package/Legacy/FormProjectQtSettings.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file
diff --git a/QtVsTools.Package/Legacy/ProjectQtSettings.cs b/QtVsTools.Package/Legacy/ProjectQtSettings.cs
new file mode 100644
index 0000000..1cc4d53
--- /dev/null
+++ b/QtVsTools.Package/Legacy/ProjectQtSettings.cs
@@ -0,0 +1,336 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.ComponentModel;
+using System.Globalization;
+using System.Text.RegularExpressions;
+
+namespace QtVsTools.Legacy
+{
+    using Core;
+    using Legacy = Core.Legacy;
+
+    public class ProjectQtSettings : INotifyPropertyChanged
+    {
+        public event PropertyChangedEventHandler PropertyChanged;
+        protected void OnPropertyChanged(string propertyName)
+        {
+            var eventHandler = PropertyChanged;
+            if (eventHandler != null)
+                eventHandler.Invoke(this, new PropertyChangedEventArgs(propertyName));
+        }
+
+        public ProjectQtSettings(EnvDTE.Project proj)
+        {
+            versionManager = QtVersionManager.The();
+            project = proj;
+            newMocDir = oldMocDir = Legacy.QtVSIPSettings.GetMocDirectory(project);
+            newMocOptions = oldMocOptions = Legacy.QtVSIPSettings.GetMocOptions(project);
+            newRccDir = oldRccDir = Legacy.QtVSIPSettings.GetRccDirectory(project);
+            newUicDir = oldUicDir = Legacy.QtVSIPSettings.GetUicDirectory(project);
+            newLUpdateOnBuild = oldLUpdateOnBuild = Legacy.QtVSIPSettings.GetLUpdateOnBuild(project);
+            newLUpdateOptions = oldLUpdateOptions = Legacy.QtVSIPSettings.GetLUpdateOptions(project);
+            newLReleaseOptions = oldLReleaseOptions = Legacy.QtVSIPSettings.GetLReleaseOptions(project);
+            newQtVersion = oldQtVersion = versionManager.GetProjectQtVersion(project);
+            QmlDebug = oldQmlDebug = Legacy.QtVSIPSettings.GetQmlDebug(project);
+        }
+
+        private readonly QtVersionManager versionManager;
+        private EnvDTE.Project project;
+
+        private readonly string oldMocDir;
+        private readonly string oldMocOptions;
+        private readonly string oldRccDir;
+        private readonly string oldUicDir;
+        private readonly string oldQtVersion;
+        private readonly bool oldLUpdateOnBuild;
+        private readonly string oldLUpdateOptions;
+        private readonly string oldLReleaseOptions;
+        private readonly bool oldQmlDebug;
+
+        private string newMocDir;
+        private string newMocOptions;
+        private string newRccDir;
+        private string newUicDir;
+        private string newQtVersion;
+        private bool newLUpdateOnBuild;
+        private string newLUpdateOptions;
+        private string newLReleaseOptions;
+
+        public void SaveSettings()
+        {
+            var updateMoc = false;
+            var qtPro = QtProject.Create(project);
+
+            if (oldMocDir != newMocDir) {
+                Legacy.QtVSIPSettings.SaveMocDirectory(project, newMocDir);
+                updateMoc = true;
+            }
+            if (oldMocOptions != newMocOptions) {
+                Legacy.QtVSIPSettings.SaveMocOptions(project, newMocOptions);
+                updateMoc = true;
+            }
+            if (updateMoc)
+                qtPro.UpdateMocSteps(oldMocDir);
+
+            if (oldUicDir != newUicDir) {
+                Legacy.QtVSIPSettings.SaveUicDirectory(project, newUicDir);
+                qtPro.UpdateUicSteps(oldUicDir, true);
+            }
+
+            if (oldRccDir != newRccDir) {
+                Legacy.QtVSIPSettings.SaveRccDirectory(project, newRccDir);
+                qtPro.RefreshRccSteps(oldRccDir);
+            }
+
+            if (oldLUpdateOnBuild != newLUpdateOnBuild)
+                Legacy.QtVSIPSettings.SaveLUpdateOnBuild(project, newLUpdateOnBuild);
+
+            if (oldLUpdateOptions != newLUpdateOptions)
+                Legacy.QtVSIPSettings.SaveLUpdateOptions(project, newLUpdateOptions);
+
+            if (oldLReleaseOptions != newLReleaseOptions)
+                Legacy.QtVSIPSettings.SaveLReleaseOptions(project, newLReleaseOptions);
+
+            if (oldQmlDebug != QmlDebug)
+                Legacy.QtVSIPSettings.SaveQmlDebug(project, QmlDebug);
+
+            if (oldQtVersion != newQtVersion) {
+                if (Legacy.QtProject.PromptChangeQtVersion(project, oldQtVersion, newQtVersion)) {
+                    var newProjectCreated = false;
+                    var versionChanged = qtPro.ChangeQtVersion(
+                        oldQtVersion, newQtVersion, ref newProjectCreated);
+                    if (versionChanged && newProjectCreated)
+                        project = qtPro.Project;
+                }
+            }
+        }
+
+        public string MocDirectory
+        {
+            get
+            {
+                return newMocDir;
+            }
+            set
+            {
+                var tmp = HelperFunctions.NormalizeRelativeFilePath(value);
+                if (tmp.Equals(oldMocDir, StringComparison.OrdinalIgnoreCase))
+                    return;
+
+                string badMacros = IncompatibleMacros(tmp);
+                if (!string.IsNullOrEmpty(badMacros))
+                    Messages.DisplayErrorMessage(SR.GetString("IncompatibleMacros", badMacros));
+                else
+                    newMocDir = tmp;
+            }
+        }
+
+        public string MocOptions
+        {
+            get
+            {
+                return newMocOptions;
+            }
+
+            set
+            {
+                newMocOptions = value;
+            }
+        }
+
+        public string UicDirectory
+        {
+            get
+            {
+                return newUicDir;
+            }
+            set
+            {
+                var tmp = HelperFunctions.NormalizeRelativeFilePath(value);
+                if (tmp.Equals(oldUicDir, StringComparison.OrdinalIgnoreCase))
+                    return;
+
+                string badMacros = IncompatibleMacros(tmp);
+                if (!string.IsNullOrEmpty(badMacros))
+                    Messages.DisplayErrorMessage(SR.GetString("IncompatibleMacros", badMacros));
+                else
+                    newUicDir = tmp;
+            }
+        }
+
+        public string RccDirectory
+        {
+            get
+            {
+                return newRccDir;
+            }
+            set
+            {
+                var tmp = HelperFunctions.NormalizeRelativeFilePath(value);
+                if (tmp.Equals(oldRccDir, StringComparison.OrdinalIgnoreCase))
+                    return;
+
+                string badMacros = IncompatibleMacros(tmp);
+                if (!string.IsNullOrEmpty(badMacros))
+                    Messages.DisplayErrorMessage(SR.GetString("IncompatibleMacros", badMacros));
+                else
+                    newRccDir = tmp;
+            }
+        }
+
+        public bool lupdateOnBuild
+        {
+            get
+            {
+                return newLUpdateOnBuild;
+            }
+
+            set
+            {
+                newLUpdateOnBuild = value;
+            }
+        }
+
+        public string LUpdateOptions
+        {
+            get
+            {
+                return newLUpdateOptions;
+            }
+
+            set
+            {
+                newLUpdateOptions = value;
+            }
+        }
+
+        public string LReleaseOptions
+        {
+            get
+            {
+                return newLReleaseOptions;
+            }
+
+            set
+            {
+                newLReleaseOptions = value;
+            }
+        }
+
+        [DisplayName("QML Debug")]
+        [TypeConverter(typeof(QmlDebugConverter))]
+        private bool QmlDebug { get; }
+
+        private static string IncompatibleMacros(string stringToExpand)
+        {
+            string incompatibleMacros = "";
+            foreach (Match metaNameMatch in Regex.Matches(stringToExpand, @"\%\(([^\)]+)\)")) {
+                string metaName = metaNameMatch.Groups[1].Value;
+                if (!incompatibleMacros.Contains(string.Format("%({0})", metaName))) {
+                    switch (metaName) {
+                    case "RecursiveDir":
+                    case "ModifiedTime":
+                    case "CreatedTime":
+                    case "AccessedTime":
+                        if (!string.IsNullOrEmpty(incompatibleMacros))
+                            incompatibleMacros += ", ";
+                        incompatibleMacros += string.Format("%({0})", metaName);
+                        break;
+                    }
+                }
+            }
+            return incompatibleMacros;
+        }
+
+        internal class QmlDebugConverter : BooleanConverter
+        {
+            public override object ConvertTo(
+                ITypeDescriptorContext context,
+                CultureInfo culture,
+                object value,
+                Type destinationType)
+            {
+                return (bool)value ? "Enabled" : "Disabled";
+            }
+
+            public override object ConvertFrom(
+                ITypeDescriptorContext context,
+                CultureInfo culture,
+                object value)
+            {
+                return (string)value == "Enabled";
+            }
+        }
+
+        [TypeConverter(typeof(VersionConverter))]
+        public string Version
+        {
+            get
+            {
+                return newQtVersion;
+            }
+            set
+            {
+                if (newQtVersion != value) {
+                    newQtVersion = value;
+                    OnPropertyChanged("Version");
+                }
+            }
+        }
+
+        internal class VersionConverter : StringConverter
+        {
+            private readonly QtVersionManager versionManager;
+
+            public VersionConverter()
+            {
+                versionManager = QtVersionManager.The();
+            }
+
+            public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
+            {
+                return true;
+            }
+
+            public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
+            {
+                var versions = versionManager.GetVersions();
+                Array.Resize(ref versions, versions.Length + 1);
+                versions[versions.Length - 1] = "$(DefaultQtVersion)";
+                return new StandardValuesCollection(versions);
+            }
+
+            public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
+            {
+                return true;
+            }
+        }
+    }
+}
diff --git a/QtVsTools.Package/Legacy/QtMenu.cs b/QtVsTools.Package/Legacy/QtMenu.cs
new file mode 100644
index 0000000..bc38e6e
--- /dev/null
+++ b/QtVsTools.Package/Legacy/QtMenu.cs
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Windows.Forms;
+using EnvDTE;
+using EnvDTE80;
+using Microsoft.VisualStudio.Shell;
+
+namespace QtVsTools.Legacy
+{
+    using Core;
+    using Legacy = Core.Legacy;
+
+    internal static class QtMenu
+    {
+        internal static void ShowFormProjectQtSettings(Project project)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            using (var form = new FormProjectQtSettings(project)) {
+                form.StartPosition = FormStartPosition.CenterParent;
+                form.ShowDialog(new MainWinWrapper(QtVsToolsPackage.Instance.Dte));
+            }
+        }
+
+        internal static void ShowFormChangeProjectQtVersion()
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            var pro = HelperFunctions.GetSelectedQtProject(QtVsToolsPackage.Instance.Dte);
+            if (!HelperFunctions.IsQtProject(pro))
+                return;
+
+            using (var formChangeQtVersion = new FormChangeQtVersion()) {
+                formChangeQtVersion.UpdateContent(ChangeFor.Project);
+                var ww = new MainWinWrapper(QtVsToolsPackage.Instance.Dte);
+                if (formChangeQtVersion.ShowDialog(ww) == DialogResult.OK) {
+                    var qtVersion = formChangeQtVersion.GetSelectedQtVersion();
+                    HelperFunctions.SetDebuggingEnvironment(pro, "PATH=" + QtVersionManager
+                        .The().GetInstallPath(qtVersion) + @"\bin;$(PATH)", true);
+                }
+            }
+        }
+
+        internal static void ShowFormChangeSolutionQtVersion()
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            string newQtVersion = null;
+            using (var formChangeQtVersion = new FormChangeQtVersion()) {
+                formChangeQtVersion.UpdateContent(ChangeFor.Solution);
+                if (formChangeQtVersion.ShowDialog() != DialogResult.OK)
+                    return;
+                newQtVersion = formChangeQtVersion.GetSelectedQtVersion();
+            }
+            if (newQtVersion == null)
+                return;
+
+            string platform = null;
+            var dte = QtVsToolsPackage.Instance.Dte;
+            try {
+                platform = (dte.Solution.SolutionBuild.ActiveConfiguration as SolutionConfiguration2)
+                    .PlatformName;
+            } catch { }
+            if (string.IsNullOrEmpty(platform))
+                return;
+
+            var vm = QtVersionManager.The();
+            foreach (var project in HelperFunctions.ProjectsInSolution(dte)) {
+                if (HelperFunctions.IsVsToolsProject(project)) {
+                    var OldQtVersion = vm.GetProjectQtVersion(project, platform);
+                    if (OldQtVersion == null)
+                        OldQtVersion = vm.GetDefaultVersion();
+
+                    var created = false;
+                    var qtProject = QtProject.Create(project);
+                    if (Legacy.QtProject.PromptChangeQtVersion(project, OldQtVersion, newQtVersion))
+                        qtProject.ChangeQtVersion(OldQtVersion, newQtVersion, ref created);
+                }
+            }
+            Legacy.QtVersionManager.SaveSolutionQtVersion(dte.Solution, newQtVersion);
+        }
+    }
+}
diff --git a/QtVsTools.Package/Legacy/QtOptionsPage.cs b/QtVsTools.Package/Legacy/QtOptionsPage.cs
new file mode 100644
index 0000000..c0783c6
--- /dev/null
+++ b/QtVsTools.Package/Legacy/QtOptionsPage.cs
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.ComponentModel;
+using Microsoft.Win32;
+using Microsoft.VisualStudio.Shell;
+
+namespace QtVsTools.Legacy
+{
+    using Core;
+
+    public class QtOptionsPage : DialogPage
+    {
+        [Category(@"Qt VS Project Format v2 (Qt tools integrated via custom-build steps)")]
+        [DisplayName("Source control: Ask before checking out files")]
+        public bool CheckoutPrompt { get; set; }
+
+        [Category(@"Qt VS Project Format v2 (Qt tools integrated via custom-build steps)")]
+        [DisplayName("Source control: Enable file check-out")]
+        public bool Checkout { get; set; }
+
+        [Category(@"Qt VS Project Format v2 (Qt tools integrated via custom-build steps)")]
+        [DisplayName("Linguist: Default lrelease options")]
+        public string DefaultLReleaseOptions { get; set; }
+
+        [Category(@"Qt VS Project Format v2 (Qt tools integrated via custom-build steps)")]
+        [DisplayName("Linguist: Default lupdate options")]
+        public string DefaultLUpdateOptions { get; set; }
+
+        [Category(@"Qt VS Project Format v2 (Qt tools integrated via custom-build steps)")]
+        [DisplayName("Linguist: Run lupdate during build")]
+        public bool EnableLUpdateOnBuild { get; set; }
+
+        [Category(@"Qt VS Project Format v2 (Qt tools integrated via custom-build steps)")]
+        [DisplayName("Meta-Object Compiler: Default moc generated files directory")]
+        public string DefaultMocDir { get; set; }
+
+        [Category(@"Qt VS Project Format v2 (Qt tools integrated via custom-build steps)")]
+        [DisplayName("Meta-Object Compiler: Default additional moc options ")]
+        public string AdditionalMocOptions { get; set; }
+
+        [Category(@"Qt VS Project Format v2 (Qt tools integrated via custom-build steps)")]
+        [DisplayName("Meta-Object Compiler: Enable automatic moc")]
+        public bool AutoMoc { get; set; }
+
+        [Category(@"Qt VS Project Format v2 (Qt tools integrated via custom-build steps)")]
+        [DisplayName("Resource Compiler: Default rcc generated files directory")]
+        public string DefaultRccDir { get; set; }
+
+        [Category(@"Qt VS Project Format v2 (Qt tools integrated via custom-build steps)")]
+        [DisplayName("User Interface Compiler: Default uic generated files directory")]
+        public string DefaultUicDir { get; set; }
+
+        [Category(@"Qt VS Project Format v2 (Qt tools integrated via custom-build steps)")]
+        [DisplayName("Build: Run pre-build setup")]
+        public bool PreBuildSetup { get; set; }
+
+        const string VALUENAME_LegacyPreBuild = "LegacyPreBuild";
+
+        public override void ResetSettings()
+        {
+            CheckoutPrompt = true;
+            Checkout = true;
+            DefaultLReleaseOptions = "";
+            DefaultLUpdateOptions = "";
+            EnableLUpdateOnBuild = false;
+            DefaultMocDir = "";
+            AdditionalMocOptions = "";
+            AutoMoc = true;
+            DefaultRccDir = "";
+            DefaultUicDir = "";
+            PreBuildSetup = false;
+        }
+
+        public override void LoadSettingsFromStorage()
+        {
+            ResetSettings();
+            try {
+                using (var key = Registry.CurrentUser
+                    .OpenSubKey(@"SOFTWARE\" + Resources.registryPackagePath, writable: false)) {
+                    if (key == null)
+                        return;
+                    if (key.GetValue(Resources.askBeforeCheckoutFileKeyword) is int checkoutPrompt)
+                        CheckoutPrompt = (checkoutPrompt != 0);
+                    if (key.GetValue(Resources.disableCheckoutFilesKeyword) is int disableCheckout)
+                        Checkout = (disableCheckout == 0);
+                    if (key.GetValue(Resources.lreleaseOptionsKeyword) is string lreleaseOptions)
+                        DefaultLReleaseOptions = lreleaseOptions;
+                    if (key.GetValue(Resources.lupdateOptionsKeyword) is string lupdateOptions)
+                        DefaultLUpdateOptions = lupdateOptions;
+                    if (key.GetValue(Resources.lupdateKeyword) is int lupdateOnBuild)
+                        EnableLUpdateOnBuild = (lupdateOnBuild != 0);
+                    if (key.GetValue(Resources.mocDirKeyword) is string mocDir)
+                        DefaultMocDir = mocDir;
+                    if (key.GetValue(Resources.mocOptionsKeyword) is string mocOptions)
+                        AdditionalMocOptions = mocOptions;
+                    if (key.GetValue(Resources.disableAutoMocStepsUpdateKeyword) is int autoMocOff)
+                        AutoMoc = (autoMocOff == 0);
+                    if (key.GetValue(Resources.rccDirKeyword) is string rccDir)
+                        DefaultRccDir = rccDir;
+                    if (key.GetValue(Resources.uicDirKeyword) is string uicDir)
+                        DefaultUicDir = uicDir;
+                    if (key.GetValue(VALUENAME_LegacyPreBuild) is int preBuild)
+                        PreBuildSetup = (preBuild != 0);
+                }
+            } catch (Exception exception) {
+                exception.Log();
+            }
+        }
+
+        public override void SaveSettingsToStorage()
+        {
+            try {
+                using (var key = Registry.CurrentUser
+                    .CreateSubKey(@"SOFTWARE\" + Resources.registryPackagePath)) {
+                    if (key == null)
+                        return;
+                    key.SetValue(Resources.askBeforeCheckoutFileKeyword, CheckoutPrompt ? 1 : 0);
+                    key.SetValue(Resources.disableCheckoutFilesKeyword, Checkout ? 0 : 1);
+                    key.SetValue(Resources.lreleaseOptionsKeyword, DefaultLReleaseOptions);
+                    key.SetValue(Resources.lupdateOptionsKeyword, DefaultLUpdateOptions);
+                    key.SetValue(Resources.lupdateKeyword, EnableLUpdateOnBuild ? 1 : 0);
+                    key.SetValue(Resources.mocDirKeyword, DefaultMocDir);
+                    key.SetValue(Resources.mocOptionsKeyword, AdditionalMocOptions);
+                    key.SetValue(Resources.disableAutoMocStepsUpdateKeyword, AutoMoc ? 0 : 1);
+                    key.SetValue(Resources.rccDirKeyword, DefaultRccDir);
+                    key.SetValue(Resources.uicDirKeyword, DefaultUicDir);
+                    key.SetValue(VALUENAME_LegacyPreBuild, PreBuildSetup ? 1 : 0);
+                }
+            } catch (Exception exception) {
+                exception.Log();
+            }
+        }
+    }
+}
diff --git a/QtVsTools.Package/Legacy/Translation.cs b/QtVsTools.Package/Legacy/Translation.cs
new file mode 100644
index 0000000..645d0ee
--- /dev/null
+++ b/QtVsTools.Package/Legacy/Translation.cs
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using Microsoft.VisualStudio.VCProjectEngine;
+
+namespace QtVsTools.Legacy
+{
+    using Core;
+    using Legacy = Core.Legacy;
+
+    using static Core.HelperFunctions;
+    using BuildAction = QtVsTools.Translation.BuildAction;
+
+    internal static class Translation
+    {
+        internal static void Run(BuildAction buildAction, QtProject qtProject,
+            IEnumerable<string> tsFiles)
+        {
+            var qtInstallPath = QtVersionManager.The().GetInstallPath(qtProject.GetQtVersion());
+            if (string.IsNullOrEmpty(qtInstallPath)) {
+                Messages.Print("translation: Error accessing Qt installation");
+                return;
+            }
+
+            if (tsFiles == null) {
+                tsFiles = (qtProject.VCProject
+                    .GetFilesEndingWith(".ts") as IVCCollection)
+                    .Cast<VCFile>()
+                    .Select(vcFile => vcFile.RelativePath);
+            }
+
+            if (tsFiles != null) {
+                var project = qtProject.Project;
+                var tempFile = Path.GetTempFileName();
+
+                File.WriteAllLines(tempFile, GetProjectFiles(project, FilesToList.FL_HFiles)
+                    .Union(GetProjectFiles(project, FilesToList.FL_CppFiles))
+                    .Union(GetProjectFiles(project, FilesToList.FL_UiFiles))
+                    .Union(GetProjectFiles(project, FilesToList.FL_QmlFiles)));
+
+                var procInfo = new ProcessStartInfo
+                {
+                    WorkingDirectory = qtProject.ProjectDir,
+                    CreateNoWindow = true,
+                    UseShellExecute = false,
+                    RedirectStandardError = true,
+                    RedirectStandardOutput = true,
+                    Arguments = ""
+                };
+                procInfo.FileName = Path.Combine(qtInstallPath, "bin",
+                    buildAction == BuildAction.Update ? "lupdate.exe" : "lrelease.exe");
+
+                foreach (var file in tsFiles.Where(file => file != null))
+                    Run(buildAction, file, tempFile, procInfo);
+            } else {
+                Messages.Print("translation: No translation files found");
+            }
+        }
+
+        private static void Run(BuildAction buildAction, string tsFile, string tempFile,
+            ProcessStartInfo procInfo)
+        {
+            switch (buildAction) {
+            case BuildAction.Update:
+                Messages.Print("\r\n--- (lupdate) file: " + tsFile);
+                var options = Legacy.QtVSIPSettings.GetLUpdateOptions();
+                if (!string.IsNullOrEmpty(options))
+                    procInfo.Arguments += options + " ";
+                procInfo.Arguments += string.Format("\"@{0}\" -ts \"{1}\"", tempFile, tsFile);
+                break;
+            case BuildAction.Release:
+                Messages.Print("\r\n--- (lrelease) file: " + tsFile);
+                options = Legacy.QtVSIPSettings.GetLReleaseOptions();
+                if (!string.IsNullOrEmpty(options))
+                    procInfo.Arguments += options + " ";
+                procInfo.Arguments += string.Format("\"{0}\"", tsFile);
+                break;
+            }
+
+            using (var proc = Process.Start(procInfo)) {
+                proc.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
+                {
+                    if (!string.IsNullOrEmpty(e.Data))
+                        Messages.Print(e.Data);
+                };
+                proc.ErrorDataReceived += (object sender, DataReceivedEventArgs e) =>
+                {
+                    if (!string.IsNullOrEmpty(e.Data))
+                        Messages.Print(e.Data);
+                };
+                proc.BeginOutputReadLine();
+                proc.BeginErrorReadLine();
+                proc.WaitForExit();
+                switch (proc.ExitCode) {
+                case 0:
+                    Messages.Print("translation: ok");
+                    break;
+                default:
+                    Messages.Print(string.Format("translation: ERROR {0}", proc.ExitCode));
+                    break;
+                }
+            }
+        }
+    }
+}
diff --git a/QtVsTools.Package/Marketplace/Overview.html_TT b/QtVsTools.Package/Marketplace/Overview.html_TT
index 7f83418..875bea6 100644
--- a/QtVsTools.Package/Marketplace/Overview.html_TT
+++ b/QtVsTools.Package/Marketplace/Overview.html_TT
@@ -94,7 +94,7 @@
 <p><h3><span>The main features of Qt VS Tools are:</span></h3></p>
 <ul>
     <li>
-        Wizards for creating new Qt projects and classes.
+        Wizards for creating new Qt and Qt Quick projects and files.
     </li>
     <li>
         Automated build setup for the <a href="http://doc.qt.io/qt-5/moc.html">
@@ -122,6 +122,9 @@
     <li>
         Debugging extensions for Qt data types.
     </li>
+    <li>
+        QML debug engine for debugging Qt Quick applications.
+    </li>
 </ul>
 <p><h3>How to set up F1 help</h3></p>
 <ol class="1" type="1">
@@ -140,13 +143,41 @@
         Select <strong>Assign</strong>, and then select <strong>OK</strong>.
     </li>
 </ol>
-<p><h3>How to report bugs and contribute code?</h3></p>
+<p><h3>How to contribute via GitHub?</h3></p>
 <ul>
     <li>
-        <a title="Bug reports" href="https://bugreports.qt.io/browse/QTVSADDINBUG">Bug reports</a>
+        <a title="Source code on GitHub"
+           href="https://github.com/qt-labs/vstools">Source code on GitHub</a>
     </li>
     <li>
-        <a title="Source code" href="https://code.qt.io/cgit/qt-labs/vstools.git">Source code</a>
+        <a title="Pull requests on GitHub"
+           href="https://github.com/qt-labs/vstools/pulls">Pull requests on GitHub</a>
+    </li>
+</ul>
+<p><h3>How to contribute via Qt Labs?</h3></p>
+<ul>
+    <li>
+        <a title="Source code on Qt Labs"
+           href="https://code.qt.io/cgit/qt-labs/vstools.git">Source code on Qt Labs</a>
+    </li>
+    <li>
+        <a title="Qt VS Tools Code Review"
+           href="https://codereview.qt-project.org/q/project:qt-labs/vstools">Qt VS Tools Code Review</a>
+    </li>
+</ul>
+For more information on how to contribute to the Qt Visual Tools via Qt Labs, please look at the
+        <a title="Qt contribution Guidelines"
+           href="https://wiki.qt.io/Qt_Contribution_Guidelines">
+                Qt contribution Guidelines</a> first.
+<p><h3>How to report bugs?</h3></p>
+<ul>
+    <li>
+        <a title="Qt Bug Tracker"
+           href="https://bugreports.qt.io/browse/QTVSADDINBUG">Qt Bug Tracker</a>
+    </li>
+    <li>
+        <a title="GitHub Issue Tracker"
+           href="https://github.com/qt-labs/vstools/issues">GitHub Issue Tracker</a>
     </li>
 </ul>
 <p>
diff --git a/QtVsTools.Package/Options/QtOptionsPage.cs b/QtVsTools.Package/Options/QtOptionsPage.cs
index 5035285..7da27ae 100644
--- a/QtVsTools.Package/Options/QtOptionsPage.cs
+++ b/QtVsTools.Package/Options/QtOptionsPage.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -30,20 +30,20 @@
 using System.ComponentModel;
 using System.Globalization;
 using System.Linq;
-using Microsoft.Win32;
+using System.Linq.Expressions;
+using System.Reflection;
+using Microsoft.Build.Framework;
 using Microsoft.VisualStudio.Shell;
 using Microsoft.VisualStudio.Shell.Interop;
-using Microsoft.Build.Framework;
+using Microsoft.Win32;
 using EnvDTE;
-using QtVsTools.Core;
-using QtVsTools.Common;
-using QtVsTools.VisualStudio;
-using System.Reflection;
-using System.Linq.Expressions;
 
 namespace QtVsTools.Options
 {
-    using static EnumExt;
+    using Core;
+    using VisualStudio;
+
+    using static Common.EnumExt;
 
     public class QtOptionsPage : DialogPage, IQtVsToolsOptions
     {
@@ -85,6 +85,16 @@
             [String("BkgBuild_RunQtTools")] RunQtTools,
             [String("BkgBuild_DebugInfo")] DebugInfo,
             [String("BkgBuild_LoggerVerbosity")] LoggerVerbosity,
+        }
+
+        public enum Notifications
+        {
+            [String("Notifications_Installed")] Installed,
+        }
+
+        public enum Natvis
+        {
+            [String("LinkNatvis")] Link,
         }
 
         public enum Timeout : uint { Disabled = 0 }
@@ -144,8 +154,8 @@
                 object value,
                 Type destinationType)
             {
-                if (value.GetType() == typeof(bool) && destinationType == typeof(string))
-                    return ((bool)value) ? "Enable" : "Disable";
+                if (value is bool b && destinationType == typeof(string))
+                    return b ? "Enable" : "Disable";
                 return base.ConvertTo(context, culture, value, destinationType);
             }
         }
@@ -170,7 +180,7 @@
         [DisplayName("Keyboard shortcut")]
         [Description("To change keyboard mapping, go to: Tools > Options > Keyboard")]
         [ReadOnly(true)]
-        public string QtHelpKeyBinding { get; set; }
+        private string QtHelpKeyBinding { get; set; }
 
         [Category("Help")]
         [DisplayName("Preferred source")]
@@ -222,8 +232,25 @@
         [Description("Configure verbosity level of background build log.")]
         public LoggerVerbosity BuildLoggerVerbosity { get; set; }
 
+        [Category("Notifications")]
+        [DisplayName("New version installed")]
+        [Description("Show notification when a new version was recently installed.")]
+        [TypeConverter(typeof(EnableDisableConverter))]
+        public bool NotifyInstalled { get; set; }
+
+        [Category("Natvis")]
+        [DisplayName("Embed .natvis file into PDB")]
+        [Description("Embeds the debugger visualizations (.natvis file) into the PDB file"
+            + "generated by LINK. While setting this option, the embedded Natvis file will"
+            + "take precedence over user-specific Natvis files(for example the files"
+            + "located in %USERPROFILE%\\Documents\\Visual Studio 2022\\Visualizers).")]
+        [TypeConverter(typeof(EnableDisableConverter))]
+        public bool LinkNatvis { get; set; }
+
         public override void ResetSettings()
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             QtMsBuildPath = "";
             QmlDebuggerEnabled = true;
             QmlDebuggerTimeout = (Timeout)60000;
@@ -234,6 +261,8 @@
             BuildRunQtTools = ProjectTracking = true;
             BuildDebugInformation = false;
             BuildLoggerVerbosity = LoggerVerbosity.Quiet;
+            NotifyInstalled = true;
+            LinkNatvis = true;
 
             ////////
             // Get Qt Help keyboard shortcut
@@ -252,6 +281,8 @@
 
         public override void LoadSettingsFromStorage()
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             ResetSettings();
             try {
                 QtMsBuildPath = Environment.GetEnvironmentVariable("QTMSBUILD");
@@ -271,10 +302,11 @@
                     Load(() => BuildRunQtTools, key, BkgBuild.RunQtTools);
                     Load(() => BuildDebugInformation, key, BkgBuild.DebugInfo);
                     Load(() => BuildLoggerVerbosity, key, BkgBuild.LoggerVerbosity);
+                    Load(() => NotifyInstalled, key, Notifications.Installed);
+                    Load(() => LinkNatvis, key, Natvis.Link);
                 }
             } catch (Exception exception) {
-                Messages.Print(
-                    exception.Message + "\r\n\r\nStacktrace:\r\n" + exception.StackTrace);
+                exception.Log();
             }
         }
 
@@ -296,7 +328,7 @@
                     Save(QmlDebuggerEnabled, key, QmlDebug.Enable);
                     Save(QmlDebuggerTimeout, key, QmlDebug.Timeout);
                     Save(HelpPreference, key, Help.Preference);
-                    Save(TryQtHelpOnF1Pressed, key, Help.Preference);
+                    Save(TryQtHelpOnF1Pressed, key, Help.TryOnF1Pressed);
                     Save(DesignerDetached, key, Designer.Detached);
                     Save(LinguistDetached, key, Linguist.Detached);
                     Save(ResourceEditorDetached, key, ResEditor.Detached);
@@ -304,10 +336,11 @@
                     Save(BuildRunQtTools, key, BkgBuild.RunQtTools);
                     Save(BuildDebugInformation, key, BkgBuild.DebugInfo);
                     Save(BuildLoggerVerbosity, key, BkgBuild.LoggerVerbosity);
+                    Save(NotifyInstalled, key, Notifications.Installed);
+                    Save(LinkNatvis, key, Natvis.Link);
                 }
             } catch (Exception exception) {
-                Messages.Print(
-                    exception.Message + "\r\n\r\nStacktrace:\r\n" + exception.StackTrace);
+                exception.Log();
             }
         }
 
diff --git a/QtVsTools.Package/Options/QtVersionsPage.cs b/QtVsTools.Package/Options/QtVersionsPage.cs
index f28e8ee..cffc4b7 100644
--- a/QtVsTools.Package/Options/QtVersionsPage.cs
+++ b/QtVsTools.Package/Options/QtVersionsPage.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -28,29 +28,37 @@
 
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Windows;
 using Microsoft.VisualStudio.Shell;
 using Microsoft.VisualStudio.Shell.Interop;
-using QtVsTools.Core;
 
 namespace QtVsTools.Options
 {
+    using Common;
+    using Core;
+    using static QtVsTools.Options.QtVersionsTable;
+
     public class QtVersionsPage : UIElementDialogPage
     {
+        static LazyFactory Lazy { get; } = new LazyFactory();
+
         QtVersionManager VersionManager => QtVersionManager.The();
 
-        QtVersionsTable _VersionsTable;
-        QtVersionsTable VersionsTable => _VersionsTable
-            ?? (_VersionsTable = new QtVersionsTable());
+        QtVersionsTable VersionsTable => Lazy.Get(() =>
+            VersionsTable, () => new QtVersionsTable());
 
         protected override UIElement Child => VersionsTable;
 
         public override void LoadSettingsFromStorage()
         {
-            var versions = new List<QtVersionsTable.Row>();
+            var versions = new List<Row>();
             foreach (var versionName in VersionManager.GetVersions()) {
                 var versionPath = VersionManager.GetInstallPath(versionName);
+                if (string.IsNullOrEmpty(versionPath))
+                    continue;
+
                 BuildHost host = BuildHost.Windows;
                 string compiler = "msvc";
                 if (versionPath.StartsWith("SSH:") || versionPath.StartsWith("WSL:")) {
@@ -65,13 +73,15 @@
                         compiler = linuxPaths[2];
                 }
                 var defaultVersion = VersionManager.GetDefaultVersion();
-                versions.Add(new QtVersionsTable.Row()
+                versions.Add(new Row()
                 {
                     IsDefault = (versionName == defaultVersion),
                     VersionName = versionName,
+                    InitialVersionName = versionName,
                     Path = versionPath,
                     Host = host,
                     Compiler = compiler,
+                    State = State.Unknown
                 });
             }
             VersionsTable.UpdateVersions(versions);
@@ -79,23 +89,40 @@
 
         public override void SaveSettingsToStorage()
         {
-            foreach (var versionName in VersionManager.GetVersions()) {
+            void RemoveVersion(string versionName)
+            {
                 try {
                     VersionManager.RemoveVersion(versionName);
                 } catch (Exception exception) {
-                    Messages.Print(
-                        exception.Message + "\r\n\r\nStacktrace:\r\n" + exception.StackTrace);
+                    exception.Log();
                 }
             }
-            foreach (var version in VersionsTable.Versions) {
+
+            var versions = VersionsTable.Versions;
+            foreach (var version in versions) {
+                if (version.State.HasFlag(State.Removed))
+                    RemoveVersion(version.VersionName);
+
+                if (!version.State.HasFlag(State.Modified))
+                    continue;
+
                 try {
                     if (version.Host == BuildHost.Windows) {
-                        var versionInfo = VersionInformation.Get(version.Path);
-                        var generator = versionInfo.GetQMakeConfEntry("MAKEFILE_GENERATOR");
-                        if (generator != "MSVC.NET" && generator != "MSBUILD")
-                            throw new Exception(SR.GetString(
-                                "AddQtVersionDialog_IncorrectMakefileGenerator", generator));
-                        VersionManager.SaveVersion(version.VersionName, version.Path);
+                        if (version.State.HasFlag((State)Column.Path)) {
+                            var versionPath = version.Path;
+                            var ignoreCase = StringComparison.CurrentCultureIgnoreCase;
+                            if (Path.GetFileName(versionPath).Equals("qmake.exe", ignoreCase))
+                                versionPath = Path.GetDirectoryName(versionPath);
+                            if (Path.GetFileName(versionPath).Equals("bin", ignoreCase))
+                                versionPath = Path.GetDirectoryName(versionPath);
+                            var versionInfo = VersionInformation.Get(versionPath);
+                            var generator = versionInfo.GetQMakeConfEntry("MAKEFILE_GENERATOR");
+                            if (generator != "MSVC.NET" && generator != "MSBUILD")
+                                throw new Exception(string.Format(
+                                    "This Qt version uses an unsupported makefile generator (used: "
+                                    + "{0}, supported: MSVC.NET, MSBUILD)", generator));
+                            VersionManager.SaveVersion(version.VersionName, versionPath);
+                        }
                     } else {
                         string name = version.VersionName;
                         string access =
@@ -107,21 +134,34 @@
                         path = string.Format("{0}:{1}:{2}", access, path, compiler);
                         VersionManager.SaveVersion(name, path, checkPath: false);
                     }
+
+                    if (version.State.HasFlag((State)Column.VersionName)) {
+                        try {
+                            VersionManager.SaveVersion(version.VersionName, version.Path);
+                            if (!string.IsNullOrEmpty(version.InitialVersionName))
+                                VersionManager.RemoveVersion(version.InitialVersionName);
+                        } catch (Exception exception) {
+                            exception.Log();
+                        }
+                    }
                 } catch (Exception exception) {
-                    Messages.Print(
-                        exception.Message + "\r\n\r\nStacktrace:\r\n" + exception.StackTrace);
+                    exception.Log();
+                    version.State = State.Removed;
+                    RemoveVersion(version.VersionName);
                 }
             }
+
             try {
-                var defaultVersion = VersionsTable.Versions
-                    .Where(version => version.IsDefault)
-                    .FirstOrDefault();
-                if (defaultVersion != null)
-                    VersionManager.SaveDefaultVersion(defaultVersion.VersionName);
+                var defaultVersion =
+                    versions.FirstOrDefault(v => v.IsDefault && v.State != State.Removed)
+                        ?? versions.FirstOrDefault(v => v.State != State.Removed);
+                VersionManager.SaveDefaultVersion(defaultVersion?.VersionName ?? "");
             } catch (Exception exception) {
-                Messages.Print(
-                    exception.Message + "\r\n\r\nStacktrace:\r\n" + exception.StackTrace);
+                exception.Log();
             }
+
+            if (Notifications.NoQtVersion.IsOpen && VersionManager.GetVersions()?.Any() == true)
+                Notifications.NoQtVersion.Close();
         }
 
         protected override void OnApply(PageApplyEventArgs e)
diff --git a/QtVsTools.Package/Options/QtVersionsTable.cs b/QtVsTools.Package/Options/QtVersionsTable.cs
index dc6f9c5..cb09fff 100644
--- a/QtVsTools.Package/Options/QtVersionsTable.cs
+++ b/QtVsTools.Package/Options/QtVersionsTable.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -37,11 +37,12 @@
 using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using Microsoft.Win32;
-using QtVsTools.Common;
 
 namespace QtVsTools.Options
 {
-    using static EnumExt;
+    using Common;
+    using QtVsTools.Core;
+    using static Common.EnumExt;
 
     public enum BuildHost
     {
@@ -52,9 +53,28 @@
 
     public partial class QtVersionsTable : UserControl
     {
+        LazyFactory Lazy { get; } = new LazyFactory();
+
         public QtVersionsTable()
         {
             InitializeComponent();
+        }
+
+        [Flags] public enum Column
+        {
+            IsDefault = 0x10,
+            VersionName = 0x20,
+            Host = 0x40,
+            Path = 0x80,
+            Compiler = 0x100
+        }
+
+        [Flags] public enum State
+        {
+            Unknown = 0x00,
+            Existing = 0x01,
+            Removed = 0x02,
+            Modified = 0x04
         }
 
         public class Field
@@ -62,57 +82,66 @@
             public string Value { get; set; }
             public Control Control { get; set; }
             public DataGridCell Cell { get; set; }
-            public string ValidationError { get; set; }
+            private string error;
+            public string ValidationError {
+                set {
+                    UpdateUi = value != error;
+                    error = value;
+                }
+                get { return error; }
+            }
             public bool IsValid => string.IsNullOrEmpty(ValidationError);
             public ToolTip ToolTip
                 => IsValid ? null : new ToolTip() { Content = ValidationError };
             public int SelectionStart { get; set; }
+            public bool UpdateUi { get; private set; } = false;
         }
 
         public class Row
         {
-            public enum FieldNames { IsDefault, VersionName, Host, Path, Compiler }
+            static LazyFactory StaticLazy { get; } = new LazyFactory();
+            LazyFactory Lazy { get; } = new LazyFactory();
 
-            public Dictionary<FieldNames, Field> _Fields;
-            public Dictionary<FieldNames, Field> Fields => _Fields
-                ?? (_Fields = GetValues<FieldNames>()
-                    .Select(field => new KeyValuePair<FieldNames, Field>(field, null))
+            public Dictionary<Column, Field> Fields => Lazy.Get(() =>
+                Fields, () => GetValues<Column>()
+                    .Select(field => new KeyValuePair<Column, Field>(field, null))
                     .ToDictionary(keyValue => keyValue.Key, keyValue => keyValue.Value));
 
-            public Field FieldDefault => Fields[FieldNames.IsDefault]
-                ?? (Fields[FieldNames.IsDefault] = new Field());
+            public Field FieldDefault => Fields[Column.IsDefault]
+                ?? (Fields[Column.IsDefault] = new Field());
             public bool IsDefault
             {
                 get => (FieldDefault.Value == true.ToString());
                 set => FieldDefault.Value = value.ToString();
             }
 
-            public Field FieldVersionName => Fields[FieldNames.VersionName]
-                ?? (Fields[FieldNames.VersionName] = new Field());
+            public Field FieldVersionName => Fields[Column.VersionName]
+                ?? (Fields[Column.VersionName] = new Field());
             public string VersionName
             {
                 get => FieldVersionName.Value;
                 set => FieldVersionName.Value = value;
             }
+            public string InitialVersionName { get; set; }
 
-            public Field FieldHost => Fields[FieldNames.Host]
-                ?? (Fields[FieldNames.Host] = new Field());
+            public Field FieldHost => Fields[Column.Host]
+                ?? (Fields[Column.Host] = new Field());
             public BuildHost Host
             {
                 get => FieldHost.Value.Cast(defaultValue: BuildHost.Windows);
                 set => FieldHost.Value = value.Cast<string>();
             }
 
-            public Field FieldPath => Fields[FieldNames.Path]
-                ?? (Fields[FieldNames.Path] = new Field());
+            public Field FieldPath => Fields[Column.Path]
+                ?? (Fields[Column.Path] = new Field());
             public string Path
             {
                 get => FieldPath.Value;
                 set => FieldPath.Value = value;
             }
 
-            public Field FieldCompiler => Fields[FieldNames.Compiler]
-                ?? (Fields[FieldNames.Compiler] = new Field());
+            public Field FieldCompiler => Fields[Column.Compiler]
+                ?? (Fields[Column.Compiler] = new Field());
             public string Compiler
             {
                 get => FieldCompiler.Value;
@@ -124,7 +153,7 @@
             public bool DefaultEnabled => !IsDefault && !LastRow;
             public bool NameEnabled => !LastRow;
             public bool CompilerEnabled => (Host != BuildHost.Windows);
-            public Visibility RowVisibility
+            public Visibility RowContentVisibility
                 => LastRow ? Visibility.Hidden : Visibility.Visible;
             public Visibility ButtonAddVisibility
                 => LastRow ? Visibility.Visible : Visibility.Hidden;
@@ -135,17 +164,16 @@
             public FontWeight FontWeight
                 => IsDefault ? FontWeights.Bold : FontWeights.Normal;
 
-            public static ImageSource _ExplorerIcon;
-            public static ImageSource ExplorerIcon => _ExplorerIcon
-                ?? (_ExplorerIcon = GetExplorerIcon());
-        }
+            public static ImageSource ExplorerIcon => StaticLazy.Get(() =>
+                ExplorerIcon, () => GetExplorerIcon());
 
-        public bool IsValid { get; private set; }
+            public State State { get; set; } = State.Unknown;
+            public bool RowVisible => State != State.Removed;
+        }
 
         Field FocusedField { get; set; }
 
-        List<Row> _Rows;
-        List<Row> Rows => _Rows ?? (_Rows = new List<Row>());
+        List<Row> Rows => Lazy.Get(() => Rows, () => new List<Row>());
         public IEnumerable<Row> Versions => Rows.TakeWhile(item => !item.LastRow);
 
         public void UpdateVersions(IEnumerable<Row> versions)
@@ -154,15 +182,16 @@
             Rows.AddRange(versions);
             Rows.Add(new Row { LastRow = true });
             DataGrid.ItemsSource = Rows;
-            IsValid = true;
             FocusedField = null;
             Validate(true);
+            Rows.ForEach(item => item.State = State.Existing);
         }
 
         public IEnumerable<string> GetErrorMessages()
         {
             Validate(true);
             return Versions
+                .Where(v => v.State != State.Removed)
                 .SelectMany(v => v.Fields.Values.Select(f => f.ValidationError))
                 .Where(s => !string.IsNullOrEmpty(s))
                 .Distinct();
@@ -170,95 +199,73 @@
 
         void Validate(bool mustRefresh)
         {
-            /////////////////////////
-            // Automatic cell values
-            foreach (var version in Versions) {
-                if (version.Host != BuildHost.Windows && version.Compiler == "msvc") {
-                    version.Compiler = "g++";
-                    version.FieldCompiler.SelectionStart = version.Compiler.Length;
-                    mustRefresh = true;
-                } else if (version.Host == BuildHost.Windows && version.Compiler != "msvc") {
-                    version.Compiler = "msvc";
-                    version.FieldCompiler.SelectionStart = version.Compiler.Length;
-                    mustRefresh = true;
-                }
-            }
-
             ////////////////////////
             // Validate cell values
-            string previousValidation;
-            bool wasValid = IsValid;
-            IsValid = true;
             foreach (var version in Versions) {
+                if (!version.State.HasFlag(State.Modified))
+                    continue;
 
                 //////////////////////
                 // Default validation
-                previousValidation = version.FieldDefault.ValidationError;
-                version.FieldDefault.ValidationError = null;
-                if (version.IsDefault && version.Host != BuildHost.Windows) {
-                    version.FieldDefault.ValidationError = "Default version: host must be Windows";
-                    IsValid = false;
+                if (version.State.HasFlag((State)Column.IsDefault)) {
+                    version.FieldDefault.ValidationError = null;
+                    if (version.IsDefault && version.Host != BuildHost.Windows)
+                        version.FieldDefault.ValidationError = "Default version: Host must be Windows";
+                    mustRefresh |= version.FieldDefault.UpdateUi;
                 }
-                if (previousValidation != version.FieldDefault.ValidationError)
-                    mustRefresh = true;
 
                 ///////////////////
                 // Name validation
-                previousValidation = version.FieldVersionName.ValidationError;
-                version.FieldVersionName.ValidationError = null;
-                if (string.IsNullOrEmpty(version.VersionName)) {
-                    version.FieldVersionName.ValidationError = "Name cannot be empty";
-                    IsValid = false;
-                } else if (Versions
-                    .Where(otherVersion => otherVersion != version
-                        && otherVersion.VersionName == version.VersionName)
-                    .Any()) {
-                    version.FieldVersionName.ValidationError = "Duplicate version names";
-                    IsValid = false;
+                if (version.State.HasFlag((State)Column.VersionName)) {
+                    version.FieldVersionName.ValidationError = null;
+                    if (string.IsNullOrEmpty(version.VersionName)) {
+                        version.FieldVersionName.ValidationError = "Name cannot be empty";
+                    } else if (Versions.Where(otherVersion => otherVersion != version
+                        && otherVersion.VersionName == version.VersionName).Any()) {
+                        version.FieldVersionName.ValidationError = "Duplicate version names";
+                    }
+                    mustRefresh |= version.FieldVersionName.UpdateUi;
                 }
-                if (previousValidation != version.FieldVersionName.ValidationError)
-                    mustRefresh = true;
 
                 ///////////////////
                 // Host validation
-                previousValidation = version.FieldHost.ValidationError;
-                version.FieldHost.ValidationError = null;
-                if (version.IsDefault && version.Host != BuildHost.Windows) {
-                    version.FieldHost.ValidationError = "Default version: host must be Windows";
-                    IsValid = false;
+                if (version.State.HasFlag((State)Column.Host)) {
+                    version.FieldHost.ValidationError = null;
+                    if (version.IsDefault && version.Host != BuildHost.Windows)
+                        version.FieldHost.ValidationError = "Default version: Host must be Windows";
+                    mustRefresh |= version.FieldHost.UpdateUi;
                 }
-                if (previousValidation != version.FieldHost.ValidationError)
-                    mustRefresh = true;
 
                 ///////////////////
                 // Path validation
-                previousValidation = version.FieldPath.ValidationError;
-                version.FieldPath.ValidationError = null;
-                if (string.IsNullOrEmpty(version.Path)) {
-                    version.FieldPath.ValidationError = "Path cannot be empty";
-                    IsValid = false;
-                } else if (version.Host == BuildHost.Windows && !Directory.Exists(version.Path)) {
-                    version.FieldPath.ValidationError = "Path does not exist";
-                    IsValid = false;
+                if (version.State.HasFlag((State)Column.Path)) {
+                    version.FieldPath.ValidationError = null;
+                    if (string.IsNullOrEmpty(version.Path)) {
+                        version.FieldPath.ValidationError = "Path cannot be empty";
+                    } else if (version.Host == BuildHost.Windows) {
+                        string path = NormalizePath(version.Path);
+                        if (path == null) {
+                            version.FieldPath.ValidationError = "Invalid path format";
+                        } else {
+                            if (!QMake.Exists(path))
+                                version.FieldPath.ValidationError = "Cannot find qmake.exe";
+                        }
+                    }
+                    mustRefresh |= version.FieldPath.UpdateUi;
                 }
-                if (previousValidation != version.FieldPath.ValidationError)
-                    mustRefresh = true;
 
                 ///////////////////////
                 // Compiler validation
-                previousValidation = version.FieldCompiler.ValidationError;
-                version.FieldCompiler.ValidationError = null;
-                if (string.IsNullOrEmpty(version.Compiler)) {
-                    version.FieldCompiler.ValidationError = "Compiler cannot be empty";
-                    IsValid = false;
+                if (version.State.HasFlag((State)Column.Compiler)) {
+                    version.FieldCompiler.ValidationError = null;
+                    if (string.IsNullOrEmpty(version.Compiler))
+                        version.FieldCompiler.ValidationError = "Compiler cannot be empty";
+                    mustRefresh |= version.FieldCompiler.UpdateUi;
                 }
-                if (previousValidation != version.FieldCompiler.ValidationError)
-                    mustRefresh = true;
             }
 
             //////////////////////////////////////
             // Refresh versions table if required
-            mustRefresh |= (wasValid != IsValid);
             if (mustRefresh) {
                 // Reset bindings
                 foreach (var version in Versions) {
@@ -304,22 +311,20 @@
             if (sender is Control control && GetBinding(control) is Row version) {
                 if (version.LastRow)
                     return;
-
-                Row.FieldNames field;
-                if (string.IsNullOrEmpty(control.Name) || !control.Name.TryCast(out field))
+                if (string.IsNullOrEmpty(control.Name) || !control.Name.TryCast(out Column column))
                     return;
 
-                var fieldBinding = version.Fields[field];
-                fieldBinding.Control = control;
-                fieldBinding.Cell = FindContainingCell(control);
-                if (fieldBinding.Cell != null) {
-                    fieldBinding.Cell.Background =
-                        fieldBinding.IsValid ? Brushes.Transparent : InvalidCellBackground;
+                var field = version.Fields[column];
+                field.Control = control;
+                field.Cell = FindContainingCell(control);
+                if (field.Cell != null) {
+                    field.Cell.Background =
+                        field.IsValid ? Brushes.Transparent : InvalidCellBackground;
                 }
-                if (fieldBinding == FocusedField)
+                if (field == FocusedField)
                     control.Focus();
-                if (control is TextBox textBox && fieldBinding.SelectionStart >= 0)
-                    textBox.Select(fieldBinding.SelectionStart, 0);
+                if (control is TextBox textBox && field.SelectionStart >= 0)
+                    textBox.Select(field.SelectionStart, 0);
             }
         }
 
@@ -339,24 +344,24 @@
         void Control_GotFocus(object sender, RoutedEventArgs e)
         {
             if (sender is Control control && GetBinding(control) is Row version) {
-                Row.FieldNames field;
-                if (string.IsNullOrEmpty(control.Name) || !control.Name.TryCast(out field))
+                if (string.IsNullOrEmpty(control.Name) || !control.Name.TryCast(out Column column))
                     return;
-                var fieldBinding = version.Fields[field];
-                if (fieldBinding.Control != control)
+
+                var field = version.Fields[column];
+                if (field.Control != control)
                     return;
-                FocusedField = fieldBinding;
+                FocusedField = field;
             }
         }
 
         void Control_LostFocus(object sender, RoutedEventArgs e)
         {
             if (sender is Control control && GetBinding(control) is Row version) {
-                Row.FieldNames field;
-                if (string.IsNullOrEmpty(control.Name) || !control.Name.TryCast(out field))
+                if (string.IsNullOrEmpty(control.Name) || !control.Name.TryCast(out Column column))
                     return;
-                var fieldBinding = version.Fields[field];
-                if (fieldBinding != FocusedField || fieldBinding.Control != control)
+
+                var field = version.Fields[column];
+                if (field != FocusedField || field.Control != control)
                     return;
                 FocusedField = null;
             }
@@ -365,29 +370,32 @@
         void TextBox_SelectionChanged(object sender, RoutedEventArgs e)
         {
             if (sender is TextBox textBox && GetBinding(textBox) is Row version) {
-                Row.FieldNames field;
-                if (string.IsNullOrEmpty(textBox.Name) || !textBox.Name.TryCast(out field))
+                if (string.IsNullOrEmpty(textBox.Name) || !textBox.Name.TryCast(out Column column))
                     return;
-                var fieldBinding = version.Fields[field];
-                if (fieldBinding.Control != textBox)
+
+                var field = version.Fields[column];
+                if (field.Control != textBox)
                     return;
-                fieldBinding.SelectionStart = textBox.SelectionStart;
+                field.SelectionStart = textBox.SelectionStart;
             }
         }
 
         void TextBox_TextChanged(object sender, TextChangedEventArgs e)
         {
             if (sender is TextBox textBox && GetBinding(textBox) is Row version) {
-                Row.FieldNames field;
-                if (string.IsNullOrEmpty(textBox.Name) || !textBox.Name.TryCast(out field))
+                if (string.IsNullOrEmpty(textBox.Name) || !textBox.Name.TryCast(out Column column))
                     return;
-                var fieldBinding = version.Fields[field];
-                if (fieldBinding == null
-                    || fieldBinding.Control != textBox
-                    || fieldBinding.Value == textBox.Text)
+
+                var field = version.Fields[column];
+                if (field == null
+                    || field.Control != textBox
+                    || field.Value == textBox.Text)
                     return;
-                fieldBinding.SelectionStart = textBox.SelectionStart;
-                fieldBinding.Value = textBox.Text;
+
+                field.SelectionStart = textBox.SelectionStart;
+                field.Value = textBox.Text;
+                version.State |= State.Modified | (State)column;
+
                 Validate(false);
             }
         }
@@ -397,28 +405,49 @@
             if (sender is ComboBox comboBox && GetBinding(comboBox) is Row version) {
                 if (!comboBox.IsEnabled || comboBox.SelectedIndex < 0)
                     return;
+                if (string.IsNullOrEmpty(comboBox.Name) || !comboBox.Name.TryCast(out Column column))
+                    return;
+
                 string comboBoxValue = comboBox.Items[comboBox.SelectedIndex] as string;
-                string controlName = comboBox.Name;
-                Row.FieldNames field;
-                if (string.IsNullOrEmpty(controlName) || !controlName.TryCast(out field))
+                var field = version.Fields[column];
+                if (field == null
+                    || field.Control != comboBox
+                    || field.Value == comboBoxValue)
                     return;
-                var fieldBinding = version.Fields[field];
-                if (fieldBinding == null
-                    || fieldBinding.Control != comboBox
-                    || fieldBinding.Value == comboBoxValue)
-                    return;
-                fieldBinding.Value = comboBoxValue;
-                Validate(false);
+
+                field.Value = comboBoxValue;
+                version.State |= State.Modified | (State)Column.Host;
+
+                bool mustRefresh = false;
+                if (version.Host != BuildHost.Windows && version.Compiler == "msvc") {
+                    version.Compiler = "g++";
+                    version.FieldCompiler.SelectionStart = version.Compiler.Length;
+                    version.State |= (State)Column.Compiler;
+                    mustRefresh = true;
+                } else if (version.Host == BuildHost.Windows && version.Compiler != "msvc") {
+                    version.Compiler = "msvc";
+                    version.FieldCompiler.SelectionStart = version.Compiler.Length;
+                    version.State |= (State)Column.Compiler;
+                    mustRefresh = true;
+                }
+
+                Validate(mustRefresh);
             }
+        }
+
+        static void SetDefaultState(ref Row version, bool value)
+        {
+            version.IsDefault = value;
+            version.State |= State.Modified | (State)Column.IsDefault;
         }
 
         void Default_Click(object sender, RoutedEventArgs e)
         {
             if (sender is CheckBox checkBox && GetBinding(checkBox) is Row version) {
-                var defaultVersion = Rows.Where(row => row.IsDefault).FirstOrDefault();
+                var defaultVersion = Rows.FirstOrDefault(row => row.IsDefault);
                 if (defaultVersion != null)
-                    defaultVersion.IsDefault = false;
-                version.IsDefault = true;
+                    SetDefaultState(ref defaultVersion, false);
+                SetDefaultState(ref version, true);
                 Validate(true);
             }
         }
@@ -427,12 +456,16 @@
         {
             var version = new Row()
             {
-                IsDefault = !Versions.Any(),
+                IsDefault = !Versions.Any(x => x.State != State.Removed),
                 Host = BuildHost.Windows,
                 Path = "",
                 Compiler = "msvc",
-                LastRow = false
+                LastRow = false,
+                State = State.Modified | (State)Column.VersionName | (State)Column.Host
+                                       | (State)Column.Path | (State)Column.Compiler
             };
+            if (version.IsDefault)
+                version.State |= (State)Column.IsDefault;
             Rows.Insert(Rows.Count - 1, version);
             FocusedField = version.FieldVersionName;
             Validate(true);
@@ -441,10 +474,26 @@
         void Remove_Click(object sender, RoutedEventArgs e)
         {
             if (sender is Button button && GetBinding(button) is Row version) {
-                Rows.Remove(version);
-                if (version.IsDefault && Versions.Any())
-                    Versions.First().IsDefault = true;
+                version.State = State.Removed;
+                if (version.IsDefault) {
+                    var first = Versions.FirstOrDefault(x => x.State != State.Removed);
+                    if (first != null)
+                        SetDefaultState(ref first, true);
+                }
                 Validate(true);
+            }
+        }
+
+        static string NormalizePath(string path)
+        {
+            if (string.IsNullOrEmpty(path))
+                return path;
+            try {
+                return Path.GetFullPath(new Uri(path).LocalPath)
+                    .TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
+                    .ToUpperInvariant();
+            } catch (UriFormatException) {
+                return null;
             }
         }
 
@@ -462,6 +511,7 @@
                 if (openFileDialog.ShowDialog() == true) {
                     var qmakePath = openFileDialog.FileName;
                     var qmakeDir = Path.GetDirectoryName(qmakePath);
+                    var previousPath = NormalizePath(version.Path);
                     if (Path.GetFileName(qmakeDir)
                         .Equals("bin", StringComparison.InvariantCultureIgnoreCase)) {
                         qmakeDir = Path.GetDirectoryName(qmakeDir);
@@ -469,12 +519,18 @@
                     } else {
                         version.Path = qmakePath;
                     }
+
+                    if (previousPath != NormalizePath(version.Path))
+                        version.State |= State.Modified | (State)Column.Path;
+
                     if (string.IsNullOrEmpty(version.VersionName)) {
                         version.VersionName = string.Format("{0}_{1}",
                             Path.GetFileName(Path.GetDirectoryName(qmakeDir)),
                             Path.GetFileName(qmakeDir))
                             .Replace(" ", "_");
+                        version.State |= State.Modified | (State)Column.VersionName;
                     }
+
                     Validate(true);
                 }
             }
@@ -503,9 +559,9 @@
         static object GetBinding(FrameworkElement control)
         {
             if (control == null
-            || control.BindingGroup == null
-            || control.BindingGroup.Items == null
-            || control.BindingGroup.Items.Count == 0) {
+                || control.BindingGroup == null
+                || control.BindingGroup.Items == null
+                || control.BindingGroup.Items.Count == 0) {
                 return null;
             }
             return control.BindingGroup.Items[0];
@@ -515,7 +571,7 @@
         {
             while (control != null) {
                 if (control is ContentPresenter contentPresenter
-                && contentPresenter.Parent is DataGridCell cell) {
+                    && contentPresenter.Parent is DataGridCell cell) {
                     return cell;
                 }
                 control = VisualTreeHelper.GetParent(control);
diff --git a/QtVsTools.Package/Options/QtVersionsTable.xaml b/QtVsTools.Package/Options/QtVersionsTable.xaml
index 1b147ff..9f85dc3 100644
--- a/QtVsTools.Package/Options/QtVersionsTable.xaml
+++ b/QtVsTools.Package/Options/QtVersionsTable.xaml
@@ -1,7 +1,7 @@
 <!--
 /****************************************************************************
 **
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -32,7 +32,6 @@
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-             xmlns:local="clr-namespace:QtVsTools.Options"
              mc:Ignorable="d"
              d:DesignHeight="450"
              d:DesignWidth="800">
@@ -58,7 +57,13 @@
                        Color="Transparent" />
       <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}"
                        Color="Transparent" />
+      <BooleanToVisibilityConverter x:Key="b2v" />
     </DataGrid.Resources>
+    <DataGrid.RowStyle>
+      <Style TargetType="{x:Type DataGridRow}">
+        <Setter Property="Visibility" Value="{Binding RowVisible, Converter={StaticResource b2v}}"/>
+      </Style>
+    </DataGrid.RowStyle>
     <DataGrid.CellStyle>
       <Style TargetType="DataGridCell">
         <Setter Property="BorderThickness"
@@ -76,8 +81,7 @@
             <CheckBox x:Name="IsDefault"
                       IsChecked="{Binding IsDefault}"
                       Focusable="{Binding DefaultEnabled}"
-                      IsHitTestVisible="{Binding DefaultEnabled}"
-                      Visibility="{Binding RowVisibility}"
+                      Visibility="{Binding RowContentVisibility}"
                       BorderThickness="1"
                       Background="Transparent"
                       VerticalAlignment="Center"
@@ -94,7 +98,7 @@
             <!--//// Name ////-->
             <Grid>
               <Button Cursor="Hand"
-                      Visibility="{Binding RowVisibility}"
+                      Visibility="{Binding RowContentVisibility}"
                       HorizontalAlignment="Left"
                       VerticalAlignment="Center"
                       Click="Remove_Click">
@@ -153,7 +157,7 @@
               </Button>
               <TextBox x:Name="VersionName"
                        Text="{Binding VersionName}"
-                       Visibility="{Binding RowVisibility}"
+                       Visibility="{Binding RowContentVisibility}"
                        IsEnabled="{Binding NameEnabled}"
                        FontWeight="{Binding FontWeight}"
                        Margin="20,4,2,4"
@@ -166,7 +170,7 @@
                        LostFocus="Control_LostFocus"
                        TextChanged="TextBox_TextChanged"
                        SelectionChanged="TextBox_SelectionChanged"
-                       ToolTip="{Binding FieldName.ToolTip}">
+                       ToolTip="{Binding FieldVersionName.ToolTip}">
                 <TextBox.Resources>
                   <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
                                    Color="LimeGreen" />
@@ -181,7 +185,7 @@
           <DataTemplate>
             <!--//// Host ////-->
             <ComboBox x:Name="Host"
-                      Visibility="{Binding RowVisibility}"
+                      Visibility="{Binding RowContentVisibility}"
                       IsEditable="True"
                       IsReadOnly="True"
                       BorderThickness="0"
@@ -233,7 +237,7 @@
               </Button>
               <TextBox x:Name="Path"
                        Text="{Binding Path}"
-                       Visibility="{Binding RowVisibility}"
+                       Visibility="{Binding RowContentVisibility}"
                        BorderThickness="0"
                        Background="Transparent"
                        Margin="{Binding PathMargin}"
@@ -260,7 +264,7 @@
             <!--//// Compiler ////-->
             <TextBox x:Name="Compiler"
                      Text="{Binding Compiler}"
-                     Visibility="{Binding RowVisibility}"
+                     Visibility="{Binding RowContentVisibility}"
                      IsEnabled="{Binding CompilerEnabled}"
                      BorderThickness="0"
                      Background="Transparent"
diff --git a/QtVsTools.Package/Package/DteEventsHandler.cs b/QtVsTools.Package/Package/DteEventsHandler.cs
index c7304c0..df8bfc4 100644
--- a/QtVsTools.Package/Package/DteEventsHandler.cs
+++ b/QtVsTools.Package/Package/DteEventsHandler.cs
@@ -26,44 +26,45 @@
 **
 ****************************************************************************/
 
-using EnvDTE;
-using EnvDTE80;
-using Microsoft.VisualStudio;
-using Microsoft.VisualStudio.Shell;
-using Microsoft.VisualStudio.Shell.Interop;
-using Microsoft.VisualStudio.VCProjectEngine;
-using QtVsTools.Core;
-using QtVsTools.Core.QtMsBuild;
-using QtVsTools.QtMsBuild;
 using System;
-using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Runtime.InteropServices;
 using System.Text.RegularExpressions;
+using Microsoft.VisualStudio;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.VCProjectEngine;
+using EnvDTE;
+using EnvDTE80;
 
 namespace QtVsTools
 {
+    using Core;
+    using QtMsBuild;
+
     class DteEventsHandler
     {
-        private DTE dte;
-        private SolutionEvents solutionEvents;
-        private BuildEvents buildEvents;
-        private DocumentEvents documentEvents;
-        private ProjectItemsEvents projectItemsEvents;
+        private readonly DTE dte;
+        private readonly SolutionEvents solutionEvents;
+        private readonly BuildEvents buildEvents;
+        private readonly DocumentEvents documentEvents;
+        private readonly ProjectItemsEvents projectItemsEvents;
         private vsBuildAction currentBuildAction = vsBuildAction.vsBuildActionBuild;
         private VCProjectEngineEvents vcProjectEngineEvents;
-        private CommandEvents debugStartEvents;
-        private CommandEvents debugStartWithoutDebuggingEvents;
-        private CommandEvents f1HelpEvents;
-        private int dispId_VCFileConfiguration_ExcludedFromBuild;
-        private int dispId_VCCLCompilerTool_UsePrecompiledHeader;
-        private int dispId_VCCLCompilerTool_PrecompiledHeaderThrough;
-        private int dispId_VCCLCompilerTool_PreprocessorDefinitions;
-        private int dispId_VCCLCompilerTool_AdditionalIncludeDirectories;
+        private readonly CommandEvents debugStartEvents;
+        private readonly CommandEvents debugStartWithoutDebuggingEvents;
+        private readonly CommandEvents f1HelpEvents;
+        private WindowEvents windowEvents;
+        private readonly int dispId_VCFileConfiguration_ExcludedFromBuild;
+        private readonly int dispId_VCCLCompilerTool_UsePrecompiledHeader;
+        private readonly int dispId_VCCLCompilerTool_PrecompiledHeaderThrough;
+        private readonly int dispId_VCCLCompilerTool_PreprocessorDefinitions;
+        private readonly int dispId_VCCLCompilerTool_AdditionalIncludeDirectories;
 
         public DteEventsHandler(DTE _dte)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             dte = _dte;
             var events = dte.Events as Events2;
 
@@ -85,6 +86,9 @@
             solutionEvents.Opened += SolutionEvents_Opened;
             solutionEvents.AfterClosing += SolutionEvents_AfterClosing;
 
+            windowEvents = events.WindowEvents;
+            windowEvents.WindowActivated += WindowEvents_WindowActivated;
+
             var debugCommandsGUID = "{5EFC7975-14BC-11CF-9B2B-00AA00573819}";
             debugStartEvents = events.get_CommandEvents(debugCommandsGUID, 295);
             debugStartEvents.BeforeExecute += debugStartEvents_BeforeExecute;
@@ -105,15 +109,33 @@
             InitializeVCProjects();
         }
 
+        private void WindowEvents_WindowActivated(Window gotFocus, Window lostFocus)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+            if (dte.MainWindow?.Visible == true) {
+                windowEvents.WindowActivated -= WindowEvents_WindowActivated;
+                windowEvents = null;
+                QtVsToolsPackage.Instance.VsMainWindowActivated();
+            }
+        }
+
         private void F1HelpEvents_BeforeExecute(
             string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault)
         {
-            if (QtVsToolsPackage.Instance.Options.TryQtHelpOnF1Pressed && QtHelp.QueryEditorContextHelp())
+            ThreadHelper.ThrowIfNotOnUIThread();
+            if (QtVsToolsPackage.Instance.Options.TryQtHelpOnF1Pressed) {
+                if (!QtHelp.ShowEditorContextHelp()) {
+                    Messages.Print("No help match was found. You can still try to search online at "
+                        + "https://doc.qt.io" + ".", false, true);
+                }
                 CancelDefault = true;
+            }
         }
 
         void debugStartEvents_BeforeExecute(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var debugger = dte.Debugger;
             if (debugger != null && debugger.CurrentMode != dbgDebugMode.dbgDesignMode)
                 return;
@@ -147,6 +169,8 @@
 
         public void Disconnect()
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (buildEvents != null) {
                 buildEvents.OnBuildBegin -= buildEvents_OnBuildBegin;
                 buildEvents.OnBuildProjConfigBegin -= OnBuildProjConfigBegin;
@@ -174,12 +198,19 @@
             if (debugStartWithoutDebuggingEvents != null)
                 debugStartWithoutDebuggingEvents.BeforeExecute -= debugStartWithoutDebuggingEvents_BeforeExecute;
 
-            if (vcProjectEngineEvents != null)
+            if (vcProjectEngineEvents != null) {
                 vcProjectEngineEvents.ItemPropertyChange -= OnVCProjectEngineItemPropertyChange;
+                vcProjectEngineEvents.ItemPropertyChange2 -= OnVCProjectEngineItemPropertyChange2;
+            }
+
+            if (windowEvents != null)
+                windowEvents.WindowActivated -= WindowEvents_WindowActivated;
         }
 
         public void OnBuildProjConfigBegin(string projectName, string projectConfig, string platform, string solutionConfig)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (!QtVsToolsPackage.Instance.LegacyOptions.PreBuildSetup)
                 return;
 
@@ -195,7 +226,7 @@
                     break;
                 }
             }
-            if (project == null || !HelperFunctions.IsQtProject(project))
+            if (project == null || !HelperFunctions.IsVsToolsProject(project))
                 return;
 
             if (QtProject.GetFormatVersion(project) >= Resources.qtMinFormatVersion_Settings)
@@ -229,9 +260,11 @@
 
         public void DocumentSaved(Document document)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var qtPro = QtProject.Create(document.ProjectItem.ContainingProject);
 
-            if (!HelperFunctions.IsQtProject(qtPro.VCProject))
+            if (!HelperFunctions.IsVsToolsProject(qtPro.VCProject))
                 return;
 
             var file = (VCFile)((IVCCollection)qtPro.VCProject.Files).Item(document.FullName);
@@ -323,10 +356,13 @@
 
         public void ProjectItemsEvents_ItemAdded(ProjectItem projectItem)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var project = HelperFunctions.GetSelectedQtProject(QtVsToolsPackage.Instance.Dte);
             var qtPro = QtProject.Create(project);
-            if (!HelperFunctions.IsQtProject(project))
+            if (!HelperFunctions.IsVsToolsProject(project))
                 return;
+
             var vcFile = GetVCFileFromProject(projectItem.Name, qtPro.VCProject);
             if (vcFile == null)
                 return;
@@ -373,12 +409,15 @@
                         HelperFunctions.EnsureCustomBuildToolAvailable(projectItem);
                     qtPro.UpdateRccStep(vcFile, null);
                 } else if (HelperFunctions.IsTranslationFile(vcFile.Name)) {
+                    Translation.RunlUpdate(vcFile);
                 }
             } catch { }
         }
 
         void ProjectItemsEvents_ItemRemoved(ProjectItem ProjectItem)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var pro = HelperFunctions.GetSelectedQtProject(QtVsToolsPackage.Instance.Dte);
             if (pro == null)
                 return;
@@ -389,6 +428,8 @@
 
         void ProjectItemsEvents_ItemRenamed(ProjectItem ProjectItem, string OldName)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (OldName == null)
                 return;
             var pro = HelperFunctions.GetSelectedQtProject(QtVsToolsPackage.Instance.Dte);
@@ -397,12 +438,15 @@
 
             var qtPro = QtProject.Create(pro);
             qtPro.RemoveGeneratedFiles(OldName);
+
             ProjectItemsEvents_ItemAdded(ProjectItem);
         }
 
         void SolutionEvents_ProjectAdded(Project project)
         {
-            if (HelperFunctions.IsQMakeProject(project)) {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            if (HelperFunctions.IsQtProject(project)) {
                 InitializeVCProject(project);
                 QtProjectTracker.Add(project);
                 var vcpro = project.Object as VCProject;
@@ -446,9 +490,11 @@
 
         public void SolutionEvents_Opened()
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             QtProjectTracker.SolutionPath = QtVsToolsPackage.Instance.Dte.Solution.FullName;
             foreach (var p in HelperFunctions.ProjectsInSolution(QtVsToolsPackage.Instance.Dte)) {
-                if (HelperFunctions.IsQtProject(p)) {
+                if (HelperFunctions.IsVsToolsProject(p)) {
                     InitializeVCProject(p);
                     QtProjectTracker.Add(p);
                 }
@@ -464,14 +510,18 @@
 
         void InitializeVCProjects()
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             foreach (var project in HelperFunctions.ProjectsInSolution(dte)) {
-                if (project != null && HelperFunctions.IsQtProject(project))
+                if (project != null && HelperFunctions.IsVsToolsProject(project))
                     InitializeVCProject(project);
             }
         }
 
         void InitializeVCProject(Project p)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (vcProjectEngineEvents != null)
                 return;
 
@@ -480,12 +530,12 @@
                 return;
 
             // Retrieves the VCProjectEngine from the given project and registers the handlers for VCProjectEngineEvents.
-            var prjEngine = vcPrj.VCProjectEngine as VCProjectEngine;
-            if (prjEngine != null) {
+            if (vcPrj.VCProjectEngine is VCProjectEngine prjEngine) {
                 vcProjectEngineEvents = prjEngine.Events as VCProjectEngineEvents;
                 if (vcProjectEngineEvents != null) {
                     try {
                         vcProjectEngineEvents.ItemPropertyChange += OnVCProjectEngineItemPropertyChange;
+                        vcProjectEngineEvents.ItemPropertyChange2 += OnVCProjectEngineItemPropertyChange2;
                     } catch {
                         Messages.DisplayErrorMessage("VCProjectEngine events could not be registered.");
                     }
@@ -495,7 +545,6 @@
 
         private void OnVCProjectEngineItemPropertyChange(object item, object tool, int dispid)
         {
-            //System.Diagnostics.Debug.WriteLine("OnVCProjectEngineItemPropertyChange " + dispid.ToString());
             var vcFileCfg = item as VCFileConfiguration;
             if (vcFileCfg == null) {
                 // A global or project specific property has changed.
@@ -506,7 +555,7 @@
                 var vcPrj = vcCfg.project as VCProject;
                 if (vcPrj == null)
                     return;
-                if (!HelperFunctions.IsQtProject(vcPrj))
+                if (!HelperFunctions.IsVsToolsProject(vcPrj))
                     return;
                 // Ignore property events when using shared compiler properties
                 if (QtProject.GetFormatVersion(vcPrj) >= Resources.qtMinFormatVersion_ClProperties)
@@ -538,7 +587,7 @@
                 var vcPrj = vcFile.project as VCProject;
                 if (vcPrj == null)
                     return;
-                if (!HelperFunctions.IsQtProject(vcPrj))
+                if (!HelperFunctions.IsVsToolsProject(vcPrj))
                     return;
                 // Ignore property events when using shared compiler properties
                 if (QtProject.GetFormatVersion(vcPrj) >= Resources.qtMinFormatVersion_ClProperties)
@@ -557,10 +606,27 @@
             }
         }
 
+        private void OnVCProjectEngineItemPropertyChange2(
+            object item,
+            string propertySheet,
+            string itemType,
+            string propertyName)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+            if (!propertyName.StartsWith("Qt") || propertyName == "QtLastBackgroundBuild")
+                return;
+            if (item is VCConfiguration vcConfig
+                && vcConfig.project is VCProject vcProject
+                && vcProject.Object is Project project) {
+                QtProjectIntellisense.Refresh(
+                    QtProjectTracker.Get(project, project.FullName).Project, vcConfig.Name);
+            }
+        }
+
         private static VCFile GetVCFileFromProject(string absFileName, VCProject project)
         {
             foreach (VCFile f in (IVCCollection)project.Files) {
-                if (f.Name.ToLower() == absFileName.ToLower())
+                if (f.Name.Equals(absFileName, StringComparison.OrdinalIgnoreCase))
                     return f;
             }
             return null;
@@ -574,8 +640,7 @@
             var pi = type.GetProperty(propertyName);
             if (pi != null) {
                 foreach (Attribute attribute in pi.GetCustomAttributes(true)) {
-                    var dispIdAttribute = attribute as DispIdAttribute;
-                    if (dispIdAttribute != null)
+                    if (attribute is DispIdAttribute dispIdAttribute)
                         return dispIdAttribute.Value;
                 }
             }
diff --git a/QtVsTools.Package/Package/ExtLoader.cs b/QtVsTools.Package/Package/ExtLoader.cs
index 83885ac..76fc8bf 100644
--- a/QtVsTools.Package/Package/ExtLoader.cs
+++ b/QtVsTools.Package/Package/ExtLoader.cs
@@ -26,22 +26,27 @@
 **
 ****************************************************************************/
 
-using Microsoft.VisualStudio.VCProjectEngine;
-using QtVsTools.Core;
 using System.Collections.Generic;
 using System.IO;
 using System.Text.RegularExpressions;
 using System.Windows.Forms;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.VCProjectEngine;
 
 namespace QtVsTools
 {
+    using Core;
+
     public static class ExtLoader
     {
         public static void ImportProFile()
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var vm = QtVersionManager.The();
             var qtVersion = vm.GetDefaultVersion();
             var qtDir = vm.GetInstallPath(qtVersion);
+
             if (qtDir == null) {
                 Messages.DisplayErrorMessage(SR.GetString("CannotFindQMake"));
                 return;
@@ -59,11 +64,13 @@
 
         public static void ImportPriFile(EnvDTE.Project project)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (project == null)
                 return;
 
             VCProject vcproj;
-            if (!HelperFunctions.IsQtProject(project))
+            if (!HelperFunctions.IsVsToolsProject(project))
                 return;
 
             vcproj = project.Object as VCProject;
@@ -87,10 +94,12 @@
 
         public static void ImportPriFile(EnvDTE.Project project, string fileName)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (project == null)
                 return;
 
-            if (!HelperFunctions.IsQtProject(project))
+            if (!HelperFunctions.IsVsToolsProject(project))
                 return;
 
             var vcproj = project.Object as VCProject;
@@ -134,6 +143,8 @@
 
         private static List<string> ResolveFilesFromQMake(string[] files, EnvDTE.Project project, string path)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var lst = new List<string>();
             foreach (var file in files) {
                 var s = ResolveEnvironmentVariables(file, project);
diff --git a/QtVsTools.Package/Package/Notifications.cs b/QtVsTools.Package/Package/Notifications.cs
new file mode 100644
index 0000000..de0a639
--- /dev/null
+++ b/QtVsTools.Package/Package/Notifications.cs
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using Microsoft.VisualStudio.Imaging;
+using Microsoft.VisualStudio.Shell;
+
+namespace QtVsTools
+{
+    using Common;
+    using Microsoft.VisualStudio.Imaging.Interop;
+    using VisualStudio;
+
+    public static class Notifications
+    {
+        static LazyFactory StaticLazy { get; } = new LazyFactory();
+
+        public static NoQtVersion NoQtVersion
+            => StaticLazy.Get(() => NoQtVersion, () => new NoQtVersion());
+
+        public static NotifyInstall NotifyInstall
+            => StaticLazy.Get(() => NotifyInstall, () => new NotifyInstall());
+    }
+
+    public class NoQtVersion : InfoBarMessage
+    {
+        protected override ImageMoniker Icon => KnownMonikers.StatusWarning;
+
+        protected override TextSpan[] Text => new TextSpan[]
+        {
+            new TextSpan { Bold = true, Text = "Qt Visual Studio Tools" },
+            new TextSpacer(2),
+            "\u2014", // Em dash
+            new TextSpacer(2),
+            "You must select a Qt version to use for development."
+        };
+
+        protected override Hyperlink[] Hyperlinks => new Hyperlink[]
+        {
+            new Hyperlink
+            {
+                Text = "Select Qt version...",
+                CloseInfoBar = false,
+                OnClicked = () =>
+                    QtVsToolsPackage.Instance.ShowOptionPage(typeof(Options.QtVersionsPage))
+            }
+        };
+    }
+
+    public class NotifyInstall : InfoBarMessage
+    {
+        protected override ImageMoniker Icon => KnownMonikers.StatusInformation;
+
+        protected override TextSpan[] Text => new TextSpan[]
+        {
+            new TextSpan { Bold = true, Text = "Qt Visual Studio Tools" },
+            new TextSpacer(2),
+            "\u2014", // Em dash
+            new TextSpacer(2),
+            $"Version {Version.USER_VERSION} was recently installed."
+        };
+
+        protected override Hyperlink[] Hyperlinks => new Hyperlink[]
+        {
+            new Hyperlink
+            {
+                Text = "Release Notes",
+                CloseInfoBar = false,
+                OnClicked= () =>
+                {
+                    VsShellUtilities.OpenSystemBrowser(
+                        "https://code.qt.io/cgit/qt-labs/vstools.git/tree/Changelog");
+                }
+            },
+            new Hyperlink
+            {
+                Text = "Don't show again",
+                CloseInfoBar = true,
+                OnClicked = () =>
+                {
+                    QtVsToolsPackage.Instance.Options.NotifyInstalled = false;
+                    QtVsToolsPackage.Instance.Options.SaveSettingsToStorage();
+                }
+            }
+        };
+    }
+}
diff --git a/QtVsTools.Package/Package/QMakeWrapper.cs b/QtVsTools.Package/Package/QMakeWrapper.cs
index 11b0614..61f7bcb 100644
--- a/QtVsTools.Package/Package/QMakeWrapper.cs
+++ b/QtVsTools.Package/Package/QMakeWrapper.cs
@@ -37,7 +37,7 @@
         public string QtDir { get; set; }
 
         public bool IsFlat { get; private set; }
-        public bool IsValid { get; private set; }
+        private bool IsValid { get; set; }
 
         public string[] SourceFiles { get; private set; }
         public string[] HeaderFiles { get; private set; }
diff --git a/QtVsTools.Package/Package/QtHelp.cs b/QtVsTools.Package/Package/QtHelp.cs
index e36cb83..12e7b19 100644
--- a/QtVsTools.Package/Package/QtHelp.cs
+++ b/QtVsTools.Package/Package/QtHelp.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -26,13 +26,6 @@
 **
 ****************************************************************************/
 
-using EnvDTE;
-using Microsoft.VisualStudio.Settings;
-using Microsoft.VisualStudio.Shell;
-using Microsoft.VisualStudio.Shell.Interop;
-using Microsoft.VisualStudio.Shell.Settings;
-using QtVsTools.Core;
-using QtVsTools.VisualStudio;
 using System;
 using System.Collections.Generic;
 using System.ComponentModel.Design;
@@ -40,37 +33,36 @@
 using System.Data.SQLite;
 using System.IO;
 using System.Linq;
-using System.Threading.Tasks;
-using Task = System.Threading.Tasks.Task;
+using EnvDTE;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
 
 namespace QtVsTools
 {
+    using Core;
+    using VisualStudio;
+
     public class QtHelp
     {
         public enum SourcePreference { Online, Offline }
 
-        public static QtHelp Instance
+        private static QtHelp Instance
         {
             get;
-            private set;
+            set;
         }
 
-        public static void Initialize(Package package)
+        public static void Initialize()
         {
-            Instance = new QtHelp(package);
+            Instance = new QtHelp();
         }
 
         const int F1QtHelpId = 0x0502;
 
-        readonly Package package;
-        public static readonly Guid MainMenuGuid = new Guid("58f83fff-d39d-4c66-810b-2702e1f04e73");
+        private static readonly Guid MainMenuGuid = new Guid("58f83fff-d39d-4c66-810b-2702e1f04e73");
 
-        QtHelp(Package pkg)
+        private QtHelp()
         {
-            if (pkg == null)
-                throw new ArgumentNullException("package");
-            package = pkg;
-
             var commandService = VsServiceProvider
                 .GetService<IMenuCommandService, OleMenuCommandService>();
             if (commandService == null)
@@ -79,12 +71,6 @@
             var menuCommandID = new CommandID(MainMenuGuid, F1QtHelpId);
             commandService.AddCommand(new MenuCommand(F1QtHelpEventHandler, menuCommandID));
         }
-
-        IServiceProvider ServiceProvider
-        {
-            get { return package; }
-        }
-
         static bool IsSuperfluousCharacter(string text)
         {
             switch (text) {
@@ -131,11 +117,17 @@
 
         void F1QtHelpEventHandler(object sender, EventArgs args)
         {
-            QueryEditorContextHelp(true);
+            ThreadHelper.ThrowIfNotOnUIThread();
+            if (!ShowEditorContextHelp()) {
+                Messages.Print("No help match was found. You can still try to search online at "
+                    + "https://doc.qt.io" + ".", false, true);
+            }
         }
 
-        public static bool QueryEditorContextHelp(bool defaultTryOnline = false)
+        public static bool ShowEditorContextHelp()
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             try {
                 var dte = VsServiceProvider.GetService<SDTE, DTE>();
                 var objTextDocument = dte?.ActiveDocument?.Object() as TextDocument;
@@ -173,7 +165,7 @@
                 var project = HelperFunctions.GetSelectedQtProject(dte);
                 if (project == null) {
                     project = HelperFunctions.GetSelectedProject(dte);
-                    if (project != null && HelperFunctions.IsQMakeProject(project)) {
+                    if (project != null && HelperFunctions.IsQtProject(project)) {
                         var qmakeQtDir = HelperFunctions.GetQtDirFromQMakeProject(project);
                         qtVersion = QtVersionManager.The().GetQtVersionFromInstallDir(qmakeQtDir);
                     }
@@ -188,7 +180,7 @@
 
                 var qchFiles = Directory.GetFiles(docPath, "*?.qch");
                 if (qchFiles.Length == 0)
-                    return false;
+                    return TryShowGenericSearchResultsOnline(keyword, info.qtMajor);
 
                 var offline = QtVsToolsPackage.Instance.Options.HelpPreference == SourcePreference.Offline;
 
@@ -207,8 +199,9 @@
                     using (var connection = new SQLiteConnection(builder.ToString())) {
                         connection.Open();
                         using (var command = new SQLiteCommand(linksForKeyword, connection)) {
-                            using (var reader =
-                                Task.Run(async () => await command.ExecuteReaderAsync()).Result) {
+                            var reader = QtVsToolsPackage.Instance.JoinableTaskFactory
+                                .Run(async () => await command.ExecuteReaderAsync());
+                            using (reader) {
                                 while (reader.Read()) {
                                     var title = GetString(reader, 0);
                                     if (string.IsNullOrWhiteSpace(title))
@@ -233,15 +226,7 @@
                 var uri = string.Empty;
                 switch (links.Values.Count) {
                 case 0:
-                    if (!offline && defaultTryOnline) {
-                        uri = new UriBuilder($"https://doc.qt.io/qt-{info.qtMajor}/search-results.html")
-                        {
-                            Query = "q=" + keyword
-                        }.ToString();
-                    } else {
-                        return false;
-                    }
-                    break;
+                    return TryShowGenericSearchResultsOnline(keyword, info.qtMajor);
                 case 1:
                     uri = links.First().Value;
                     break;
@@ -254,34 +239,40 @@
                     };
                     if (!dialog.ShowModal().GetValueOrDefault())
                         return false;
-                    uri = dialog.Link
-                        .Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
+                    uri = dialog.Link;
                     break;
                 }
 
-                if (string.IsNullOrEmpty(uri)) { // offline mode without a single search hit
-                    VsShellUtilities.ShowMessageBox(Instance.ServiceProvider,
-                        "Your search - " + keyword + " - did not match any documents.",
+                uri = HelperFunctions.FromNativeSeparators(uri);
+                var helpUri = new Uri(uri);
+                if (helpUri.IsFile && !File.Exists(helpUri.LocalPath)) {
+                    VsShellUtilities.ShowMessageBox(QtVsToolsPackage.Instance,
+                        "Your search - " + keyword + " - did match a document, but it could "
+                        + "not be found on disk. To use the online help, select: "
+                        + "Tools | Options | Qt | Preferred source | Online",
                         string.Empty, OLEMSGICON.OLEMSGICON_INFO, OLEMSGBUTTON.OLEMSGBUTTON_OK,
                         OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                 } else {
-                    var helpUri = new Uri(uri.Replace('\\', '/'));
-                    if (helpUri.IsFile && !File.Exists(helpUri.LocalPath)) {
-                        VsShellUtilities.ShowMessageBox(Instance.ServiceProvider,
-                            "Your search - " + keyword + " - did match a document, but it could "
-                            + "not be found on disk. To use the online help, select: "
-                            + "Help | Set Qt Help Preference | Use Online Documentation",
-                            string.Empty, OLEMSGICON.OLEMSGICON_INFO, OLEMSGBUTTON.OLEMSGBUTTON_OK,
-                            OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
-                    } else {
-                        VsShellUtilities.OpenSystemBrowser(HelperFunctions.ChangePathFormat(uri));
-                    }
+                    VsShellUtilities.OpenSystemBrowser(uri);
                 }
-            } catch (Exception e) {
-                Messages.Print(
-                    e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
+            } catch (Exception exception) {
+                exception.Log();
             }
             return true;
         }
+
+        private static bool TryShowGenericSearchResultsOnline(string keyword, uint version)
+        {
+            if (QtVsToolsPackage.Instance.Options.HelpPreference != SourcePreference.Online)
+                return false;
+
+            VsShellUtilities.OpenSystemBrowser(HelperFunctions.FromNativeSeparators(
+                new UriBuilder($"https://doc.qt.io/qt-{version}/search-results.html")
+                {
+                    Query = "q=" + keyword
+                }.ToString())
+            );
+            return true;
+        }
     }
 }
diff --git a/QtVsTools.Package/Package/QtHelpLinkChooser.xaml b/QtVsTools.Package/Package/QtHelpLinkChooser.xaml
index d901292..adfa3d6 100644
--- a/QtVsTools.Package/Package/QtHelpLinkChooser.xaml
+++ b/QtVsTools.Package/Package/QtHelpLinkChooser.xaml
@@ -1,7 +1,7 @@
 <!--
     *****************************************************************************
     **
-    ** Copyright (C) 2016 The Qt Company Ltd.
+    ** Copyright (C) 2022 The Qt Company Ltd.
     ** Contact: https://www.qt.io/licensing/
     **
     ** This file is part of the Qt VS Tools.
@@ -28,33 +28,31 @@
     *****************************************************************************
 -->
 
-<local:VsToolsDialogWindow x:Class="QtVsTools.QtHelpLinkChooser"
-                           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-                           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-                           xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-                           xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-                           xmlns:local="clr-namespace:QtVsTools"
-                           Width="400"
-                           Height="250"
-                           MinWidth="400"
-                           MinHeight="250"
-                           mc:Ignorable="d"
-                           Title="Choose Topic"
-                           ShowInTaskbar="False"
-                           HasHelpButton="False"
-                           HasMinimizeButton="False"
-                           ResizeMode="CanResizeWithGrip"
-                           WindowStartupLocation="CenterOwner">
-    <local:VsToolsDialogWindow.Resources>
-        <BooleanToVisibilityConverter x:Key="b2v" />
+<vsui:DialogWindow x:Class="QtVsTools.QtHelpLinkChooser"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        xmlns:vsui="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0"
+        Width="400"
+        Height="250"
+        MinWidth="400"
+        MinHeight="250"
+        mc:Ignorable="d"
+        Title="Choose Topic"
+        ShowInTaskbar="False"
+        HasHelpButton="False"
+        HasMinimizeButton="False"
+        ResizeMode="CanResizeWithGrip"
+        WindowStartupLocation="CenterOwner">
+    <vsui:DialogWindow.Resources>
         <Style x:Key="ListBoxDoubleClickStyle"
                TargetType="ListBoxItem">
             <EventSetter Event="MouseDoubleClick"
                          Handler="OnListBoxItem_DoubleClick" />
         </Style>
-    </local:VsToolsDialogWindow.Resources>
-    <Grid Margin="10"
-          FocusManager.FocusedElement="{Binding ElementName=searchBox}">
+    </vsui:DialogWindow.Resources>
+    <Grid Margin="10">
         <Grid.RowDefinitions>
             <RowDefinition Height="Auto" />
             <RowDefinition Height="Auto" />
@@ -68,18 +66,8 @@
                  Text="{Binding Path=Keyword}" />
             <Run Text=":" />
         </TextBlock>
-        <Grid Grid.Row="1"
-              MinHeight="22"
-              Background="White">
-            <TextBlock Text=" Filter..."
-                       Foreground="LightSteelBlue"
-                       VerticalAlignment="Center"
-                       Visibility="{Binding ElementName=searchBox,
-                                    Path=Text.IsEmpty, Converter={StaticResource b2v}}" />
-            <TextBox Name="searchBox"
-                     Background="Transparent"
-                     TextChanged="OnSearchBox_TextChanged"
-                     VerticalContentAlignment="Center" />
+        <Grid Grid.Row="1">
+            <Grid Name="searchControlHost" />
         </Grid>
         <ListBox Grid.Row="2"
                  Margin="0,10,0,0"
@@ -104,4 +92,4 @@
                     Margin="0,10,0,0" />
         </StackPanel>
     </Grid>
-</local:VsToolsDialogWindow>
+</vsui:DialogWindow>
diff --git a/QtVsTools.Package/Package/QtHelpLinkChooser.xaml.cs b/QtVsTools.Package/Package/QtHelpLinkChooser.xaml.cs
index 290f966..8d71431 100644
--- a/QtVsTools.Package/Package/QtHelpLinkChooser.xaml.cs
+++ b/QtVsTools.Package/Package/QtHelpLinkChooser.xaml.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -32,10 +32,14 @@
 using System.Windows.Controls;
 using System.Windows.Data;
 using System.Windows.Input;
+using Microsoft.VisualStudio.PlatformUI;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+using QtVsTools.VisualStudio;
 
 namespace QtVsTools
 {
-    partial class QtHelpLinkChooser : VsToolsDialogWindow
+    partial class QtHelpLinkChooser : DialogWindow
     {
         public QtHelpLinkChooser()
         {
@@ -46,28 +50,32 @@
         }
 
         public string Link { get; set; }
+        public string SearchText { get; set; }
+
         public string Keyword { private get; set; }
         public Dictionary<string, string> Links { private get; set; }
 
         private void OnLoaded(object sender, RoutedEventArgs e)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var view = CollectionViewSource.GetDefaultView(linkListBox.ItemsSource);
             view.Filter = obj =>
             {
-                if (string.IsNullOrEmpty(searchBox.Text))
+                if (string.IsNullOrEmpty(SearchText))
                     return true;
 
                 var item = (KeyValuePair<string, string>)obj;
-                return item.Key.IndexOf(searchBox.Text, StringComparison.OrdinalIgnoreCase) >= 0;
+                return item.Key.IndexOf(SearchText, StringComparison.OrdinalIgnoreCase) >= 0;
             };
             linkListBox.SelectedIndex = 0;
-        }
 
-        private void OnSearchBox_TextChanged(object sender, TextChangedEventArgs e)
-        {
-            CollectionViewSource.GetDefaultView(linkListBox.ItemsSource).Refresh();
-            if (linkListBox.Items.Count == 1 || linkListBox.SelectedItem == null)
-                linkListBox.SelectedIndex = 0;
+            var factory = VsServiceProvider
+                .GetService<SVsWindowSearchHostFactory, IVsWindowSearchHostFactory>();
+            var host = factory.CreateWindowSearchHost(searchControlHost);
+
+            host.SetupSearch(new ListBoxSearch(linkListBox, value => SearchText = value));
+            host.Activate(); // set focus
         }
 
         private void OnListBoxItem_DoubleClick(object sender, MouseButtonEventArgs e)
diff --git a/QtVsTools.Package/Package/QtItemContextMenu.cs b/QtVsTools.Package/Package/QtItemContextMenu.cs
index 19bc389..ce4f888 100644
--- a/QtVsTools.Package/Package/QtItemContextMenu.cs
+++ b/QtVsTools.Package/Package/QtItemContextMenu.cs
@@ -26,15 +26,16 @@
 **
 ****************************************************************************/
 
-using EnvDTE;
-using Microsoft.VisualStudio.Shell;
-using QtVsTools.Core;
-using QtVsTools.VisualStudio;
 using System;
 using System.ComponentModel.Design;
+using Microsoft.VisualStudio.Shell;
+using EnvDTE;
 
 namespace QtVsTools
 {
+    using Core;
+    using VisualStudio;
+
     /// <summary>
     /// Command handler
     /// </summary>
@@ -43,30 +44,24 @@
         /// <summary>
         /// Command menu group (command set GUID).
         /// </summary>
-        public static readonly Guid ItemContextMenuGuid = new Guid("9f67a0bd-ee0a-47e3-b656-5efb12e3c770");
+        private static readonly Guid ItemContextMenuGuid = new Guid("9f67a0bd-ee0a-47e3-b656-5efb12e3c770");
 
         /// <summary>
         /// Gets the instance of the command.
         /// </summary>
-        public static QtItemContextMenu Instance
+        private static QtItemContextMenu Instance
         {
             get;
-            private set;
+            set;
         }
 
         /// <summary>
         /// Initializes the singleton instance of the command.
         /// </summary>
-        /// <param name="package">Owner package, not null.</param>
-        public static void Initialize(Package package)
+        public static void Initialize()
         {
-            Instance = new QtItemContextMenu(package);
+            Instance = new QtItemContextMenu();
         }
-
-        /// <summary>
-        /// VS Package that provides this command, not null.
-        /// </summary>
-        private readonly Package m_package;
 
         /// <summary>
         /// Command ID.
@@ -78,14 +73,8 @@
         /// Initializes a new instance of the <see cref="QtMainMenu"/> class.
         /// Adds our command handlers for menu (commands must exist in the command table file)
         /// </summary>
-        /// <param name="package">Owner package, not null.</param>
-        private QtItemContextMenu(Package package)
+        private QtItemContextMenu()
         {
-            if (package == null)
-                throw new ArgumentNullException("package");
-
-            m_package = package;
-
             var commandService = VsServiceProvider
                 .GetService<IMenuCommandService, OleMenuCommandService>();
             if (commandService == null)
@@ -104,6 +93,8 @@
 
         private void execHandler(object sender, EventArgs e)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var command = sender as OleMenuCommand;
             if (command == null)
                 return;
@@ -120,6 +111,8 @@
 
         private void beforeQueryStatus(object sender, EventArgs e)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var command = sender as OleMenuCommand;
             if (command == null)
                 return;
@@ -128,7 +121,7 @@
             command.Visible = false;
 
             var prj = HelperFunctions.GetSelectedProject(QtVsToolsPackage.Instance.Dte);
-            if (!HelperFunctions.IsQtProject(prj) || QtVsToolsPackage.Instance.Dte.SelectedItems.Count <= 0)
+            if (!HelperFunctions.IsVsToolsProject(prj) || QtVsToolsPackage.Instance.Dte.SelectedItems.Count <= 0)
                 return;
 
             foreach (SelectedItem si in QtVsToolsPackage.Instance.Dte.SelectedItems) {
@@ -136,7 +129,7 @@
                     return; // Don't display commands if one of the selected files is not a .ts file.
             }
 
-            command.Enabled = true;
+            command.Enabled = Translation.ToolsAvailable(prj);
             command.Visible = true;
         }
     }
diff --git a/QtVsTools.Package/Package/QtMainMenu.cs b/QtVsTools.Package/Package/QtMainMenu.cs
index 2c8e90d..7298333 100644
--- a/QtVsTools.Package/Package/QtMainMenu.cs
+++ b/QtVsTools.Package/Package/QtMainMenu.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -26,16 +26,17 @@
 **
 ****************************************************************************/
 
-using EnvDTE;
-using Microsoft.VisualStudio.Shell;
-using QtVsTools.Core;
-using QtVsTools.VisualStudio;
 using System;
 using System.ComponentModel.Design;
 using System.Windows.Forms;
+using Microsoft.VisualStudio.Shell;
+using EnvDTE;
 
 namespace QtVsTools
 {
+    using Core;
+    using VisualStudio;
+
     /// <summary>
     /// Command handler
     /// </summary>
@@ -44,24 +45,23 @@
         /// <summary>
         /// Command menu group (command set GUID).
         /// </summary>
-        public static readonly Guid MainMenuGuid = new Guid("58f83fff-d39d-4c66-810b-2702e1f04e73");
+        private static readonly Guid MainMenuGuid = new Guid("58f83fff-d39d-4c66-810b-2702e1f04e73");
 
         /// <summary>
         /// Gets the instance of the command.
         /// </summary>
-        public static QtMainMenu Instance
+        private static QtMainMenu Instance
         {
             get;
-            private set;
+            set;
         }
 
         /// <summary>
         /// Initializes the singleton instance of the command.
         /// </summary>
-        /// <param name="package">Owner package, not null.</param>
-        public static void Initialize(Package package)
+        public static void Initialize()
         {
-            Instance = new QtMainMenu(package);
+            Instance = new QtMainMenu();
         }
 
         /// <summary>
@@ -71,16 +71,14 @@
         {
             QtVersionId = 0x0500,
             ViewQtHelpId = 0x0501,
+            ViewGettingStartedId = 0x0503,
             LaunchDesignerId = 0x0100,
             LaunchLinguistId = 0x0101,
             OpenProFileId = 0x0102,
             ImportPriFileId = 0x0103,
             ExportPriFileId = 0x0104,
             ExportProFileId = 0x0105,
-            CreateNewTsFileId = 0x0107,
             ConvertToQtMsBuild = 0x0130,
-            ConvertToQtId = 0x0124,
-            ConvertToQmakeId = 0x0108,
             QtProjectSettingsId = 0x0109,
             ChangeProjectQtVersionId = 0x0126,
             QtOptionsId = 0x0110,
@@ -88,22 +86,12 @@
         }
 
         /// <summary>
-        /// VS Package that provides this command, not null.
-        /// </summary>
-        private readonly Package m_package;
-
-        /// <summary>
         /// Initializes a new instance of the <see cref="QtMainMenu"/> class.
         /// Adds our command handlers for menu (commands must exist in the command table file)
         /// </summary>
         /// <param name="package">Owner package, not null.</param>
-        private QtMainMenu(Package package)
+        private QtMainMenu()
         {
-            if (package == null)
-                throw new ArgumentNullException("package");
-
-            m_package = package;
-
             var commandService = VsServiceProvider
                 .GetService<IMenuCommandService, OleMenuCommandService>();
             if (commandService == null)
@@ -119,6 +107,8 @@
 
         private void execHandler(object sender, EventArgs e)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var command = sender as OleMenuCommand;
             if (command == null)
                 return;
@@ -126,6 +116,9 @@
             switch ((CommandId)command.CommandID.ID) {
             case CommandId.ViewQtHelpId:
                 VsShellUtilities.OpenSystemBrowser("https://www.qt.io/developers");
+                break;
+            case CommandId.ViewGettingStartedId:
+                VsShellUtilities.OpenSystemBrowser("https://doc.qt.io/qtvstools/qtvstools-getting-started.html");
                 break;
             case CommandId.LaunchDesignerId:
                 QtVsToolsPackage.Instance.QtDesigner.Start(hideWindow: false);
@@ -145,23 +138,8 @@
             case CommandId.ExportProFileId:
                 ExtLoader.ExportProFile();
                 break;
-            case CommandId.CreateNewTsFileId:
-                Translation.CreateNewTranslationFile(HelperFunctions.GetSelectedQtProject(QtVsToolsPackage
-                    .Instance.Dte));
-                break;
-            case CommandId.ConvertToQtId:
-            case CommandId.ConvertToQmakeId: {
-                    var caption = SR.GetString("ConvertTitle");
-                    var text = SR.GetString("ConvertConfirmation");
-                    if (MessageBox.Show(text, caption, MessageBoxButtons.YesNo) == DialogResult.Yes) {
-                        HelperFunctions.ToggleProjectKind(HelperFunctions.GetSelectedProject(QtVsToolsPackage
-                            .Instance.Dte));
-                    }
-                }
-                break;
-            case CommandId.ConvertToQtMsBuild: {
-                    QtMsBuildConverter.SolutionToQtMsBuild();
-                }
+            case CommandId.ConvertToQtMsBuild:
+                QtMsBuildConverter.SolutionToQtMsBuild();
                 break;
             case CommandId.QtProjectSettingsId: {
                     var pro = HelperFunctions.GetSelectedQtProject(QtVsToolsPackage.Instance.Dte);
@@ -169,31 +147,14 @@
                     if (projectVersion >= Resources.qtMinFormatVersion_Settings) {
                         QtVsToolsPackage.Instance.Dte.ExecuteCommand("Project.Properties");
                     } else if (pro != null) {
-                        using (var formProjectQtSettings = new FormProjectQtSettings()) {
-                            formProjectQtSettings.SetProject(pro);
-                            formProjectQtSettings.StartPosition = FormStartPosition.CenterParent;
-                            var ww = new MainWinWrapper(QtVsToolsPackage.Instance.Dte);
-                            formProjectQtSettings.ShowDialog(ww);
-                        }
+                        Legacy.QtMenu.ShowFormProjectQtSettings(pro);
                     } else {
                         MessageBox.Show(SR.GetString("NoProjectOpened"));
                     }
                 }
                 break;
-            case CommandId.ChangeProjectQtVersionId: {
-                    var pro = HelperFunctions.GetSelectedQtProject(QtVsToolsPackage.Instance.Dte);
-                    if (HelperFunctions.IsQMakeProject(pro)) {
-                        using (var formChangeQtVersion = new FormChangeQtVersion()) {
-                            formChangeQtVersion.UpdateContent(ChangeFor.Project);
-                            var ww = new MainWinWrapper(QtVsToolsPackage.Instance.Dte);
-                            if (formChangeQtVersion.ShowDialog(ww) == DialogResult.OK) {
-                                var qtVersion = formChangeQtVersion.GetSelectedQtVersion();
-                                HelperFunctions.SetDebuggingEnvironment(pro, "PATH=" + QtVersionManager
-                                    .The().GetInstallPath(qtVersion) + @"\bin;$(PATH)", true);
-                            }
-                        }
-                    }
-                }
+            case CommandId.ChangeProjectQtVersionId:
+                Legacy.QtMenu.ShowFormChangeProjectQtVersion();
                 break;
             case CommandId.QtOptionsId:
                 QtVsToolsPackage.Instance.ShowOptionPage(typeof(Options.QtOptionsPage));
@@ -206,12 +167,17 @@
 
         private void beforeQueryStatus(object sender, EventArgs e)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var command = sender as OleMenuCommand;
             if (command == null)
                 return;
 
+            var project = HelperFunctions.GetSelectedProject(QtVsToolsPackage.Instance.Dte);
+
             switch ((CommandId)command.CommandID.ID) {
             case CommandId.ViewQtHelpId:
+            case CommandId.ViewGettingStartedId:
                 command.Visible = command.Enabled = true;
                 break;
             case CommandId.QtVersionId:
@@ -230,39 +196,26 @@
             case CommandId.ImportPriFileId:
             case CommandId.ExportPriFileId:
             case CommandId.ExportProFileId:
-            case CommandId.CreateNewTsFileId: {
-                    command.Visible = true;
-                    command.Enabled = HelperFunctions.IsQtProject(HelperFunctions
-                        .GetSelectedProject(QtVsToolsPackage.Instance.Dte));
-                }
+                command.Visible = true;
+                command.Enabled = HelperFunctions.IsVsToolsProject(project);
                 break;
-            // TODO: Fix these functionality and re-enable the menu items
-            case CommandId.ConvertToQtId:
-            case CommandId.ConvertToQmakeId: {
-                    command.Visible = false;
-                }
-                break;
-            //case CommandId.ConvertToQmakeId:
             case CommandId.QtProjectSettingsId: {
                     var status = vsCommandStatus.vsCommandStatusSupported;
-                    var project = HelperFunctions.GetSelectedProject(QtVsToolsPackage.Instance.Dte);
                     if (project != null) {
-                        if (HelperFunctions.IsQtProject(project))
+                        if (HelperFunctions.IsVsToolsProject(project))
                             status |= vsCommandStatus.vsCommandStatusEnabled;
-                        else if (HelperFunctions.IsQMakeProject(project))
+                        else if (HelperFunctions.IsQtProject(project))
                             status |= vsCommandStatus.vsCommandStatusInvisible;
                     }
                     command.Enabled = ((status & vsCommandStatus.vsCommandStatusEnabled) != 0);
                     command.Visible = ((status & vsCommandStatus.vsCommandStatusInvisible) == 0);
                 }
                 break;
-            //case CommandId.ConvertToQtId:
             case CommandId.ChangeProjectQtVersionId: {
                     var status = vsCommandStatus.vsCommandStatusSupported;
-                    var project = HelperFunctions.GetSelectedProject(QtVsToolsPackage.Instance.Dte);
-                    if ((project == null) || HelperFunctions.IsQtProject(project))
+                    if ((project == null) || HelperFunctions.IsVsToolsProject(project))
                         status |= vsCommandStatus.vsCommandStatusInvisible;
-                    else if (HelperFunctions.IsQMakeProject(project))
+                    else if (HelperFunctions.IsQtProject(project))
                         status |= vsCommandStatus.vsCommandStatusEnabled;
                     else
                         status |= vsCommandStatus.vsCommandStatusInvisible;
diff --git a/QtVsTools.Package/Package/QtMsBuildConverter.cs b/QtVsTools.Package/Package/QtMsBuildConverter.cs
index eac783f..79d484d 100644
--- a/QtVsTools.Package/Package/QtMsBuildConverter.cs
+++ b/QtVsTools.Package/Package/QtMsBuildConverter.cs
@@ -32,17 +32,21 @@
 using System.Linq;
 using System.Windows.Forms;
 using Microsoft.VisualStudio;
+using Microsoft.VisualStudio.Shell;
 using Microsoft.VisualStudio.Shell.Interop;
 using Microsoft.VisualStudio.VCProjectEngine;
-using QtVsTools.Core;
-using QtVsTools.VisualStudio;
 
 namespace QtVsTools
 {
+    using Core;
+    using VisualStudio;
+
     static class QtMsBuildConverter
     {
         public static bool SolutionToQtMsBuild()
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var solution = QtVsToolsPackage.Instance.Dte.Solution;
             if (solution == null)
                 return ErrorMessage(string.Format(SR.GetString("ErrorConvertingProject"), ""));
@@ -53,8 +57,8 @@
                 return WarningMessage(SR.GetString("NoProjectsToConvert"));
 
             foreach (EnvDTE.Project project in allProjects) {
-                if ((HelperFunctions.IsQtProject(project)
-                    || HelperFunctions.IsQMakeProject(project))
+                if ((HelperFunctions.IsVsToolsProject(project)
+                    || HelperFunctions.IsQtProject(project))
                     && !QtProject.IsQtMsBuildEnabled(project)) {
                     projects.Add(project);
                 }
@@ -68,7 +72,14 @@
                 MessageBoxButtons.YesNo) != DialogResult.Yes)
                 return WarningMessage(SR.GetString("CancelConvertingProject"));
 
-            if (projects.Where(project => project.IsDirty).Any()) {
+            bool hasDirtyProjects = projects
+                .Where(project =>
+                {
+                    ThreadHelper.ThrowIfNotOnUIThread();
+                    return project.IsDirty;
+                })
+                .Any();
+            if (hasDirtyProjects) {
                 if (MessageBox.Show(
                     SR.GetString("ConvertSaveConfirmation"),
                     SR.GetString("ConvertTitle"),
@@ -76,7 +87,13 @@
                     return WarningMessage(SR.GetString("CancelConvertingProject"));
             }
 
-            var projectPaths = projects.Select(x => x.FullName).ToList();
+            var projectPaths = projects
+                .Select(x =>
+                {
+                    ThreadHelper.ThrowIfNotOnUIThread();
+                    return x.FullName;
+                })
+                .ToList();
 
             string solutionPath = solution.FileName;
             solution.Close(true);
@@ -142,6 +159,8 @@
 
         public static bool ProjectToQtMsBuild(EnvDTE.Project project, bool askConfirmation = true)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (project == null)
                 return ErrorMessage(string.Format(SR.GetString("ErrorConvertingProject"), ""));
             var pathToProject = project.FullName;
@@ -178,7 +197,7 @@
             try {
                 if (solution.UnloadProject(
                     ref projectGuid,
-                    (uint)_VSProjectUnloadStatus.UNLOADSTATUS_LoadPendingIfNeeded)
+                    (uint)_VSProjectUnloadStatus.UNLOADSTATUS_UnloadedByUser)
                     != VSConstants.S_OK)
                     return ErrorMessage(
                         string.Format(SR.GetString("ErrorConvertingProject"), projectName));
diff --git a/QtVsTools.Package/Package/QtProjectContextMenu.cs b/QtVsTools.Package/Package/QtProjectContextMenu.cs
index 2706ef5..3b08b13 100644
--- a/QtVsTools.Package/Package/QtProjectContextMenu.cs
+++ b/QtVsTools.Package/Package/QtProjectContextMenu.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -26,20 +26,17 @@
 **
 ****************************************************************************/
 
-using EnvDTE;
-using Microsoft.VisualStudio;
-using Microsoft.VisualStudio.Shell;
-using Microsoft.VisualStudio.Shell.Interop;
-using Microsoft.VisualStudio.VCProjectEngine;
-using QtVsTools.Core;
-using QtVsTools.VisualStudio;
 using System;
 using System.ComponentModel.Design;
 using System.Windows.Forms;
+using Microsoft.VisualStudio.Shell;
+using EnvDTE;
 
 namespace QtVsTools
 {
+    using Core;
     using QtMsBuild;
+    using VisualStudio;
 
     /// <summary>
     /// Command handler
@@ -49,24 +46,23 @@
         /// <summary>
         /// Command menu group (command set GUID).
         /// </summary>
-        public static readonly Guid ProjectContextMenuGuid = new Guid("5732faa9-6074-4e07-b035-2816e809f50e");
+        private static readonly Guid ProjectContextMenuGuid = new Guid("5732faa9-6074-4e07-b035-2816e809f50e");
 
         /// <summary>
         /// Gets the instance of the command.
         /// </summary>
-        public static QtProjectContextMenu Instance
+        private static QtProjectContextMenu Instance
         {
             get;
-            private set;
+            set;
         }
 
         /// <summary>
         /// Initializes the singleton instance of the command.
         /// </summary>
-        /// <param name="package">Owner package, not null.</param>
-        public static void Initialize(Package package)
+        public static void Initialize()
         {
-            Instance = new QtProjectContextMenu(package);
+            Instance = new QtProjectContextMenu();
         }
 
         /// <summary>
@@ -77,35 +73,20 @@
             ImportPriFileProjectId = 0x0114,
             ExportPriFileProjectId = 0x0115,
             ExportProFileProjectId = 0x0116,
-            CreateNewTsFileProjectId = 0x0117,
             lUpdateOnProjectId = 0x0118,
             lReleaseOnProjectId = 0x0119,
             ProjectConvertToQtMsBuild = 0x0130,
             ProjectRefreshIntelliSense = 0x0131,
-            ConvertToQtProjectId = 0x0120,
-            ConvertToQmakeProjectId = 0x0121,
             QtProjectSettingsProjectId = 0x0122,
-            ChangeProjectQtVersionProjectId = 0x0123,
-            ProjectAddNewQtClassProjectId = 0x200
+            ChangeProjectQtVersionProjectId = 0x0123
         }
-
-        /// <summary>
-        /// VS Package that provides this command, not null.
-        /// </summary>
-        private readonly Package m_package;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="QtMainMenu"/> class.
         /// Adds our command handlers for menu (commands must exist in the command table file)
         /// </summary>
-        /// <param name="package">Owner package, not null.</param>
-        private QtProjectContextMenu(Package package)
+        private QtProjectContextMenu()
         {
-            if (package == null)
-                throw new ArgumentNullException("package");
-
-            m_package = package;
-
             var commandService = VsServiceProvider
                 .GetService<IMenuCommandService, OleMenuCommandService>();
             if (commandService == null)
@@ -121,6 +102,8 @@
 
         private void execHandler(object sender, EventArgs e)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var command = sender as OleMenuCommand;
             if (command == null)
                 return;
@@ -135,25 +118,11 @@
             case CommandId.ExportProFileProjectId:
                 ExtLoader.ExportProFile();
                 break;
-            case CommandId.CreateNewTsFileProjectId:
-                Translation.CreateNewTranslationFile(HelperFunctions.GetSelectedQtProject(QtVsToolsPackage
-                    .Instance.Dte));
-                break;
             case CommandId.lUpdateOnProjectId:
                 Translation.RunlUpdate(HelperFunctions.GetSelectedQtProject(QtVsToolsPackage.Instance.Dte));
                 break;
             case CommandId.lReleaseOnProjectId:
                 Translation.RunlRelease(HelperFunctions.GetSelectedQtProject(QtVsToolsPackage.Instance.Dte));
-                break;
-            case CommandId.ConvertToQtProjectId:
-            case CommandId.ConvertToQmakeProjectId: {
-                    var caption = SR.GetString("ConvertTitle");
-                    var text = SR.GetString("ConvertConfirmation");
-                    if (MessageBox.Show(text, caption, MessageBoxButtons.YesNo) == DialogResult.Yes) {
-                        HelperFunctions.ToggleProjectKind(HelperFunctions.GetSelectedProject(QtVsToolsPackage
-                            .Instance.Dte));
-                    }
-                }
                 break;
             case CommandId.QtProjectSettingsProjectId: {
                     var pro = HelperFunctions.GetSelectedQtProject(QtVsToolsPackage.Instance.Dte);
@@ -161,31 +130,14 @@
                     if (projectVersion >= Resources.qtMinFormatVersion_Settings) {
                         QtVsToolsPackage.Instance.Dte.ExecuteCommand("Project.Properties");
                     } else if (pro != null) {
-                        using (var formProjectQtSettings = new FormProjectQtSettings()) {
-                            formProjectQtSettings.SetProject(pro);
-                            formProjectQtSettings.StartPosition = FormStartPosition.CenterParent;
-                            var ww = new MainWinWrapper(QtVsToolsPackage.Instance.Dte);
-                            formProjectQtSettings.ShowDialog(ww);
-                        }
+                        Legacy.QtMenu.ShowFormProjectQtSettings(pro);
                     } else {
                         MessageBox.Show(SR.GetString("NoProjectOpened"));
                     }
                 }
                 break;
-            case CommandId.ChangeProjectQtVersionProjectId: {
-                    var pro = HelperFunctions.GetSelectedQtProject(QtVsToolsPackage.Instance.Dte);
-                    if (HelperFunctions.IsQMakeProject(pro)) {
-                        using (var formChangeQtVersion = new FormChangeQtVersion()) {
-                            formChangeQtVersion.UpdateContent(ChangeFor.Project);
-                            var ww = new MainWinWrapper(QtVsToolsPackage.Instance.Dte);
-                            if (formChangeQtVersion.ShowDialog(ww) == DialogResult.OK) {
-                                var qtVersion = formChangeQtVersion.GetSelectedQtVersion();
-                                HelperFunctions.SetDebuggingEnvironment(pro, "PATH=" + QtVersionManager
-                                    .The().GetInstallPath(qtVersion) + @"\bin;$(PATH)", true);
-                            }
-                        }
-                    }
-                }
+            case CommandId.ChangeProjectQtVersionProjectId:
+                Legacy.QtMenu.ShowFormChangeProjectQtVersion();
                 break;
             case CommandId.ProjectConvertToQtMsBuild: {
                     QtMsBuildConverter.ProjectToQtMsBuild(
@@ -194,29 +146,8 @@
                 break;
             case CommandId.ProjectRefreshIntelliSense: {
                     var selectedProject = HelperFunctions.GetSelectedProject(QtVsToolsPackage.Instance.Dte);
-                    var tracker = QtProjectTracker.Get(selectedProject);
+                    var tracker = QtProjectTracker.Get(selectedProject, selectedProject.FullName);
                     QtProjectIntellisense.Refresh(tracker.Project);
-                }
-                break;
-            case CommandId.ProjectAddNewQtClassProjectId: {
-                    try {
-                        var project = HelperFunctions.GetSelectedProject(QtVsToolsPackage.Instance.Dte);
-                        if (!HelperFunctions.IsQtProject(project))
-                            return;
-
-                        var vcProject = project.Object as VCProject;
-                        if (vcProject == null)
-                            return;
-
-                        var loop = true;
-                        do {
-                            var classWizard = new Wizards.ClassWizard.AddClassWizard();
-                            loop = classWizard.Run(QtVsToolsPackage.Instance.Dte, vcProject.Name,
-                                vcProject.ProjectDirectory) == Wizards.WizardResult.Exception;
-                        } while (loop);
-                    } catch {
-                        // Deliberately ignore any kind of exception but close the dialog.
-                    }
                 }
                 break;
             }
@@ -229,8 +160,8 @@
                 return;
 
             var project = HelperFunctions.GetSelectedProject(QtVsToolsPackage.Instance.Dte);
-            var isQtProject = HelperFunctions.IsQtProject(project);
-            var isQMakeProject = HelperFunctions.IsQMakeProject(project);
+            var isQtProject = HelperFunctions.IsVsToolsProject(project);
+            var isQMakeProject = HelperFunctions.IsQtProject(project);
             var isQtMsBuildEnabled = QtProject.IsQtMsBuildEnabled(project);
 
             if (!isQtProject && !isQMakeProject) {
@@ -239,25 +170,19 @@
             }
 
             switch ((CommandId)command.CommandID.ID) {
-            // TODO: Fix these functionality and re-enable the menu items
-            case CommandId.ConvertToQtProjectId:
-            case CommandId.ConvertToQmakeProjectId: {
-                    command.Visible = false;
-                }
-                break;
             case CommandId.ImportPriFileProjectId:
             case CommandId.ExportPriFileProjectId:
             case CommandId.ExportProFileProjectId:
-            case CommandId.CreateNewTsFileProjectId:
+                command.Visible = true;
+                command.Enabled = HelperFunctions.IsVsToolsProject(HelperFunctions
+                    .GetSelectedProject(QtVsToolsPackage.Instance.Dte));
+                break;
             case CommandId.lUpdateOnProjectId:
             case CommandId.lReleaseOnProjectId:
                 command.Visible = true;
-                command.Enabled = HelperFunctions.IsQtProject(HelperFunctions
-                    .GetSelectedProject(QtVsToolsPackage.Instance.Dte));
+                command.Enabled = Translation.ToolsAvailable(project);
                 break;
-            //case CommandId.ConvertToQmakeProjectId:
-            case CommandId.QtProjectSettingsProjectId:
-            case CommandId.ProjectAddNewQtClassProjectId: {
+            case CommandId.QtProjectSettingsProjectId: {
                     var status = vsCommandStatus.vsCommandStatusSupported;
                     if (project != null) {
                         if (isQtProject)
@@ -269,7 +194,6 @@
                     command.Visible = ((status & vsCommandStatus.vsCommandStatusInvisible) == 0);
                 }
                 break;
-            //case CommandId.ConvertToQtProjectId:
             case CommandId.ChangeProjectQtVersionProjectId: {
                     var status = vsCommandStatus.vsCommandStatusSupported;
                     if ((project == null) || isQtProject)
diff --git a/QtVsTools.Package/Package/QtSolutionContextMenu.cs b/QtVsTools.Package/Package/QtSolutionContextMenu.cs
index d680fe7..67f2a8c 100644
--- a/QtVsTools.Package/Package/QtSolutionContextMenu.cs
+++ b/QtVsTools.Package/Package/QtSolutionContextMenu.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -26,17 +26,15 @@
 **
 ****************************************************************************/
 
-using EnvDTE80;
-using Microsoft.VisualStudio.Shell;
-using QtVsTools.Core;
-using QtVsTools.VisualStudio;
 using System;
 using System.ComponentModel.Design;
-using System.Windows.Forms;
+using Microsoft.VisualStudio.Shell;
 
 namespace QtVsTools
 {
+    using Core;
     using QtMsBuild;
+    using VisualStudio;
 
     /// <summary>
     /// Command handler
@@ -46,30 +44,24 @@
         /// <summary>
         /// Command menu group (command set GUID).
         /// </summary>
-        public static readonly Guid SolutionContextMenuGuid = new Guid("6dcda34f-4d22-4d6a-a176-5507069c5a3e");
+        private static readonly Guid SolutionContextMenuGuid = new Guid("6dcda34f-4d22-4d6a-a176-5507069c5a3e");
 
         /// <summary>
         /// Gets the instance of the command.
         /// </summary>
-        public static QtSolutionContextMenu Instance
+        private static QtSolutionContextMenu Instance
         {
             get;
-            private set;
+            set;
         }
 
         /// <summary>
         /// Initializes the singleton instance of the command.
         /// </summary>
-        /// <param name="package">Owner package, not null.</param>
-        public static void Initialize(Package package)
+        public static void Initialize()
         {
-            Instance = new QtSolutionContextMenu(package);
+            Instance = new QtSolutionContextMenu();
         }
-
-        /// <summary>
-        /// VS Package that provides this command, not null.
-        /// </summary>
-        private readonly Package m_package;
 
         /// <summary>
         /// Command ID.
@@ -87,14 +79,8 @@
         /// Initializes a new instance of the <see cref="QtMainMenu"/> class.
         /// Adds our command handlers for menu (commands must exist in the command table file)
         /// </summary>
-        /// <param name="package">Owner package, not null.</param>
-        private QtSolutionContextMenu(Package package)
+        private QtSolutionContextMenu()
         {
-            if (package == null)
-                throw new ArgumentNullException("package");
-
-            m_package = package;
-
             var commandService = VsServiceProvider
                 .GetService<IMenuCommandService, OleMenuCommandService>();
             if (commandService == null)
@@ -113,66 +99,51 @@
             var command = sender as OleMenuCommand;
             if (command == null)
                 return;
-            command.Enabled = command.Visible = true;
+
+            switch (command.CommandID.ID) {
+            case (int)CommandId.ChangeSolutionQtVersionId:
+                var projects = HelperFunctions.ProjectsInSolution(QtVsToolsPackage.Instance.Dte);
+                foreach (var project in projects) {
+                    if (!HelperFunctions.IsVsToolsProject(project)
+                        && HelperFunctions.IsQtProject(project)) {
+                        command.Enabled = command.Visible = true;
+                        return;
+                    }
+                }
+                command.Enabled = command.Visible = false;
+                break;
+            default:
+                command.Enabled = command.Visible = true;
+                break;
+            }
         }
 
         private void execHandler(object sender, EventArgs e)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var command = sender as OleMenuCommand;
             if (command == null)
                 return;
 
             var dte = QtVsToolsPackage.Instance.Dte;
-            switch (command.CommandID.ID) {
-            case (int)CommandId.lUpdateOnSolutionId:
+            switch ((CommandId)command.CommandID.ID) {
+            case CommandId.lUpdateOnSolutionId:
                 Translation.RunlUpdate(QtVsToolsPackage.Instance.Dte.Solution);
                 break;
-            case (int)CommandId.lReleaseOnSolutionId:
+            case CommandId.lReleaseOnSolutionId:
                 Translation.RunlRelease(QtVsToolsPackage.Instance.Dte.Solution);
                 break;
-            case (int)CommandId.ChangeSolutionQtVersionId:
-                string newQtVersion = null;
-                using (var formChangeQtVersion = new FormChangeQtVersion()) {
-                    formChangeQtVersion.UpdateContent(ChangeFor.Solution);
-                    if (formChangeQtVersion.ShowDialog() != DialogResult.OK)
-                        return;
-                    newQtVersion = formChangeQtVersion.GetSelectedQtVersion();
-                }
-                if (newQtVersion == null)
-                    return;
-
-                string currentPlatform = null;
-                try {
-                    var config2 = QtVsToolsPackage.Instance.Dte.Solution.SolutionBuild
-                        .ActiveConfiguration as SolutionConfiguration2;
-                    currentPlatform = config2.PlatformName;
-                } catch { }
-                if (string.IsNullOrEmpty(currentPlatform))
-                    return;
-
-                foreach (var project in HelperFunctions.ProjectsInSolution(dte)) {
-                    if (HelperFunctions.IsQtProject(project)) {
-                        var OldQtVersion = QtVersionManager.The().GetProjectQtVersion(project,
-                            currentPlatform);
-                        if (OldQtVersion == null)
-                            OldQtVersion = QtVersionManager.The().GetDefaultVersion();
-
-                        var created = false;
-                        var qtProject = QtProject.Create(project);
-                        if (qtProject.PromptChangeQtVersion(OldQtVersion, newQtVersion))
-                            qtProject.ChangeQtVersion(OldQtVersion, newQtVersion, ref created);
-                    }
-                }
-                QtVersionManager.The().SaveSolutionQtVersion(dte.Solution, newQtVersion);
+            case CommandId.ChangeSolutionQtVersionId:
+                Legacy.QtMenu.ShowFormChangeSolutionQtVersion();
                 break;
-            case (int)CommandId.SolutionConvertToQtMsBuild: {
-                    QtMsBuildConverter.SolutionToQtMsBuild();
-                }
+            case CommandId.SolutionConvertToQtMsBuild:
+                QtMsBuildConverter.SolutionToQtMsBuild();
                 break;
-            case (int)CommandId.SolutionEnableProjectTracking: {
+            case CommandId.SolutionEnableProjectTracking: {
                     foreach (var project in HelperFunctions.ProjectsInSolution(dte)) {
-                        if (HelperFunctions.IsQtProject(project))
-                            QtProjectTracker.Get(project);
+                        if (HelperFunctions.IsVsToolsProject(project))
+                            QtProjectTracker.Get(project, project.FullName);
                     }
                 }
                 break;
diff --git a/QtVsTools.Package/Package/SR.cs b/QtVsTools.Package/Package/SR.cs
index 8dd6c57..6bf9f44 100644
--- a/QtVsTools.Package/Package/SR.cs
+++ b/QtVsTools.Package/Package/SR.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -26,8 +26,6 @@
 **
 ****************************************************************************/
 
-using System;
-using System.Globalization;
 using System.Resources;
 
 namespace QtVsTools
@@ -36,66 +34,39 @@
     {
         static SR loader;
         readonly ResourceManager resources;
-        static readonly Object obj = new Object();
+        static readonly object obj = new object();
 
-        internal const string OK = "OK";
-        internal const string Cancel = "Cancel";
-
-        internal static CultureInfo appCultureInfo;
-        internal static CultureInfo defaultCultureInfo;
-
-        internal SR(int localeId)
+        internal SR()
         {
-            defaultCultureInfo = CultureInfo.GetCultureInfo("en");
-            appCultureInfo = CultureInfo.GetCultureInfo(localeId);
-            if (appCultureInfo.Name.StartsWith("en", StringComparison.Ordinal))
-                appCultureInfo = null;
             resources = new ResourceManager("QtVsTools.Package.Resources", GetType().Assembly);
         }
 
-        private static SR GetLoader(int localeId)
+        private static SR GetLoader()
         {
             if (loader == null) {
                 lock (obj) {
                     if (loader == null)
-                        loader = new SR(localeId);
+                        loader = new SR();
                 }
             }
             return loader;
         }
 
-        private static CultureInfo Culture
-        {
-            get { return appCultureInfo; }
-        }
-
         public static string GetString(string name, params object[] args)
         {
-            var res = GetString(name);
-            if (!string.IsNullOrEmpty(res) && args != null && args.Length > 0)
+            var sys = GetLoader();
+            if (sys == null)
+                return null;
+
+            var res = sys.resources.GetString(name, null);
+            if (args != null && args.Length > 0 && !string.IsNullOrEmpty(res))
                 return string.Format(res, args);
             return res;
         }
 
         public static string GetString(string name)
         {
-            return GetString(name, QtVsToolsPackage.Instance);
-        }
-
-        public static string GetString(string name, QtVsToolsPackage vsixInstance)
-        {
-            var sys = GetLoader(vsixInstance.Dte.LocaleID);
-            if (sys == null)
-                return null;
-
-            string result;
-            try {
-                result = sys.resources.GetString(name, Culture);
-            } catch (Exception) {
-                result = sys.resources.GetString(name, defaultCultureInfo);
-            }
-
-            return result;
+            return GetString(name, null);
         }
     }
 }
diff --git a/QtVsTools.Package/Package/Translation.cs b/QtVsTools.Package/Package/Translation.cs
index 3c7e9f2..d47e525 100644
--- a/QtVsTools.Package/Package/Translation.cs
+++ b/QtVsTools.Package/Package/Translation.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -26,24 +26,16 @@
 **
 ****************************************************************************/
 
-using Microsoft.VisualStudio;
-using Microsoft.VisualStudio.Shell.Interop;
-using Microsoft.VisualStudio.VCProjectEngine;
-using QtVsTools.Core;
-using QtVsTools.VisualStudio;
 using System;
 using System.Collections.Generic;
-using System.Diagnostics;
 using System.IO;
 using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows.Forms;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.VCProjectEngine;
 
 namespace QtVsTools
 {
-    using static Core.HelperFunctions;
+    using Core;
     using QtMsBuild;
 
     /// <summary>
@@ -51,16 +43,10 @@
     /// </summary>
     public static class Translation
     {
-        public static void RunlRelease(VCFile vcFile)
-        {
-            var vcProj = vcFile.project as VCProject;
-            var project = vcProj?.Object as EnvDTE.Project;
-            RunTranslationTarget(BuildAction.Release,
-                project, new[] { vcFile.RelativePath });
-        }
-
         public static void RunlRelease(VCFile[] vcFiles)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var vcProj = vcFiles.FirstOrDefault()?.project as VCProject;
             var project = vcProj?.Object as EnvDTE.Project;
             RunTranslationTarget(BuildAction.Release,
@@ -69,11 +55,14 @@
 
         public static void RunlRelease(EnvDTE.Project project)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
             RunTranslationTarget(BuildAction.Release, project);
         }
 
         public static void RunlRelease(EnvDTE.Solution solution)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (solution == null)
                 return;
 
@@ -83,6 +72,8 @@
 
         public static void RunlUpdate(VCFile vcFile)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var vcProj = vcFile.project as VCProject;
             var project = vcProj?.Object as EnvDTE.Project;
             RunTranslationTarget(BuildAction.Update,
@@ -91,6 +82,8 @@
 
         public static void RunlUpdate(VCFile[] vcFiles)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var vcProj = vcFiles.FirstOrDefault()?.project as VCProject;
             var project = vcProj?.Object as EnvDTE.Project;
             RunTranslationTarget(BuildAction.Update,
@@ -99,16 +92,19 @@
 
         public static void RunlUpdate(EnvDTE.Project project)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
             RunTranslationTarget(BuildAction.Update, project);
         }
 
-        enum BuildAction { Update, Release }
+        internal enum BuildAction { Update, Release }
 
         static void RunTranslationTarget(
             BuildAction buildAction,
             EnvDTE.Project project,
             IEnumerable<string> selectedFiles = null)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             using (WaitDialog.Start(
                 "Qt Visual Studio Tools", "Running translation tool...")) {
 
@@ -122,10 +118,9 @@
                 if (qtPro.FormatVersion < Resources.qtMinFormatVersion_Settings) {
                     Messages.Print("translation: Legacy project format");
                     try {
-                        Legacy_RunTranslation(buildAction, qtPro, selectedFiles);
-                    } catch (Exception e) {
-                        Messages.Print(
-                            e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
+                        Legacy.Translation.Run(buildAction, qtPro, selectedFiles);
+                    } catch (Exception exception) {
+                        exception.Log();
                     }
                     return;
                 }
@@ -152,12 +147,15 @@
                 if (selectedFiles != null)
                     properties["SelectedFiles"] = string.Join(";", selectedFiles);
 
-                QtProjectBuild.StartBuild(project, activeConfigId, properties, new[] { target });
+                QtProjectBuild.StartBuild(
+                    project, project.FullName, activeConfigId, properties, new[] { target });
             }
         }
 
         public static void RunlUpdate(EnvDTE.Solution solution)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (solution == null)
                 return;
 
@@ -165,118 +163,23 @@
                 RunlUpdate(project);
         }
 
-        static void Legacy_RunTranslation(
-            BuildAction buildAction,
-            QtProject qtProject,
-            IEnumerable<string> tsFiles)
-        {
-            if (tsFiles == null) {
-                tsFiles = (qtProject.VCProject
-                    .GetFilesEndingWith(".ts") as IVCCollection)
-                    .Cast<VCFile>()
-                    .Select(vcFile => vcFile.RelativePath);
-                if (tsFiles == null) {
-                    Messages.Print("translation: no translation files found");
-                    return;
-                }
-            }
-            string tempFile = null;
-            foreach (var file in tsFiles.Where(file => file != null))
-                Legacy_RunTranslation(buildAction, qtProject, file, ref tempFile);
-        }
-
-        static void Legacy_RunTranslation(
-            BuildAction buildAction,
-            QtProject qtProject,
-            string tsFile,
-            ref string tempFile)
-        {
-            var qtVersion = qtProject.GetQtVersion();
-            var qtInstallPath = QtVersionManager.The().GetInstallPath(qtVersion);
-            if (string.IsNullOrEmpty(qtInstallPath)) {
-                Messages.Print("translation: Error accessing Qt installation");
-                return;
-            }
-
-            var procInfo = new ProcessStartInfo
-            {
-                WorkingDirectory = qtProject.ProjectDir,
-                CreateNoWindow = true,
-                UseShellExecute = false,
-                RedirectStandardError = true,
-                RedirectStandardOutput = true,
-                Arguments = ""
-            };
-            switch (buildAction) {
-            case BuildAction.Update:
-                Messages.Print("\r\n--- (lupdate) file: " + tsFile);
-                procInfo.FileName = Path.Combine(qtInstallPath, "bin", "lupdate.exe");
-                var options = QtVSIPSettings.GetLUpdateOptions();
-                if (!string.IsNullOrEmpty(options))
-                    procInfo.Arguments += options + " ";
-                if (tempFile == null) {
-                    var inputFiles = GetProjectFiles(qtProject.Project, FilesToList.FL_HFiles)
-                        .Union(GetProjectFiles(qtProject.Project, FilesToList.FL_CppFiles))
-                        .Union(GetProjectFiles(qtProject.Project, FilesToList.FL_UiFiles))
-                        .Union(GetProjectFiles(qtProject.Project, FilesToList.FL_QmlFiles));
-                    tempFile = Path.GetTempFileName();
-                    File.WriteAllLines(tempFile, inputFiles);
-                }
-                procInfo.Arguments += string.Format("\"@{0}\" -ts \"{1}\"", tempFile, tsFile);
-                break;
-            case BuildAction.Release:
-                Messages.Print("\r\n--- (lrelease) file: " + tsFile);
-                procInfo.FileName = Path.Combine(qtInstallPath, "bin", "lrelease.exe");
-                options = QtVSIPSettings.GetLReleaseOptions();
-                if (!string.IsNullOrEmpty(options))
-                    procInfo.Arguments += options + " ";
-                procInfo.Arguments += string.Format("\"{0}\"", tsFile);
-                break;
-            }
-            using (var proc = Process.Start(procInfo)) {
-                proc.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
-                {
-                    if (!string.IsNullOrEmpty(e.Data))
-                        Messages.Print(e.Data);
-                };
-                proc.ErrorDataReceived += (object sender, DataReceivedEventArgs e) =>
-                {
-                    if (!string.IsNullOrEmpty(e.Data))
-                        Messages.Print(e.Data);
-                };
-                proc.BeginOutputReadLine();
-                proc.BeginErrorReadLine();
-                proc.WaitForExit();
-                switch (proc.ExitCode) {
-                case 0:
-                    Messages.Print("translation: ok");
-                    break;
-                default:
-                    Messages.Print(string.Format("translation: ERROR {0}", proc.ExitCode));
-                    break;
-                }
-            }
-        }
-
-        public static void CreateNewTranslationFile(EnvDTE.Project project)
+        public static bool ToolsAvailable(EnvDTE.Project project)
         {
             if (project == null)
-                return;
+                return false;
+            if (QtProject.GetPropertyValue(project, "ApplicationType") == "Linux")
+                return true;
 
-            using (var transDlg = new AddTranslationDialog(project)) {
-                if (transDlg.ShowDialog() == DialogResult.OK) {
-                    try {
-                        var qtPro = QtProject.Create(project);
-                        var file = qtPro.AddFileInFilter(Filters.TranslationFiles(),
-                            transDlg.TranslationFile, true);
-                        RunlUpdate(file);
-                    } catch (QtVSException e) {
-                        Messages.DisplayErrorMessage(e.Message);
-                    } catch (System.Exception ex) {
-                        Messages.DisplayErrorMessage(ex.Message);
-                    }
-                }
+            var qtToolsPath = QtProject.GetPropertyValue(project, "QtToolsPath");
+            if (string.IsNullOrEmpty(qtToolsPath)) {
+                var qtVersion = QtVersionManager.The().GetProjectQtVersion(project);
+                var qtInstallPath = QtVersionManager.The().GetInstallPath(qtVersion);
+                if (string.IsNullOrEmpty(qtInstallPath))
+                    return false;
+                qtToolsPath = Path.Combine(qtInstallPath, "bin");
             }
+            return File.Exists(Path.Combine(qtToolsPath, "lupdate.exe"))
+                && File.Exists(Path.Combine(qtToolsPath, "lrelease.exe"));
         }
     }
 }
diff --git a/QtVsTools.Package/QML/Classification/QmlAsyncClassifier.cs b/QtVsTools.Package/QML/Classification/QmlAsyncClassifier.cs
index d8698b4..b69d9b6 100644
--- a/QtVsTools.Package/QML/Classification/QmlAsyncClassifier.cs
+++ b/QtVsTools.Package/QML/Classification/QmlAsyncClassifier.cs
@@ -33,7 +33,6 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
-using System.Threading;
 using System.Threading.Tasks;
 using System.Windows.Threading;
 using Microsoft.VisualStudio.Text;
@@ -52,7 +51,7 @@
     /// </summary>
     class SharedTagList : Concurrent
     {
-        SortedList<int, TrackingTag> data = new SortedList<int, TrackingTag>();
+        readonly SortedList<int, TrackingTag> data = new SortedList<int, TrackingTag>();
         object owner;
 
         public bool Ready { get; private set; }
@@ -97,7 +96,7 @@
 
         class TrackingTagComparer : Comparer<TrackingTag>
         {
-            ITextSnapshot snapshot;
+            readonly ITextSnapshot snapshot;
             public TrackingTagComparer(ITextSnapshot snapshot)
             {
                 this.snapshot = snapshot;
@@ -232,17 +231,16 @@
         /// <returns>Instance of T corresponding to the given TrackingTag</returns>
         protected abstract T GetClassification(TrackingTag tag);
 
-        protected ITextView TextView { get; private set; }
-        protected ITextBuffer Buffer { get; private set; }
+        private ITextView TextView { get; }
+        private ITextBuffer Buffer { get; }
 
         readonly object criticalSection = new object();
-
-        string classificationType;
+        readonly string classificationType;
         ParserKey currentParserKey;
         TagListKey currentTagListKey;
         SharedTagList currentTagList;
-        Dispatcher dispatcher;
-        DispatcherTimer timer;
+        readonly Dispatcher dispatcher;
+        readonly DispatcherTimer timer;
         bool flag = false;
 
         protected QmlAsyncClassifier(
@@ -267,7 +265,7 @@
             currentTagList = null;
             this.classificationType = classificationType;
 
-            AsyncParse(buffer.CurrentSnapshot);
+            Parse(buffer.CurrentSnapshot);
         }
 
         private void TextView_Closed(object sender, EventArgs e)
@@ -286,16 +284,16 @@
         private void Buffer_Changed(object sender, TextContentChangedEventArgs e)
         {
             timer.Stop();
-            AsyncParse(e.After);
+            Parse(e.After);
         }
 
         private void Timer_Tick(object sender, EventArgs e)
         {
             timer.Stop();
-            AsyncParse(Buffer.CurrentSnapshot);
+            Parse(Buffer.CurrentSnapshot);
         }
 
-        private async void AsyncParse(ITextSnapshot snapshot)
+        private void Parse(ITextSnapshot snapshot)
         {
             lock (criticalSection) {
                 if (flag)
@@ -311,7 +309,7 @@
             ParserKey oldParserKey = null;
             TagListKey oldTagListKey = null;
 
-            await Task.Run(() =>
+            _ = Task.Run(() =>
             {
                 var parser = ParserStore.Instance.Get(this, newParserKey);
 
@@ -344,7 +342,7 @@
                 flag = false;
             }
 
-            await Task.Run(() =>
+            _ = Task.Run(() =>
             {
                 if (oldParserKey != null)
                     ParserStore.Instance.Release(this, oldParserKey);
@@ -511,7 +509,7 @@
                 public TValue Value { get; set; }
                 public HashSet<object> ClientObjects { get; set; }
             }
-            Dictionary<TKey, ValueRef> data = new Dictionary<TKey, ValueRef>();
+            readonly Dictionary<TKey, ValueRef> data = new Dictionary<TKey, ValueRef>();
 
             static readonly object staticCriticalSection = new object();
             readonly object criticalSection = new object();
@@ -524,8 +522,7 @@
             public TValue Get(object client, TKey key)
             {
                 lock (criticalSection) {
-                    ValueRef valueRef;
-                    if (!data.TryGetValue(key, out valueRef)) {
+                    if (!data.TryGetValue(key, out ValueRef valueRef)) {
                         valueRef = new ValueRef
                         {
                             Value = GetDefaultValue(key),
@@ -543,8 +540,7 @@
             {
                 IDisposable disposable = null;
                 lock (criticalSection) {
-                    ValueRef valueRef;
-                    if (data.TryGetValue(key, out valueRef)) {
+                    if (data.TryGetValue(key, out ValueRef valueRef)) {
                         valueRef.ClientObjects.Remove(client);
                         if (valueRef.ClientObjects.Count == 0) {
                             data.Remove(key);
@@ -573,8 +569,8 @@
 
         class TagListKey
         {
-            public string Classification { get; private set; }
-            public ITextSnapshot Snapshot { get; private set; }
+            private string Classification { get; }
+            private ITextSnapshot Snapshot { get; }
             public TagListKey(string classification, ITextSnapshot snapshot)
             {
                 Classification = classification;
@@ -614,7 +610,7 @@
 
         class ParserKey
         {
-            public ITextSnapshot Snapshot { get; private set; }
+            public ITextSnapshot Snapshot { get; }
             public ParserKey(ITextSnapshot snapshot)
             {
                 Snapshot = snapshot;
diff --git a/QtVsTools.Package/QML/Classification/QmlErrorClassifier.cs b/QtVsTools.Package/QML/Classification/QmlErrorClassifier.cs
index 85c216d..1878c56 100644
--- a/QtVsTools.Package/QML/Classification/QmlErrorClassifier.cs
+++ b/QtVsTools.Package/QML/Classification/QmlErrorClassifier.cs
@@ -28,11 +28,7 @@
 
 /// Highlighting of syntax errors
 
-using System;
-using System.Collections.Generic;
 using System.ComponentModel.Composition;
-using System.Threading.Tasks;
-using System.Windows.Threading;
 using Microsoft.VisualStudio.Text;
 using Microsoft.VisualStudio.Text.Classification;
 using Microsoft.VisualStudio.Text.Editor;
diff --git a/QtVsTools.Package/QML/Classification/QmlExpressionEvalClassifier.cs b/QtVsTools.Package/QML/Classification/QmlExpressionEvalClassifier.cs
index dd0528e..9cb30eb 100644
--- a/QtVsTools.Package/QML/Classification/QmlExpressionEvalClassifier.cs
+++ b/QtVsTools.Package/QML/Classification/QmlExpressionEvalClassifier.cs
@@ -41,11 +41,12 @@
 using Microsoft.VisualStudio.Text.Tagging;
 using Microsoft.VisualStudio.TextManager.Interop;
 using Microsoft.VisualStudio.Utilities;
-using QtVsTools.Qml.Syntax;
-using QtVsTools.VisualStudio;
 
 namespace QtVsTools.Qml.Classification
 {
+    using QtVsTools.VisualStudio;
+    using Syntax;
+
     [Export(typeof(IViewTaggerProvider))]
     [ContentType("qml")]
     [TagType(typeof(ClassificationTag))]
@@ -169,6 +170,8 @@
 
         int IVsTextViewFilter.GetDataTipText(TextSpan[] pSpan, out string pbstrText)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             pbstrText = "";
             var dbgMode = new DBGMODE[1];
             if (debugger.GetMode(dbgMode) != VSConstants.S_OK
@@ -215,6 +218,7 @@
             OLECMD[] prgCmds,
             IntPtr pCmdText)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
             return nextTarget.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
         }
 
@@ -225,12 +229,13 @@
             IntPtr pvaIn,
             IntPtr pvaOut)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
             return nextTarget.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
         }
 
         class ExprTrackingTag : TrackingTag
         {
-            public IOrderedEnumerable<AstNode> Exprs { get; private set; }
+            public IOrderedEnumerable<AstNode> Exprs { get; }
 
             public ExprTrackingTag(
                 ITextSnapshot snapshot,
@@ -245,7 +250,7 @@
 
         class ExprTag : ClassificationTag
         {
-            public IOrderedEnumerable<AstNode> Exprs { get; private set; }
+            public IOrderedEnumerable<AstNode> Exprs { get; }
 
             public ExprTag(IOrderedEnumerable<AstNode> exprs, IClassificationType type)
                 : base(type)
diff --git a/QtVsTools.Package/QML/Classification/QmlSyntaxClassifier.cs b/QtVsTools.Package/QML/Classification/QmlSyntaxClassifier.cs
index 4675637..4035a67 100644
--- a/QtVsTools.Package/QML/Classification/QmlSyntaxClassifier.cs
+++ b/QtVsTools.Package/QML/Classification/QmlSyntaxClassifier.cs
@@ -29,11 +29,7 @@
 /// This file implements the actual highlighting of the text according to the
 /// classification of the syntax elements recognized by the QML parser.
 
-using System;
-using System.Collections.Generic;
 using System.ComponentModel.Composition;
-using System.Threading.Tasks;
-using System.Windows.Threading;
 using Microsoft.VisualStudio.Text;
 using Microsoft.VisualStudio.Text.Classification;
 using Microsoft.VisualStudio.Text.Editor;
diff --git a/QtVsTools.Package/QML/Classification/QmlTag.cs b/QtVsTools.Package/QML/Classification/QmlTag.cs
index 5d92dcd..8cd0ba1 100644
--- a/QtVsTools.Package/QML/Classification/QmlTag.cs
+++ b/QtVsTools.Package/QML/Classification/QmlTag.cs
@@ -47,10 +47,10 @@
     /// </summary>
     public class TrackingTag : ITag
     {
-        public ITextSnapshot Snapshot { get; private set; }
-        public int Start { get; private set; }
-        public int Length { get; private set; }
-        public ITrackingSpan Span { get; private set; }
+        public ITextSnapshot Snapshot { get; }
+        public int Start { get; }
+        private int Length { get; }
+        public ITrackingSpan Span { get; }
         public TrackingTag(ITextSnapshot snapshot, int start, int length)
         {
             Snapshot = snapshot;
@@ -76,9 +76,9 @@
         public const string TypeName = "typename.qml";
         public const string Binding = "binding.qml";
 
-        public SyntaxElement SyntaxElement { get; private set; }
-        public SourceLocation SourceLocation { get; private set; }
-        public IClassificationType ClassificationType { get; private set; }
+        private SyntaxElement SyntaxElement { get; }
+        private SourceLocation SourceLocation { get; }
+        public IClassificationType ClassificationType { get; }
 
         private QmlSyntaxTag(ITextSnapshot snapshot, SourceLocation location)
             : base(snapshot, location.Offset, location.Length)
@@ -118,7 +118,7 @@
             return new QmlSyntaxTag(snapshot, parentNode, classificationType, fullNameLocation);
         }
 
-        public static readonly HashSet<string> QmlBasicTypes = new HashSet<string> {
+        private static readonly HashSet<string> QmlBasicTypes = new HashSet<string> {
             "bool", "double", "enumeration", "int",
             "list", "real", "string", "url", "var",
             "date", "point", "rect", "size", "alias"
@@ -223,7 +223,7 @@
 
     public class QmlDiagnosticsTag : TrackingTag
     {
-        public DiagnosticMessage DiagnosticMessage { get; private set; }
+        private DiagnosticMessage DiagnosticMessage { get; }
         public QmlDiagnosticsTag(ITextSnapshot snapshot, DiagnosticMessage diagnosticMessage)
             : base(snapshot, diagnosticMessage.Location.Offset, diagnosticMessage.Location.Length)
         {
diff --git a/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Breakpoint.cs b/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Breakpoint.cs
index fad795d..13838bc 100644
--- a/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Breakpoint.cs
+++ b/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Breakpoint.cs
@@ -44,12 +44,12 @@
         static readonly string[] ValidExtensions = new string[] { ".qml", ".js" };
 
         public QmlEngine Engine { get; private set; }
-        public IDebugBreakpointRequest2 Request { get; private set; }
-        public enum_BP_LOCATION_TYPE LocationType { get; private set; }
-        public BP_REQUEST_INFO RequestInfo { get; private set; }
+        private IDebugBreakpointRequest2 Request { get; set; }
+        private enum_BP_LOCATION_TYPE LocationType { get; set; }
+        private BP_REQUEST_INFO RequestInfo { get; set; }
         public string FileName { get; private set; }
         public TEXT_POSITION BeginPosition { get; private set; }
-        public TEXT_POSITION EndPosition { get; private set; }
+        private TEXT_POSITION EndPosition { get; set; }
         public bool Enabled { get; private set; }
 
         HashSet<Breakpoint> breakpoints;
@@ -85,8 +85,7 @@
             if (docPosition == null)
                 return false;
 
-            string fileName;
-            if (docPosition.GetFileName(out fileName) != VSConstants.S_OK)
+            if (docPosition.GetFileName(out string fileName) != VSConstants.S_OK)
                 return false;
 
             if (!ValidExtensions.Where(x => string.Equals(x, Path.GetExtension(fileName))).Any())
@@ -186,12 +185,12 @@
         IDebugBreakpointResolution2 // "This interface represents the information that describes a
                                     //  bound breakpoint."
     {
-        public QmlDebugger Debugger { get; private set; }
-        public QmlEngine Engine { get; private set; }
+        private QmlDebugger Debugger { get; set; }
+        private QmlEngine Engine { get; set; }
         public Program Program { get; private set; }
         public PendingBreakpoint Parent { get; private set; }
-        public CodeContext CodeContext { get; private set; }
-        public bool Enabled { get; set; }
+        private CodeContext CodeContext { get; set; }
+        private bool Enabled { get; set; }
 
         bool supressNotify;
 
diff --git a/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Engine.cs b/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Engine.cs
index 8da6eb9..5dc4bdb 100644
--- a/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Engine.cs
+++ b/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Engine.cs
@@ -78,13 +78,13 @@
             FileSystem = FileSystem.Create();
         }
 
-        Dictionary<Guid, Program> programs = new Dictionary<Guid, Program>();
+        readonly Dictionary<Guid, Program> programs = new Dictionary<Guid, Program>();
         public IEnumerable<Program> Programs
         {
             get { return ThreadSafe(() => programs.Values.ToList()); }
         }
 
-        HashSet<PendingBreakpoint> pendingBreakpoints = new HashSet<PendingBreakpoint>();
+        readonly HashSet<PendingBreakpoint> pendingBreakpoints = new HashSet<PendingBreakpoint>();
         public IEnumerable<PendingBreakpoint> PendingBreakpoints
         {
             get { return ThreadSafe(() => pendingBreakpoints.ToList()); }
@@ -106,8 +106,7 @@
             if (string.IsNullOrEmpty(pszOptions))
                 return VSConstants.E_FAIL;
 
-            uint procId;
-            if (!uint.TryParse(pszOptions, out procId))
+            if (!uint.TryParse(pszOptions, out uint procId))
                 return VSConstants.E_FAIL;
 
             var env = bstrEnv.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
@@ -120,13 +119,12 @@
                     FileSystem.RegisterRccFile(rccFile);
             }
 
-            IDebugProcess2 nativeProc;
             var nativeProcId = new AD_PROCESS_ID
             {
                 ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM,
                 dwProcessId = procId
             };
-            if (pPort.GetProcess(nativeProcId, out nativeProc) != VSConstants.S_OK)
+            if (pPort.GetProcess(nativeProcId, out IDebugProcess2 nativeProc) != VSConstants.S_OK)
                 return VSConstants.E_FAIL;
 
             var program = Program.Create(this, nativeProc, pszExe, pszArgs);
@@ -144,20 +142,11 @@
             if (program == null)
                 return VSConstants.E_FAIL;
 
-            IDebugPort2 port;
-            if (process.GetPort(out port) != VSConstants.S_OK)
+            if (process.GetPort(out IDebugPort2 port) != VSConstants.S_OK)
                 return VSConstants.E_FAIL;
 
-            string portName;
-            port.GetPortName(out portName);
-
-            Guid guidPort;
-            port.GetPortId(out guidPort);
-
             IDebugDefaultPort2 defaultPort = (IDebugDefaultPort2)port;
-
-            IDebugPortNotify2 portNotify;
-            if (defaultPort.GetPortNotify(out portNotify) != VSConstants.S_OK)
+            if (defaultPort.GetPortNotify(out IDebugPortNotify2 portNotify) != VSConstants.S_OK)
                 return VSConstants.E_FAIL;
 
             if (portNotify.AddProgramNode(program) != VSConstants.S_OK)
@@ -181,8 +170,7 @@
 
             DebugEvent.Send(new EngineCreateEvent(this));
 
-            Guid pguidProgramId;
-            if (rgpPrograms[0].GetProgramId(out pguidProgramId) != VSConstants.S_OK)
+            if (rgpPrograms[0].GetProgramId(out Guid pguidProgramId) != VSConstants.S_OK)
                 return VSConstants.E_FAIL;
 
             program.ProgramId = pguidProgramId;
@@ -199,15 +187,10 @@
 
         int IDebugEngineLaunch2.CanTerminateProcess(IDebugProcess2 pProcess)
         {
-            Guid procId;
-            if (pProcess.GetProcessId(out procId) != VSConstants.S_OK)
+            if (pProcess.GetProcessId(out Guid procId) != VSConstants.S_OK)
                 return VSConstants.E_FAIL;
 
-            Program program;
-            if (!programs.TryGetValue(procId, out program))
-                return VSConstants.S_FALSE;
-
-            return VSConstants.S_OK;
+            return programs.TryGetValue(procId, out _) ? VSConstants.S_OK : VSConstants.S_FALSE;
         }
 
         public bool ProgramIsRunning(Program program)
@@ -217,12 +200,10 @@
 
         int IDebugEngineLaunch2.TerminateProcess(IDebugProcess2 pProcess)
         {
-            Guid procId;
-            if (pProcess.GetProcessId(out procId) != VSConstants.S_OK)
+            if (pProcess.GetProcessId(out Guid procId) != VSConstants.S_OK)
                 return VSConstants.E_FAIL;
 
-            Program program;
-            if (!programs.TryGetValue(procId, out program))
+            if (!programs.TryGetValue(procId, out Program program))
                 return VSConstants.S_FALSE;
 
             programs.Remove(procId);
@@ -235,8 +216,7 @@
 
         int IDebugEngine2.ContinueFromSynchronousEvent(IDebugEvent2 pEvent)
         {
-            var evtProgramDestroy = pEvent as ProgramDestroyEvent;
-            if (evtProgramDestroy != null)
+            if (pEvent is ProgramDestroyEvent evtProgramDestroy)
                 evtProgramDestroy.Program.Dispose();
 
             return VSConstants.S_OK;
@@ -271,7 +251,7 @@
 
         #region //////////////////// Concurrent ///////////////////////////////////////////////////
 
-        LocalConcurrent concurrent = new LocalConcurrent();
+        readonly LocalConcurrent concurrent = new LocalConcurrent();
         class LocalConcurrent : Concurrent
         {
             public void LocalThreadSafe(Action action)
diff --git a/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Events.cs b/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Events.cs
index 9c75bc5..6ea40cf 100644
--- a/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Events.cs
+++ b/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Events.cs
@@ -38,8 +38,8 @@
                      //  such as stopping at a breakpoint, and non-critical information, such as a
                      //  debugging message."
     {
-        public Guid InterfaceId { get; protected set; }
-        public uint Attributes { get; protected set; }
+        private Guid InterfaceId { get; }
+        private uint Attributes { get; }
 
         protected const uint ASYNCHRONOUS = (uint)enum_EVENTATTRIBUTES.EVENT_ASYNCHRONOUS;
         protected const uint STOPPING = (uint)enum_EVENTATTRIBUTES.EVENT_ASYNC_STOP;
@@ -48,10 +48,10 @@
               (uint)enum_EVENTATTRIBUTES.EVENT_STOPPING
             | (uint)enum_EVENTATTRIBUTES.EVENT_SYNCHRONOUS;
 
-        protected QmlEngine Engine { get; set; }
-        protected IDebugProgram2 Program { get; set; }
-        protected IDebugThread2 Thread { get; set; }
-        protected IDebugEventCallback2 Callback { get; set; }
+        protected QmlEngine Engine { get; }
+        private IDebugProgram2 Program { get; }
+        private IDebugThread2 Thread { get; }
+        private IDebugEventCallback2 Callback { get; }
 
         protected DebugEvent(
             QmlEngine engine,
@@ -114,8 +114,8 @@
 
     class ProgramDestroyEvent : DebugEvent, IDebugProgramDestroyEvent2
     {
-        uint exitCode;
-        public new Program Program { get; private set; }
+        readonly uint exitCode;
+        public Program Program { get; }
 
         public ProgramDestroyEvent(Program program, uint exitCode)
         : base(program.Engine, typeof(IDebugProgramDestroyEvent2).GUID,
@@ -142,7 +142,7 @@
 
     class ThreadDestroyEvent : DebugEvent, IDebugThreadDestroyEvent2
     {
-        uint exitCode;
+        readonly uint exitCode;
 
         public ThreadDestroyEvent(Program program, uint exitCode)
         : base(program.Engine, typeof(IDebugThreadDestroyEvent2).GUID,
@@ -176,7 +176,7 @@
 
     class BreakpointBoundEvent : DebugEvent, IDebugBreakpointBoundEvent2
     {
-        public Breakpoint Breakpoint { get; private set; }
+        private Breakpoint Breakpoint { get; }
         public BreakpointBoundEvent(Breakpoint breakpoint)
         : base(breakpoint.Program.Engine, typeof(IDebugBreakpointBoundEvent2).GUID,
               ASYNCHRONOUS, breakpoint.Program, breakpoint.Program)
@@ -201,7 +201,7 @@
 
     class BreakpointEvent : DebugEvent, IDebugBreakpointEvent2
     {
-        IEnumDebugBoundBreakpoints2 boundBreakpoints;
+        readonly IEnumDebugBoundBreakpoints2 boundBreakpoints;
 
         public BreakpointEvent(Program program,
             IEnumDebugBoundBreakpoints2 boundBreakpoints)
@@ -228,8 +228,8 @@
 
     class ExpressionEvaluationCompleteEvent : DebugEvent, IDebugExpressionEvaluationCompleteEvent2
     {
-        public Expression Expression { get; private set; }
-        public Property Property { get; private set; }
+        private Expression Expression { get; }
+        private Property Property { get; }
 
         public ExpressionEvaluationCompleteEvent(
             IDebugEventCallback2 callback,
@@ -257,7 +257,7 @@
 
     class OutputStringEvent : DebugEvent, IDebugOutputStringEvent2
     {
-        string outputString;
+        readonly string outputString;
 
         public OutputStringEvent(QmlEngine engine, string outputString)
         : base(engine, typeof(IDebugOutputStringEvent2).GUID, ASYNCHRONOUS)
diff --git a/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Expression.cs b/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Expression.cs
index 57f2e8b..f705c84 100644
--- a/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Expression.cs
+++ b/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Expression.cs
@@ -26,7 +26,6 @@
 **
 ****************************************************************************/
 
-using System;
 using System.Threading.Tasks;
 using Microsoft.VisualStudio;
 using Microsoft.VisualStudio.Debugger.Interop;
@@ -40,13 +39,13 @@
         IDebugExpression2 // "This interface represents a parsed expression ready for binding
                           //  and evaluating."
     {
-        public string ExpressionString { get; private set; }
+        private string ExpressionString { get; set; }
 
-        public StackFrame StackFrame { get; private set; }
+        private StackFrame StackFrame { get; set; }
         public QmlEngine Engine { get; private set; }
         public Program Program { get; private set; }
-        public QmlDebugger Debugger { get; private set; }
-        public CodeContext CodeContext { get; private set; }
+        private QmlDebugger Debugger { get; set; }
+        private CodeContext CodeContext { get; set; }
 
         public static Expression Create(StackFrame frame, string expr)
         {
@@ -86,7 +85,7 @@
             enum_EVALFLAGS dwFlags,
             IDebugEventCallback2 pExprCallback)
         {
-            Task.Run(() =>
+            _ = Task.Run(() =>
             {
                 var value = Debugger.Evaluate(StackFrame.FrameNumber, ExpressionString);
                 if (value != null)
diff --git a/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7InfoHelpers.cs b/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7InfoHelpers.cs
index 312aa39..dfd2af2 100644
--- a/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7InfoHelpers.cs
+++ b/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7InfoHelpers.cs
@@ -26,12 +26,9 @@
 **
 ****************************************************************************/
 
-using Microsoft.VisualStudio.Debugger.Interop;
 using System;
 using System.Collections;
 using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
 
 namespace QtVsTools.Qml.Debug.AD7
 {
@@ -76,9 +73,9 @@
         public class Mapping<TStruct, TFieldMask> : Mapping,
             IEnumerable<MapField<TStruct, TFieldMask>>
         {
-            List<MapField<TStruct, TFieldMask>> fieldMaps;
+            readonly List<MapField<TStruct, TFieldMask>> fieldMaps;
 
-            protected static Action<Ref<TStruct>, TFieldMask> UpdateMask { get; set; }
+            private static Action<Ref<TStruct>, TFieldMask> UpdateMask { get; set; }
 
             public Mapping(Action<Ref<TStruct>, TFieldMask> updateMask)
             {
@@ -188,8 +185,7 @@
             TFieldMask fieldMask,
             out TStruct infoStruct)
         {
-            var mappingToStruct = mapping as Mapping<TStruct, TFieldMask>;
-            if (mappingToStruct != null)
+            if (mapping is Mapping<TStruct, TFieldMask> mappingToStruct)
                 mappingToStruct.Map(this as TDerived, fieldMask, out infoStruct);
             else
                 infoStruct = default(TStruct);
diff --git a/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Program.cs b/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Program.cs
index 6a7cee4..0111f31 100644
--- a/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Program.cs
+++ b/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Program.cs
@@ -29,18 +29,16 @@
 using System;
 using System.Collections.Generic;
 using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
 using System.Windows.Threading;
 using Microsoft.VisualStudio;
 using Microsoft.VisualStudio.Debugger.Interop;
 using Microsoft.VisualStudio.Shell;
 using Microsoft.VisualStudio.Shell.Interop;
-using QtVsTools.VisualStudio;
 
 namespace QtVsTools.Qml.Debug.AD7
 {
+    using VisualStudio;
+
     sealed partial class Program : Disposable, IDebuggerEventSink,
 
         IDebugProgramNode2,  // "This interface represents a program that can be debugged."
@@ -64,21 +62,21 @@
 
         public QmlEngine Engine { get; private set; }
 
-        public List<StackFrame> CurrentFrames { get; private set; }
+        private List<StackFrame> CurrentFrames { get; set; }
 
-        public const string Name = "QML Debugger";
-        public Guid ProcessId { get; private set; }
+        private const string Name = "QML Debugger";
+        public Guid ProcessId { get; set; }
         public Guid ProgramId { get; set; }
-        public IDebugProcess2 NativeProc { get; private set; }
-        public uint NativeProcId { get; private set; }
-        public string ExecPath { get; private set; }
-        public string ExecArgs { get; private set; }
-        public IVsDebugger VsDebugger { get; private set; }
-        Dispatcher vsDebuggerThreadDispatcher;
+        private IDebugProcess2 NativeProc { get; set; }
+        private uint NativeProcId { get; set; }
+        private string ExecPath { get; set; }
+        private string ExecArgs { get; set; }
+        private IVsDebugger VsDebugger { get; set; }
+        private Dispatcher vsDebuggerThreadDispatcher;
 
-        private readonly static object criticalSectionGlobal = new object();
-        static bool originalBreakAllProcesses = BreakAllProcesses;
-        static int runningPrograms = 0;
+        private static readonly object criticalSectionGlobal = new object();
+        private static bool originalBreakAllProcesses = BreakAllProcesses;
+        private static int runningPrograms = 0;
 
         public static Program Create(
             QmlEngine engine,
@@ -114,8 +112,13 @@
                 return false;
 
             VsDebugger = VsServiceProvider.GetService<IVsDebugger>();
-            if (VsDebugger != null)
-                VsDebugger.AdviseDebugEventCallback(this as IDebugEventCallback2);
+            if (VsDebugger != null) {
+                ThreadHelper.JoinableTaskFactory.Run(async () =>
+                {
+                    await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+                    VsDebugger.AdviseDebugEventCallback(this);
+                });
+            }
             vsDebuggerThreadDispatcher = Dispatcher.CurrentDispatcher;
 
             ProcessId = Guid.NewGuid();
@@ -141,8 +144,13 @@
         protected override void DisposeManaged()
         {
             Debugger.Dispose();
-            if (VsDebugger != null)
-                VsDebugger.UnadviseDebugEventCallback(this as IDebugEventCallback2);
+            if (VsDebugger != null) {
+                ThreadHelper.JoinableTaskFactory.Run(async () =>
+                {
+                    await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+                    VsDebugger.UnadviseDebugEventCallback(this as IDebugEventCallback2);
+                });
+            }
 
             lock (criticalSectionGlobal) {
                 runningPrograms--;
@@ -161,9 +169,12 @@
         {
             var debugMode = new DBGMODE[1];
             int res = VSConstants.S_FALSE;
-            vsDebuggerThreadDispatcher
-                .BeginInvoke(new Action(() => res = VsDebugger.GetMode(debugMode)), new object[0])
-                .Wait();
+
+            QtVsToolsPackage.Instance.JoinableTaskFactory.Run(async () =>
+            {
+                await QtVsToolsPackage.Instance.JoinableTaskFactory.SwitchToMainThreadAsync();
+                res = VsDebugger.GetMode(debugMode);
+            });
 
             if (res != VSConstants.S_OK)
                 return false;
@@ -295,17 +306,24 @@
         {
             get
             {
-                return ((bool)QtVsToolsPackage.Instance.Dte
-                    .Properties["Debugging", "General"]
-                    .Item("BreakAllProcesses")
-                    .Value);
+                return ThreadHelper.JoinableTaskFactory.Run(async () => {
+                    await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+                    return ((bool)QtVsToolsPackage.Instance.Dte
+                        .Properties["Debugging", "General"]
+                        .Item("BreakAllProcesses")
+                        .Value);
+                });
             }
             set
             {
-                QtVsToolsPackage.Instance.Dte
-                    .Properties["Debugging", "General"]
-                    .Item("BreakAllProcesses")
-                    .let_Value(value ? "True" : "False");
+                ThreadHelper.JoinableTaskFactory.Run(async () =>
+                {
+                    await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+                    QtVsToolsPackage.Instance.Dte
+                        .Properties["Debugging", "General"]
+                        .Item("BreakAllProcesses")
+                        .let_Value(value ? "True" : "False");
+                });
             }
         }
 
diff --git a/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Property.cs b/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Property.cs
index c1e7c1f..eba56a8 100644
--- a/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Property.cs
+++ b/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7Property.cs
@@ -29,7 +29,6 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
-using System.Text;
 using Microsoft.VisualStudio;
 using Microsoft.VisualStudio.Debugger.Interop;
 
@@ -43,23 +42,23 @@
                         //  property, or some other property. The property is usually the result of
                         //  an expression evaluation."
     {
-        public QmlDebugger Debugger { get; private set; }
+        private QmlDebugger Debugger { get; set; }
 
-        public QmlEngine Engine { get; private set; }
-        public Program Program { get; private set; }
-        public StackFrame StackFrame { get; private set; }
-        public CodeContext CodeContext { get; private set; }
+        private QmlEngine Engine { get; set; }
+        private Program Program { get; set; }
+        private StackFrame StackFrame { get; set; }
+        private CodeContext CodeContext { get; set; }
 
-        public Property Parent { get; private set; }
-        public SortedDictionary<string, Property> Children { get; private set; }
+        private Property Parent { get; set; }
+        private SortedDictionary<string, Property> Children { get; set; }
 
-        public int FrameNumber { get; private set; }
-        public int ScopeNumber { get; private set; }
-        public JsValue JsValue { get; private set; }
-        public string Name { get; private set; }
-        public string FullName { get; private set; }
-        public string Type { get; private set; }
-        public string Value { get; private set; }
+        private int FrameNumber { get; set; }
+        private int ScopeNumber { get; set; }
+        private JsValue JsValue { get; set; }
+        private string Name { get; set; }
+        private string FullName { get; set; }
+        private string Type { get; set; }
+        private string Value { get; set; }
 
         public static Property Create(
             StackFrame frame,
@@ -120,11 +119,9 @@
 
         static string GetChildKey(string childName)
         {
-            int childIndex;
-            if (int.TryParse(childName, out childIndex))
+            if (int.TryParse(childName, out int childIndex))
                 return string.Format("{0:D9}", childIndex);
-            else
-                return childName;
+            return childName;
         }
 
         int IDebugProperty2.SetValueAsString(string pszValue, uint dwRadix, uint dwTimeout)
@@ -242,8 +239,7 @@
 
         public DEBUG_PROPERTY_INFO GetInfo(enum_DEBUGPROP_INFO_FLAGS dwFields)
         {
-            DEBUG_PROPERTY_INFO info;
-            Info.Map(MappingToDEBUG_PROPERTY_INFO, dwFields, out info);
+            Info.Map(MappingToDEBUG_PROPERTY_INFO, dwFields, out DEBUG_PROPERTY_INFO info);
             return info;
         }
 
@@ -275,19 +271,19 @@
             public static readonly Guid Registers
                 = new Guid("223ae797-bd09-4f28-8241-2763bdc5f713");
 
-            public static readonly Guid Locals
+            private static readonly Guid Locals
                 = new Guid("b200f725-e725-4c53-b36a-1ec27aef12ef");
 
-            public static readonly Guid AllLocals
+            private static readonly Guid AllLocals
                 = new Guid("196db21f-5f22-45a9-b5a3-32cddb30db06");
 
             public static readonly Guid Args
                 = new Guid("804bccea-0475-4ae7-8a46-1862688ab863");
 
-            public static readonly Guid LocalsPlusArgs
+            private static readonly Guid LocalsPlusArgs
                 = new Guid("e74721bb-10c0-40f5-807f-920d37f95419");
 
-            public static readonly Guid AllLocalsPlusArgs
+            private static readonly Guid AllLocalsPlusArgs
                 = new Guid("939729a8-4cb0-4647-9831-7ff465240d5f");
 
             public static bool LocalsSelected(ref Guid guidFilter)
diff --git a/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7StackFrame.cs b/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7StackFrame.cs
index 8578f60..cc80a67 100644
--- a/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7StackFrame.cs
+++ b/QtVsTools.Package/QML/Debugging/AD7/QmlDebugAD7StackFrame.cs
@@ -32,6 +32,7 @@
 using System.Threading.Tasks;
 using Microsoft.VisualStudio;
 using Microsoft.VisualStudio.Debugger.Interop;
+using Microsoft.VisualStudio.Threading;
 
 namespace QtVsTools.Qml.Debug.AD7
 {
@@ -52,14 +53,14 @@
         public Program Program { get; private set; }
 
         public CodeContext Context { get; private set; }
-        public Dictionary<int, Dictionary<string, Property>> Properties { get; private set; }
+        private Dictionary<int, Dictionary<string, Property>> Properties { get; set; }
 
-        public string Name { get; private set; }
-        public int FrameNumber { get; private set; }
-        public IEnumerable<int> Scopes { get; private set; }
-        public Task InitThread { get; private set; }
+        private string Name { get; set; }
+        public int FrameNumber { get; set; }
+        private IEnumerable<int> Scopes { get; set; }
+        private JoinableTask InitThread { get; set; }
 
-        static public StackFrame Create(
+        public static StackFrame Create(
             string name,
             int number,
             IEnumerable<int> scopes,
@@ -85,7 +86,11 @@
             Name = string.Format("{0}@{1}:{2}", name, context.FilePath, context.FileLine + 1);
             FrameNumber = number;
             Scopes = scopes;
-            InitThread = Task.Run(() => InitializeProperties());
+            InitThread = QtVsToolsPackage.Instance.JoinableTaskFactory.RunAsync(async () =>
+            {
+                InitializeProperties();
+                await Task.Yield();
+            });
             return true;
         }
 
@@ -134,7 +139,7 @@
             if (guidFilter != Guid.Empty && !Property.Filter.LocalsSelected(ref guidFilter))
                 return VSConstants.S_OK;
 
-            InitThread.Wait();
+            InitThread.Join();
             pcelt = 0;
             ppEnum = PropertyEnum.Create(Properties
                 .SelectMany(x => x.Value
@@ -152,9 +157,8 @@
             uint dwTimeout,
             out IEnumDebugPropertyInfo2 ppEnum)
         {
-            uint pcelt;
             return ((IDebugStackFrame2)this)
-                .EnumProperties(dwFields, dwRadix, guidFilter, dwTimeout, out pcelt, out ppEnum);
+                .EnumProperties(dwFields, dwRadix, guidFilter, dwTimeout, out _, out ppEnum);
         }
 
         #region //////////////////// Info /////////////////////////////////////////////////////////
diff --git a/QtVsTools.Package/QML/Debugging/QmlDebugLauncher.cs b/QtVsTools.Package/QML/Debugging/QmlDebugLauncher.cs
index 025ee42..02fd242 100644
--- a/QtVsTools.Package/QML/Debugging/QmlDebugLauncher.cs
+++ b/QtVsTools.Package/QML/Debugging/QmlDebugLauncher.cs
@@ -35,39 +35,50 @@
 using Microsoft.VisualStudio.Shell;
 using Microsoft.VisualStudio.Shell.Interop;
 using Microsoft.VisualStudio.VCProjectEngine;
-using QtVsTools.Core;
-using QtVsTools.Core.QtMsBuild;
-using QtVsTools.SyntaxAnalysis;
-using static QtVsTools.SyntaxAnalysis.RegExpr;
 
 namespace QtVsTools.Qml.Debug
 {
     using AD7;
+    using Common;
+    using Core;
+    using Core.QtMsBuild;
+    using SyntaxAnalysis;
     using VisualStudio;
+
+    using static SyntaxAnalysis.RegExpr;
 
     class Launcher : Disposable, IDebugEventCallback2
     {
-        public static Launcher Instance { get; private set; }
+        LazyFactory Lazy { get; } = new LazyFactory();
+
+        private static Launcher Instance { get; set; }
         IVsDebugger debugger;
         IVsDebugger4 debugger4;
 
-        HashSet<Guid> _ExcludedProcesses;
-        HashSet<Guid> ExcludedProcesses => _ExcludedProcesses
-            ?? (_ExcludedProcesses = new HashSet<Guid>());
+        HashSet<Guid> ExcludedProcesses => Lazy.Get(() =>
+            ExcludedProcesses, () => new HashSet<Guid>());
 
         public static void Initialize()
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             Instance = new Launcher();
             Instance.debugger = VsServiceProvider.GetService<IVsDebugger>();
             Instance.debugger4 = VsServiceProvider.GetService<IVsDebugger, IVsDebugger4>();
+
             if (Instance.debugger != null && Instance.debugger4 != null)
                 Instance.debugger.AdviseDebugEventCallback(Instance);
         }
 
         protected override void DisposeManaged()
         {
-            if (debugger != null)
-                debugger.UnadviseDebugEventCallback(this);
+            if (debugger != null) {
+                ThreadHelper.JoinableTaskFactory.Run(async () =>
+                {
+                    await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+                    debugger.UnadviseDebugEventCallback(this);
+                });
+            }
         }
 
         int IDebugEventCallback2.Event(
@@ -79,6 +90,8 @@
             ref Guid riidEvent,
             uint dwAttrib)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             if (!QtVsToolsPackage.Instance.Options.QmlDebuggerEnabled)
                 return VSConstants.S_OK;
 
@@ -90,8 +103,7 @@
             if (pProcess == null && pProgram.GetProcess(out pProcess) != VSConstants.S_OK)
                 return VSConstants.S_OK;
 
-            Guid procGuid;
-            if (pProcess.GetProcessId(out procGuid) != VSConstants.S_OK)
+            if (pProcess.GetProcessId(out Guid procGuid) != VSConstants.S_OK)
                 return VSConstants.S_OK;
 
             // Run only once per process
@@ -119,14 +131,10 @@
             else
                 return VSConstants.S_OK;
 
-            string execPath;
-            uint procId;
-            if (!GetProcessInfo(pProcess, native, out execPath, out procId))
+            if (!GetProcessInfo(pProcess, native, out string execPath, out uint procId))
                 return VSConstants.S_OK;
 
-            string execCmd;
-            IEnumerable<string> rccItems;
-            if (!GetProjectInfo(execPath, native, out execCmd, out rccItems))
+            if (!GetProjectInfo(execPath, native, out string execCmd, out IEnumerable<string> rccItems))
                 return VSConstants.S_OK;
 
             LaunchDebug(execPath, execCmd, procId, rccItems);
@@ -135,9 +143,7 @@
 
         Guid GetEngineId(IDebugProgram2 pProgram)
         {
-            string engineName;
-            Guid engineGuid;
-            if (pProgram.GetEngineInfo(out engineName, out engineGuid) != VSConstants.S_OK)
+            if (pProgram.GetEngineInfo(out _, out Guid engineGuid) != VSConstants.S_OK)
                 return Guid.Empty;
             return engineGuid;
         }
@@ -152,7 +158,7 @@
             }
         }
 
-        static RegExpr wslPathRegex = new Token("WSLPATH", SkipWs_Disable, StartOfFile
+        static readonly RegExpr wslPathRegex = new Token("WSLPATH", SkipWs_Disable, StartOfFile
             & "/mnt/" & new Token("DRIVE", CharWord) & "/" & new Token("PATH", AnyChar.Repeat()))
         {
             new Rule<WslPath>
@@ -161,15 +167,14 @@
                 Update("PATH", (WslPath wslPath, string path) => wslPath.Path = path),
             }
         };
-        static RegExpr.Parser wslPathParser = wslPathRegex.Render();
+        static readonly RegExpr.Parser wslPathParser = wslPathRegex.Render();
 
         bool GetProcessInfo(IDebugProcess2 pProcess, bool native, out string execPath, out uint procId)
         {
             execPath = "";
             procId = 0;
 
-            string fileName;
-            if (pProcess.GetName(enum_GETNAME_TYPE.GN_FILENAME, out fileName) != VSConstants.S_OK)
+            if (pProcess.GetName(enum_GETNAME_TYPE.GN_FILENAME, out string fileName) != VSConstants.S_OK)
                 return false;
 
             var pProcessId = new AD_PROCESS_ID[1];
@@ -193,6 +198,8 @@
 
         bool GetProjectInfo(string execPath, bool native, out string execCmd, out IEnumerable<string> rccItems)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             execCmd = "";
             rccItems = null;
 
@@ -290,6 +297,8 @@
             uint procId,
             IEnumerable<string> rccItems)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             var targets = new[] { new VsDebugTargetInfo4
             {
                 dlo = (uint)DEBUG_LAUNCH_OPERATION.DLO_CreateProcess,
@@ -305,8 +314,8 @@
             try {
                 debugger4.LaunchDebugTargets4((uint)targets.Length, targets, processInfo);
 
-            } catch (System.Exception e) {
-                OutputWriteLine(e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
+            } catch (Exception exception) {
+                exception.Log();
             }
         }
     }
diff --git a/QtVsTools.Package/QML/Debugging/QmlDebugger.cs b/QtVsTools.Package/QML/Debugging/QmlDebugger.cs
index 892a17d..b877956 100644
--- a/QtVsTools.Package/QML/Debugging/QmlDebugger.cs
+++ b/QtVsTools.Package/QML/Debugging/QmlDebugger.cs
@@ -26,18 +26,19 @@
 **
 ****************************************************************************/
 
-using System;
 using System.Collections.Generic;
-using System.IO;
 using System.Linq;
 using System.Threading.Tasks;
-using QtVsTools.SyntaxAnalysis;
-using static QtVsTools.SyntaxAnalysis.RegExpr;
-using RegExprParser = QtVsTools.SyntaxAnalysis.RegExpr.Parser;
 
 namespace QtVsTools.Qml.Debug
 {
+    using Common;
+    using SyntaxAnalysis;
     using V4;
+
+    using RegExprParser = SyntaxAnalysis.RegExpr.Parser;
+
+    using static SyntaxAnalysis.RegExpr;
 
     struct FrameInfo
     {
@@ -69,6 +70,8 @@
 
     class QmlDebugger : Disposable, IMessageEventSink
     {
+        static LazyFactory StaticLazy { get; } = new LazyFactory();
+
         IDebuggerEventSink sink;
         ProtocolDriver driver;
         string connectionHostName;
@@ -80,11 +83,11 @@
         List<Request> outbox;
         Dictionary<int, IBreakpoint> breakpoints;
 
-        public bool Started { get; private set; }
+        private bool Started { get; set; }
 
-        public bool Running { get; private set; }
+        private bool Running { get; set; }
 
-        public string Version { get; private set; }
+        private string Version { get; set; }
 
         public uint? ThreadId { get { return driver.ThreadId; } }
 
@@ -160,7 +163,7 @@
             if (!Started) {
                 Running = Started = true;
                 LeaveCriticalSection();
-                Task.Run(() => ConnectToDebugger());
+                _ = Task.Run(() => ConnectToDebugger());
 
             } else if (!Running) {
                 Running = true;
@@ -201,7 +204,7 @@
             setBreakpoint.Arguments.Line = (int)breakpoint.Line;
             setBreakpoint.Tag = breakpoint;
             if (driver.ConnectionState == DebugClientState.Connected)
-                setBreakpoint.SendAsync();
+                setBreakpoint.SendRequest();
             else
                 ThreadSafe(() => outbox.Add(setBreakpoint));
         }
@@ -231,7 +234,7 @@
 
             var reqClearBreak = Message.Create<ClearBreakpointRequest>(driver);
             reqClearBreak.Arguments.Breakpoint = breakpointNum[breakpoint];
-            reqClearBreak.SendAsync();
+            reqClearBreak.SendRequest();
         }
 
         void RefreshFrames()
@@ -286,8 +289,7 @@
 
             } else {
                 foreach (int breakpointId in evtBreak.Body.Breakpoints) {
-                    IBreakpoint breakpoint;
-                    if (!breakpoints.TryGetValue(breakpointId, out breakpoint))
+                    if (!breakpoints.TryGetValue(breakpointId, out IBreakpoint breakpoint))
                         continue;
                     breakpoint.NotifyBreak();
                 }
@@ -406,20 +408,20 @@
         {
             if (oldState != DebugClientState.Unavailable
                 && newState == DebugClientState.Disconnected) {
-                Task.Run(() => sink.NotifyClientDisconnected());
+                _ = Task.Run(() => sink.NotifyClientDisconnected());
             }
         }
 
         void IMessageEventSink.NotifyRequestResponded(Request msgRequest)
         {
             if (msgRequest is SetBreakpointRequest)
-                Task.Run(() => SetBreakpointResponded(msgRequest as SetBreakpointRequest));
+                _ = Task.Run(() => SetBreakpointResponded(msgRequest as SetBreakpointRequest));
         }
 
         void IMessageEventSink.NotifyEvent(Event msgEvent)
         {
             if (msgEvent is BreakEvent)
-                Task.Run(() => BreakNotified(msgEvent as BreakEvent));
+                _ = Task.Run(() => BreakNotified(msgEvent as BreakEvent));
         }
 
         void IMessageEventSink.NotifyMessage(Message msg)
@@ -430,13 +432,7 @@
 
         public static bool CheckCommandLine(string execPath, string args)
         {
-            ushort portFrom;
-            ushort portTo;
-            string hostName;
-            string fileName;
-            bool block;
-            return ParseCommandLine(
-                execPath, args, out portFrom, out portTo, out hostName, out fileName, out block);
+            return ParseCommandLine(execPath, args, out _, out _, out _, out _, out _);
         }
 
         /// <summary>
@@ -456,8 +452,8 @@
         /// <summary>
         /// Regex-based parser for QML debug connection parameters
         /// </summary>
-        static RegExprParser ConnectParamsParser => _ConnectParamsParser ?? (
-            _ConnectParamsParser = new Token(TokenId.ConnectParams, RxConnectParams)
+        static RegExprParser ConnectParamsParser => StaticLazy.Get(() =>
+            ConnectParamsParser, () => new Token(TokenId.ConnectParams, RxConnectParams)
             {
                 new Rule<ConnectParams>
                 {
@@ -469,7 +465,6 @@
                 }
             }
             .Render());
-        static RegExprParser _ConnectParamsParser;
 
         /// <summary>
         /// Regular expression for parsing connection parameters string in the form:
diff --git a/QtVsTools.Package/QML/Debugging/QmlFileSystem.cs b/QtVsTools.Package/QML/Debugging/QmlFileSystem.cs
index 4b33faf..20af63b 100644
--- a/QtVsTools.Package/QML/Debugging/QmlFileSystem.cs
+++ b/QtVsTools.Package/QML/Debugging/QmlFileSystem.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -36,6 +36,8 @@
 
 namespace QtVsTools.Qml.Debug
 {
+    using QtVsTools.Core;
+
     struct QmlFile
     {
         public string QrcPath;
@@ -92,9 +94,8 @@
                 using (var reader = XmlReader.Create(new StringReader(xmlText), settings)) {
                     rccXml = XDocument.Load(reader);
                 }
-            } catch (Exception e) {
-                System.Diagnostics.Debug.WriteLine(
-                    e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
+            } catch (Exception exception) {
+                exception.Log();
                 return;
             }
 
@@ -156,8 +157,7 @@
 
             qrcPath = string.Format("qrc:///{0}", qrcPath);
 
-            QmlFile file;
-            if (!files.TryGetValue(qrcPath, out file))
+            if (!files.TryGetValue(qrcPath, out QmlFile file))
                 return default(QmlFile);
 
             return file;
@@ -190,8 +190,7 @@
                 return default(QmlFile);
             }
 
-            QmlFile file;
-            if (files.TryGetValue(fullPath, out file))
+            if (files.TryGetValue(fullPath, out QmlFile file))
                 return file;
 
             return new QmlFile
diff --git a/QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Continue.cs b/QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Continue.cs
index 905adff..febf0d7 100644
--- a/QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Continue.cs
+++ b/QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Continue.cs
@@ -26,10 +26,7 @@
 **
 ****************************************************************************/
 
-using System.Collections.Generic;
-using System.ComponentModel;
 using System.Runtime.Serialization;
-using System.Threading;
 
 namespace QtVsTools.Qml.Debug.V4
 {
diff --git a/QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4JsObject.cs b/QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4JsObject.cs
index a5a9272..eb5b243 100644
--- a/QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4JsObject.cs
+++ b/QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4JsObject.cs
@@ -26,7 +26,6 @@
 **
 ****************************************************************************/
 
-using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Runtime.Serialization;
diff --git a/QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Message.cs b/QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Message.cs
index ad1a5b9..f1c3739 100644
--- a/QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Message.cs
+++ b/QtVsTools.Package/QML/Debugging/V4/Messages/QmlDebugV4Message.cs
@@ -143,14 +143,14 @@
             set { Atomic(() => tag == null, () => tag = value); }
         }
 
-        public virtual ProtocolDriver.PendingRequest SendAsync()
+        public virtual ProtocolDriver.PendingRequest SendRequest()
         {
             return Driver.SendRequest(this);
         }
 
         public new Response Send()
         {
-            return SendAsync().WaitForResponse();
+            return SendRequest().WaitForResponse();
         }
 
         public static new Response Send<T>(ProtocolDriver driver, Action<T> initMsg = null)
@@ -173,7 +173,7 @@
 
         public new virtual TResponse Send()
         {
-            var pendingRequest = SendAsync();
+            var pendingRequest = SendRequest();
             if (!pendingRequest.RequestSent)
                 return null;
 
diff --git a/QtVsTools.Package/QML/Debugging/V4/QmlDebugV4Client.cs b/QtVsTools.Package/QML/Debugging/V4/QmlDebugV4Client.cs
index abbf6de..19f88f2 100644
--- a/QtVsTools.Package/QML/Debugging/V4/QmlDebugV4Client.cs
+++ b/QtVsTools.Package/QML/Debugging/V4/QmlDebugV4Client.cs
@@ -26,14 +26,9 @@
 **
 ****************************************************************************/
 
-using QtVsTools.Options;
 using System;
-using System.Collections.Concurrent;
-using System.IO;
 using System.Net.Sockets;
 using System.Runtime.InteropServices;
-using System.Runtime.Serialization;
-using System.Runtime.Serialization.Json;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
@@ -62,7 +57,7 @@
         IConnectionEventSink sink;
         IntPtr client;
         Task clientThread;
-        EventWaitHandle clientCreated = new EventWaitHandle(false, EventResetMode.ManualReset);
+        readonly EventWaitHandle clientCreated = new EventWaitHandle(false, EventResetMode.ManualReset);
         EventWaitHandle clientConnected;
 
         public uint? ThreadId { get; private set; }
@@ -82,7 +77,7 @@
                 if (state != value) {
                     var oldState = state;
                     state = value;
-                    Task.Run(() => sink.NotifyStateTransition(this, oldState, value));
+                    _ = Task.Run(() => sink.NotifyStateTransition(this, oldState, value));
                 }
             }
         }
@@ -100,14 +95,17 @@
         {
             this.sink = sink;
 
-            Task.WaitAny(new[]
+            QtVsToolsPackage.Instance.JoinableTaskFactory.Run(async () =>
             {
-                // Try to start client thread
-                // Unblock if thread was abruptly terminated (e.g. DLL not found)
-                clientThread = Task.Run(() => ClientThread()),
+                await Task.WhenAny(new[]
+                {
+                    // Try to start client thread
+                    // Unblock if thread was abruptly terminated (e.g. DLL not found)
+                    clientThread = Task.Run(() => ClientThread()),
 
-                // Unblock if client was created (i.e. client thread is running)
-                Task.Run(() => clientCreated.WaitOne())
+                    // Unblock if client was created (i.e. client thread is running)
+                    Task.Run(() => clientCreated.WaitOne())
+                });
             });
 
             if (State == DebugClientState.Unavailable) {
@@ -135,7 +133,9 @@
         {
             if (State != DebugClientState.Unavailable) {
                 NativeMethods.DebugClientShutdown(client);
-                clientThread.Wait();
+
+                QtVsToolsPackage.Instance.JoinableTaskFactory.Run(
+                    async () => await Task.WhenAll(new[] { clientThread }));
             }
         }
 
@@ -180,7 +180,7 @@
             var hostNameData = Encoding.UTF8.GetBytes(hostName);
 
             uint timeout = (uint)QtVsToolsPackage.Instance.Options.QmlDebuggerTimeout;
-            Task.Run(() =>
+            _ = Task.Run(() =>
             {
                 var connectTimer = new System.Diagnostics.Stopwatch();
                 connectTimer.Start();
@@ -246,7 +246,7 @@
 
             uint timeout = (uint)QtVsToolsPackage.Instance.Options.QmlDebuggerTimeout;
             if (timeout != 0) {
-                Task.Run(() =>
+                _ = Task.Run(() =>
                 {
                     var connectTimer = new System.Diagnostics.Stopwatch();
                     connectTimer.Start();
diff --git a/QtVsTools.Package/QML/Debugging/V4/QmlDebugV4Protocol.cs b/QtVsTools.Package/QML/Debugging/V4/QmlDebugV4Protocol.cs
index 07315df..a6bc303 100644
--- a/QtVsTools.Package/QML/Debugging/V4/QmlDebugV4Protocol.cs
+++ b/QtVsTools.Package/QML/Debugging/V4/QmlDebugV4Protocol.cs
@@ -53,10 +53,10 @@
         IMessageEventSink sink;
         DebugClient client;
         int nextRequestSeq = 0;
-        Dictionary<int, PendingRequest> pendingRequests = new Dictionary<int, PendingRequest>();
+        readonly Dictionary<int, PendingRequest> pendingRequests = new Dictionary<int, PendingRequest>();
         Task eventHandlingThread;
-        EventWaitHandle eventReceived = new EventWaitHandle(false, EventResetMode.AutoReset);
-        ConcurrentQueue<Event> eventQueue = new ConcurrentQueue<Event>();
+        readonly EventWaitHandle eventReceived = new EventWaitHandle(false, EventResetMode.AutoReset);
+        readonly ConcurrentQueue<Event> eventQueue = new ConcurrentQueue<Event>();
 
         public uint? ThreadId { get { return client.ThreadId; } }
 
@@ -92,7 +92,8 @@
         protected override void DisposeFinally()
         {
             eventReceived.Set();
-            eventHandlingThread.Wait();
+            QtVsToolsPackage.Instance.JoinableTaskFactory.Run(
+                async () => await Task.WhenAll(new[] { eventHandlingThread }));
             eventReceived.Dispose();
         }
 
@@ -100,8 +101,7 @@
         {
             while (!Disposing) {
                 eventReceived.WaitOne();
-                Event evt;
-                while (!Disposing && eventQueue.TryDequeue(out evt))
+                while (!Disposing && eventQueue.TryDequeue(out Event evt))
                     sink.NotifyEvent(evt);
             }
         }
@@ -209,8 +209,8 @@
 
         public class PendingRequest : Finalizable
         {
-            public Request Request { get; private set; }
-            EventWaitHandle responded;
+            public Request Request { get; }
+            readonly EventWaitHandle responded;
 
             public PendingRequest()
             {
diff --git a/QtVsTools.Package/QML/Parser/QmlParserDiagnostics.cs b/QtVsTools.Package/QML/Parser/QmlParserDiagnostics.cs
index 484dc03..929bb80 100644
--- a/QtVsTools.Package/QML/Parser/QmlParserDiagnostics.cs
+++ b/QtVsTools.Package/QML/Parser/QmlParserDiagnostics.cs
@@ -37,8 +37,8 @@
     /// </summary>
     public class DiagnosticMessage
     {
-        public DiagnosticMessageKind Kind { get; set; }
-        public SourceLocation Location { get; set; }
+        private DiagnosticMessageKind Kind { get; }
+        public SourceLocation Location { get; }
         public DiagnosticMessage(DiagnosticMessageKind kind, int offset, int length)
         {
             Kind = kind;
diff --git a/QtVsTools.Package/QML/Parser/QmlParserInterop.cs b/QtVsTools.Package/QML/Parser/QmlParserInterop.cs
index 8ff5d87..d9965f2 100644
--- a/QtVsTools.Package/QML/Parser/QmlParserInterop.cs
+++ b/QtVsTools.Package/QML/Parser/QmlParserInterop.cs
@@ -148,28 +148,27 @@
 
         IntPtr qmlTextPtr = IntPtr.Zero;
         IntPtr qmlParserPtr = IntPtr.Zero;
-
-        List<Token> tokens;
+        readonly List<Token> tokens;
         public IEnumerable<Token> Tokens
         {
             get { return tokens; }
         }
 
-        List<DiagnosticMessage> diagnosticMessages;
+        readonly List<DiagnosticMessage> diagnosticMessages;
         public IEnumerable<DiagnosticMessage> DiagnosticMessages
         {
             get { return diagnosticMessages; }
         }
 
-        public int FirstErrorOffset { get; private set; }
+        private int FirstErrorOffset { get; set; }
 
-        List<AstNode> visitedNodes;
+        readonly List<AstNode> visitedNodes;
         public IEnumerable<AstNode> AstNodes { get { return visitedNodes; } }
 
         public bool ParsedCorrectly { get; private set; }
 
-        Dictionary<IntPtr, AstNode> nodesBytPtr;
-        Dictionary<IntPtr, List<KeyValuePair<AstNode, PropertyInfo>>> pendingDereferences;
+        readonly Dictionary<IntPtr, AstNode> nodesBytPtr;
+        readonly Dictionary<IntPtr, List<KeyValuePair<AstNode, PropertyInfo>>> pendingDereferences;
 
         Parser()
         {
@@ -315,8 +314,7 @@
             if (ptrRef == IntPtr.Zero)
                 return;
 
-            AstNode nodeRef;
-            if (nodesBytPtr.TryGetValue(ptrRef, out nodeRef)) {
+            if (nodesBytPtr.TryGetValue(ptrRef, out AstNode nodeRef)) {
                 nodeProperty.SetValue(node, nodeRef);
             } else {
                 List<KeyValuePair<AstNode, PropertyInfo>> pendingRefList;
diff --git a/QtVsTools.Package/QML/Syntax/QmlAst.cs b/QtVsTools.Package/QML/Syntax/QmlAst.cs
index 1b3b1d1..a5e5ff4 100644
--- a/QtVsTools.Package/QML/Syntax/QmlAst.cs
+++ b/QtVsTools.Package/QML/Syntax/QmlAst.cs
@@ -156,7 +156,7 @@
 
     public class AstNode : SyntaxElement
     {
-        public AstNodeKind Kind { get; private set; }
+        public AstNodeKind Kind { get; }
         public AstNode(AstNodeKind kind) { Kind = kind; }
         public SourceLocation FirstSourceLocation { get; set; }
         public SourceLocation LastSourceLocation { get; set; }
diff --git a/QtVsTools.Package/QML/Syntax/QmlSyntax.cs b/QtVsTools.Package/QML/Syntax/QmlSyntax.cs
index 1035815..0e5ac06 100644
--- a/QtVsTools.Package/QML/Syntax/QmlSyntax.cs
+++ b/QtVsTools.Package/QML/Syntax/QmlSyntax.cs
@@ -192,7 +192,7 @@
     /// </summary>
     public class Token : SyntaxElement
     {
-        public TokenKind Kind { get; private set; }
+        private TokenKind Kind { get; set; }
         public SourceLocation Location { get; private set; }
         protected Token() { }
         public static Token Create(TokenKind kind, int offset, int length)
diff --git a/QtVsTools.Package/QtMenus.vsct_TT b/QtVsTools.Package/QtMenus.vsct_TT
index 76d066f..2f7f7d8 100644
--- a/QtVsTools.Package/QtMenus.vsct_TT
+++ b/QtVsTools.Package/QtMenus.vsct_TT
@@ -2,7 +2,7 @@
 <!--
     *****************************************************************************
     **
-    ** Copyright (C) 2016 The Qt Company Ltd.
+    ** Copyright (C) 2022 The Qt Company Ltd.
     ** Contact: https://www.qt.io/licensing/
     **
     ** This file is part of the Qt VS Tools.
@@ -152,15 +152,8 @@
             <Group guid="ProjectContextMenuGuid" id="ProjectContextOthersMenuGroup" priority="0x0600">
                 <Parent guid="ProjectContextMenuGuid" id="QtProjectSubMenu"/>
             </Group>
-            <Group guid="ProjectContextMenuGuid" id="ProjectContextAddNewQtClassMenuGroup" priority="0x0600">
-                <Parent guid="guidSHLMainMenu" id="cmdidShellWindowNavigate7"/>
-            </Group>
 
             <!-- Endregion Project context menu groups -->
-
-            <Group guid="ProjectContextMenuGuid" id="ProjectContextAddNewQtClassMenuGroup" priority="0x0600">
-                <Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_PROJECT" />
-            </Group>
 
             <Group guid="ItemContextMenuGuid" id="ItemContextTsMenuGroup" priority="0x0600">
                 <Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_ITEMNODE" />
@@ -209,6 +202,15 @@
                     <ButtonText>qt.io</ButtonText>
                 </Strings>
             </Button>
+          <Button guid="MainMenuGuid" id="ViewGettingStartedId" priority="0x0100" type="Button">
+            <Parent guid="MainMenuGuid" id="VersionMenuGroup" />
+            <Icon guid="MenuImages" id="QtLogoBitmap" />
+            <CommandFlag>DynamicVisibility</CommandFlag>
+            <CommandFlag>DefaultInvisible</CommandFlag>
+            <Strings>
+              <ButtonText>Getting Started</ButtonText>
+            </Strings>
+          </Button>
 
             <Button guid="MainMenuGuid" id="F1QtHelpId" priority="0x0100" type="Button">
                 <Parent guid="MainMenuGuid" id="VersionMenuGroup" />
@@ -285,16 +287,6 @@
                 </Strings>
             </Button>
 
-            <Button guid="MainMenuGuid" id="CreateNewTsFileId" priority="0x0100" type="Button">
-                <Parent guid="MainMenuGuid" id="OthersMenuGroup" />
-                <CommandFlag>DefaultDisabled</CommandFlag>
-                <CommandFlag>DynamicVisibility</CommandFlag>
-                <CommandFlag>DefaultInvisible</CommandFlag>
-                <Strings>
-                    <ButtonText>Create New Translation File</ButtonText>
-                    <ToolTipText>Create a new translation file that you can open in Qt Linguist</ToolTipText>
-                </Strings>
-            </Button>
             <Button guid="MainMenuGuid" id="ConvertToQtMsBuild" priority="0x0100" type="Button">
                 <Parent guid="MainMenuGuid" id="OthersMenuGroup" />
                 <CommandFlag>DefaultDisabled</CommandFlag>
@@ -302,24 +294,6 @@
                 <CommandFlag>DynamicVisibility</CommandFlag>
                 <Strings>
                     <ButtonText>Convert custom build steps to Qt/MSBuild</ButtonText>
-                </Strings>
-            </Button>
-            <Button guid="MainMenuGuid" id="ConvertToQtId" priority="0x0100" type="Button">
-                <Parent guid="MainMenuGuid" id="OthersMenuGroup" />
-                <CommandFlag>DefaultDisabled</CommandFlag>
-                <CommandFlag>DefaultInvisible</CommandFlag>
-                <CommandFlag>DynamicVisibility</CommandFlag>
-                <Strings>
-                    <ButtonText>Convert Project to Qt VS Tools Project</ButtonText>
-                </Strings>
-            </Button>
-            <Button guid="MainMenuGuid" id="ConvertToQmakeId" priority="0x0100" type="Button">
-                <Parent guid="MainMenuGuid" id="OthersMenuGroup" />
-                <CommandFlag>DefaultDisabled</CommandFlag>
-                <CommandFlag>DynamicVisibility</CommandFlag>
-                <CommandFlag>DefaultInvisible</CommandFlag>
-                <Strings>
-                    <ButtonText>Convert Project to QMake Generated Project</ButtonText>
                 </Strings>
             </Button>
             <Button guid="MainMenuGuid" id="QtProjectSettingsId" priority="0x0100" type="Button">
@@ -451,15 +425,6 @@
                 </Strings>
             </Button>
 
-            <Button guid="ProjectContextMenuGuid" id="CreateNewTsFileProjectId" priority="0x0100" type="Button">
-                <Parent guid="ProjectContextMenuGuid" id="ProjectContextTsMenuGroup" />
-                <CommandFlag>DefaultDisabled</CommandFlag>
-                <CommandFlag>DynamicVisibility</CommandFlag>
-                <Strings>
-                    <ButtonText>Create New Translation File</ButtonText>
-                    <ToolTipText>Create a new translation file that you can open in Qt Linguist</ToolTipText>
-                </Strings>
-            </Button>
             <Button guid="ProjectContextMenuGuid" id="lUpdateOnProjectId" priority="0x0100" type="Button">
                 <Parent guid="ProjectContextMenuGuid" id="ProjectContextTsMenuGroup" />
                 <Icon guid="MenuImages" id="LaunchLinguistBitmap" />
@@ -499,23 +464,6 @@
                     <ButtonText>Refresh IntelliSense</ButtonText>
                 </Strings>
             </Button>
-            <Button guid="ProjectContextMenuGuid" id="ConvertToQtProjectId" priority="0x0100" type="Button">
-                <Parent guid="ProjectContextMenuGuid" id="ProjectContextOthersMenuGroup" />
-                <CommandFlag>DefaultDisabled</CommandFlag>
-                <CommandFlag>DefaultInvisible</CommandFlag>
-                <CommandFlag>DynamicVisibility</CommandFlag>
-                <Strings>
-                    <ButtonText>Convert Project to Qt VS Tools Project</ButtonText>
-                </Strings>
-            </Button>
-            <Button guid="ProjectContextMenuGuid" id="ConvertToQmakeProjectId" priority="0x0100" type="Button">
-                <Parent guid="ProjectContextMenuGuid" id="ProjectContextOthersMenuGroup" />
-                <CommandFlag>DefaultDisabled</CommandFlag>
-                <CommandFlag>DynamicVisibility</CommandFlag>
-                <Strings>
-                    <ButtonText>Convert Project to QMake Generated Project</ButtonText>
-                </Strings>
-            </Button>
             <Button guid="ProjectContextMenuGuid" id="QtProjectSettingsProjectId" priority="0x0100" type="Button">
                 <Parent guid="ProjectContextMenuGuid" id="ProjectContextOthersMenuGroup" />
                 <CommandFlag>DefaultDisabled</CommandFlag>
@@ -532,16 +480,6 @@
                 <CommandFlag>DynamicVisibility</CommandFlag>
                 <Strings>
                     <ButtonText>Change Project's Qt Version</ButtonText>
-                </Strings>
-            </Button>
-            <Button guid="ProjectContextMenuGuid" id="ProjectAddNewQtClassProjectId" priority="0x0100" type="Button">
-                <Parent guid="ProjectContextMenuGuid" id="ProjectContextAddNewQtClassMenuGroup" />
-                <Icon guid="MenuImages" id="AddNewQtClassBitmap" />
-                <CommandFlag>DefaultDisabled</CommandFlag>
-                <CommandFlag>DefaultInvisible</CommandFlag>
-                <CommandFlag>DynamicVisibility</CommandFlag>
-                <Strings>
-                    <ButtonText>Add Qt Class...</ButtonText>
                 </Strings>
             </Button>
 
@@ -586,7 +524,7 @@
             -->
             <Bitmap guid="MenuImages" href="Resources\menuimages.png" usedList="LaunchDesignerBitmap,
                 LaunchLinguistBitmap, OpenProFileBitmap, ImportPriFileBitmap, ExportProFileBitmap,
-                CreateProFileBitmap, QtLogoBitmap, AddNewQtClassBitmap" />
+                CreateProFileBitmap, QtLogoBitmap" />
         </Bitmaps>
     </Commands>
 
@@ -605,6 +543,7 @@
             <IDSymbol name="QtVersionId" value="0x0500" />
             <IDSymbol name="ViewQtHelpId" value="0x0501" />
             <IDSymbol name="F1QtHelpId" value="0x0502" />
+            <IDSymbol name="ViewGettingStartedId" value="0x0503" />
 
             <IDSymbol name="LaunchMenuGroup" value="0x1021" />
             <IDSymbol name="LaunchDesignerId" value="0x0100" />
@@ -617,10 +556,7 @@
             <IDSymbol name="ExportProFileId" value="0x0105" />
 
             <IDSymbol name="OthersMenuGroup" value="0x1023" />
-            <IDSymbol name="CreateNewTsFileId" value="0x0107" />
             <IDSymbol name="ConvertToQtMsBuild" value="0x0130" />
-            <IDSymbol name="ConvertToQtId" value="0x0124" />
-            <IDSymbol name="ConvertToQmakeId" value="0x0108" />
             <IDSymbol name="QtProjectSettingsId" value="0x0109" />
             <IDSymbol name="ChangeProjectQtVersionId" value="0x0126" />
 
@@ -665,20 +601,16 @@
             <IDSymbol name="ExportProFileProjectId" value="0x0116" />
 
             <IDSymbol name="ProjectContextTsMenuGroup" value="0x1028" />
-            <IDSymbol name="CreateNewTsFileProjectId" value="0x0117" />
             <IDSymbol name="lUpdateOnProjectId" value="0x0118" />
             <IDSymbol name="lReleaseOnProjectId" value="0x0119" />
 
             <IDSymbol name="ProjectContextOthersMenuGroup" value="0x1029" />
             <IDSymbol name="ProjectConvertToQtMsBuild" value="0x0130" />
             <IDSymbol name="ProjectRefreshIntelliSense" value="0x0131" />
-            <IDSymbol name="ConvertToQtProjectId" value="0x0120" />
-            <IDSymbol name="ConvertToQmakeProjectId" value="0x0121" />
             <IDSymbol name="QtProjectSettingsProjectId" value="0x0122" />
             <IDSymbol name="ChangeProjectQtVersionProjectId" value="0x0123" />
 
             <IDSymbol name="ProjectContextAddNewQtClassMenuGroup" value="0x1031" />
-            <IDSymbol name="ProjectAddNewQtClassProjectId" value="0x0200" />
 
             <!-- Endregion Project context menu button Ids -->
 
@@ -700,7 +632,6 @@
             <IDSymbol name="ExportProFileBitmap" value="5" />
             <IDSymbol name="CreateProFileBitmap" value="6" />
             <IDSymbol name="QtLogoBitmap" value="7" />
-            <IDSymbol name="AddNewQtClassBitmap" value="8" />
         </GuidSymbol>
     </Symbols>
 
diff --git a/QtVsTools.Package/QtMsBuild/QtModulesEditor.cs b/QtVsTools.Package/QtMsBuild/QtModulesEditor.cs
index 8fbd145..e05e4ce 100644
--- a/QtVsTools.Package/QtMsBuild/QtModulesEditor.cs
+++ b/QtVsTools.Package/QtMsBuild/QtModulesEditor.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -28,15 +28,15 @@
 
 using Microsoft.VisualStudio.ProjectSystem;
 using Microsoft.VisualStudio.ProjectSystem.Properties;
-using Microsoft.Internal.VisualStudio.PlatformUI;
 using System;
+using System.Collections.Generic;
 using System.ComponentModel.Composition;
 using System.Linq;
 using System.Threading.Tasks;
 
 namespace QtVsTools.QtMsBuild
 {
-    using QtVsTools.Core;
+    using Core;
 
     [Export(typeof(IPropertyPageUIValueEditor))]
     [ExportMetadata("Name", "QtModulesEditor")]
@@ -50,7 +50,15 @@
         {
             await Task.Yield();
 
-            var modules = QtModules.Instance.GetAvailableModules()
+            var qtSettings = ruleProperty.ContainingRule;
+            var qtVersion = await qtSettings.GetPropertyValueAsync("QtInstall");
+
+            var vm = QtVersionManager.The();
+            var versionInfo = vm.GetVersionInfo(qtVersion);
+            if (versionInfo == null)
+                versionInfo = vm.GetVersionInfo(vm.GetDefaultVersion());
+
+            var modules = QtModules.Instance.GetAvailableModules(versionInfo.qtMajor)
                 .Where(x => !string.IsNullOrEmpty(x.proVarQT))
                 .Select(x => new QtModulesPopup.Module
                 {
@@ -61,24 +69,28 @@
                 })
                 .ToList();
 
-            var allQT = modules.SelectMany(x => x.QT).ToHashSet();
-            var selectedQT = currentValue.ToString().Split(';').ToHashSet();
-            var extraQT = selectedQT.Except(allQT);
+            HashSet<string> selectedQt = null;
+            IEnumerable<string> extraQt = null;
+            if (currentValue != null) {
+                var allQt = modules.SelectMany(x => x.QT).ToHashSet();
+                selectedQt = currentValue.ToString().Split(';').ToHashSet();
+                extraQt = selectedQt.Except(allQt);
 
-            foreach (var module in modules)
-                module.IsSelected = module.QT.Intersect(selectedQT).Count() == module.QT.Count;
+                foreach (var module in modules)
+                    module.IsSelected = module.QT.Intersect(selectedQt).Count() == module.QT.Count;
+            }
 
             var popup = new QtModulesPopup();
-            popup.SetModules(modules);
+            popup.SetModules(modules.OrderBy(module => module.Name));
 
             if (popup.ShowModal().GetValueOrDefault()) {
-                selectedQT = modules
+                selectedQt = modules
                     .Where(x => x.IsSelected)
                     .SelectMany(x => x.QT)
-                    .Union(extraQT)
+                    .Union(extraQt ?? Enumerable.Empty<string>())
                     .ToHashSet();
             }
-            return string.Join(";", selectedQT);
+            return selectedQt == null ? "" : string.Join(";", selectedQt);
         }
     }
 }
diff --git a/QtVsTools.Package/QtMsBuild/QtModulesPopup.xaml b/QtVsTools.Package/QtMsBuild/QtModulesPopup.xaml
index 54e13a7..fd22f7b 100644
--- a/QtVsTools.Package/QtMsBuild/QtModulesPopup.xaml
+++ b/QtVsTools.Package/QtMsBuild/QtModulesPopup.xaml
@@ -1,7 +1,7 @@
 <!--
 *****************************************************************************
 **
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -27,10 +27,10 @@
 **
 *****************************************************************************
 -->
-<local:VsToolsDialogWindow x:Class="QtVsTools.QtMsBuild.QtModulesPopup"
+<vsui:DialogWindow x:Class="QtVsTools.QtMsBuild.QtModulesPopup"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-        xmlns:local="clr-namespace:QtVsTools"
+        xmlns:vsui="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0"
         ResizeMode="CanResize"
         Width="800" MaxHeight="550"
         MouseDown="Window_MouseDown"
@@ -108,4 +108,4 @@
             <Button IsCancel="True" MinHeight="23" MinWidth="74">_Cancel</Button>
         </WrapPanel>
     </Grid>
-</local:VsToolsDialogWindow>
+</vsui:DialogWindow>
diff --git a/QtVsTools.Package/QtMsBuild/QtModulesPopup.xaml.cs b/QtVsTools.Package/QtMsBuild/QtModulesPopup.xaml.cs
index 19d045b..ba20831 100644
--- a/QtVsTools.Package/QtMsBuild/QtModulesPopup.xaml.cs
+++ b/QtVsTools.Package/QtMsBuild/QtModulesPopup.xaml.cs
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the Qt VS Tools.
@@ -30,10 +30,11 @@
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Input;
+using Microsoft.VisualStudio.PlatformUI;
 
 namespace QtVsTools.QtMsBuild
 {
-    public partial class QtModulesPopup : VsToolsDialogWindow
+    public partial class QtModulesPopup : DialogWindow
     {
         public class Module
         {
@@ -81,8 +82,7 @@
         private void PopupListBox_KeyDown(object sender, KeyEventArgs e)
         {
             if (e.Key == Key.Enter || e.Key == Key.Space) {
-                var module = PopupListBox.SelectedItem as Module;
-                if (module != null && module.IsEnabled)
+                if (PopupListBox.SelectedItem is Module module && module.IsEnabled)
                     module.CheckBox.IsChecked = (module.CheckBox.IsChecked != true);
             }
         }
diff --git a/QtVsTools.Package/QtMsBuild/QtProjectBuild.cs b/QtVsTools.Package/QtMsBuild/QtProjectBuild.cs
index f2fea0b..44023ee 100644
--- a/QtVsTools.Package/QtMsBuild/QtProjectBuild.cs
+++ b/QtVsTools.Package/QtMsBuild/QtProjectBuild.cs
@@ -40,36 +40,42 @@
 using Microsoft.VisualStudio.TaskStatusCenter;
 using Microsoft.VisualStudio.Threading;
 using Microsoft.VisualStudio.VCProjectEngine;
-using EnvDTE;
+
+using Thread = System.Threading.Thread;
 
 namespace QtVsTools.QtMsBuild
 {
+    using Common;
     using Core;
     using VisualStudio;
-    using Thread = System.Threading.Thread;
+    using static Common.EnumExt;
 
     class QtProjectBuild : Concurrent<QtProjectBuild>
     {
-        static PunisherQueue<QtProjectBuild> _BuildQueue;
-        static PunisherQueue<QtProjectBuild> BuildQueue =>
-            StaticThreadSafeInit(() => _BuildQueue,
-                () => _BuildQueue = new PunisherQueue<QtProjectBuild>(
-                    getItemKey: (QtProjectBuild build) =>
-                    {
-                        return build.ConfiguredProject;
-                    })
-                );
+        static LazyFactory StaticLazy { get; } = new LazyFactory();
 
-        static ConcurrentStopwatch _RequestTimer;
-        static ConcurrentStopwatch RequestTimer =>
-            StaticThreadSafeInit(() => _RequestTimer, () => _RequestTimer = new ConcurrentStopwatch());
+        public enum Target
+        {
+            // Mark project as dirty, but do not request a build
+            [String("QtVsTools.QtMsBuild.QtProjectBuild.Target.SetOutdated")] SetOutdated
+        }
 
-        static IVsTaskStatusCenterService _StatusCenter;
-        static IVsTaskStatusCenterService StatusCenter => StaticThreadSafeInit(() => _StatusCenter,
-                () => _StatusCenter = VsServiceProvider
-                    .GetService<SVsTaskStatusCenterService, IVsTaskStatusCenterService>());
+        static PunisherQueue<QtProjectBuild> BuildQueue => StaticLazy.Get(() =>
+            BuildQueue, () => new PunisherQueue<QtProjectBuild>(
+                getItemKey: (QtProjectBuild build) =>
+                {
+                    return build.ConfiguredProject;
+                }));
+
+        static ConcurrentStopwatch RequestTimer => StaticLazy.Get(() =>
+            RequestTimer, () => new ConcurrentStopwatch());
+
+        static IVsTaskStatusCenterService StatusCenter => StaticLazy.Get(() =>
+            StatusCenter, () => VsServiceProvider
+                .GetService<SVsTaskStatusCenterService, IVsTaskStatusCenterService>());
 
         EnvDTE.Project Project { get; set; }
+        VCProject VcProject { get; set; }
         UnconfiguredProject UnconfiguredProject { get; set; }
         ConfiguredProject ConfiguredProject { get; set; }
         Dictionary<string, string> Properties { get; set; }
@@ -80,6 +86,7 @@
 
         public static void StartBuild(
             EnvDTE.Project project,
+            string projectPath,
             string configName,
             Dictionary<string, string> properties,
             IEnumerable<string> targets,
@@ -90,11 +97,13 @@
             if (configName == null)
                 throw new ArgumentException("Configuration name cannot be null.");
 
-            Task.Run(() => StartBuildAsync(project, configName, properties, targets, verbosity));
+            _ = Task.Run(() => StartBuildAsync(
+                project, projectPath, configName, properties, targets, verbosity));
         }
 
         public static async Task StartBuildAsync(
             EnvDTE.Project project,
+            string projectPath,
             string configName,
             Dictionary<string, string> properties,
             IEnumerable<string> targets,
@@ -106,15 +115,15 @@
                 throw new ArgumentException("Configuration name cannot be null.");
 
             RequestTimer.Restart();
+            var tracker = QtProjectTracker.Get(project, projectPath);
+            await tracker.Initialized;
+
             if (QtVsToolsPackage.Instance.Options.BuildDebugInformation) {
                 Messages.Print(string.Format(
                 "{0:HH:mm:ss.FFF} QtProjectBuild({1}): Request [{2}] {3}",
                 DateTime.Now, Thread.CurrentThread.ManagedThreadId,
-                configName, project.FullName));
+                configName, tracker.UnconfiguredProject.FullPath));
             }
-
-            var tracker = QtProjectTracker.Get(project);
-            await tracker.Initialized;
 
             var knownConfigs = await tracker.UnconfiguredProject.Services
                 .ProjectConfigurationsService.GetKnownProjectConfigurationsAsync();
@@ -134,6 +143,7 @@
             BuildQueue.Enqueue(new QtProjectBuild()
             {
                 Project = project,
+                VcProject = tracker.VcProject,
                 UnconfiguredProject = tracker.UnconfiguredProject,
                 ConfiguredProject = configuredProject,
                 Properties = properties?.ToDictionary(x => x.Key, x => x.Value),
@@ -143,6 +153,35 @@
             StaticThreadSafeInit(() => BuildDispatcher,
                 () => BuildDispatcher = Task.Run(BuildDispatcherLoopAsync))
                 .Forget();
+        }
+
+        public static void SetOutdated(
+            EnvDTE.Project project,
+            string projectPath,
+            string configName,
+            LoggerVerbosity verbosity = LoggerVerbosity.Quiet)
+        {
+            if (project == null)
+                throw new ArgumentException("Project cannot be null.");
+            if (configName == null)
+                throw new ArgumentException("Configuration name cannot be null.");
+
+            _ = Task.Run(() => SetOutdatedAsync(project, projectPath, configName, verbosity));
+        }
+
+        public static async Task SetOutdatedAsync(
+            EnvDTE.Project project,
+            string projectPath,
+            string configName,
+            LoggerVerbosity verbosity = LoggerVerbosity.Quiet)
+        {
+            await StartBuildAsync(
+                project,
+                projectPath,
+                configName,
+                null,
+                new[] { Target.SetOutdated.Cast<string>() },
+                verbosity);
         }
 
         public static void Reset()
@@ -161,8 +200,7 @@
                     }
                     await Task.Delay(100);
                 }
-                QtProjectBuild buildRequest;
-                if (BuildQueue.TryDequeue(out buildRequest)) {
+                if (BuildQueue.TryDequeue(out QtProjectBuild buildRequest)) {
                     if (dispatchStatus == null) {
                         dispatchStatus = StatusCenter.PreRegister(
                             new TaskHandlerOptions
@@ -202,6 +240,140 @@
             }
         }
 
+        async Task<bool> BuildProjectAsync(ProjectWriteLockReleaser writeAccess)
+        {
+            var msBuildProject = await writeAccess.GetProjectAsync(ConfiguredProject);
+
+            if (Targets.Any(t => t == Target.SetOutdated.Cast<string>())) {
+                msBuildProject.MarkDirty();
+                await writeAccess.ReleaseAsync();
+                return true;
+            }
+
+            var solutionPath = QtProjectTracker.SolutionPath;
+            var configProps = new Dictionary<string, string>(
+                ConfiguredProject.ProjectConfiguration.Dimensions.ToImmutableDictionary())
+                {
+                    { "SolutionPath", solutionPath },
+                    { "SolutionFileName", Path.GetFileName(solutionPath) },
+                    { "SolutionName", Path.GetFileNameWithoutExtension(solutionPath) },
+                    { "SolutionExt", Path.GetExtension(solutionPath) },
+                    { "SolutionDir", Path.GetDirectoryName(solutionPath).TrimEnd('\\') + '\\'  }
+                };
+
+            foreach (var property in Properties)
+                configProps[property.Key] = property.Value;
+
+            var projectInstance = new ProjectInstance(msBuildProject.Xml,
+                configProps, null, new ProjectCollection());
+
+            var loggerVerbosity = LoggerVerbosity;
+            if (QtVsToolsPackage.Instance.Options.BuildDebugInformation)
+                loggerVerbosity = QtVsToolsPackage.Instance.Options.BuildLoggerVerbosity;
+            var buildParams = new BuildParameters()
+            {
+                Loggers = (loggerVerbosity != LoggerVerbosity.Quiet)
+                        ? new[] { new QtProjectLogger() { Verbosity = loggerVerbosity } }
+                        : null
+            };
+
+            var buildRequest = new BuildRequestData(projectInstance,
+                Targets.ToArray(),
+                hostServices: null,
+                flags: BuildRequestDataFlags.ProvideProjectStateAfterBuild);
+
+            if (QtVsToolsPackage.Instance.Options.BuildDebugInformation) {
+                Messages.Print(string.Format(
+                    "{0:HH:mm:ss.FFF} QtProjectBuild({1}): Build [{2}] {3}",
+                    DateTime.Now, Thread.CurrentThread.ManagedThreadId,
+                    ConfiguredProject.ProjectConfiguration.Name,
+                    UnconfiguredProject.FullPath));
+                Messages.Print("=== Targets");
+                foreach (var target in buildRequest.TargetNames)
+                    Messages.Print(string.Format("    {0}", target));
+                Messages.Print("=== Properties");
+                foreach (var property in Properties) {
+                    Messages.Print(string.Format("    {0}={1}",
+                        property.Key, property.Value));
+                }
+            }
+
+            BuildResult result = null;
+            while (result == null) {
+                try {
+                    result = BuildManager.DefaultBuildManager.Build(
+                        buildParams, buildRequest);
+                } catch (InvalidOperationException) {
+                    if (QtVsToolsPackage.Instance.Options.BuildDebugInformation) {
+                        Messages.Print(string.Format(
+                            "{0:HH:mm:ss.FFF} QtProjectBuild({1}): [{2}] "
+                            + "Warning: Another build is in progress; waiting...",
+                            DateTime.Now,
+                            Thread.CurrentThread.ManagedThreadId,
+                            ConfiguredProject.ProjectConfiguration.Name));
+                    }
+                    await Task.Delay(3000);
+                }
+            }
+
+            if (QtVsToolsPackage.Instance.Options.BuildDebugInformation) {
+                string resMsg;
+                StringBuilder resInfo = new StringBuilder();
+                if (result?.OverallResult == BuildResultCode.Success) {
+                    resMsg = "Build ok";
+                } else {
+                    resMsg = "Build FAIL";
+                    if (result == null) {
+                        resInfo.AppendLine("####### Build returned 'null'");
+                    } else {
+                        resInfo.AppendLine("####### Build returned 'Failure' code");
+                        if (result.ResultsByTarget != null) {
+                            foreach (var tr in result.ResultsByTarget) {
+                                var res = tr.Value;
+                                if (res.ResultCode != TargetResultCode.Failure)
+                                    continue;
+                                resInfo.AppendFormat("### Target '{0}' FAIL\r\n", tr.Key);
+                                if (res.Items != null && res.Items.Length > 0) {
+                                    resInfo.AppendFormat(
+                                        "Items: {0}\r\n", string.Join(", ", res.Items
+                                            .Select(it => it.ItemSpec)));
+                                }
+                                var e = tr.Value?.Exception;
+                                if (e != null) {
+                                    resInfo.AppendFormat(
+                                        "Exception: {0}\r\nStacktrace:\r\n{1}\r\n",
+                                        e.Message, e.StackTrace);
+                                }
+                            }
+                        }
+                    }
+                }
+                Messages.Print(string.Format(
+                    "{0:HH:mm:ss.FFF} QtProjectBuild({1}): [{2}] {3}\r\n{4}",
+                    DateTime.Now, Thread.CurrentThread.ManagedThreadId,
+                    ConfiguredProject.ProjectConfiguration.Name,
+                    resMsg, resInfo.ToString()));
+            }
+
+            bool ok = false;
+            if (result == null
+                || result.ResultsByTarget == null
+                || result.OverallResult != BuildResultCode.Success) {
+                Messages.Print(string.Format("{0}: background build FAILED!",
+                        Path.GetFileName(UnconfiguredProject.FullPath)));
+            } else {
+                var checkResults = result.ResultsByTarget
+                    .Where(x => Targets.Contains(x.Key))
+                    .Select(x => x.Value);
+                ok = checkResults.Any()
+                    && checkResults.All(x => x.ResultCode == TargetResultCode.Success);
+                if (ok)
+                    msBuildProject.MarkDirty();
+            }
+            await writeAccess.ReleaseAsync();
+            return ok;
+        }
+
         async Task BuildAsync()
         {
             if (LoggerVerbosity != LoggerVerbosity.Quiet) {
@@ -211,7 +383,7 @@
   * Properties: {1}
   * Targets: {2}
 ",
-                    /*{0}*/ Project.Name,
+                    /*{0}*/ Path.GetFileNameWithoutExtension(UnconfiguredProject.FullPath),
                     /*{1}*/ string.Join("", Properties
                         .Select(property => string.Format(@"
         {0} = {1}",     /*{0}*/ property.Key, /*{1}*/ property.Value))),
@@ -222,151 +394,41 @@
 
             bool ok = false;
             try {
-                ProjectWriteLockReleaser writeAccess;
                 var timer = ConcurrentStopwatch.StartNew();
                 while (timer.IsRunning) {
                     try {
-                        writeAccess = await lockService.WriteLockAsync();
+#if VS2017
+                        using (var writeAccess = await lockService.WriteLockAsync())
+                            ok = await BuildProjectAsync(writeAccess);
+#else
+                        await lockService.WriteLockAsync(
+                            async (ProjectWriteLockReleaser writeAccess) =>
+                            {
+                                ok = await BuildProjectAsync(writeAccess);
+                            });
+#endif
                         timer.Stop();
                     } catch (InvalidOperationException) {
                         if (timer.ElapsedMilliseconds >= 5000)
                             throw;
+#if VS2017
                         using (var readAccess = await lockService.ReadLockAsync())
                             await readAccess.ReleaseAsync();
+#else
+                        await lockService.ReadLockAsync(
+                            async (ProjectLockReleaser readAccess) =>
+                            {
+                                await readAccess.ReleaseAsync();
+                            });
+#endif
                     }
-                }
-
-                using (writeAccess) {
-                    var msBuildProject = await writeAccess.GetProjectAsync(ConfiguredProject);
-
-                    var solutionPath = QtProjectTracker.SolutionPath;
-                    var configProps = new Dictionary<string, string>(
-                        ConfiguredProject.ProjectConfiguration.Dimensions.ToImmutableDictionary())
-                    {
-                        { "SolutionPath", solutionPath },
-                        { "SolutionFileName", Path.GetFileName(solutionPath) },
-                        { "SolutionName", Path.GetFileNameWithoutExtension(solutionPath) },
-                        { "SolutionExt", Path.GetExtension(solutionPath) },
-                        { "SolutionDir", Path.GetDirectoryName(solutionPath).TrimEnd('\\') + '\\'  }
-                    };
-
-                    foreach (var property in Properties)
-                        configProps[property.Key] = property.Value;
-
-                    var projectInstance = new ProjectInstance(msBuildProject.Xml,
-                        configProps, null, new ProjectCollection());
-
-                    var loggerVerbosity = LoggerVerbosity;
-                    if (QtVsToolsPackage.Instance.Options.BuildDebugInformation)
-                        loggerVerbosity = QtVsToolsPackage.Instance.Options.BuildLoggerVerbosity;
-                    var buildParams = new BuildParameters()
-                    {
-                        Loggers = (loggerVerbosity != LoggerVerbosity.Quiet)
-                                ? new[] { new QtProjectLogger() { Verbosity = loggerVerbosity } }
-                                : null
-                    };
-
-                    var buildRequest = new BuildRequestData(projectInstance,
-                        Targets.ToArray(),
-                        hostServices: null,
-                        flags: BuildRequestDataFlags.ProvideProjectStateAfterBuild);
-
-                    if (QtVsToolsPackage.Instance.Options.BuildDebugInformation) {
-                        Messages.Print(string.Format(
-                            "{0:HH:mm:ss.FFF} QtProjectBuild({1}): Build [{2}] {3}",
-                            DateTime.Now, Thread.CurrentThread.ManagedThreadId,
-                            ConfiguredProject.ProjectConfiguration.Name,
-                            UnconfiguredProject.FullPath));
-                        Messages.Print("=== Targets");
-                        foreach (var target in buildRequest.TargetNames)
-                            Messages.Print(string.Format("    {0}", target));
-                        Messages.Print("=== Properties");
-                        foreach (var property in Properties) {
-                            Messages.Print(string.Format("    {0}={1}",
-                                property.Key, property.Value));
-                        }
-                    }
-
-                    BuildResult result = null;
-                    while (result == null) {
-                        try {
-                            result = BuildManager.DefaultBuildManager.Build(
-                                buildParams, buildRequest);
-                        } catch (InvalidOperationException) {
-                            if (QtVsToolsPackage.Instance.Options.BuildDebugInformation) {
-                                Messages.Print(string.Format(
-                                    "{0:HH:mm:ss.FFF} QtProjectBuild({1}): [{2}] "
-                                    + "Warning: Another build is in progress; waiting...",
-                                    DateTime.Now,
-                                    Thread.CurrentThread.ManagedThreadId,
-                                    ConfiguredProject.ProjectConfiguration.Name));
-                            }
-                            await Task.Delay(3000);
-                        }
-                    }
-
-                    if (QtVsToolsPackage.Instance.Options.BuildDebugInformation) {
-                        string resMsg;
-                        StringBuilder resInfo = new StringBuilder();
-                        if (result?.OverallResult == BuildResultCode.Success) {
-                            resMsg = "Build ok";
-                        } else {
-                            resMsg = "Build FAIL";
-                            if (result == null) {
-                                resInfo.AppendLine("####### Build returned 'null'");
-                            } else {
-                                resInfo.AppendLine("####### Build returned 'Failure' code");
-                                if (result.ResultsByTarget != null) {
-                                    foreach (var tr in result.ResultsByTarget) {
-                                        var res = tr.Value;
-                                        if (res.ResultCode != TargetResultCode.Failure)
-                                            continue;
-                                        resInfo.AppendFormat("### Target '{0}' FAIL\r\n", tr.Key);
-                                        if (res.Items != null && res.Items.Length > 0) {
-                                            resInfo.AppendFormat(
-                                                "Items: {0}\r\n", string.Join(", ", res.Items
-                                                    .Select(it => it.ItemSpec)));
-                                        }
-                                        var e = tr.Value?.Exception;
-                                        if (e != null) {
-                                            resInfo.AppendFormat(
-                                                "Exception: {0}\r\nStacktrace:\r\n{1}\r\n",
-                                                e.Message, e.StackTrace);
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                        Messages.Print(string.Format(
-                            "{0:HH:mm:ss.FFF} QtProjectBuild({1}): [{2}] {3}\r\n{4}",
-                            DateTime.Now, Thread.CurrentThread.ManagedThreadId,
-                            ConfiguredProject.ProjectConfiguration.Name,
-                            resMsg, resInfo.ToString()));
-                    }
-
-                    if (result == null
-                        || result.ResultsByTarget == null
-                        || result.OverallResult != BuildResultCode.Success) {
-                        Messages.Print(string.Format("{0}: background build FAILED!",
-                                Path.GetFileName(UnconfiguredProject.FullPath)));
-                    } else {
-                        var checkResults = result.ResultsByTarget
-                            .Where(x => Targets.Contains(x.Key))
-                            .Select(x => x.Value);
-                        ok = checkResults.Any()
-                            && checkResults.All(x => x.ResultCode == TargetResultCode.Success);
-                        if (ok)
-                            msBuildProject.MarkDirty();
-                    }
-                    await writeAccess.ReleaseAsync();
                 }
 
                 if (ok) {
-                    var vcProject = Project.Object as VCProject;
-                    var vcConfigs = vcProject.Configurations as IVCCollection;
+                    var vcConfigs = VcProject.Configurations as IVCCollection;
                     var vcConfig = vcConfigs.Item(ConfiguredProject.ProjectConfiguration.Name) as VCConfiguration;
                     var props = vcConfig.Rules.Item("QtRule10_Settings") as IVCRulePropertyStorage;
-                    props.SetPropertyValue("QtLastBackgroundBuild", DateTime.UtcNow.ToString("o"));
+                    props?.SetPropertyValue("QtLastBackgroundBuild", DateTime.UtcNow.ToString("o"));
                 }
             } catch (Exception e) {
                 Messages.Print(string.Format("{0}: background build ERROR: {1}",
@@ -377,7 +439,8 @@
                 Messages.Print(string.Format(
 @"
 == {0}: build {1}",
-                    Project.Name, ok ? "successful" : "ERROR"));
+                    Path.GetFileNameWithoutExtension(UnconfiguredProject.FullPath),
+                    ok ? "successful" : "ERROR"));
             }
         }
     }
diff --git a/QtVsTools.Package/QtMsBuild/QtProjectIntelliSense.cs b/QtVsTools.Package/QtMsBuild/QtProjectIntelliSense.cs
index 605763f..46ff9d4 100644
--- a/QtVsTools.Package/QtMsBuild/QtProjectIntelliSense.cs
+++ b/QtVsTools.Package/QtMsBuild/QtProjectIntelliSense.cs
@@ -31,12 +31,15 @@
 using System.Linq;
 using System.Threading.Tasks;
 using Microsoft.Build.Framework;
+using Microsoft.VisualStudio.Shell;
 using Microsoft.VisualStudio.Threading;
+
+using Task = System.Threading.Tasks.Task;
+using Thread = System.Threading.Thread;
 
 namespace QtVsTools.QtMsBuild
 {
     using Core;
-    using Thread = System.Threading.Thread;
 
     static class QtProjectIntellisense
     {
@@ -45,25 +48,31 @@
             string configId = null,
             IEnumerable<string> selectedFiles = null)
         {
-            if (project == null || !QtProjectTracker.IsTracked(project))
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            if (project == null || !QtProjectTracker.IsTracked(project.FullName))
                 return;
+
             if (QtVsToolsPackage.Instance.Options.BuildDebugInformation) {
                 Messages.Print(string.Format(
                     "{0:HH:mm:ss.FFF} QtProjectIntellisense({1}): Refreshing: [{2}] {3}",
                     DateTime.Now, Thread.CurrentThread.ManagedThreadId,
                     (configId != null) ? configId : "(all configs)", project.FullName));
             }
-            Task.Run(() => RefreshAsync(project, configId, selectedFiles));
+            string projectPath = project.FullName;
+            _ = Task.Run(() => RefreshAsync(project, projectPath, configId, selectedFiles, false));
         }
 
         public static async Task RefreshAsync(
             EnvDTE.Project project,
+            string projectPath,
             string configId = null,
-            IEnumerable<string> selectedFiles = null)
+            IEnumerable<string> selectedFiles = null,
+            bool refreshQtVars = false)
         {
-            if (project == null || !QtProjectTracker.IsTracked(project))
+            if (project == null || !QtProjectTracker.IsTracked(projectPath))
                 return;
-            var tracker = QtProjectTracker.Get(project);
+            var tracker = QtProjectTracker.Get(project, projectPath);
             await tracker.Initialized;
 
             var properties = new Dictionary<string, string>();
@@ -84,9 +93,14 @@
             }
 
             foreach (var config in configs) {
-                await QtProjectBuild.StartBuildAsync(
-                    project, config, properties, targets,
-                    LoggerVerbosity.Quiet);
+                if (refreshQtVars) {
+                    await QtProjectBuild.StartBuildAsync(
+                        project, projectPath, config, properties, targets,
+                        LoggerVerbosity.Quiet);
+                } else {
+                    await QtProjectBuild.SetOutdatedAsync(
+                        project, projectPath, config, LoggerVerbosity.Quiet);
+                }
             }
         }
     }
diff --git a/QtVsTools.Package/QtMsBuild/QtProjectTracker.cs b/QtVsTools.Package/QtMsBuild/QtProjectTracker.cs
index 66db5c7..1d8e719 100644
--- a/QtVsTools.Package/QtMsBuild/QtProjectTracker.cs
+++ b/QtVsTools.Package/QtMsBuild/QtProjectTracker.cs
@@ -29,41 +29,41 @@
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks.Dataflow;
-using Microsoft.Build.Evaluation;
-using Microsoft.Build.Framework;
 using Microsoft.VisualStudio.ProjectSystem;
 using Microsoft.VisualStudio.ProjectSystem.Properties;
+using Microsoft.VisualStudio.Shell;
 using Microsoft.VisualStudio.TaskStatusCenter;
 using Microsoft.VisualStudio.Threading;
-using EnvDTE;
+using Microsoft.VisualStudio.VCProjectEngine;
+
+using Task = System.Threading.Tasks.Task;
 
 namespace QtVsTools.QtMsBuild
 {
+    using Common;
     using Core;
     using VisualStudio;
-    using Thread = System.Threading.Thread;
+
     using SubscriberAction = ActionBlock<IProjectVersionedValue<IProjectSubscriptionUpdate>>;
 
     class QtProjectTracker : Concurrent<QtProjectTracker>
     {
-        static ConcurrentDictionary<string, QtProjectTracker> _Instances;
-        static ConcurrentDictionary<string, QtProjectTracker> Instances =>
-            StaticThreadSafeInit(() => _Instances, () =>
-                _Instances = new ConcurrentDictionary<string, QtProjectTracker>());
+        static LazyFactory StaticLazy { get; } = new LazyFactory();
 
-        static PunisherQueue<QtProjectTracker> _InitQueue;
-        static PunisherQueue<QtProjectTracker> InitQueue =>
-            StaticThreadSafeInit(() => _InitQueue, () =>
-                _InitQueue = new PunisherQueue<QtProjectTracker>());
+        static ConcurrentDictionary<string, QtProjectTracker> Instances => StaticLazy.Get(() =>
+            Instances, () => new ConcurrentDictionary<string, QtProjectTracker>());
 
-        static IVsTaskStatusCenterService _StatusCenter;
-        static IVsTaskStatusCenterService StatusCenter => StaticThreadSafeInit(() => _StatusCenter,
-                () => _StatusCenter = VsServiceProvider
-                    .GetService<SVsTaskStatusCenterService, IVsTaskStatusCenterService>());
+        static PunisherQueue<QtProjectTracker> InitQueue => StaticLazy.Get(() =>
+            InitQueue, () => new PunisherQueue<QtProjectTracker>());
+
+        static IVsTaskStatusCenterService StatusCenter => StaticLazy.Get(() =>
+            StatusCenter, () => VsServiceProvider
+                .GetService<SVsTaskStatusCenterService, IVsTaskStatusCenterService>());
 
         static Task InitDispatcher { get; set; }
         static ITaskHandler2 InitStatus { get; set; }
@@ -75,73 +75,37 @@
             Initialized = new EventWaitHandle(false, EventResetMode.ManualReset);
         }
 
-        class Subscriber : IDisposable
-        {
-            public Subscriber(QtProjectTracker tracker, ConfiguredProject config)
-            {
-                Tracker = tracker;
-                Config = config;
-                Subscription = Config.Services.ProjectSubscription.JointRuleSource.SourceBlock
-                    .LinkTo(new SubscriberAction(ProjectUpdateAsync),
-                        ruleNames: new[]
-                        {
-                            "ClCompile",
-                            "QtRule10_Settings",
-                            "QtRule30_Moc",
-                            "QtRule40_Rcc",
-                            "QtRule60_Repc",
-                            "QtRule50_Uic",
-                            "QtRule_Translation",
-                            "QtRule70_Deploy",
-                        },
-                        initialDataAsNew: false
-                    );
-            }
-
-            QtProjectTracker Tracker { get; set; }
-            ConfiguredProject Config { get; set; }
-            IDisposable Subscription { get; set; }
-
-            public void Dispose()
-            {
-                Subscription?.Dispose();
-                Subscription = null;
-            }
-
-            async Task ProjectUpdateAsync(IProjectVersionedValue<IProjectSubscriptionUpdate> update)
-            {
-                await Tracker.OnProjectUpdateAsync(Config, update.Value);
-            }
-        }
-
         public EnvDTE.Project Project { get; private set; }
+        public string ProjectPath { get; private set; }
+        public VCProject VcProject { get; private set; }
         public UnconfiguredProject UnconfiguredProject { get; private set; }
-        public EventWaitHandle Initialized { get; private set; }
-        List<Subscriber> Subscribers { get; set; }
+        public EventWaitHandle Initialized { get; }
 
-        public static bool IsTracked(EnvDTE.Project project)
+        public static bool IsTracked(string projectPath)
         {
-            return Instances.ContainsKey(project.FullName);
+            return Instances.ContainsKey(projectPath);
         }
 
         public static void Add(EnvDTE.Project project)
         {
             if (!QtVsToolsPackage.Instance.Options.ProjectTracking)
                 return;
-            Get(project);
+
+            ThreadHelper.ThrowIfNotOnUIThread();
+            Get(project, project.FullName);
         }
 
-        public static QtProjectTracker Get(EnvDTE.Project project)
+        public static QtProjectTracker Get(EnvDTE.Project project, string projectPath)
         {
             lock (StaticCriticalSection) {
-                QtProjectTracker tracker = null;
-                if (Instances.TryGetValue(project.FullName, out tracker))
+                if (Instances.TryGetValue(projectPath, out QtProjectTracker tracker))
                     return tracker;
                 tracker = new QtProjectTracker
                 {
                     Project = project,
+                    ProjectPath = projectPath
                 };
-                Instances[project.FullName] = tracker;
+                Instances[projectPath] = tracker;
                 InitQueue.Enqueue(tracker);
                 if (InitDispatcher == null)
                     InitDispatcher = Task.Run(InitDispatcherLoopAsync);
@@ -162,14 +126,17 @@
             while (!QtVsToolsPackage.Instance.Zombied) {
                 while (InitQueue.IsEmpty)
                     await Task.Delay(100);
-                QtProjectTracker tracker;
-                if (InitQueue.TryDequeue(out tracker)) {
+                if (InitQueue.TryDequeue(out QtProjectTracker tracker)) {
                     if (InitStatus == null) {
-                        await QtVsToolsPackage.Instance.JoinableTaskFactory.SwitchToMainThreadAsync();
+                        await QtVsToolsPackage.Instance.JoinableTaskFactory
+                            .SwitchToMainThreadAsync();
                         tracker.BeginInitStatus();
                         await TaskScheduler.Default;
                     } else {
+                        await QtVsToolsPackage.Instance.JoinableTaskFactory
+                            .SwitchToMainThreadAsync();
                         tracker.UpdateInitStatus(0);
+                        await TaskScheduler.Default;
                     }
                     await tracker.InitializeAsync();
                 }
@@ -187,9 +154,12 @@
         async Task InitializeAsync()
         {
             int p = 0;
+            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
             UpdateInitStatus(p += 10);
 
-            await QtVsToolsPackage.Instance.JoinableTaskFactory.SwitchToMainThreadAsync();
+            VcProject = Project.Object as VCProject;
+            if (VcProject == null)
+                return;
             UpdateInitStatus(p += 10);
 
             var context = Project.Object as IVsBrowseObjectContext;
@@ -211,57 +181,23 @@
 
             Initialized.Set();
 
-            Subscribers = new List<Subscriber>();
             int n = configs.Count;
             int d = (100 - p) / (n * 2);
             foreach (var config in configs) {
                 var configProject = await UnconfiguredProject.LoadConfiguredProjectAsync(config);
                 UpdateInitStatus(p += d);
-                Subscribers.Add(new Subscriber(this, configProject));
-                configProject.ProjectUnloading += OnProjectUnloading;
+                configProject.ProjectUnloading += OnProjectUnloadingAsync;
                 if (QtVsToolsPackage.Instance.Options.BuildDebugInformation) {
                     Messages.Print(string.Format(
                         "{0:HH:mm:ss.FFF} QtProjectTracker({1}): Started tracking [{2}] {3}",
                         DateTime.Now, Thread.CurrentThread.ManagedThreadId,
-                        config.Name,
-                        UnconfiguredProject.FullPath));
+                        config.Name, ProjectPath));
                 }
                 UpdateInitStatus(p += d);
             }
         }
 
-
-        async Task OnProjectUpdateAsync(ConfiguredProject config, IProjectSubscriptionUpdate update)
-        {
-            var changes = update.ProjectChanges.Values
-                .Where(x => x.Difference.AnyChanges)
-                .Select(x => x.Difference);
-            var changesCount = changes
-                .Select(x => x.AddedItems.Count
-                    + x.ChangedItems.Count
-                    + x.ChangedProperties.Count
-                    + x.RemovedItems.Count
-                    + x.RenamedItems.Count)
-                .Sum();
-            var changedProps = changes.SelectMany(x => x.ChangedProperties);
-            if (changesCount == 0
-                || (changesCount == 1
-                    && changedProps.Count() == 1
-                    && changedProps.First() == "QtLastBackgroundBuild")) {
-                return;
-            }
-
-            if (QtVsToolsPackage.Instance.Options.BuildDebugInformation) {
-                Messages.Print(string.Format(
-                    "{0:HH:mm:ss.FFF} QtProjectTracker({1}): Changed [{2}] {3}",
-                    DateTime.Now, Thread.CurrentThread.ManagedThreadId,
-                    config.ProjectConfiguration.Name,
-                    config.UnconfiguredProject.FullPath));
-            }
-            await QtProjectIntellisense.RefreshAsync(Project, config.ProjectConfiguration.Name);
-        }
-
-        async Task OnProjectUnloading(object sender, EventArgs args)
+        async Task OnProjectUnloadingAsync(object sender, EventArgs args)
         {
             var project = sender as ConfiguredProject;
             if (project == null || project.Services == null)
@@ -274,18 +210,16 @@
                     project.UnconfiguredProject.FullPath));
             }
             lock (CriticalSection) {
-                if (Subscribers != null) {
-                    Subscribers.ForEach(s => s.Dispose());
-                    Subscribers.Clear();
-                    Subscribers = null;
-                }
-                project.ProjectUnloading -= OnProjectUnloading;
-                Instances.TryRemove(Project.FullName, out QtProjectTracker tracker);
+                project.ProjectUnloading -= OnProjectUnloadingAsync;
+                Instances.TryRemove(project.UnconfiguredProject.FullPath, out QtProjectTracker _);
             }
+            await Task.Yield();
         }
 
         void BeginInitStatus()
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             lock (StaticCriticalSection) {
                 if (InitStatus != null)
                     return;
@@ -303,9 +237,8 @@
                             PercentComplete = 0
                         })
                         as ITaskHandler2;
-                } catch (Exception e) {
-                    Messages.Print(
-                        e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
+                } catch (Exception exception) {
+                    exception.Log();
                 }
                 InitStatus.RegisterTask(new Task(() => throw new InvalidOperationException()));
             }
@@ -320,13 +253,12 @@
                     InitStatus.Progress.Report(new TaskProgressData
                     {
                         ProgressText = string.Format("{0} ({1} project(s) remaining)",
-                            Project.Name, InitQueue.Count),
+                            Path.GetFileNameWithoutExtension(ProjectPath), InitQueue.Count),
                         CanBeCanceled = true,
                         PercentComplete = percentComplete
                     });
-                } catch (Exception e) {
-                    Messages.Print(
-                        e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
+                } catch (Exception exception) {
+                    exception.Log();
                 }
             }
         }
diff --git a/QtVsTools.Package/QtMsBuild/QtVersionProvider.cs b/QtVsTools.Package/QtMsBuild/QtVersionProvider.cs
index f9626ca..4fd6db9 100644
--- a/QtVsTools.Package/QtMsBuild/QtVersionProvider.cs
+++ b/QtVsTools.Package/QtMsBuild/QtVersionProvider.cs
@@ -57,7 +57,6 @@
 
         public async Task<ICollection<IEnumValue>> GetListedValuesAsync()
         {
-            List<IEnumValue> values = new List<IEnumValue>();
             using (var qtVersions = Registry.CurrentUser.OpenSubKey(@"Software\Digia\Versions")) {
 
                 return await Task.FromResult(
diff --git a/QtVsTools.Package/QtVsTools.Icons.pkgdef b/QtVsTools.Package/QtVsTools.Icons.pkgdef
new file mode 100644
index 0000000..5bc4660
--- /dev/null
+++ b/QtVsTools.Package/QtVsTools.Icons.pkgdef
@@ -0,0 +1,20 @@
+[$RootKey$\ShellFileAssociations\.prf]
+"DefaultIconMoniker"="0d2e443f-6dbb-4001-99dc-9cd7d5c924e7:0"
+
+[$RootKey$\ShellFileAssociations\.pri]
+"DefaultIconMoniker"="0d2e443f-6dbb-4001-99dc-9cd7d5c924e7:1"
+
+[$RootKey$\ShellFileAssociations\.pro]
+"DefaultIconMoniker"="0d2e443f-6dbb-4001-99dc-9cd7d5c924e7:2"
+
+[$RootKey$\ShellFileAssociations\.qml]
+"DefaultIconMoniker"="0d2e443f-6dbb-4001-99dc-9cd7d5c924e7:3"
+
+[$RootKey$\ShellFileAssociations\.qrc]
+"DefaultIconMoniker"="0d2e443f-6dbb-4001-99dc-9cd7d5c924e7:4"
+
+[$RootKey$\ShellFileAssociations\.ts]
+"DefaultIconMoniker"="0d2e443f-6dbb-4001-99dc-9cd7d5c924e7:5"
+
+[$RootKey$\ShellFileAssociations\.ui]
+"DefaultIconMoniker"="0d2e443f-6dbb-4001-99dc-9cd7d5c924e7:6"
diff --git a/QtVsTools.Package/QtVsTools.Package.csproj b/QtVsTools.Package/QtVsTools.Package.csproj
index 270b6c9..e57b845 100644
--- a/QtVsTools.Package/QtVsTools.Package.csproj
+++ b/QtVsTools.Package/QtVsTools.Package.csproj
@@ -90,59 +90,45 @@
     <Reference Include="System.Data" />
     <Reference Include="System.Design" />
     <Reference Include="System.Drawing" />
+    <Reference Include="System.ComponentModel.Composition" />
+    <Reference Include="System.Xaml" />
     <Reference Include="PresentationCore" />
     <Reference Include="PresentationFramework" />
     <Reference Include="WindowsBase" />
-    <Reference Include="Microsoft.VisualStudio.ProjectSystem">
-      <HintPath>$(VsInstallRoot)\Common7\IDE\CommonExtensions\Microsoft\Project\Microsoft.VisualStudio.ProjectSystem.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.VisualStudio.Composition">
-      <HintPath>$(VsInstallRoot)\Common7\IDE\PrivateAssemblies\Microsoft.VisualStudio.Composition.dll</HintPath>
-    </Reference>
   </ItemGroup>
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
-  // Version specific references
+  // General package references
   // -->
   <Import Project="$(SolutionDir)\references.props" />
   <ItemGroup>
-    <PackageReference Include="System.ComponentModel.Composition"
-      Version="$(Version_System_ComponentModel_Composition)" />
-    <PackageReference Include="Stub.System.Data.SQLite.Core.NetFramework"
-      Version="$(Version_Stub_System_Data_SQLite_Core_NetFramework)"
-      GeneratePathProperty="true" />
-    <PackageReference Include="Newtonsoft.Json"
-      Version="$(Version_Newtonsoft_Json)" />
-    <PackageReference Include="Microsoft.Build"
-      Version="$(Version_Microsoft_Build)" />
-    <PackageReference Include="Microsoft.Build.Framework"
-      Version="$(Version_Microsoft_Build_Framework)" />
-    <PackageReference Include="Microsoft.Build.Tasks.Core"
-      Version="$(Version_Microsoft_Build_Tasks_Core)" />
-    <PackageReference Include="Microsoft.VisualStudio.SDK"
-      Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
-    <PackageReference Include="Microsoft.VSSDK.BuildTools"
-      Version="$(Version_Microsoft_VSSDK_BuildTools)" />
-    <PackageReference Include="Microsoft.VisualStudio.Shell.Framework"
-      Version="$(Version_Microsoft_VisualStudio_Shell_Framework)" />
-    <PackageReference Include="Microsoft.VisualStudio.Validation"
-      Version="$(Version_Microsoft_VisualStudio_Validation)" />
-    <PackageReference Include="$(Name_Microsoft_VisualStudio_Threading)"
-      Version="$(Version_Microsoft_VisualStudio_Threading)" />
-    <PackageReference Include="System.Collections.Immutable"
-      Version="$(Version_System_Collections_Immutable)" />
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_ProjectSystem)" Version="$(Version_Microsoft_VisualStudio_ProjectSystem)" />
+    <PackageReference Include="$(Name_Newtonsoft_Json)" Version="$(Version_Newtonsoft_Json)" />
+    <PackageReference Include="$(Name_Stub_System_Data_SQLite_Core_NetFramework)" Version="$(Version_Stub_System_Data_SQLite_Core_NetFramework)" GeneratePathProperty="true" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_Shell_15)" Version="$(Version_Microsoft_VisualStudio_Shell_15)" />
   </ItemGroup>
-  <ItemGroup Condition="'$(VisualStudioVersion)'=='17.0'">
-    <PackageReference Include="$(Name_Microsoft_VisualStudio_VCProjectEngine)"
-      Version="$(Version_Microsoft_VisualStudio_VCProjectEngine)" />
-  </ItemGroup>
-  <ItemGroup Condition="'$(VisualStudioVersion)'=='16.0'">
-    <PackageReference Include="$(Name_Microsoft_VisualStudio_VCProjectEngine)"
-      Version="$(Version_Microsoft_VisualStudio_VCProjectEngine)" />
-  </ItemGroup>
-  <ItemGroup Condition="'$(VisualStudioVersion)'=='15.0'">
-    <Reference Include="Microsoft.VisualStudio.VCProjectEngine" />
-  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+        <Reference Include="$(Name_Microsoft_VisualStudio_VCProjectEngine)" />
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Shell_Framework)" Version="$(Version_Microsoft_VisualStudio_Shell_Framework)" />
+      </ItemGroup>
+    </When>
+  </Choose>
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
   // Solution project references
@@ -173,6 +159,27 @@
       <Project>{4cee73c9-fcfa-3a72-a0a3-036bdbb3240f}</Project>
       <Name>qrceditor</Name>
       <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+    </ProjectReference>
+    <ProjectReference Include="..\Templates\qtclass\QtTemplate.Item.QtClass.csproj">
+      <Project>{4981AAE8-9AC7-4758-87EA-FB2397D6C404}</Project>
+      <Name>QtTemplate.Item.QtClass</Name>
+      <VSIXSubPath>ItemTemplates</VSIXSubPath>
+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+      <IncludeOutputGroupsInVSIX>TemplateProjectOutputGroup%3b</IncludeOutputGroupsInVSIX>
+    </ProjectReference>
+    <ProjectReference Include="..\Templates\translation\QtTemplate.Item.Translation.csproj">
+      <Project>{202F4A6D-77CD-4992-AA53-01B585463287}</Project>
+      <Name>QtTemplate.Item.Translation</Name>
+      <VSIXSubPath>ItemTemplates</VSIXSubPath>
+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+      <IncludeOutputGroupsInVSIX>TemplateProjectOutputGroup%3b</IncludeOutputGroupsInVSIX>
+    </ProjectReference>
+    <ProjectReference Include="..\Templates\widgetsclass\QtTemplate.Item.WidgetsClass.csproj">
+      <Project>{020422DA-33AB-4495-A439-7DAC2690795C}</Project>
+      <Name>QtTemplate.Item.WidgetsClass</Name>
+      <VSIXSubPath>ItemTemplates</VSIXSubPath>
+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+      <IncludeOutputGroupsInVSIX>TemplateProjectOutputGroup%3b</IncludeOutputGroupsInVSIX>
     </ProjectReference>
     <ProjectReference Include="..\vsqml\vsqml.vcxproj">
       <Project>{b12702ad-abfb-343a-a199-8e24837244a3}</Project>
@@ -303,6 +310,12 @@
       <DependsOn>$(SolutionDir)\version.targets;$(SolutionDir)\version.tt;$(SolutionDir)\common.tt</DependsOn>
       <LastGenOutput>AssemblyInfo.tt.cs</LastGenOutput>
     </T4Template>
+    <Compile Include="Legacy\ProjectQtSettings.cs" />
+    <Compile Include="Legacy\QtMenu.cs" />
+    <Compile Include="Legacy\QtOptionsPage.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Legacy\Translation.cs" />
     <Compile Include="Properties\AssemblyInfo.tt.cs">
       <AutoGen>True</AutoGen>
       <DesignTime>True</DesignTime>
@@ -321,15 +334,11 @@
       <DesignTime>True</DesignTime>
       <DependentUpon>QtMenus.vsct_TT</DependentUpon>
     </VSCTCompile>
-    <Content Include="Resources\Vsix.ico" />
     <EmbeddedResource Include="VSPackage.resx">
       <MergeWithCTO>true</MergeWithCTO>
       <ManifestResourceName>VSPackage</ManifestResourceName>
     </EmbeddedResource>
-    <Compile Include="Package\AddTranslationDialog.cs">
-      <SubType>Form</SubType>
-    </Compile>
-    <Compile Include="Package\ChangeFor.cs" />
+    <Compile Include="Legacy\ChangeFor.cs" />
     <Compile Include="Common\Concurrent.cs" />
     <Compile Include="Common\ConcurrentStopwatch.cs" />
     <Compile Include="Common\Disposable.cs" />
@@ -348,20 +357,17 @@
     <Compile Include="Editors\Editor.QtLinguist.cs" />
     <Compile Include="Editors\Editor.QtResourceEditor.cs" />
     <Compile Include="Package\ExtLoader.cs" />
-    <Compile Include="Package\FormChangeQtVersion.cs">
+    <Compile Include="Legacy\FormChangeQtVersion.cs">
       <SubType>Form</SubType>
     </Compile>
-    <Compile Include="Package\FormChangeQtVersion.Designer.cs">
+    <Compile Include="Legacy\FormChangeQtVersion.Designer.cs">
       <DependentUpon>FormChangeQtVersion.cs</DependentUpon>
     </Compile>
-    <Compile Include="Package\FormProjectQtSettings.cs">
+    <Compile Include="Legacy\FormProjectQtSettings.cs">
       <SubType>Form</SubType>
     </Compile>
-    <Compile Include="Package\FormProjectQtSettings.Designer.cs">
+    <Compile Include="Legacy\FormProjectQtSettings.Designer.cs">
       <DependentUpon>FormProjectQtSettings.cs</DependentUpon>
-    </Compile>
-    <Compile Include="Options\QtLegacyOptionsPage.cs">
-      <SubType>Component</SubType>
     </Compile>
     <Compile Include="Options\QtOptionsPage.cs">
       <SubType>Component</SubType>
@@ -372,7 +378,6 @@
     <Compile Include="Options\QtVersionsPage.cs">
       <SubType>Component</SubType>
     </Compile>
-    <Compile Include="Package\ProjectQtSettings.cs" />
     <Compile Include="Package\QMakeWrapper.cs" />
     <Compile Include="QML\Classification\QmlAsyncClassifier.cs" />
     <Compile Include="QML\Classification\QmlClassificationFormat.cs" />
@@ -437,9 +442,7 @@
     <Compile Include="Package\QtSolutionContextMenu.cs" />
     <Compile Include="Package\SR.cs" />
     <Compile Include="Package\Translation.cs" />
-    <Compile Include="Package\TranslationItem.cs" />
-    <Compile Include="VisualStudio\VsShell.cs" />
-    <Compile Include="Common\VsToolsDialogWindow.cs" />
+    <Compile Include="Package\Notifications.cs" />
     <Content Include="..\Changelog">
       <Link>Changelog</Link>
       <CopyToOutputDirectory>Always</CopyToOutputDirectory>
@@ -456,6 +459,9 @@
       <DependsOn>$(SolutionDir)\version.targets;$(SolutionDir)\version.tt;$(SolutionDir)\common.tt</DependsOn>
       <LastGenOutput>source.extension.vsixmanifest</LastGenOutput>
     </T4Template>
+    <Content Include="Icons\Monikers.imagemanifest">
+      <IncludeInVSIX>true</IncludeInVSIX>
+    </Content>
     <None Include="source.extension.vsixmanifest">
       <DependentUpon>source.extension.vsixmanifest_TT</DependentUpon>
       <SubType>Designer</SubType>
@@ -473,6 +479,16 @@
       <DependsOn>$(SolutionDir)\version.targets;$(SolutionDir)\version.tt;$(SolutionDir)\common.tt</DependsOn>
       <LastGenOutput>Overview.html</LastGenOutput>
     </T4Template>
+    <Content Include="QtVsTools.Icons.pkgdef">
+      <IncludeInVSIX>true</IncludeInVSIX>
+    </Content>
+    <Resource Include="Icons\prf32.png" />
+    <Resource Include="Icons\pri32.png" />
+    <Resource Include="Icons\pro32.png" />
+    <Resource Include="Icons\qml32.png" />
+    <Resource Include="Icons\qrc32.png" />
+    <Resource Include="Icons\ts32.png" />
+    <Resource Include="Icons\ui32.png" />
     <Content Include="Marketplace\Overview.html">
       <AutoGen>True</AutoGen>
       <DesignTime>True</DesignTime>
@@ -499,6 +515,10 @@
       <IncludeInVSIX>true</IncludeInVSIX>
       <SubType>Designer</SubType>
     </Content>
+    <Content Include="qt6modules.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+      <IncludeInVSIX>true</IncludeInVSIX>
+    </Content>
     <Content Include="QtVsTools.ico" />
     <Content Include="QtVsTools.Qml.Debug.pkgdef">
       <CopyToOutputDirectory>Always</CopyToOutputDirectory>
@@ -509,14 +529,12 @@
       <CopyToOutputDirectory>Always</CopyToOutputDirectory>
       <IncludeInVSIX>true</IncludeInVSIX>
     </Content>
-    <EmbeddedResource Include="Package\AddTranslationDialog.resx">
-      <DependentUpon>AddTranslationDialog.cs</DependentUpon>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Package\FormChangeQtVersion.resx">
+    <EmbeddedResource Include="Legacy\FormChangeQtVersion.resx">
       <DependentUpon>FormChangeQtVersion.cs</DependentUpon>
     </EmbeddedResource>
-    <EmbeddedResource Include="Package\FormProjectQtSettings.resx">
+    <EmbeddedResource Include="Legacy\FormProjectQtSettings.resx">
       <DependentUpon>FormProjectQtSettings.cs</DependentUpon>
+      <SubType>Designer</SubType>
     </EmbeddedResource>
     <EmbeddedResource Include="Resources.resx">
       <SubType>Designer</SubType>
@@ -546,8 +564,8 @@
     </Page>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
   <Import Project="$(SolutionDir)\transform.targets" />
+  <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
   <Target Name="QtVsTools_PostBuild" AfterTargets="Build">
     <Error Condition="!Exists('$(TargetPath)')" Text="Build failed." />
     <PropertyGroup>
@@ -602,19 +620,13 @@
   /////////////////////////////////////////////////////////////////////////////////////////////////
   // NuGet native libs
   // -->
-  <PropertyGroup
-    Condition="'$(PkgStub_System_Data_SQLite_Core_NetFramework)' != ''">
-    <SQLitePkgDir Condition="'$(SQLitePkgDir)' == ''"
-      >$(PkgStub_System_Data_SQLite_Core_NetFramework)</SQLitePkgDir>
+  <PropertyGroup Condition="'$(PkgStub_System_Data_SQLite_Core_NetFramework)' != ''">
+    <SQLitePkgDir Condition="'$(SQLitePkgDir)' == ''">$(PkgStub_System_Data_SQLite_Core_NetFramework)</SQLitePkgDir>
   </PropertyGroup>
-  <PropertyGroup
-    Condition="'$(PkgStub_System_Data_SQLite_Core_NetFramework)' == ''">
-    <NuGetGlobalPkgDir Condition="'$(NuGetGlobalPkgDir)' == ''"
-      >$(USERPROFILE)\.nuget\packages</NuGetGlobalPkgDir>
-    <SQLitePkgRoot
-      >$(NuGetGlobalPkgDir)\Stub.System.Data.SQLite.Core.NetFramework</SQLitePkgRoot>
-    <SQLitePkgDir Condition="'$(SQLitePkgDir)' == ''"
-      >$(SQLitePkgRoot)\$(Version_Stub_System_Data_SQLite_Core_NetFramework)</SQLitePkgDir>
+  <PropertyGroup Condition="'$(PkgStub_System_Data_SQLite_Core_NetFramework)' == ''">
+    <NuGetGlobalPkgDir Condition="'$(NuGetGlobalPkgDir)' == ''">$(USERPROFILE)\.nuget\packages</NuGetGlobalPkgDir>
+    <SQLitePkgRoot>$(NuGetGlobalPkgDir)\Stub.System.Data.SQLite.Core.NetFramework</SQLitePkgRoot>
+    <SQLitePkgDir Condition="'$(SQLitePkgDir)' == ''">$(SQLitePkgRoot)\$(Version_Stub_System_Data_SQLite_Core_NetFramework)</SQLitePkgDir>
   </PropertyGroup>
   <ItemGroup>
     <Content Include="$(SQLitePkgDir)\build\net46\x64\SQLite.Interop.dll">
diff --git a/QtVsTools.Package/QtVsToolsPackage.cs b/QtVsTools.Package/QtVsToolsPackage.cs
index aad01be..93325f3 100644
--- a/QtVsTools.Package/QtVsToolsPackage.cs
+++ b/QtVsTools.Package/QtVsToolsPackage.cs
@@ -27,20 +27,14 @@
 ****************************************************************************/
 
 using System;
-using System.ComponentModel.Design;
 using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
 using System.IO;
 using System.Linq;
 using System.Net.Http;
 using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading.Tasks;
-using Task = System.Threading.Tasks.Task;
-using System.Windows.Forms;
 using Microsoft.VisualStudio;
-using Microsoft.VisualStudio.OLE.Interop;
 using Microsoft.VisualStudio.Settings;
 using Microsoft.VisualStudio.Shell;
 using Microsoft.VisualStudio.Shell.Interop;
@@ -49,13 +43,15 @@
 using Microsoft.Win32;
 using EnvDTE;
 
+using Task = System.Threading.Tasks.Task;
+
 namespace QtVsTools
 {
     using Core;
     using QtMsBuild;
-    using SyntaxAnalysis;
-    using static SyntaxAnalysis.RegExpr;
     using VisualStudio;
+
+    using static SyntaxAnalysis.RegExpr;
 
     [Guid(QtVsToolsPackage.PackageGuidString)]
     [InstalledProductRegistration("#110", "#112", Version.PRODUCT_VERSION, IconResourceID = 400)]
@@ -97,7 +93,7 @@
         "Qt", "Versions", 0, 0, true, Sort = 1)]
 
     // Legacy options page
-    [ProvideOptionPage(typeof(Options.QtLegacyOptionsPage),
+    [ProvideOptionPage(typeof(Legacy.QtOptionsPage),
         "Qt", "Legacy Project Format", 0, 0, true, Sort = 2)]
 
     public sealed class QtVsToolsPackage : AsyncPackage, IVsServiceProvider, IProjectTracker
@@ -109,13 +105,13 @@
         public string PkgInstallPath { get; private set; }
         public Options.QtOptionsPage Options
             => GetDialogPage(typeof(Options.QtOptionsPage)) as Options.QtOptionsPage;
-        public Options.QtLegacyOptionsPage LegacyOptions
-            => GetDialogPage(typeof(Options.QtLegacyOptionsPage)) as Options.QtLegacyOptionsPage;
+        public Legacy.QtOptionsPage LegacyOptions
+            => GetDialogPage(typeof(Legacy.QtOptionsPage)) as Legacy.QtOptionsPage;
         public Editors.QtDesigner QtDesigner { get; private set; }
         public Editors.QtLinguist QtLinguist { get; private set; }
-        public Editors.QtResourceEditor QtResourceEditor { get; private set; }
+        private Editors.QtResourceEditor QtResourceEditor { get; set; }
 
-        static EventWaitHandle initDone = new EventWaitHandle(false, EventResetMode.ManualReset);
+        static readonly EventWaitHandle initDone = new EventWaitHandle(false, EventResetMode.ManualReset);
 
         static QtVsToolsPackage instance = null;
         public static QtVsToolsPackage Instance
@@ -167,7 +163,6 @@
                 var timeInitBegin = initTimer.Elapsed;
                 VsServiceProvider.Instance = instance = this;
                 QtProject.ProjectTracker = this;
-                Messages.JoinableTaskFactory = JoinableTaskFactory;
 
                 // determine the package installation directory
                 var uri = new Uri(System.Reflection.Assembly
@@ -180,7 +175,7 @@
                 await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
                 var timeUiThreadBegin = initTimer.Elapsed;
 
-                if ((Dte = VsServiceProvider.GetService<DTE>()) == null)
+                if ((Dte = await VsServiceProvider.GetServiceAsync<DTE>()) == null)
                     throw new Exception("Unable to get service: DTE");
 
                 QtVSIPSettings.Options = Options;
@@ -188,14 +183,14 @@
                 eventHandler = new DteEventsHandler(Dte);
 
                 Qml.Debug.Launcher.Initialize();
-                QtMainMenu.Initialize(this);
-                QtSolutionContextMenu.Initialize(this);
-                QtProjectContextMenu.Initialize(this);
-                QtItemContextMenu.Initialize(this);
+                QtMainMenu.Initialize();
+                QtSolutionContextMenu.Initialize();
+                QtProjectContextMenu.Initialize();
+                QtItemContextMenu.Initialize();
                 RegisterEditorFactory(QtDesigner = new Editors.QtDesigner());
                 RegisterEditorFactory(QtLinguist = new Editors.QtLinguist());
                 RegisterEditorFactory(QtResourceEditor = new Editors.QtResourceEditor());
-                QtHelp.Initialize(this);
+                QtHelp.Initialize();
 
                 if (!string.IsNullOrEmpty(VsShell.InstallRootDir))
                     HelperFunctions.VCPath = Path.Combine(VsShell.InstallRootDir, "VC");
@@ -209,9 +204,11 @@
                 var timeUiThreadEnd = initTimer.Elapsed;
 
                 var vm = QtVersionManager.The(initDone);
-                var error = string.Empty;
-                if (vm.HasInvalidVersions(out error))
+                if (vm.HasInvalidVersions(out string error, out bool defaultInvalid)) {
+                    if (defaultInvalid)
+                        vm.SetLatestQtVersionAsDefault();
                     Messages.Print(error);
+                }
 
                 ///////////
                 // Install Qt/MSBuild files from package folder to standard location
@@ -306,9 +303,8 @@
     ================================================================",
                         urlDownloadQtIo, devRelease));
                 }
-            } catch (Exception e) {
-                Messages.Print(
-                    e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
+            } catch (Exception exception) {
+                exception.Log();
             } finally {
                 initDone.Set();
                 initTimer.Stop();
@@ -326,11 +322,35 @@
                 eventHandler.SolutionEvents_Opened();
         }
 
+        bool TestVersionInstalled()
+        {
+            bool newVersion = false;
+            string versionFile = Path.Combine(PkgInstallPath, "lastversion.txt");
+            if (File.Exists(versionFile)) {
+                string lastVersion = File.ReadAllText(versionFile);
+                newVersion = (lastVersion!= Version.PRODUCT_VERSION);
+            } else {
+                newVersion = true;
+            }
+            if (newVersion)
+                File.WriteAllText(versionFile, Version.PRODUCT_VERSION);
+            return newVersion;
+        }
+
+        public void VsMainWindowActivated()
+        {
+            if (QtVersionManager.The().GetVersions()?.Length == 0)
+                Notifications.NoQtVersion.Show();
+            if (Options.NotifyInstalled && TestVersionInstalled())
+                Notifications.NotifyInstall.Show();
+        }
+
         protected override int QueryClose(out bool canClose)
         {
-            if (eventHandler != null) {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            if (eventHandler != null)
                 eventHandler.Disconnect();
-            }
             return base.QueryClose(out canClose);
         }
 
@@ -381,14 +401,15 @@
 
                 File.WriteAllText(Path.Combine(visualizersPath, natvisFile),
                     natvis, System.Text.Encoding.UTF8);
-            } catch (Exception e) {
-                Messages.Print(
-                    e.Message + "\r\n\r\nStacktrace:\r\n" + e.StackTrace);
+            } catch (Exception exception) {
+                exception.Log();
             }
         }
 
         public string GetNatvisPath()
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
             try {
                 using (var vsRootKey = Registry.CurrentUser.OpenSubKey(Dte.RegistryRoot)) {
                     if (vsRootKey.GetValue("VisualStudioLocation") is string vsLocation)
@@ -433,6 +454,7 @@
 
         void IProjectTracker.AddProject(Project project)
         {
+            ThreadHelper.ThrowIfNotOnUIThread();
             QtProjectTracker.Add(project);
         }
 
diff --git a/QtVsTools.Package/Resources.resx b/QtVsTools.Package/Resources.resx
index 4c63e0b..cee5e85 100644
--- a/QtVsTools.Package/Resources.resx
+++ b/QtVsTools.Package/Resources.resx
@@ -117,24 +117,6 @@
   <resheader name="writer">
     <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
-  <data name="ActionDialog_Properties" xml:space="preserve">
-    <value>Properties</value>
-  </data>
-  <data name="AddQtVersionDialog_IncorrectMakefileGenerator" xml:space="preserve">
-    <value>This Qt version uses an unsupported makefile generator (used: {0}, supported: MSVC.NET, MSBUILD)</value>
-  </data>
-  <data name="AddTranslationDialog_FileName" xml:space="preserve">
-    <value>Filename:</value>
-  </data>
-  <data name="AddTranslationDialog_Language" xml:space="preserve">
-    <value>Language:</value>
-  </data>
-  <data name="AddTranslationDialog_Title" xml:space="preserve">
-    <value>Add Translation</value>
-  </data>
-  <data name="Cancel" xml:space="preserve">
-    <value>&amp;Cancel</value>
-  </data>
   <data name="CannotFindQMake" xml:space="preserve">
     <value>Cannot find qmake. Make sure you have specified a Qt version.</value>
   </data>
@@ -175,32 +157,11 @@
   <data name="ImportPriFileNotResolved" xml:space="preserve">
     <value>--- (importing .pri file) file: {0} cannot be resolved. Skipping file.</value>
   </data>
-  <data name="InstalledQtVersions" xml:space="preserve">
-    <value>Installed Qt Versions</value>
-  </data>
   <data name="NoProjectOpened" xml:space="preserve">
     <value>No Project Opened</value>
   </data>
-  <data name="OK" xml:space="preserve">
-    <value>&amp;OK</value>
-  </data>
-  <data name="IncompatibleMacros" xml:space="preserve">
-    <value>The following macros are not compatible: {0}</value>
-  </data>
-  <data name="ProjectQtSettingsButtonText" xml:space="preserve">
-    <value>Qt Project Settings</value>
-  </data>
-  <data name="ProjectQtVersion" xml:space="preserve">
-    <value>Set Project's Qt Version</value>
-  </data>
   <data name="ProjectQtVersionNotFoundError" xml:space="preserve">
     <value>There's no Qt version assigned to project {0} for configuration {1}/{2}. Please use the 'Qt Project Settings' editor to change the 'Version' to a valid Qt version for this platform.</value>
-  </data>
-  <data name="QtModules" xml:space="preserve">
-    <value>Qt Modules</value>
-  </data>
-  <data name="SolutionQtVersion" xml:space="preserve">
-    <value>Set Solution's Qt Version</value>
   </data>
   <data name="ExportProject_ImportPriFile" xml:space="preserve">
     <value>Import from .pri File</value>
diff --git a/QtVsTools.Package/qt5.natvis.xml b/QtVsTools.Package/qt5.natvis.xml
index 237fbd9..fc3e557 100644
--- a/QtVsTools.Package/qt5.natvis.xml
+++ b/QtVsTools.Package/qt5.natvis.xml
@@ -224,14 +224,41 @@
     </Type>
 
     <Type Name="##NAMESPACE##::QString">
-        <DisplayString>{((reinterpret_cast&lt;unsigned short*&gt;(d)) + d->offset / 2),sub}</DisplayString>
-        <StringView>((reinterpret_cast&lt;unsigned short*&gt;(d)) + d->offset / 2),sub</StringView>
+        <DisplayString>{((reinterpret_cast&lt;unsigned short*&gt;(d)) + d-&gt;offset / 2),sub}</DisplayString>
+        <StringView>((reinterpret_cast&lt;unsigned short*&gt;(d)) + d-&gt;offset / 2),sub</StringView>
         <Expand>
             <Item Name="[size]">d-&gt;size</Item>
             <Item Name="[referenced]">d-&gt;ref.atomic._q_value</Item>
             <ArrayItems>
                 <Size>d-&gt;size</Size>
-                <ValuePointer>((reinterpret_cast&lt;unsigned short*&gt;(d)) + d->offset / 2),c</ValuePointer>
+                <ValuePointer>((reinterpret_cast&lt;unsigned short*&gt;(d)) + d-&gt;offset / 2),c</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QStringRef">
+        <Intrinsic Name="offset" Expression="(reinterpret_cast&lt;char16_t*&gt;(m_string-&gt;d))
+            + m_string-&gt;d->offset / 2" />
+        <DisplayString Condition="m_string == nullptr">{m_string,[m_size]} u""</DisplayString>
+        <DisplayString Condition="m_string != nullptr">{offset() + m_position,[m_size]}</DisplayString>
+        <Expand>
+            <Item Name="[position]" ExcludeView="simple">m_position</Item>
+            <Item Name="[size]" ExcludeView="simple">m_size</Item>
+            <ArrayItems Condition="m_string != nullptr">
+                <Size>m_size</Size>
+                <ValuePointer>offset()+m_position</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QStringView">
+        <DisplayString>{m_data,[m_size]}</DisplayString>
+        <StringView>m_data,[m_size]</StringView>
+        <Expand>
+            <Item Name="[size]" ExcludeView="simple">m_size</Item>
+            <ArrayItems>
+                <Size>m_size</Size>
+                <ValuePointer>m_data</ValuePointer>
             </ArrayItems>
         </Expand>
     </Type>
@@ -264,8 +291,8 @@
         <Intrinsic Name="query" Expression="*((QString*)(((char*)(d) + memberOffset(5))))" />
         <Intrinsic Name="fragment" Expression="*((QString*)(((char*)(d) + memberOffset(6))))" />
 
-        <DisplayString Condition="!isEmpty(scheme().d->size)">{scheme()}://{host()}{path()}</DisplayString>
-        <DisplayString Condition="isEmpty(scheme().d->size)">{path()}</DisplayString>
+        <DisplayString Condition="!isEmpty(scheme().d-&gt;size)">{scheme()}://{host()}{path()}</DisplayString>
+        <DisplayString Condition="isEmpty(scheme().d-&gt;size)">{path()}</DisplayString>
         <Expand>
             <Item Name="[scheme]">scheme()</Item>
             <Item Name="[username]">username()</Item>
@@ -424,8 +451,8 @@
             <IndexListItems>
                 <Size>d-&gt;end - d-&gt;begin</Size>
                 <ValueNode>*reinterpret_cast&lt;$T1*&gt;((sizeof($T1) &gt; sizeof(void*))
-                    ? reinterpret_cast&lt;Node*&gt;(d->array + d->begin + $i)->v
-                    : reinterpret_cast&lt;$T1*&gt;(d->array + d->begin + $i))
+                    ? reinterpret_cast&lt;Node*&gt;(d-&gt;array + d-&gt;begin + $i)-&gt;v
+                    : reinterpret_cast&lt;$T1*&gt;(d-&gt;array + d-&gt;begin + $i))
                 </ValueNode>
             </IndexListItems>
         </Expand>
@@ -439,8 +466,8 @@
                 <Size>d-&gt;end - d-&gt;begin</Size>
                 <ValueNode>
                     *reinterpret_cast&lt;QString*&gt;((sizeof(QString) &gt; sizeof(void*))
-                    ? reinterpret_cast&lt;Node*&gt;(d->array + d->begin + $i)->v
-                    : reinterpret_cast&lt;QString*&gt;(d->array + d->begin + $i))
+                    ? reinterpret_cast&lt;Node*&gt;(d-&gt;array + d-&gt;begin + $i)-&gt;v
+                    : reinterpret_cast&lt;QString*&gt;(d-&gt;array + d-&gt;begin + $i))
                 </ValueNode>
             </IndexListItems>
         </Expand>
@@ -454,8 +481,8 @@
                 <Size>d-&gt;end - d-&gt;begin</Size>
                 <ValueNode>
                     *reinterpret_cast&lt;QVariant*&gt;((sizeof(QVariant) &gt; sizeof(void*))
-                    ? reinterpret_cast&lt;Node*&gt;(d->array + d->begin + $i)->v
-                    : reinterpret_cast&lt;QVariant*&gt;(d->array + d->begin + $i))
+                    ? reinterpret_cast&lt;Node*&gt;(d-&gt;array + d-&gt;begin + $i)-&gt;v
+                    : reinterpret_cast&lt;QVariant*&gt;(d-&gt;array + d-&gt;begin + $i))
                 </ValueNode>
             </IndexListItems>
         </Expand>
@@ -526,7 +553,7 @@
                     <Exec>node = *(bucket++)</Exec>
                     <Exec>--n</Exec>
                     <Loop>
-                        <Break Condition="!node || !node->next"/>
+                        <Break Condition="!node || !node-&gt;next"/>
                         <Exec>keyValuePair = reinterpret_cast&lt;Node *&gt;(node)</Exec>
                         <Item Name="[{keyValuePair-&gt;key}]">keyValuePair-&gt;value</Item>
                         <Exec>node = node-&gt;next</Exec>
diff --git a/QtVsTools.Package/qt6.natvis.xml b/QtVsTools.Package/qt6.natvis.xml
index 5274053..18c7adf 100644
--- a/QtVsTools.Package/qt6.natvis.xml
+++ b/QtVsTools.Package/qt6.natvis.xml
@@ -259,7 +259,34 @@
         </Expand>
     </Type>
 
-   <Type Name="##NAMESPACE##::QByteArray">
+    <Type Name="##NAMESPACE##::QStringRef">
+        <DisplayString Condition="m_string == nullptr">{m_string,[m_size]} u""</DisplayString>
+        <DisplayString Condition="m_string != nullptr">{m_string-&gt;d.ptr+m_position,[m_size]}</DisplayString>
+        <StringView Condition="m_string == nullptr">""</StringView>
+        <StringView Condition="m_string != nullptr">m_string,[m_position+m_size]</StringView>
+        <Expand>
+            <Item Name="[position]" ExcludeView="simple">m_position</Item>
+            <Item Name="[size]" ExcludeView="simple">m_size</Item>
+            <ArrayItems Condition="m_string != nullptr">
+                <Size>m_size</Size>
+                <ValuePointer>m_string-&gt;d.ptr+m_position</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QStringView">
+        <DisplayString>{m_data,[m_size]}</DisplayString>
+        <StringView>m_data,[m_size]</StringView>
+        <Expand>
+            <Item Name="[size]" ExcludeView="simple">m_size</Item>
+            <ArrayItems>
+                <Size>m_size</Size>
+                <ValuePointer>m_data</ValuePointer>
+            </ArrayItems>
+        </Expand>
+    </Type>
+
+    <Type Name="##NAMESPACE##::QByteArray">
         <DisplayString>&quot;{((reinterpret_cast&lt;char*&gt;(d.ptr))),sb}&quot;</DisplayString>
         <StringView>((reinterpret_cast&lt;char*&gt;(d.ptr))),sb</StringView>
         <Expand>
@@ -286,8 +313,8 @@
         <Intrinsic Name="query" Expression="*((QString*)(((char*)(d) + memberOffset(5))))" />
         <Intrinsic Name="fragment" Expression="*((QString*)(((char*)(d) + memberOffset(6))))" />
 
-        <DisplayString Condition="!isEmpty(scheme().d->size)">{scheme()}://{host()}{path()}</DisplayString>
-        <DisplayString Condition="isEmpty(scheme().d->size)">{path()}</DisplayString>
+        <DisplayString Condition="!isEmpty(scheme().d-&gt;size)">{scheme()}://{host()}{path()}</DisplayString>
+        <DisplayString Condition="isEmpty(scheme().d-&gt;size)">{path()}</DisplayString>
         <Expand>
             <Item Name="[scheme]">scheme()</Item>
             <Item Name="[username]">username()</Item>
diff --git a/QtVsTools.Package/qt6modules.xml b/QtVsTools.Package/qt6modules.xml
new file mode 100644
index 0000000..1754d1a
--- /dev/null
+++ b/QtVsTools.Package/qt6modules.xml
@@ -0,0 +1,510 @@
+<?xml version="1.0" encoding="utf-8"?>
+<QtVsTools>
+
+  <!-- Qt Essentials -->
+
+  <Module Id="1">
+    <Name>Qt Core</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtCore</LibraryPrefix>
+    <proVarQT>core</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtCore</IncludePath>
+    <Defines>QT_CORE_LIB</Defines>
+    <Tag>Essential</Tag>
+  </Module>
+  <Module Id="2">
+    <Name>Qt D-Bus</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtDBus</LibraryPrefix>
+    <proVarQT>dbus</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtDBus</IncludePath>
+    <Defines>QT_DBUS_LIB</Defines>
+    <Tag>Essential</Tag>
+  </Module>
+  <Module Id="3">
+    <Name>Qt GUI</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtGui</LibraryPrefix>
+    <proVarQT>gui</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtGui</IncludePath>
+    <Defines>QT_GUI_LIB</Defines>
+    <Tag>Essential</Tag>
+  </Module>
+  <Module Id="4">
+    <Name>Qt Network</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtNetwork</LibraryPrefix>
+    <proVarQT>network</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtNetwork</IncludePath>
+    <Defines>QT_NETWORK_LIB</Defines>
+    <Tag>Essential</Tag>
+  </Module>
+  <Module Id="5">
+    <Name>Qt QML</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtQml</LibraryPrefix>
+    <proVarQT>qml</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtQml</IncludePath>
+    <Defines>QT_QML_LIB</Defines>
+    <Tag>Essential</Tag>
+  </Module>
+  <Module Id="6">
+    <Name>Qt Quick</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtQuick</LibraryPrefix>
+    <proVarQT>quick</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtQuick</IncludePath>
+    <Defines>QT_QUICK_LIB</Defines>
+    <Tag>Essential</Tag>
+  </Module>
+  <Module Id="7">
+    <Name>Qt Quick Controls</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtQuickControls2</LibraryPrefix>
+    <proVarQT>quickcontrols2</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtQuickControls2</IncludePath>
+    <Defines>QT_QUICKCONTROLS2_LIB</Defines>
+    <Tag>Essential</Tag>
+  </Module>
+  <Module Id="8">
+    <Name>Qt Quick Dialogs</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtQuickDialogs2</LibraryPrefix>
+    <proVarQT>quickdialogs2</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtQuickDialogs2</IncludePath>
+    <Defines>QT_QUICKDIALOGS2_LIB</Defines>
+    <Tag>Essential</Tag>
+  </Module>
+  <Module Id="9">
+    <Name>Qt Quick Layouts</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtQuickLayouts</LibraryPrefix>
+    <proVarQT>quicklayouts</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtQuickLayouts</IncludePath>
+    <Defines>QT_QUICKLAYOUTS_LIB</Defines>
+    <Tag>Essential</Tag>
+  </Module>
+  <Module Id="10">
+    <Name>Qt Quick Test</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtQuickTest</LibraryPrefix>
+    <proVarQT>qmltest</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtQuickTest</IncludePath>
+    <Defines>QT_QMLTEST_LIB</Defines>
+    <Tag>Essential</Tag>
+  </Module>
+  <Module Id="11">
+    <Name>Qt Test</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtTest</LibraryPrefix>
+    <proVarQT>testlib</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtTest</IncludePath>
+    <Defines>QT_TESTLIB_LIB</Defines>
+    <Tag>Essential</Tag>
+  </Module>
+  <Module Id="12">
+    <Name>Qt Widgets</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtWidgets</LibraryPrefix>
+    <proVarQT>widgets</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtWidgets</IncludePath>
+    <Defines>QT_WIDGETS_LIB</Defines>
+    <Tag>Essential</Tag>
+  </Module>
+
+  <!-- Qt Add-Ons-->
+
+  <Module Id="13">
+    <Name>Active Qt (Server)</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtAxServer</LibraryPrefix>
+    <proVarQT>axserver</proVarQT>
+    <IncludePath>$(QTDIR)\include\ActiveQt</IncludePath>
+    <Defines>QAXSERVER</Defines>
+    <Defines>QT_AXSERVER_LIB</Defines>
+    <AdditionalLibraries>Qt6AxBase.lib</AdditionalLibraries>
+    <AdditionalLibrariesDebug>Qt6AxBased.lib</AdditionalLibrariesDebug>
+  </Module>
+  <Module Id="14">
+    <Name>Active Qt (Container)</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtAxContainer</LibraryPrefix>
+    <proVarQT>axcontainer</proVarQT>
+    <IncludePath>$(QTDIR)\include\ActiveQt</IncludePath>
+    <Defines>QT_AXCONTAINER_LIB</Defines>
+    <AdditionalLibraries>Qt6AxBase.lib</AdditionalLibraries>
+    <AdditionalLibrariesDebug>Qt6AxBased.lib</AdditionalLibrariesDebug>
+  </Module>
+  <Module Id="15">
+    <Name>Qt Bluetooth</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtBluetooth</LibraryPrefix>
+    <proVarQT>bluetooth</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtBluetooth</IncludePath>
+    <Defines>QT_BLUETOOTH_LIB</Defines>
+  </Module>
+  <Module Id="16">
+    <Name>Qt 3D</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>Qt3DCore</LibraryPrefix>
+    <proVarQT>3dcore 3danimation 3dextras 3dinput 3dlogic 3drender</proVarQT>
+    <IncludePath>$(QTDIR)\include\Qt3DCore</IncludePath>
+    <IncludePath>$(QTDIR)\include\Qt3DAnimation</IncludePath>
+    <IncludePath>$(QTDIR)\include\Qt3DExtras</IncludePath>
+    <IncludePath>$(QTDIR)\include\Qt3DInput</IncludePath>
+    <IncludePath>$(QTDIR)\include\Qt3DLogic</IncludePath>
+    <IncludePath>$(QTDIR)\include\Qt3DRender</IncludePath>
+    <Defines>QT_3DCORE_LIB</Defines>
+    <Defines>QT_3DANIMATION_LIB</Defines>
+    <Defines>QT_3DEXTRAS_LIB</Defines>
+    <Defines>QT_3DINPUT_LIB</Defines>
+    <Defines>QT_3DLOGIC_LIB</Defines>
+    <Defines>QT_3DRENDER_LIB</Defines>
+    <AdditionalLibraries>Qt63DCore.lib</AdditionalLibraries>
+    <AdditionalLibraries>Qt63DAnimation.lib</AdditionalLibraries>
+    <AdditionalLibraries>Qt63DExtras.lib</AdditionalLibraries>
+    <AdditionalLibraries>Qt63DInput.lib</AdditionalLibraries>
+    <AdditionalLibraries>Qt63DLogic.lib</AdditionalLibraries>
+    <AdditionalLibraries>Qt63DRender.lib</AdditionalLibraries>
+    <AdditionalLibrariesDebug>Qt63DCored.lib</AdditionalLibrariesDebug>
+    <AdditionalLibrariesDebug>Qt63DAnimationd.lib</AdditionalLibrariesDebug>
+    <AdditionalLibrariesDebug>Qt63DExtrasd.lib</AdditionalLibrariesDebug>
+    <AdditionalLibrariesDebug>Qt63DInputd.lib</AdditionalLibrariesDebug>
+    <AdditionalLibrariesDebug>Qt63DLogicd.lib</AdditionalLibrariesDebug>
+    <AdditionalLibrariesDebug>Qt63DRenderd.lib</AdditionalLibrariesDebug>
+  </Module>
+  <Module Id="17">
+    <Name>Qt 5 Core Compatibility APIs</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtCore5Compat</LibraryPrefix>
+    <proVarQT>core5compat</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtCore5Compat</IncludePath>
+    <Defines>QT_CORE5COMPAT_LIB</Defines>
+  </Module>
+  <Module Id="18"> <!-- TODO: Split? -->
+    <Name>Qt for Automation</Name>
+    <proVarQT>coap mqtt opcua</proVarQT>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtCoap</LibraryPrefix>
+    <AdditionalLibraries>Qt6Coap.lib</AdditionalLibraries>
+    <AdditionalLibraries>Qt6Coapd.lib</AdditionalLibraries>
+    <AdditionalLibraries>Qt6Mqtt.lib</AdditionalLibraries>
+    <AdditionalLibraries>Qt6Mqttd.lib</AdditionalLibraries>
+    <AdditionalLibraries>Qt6OpcUa.lib</AdditionalLibraries>
+    <AdditionalLibraries>Qt6OpcUad.lib</AdditionalLibraries>
+  </Module>
+  <Module Id="19">
+    <Name>Qt Concurrent</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtConcurrent</LibraryPrefix>
+    <proVarQT>concurrent</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtConcurrent</IncludePath>
+    <Defines>QT_CONCURRENT_LIB</Defines>
+  </Module>
+  <Module Id="20">
+    <Name>Qt Help</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtHelp</LibraryPrefix>
+    <proVarQT>help</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtHelp</IncludePath>
+    <Defines>QT_HELP_LIB</Defines>
+  </Module>
+  <!--
+      Image formats
+  -->
+  <Module Id="21">
+    <Name>Qt OpenGL</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtOpenGL</LibraryPrefix>
+    <proVarQT>opengl</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtOpenGL</IncludePath>
+    <Defines>QT_OPENGL_LIB</Defines>
+  </Module>
+  <Module Id="22">
+    <Name>Qt Multimedia</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtMultimedia</LibraryPrefix>
+    <proVarQT>multimedia</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtMultimedia</IncludePath>
+    <Defines>QT_MULTIMEDIA_LIB</Defines>
+  </Module>
+  <Module Id="23">
+    <Name>Qt Print Support</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtPrintSupport</LibraryPrefix>
+    <proVarQT>printsupport</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtPrintSupport</IncludePath>
+    <Defines>QT_PRINTSUPPORT_LIB</Defines>
+  </Module>
+  <Module Id="24">
+    <Name>Qt Quick Widgets</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtQuickWidgets</LibraryPrefix>
+    <proVarQT>quickwidgets</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtQuickWidgets</IncludePath>
+    <Defines>QT_QUICKWIDGETS_LIB</Defines>
+  </Module>
+  <Module Id="25">
+    <Name>Qt Remote Objects</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtRemoteObjects</LibraryPrefix>
+    <proVarQT>remoteobjects</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtRemoteObjects</IncludePath>
+    <Defines>QT_REMOTEOBJECTS_LIB</Defines>
+  </Module>
+  <Module Id="26">
+    <Name>Qt SCXML</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtScxml</LibraryPrefix>
+    <proVarQT>scxml</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtScxml</IncludePath>
+    <Defines>QT_SCXML_LIB</Defines>
+  </Module>
+  <Module Id="27">
+    <Name>Qt Sensors</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtSensors</LibraryPrefix>
+    <proVarQT>sensors</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtSensors</IncludePath>
+    <Defines>QT_SENSORS_LIB</Defines>
+  </Module>
+  <Module Id="28">
+    <Name>Qt Serial Bus</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtSerialBus</LibraryPrefix>
+    <proVarQT>serialbus</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtSerialBus</IncludePath>
+    <Defines>QT_SERIALBUS_LIB</Defines>
+  </Module>
+  <Module Id="29">
+    <Name>Qt Serial Port</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtSerialPort</LibraryPrefix>
+    <proVarQT>serialport</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtSerialPort</IncludePath>
+    <Defines>QT_SERIALPORT_LIB</Defines>
+  </Module>
+  <Module Id="30">
+    <Name>Qt SQL</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtSql</LibraryPrefix>
+    <proVarQT>sql</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtSql</IncludePath>
+    <Defines>QT_SQL_LIB</Defines>
+  </Module>
+  <Module Id="31">
+    <Name>Qt State Machine</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtStateMachine</LibraryPrefix>
+    <proVarQT>statemachine</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtStateMachine</IncludePath>
+    <Defines>QT_STATEMACHINE_LIB</Defines>
+  </Module>
+  <Module Id="32">
+    <Name>Qt SVG</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtSvg</LibraryPrefix>
+    <proVarQT>svg</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtSvg</IncludePath>
+    <Defines>QT_SVG_LIB</Defines>
+  </Module>
+  <Module Id="34">
+    <Name>Qt WebChannel</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtWebChannel</LibraryPrefix>
+    <proVarQT>webchannel</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtWebChannel</IncludePath>
+    <Defines>QT_WEBCHANNEL_LIB</Defines>
+  </Module>
+  <Module Id="35">
+    <Name>Qt WebEngine</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtWebEngine</LibraryPrefix>
+    <proVarQT>webenginecore</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtWebEngineCore</IncludePath>
+    <Defines>QT_WEBENGINECORE_LIB</Defines>
+    <AdditionalLibraries>Qt6WebEngine.lib</AdditionalLibraries>
+    <AdditionalLibraries>Qt6WebEngineCore.lib</AdditionalLibraries>
+    <AdditionalLibrariesDebug>Qt6WebEngined.lib</AdditionalLibrariesDebug>
+    <AdditionalLibrariesDebug>Qt6WebEngineCored.lib</AdditionalLibrariesDebug>
+  </Module>
+  <Module Id="36">
+    <Name>Qt WebSockets</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtWebSockets</LibraryPrefix>
+    <proVarQT>websockets</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtWebSockets</IncludePath>
+    <Defines>QT_WEBSOCKETS_LIB</Defines>
+  </Module>
+  <Module Id="37">
+    <Name>WebView</Name>
+    <proVarQT>webview</proVarQT>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtWebView</LibraryPrefix>
+  </Module>
+  <Module Id="38">
+    <Name>Qt XML</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtXml</LibraryPrefix>
+    <proVarQT>xml</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtXml</IncludePath>
+    <Defines>QT_XML_LIB</Defines>
+  </Module>
+  <Module Id="39">
+    <Name>Qt Positioning</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtPositioning</LibraryPrefix>
+    <proVarQT>positioning</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtPositioning</IncludePath>
+    <Defines>QT_POSITIONING_LIB</Defines>
+  </Module>
+  <Module Id="40">
+    <Name>Qt NFC</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtNfc</LibraryPrefix>
+    <proVarQT>nfc</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtNfc</IncludePath>
+    <Defines>QT_NFC_LIB</Defines>
+  </Module>
+  <Module Id="41">
+    <Name>Qt Charts</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtCharts</LibraryPrefix>
+    <proVarQT>charts</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtCharts</IncludePath>
+    <Defines>QT_CHARTS_LIB</Defines>
+  </Module>
+  <Module Id="42">
+    <Name>Qt Data Visualization</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtDataVisualization</LibraryPrefix>
+    <proVarQT>datavisualization</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtDataVisualization</IncludePath>
+    <Defines>QT_DATAVISUALIZATION_LIB</Defines>
+  </Module>
+  <!--
+      lottie
+  -->
+  <Module Id="44">
+    <Name>Qt Network Authorization</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtNetworkAuth</LibraryPrefix>
+    <proVarQT>networkauth</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtNetworkAuth</IncludePath>
+    <Defines>QT_NETWORKAUTH_LIB</Defines>
+  </Module>
+  <Module Id="45">
+    <Name>Qt Virtual Keyboard</Name>
+    <proVarQT>virtualkeyboard</proVarQT>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtVirtualKeyboard</LibraryPrefix>
+  </Module>
+  <Module Id="46">
+    <Name>Qt Quick 3D</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>Qt3DQuick</LibraryPrefix>
+    <proVarQT>3dquick</proVarQT>
+    <IncludePath>$(QTDIR)\include\Qt3DQuick</IncludePath>
+    <IncludePath>$(QTDIR)\include\Qt3DQuickAnimation</IncludePath>
+    <IncludePath>$(QTDIR)\include\Qt3DQuickExtras</IncludePath>
+    <IncludePath>$(QTDIR)\include\Qt3DQuickInput</IncludePath>
+    <IncludePath>$(QTDIR)\include\Qt3DQuickRender</IncludePath>
+    <IncludePath>$(QTDIR)\include\Qt3DQuickScene2D</IncludePath>
+    <Defines>QT_3DQUICK_LIB</Defines>
+    <Defines>QT_3DQUICKANIMATION_LIB</Defines>
+    <Defines>QT_3DQUICKEXTRAS_LIB</Defines>
+    <Defines>QT_3DQUICKINPUT_LIB</Defines>
+    <Defines>QT_3DQUICKRENDER_LIB</Defines>
+    <Defines>QT_3DQUICKSCENE2D_LIB</Defines>
+    <AdditionalLibraries>Qt63DQuick.lib</AdditionalLibraries>
+    <AdditionalLibraries>Qt63DQuickAnimation.lib</AdditionalLibraries>
+    <AdditionalLibraries>Qt63DQuickExtras.lib</AdditionalLibraries>
+    <AdditionalLibraries>Qt63DQuickInput.lib</AdditionalLibraries>
+    <AdditionalLibraries>Qt63DQuickRender.lib</AdditionalLibraries>
+    <AdditionalLibraries>Qt63DQuickScene2D.lib</AdditionalLibraries>
+    <AdditionalLibrariesDebug>Qt63DQuickd.lib</AdditionalLibrariesDebug>
+    <AdditionalLibrariesDebug>Qt63DQuickAnimationd.lib</AdditionalLibrariesDebug>
+    <AdditionalLibrariesDebug>Qt63DQuickExtrasd.lib</AdditionalLibrariesDebug>
+    <AdditionalLibrariesDebug>Qt63DQuickInputd.lib</AdditionalLibrariesDebug>
+    <AdditionalLibrariesDebug>Qt63DQuickRenderd.lib</AdditionalLibrariesDebug>
+    <AdditionalLibrariesDebug>Qt63DQuickScene2Dd.lib</AdditionalLibrariesDebug>
+  </Module>
+  <Module Id="47">
+    <Name>Qt Quick Timeline</Name>
+    <proVarQT>quicktimeline</proVarQT>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtQuickTimeline</LibraryPrefix>
+  </Module>
+  <Module Id="48">
+    <Name>Qt Shader Tools</Name>
+    <proVarQT>shadertools</proVarQT>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtShaderTools</LibraryPrefix>
+  </Module>
+  <Module Id="49">
+    <Name>Qt Wayland Compositor</Name>
+    <proVarQT>waylandcompositor</proVarQT>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtWaylandCompositor</LibraryPrefix>
+  </Module>
+  <Module Id="50">
+    <Name>Qt WebEngine Widgets</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtWebEngineWidgets</LibraryPrefix>
+    <proVarQT>webenginewidgets</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtWebEngineCore</IncludePath>
+    <IncludePath>$(QTDIR)\include\QtWebEngineWidgets</IncludePath>
+    <Defines>QT_WEBENGINECORE_LIB</Defines>
+    <Defines>QT_WEBENGINEWIDGETS_LIB</Defines>
+    <AdditionalLibraries>Qt6WebEngineCore.lib</AdditionalLibraries>
+    <AdditionalLibrariesDebug>Qt6WebEngineCored.lib</AdditionalLibrariesDebug>
+    <AdditionalLibraries>Qt6WebEngineWidgets.lib</AdditionalLibraries>
+    <AdditionalLibrariesDebug>Qt6WebEngineWidgetsd.lib</AdditionalLibrariesDebug>
+  </Module>
+  <Module Id="51">
+    <Name>Qt WebEngine Quick</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtWebEngineQuick</LibraryPrefix>
+    <proVarQT>webenginequick</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtWebEngineCore</IncludePath>
+    <IncludePath>$(QTDIR)\include\QtWebEngineQuick</IncludePath>
+    <Defines>QT_WEBENGINECORE_LIB</Defines>
+    <Defines>QT_WEBENGINEQUICK_LIB</Defines>
+    <AdditionalLibraries>Qt6WebEngineCore.lib</AdditionalLibraries>
+    <AdditionalLibrariesDebug>Qt6WebEngineCored.lib</AdditionalLibrariesDebug>
+    <AdditionalLibraries>Qt6WebEngineQuick.lib</AdditionalLibraries>
+    <AdditionalLibrariesDebug>Qt6WebEngineQuickd.lib</AdditionalLibrariesDebug>
+  </Module>
+
+  <!-- Designer -->
+  <Module Id="52">
+    <Name>Designer</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtDesigner</LibraryPrefix>
+    <HasDLL>true</HasDLL>
+    <proVarQT>designer</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtDesigner</IncludePath>
+    <Defines>QT_DESIGNER_LIB</Defines>
+  </Module>
+  <Module Id="53">
+    <Name>Qt UI Tools</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtUiTools</LibraryPrefix>
+    <HasDLL>true</HasDLL>
+    <proVarQT>uitools</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtUiTools</IncludePath>
+    <Defines>QT_UITOOLS_LIB</Defines>
+  </Module>
+  <Module Id="54">
+    <Name>Qt UI Plugin</Name>
+    <Selectable>true</Selectable>
+    <LibraryPrefix>QtUiPlugin</LibraryPrefix>
+    <HasDLL>false</HasDLL>
+    <proVarQT>uiplugin</proVarQT>
+    <IncludePath>$(QTDIR)\include\QtUiPlugin</IncludePath>
+    <Defines>QT_UIPLUGIN_LIB</Defines>
+    <Defines>QDESIGNER_EXPORT_WIDGETS</Defines>
+  </Module>
+  <!-- Designer -->
+
+</QtVsTools>
diff --git a/QtVsTools.Package/qtmodules.xml b/QtVsTools.Package/qtmodules.xml
index 1a56520..364a84a 100644
--- a/QtVsTools.Package/qtmodules.xml
+++ b/QtVsTools.Package/qtmodules.xml
@@ -4,7 +4,6 @@
     <Name>Core</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtCore</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>core</proVarQT>
     <IncludePath>$(QTDIR)\include\QtCore</IncludePath>
     <Defines>QT_CORE_LIB</Defines>
@@ -13,7 +12,6 @@
     <Name>Xml</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtXml</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>xml</proVarQT>
     <IncludePath>$(QTDIR)\include\QtXml</IncludePath>
     <Defines>QT_XML_LIB</Defines>
@@ -22,7 +20,6 @@
     <Name>Sql</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtSql</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>sql</proVarQT>
     <IncludePath>$(QTDIR)\include\QtSql</IncludePath>
     <Defines>QT_SQL_LIB</Defines>
@@ -31,7 +28,6 @@
     <Name>OpenGL</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtOpenGL</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>opengl</proVarQT>
     <IncludePath>$(QTDIR)\include\QtOpenGL</IncludePath>
     <Defines>QT_OPENGL_LIB</Defines>
@@ -40,7 +36,6 @@
     <Name>Network</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtNetwork</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>network</proVarQT>
     <IncludePath>$(QTDIR)\include\QtNetwork</IncludePath>
     <Defines>QT_NETWORK_LIB</Defines>
@@ -49,7 +44,6 @@
     <Name>Gui</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtGui</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>gui</proVarQT>
     <IncludePath>$(QTDIR)\include\QtGui</IncludePath>
     <IncludePath>$(QTDIR)\include\QtANGLE</IncludePath>
@@ -59,7 +53,6 @@
     <Name>ActiveQtS</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtAxServer</LibraryPrefix>
-    <HasDLL>false</HasDLL>
     <proVarQT>axserver</proVarQT>
     <IncludePath>$(QTDIR)\include\ActiveQt</IncludePath>
     <Defines>QAXSERVER</Defines>
@@ -70,7 +63,6 @@
     <Name>ActiveQtC</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtAxContainer</LibraryPrefix>
-    <HasDLL>false</HasDLL>
     <proVarQT>axcontainer</proVarQT>
     <IncludePath>$(QTDIR)\include\ActiveQt</IncludePath>
     <AdditionalLibraries>Qt5AxBase.lib</AdditionalLibraries>
@@ -80,13 +72,11 @@
     <Name>Main</Name>
     <Selectable>false</Selectable>
     <LibraryPrefix>qtmain</LibraryPrefix>
-    <HasDLL>false</HasDLL>
   </Module>
   <Module Id="13">
     <Name>Svg</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtSvg</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>svg</proVarQT>
     <IncludePath>$(QTDIR)\include\QtSvg</IncludePath>
     <Defines>QT_SVG_LIB</Defines>
@@ -95,17 +85,14 @@
     <Name>Designer</Name>
     <Selectable>false</Selectable>
     <LibraryPrefix>QtDesigner</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>designer</proVarQT>
     <IncludePath>$(QTDIR)\include\QtDesigner</IncludePath>
-    <Defines>QDESIGNER_EXPORT_WIDGETS</Defines>
     <Defines>QT_DESIGNER_LIB</Defines>
   </Module>
   <Module Id="15">
     <Name>Test</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtTest</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>testlib</proVarQT>
     <IncludePath>$(QTDIR)\include\QtTest</IncludePath>
     <Defines>QT_TESTLIB_LIB</Defines>
@@ -114,7 +101,6 @@
     <Name>Script</Name>
     <Selectable>false</Selectable>
     <LibraryPrefix>QtScript</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>script</proVarQT>
     <IncludePath>$(QTDIR)\include\QtScript</IncludePath>
     <Defines>QT_SCRIPT_LIB</Defines>
@@ -123,7 +109,6 @@
     <Name>Help</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtHelp</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>help</proVarQT>
     <IncludePath>$(QTDIR)\include\QtHelp</IncludePath>
     <Defines>QT_HELP_LIB</Defines>
@@ -132,7 +117,6 @@
     <Name>WebKit</Name>
     <Selectable>false</Selectable>
     <LibraryPrefix>QtWebKit</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>webkit</proVarQT>
     <IncludePath>$(QTDIR)\include\QtWebKit</IncludePath>
   </Module>
@@ -140,7 +124,6 @@
     <Name>XmlPatterns</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtXmlPatterns</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>xmlpatterns</proVarQT>
     <IncludePath>$(QTDIR)\include\QtXmlPatterns</IncludePath>
     <Defines>QT_XMLPATTERNS_LIB</Defines>
@@ -149,7 +132,6 @@
     <Name>Enginio</Name>
     <Selectable>false</Selectable>
     <LibraryPrefix>Enginio</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>enginio</proVarQT>
     <IncludePath>$(QTDIR)\include\Enginio</IncludePath>
     <Defines>QT_ENGINIO_LIB</Defines>
@@ -158,7 +140,6 @@
     <Name>Multimedia</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtMultimedia</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>multimedia</proVarQT>
     <IncludePath>$(QTDIR)\include\QtMultimedia</IncludePath>
     <Defines>QT_MULTIMEDIA_LIB</Defines>
@@ -167,7 +148,6 @@
     <Name>ScriptTools</Name>
     <Selectable>false</Selectable>
     <LibraryPrefix>QtScriptTools</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>scripttools</proVarQT>
     <IncludePath>$(QTDIR)\include\QtScriptTools</IncludePath>
     <Defines>QT_SCRIPTTOOLS_LIB</Defines>
@@ -176,7 +156,6 @@
     <Name>UiTools</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtUiTools</LibraryPrefix>
-    <HasDLL>false</HasDLL>
     <proVarQT>uitools</proVarQT>
     <IncludePath>$(QTDIR)\include\QtUiTools</IncludePath>
     <Defines>QT_UITOOLS_LIB</Defines>
@@ -185,7 +164,6 @@
     <Name>Widgets</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtWidgets</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>widgets</proVarQT>
     <IncludePath>$(QTDIR)\include\QtWidgets</IncludePath>
     <Defines>QT_WIDGETS_LIB</Defines>
@@ -194,7 +172,6 @@
     <Name>Location</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtLocation</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>location</proVarQT>
     <IncludePath>$(QTDIR)\include\QtLocation</IncludePath>
     <Defines>QT_LOCATION_LIB</Defines>
@@ -203,7 +180,6 @@
     <Name>Nfc</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtNfc</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>nfc</proVarQT>
     <IncludePath>$(QTDIR)\include\QtNfc</IncludePath>
     <Defines>QT_NFC_LIB</Defines>
@@ -212,7 +188,6 @@
     <Name>Qml</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtQml</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>qml</proVarQT>
     <IncludePath>$(QTDIR)\include\QtQml</IncludePath>
     <Defines>QT_QML_LIB</Defines>
@@ -221,7 +196,6 @@
     <Name>Bluetooth</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtBluetooth</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>bluetooth</proVarQT>
     <IncludePath>$(QTDIR)\include\QtBluetooth</IncludePath>
     <Defines>QT_BLUETOOTH_LIB</Defines>
@@ -230,7 +204,6 @@
     <Name>Positioning</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtPositioning</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>positioning</proVarQT>
     <IncludePath>$(QTDIR)\include\QtPositioning</IncludePath>
     <Defines>QT_POSITIONING_LIB</Defines>
@@ -239,7 +212,6 @@
     <Name>SerialPort</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtSerialPort</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>serialport</proVarQT>
     <IncludePath>$(QTDIR)\include\QtSerialPort</IncludePath>
     <Defines>QT_SERIALPORT_LIB</Defines>
@@ -248,7 +220,6 @@
     <Name>PrintSupport</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtPrintSupport</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>printsupport</proVarQT>
     <IncludePath>$(QTDIR)\include\QtPrintSupport</IncludePath>
     <Defines>QT_PRINTSUPPORT_LIB</Defines>
@@ -257,7 +228,6 @@
     <Name>WebChannel</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtWebChannel</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>webchannel</proVarQT>
     <IncludePath>$(QTDIR)\include\QtWebChannel</IncludePath>
     <Defines>QT_WEBCHANNEL_LIB</Defines>
@@ -266,7 +236,6 @@
     <Name>WebSockets</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtWebSockets</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>websockets</proVarQT>
     <IncludePath>$(QTDIR)\include\QtWebSockets</IncludePath>
     <Defines>QT_WEBSOCKETS_LIB</Defines>
@@ -275,7 +244,6 @@
     <Name>Sensors</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtSensors</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>sensors</proVarQT>
     <IncludePath>$(QTDIR)\include\QtSensors</IncludePath>
     <Defines>QT_SENSORS_LIB</Defines>
@@ -284,7 +252,6 @@
     <Name>WindowsExtras</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtWinExtras</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>winextras</proVarQT>
     <IncludePath>$(QTDIR)\include\QtWinExtras</IncludePath>
     <Defines>QT_WINEXTRAS_LIB</Defines>
@@ -293,7 +260,6 @@
     <Name>QuickWidgets</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtQuickWidgets</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>quickwidgets</proVarQT>
     <IncludePath>$(QTDIR)\include\QtQuickWidgets</IncludePath>
     <Defines>QT_QUICKWIDGETS_LIB</Defines>
@@ -302,7 +268,6 @@
     <Name>Quick</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtQuick</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>quick</proVarQT>
     <IncludePath>$(QTDIR)\include\QtQuick</IncludePath>
     <Defines>QT_QUICK_LIB</Defines>
@@ -311,7 +276,6 @@
     <Name>WebkitWidgets</Name>
     <Selectable>false</Selectable>
     <LibraryPrefix>QtWebkitWidgets</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>webkitwidgets</proVarQT>
     <IncludePath>$(QTDIR)\include\QtWebkitWidgets</IncludePath>
     <Defines>QT_WEBKITWIDGETS_LIB</Defines>
@@ -320,7 +284,6 @@
     <Name>Concurrent</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtConcurrent</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>concurrent</proVarQT>
     <IncludePath>$(QTDIR)\include\QtConcurrent</IncludePath>
     <Defines>QT_CONCURRENT_LIB</Defines>
@@ -329,7 +292,6 @@
     <Name>MultimediaWidgets</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtMultimediaWidgets</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>multimediawidgets</proVarQT>
     <IncludePath>$(QTDIR)\include\QtMultimediaWidgets</IncludePath>
     <Defines>QT_MULTIMEDIAWIDGETS_LIB</Defines>
@@ -338,7 +300,6 @@
     <Name>3D</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>Qt3DCore</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>3dcore 3danimation 3dextras 3dinput 3dlogic 3drender</proVarQT>
     <IncludePath>$(QTDIR)\include\Qt3DCore</IncludePath>
     <IncludePath>$(QTDIR)\include\Qt3DAnimation</IncludePath>
@@ -369,7 +330,6 @@
     <Name>3D Quick</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>Qt3DQuick</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>3dquick</proVarQT>
     <IncludePath>$(QTDIR)\include\Qt3DQuick</IncludePath>
     <IncludePath>$(QTDIR)\include\Qt3DQuickAnimation</IncludePath>
@@ -400,7 +360,6 @@
     <Name>DBus</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtDBus</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>dbus</proVarQT>
     <IncludePath>$(QTDIR)\include\QtDBus</IncludePath>
     <Defines>QT_DBUS_LIB</Defines>
@@ -409,7 +368,6 @@
     <Name>Gamepad</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtGamepad</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>gamepad</proVarQT>
     <IncludePath>$(QTDIR)\include\QtGamepad</IncludePath>
     <Defines>QT_GAMEPAD_LIB</Defines>
@@ -418,7 +376,6 @@
     <Name>OpenGL Extensions</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtOpenGLExtensions</LibraryPrefix>
-    <HasDLL>false</HasDLL>
     <proVarQT>openglextensions</proVarQT>
     <IncludePath>$(QTDIR)\include\QtOpenGLExtensions</IncludePath>
     <Defines>QT_OPENGLEXTENSIONS_LIB</Defines>
@@ -427,7 +384,6 @@
     <Name>QuickTest</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtQuickTest</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>qmltest</proVarQT>
     <IncludePath>$(QTDIR)\include\QtQuickTest</IncludePath>
     <Defines>QT_QMLTEST_LIB</Defines>
@@ -436,7 +392,6 @@
     <Name>Quick Controls2</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtQuickControls2</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>quickcontrols2</proVarQT>
     <IncludePath>$(QTDIR)\include\QtQuickControls2</IncludePath>
     <Defines>QT_QUICKCONTROLS2_LIB</Defines>
@@ -445,7 +400,6 @@
     <Name>Scxml</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtScxml</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>scxml</proVarQT>
     <IncludePath>$(QTDIR)\include\QtScxml</IncludePath>
     <Defines>QT_SCXML_LIB</Defines>
@@ -454,7 +408,6 @@
     <Name>Serial Bus</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtSerialBus</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>serialbus</proVarQT>
     <IncludePath>$(QTDIR)\include\QtSerialBus</IncludePath>
     <Defines>QT_SERIALBUS_LIB</Defines>
@@ -463,16 +416,15 @@
     <Name>UI Plugin</Name>
     <Selectable>false</Selectable>
     <LibraryPrefix>QtUiPlugin</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>uiplugin</proVarQT>
     <IncludePath>$(QTDIR)\include\QtUiPlugin</IncludePath>
     <Defines>QT_UIPLUGIN_LIB</Defines>
+    <Defines>QDESIGNER_EXPORT_WIDGETS</Defines>
   </Module>
   <Module Id="111">
     <Name>WebEngine</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtWebEngine</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>webengine</proVarQT>
     <IncludePath>$(QTDIR)\include\QtWebEngine</IncludePath>
     <IncludePath>$(QTDIR)\include\QtWebEngineCore</IncludePath>
@@ -487,7 +439,6 @@
     <Name>WebEngine Widgets</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtWebEngineWidgets</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>webenginewidgets</proVarQT>
     <IncludePath>$(QTDIR)\include\QtWebEngineWidgets</IncludePath>
     <IncludePath>$(QTDIR)\include\QtWebEngineCore</IncludePath>
@@ -502,7 +453,6 @@
     <Name>Charts</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtCharts</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>charts</proVarQT>
     <IncludePath>$(QTDIR)\include\QtCharts</IncludePath>
     <Defines>QT_CHARTS_LIB</Defines>
@@ -511,7 +461,6 @@
     <Name>Data Visualization</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtDataVisualization</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>datavisualization</proVarQT>
     <IncludePath>$(QTDIR)\include\QtDataVisualization</IncludePath>
     <Defines>QT_DATAVISUALIZATION_LIB</Defines>
@@ -520,7 +469,6 @@
     <Name>Network Authorization</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtNetworkAuth</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>networkauth</proVarQT>
     <IncludePath>$(QTDIR)\include\QtNetworkAuth</IncludePath>
     <Defines>QT_NETWORKAUTH_LIB</Defines>
@@ -529,7 +477,6 @@
     <Name>Speech</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtTextToSpeech</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>texttospeech</proVarQT>
     <IncludePath>$(QTDIR)\include\QtTextToSpeech</IncludePath>
     <Defines>QT_TEXTTOSPEECH_LIB</Defines>
@@ -538,7 +485,6 @@
     <Name>Remote Objects</Name>
     <Selectable>true</Selectable>
     <LibraryPrefix>QtRemoteObjects</LibraryPrefix>
-    <HasDLL>true</HasDLL>
     <proVarQT>remoteobjects</proVarQT>
     <IncludePath>$(QTDIR)\include\QtRemoteObjects</IncludePath>
     <Defines>QT_REMOTEOBJECTS_LIB</Defines>
diff --git a/QtVsTools.Package/source.extension.vsixmanifest_TT b/QtVsTools.Package/source.extension.vsixmanifest_TT
index 7321b70..1aa4a5d 100644
--- a/QtVsTools.Package/source.extension.vsixmanifest_TT
+++ b/QtVsTools.Package/source.extension.vsixmanifest_TT
@@ -88,9 +88,9 @@
     <DisplayName>Qt Visual Studio Tools</DisplayName>
     <Description xml:space="preserve">The Qt VS Tools for Visual Studio <#=VS_NAME#> allow developers to use the standard development environment without having to worry about any Qt-related build steps or tools.</Description>
     <#=XML_COMMENT_BEGIN#> END Generated Text -->
-    <MoreInfo>http://www.qt.io</MoreInfo>
+    <MoreInfo>https://doc.qt.io/qtvstools/index.html</MoreInfo>
     <License>LICENSE.GPL3-EXCEPT</License>
-    <ReleaseNotes>Changelog</ReleaseNotes>
+    <ReleaseNotes>https://code.qt.io/cgit/qt-labs/vstools.git/tree/Changelog</ReleaseNotes>
     <Icon>qt.ico</Icon>
     <PreviewImage>preview.png</PreviewImage>
   </Metadata>
@@ -195,6 +195,20 @@
       d:TargetPath="|QtTemplate.Item.Widget;TemplateProjectOutputGroup|" Path="ItemTemplates"
       d:VsixSubPath="ItemTemplates" />
     <Asset
+      Type="Microsoft.VisualStudio.ItemTemplate" d:Source="Project" d:ProjectName="WidgetsClass"
+      d:TargetPath="|QtTemplate.Item.WidgetsClass;TemplateProjectOutputGroup|" Path="ItemTemplates"
+      d:VsixSubPath="ItemTemplates" />
+    <Asset
+      Type="Microsoft.VisualStudio.ItemTemplate" d:Source="Project" d:ProjectName="QtClass"
+      d:TargetPath="|QtTemplate.Item.QtClass;TemplateProjectOutputGroup|" Path="ItemTemplates"
+      d:VsixSubPath="ItemTemplates" />
+    <Asset
+      Type="Microsoft.VisualStudio.ItemTemplate" d:Source="Project" d:ProjectName="Translation"
+      d:TargetPath="|QtTemplate.Item.Translation;TemplateProjectOutputGroup|" Path="ItemTemplates"
+      d:VsixSubPath="ItemTemplates" />
+    <Asset
       Type="Microsoft.VisualStudio.VsPackage" d:Source="File" Path="QtVsTools.Qml.Debug.pkgdef" />
+    <Asset
+      Type="Microsoft.VisualStudio.VsPackage" d:Source="File" Path="QtVsTools.Icons.pkgdef" />
   </Assets>
 </PackageManifest>
diff --git a/QtVsTools.RegExpr/Properties/AssemblyInfo.cs b/QtVsTools.RegExpr/Properties/AssemblyInfo.cs
index 87d3c5e..4753562 100644
--- a/QtVsTools.RegExpr/Properties/AssemblyInfo.cs
+++ b/QtVsTools.RegExpr/Properties/AssemblyInfo.cs
@@ -1,5 +1,4 @@
 using System.Reflection;
-using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 
 // General Information about an assembly is controlled through the following
diff --git a/QtVsTools.RegExpr/QtVsTools.RegExpr.csproj b/QtVsTools.RegExpr/QtVsTools.RegExpr.csproj
index 92577c4..b309bab 100644
--- a/QtVsTools.RegExpr/QtVsTools.RegExpr.csproj
+++ b/QtVsTools.RegExpr/QtVsTools.RegExpr.csproj
@@ -66,21 +66,18 @@
   // -->
   <ItemGroup>
     <Reference Include="System" />
-    <Reference Include="System.Xml.Linq" />
   </ItemGroup>
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
   // Version specific references
   // -->
+  <!--<Import Project="$(SolutionDir)\references.props" />-->
   <!-- // Visual Studio 2022 -->
-  <ItemGroup Condition="'$(VisualStudioVersion)'=='17.0'">
-  </ItemGroup>
+  <ItemGroup Condition="'$(VisualStudioVersion)'=='17.0'" />
   <!-- // Visual Studio 2019 -->
-  <ItemGroup Condition="'$(VisualStudioVersion)'=='16.0'">
-  </ItemGroup>
+  <ItemGroup Condition="'$(VisualStudioVersion)'=='16.0'" />
   <!-- // Visual Studio 2017 -->
-  <ItemGroup Condition="'$(VisualStudioVersion)'=='15.0'">
-  </ItemGroup>
+  <ItemGroup Condition="'$(VisualStudioVersion)'=='15.0'" />
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
   // Solution project references
diff --git a/QtVsTools.RegExpr/expression/CharClassSet.cs b/QtVsTools.RegExpr/expression/CharClassSet.cs
index 36e1fa6..16cc9ba 100644
--- a/QtVsTools.RegExpr/expression/CharClassSet.cs
+++ b/QtVsTools.RegExpr/expression/CharClassSet.cs
@@ -26,7 +26,6 @@
 **
 ****************************************************************************/
 
-using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
@@ -48,8 +47,8 @@
     ///
     public partial class CharClassSet : CharClass, IEnumerable<IEnumerable<Element>>
     {
-        public IEnumerable<Element> Positives { get; set; }
-        public IEnumerable<Element> Negatives { get; set; }
+        private IEnumerable<Element> Positives { get; set; }
+        private IEnumerable<Element> Negatives { get; set; }
 
         bool IsSubSet { get; set; }
         bool HasPositive { get { return Positives != null && Positives.Any(); } }
@@ -210,13 +209,13 @@
 
             public class Expr
             {
-                public Op Operator { get; private set; }
+                public Op Operator { get; }
 
-                public List<Expr> Factors { get; private set; }
+                public List<Expr> Factors { get; }
                 public Expr(Op op, List<Expr> factors) { Operator = op; Factors = factors; }
                 public Expr(Op op, params Expr[] factors) : this(op, factors.ToList()) { }
 
-                public CharClass Term { get; private set; }
+                public CharClass Term { get; }
                 public Expr(CharClass c) { Operator = Op.Term; Term = c; }
                 public static implicit operator Expr(CharClass c) { return new Expr(c); }
                 public static implicit operator Expr(string s) { return Char[s]; }
@@ -325,7 +324,7 @@
             {
                 public Expr Expr { get; set; }
                 public Queue<Expr> Children { get; set; }
-                public List<CharClassSet> SubSets { get; set; }
+                public List<CharClassSet> SubSets { get; }
                 public StackFrame()
                 {
                     Expr = null;
diff --git a/QtVsTools.RegExpr/expression/RegExprAssert.cs b/QtVsTools.RegExpr/expression/RegExprAssert.cs
index 09172c0..82c6721 100644
--- a/QtVsTools.RegExpr/expression/RegExprAssert.cs
+++ b/QtVsTools.RegExpr/expression/RegExprAssert.cs
@@ -26,9 +26,7 @@
 **
 ****************************************************************************/
 
-using System;
 using System.Collections.Generic;
-using System.Collections.Concurrent;
 using System.Text;
 
 namespace QtVsTools.SyntaxAnalysis
@@ -140,7 +138,7 @@
 
         public class AssertExprBuilder
         {
-            AssertTemplate Template { get; set; }
+            AssertTemplate Template { get; }
 
             public AssertExprBuilder(AssertTemplate template)
             {
diff --git a/QtVsTools.RegExpr/expression/RegExprRepeat.cs b/QtVsTools.RegExpr/expression/RegExprRepeat.cs
index a6ee1fa..d49b9ba 100644
--- a/QtVsTools.RegExpr/expression/RegExprRepeat.cs
+++ b/QtVsTools.RegExpr/expression/RegExprRepeat.cs
@@ -26,7 +26,6 @@
 **
 ****************************************************************************/
 
-using System;
 using System.Collections.Generic;
 using System.Text;
 
diff --git a/QtVsTools.RegExpr/expression/RegExprToken.cs b/QtVsTools.RegExpr/expression/RegExprToken.cs
index 08152b1..47dce8e 100644
--- a/QtVsTools.RegExpr/expression/RegExprToken.cs
+++ b/QtVsTools.RegExpr/expression/RegExprToken.cs
@@ -57,13 +57,13 @@
         {
             public string Id { get; set; }
 
-            public bool SkipLeadingWhitespace { get; set; }
-            public RegExpr LeadingWhitespace { get; set; }
+            private bool SkipLeadingWhitespace { get; }
+            private RegExpr LeadingWhitespace { get; }
 
-            public RegExpr Expr { get; set; }
+            private RegExpr Expr { get; }
 
-            public HashSet<Token> Children { get; set; }
-            public Dictionary<string, Token> Parents { get; set; }
+            private HashSet<Token> Children { get; }
+            public Dictionary<string, Token> Parents { get; }
             public IEnumerable<string> CaptureIds => Parents.Keys;
 
             public Token(string id, RegExpr skipWs, RegExpr expr)
@@ -170,7 +170,7 @@
             /// <summary>
             /// Set of rules that can be applied to the token.
             /// </summary>
-            TokenRules Rules { get; set; }
+            TokenRules Rules { get; }
 
             public void Add(IProductionRule rule)
             {
@@ -221,7 +221,7 @@
 
         public class TokenGroup : IEnumerable<string>
         {
-            HashSet<string> TokenIds { get; set; }
+            HashSet<string> TokenIds { get; }
 
             public TokenGroup(params string[] tokenIds)
             {
@@ -261,7 +261,7 @@
 
         public class TokenRules : IEnumerable<IProductionRule>
         {
-            Dictionary<RuleCallback.Selector, IProductionRule> Rules { get; set; }
+            Dictionary<RuleCallback.Selector, IProductionRule> Rules { get; }
             IProductionRule DefaultRule { get; set; }
 
             public TokenRules()
@@ -383,6 +383,6 @@
             public object Production { get; }
         }
 
-        static TokenEndOfList EndOfList = new TokenEndOfList();
+        static readonly TokenEndOfList EndOfList = new TokenEndOfList();
     }
 }
diff --git a/QtVsTools.RegExpr/expression/Renderer.cs b/QtVsTools.RegExpr/expression/Renderer.cs
index c79da8c..3f8b334 100644
--- a/QtVsTools.RegExpr/expression/Renderer.cs
+++ b/QtVsTools.RegExpr/expression/Renderer.cs
@@ -26,7 +26,6 @@
 **
 ****************************************************************************/
 
-using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
diff --git a/QtVsTools.RegExpr/parser/ParseTree.cs b/QtVsTools.RegExpr/parser/ParseTree.cs
index 1ee054c..4ff56d0 100644
--- a/QtVsTools.RegExpr/parser/ParseTree.cs
+++ b/QtVsTools.RegExpr/parser/ParseTree.cs
@@ -26,11 +26,8 @@
 **
 ****************************************************************************/
 
-using System;
 using System.Collections.Generic;
-using System.Diagnostics;
 using System.Linq;
-using System.Text.RegularExpressions;
 
 namespace QtVsTools.SyntaxAnalysis
 {
@@ -70,7 +67,7 @@
                     }
                 }
 
-                static NodeComparer _Comparer = new NodeComparer();
+                static readonly NodeComparer _Comparer = new NodeComparer();
                 public static IComparer<Node> Comparer { get { return _Comparer; } }
 
                 public Token Token { get; set; }
@@ -80,11 +77,9 @@
 
                 public Node Parent { get; set; }
 
-                SortedList<int, Node> _ChildNodes = new SortedList<int, Node>();
-                public SortedList<int, Node> ChildNodes { get { return _ChildNodes; } }
+                public SortedList<int, Node> ChildNodes { get; } = new SortedList<int, Node>();
 
-                ProductionObjects _ChildProductions = new ProductionObjects();
-                public ProductionObjects ChildProductions { get { return _ChildProductions; } }
+                public ProductionObjects ChildProductions { get; } = new ProductionObjects();
 
                 public Queue<Node> TokenStream { get; set; }
                 public Stack<Node> OperatorStack { get; set; }
diff --git a/QtVsTools.RegExpr/parser/Parser.cs b/QtVsTools.RegExpr/parser/Parser.cs
index f69cae4..e2b9f36 100644
--- a/QtVsTools.RegExpr/parser/Parser.cs
+++ b/QtVsTools.RegExpr/parser/Parser.cs
@@ -27,8 +27,6 @@
 ****************************************************************************/
 
 using System;
-using System.Collections.Generic;
-using System.Diagnostics;
 using System.Linq;
 using System.Text.RegularExpressions;
 
@@ -46,7 +44,7 @@
         /// </summary>
         public partial class Parser
         {
-            Renderer Renderer { get; set; }
+            Renderer Renderer { get; }
             Pattern Pattern { get; set; }
             public Regex Regex { get; private set; }
 
@@ -118,11 +116,9 @@
 
                 foreach (var node in nodes.Where(n => n.Token != Pattern.Root)) {
                     // Get nodes captured by parent token
-                    Token parentToken;
-                    if (!node.Token.Parents.TryGetValue(node.CaptureId, out parentToken))
+                    if (!node.Token.Parents.TryGetValue(node.CaptureId, out Token parentToken))
                         throw new ParseErrorException("Unknown capture ID");
-                    ParseTree.Node[] parentNodes;
-                    if (!nodesByToken.TryGetValue(parentToken, out parentNodes))
+                    if (!nodesByToken.TryGetValue(parentToken, out ParseTree.Node[] parentNodes))
                         throw new ParseErrorException("Missing parent nodes");
                     // Find parent node
                     int idx = Array.BinarySearch(parentNodes, node, ParseTree.Node.Comparer);
diff --git a/QtVsTools.RegExpr/production/Production.cs b/QtVsTools.RegExpr/production/Production.cs
index 8dc30cc..39d770b 100644
--- a/QtVsTools.RegExpr/production/Production.cs
+++ b/QtVsTools.RegExpr/production/Production.cs
@@ -30,11 +30,7 @@
 using System.Collections;
 using System.Collections.Generic;
 using System.Diagnostics;
-using System.IO;
 using System.Linq;
-using System.Linq.Expressions;
-using System.Reflection;
-using System.Text;
 
 namespace QtVsTools.SyntaxAnalysis
 {
@@ -215,8 +211,8 @@
         /// </summary>
         public partial class ProductionObjects : IEnumerable<KeyValuePair<string, object>>
         {
-            List<KeyValuePair<string, object>> Productions { get; set; }
-            Dictionary<string, List<object>> ProductionsByTokenId { get; set; }
+            List<KeyValuePair<string, object>> Productions { get; }
+            Dictionary<string, List<object>> ProductionsByTokenId { get; }
 
             public ProductionObjects()
             {
@@ -227,8 +223,7 @@
             public void Add(string tokenId, object prodObj)
             {
                 Productions.Add(new KeyValuePair<string, object>(tokenId, prodObj));
-                List<object> prodObjs;
-                if (!ProductionsByTokenId.TryGetValue(tokenId, out prodObjs))
+                if (!ProductionsByTokenId.TryGetValue(tokenId, out List<object> prodObjs))
                     ProductionsByTokenId.Add(tokenId, prodObjs = new List<object>());
                 prodObjs.Add(prodObj);
             }
@@ -238,8 +233,7 @@
                 if (string.IsNullOrEmpty(tokenId))
                     return Empty<T>();
 
-                List<object> tokenProds;
-                if (!ProductionsByTokenId.TryGetValue(tokenId, out tokenProds))
+                if (!ProductionsByTokenId.TryGetValue(tokenId, out List<object> tokenProds))
                     return Empty<T>();
 
                 return tokenProds
diff --git a/QtVsTools.RegExpr/production/ProductionRule.cs b/QtVsTools.RegExpr/production/ProductionRule.cs
index 8884aae..2299177 100644
--- a/QtVsTools.RegExpr/production/ProductionRule.cs
+++ b/QtVsTools.RegExpr/production/ProductionRule.cs
@@ -29,11 +29,8 @@
 using System;
 using System.Collections;
 using System.Collections.Generic;
-using System.IO;
 using System.Linq;
-using System.Linq.Expressions;
 using System.Reflection;
-using System.Text;
 
 namespace QtVsTools.SyntaxAnalysis
 {
@@ -66,7 +63,7 @@
             public virtual Delimiter Delimiters { get { return Delimiter.None; } }
             public virtual Operand Operands { get { return Operand.None; } }
 
-            protected List<IRuleAction<T>> Actions = new List<IRuleAction<T>>();
+            private readonly List<IRuleAction<T>> Actions = new List<IRuleAction<T>>();
 
             protected void Init(
                 int priority, RuleCallback.Selector select, RuleCallback.PreCondition pre)
diff --git a/QtVsTools.RegExpr/production/ProductionRuleAction.cs b/QtVsTools.RegExpr/production/ProductionRuleAction.cs
index 71662d8..7d7a2e0 100644
--- a/QtVsTools.RegExpr/production/ProductionRuleAction.cs
+++ b/QtVsTools.RegExpr/production/ProductionRuleAction.cs
@@ -135,11 +135,9 @@
             public bool Execute(ref T prod, string value, params object[] operands)
             {
                 int idx = 0;
-                T1 x;
-                T2 y;
-                if (!GetOperand(out x, operands, ref idx))
+                if (!GetOperand(out T1 x, operands, ref idx))
                     return false;
-                if (!GetOperand(out y, operands, ref idx))
+                if (!GetOperand(out T2 y, operands, ref idx))
                     return false;
 
                 if (!TestAssert(prod, value, x, y))
diff --git a/QtVsTools.RegExpr/utils/Consts.cs b/QtVsTools.RegExpr/utils/Consts.cs
index 4835958..ec1e394 100644
--- a/QtVsTools.RegExpr/utils/Consts.cs
+++ b/QtVsTools.RegExpr/utils/Consts.cs
@@ -26,11 +26,6 @@
 **
 ****************************************************************************/
 
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
 namespace QtVsTools.SyntaxAnalysis
 {
     using static CharClass;
@@ -82,7 +77,7 @@
         /// <summary><![CDATA[
         /// Equivalent to: [\S]
         /// ]]></summary>
-        public static CharClassLiteral CharNonSpace
+        private static CharClassLiteral CharNonSpace
         { get { return new CharClassLiteral { LiteralChars = @"\S" }; } }
 
         /// <summary><![CDATA[
@@ -181,21 +176,17 @@
         public static RegExpr SkipWs
         { get { return new Token(); } }
 
-        static CharExprBuilder _Char = new CharExprBuilder();
+        static readonly CharExprBuilder _Char = new CharExprBuilder();
         public static CharExprBuilder Char { get { return _Char; } }
         public static CharExprBuilder Chars { get { return _Char; } }
 
-        static CharSetExprBuilder _CharSet = new CharSetExprBuilder();
-        public static CharSetExprBuilder CharSet { get { return _CharSet; } }
+        public static CharSetExprBuilder CharSet { get; } = new CharSetExprBuilder();
 
-        static CharSetRawExprBuilder _CharSetRaw = new CharSetRawExprBuilder();
-        public static CharSetRawExprBuilder CharSetRaw { get { return _CharSetRaw; } }
+        public static CharSetRawExprBuilder CharSetRaw { get; } = new CharSetRawExprBuilder();
 
-        static AssertExprBuilder _LookAhead = new AssertExprBuilder(AssertLookAhead);
-        public static AssertExprBuilder LookAhead { get { return _LookAhead; } }
+        public static AssertExprBuilder LookAhead { get; } = new AssertExprBuilder(AssertLookAhead);
 
-        static AssertExprBuilder _LookBehind = new AssertExprBuilder(AssertLookBehind);
-        public static AssertExprBuilder LookBehind { get { return _LookBehind; } }
+        public static AssertExprBuilder LookBehind { get; } = new AssertExprBuilder(AssertLookBehind);
 
         public const SkipWhitespace SkipWs_Disable = SkipWhitespace.Disable;
     }
diff --git a/QtVsTools.Wizards/Common/GuiPage.xaml b/QtVsTools.Wizards/Common/GuiPage.xaml
new file mode 100644
index 0000000..cdbc560
--- /dev/null
+++ b/QtVsTools.Wizards/Common/GuiPage.xaml
@@ -0,0 +1,307 @@
+<!--
+    *****************************************************************************
+    **
+    ** Copyright (C) 2022 The Qt Company Ltd.
+    ** Contact: https://www.qt.io/licensing/
+    **
+    ** This file is part of the Qt VS Tools.
+    **
+    ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+    ** Commercial License Usage
+    ** Licensees holding valid commercial Qt licenses may use this file in
+    ** accordance with the commercial license agreement provided with the
+    ** Software or, alternatively, in accordance with the terms contained in
+    ** a written agreement between you and The Qt Company. For licensing terms
+    ** and conditions see https://www.qt.io/terms-conditions. For further
+    ** information use the contact form at https://www.qt.io/contact-us.
+    **
+    ** GNU General Public License Usage
+    ** Alternatively, this file may be used under the terms of the GNU
+    ** General Public License version 3 as published by the Free Software
+    ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+    ** included in the packaging of this file. Please review the following
+    ** information to ensure the GNU General Public License requirements will
+    ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+    **
+    ** $QT_END_LICENSE$
+    **
+    *****************************************************************************
+-->
+
+<common:WizardPage x:Class="QtVsTools.Wizards.Common.GuiPage"
+                  xmlns:common="clr-namespace:QtVsTools.Wizards.Common"
+                  xmlns:util="clr-namespace:QtVsTools.Wizards.Util"
+                  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+                  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+                  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+                  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+                  KeepAlive="True"
+                  mc:Ignorable="d"
+                  d:DesignHeight="445"
+                  d:DesignWidth="585">
+    <Grid>
+        <Grid.ColumnDefinitions>
+            <ColumnDefinition Width="100" />
+            <ColumnDefinition Width="*" />
+        </Grid.ColumnDefinitions>
+        <Image Grid.Column="0"
+               HorizontalAlignment="Center"
+               Source="/QtVsTools.Wizards;component/Resources/Qt-logo-small.png"
+               VerticalAlignment="Top"
+               Margin="0,25,0,0"
+               RenderTransformOrigin="1,0">
+            <Image.RenderTransform>
+                <TransformGroup>
+                    <ScaleTransform ScaleY="0.86"
+                                    ScaleX="0.86" />
+                </TransformGroup>
+            </Image.RenderTransform>
+        </Image>
+        <Grid Grid.Column="1"
+              Margin="25,25,10,0">
+            <Grid.RowDefinitions>
+                <RowDefinition Height="Auto" />
+                <RowDefinition Height="*" />
+                <RowDefinition Height="Auto" />
+            </Grid.RowDefinitions>
+            <TextBlock TextWrapping="Wrap"
+                       Grid.Row="0">
+                <Run FontWeight="Bold"
+                     Text="{Binding Path=Header}" />
+                <LineBreak />
+                <LineBreak />
+                <Run Text="{Binding Path=Message}" />
+                <LineBreak />
+            </TextBlock>
+            <Grid Grid.Row="1">
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="*" />
+                    <ColumnDefinition Width="*" />
+                </Grid.ColumnDefinitions>
+                <Grid.Resources>
+                    <Style TargetType="TextBox">
+                        <Style.Triggers>
+                            <Trigger Property="Validation.HasError"
+                                     Value="true">
+                                <Setter Property="ToolTip"
+                                        Value="{Binding RelativeSource={RelativeSource Self},
+                                         Path=(Validation.Errors)[0].ErrorContent}" />
+                            </Trigger>
+                        </Style.Triggers>
+                    </Style>
+                </Grid.Resources>
+                <StackPanel Grid.Column="0">
+                    <TextBlock Text="Class Name:"
+                               Margin="0,0,10,0" />
+                    <TextBox Margin="0,0,10,15"
+                             Name="ClassName"
+                             TextChanged="OnClassNameChanged"
+                             TabIndex="0">
+                        <TextBox.Text>
+                            <Binding Path="Data.ClassName"
+                                     NotifyOnValidationError="True"
+                                     UpdateSourceTrigger="PropertyChanged">
+                                <Binding.ValidationRules>
+                                    <util:ClassNameValidationRule SupportNamespaces="True"/>
+                                </Binding.ValidationRules>
+                            </Binding>
+                        </TextBox.Text>
+                    </TextBox>
+                    <TextBlock Text="User Interface (.ui) file:"
+                               Margin="0,0,10,0" />
+                    <TextBox Name="UiFile"
+                             Margin="0,0,10,52"
+                             TabIndex="2">
+                        <TextBox.Text>
+                            <Binding Path="Data.UiFile"
+                                     NotifyOnValidationError="True"
+                                     UpdateSourceTrigger="PropertyChanged">
+                                <Binding.ValidationRules>
+                                    <util:FileNameValidationRule FileExt=".ui" />
+                                    <util:FileExistsinFilterValidationRule Filter="FL_UiFiles" />
+                                </Binding.ValidationRules>
+                            </Binding>
+                        </TextBox.Text>
+                    </TextBox>
+                    <TextBlock Text="Header (.h) file:"
+                               Margin="0,0,10,0" />
+                    <TextBox Name="ClassHeaderFile"
+                             Margin="0,0,10,5"
+                             TabIndex="6">
+                        <TextBox.Text>
+                            <Binding Path="Data.ClassHeaderFile"
+                                     NotifyOnValidationError="True"
+                                     UpdateSourceTrigger="PropertyChanged">
+                                <Binding.ValidationRules>
+                                    <util:FileNameValidationRule FileExt=".h" />
+                                    <util:FileExistsinFilterValidationRule Filter="FL_HFiles" />
+                                </Binding.ValidationRules>
+                            </Binding>
+                        </TextBox.Text>
+                    </TextBox>
+                    <TextBlock Text="Source (.cpp) file:"
+                               Margin="0,0,0,0" />
+                    <TextBox Name="ClassSourceFile"
+                             Margin="0,0,10,15"
+                             TabIndex="8">
+                        <TextBox.Text>
+                            <Binding Path="Data.ClassSourceFile"
+                                     NotifyOnValidationError="True"
+                                     UpdateSourceTrigger="PropertyChanged">
+                                <Binding.ValidationRules>
+                                    <util:FileNameValidationRule FileExt=".cpp" />
+                                    <util:FileExistsinFilterValidationRule Filter="FL_CppFiles" />
+                                </Binding.ValidationRules>
+                            </Binding>
+                        </TextBox.Text>
+                    </TextBox>
+
+                </StackPanel>
+                <StackPanel Grid.Column="1">
+                    <TextBlock Text="Base class:" />
+                    <ComboBox Margin="0,0,0,11"
+                                  IsEditable="{Binding Path=IsClassWizardPage}"
+                                  SelectedIndex="0"
+                                  Text="{Binding Path=Data.BaseClass}"
+                                  IsSynchronizedWithCurrentItem="True"
+                                  TabIndex="1">
+                        <ComboBoxItem Content="QMainWindow"
+                                          IsSelected="True" />
+                        <ComboBoxItem Content="QWidget" />
+                        <ComboBoxItem Content="QDialog" />
+                    </ComboBox>
+                    <TextBlock TextWrapping="Wrap"
+                           Text="Ui Class Inclusion as:"
+                           Margin="0,0,0,5"
+                           VerticalAlignment="Top"/>
+                    <StackPanel Grid.Column="1"
+                            Margin="10,0,0,10">
+                        <StackPanel.Resources>
+                            <util:UiClassInclusionConverter x:Key="UiClassInclusionConverter" />
+                        </StackPanel.Resources>
+                        <RadioButton Content="Member"
+                                 Margin="0,0,0,5"
+                                 IsChecked="{
+                                    Binding Path=Data.UiClassInclusion,
+                                    Converter={StaticResource UiClassInclusionConverter},
+                                    ConverterParameter={x:Static common:UiClassInclusion.Member}
+                                 }"
+                                 TabIndex="3" />
+                        <RadioButton Content="Member Pointer"
+                                 Margin="0,0,0,5"
+                                 IsChecked="{
+                                    Binding Path=Data.UiClassInclusion,
+                                    Converter={StaticResource UiClassInclusionConverter},
+                                    ConverterParameter={x:Static common:UiClassInclusion.MemberPointer}
+                                 }"
+                                 TabIndex="4" />
+                        <RadioButton Content="Multiple Inheritance"
+                                 IsChecked="{
+                                    Binding Path=Data.UiClassInclusion,
+                                    Converter={StaticResource UiClassInclusionConverter},
+                                    ConverterParameter={x:Static common:UiClassInclusion.MultipleInheritance}
+                                 }"
+                                 TabIndex="5" />
+                    </StackPanel>
+                    <CheckBox Content="Insert Q_OBJECT macro"
+                              TabIndex="7"
+                              Margin="0,0,0,-17"
+                              Name="InsertQObjectMacro"
+                              Visibility="{Binding Path=QObjectMacro}"
+                              IsChecked="{Binding Path=Data.InsertQObjectMacro}" />
+                    <TextBlock Margin="0,0,10,0"
+                               Text="Resource (.qrc) file:"
+                               Visibility="{Binding Path=ClassPageVisible}" />
+                    <TextBox Name="QrcFile"
+                             Margin="0,0,0,23"
+                             TabIndex="7"
+                             Visibility="{Binding Path=ClassPageVisible}" >
+                        <TextBox.Text>
+                            <Binding Path="Data.QrcFile"
+                                     NotifyOnValidationError="True"
+                                     UpdateSourceTrigger="PropertyChanged">
+                                <Binding.ValidationRules>
+                                    <util:FileNameValidationRule FileExt=".qrc" />
+                                </Binding.ValidationRules>
+                            </Binding>
+                        </TextBox.Text>
+                    </TextBox>
+                    <CheckBox Content="Lower case file names"
+                              Margin="0,0,0,5"
+                              Name="LowerCaseFileNames"
+                              TabIndex="9"
+                              Click="OnLowerCaseFileNamesClick" />
+                    <CheckBox Content="Precompiled header"
+                              Margin="0,0,0,5"
+                              IsChecked="{Binding Path=Data.UsePrecompiledHeader}"
+                              TabIndex="10"
+                              Visibility="{Binding Path=ClassPageVisible}"/>
+                    <CheckBox Content="Add default application icon"
+                              Margin="0,0,0,0"
+                              IsChecked="{Binding Path=Data.AddDefaultAppIcon}"
+                              TabIndex="11"
+                              Visibility="{Binding Path=ClassPageVisible}" />
+                </StackPanel>
+            </Grid>
+            <StackPanel HorizontalAlignment="Right"
+                        Orientation="Horizontal"
+                        Grid.Row="2"
+                        Margin="0,0,0,10">
+                <Button Click="OnPreviousButtonClick"
+                        Name="PreviousButton"
+                        IsEnabled="{Binding Path=PreviousButtonEnabled}"
+                        MinWidth="75">&lt; _Previous</Button>
+                <Button MinWidth="75"
+                        Name="NextButton"
+                        Click="OnNextButtonClick"
+                        IsEnabled="{Binding Path=NextButtonEnabled}"
+                        Margin="10,0,0,0">_Next &gt;</Button>
+                <Button MinWidth="75"
+                        Click="OnFinishButtonClick"
+                        Margin="10,0,0,0"
+                        IsDefault="True"
+                        Name="FinishButton"
+                        Content="_Finish"
+                        VerticalAlignment="Bottom">
+                    <Button.Style>
+                        <Style TargetType="Button">
+                            <Setter Property="IsEnabled"
+                                    Value="false" />
+                            <Style.Triggers>
+                                <MultiDataTrigger>
+                                    <MultiDataTrigger.Conditions>
+                                        <Condition Binding="{Binding Path=FinishButtonEnabled}"
+                                                   Value="true" />
+                                        <Condition Binding="{Binding ElementName=ClassName,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                        <Condition Binding="{Binding ElementName=ClassHeaderFile,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                        <Condition Binding="{Binding ElementName=ClassSourceFile,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                        <Condition Binding="{Binding ElementName=UiFile,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                        <Condition Binding="{Binding ElementName=QrcFile,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                    </MultiDataTrigger.Conditions>
+                                    <Setter Property="IsEnabled"
+                                            Value="true" />
+                                </MultiDataTrigger>
+                            </Style.Triggers>
+                        </Style>
+                    </Button.Style>
+                </Button>
+                <Button Click="OnCancelButtonClick"
+                        MinWidth="75"
+                        Margin="10,0,0,0"
+                        Name="CancelButton"
+                        IsEnabled="{Binding Path=CancelButtonEnabled}"
+                        IsCancel="True">_Cancel</Button>
+            </StackPanel>
+        </Grid>
+    </Grid>
+</common:WizardPage>
diff --git a/QtVsTools.Wizards/Common/GuiPage.xaml.cs b/QtVsTools.Wizards/Common/GuiPage.xaml.cs
new file mode 100644
index 0000000..764ca09
--- /dev/null
+++ b/QtVsTools.Wizards/Common/GuiPage.xaml.cs
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Windows;
+using System.Windows.Controls;
+
+namespace QtVsTools.Wizards.Common
+{
+    public partial class GuiPage : WizardPage
+    {
+        public bool IsClassWizardPage { get; set; } = false;
+        public Visibility ClassPageVisible => IsClassWizardPage ? Visibility.Hidden : Visibility.Visible;
+        public Visibility QObjectMacro => IsClassWizardPage ? Visibility.Visible : Visibility.Collapsed;
+
+        public GuiPage()
+        {
+            InitializeComponent();
+            DataContext = this;
+            UpdateFileNames();
+        }
+
+        private void OnClassNameChanged(object sender, TextChangedEventArgs e)
+        {
+            UpdateFileNames();
+        }
+
+        private void OnLowerCaseFileNamesClick(object sender, RoutedEventArgs e)
+        {
+            UpdateFileNames();
+        }
+
+        private void UpdateFileNames()
+        {
+            var filename = ClassName.Text;
+            if (LowerCaseFileNames.IsChecked.GetValueOrDefault())
+                filename = filename.ToLower();
+
+            // support namespaces in class name
+            var index = filename.LastIndexOf(@":", System.StringComparison.Ordinal);
+            if (index >= 0)
+                filename = filename.Substring(index + 1);
+
+            ClassHeaderFile.Text = filename + @".h";
+            ClassSourceFile.Text = filename + @".cpp";
+            UiFile.Text = filename + @".ui";
+            QrcFile.Text = filename + @".qrc";
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/Common/UiClassInclusion.cs b/QtVsTools.Wizards/Common/UiClassInclusion.cs
new file mode 100644
index 0000000..b99c71f
--- /dev/null
+++ b/QtVsTools.Wizards/Common/UiClassInclusion.cs
@@ -0,0 +1,37 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+namespace QtVsTools.Wizards.Common
+{
+    public enum UiClassInclusion
+    {
+        Member,
+        MemberPointer,
+        MultipleInheritance
+    }
+}
diff --git a/QtVsTools.Wizards/Common/WizardData.cs b/QtVsTools.Wizards/Common/WizardData.cs
new file mode 100644
index 0000000..8424f5e
--- /dev/null
+++ b/QtVsTools.Wizards/Common/WizardData.cs
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Collections.Generic;
+
+namespace QtVsTools.Wizards.Common
+{
+    using ProjectWizard;
+
+    public class WizardData
+    {
+        public WizardData()
+        {
+            Modules = new List<string>();
+            DefaultModules = new List<string>();
+        }
+
+        public string ClassName { get; set; }
+        public string BaseClass { get; set; }
+        public string PluginClass { get; set; }
+        public string ConstructorSignature { get; set; }
+
+        public string ClassHeaderFile { get; set; }
+        public string ClassSourceFile { get; set; }
+        public string PluginHeaderFile { get; set; }
+        public string PluginSourceFile { get; set; }
+
+        public string UiFile { get; set; }
+        public string QrcFile { get; set; }
+
+        private List<string> Modules { get; }
+        public List<string> DefaultModules { get; set; }
+
+        public bool AddDefaultAppIcon { get; set; }
+        public bool CreateStaticLibrary { get; set; }
+        public bool UsePrecompiledHeader { get; set; }
+        public bool InsertQObjectMacro { get; set; }
+        public bool LowerCaseFileNames { get; set; }
+        public UiClassInclusion UiClassInclusion { get; set; }
+
+        public IEnumerable<IWizardConfiguration> Configs { get; set; }
+    }
+}
diff --git a/QtVsTools.Wizards/Common/WizardIntroPage.xaml b/QtVsTools.Wizards/Common/WizardIntroPage.xaml
new file mode 100644
index 0000000..5db4608
--- /dev/null
+++ b/QtVsTools.Wizards/Common/WizardIntroPage.xaml
@@ -0,0 +1,102 @@
+<!--
+    *****************************************************************************
+    **
+    ** Copyright (C) 2016 The Qt Company Ltd.
+    ** Contact: https://www.qt.io/licensing/
+    **
+    ** This file is part of the Qt VS Tools.
+    **
+    ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+    ** Commercial License Usage
+    ** Licensees holding valid commercial Qt licenses may use this file in
+    ** accordance with the commercial license agreement provided with the
+    ** Software or, alternatively, in accordance with the terms contained in
+    ** a written agreement between you and The Qt Company. For licensing terms
+    ** and conditions see https://www.qt.io/terms-conditions. For further
+    ** information use the contact form at https://www.qt.io/contact-us.
+    **
+    ** GNU General Public License Usage
+    ** Alternatively, this file may be used under the terms of the GNU
+    ** General Public License version 3 as published by the Free Software
+    ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+    ** included in the packaging of this file. Please review the following
+    ** information to ensure the GNU General Public License requirements will
+    ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+    **
+    ** $QT_END_LICENSE$
+    **
+    *****************************************************************************
+-->
+
+<common:WizardPage x:Class="QtVsTools.Wizards.Common.WizardIntroPage"
+                  xmlns:common="clr-namespace:QtVsTools.Wizards.Common"
+                  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+                  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+                  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+                  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+                  KeepAlive="True"
+                  mc:Ignorable="d"
+                  d:DesignHeight="445"
+                  d:DesignWidth="585">
+    <Grid>
+        <Grid.ColumnDefinitions>
+            <ColumnDefinition Width="100" />
+            <ColumnDefinition Width="*" />
+        </Grid.ColumnDefinitions>
+        <Image Grid.Column="0"
+               HorizontalAlignment="Center"
+               Source="/QtVsTools.Wizards;component/Resources/Qt-logo-small.png"
+               VerticalAlignment="Top"
+               Margin="0,25,0,0"
+               RenderTransformOrigin="1,0">
+            <Image.RenderTransform>
+                <TransformGroup>
+                    <ScaleTransform ScaleY="0.86"
+                                    ScaleX="0.86" />
+                </TransformGroup>
+            </Image.RenderTransform>
+        </Image>
+        <Grid Grid.Column="1"
+              Margin="25,25,10,0">
+            <Grid.RowDefinitions>
+                <RowDefinition Height="*" />
+                <RowDefinition Height="Auto" />
+            </Grid.RowDefinitions>
+            <TextBlock TextWrapping="Wrap"
+                       Grid.Row="0">
+                <Run FontWeight="Bold"
+                     Text="{Binding Path=Header}" />
+                <LineBreak />
+                <LineBreak />
+                <Run Text="{Binding Path=Message}" />
+            </TextBlock>
+            <StackPanel HorizontalAlignment="Right"
+                        Orientation="Horizontal"
+                        Grid.Row="1"
+                        Margin="0,0,0,10">
+                <Button Click="OnPreviousButtonClick"
+                        Name="PreviousButton"
+                        IsEnabled="{Binding Path=PreviousButtonEnabled}"
+                        MinWidth="75">&lt; _Previous</Button>
+                <Button MinWidth="75"
+                        Name="NextButton"
+                        Click="OnNextButtonClick"
+                        IsEnabled="{Binding Path=NextButtonEnabled}"
+                        Margin="10,0,0,0">_Next &gt;</Button>
+                <Button MinWidth="75"
+                        Click="OnFinishButtonClick"
+                        Margin="10,0,0,0"
+                        IsDefault="True"
+                        IsEnabled="{Binding Path=FinishButtonEnabled}"
+                        Name="FinishButton"
+                        VerticalAlignment="Bottom">_Finish</Button>
+                <Button Click="OnCancelButtonClick"
+                        MinWidth="75"
+                        Margin="10,0,0,0"
+                        Name="CancelButton"
+                        IsEnabled="{Binding Path=CancelButtonEnabled}"
+                        IsCancel="True">_Cancel</Button>
+            </StackPanel>
+        </Grid>
+    </Grid>
+</common:WizardPage>
diff --git a/QtVsTools.Wizards/Common/WizardIntroPage.xaml.cs b/QtVsTools.Wizards/Common/WizardIntroPage.xaml.cs
new file mode 100644
index 0000000..5bee6ff
--- /dev/null
+++ b/QtVsTools.Wizards/Common/WizardIntroPage.xaml.cs
@@ -0,0 +1,39 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+namespace QtVsTools.Wizards.Common
+{
+    public partial class WizardIntroPage : WizardPage
+    {
+        public WizardIntroPage()
+        {
+            InitializeComponent();
+            DataContext = this;
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/Common/WizardPage.cs b/QtVsTools.Wizards/Common/WizardPage.cs
new file mode 100644
index 0000000..e3959ae
--- /dev/null
+++ b/QtVsTools.Wizards/Common/WizardPage.cs
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Windows;
+using System.Windows.Navigation;
+
+namespace QtVsTools.Wizards.Common
+{
+    public class WizardPage : PageFunction<WizardResult>
+    {
+        public string Header { get; set; }
+        public string Message { get; set; }
+
+        public WizardData Data { get; set; }
+        public WizardWindow Wizard { get; set; }
+
+        public bool PreviousButtonEnabled { get; set; }
+        public bool NextButtonEnabled { get; set; }
+        public bool FinishButtonEnabled { get; set; }
+        public bool CancelButtonEnabled { get; set; }
+
+        public event EventHandler NavigateForward;
+        public event EventHandler NavigatedBackward;
+
+        public event ReturnEventHandler<WizardResult> ReturnEx;
+        public void OnReturnEx(ReturnEventArgs<WizardResult> e)
+        {
+            if (ReturnEx != null)
+                ReturnEx.Invoke(this, e);
+        }
+
+        protected virtual void OnPreviousButtonClick(object sender, RoutedEventArgs e)
+        {
+            if (NavigationService == null || !NavigationService.CanGoBack)
+                return;
+
+            NavigationService.GoBack();
+            OnNavigatedBackward(new EventArgs());
+        }
+
+        protected virtual void OnNextButtonClick(object sender, RoutedEventArgs e)
+        {
+            if (NavigationService == null || Wizard == null)
+                return;
+
+            try {
+                OnNavigateForward(new EventArgs());
+            } catch (InvalidOperationException) {
+                return; // we can't navigate any further
+            }
+
+            if (!NavigationService.CanGoForward) {
+                Wizard.NextPage.ReturnEx += OnPageReturn;
+                NavigationService.Navigate(Wizard.NextPage);
+            } else {
+                NavigationService.GoForward();
+            }
+        }
+
+        protected virtual void OnFinishButtonClick(object sender, RoutedEventArgs e)
+        {
+            OnReturnEx(new ReturnEventArgs<WizardResult>(WizardResult.Finished));
+        }
+
+        protected virtual void OnCancelButtonClick(object sender, RoutedEventArgs e)
+        {
+            OnReturnEx(new ReturnEventArgs<WizardResult>(WizardResult.Canceled));
+            OnReturn(null);
+        }
+
+        protected virtual void OnNavigateForward(EventArgs e)
+        {
+            if (NavigateForward != null)
+                NavigateForward.Invoke(this, e);
+        }
+
+        protected virtual void OnNavigatedBackward(EventArgs e)
+        {
+            if (NavigatedBackward != null)
+                NavigatedBackward.Invoke(this, e);
+        }
+
+        private void OnPageReturn(object sender, ReturnEventArgs<WizardResult> e)
+        {
+            OnReturnEx(e);
+            OnReturn(null);
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/Common/WizardResult.cs b/QtVsTools.Wizards/Common/WizardResult.cs
new file mode 100644
index 0000000..96bc3f4
--- /dev/null
+++ b/QtVsTools.Wizards/Common/WizardResult.cs
@@ -0,0 +1,37 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+namespace QtVsTools.Wizards.Common
+{
+    public enum WizardResult
+    {
+        Canceled,
+        Finished,
+        Exception
+    }
+}
diff --git a/QtVsTools.Wizards/Common/WizardWindow.xaml b/QtVsTools.Wizards/Common/WizardWindow.xaml
new file mode 100644
index 0000000..9b461e7
--- /dev/null
+++ b/QtVsTools.Wizards/Common/WizardWindow.xaml
@@ -0,0 +1,44 @@
+<!--
+    *****************************************************************************
+    **
+    ** Copyright (C) 2016 The Qt Company Ltd.
+    ** Contact: https://www.qt.io/licensing/
+    **
+    ** This file is part of the Qt VS Tools.
+    **
+    ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+    ** Commercial License Usage
+    ** Licensees holding valid commercial Qt licenses may use this file in
+    ** accordance with the commercial license agreement provided with the
+    ** Software or, alternatively, in accordance with the terms contained in
+    ** a written agreement between you and The Qt Company. For licensing terms
+    ** and conditions see https://www.qt.io/terms-conditions. For further
+    ** information use the contact form at https://www.qt.io/contact-us.
+    **
+    ** GNU General Public License Usage
+    ** Alternatively, this file may be used under the terms of the GNU
+    ** General Public License version 3 as published by the Free Software
+    ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+    ** included in the packaging of this file. Please review the following
+    ** information to ensure the GNU General Public License requirements will
+    ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+    **
+    ** $QT_END_LICENSE$
+    **
+    *****************************************************************************
+-->
+
+<NavigationWindow x:Class="QtVsTools.Wizards.Common.WizardWindow"
+                  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+                  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+                  WindowStartupLocation="CenterOwner"
+                  ShowInTaskbar="False"
+                  ShowsNavigationUI="False"
+                  Title="Wizard Window"
+                  ResizeMode="CanResizeWithGrip"
+                  MinHeight="480"
+                  MinWidth="640"
+                  Height="480"
+                  Width="640"
+                  MaxHeight="768"
+                  MaxWidth="1024" />
diff --git a/QtVsTools.Wizards/Common/WizardWindow.xaml.cs b/QtVsTools.Wizards/Common/WizardWindow.xaml.cs
new file mode 100644
index 0000000..95028a3
--- /dev/null
+++ b/QtVsTools.Wizards/Common/WizardWindow.xaml.cs
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Windows.Navigation;
+
+namespace QtVsTools.Wizards.Common
+{
+    using Wizards.Util;
+
+    public partial class WizardWindow : NavigationWindow, IEnumerable<WizardPage>
+    {
+
+        public WizardWindow(IEnumerable<WizardPage> pages = null, string title = null)
+        {
+            InitializeComponent();
+            SourceInitialized += OnSourceInitialized;
+
+            if (title != null)
+                Title = title;
+
+            Pages = new List<WizardPage>();
+
+            if (pages != null) {
+                foreach (var page in pages)
+                    Add(page);
+            }
+        }
+
+        public void Add(WizardPage page)
+        {
+            bool isFirstPage = (Pages.Count == 0);
+            page.Wizard = this;
+            page.NavigateForward += OnNavigateForward;
+            page.NavigatedBackward += OnNavigatedBackwards;
+            Pages.Add(page);
+
+            if (isFirstPage) {
+                NextPage.ReturnEx += OnPageReturn;
+                Navigate(NextPage); // put on navigation stack
+            }
+        }
+
+        public WizardPage NextPage
+        {
+            get
+            {
+                return Pages[currentPage];
+            }
+        }
+
+        private List<WizardPage> Pages
+        {
+            get;
+        }
+
+        public IEnumerator<WizardPage> GetEnumerator()
+        {
+            return ((IEnumerable<WizardPage>)Pages).GetEnumerator();
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return ((IEnumerable<WizardPage>)Pages).GetEnumerator();
+        }
+
+        private int currentPage;
+
+        private void OnSourceInitialized(object sender, EventArgs e)
+        {
+            try {
+                var STYLE = -16; // see winuser.h
+                var hwnd = new System.Windows.Interop.WindowInteropHelper(this).Handle;
+                UnsafeNativeMethods.SetWindowLong(hwnd, STYLE,
+                    NativeMethods.GetWindowLong(hwnd, STYLE) & ~(0x10000 | 0x20000));
+            } catch {
+                // Ignore if we can't remove the buttons.
+                SourceInitialized -= OnSourceInitialized;
+            }
+        }
+
+        private void OnNavigateForward(object sender, EventArgs e)
+        {
+            var tmp = currentPage + 1;
+            if (tmp >= Pages.Count) {
+                throw new InvalidOperationException(@"Current wizard page "
+                    + @"cannot be equal or greater than pages count.");
+            }
+            currentPage++;
+        }
+
+        private void OnPageReturn(object sender, ReturnEventArgs<WizardResult> e)
+        {
+            if (DialogResult == null)
+                DialogResult = (e.Result == WizardResult.Finished);
+        }
+
+        private void OnNavigatedBackwards(object sender, EventArgs e)
+        {
+            var tmp = currentPage - 1;
+            if (tmp < 0)
+                throw new InvalidOperationException(@"Current wizard page cannot be less then 0.");
+            currentPage--;
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/ItemWizard/QtClass/QtClassPage.xaml b/QtVsTools.Wizards/ItemWizard/QtClass/QtClassPage.xaml
new file mode 100644
index 0000000..fe00ef0
--- /dev/null
+++ b/QtVsTools.Wizards/ItemWizard/QtClass/QtClassPage.xaml
@@ -0,0 +1,298 @@
+<!--
+    *****************************************************************************
+    **
+    ** Copyright (C) 2022 The Qt Company Ltd.
+    ** Contact: https://www.qt.io/licensing/
+    **
+    ** This file is part of the Qt VS Tools.
+    **
+    ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+    ** Commercial License Usage
+    ** Licensees holding valid commercial Qt licenses may use this file in
+    ** accordance with the commercial license agreement provided with the
+    ** Software or, alternatively, in accordance with the terms contained in
+    ** a written agreement between you and The Qt Company. For licensing terms
+    ** and conditions see https://www.qt.io/terms-conditions. For further
+    ** information use the contact form at https://www.qt.io/contact-us.
+    **
+    ** GNU General Public License Usage
+    ** Alternatively, this file may be used under the terms of the GNU
+    ** General Public License version 3 as published by the Free Software
+    ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+    ** included in the packaging of this file. Please review the following
+    ** information to ensure the GNU General Public License requirements will
+    ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+    **
+    ** $QT_END_LICENSE$
+    **
+    *****************************************************************************
+-->
+
+<common:WizardPage x:Class="QtVsTools.Wizards.ItemWizard.QtClassPage"
+                  xmlns:common="clr-namespace:QtVsTools.Wizards.Common"
+                  xmlns:util="clr-namespace:QtVsTools.Wizards.Util"
+                  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+                  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+                  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+                  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+                  KeepAlive="True"
+                  mc:Ignorable="d"
+                  d:DesignHeight="445"
+                  d:DesignWidth="585">
+    <Grid>
+        <Grid.ColumnDefinitions>
+            <ColumnDefinition Width="100" />
+            <ColumnDefinition Width="*" />
+        </Grid.ColumnDefinitions>
+        <Image Grid.Column="0"
+               HorizontalAlignment="Center"
+               Source="/QtVsTools.Wizards;component/Resources/Qt-logo-small.png"
+               VerticalAlignment="Top"
+               Margin="0,25,0,0"
+               RenderTransformOrigin="1,0">
+            <Image.RenderTransform>
+                <TransformGroup>
+                    <ScaleTransform ScaleY="0.86"
+                                    ScaleX="0.86" />
+                </TransformGroup>
+            </Image.RenderTransform>
+        </Image>
+        <Grid Grid.Column="1"
+              Margin="25,25,10,0">
+            <Grid.RowDefinitions>
+                <RowDefinition Height="Auto" />
+                <RowDefinition Height="*" />
+                <RowDefinition Height="Auto" />
+            </Grid.RowDefinitions>
+            <TextBlock TextWrapping="Wrap"
+                       Grid.Row="0">
+                <Run FontWeight="Bold"
+                     Text="{Binding Path=Header}" />
+                <LineBreak />
+                <LineBreak />
+                <Run Text="{Binding Path=Message}" />
+                <LineBreak />
+            </TextBlock>
+            <Grid Grid.Row="1">
+                <Grid.RowDefinitions>
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                </Grid.RowDefinitions>
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="*" />
+                    <ColumnDefinition Width="*" />
+                </Grid.ColumnDefinitions>
+                <Grid.Resources>
+                    <Style TargetType="TextBox">
+                        <Style.Triggers>
+                            <Trigger Property="Validation.HasError"
+                                     Value="true">
+                                <Setter Property="ToolTip"
+                                        Value="{Binding RelativeSource={RelativeSource Self},
+                                         Path=(Validation.Errors)[0].ErrorContent}" />
+                            </Trigger>
+                        </Style.Triggers>
+                    </Style>
+                </Grid.Resources>
+                <TextBlock Grid.Row="0"
+                           Text="Class Name:"
+                           Margin="0,0,10,0" />
+                <TextBox Grid.Row="1"
+                         Margin="0,0,10,10"
+                         Name="ClassName"
+                         TextChanged="OnClassNameChanged"
+                         TabIndex="0">
+                    <TextBox.Text>
+                        <Binding Path="Data.ClassName"
+                                 NotifyOnValidationError="True"
+                                 UpdateSourceTrigger="PropertyChanged">
+                            <Binding.ValidationRules>
+                                <util:ClassNameValidationRule SupportNamespaces="True" />
+                            </Binding.ValidationRules>
+                        </Binding>
+                    </TextBox.Text>
+                </TextBox>
+                <TextBlock TextWrapping="Wrap"
+                           Text="Constructor signature:"
+                           Grid.Row="2"
+                           Margin="0,0,10,5" />
+                <ComboBox Grid.Row="3"
+                          VerticalAlignment="Top"
+                          TabIndex="2"
+                          IsSynchronizedWithCurrentItem="True"
+                          Margin="0,0,10,30"
+                          SelectedIndex="0"
+                          Text="{Binding Path=Data.ConstructorSignature}">
+                    <ComboBoxItem Content="QObject *parent"
+                                  IsSelected="True" />
+                    <ComboBoxItem Content="QWidget *parent" />
+                    <ComboBoxItem Content="" />
+                    <ComboBox.Style>
+                        <Style TargetType="ComboBox">
+                            <Style.Triggers>
+                                <DataTrigger Binding="{Binding ElementName=BaseClass, Path=Text}"
+                                             Value="">
+                                    <Setter Property="IsEnabled"
+                                            Value="false" />
+                                </DataTrigger>
+                            </Style.Triggers>
+                        </Style>
+                    </ComboBox.Style>
+                </ComboBox>
+                <TextBlock TextWrapping="Wrap"
+                           Text="Base class:"
+                           Margin="0,0,10,0"
+                           Grid.Column="1" />
+                <TextBox Margin="0,0,0,10"
+                         TabIndex="1"
+                         Grid.Column="1"
+                         Grid.Row="1"
+                         Name="BaseClass">
+                    <TextBox.Text>
+                        <Binding Path="Data.BaseClass"
+                                 NotifyOnValidationError="True"
+                                 UpdateSourceTrigger="PropertyChanged">
+                            <Binding.ValidationRules>
+                                <util:ClassNameValidationRule AllowEmptyIdentifier="True"/>
+                            </Binding.ValidationRules>
+                        </Binding>
+                    </TextBox.Text>
+                </TextBox>
+                <Grid Grid.Row="4"
+                      Grid.ColumnSpan="2">
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="Auto" />
+                        <RowDefinition Height="Auto" />
+                    </Grid.RowDefinitions>
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition Width="*" />
+                        <ColumnDefinition Width="*" />
+                    </Grid.ColumnDefinitions>
+                    <TextBlock Grid.Row="0"
+                               Margin="0,0,10,5"
+                               Text="Header (.h) file:" />
+                    <TextBox Grid.Row="1"
+                             Margin="0,0,10,0"
+                             Name="ClassHeaderFile"
+                             TabIndex="4">
+                        <TextBox.Text>
+                            <Binding Path="Data.ClassHeaderFile"
+                                     NotifyOnValidationError="True"
+                                     UpdateSourceTrigger="PropertyChanged">
+                                <Binding.ValidationRules>
+                                    <util:FileNameValidationRule FileExt=".h" />
+                                    <util:FileExistsinFilterValidationRule Filter="FL_HFiles" />
+                                </Binding.ValidationRules>
+                            </Binding>
+                        </TextBox.Text>
+                    </TextBox>
+                    <TextBlock Grid.Row="0"
+                               Grid.Column="1"
+                               Margin="0,0,0,5"
+                               Text="Source (.cpp) file:" />
+                    <TextBox Grid.Row="1"
+                             Grid.Column="1"
+                             Margin="0,0,0,00"
+                             Name="ClassSourceFile"
+                             TabIndex="5">
+                        <TextBox.Text>
+                            <Binding Path="Data.ClassSourceFile"
+                                     NotifyOnValidationError="True"
+                                     UpdateSourceTrigger="PropertyChanged">
+                                <Binding.ValidationRules>
+                                    <util:FileNameValidationRule FileExt=".cpp" />
+                                    <util:FileExistsinFilterValidationRule Filter="FL_CppFiles" />
+                                </Binding.ValidationRules>
+                            </Binding>
+                        </TextBox.Text>
+                    </TextBox>
+                </Grid>
+                <CheckBox Grid.Row="5"
+                          Content="Lower case file names"
+                          Name="LowerCaseFileNames"
+                          Click="OnLowerCaseFileNamesClick"
+                          Margin="0,20,10,5"
+                          TabIndex="6" />
+                <CheckBox Content="Insert Q_OBJECT macro"
+                          Grid.Column="1"
+                          Grid.Row="3"
+                          VerticalAlignment="Center"
+                          Margin="0,0,0,30"
+                          TabIndex="3"
+                          IsChecked="{Binding Path=Data.InsertQObjectMacro}">
+                    <CheckBox.Style>
+                        <Style TargetType="CheckBox">
+                            <Style.Triggers>
+                                <DataTrigger Binding="{Binding ElementName=BaseClass, Path=Text}"
+                                             Value="">
+                                    <Setter Property="IsEnabled"
+                                            Value="false" />
+                                </DataTrigger>
+                            </Style.Triggers>
+                        </Style>
+                    </CheckBox.Style>
+                </CheckBox>
+            </Grid>
+            <StackPanel HorizontalAlignment="Right"
+                        Orientation="Horizontal"
+                        Grid.Row="2"
+                        Margin="0,0,0,10">
+                <Button Click="OnPreviousButtonClick"
+                        Name="PreviousButton"
+                        IsEnabled="{Binding Path=PreviousButtonEnabled}"
+                        MinWidth="75">&lt; _Previous</Button>
+                <Button MinWidth="75"
+                        Name="NextButton"
+                        Click="OnNextButtonClick"
+                        IsEnabled="{Binding Path=NextButtonEnabled}"
+                        Margin="10,0,0,0">_Next &gt;</Button>
+                <Button MinWidth="75"
+                        Click="OnFinishButtonClick"
+                        Margin="10,0,0,0"
+                        IsDefault="True"
+                        Name="FinishButton"
+                        Content="_Finish"
+                        VerticalAlignment="Bottom">
+                    <Button.Style>
+                        <Style TargetType="Button">
+                            <Setter Property="IsEnabled"
+                                    Value="false" />
+                            <Style.Triggers>
+                                <MultiDataTrigger>
+                                    <MultiDataTrigger.Conditions>
+                                        <Condition Binding="{Binding Path=FinishButtonEnabled}"
+                                                   Value="true" />
+                                        <Condition Binding="{Binding ElementName=ClassName,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                        <Condition Binding="{Binding ElementName=BaseClass,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                        <Condition Binding="{Binding ElementName=ClassHeaderFile,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                        <Condition Binding="{Binding ElementName=ClassSourceFile,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                    </MultiDataTrigger.Conditions>
+                                    <Setter Property="IsEnabled"
+                                            Value="true" />
+                                </MultiDataTrigger>
+                            </Style.Triggers>
+                        </Style>
+                    </Button.Style>
+                </Button>
+                <Button Click="OnCancelButtonClick"
+                        MinWidth="75"
+                        Margin="10,0,0,0"
+                        Name="CancelButton"
+                        IsEnabled="{Binding Path=CancelButtonEnabled}"
+                        IsCancel="True">_Cancel</Button>
+            </StackPanel>
+        </Grid>
+    </Grid>
+</common:WizardPage>
diff --git a/QtVsTools.Wizards/ItemWizard/QtClass/QtClassPage.xaml.cs b/QtVsTools.Wizards/ItemWizard/QtClass/QtClassPage.xaml.cs
new file mode 100644
index 0000000..fcc4960
--- /dev/null
+++ b/QtVsTools.Wizards/ItemWizard/QtClass/QtClassPage.xaml.cs
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Windows;
+using System.Windows.Controls;
+
+namespace QtVsTools.Wizards.ItemWizard
+{
+    using Wizards.Common;
+
+    public partial class QtClassPage : WizardPage
+    {
+        public QtClassPage()
+        {
+            InitializeComponent();
+            DataContext = this;
+        }
+
+        private void OnClassNameChanged(object sender, TextChangedEventArgs e)
+        {
+            UpdateFileNames();
+        }
+
+        private void OnLowerCaseFileNamesClick(object sender, RoutedEventArgs e)
+        {
+            UpdateFileNames();
+        }
+
+        private void UpdateFileNames()
+        {
+            var filename = ClassName.Text;
+            if (LowerCaseFileNames.IsChecked.GetValueOrDefault())
+                filename = filename.ToLower();
+
+            var index = filename.LastIndexOf(@":", System.StringComparison.Ordinal);
+            if (index >= 0)
+                filename = filename.Substring(index + 1);
+
+            ClassHeaderFile.Text = filename + @".h";
+            ClassSourceFile.Text = filename + @".cpp";
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/ItemWizard/QtClass/QtClassWizard.cs b/QtVsTools.Wizards/ItemWizard/QtClass/QtClassWizard.cs
new file mode 100644
index 0000000..970c585
--- /dev/null
+++ b/QtVsTools.Wizards/ItemWizard/QtClass/QtClassWizard.cs
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Windows.Controls;
+using Microsoft.VisualStudio.Shell;
+using EnvDTE;
+
+namespace QtVsTools.Wizards.ItemWizard
+{
+    using QtVsTools.Common;
+    using Core;
+    using Wizards.Common;
+    using Wizards.ProjectWizard;
+    using Wizards.Util;
+
+    using static QtVsTools.Common.EnumExt;
+
+    public sealed class QtClassWizard : ProjectTemplateWizard
+    {
+        LazyFactory Lazy { get; } = new LazyFactory();
+
+        protected override Options TemplateType => Options.ConsoleSystem;
+
+        enum NewClass
+        {
+            [String("safeitemname")] SafeItemName,
+            [String("sourcefilename")] SourceFileName,
+            [String("headerfilename")] HeaderFileName
+        }
+
+        enum NewQtItem
+        {
+            [String("classname")] ClassName,
+            [String("baseclass")] BaseClass,
+            [String("include")] Include,
+            [String("qobject")] QObject,
+            [String("baseclassdecl")] BaseClassDecl,
+            [String("signature")] Signature,
+            [String("baseclassinclude")] BaseClassInclude,
+            [String("baseclasswithparent")] BaseClassWithParent
+        }
+
+        enum Meta
+        {
+            [String("namespacebegin")] NamespaceBegin,
+            [String("namespaceend")] NamespaceEnd
+        }
+
+        protected override WizardData WizardData => Lazy.Get(() =>
+            WizardData, () => new WizardData
+            {
+                InsertQObjectMacro = true,
+                LowerCaseFileNames = false,
+                UsePrecompiledHeader = false,
+                DefaultModules = new List<string> { "core" }
+            });
+
+        protected override WizardWindow WizardWindow => Lazy.Get(() =>
+            WizardWindow, () => new WizardWindow(title: "Qt Class Wizard")
+            {
+                new WizardIntroPage
+                {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt Class Wizard",
+                    Message = @"This wizard will add a new Qt class to your project. The "
+                        + @"wizard creates a .h and .cpp file." + System.Environment.NewLine
+                        + System.Environment.NewLine + "To continue, click Next.",
+                    PreviousButtonEnabled = false,
+                    NextButtonEnabled = true,
+                    FinishButtonEnabled = false,
+                    CancelButtonEnabled = true
+                },
+                new QtClassPage {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt Class Wizard",
+                    Message = @"This wizard will add a new Qt class to your project. The "
+                        + @"wizard creates a .h and .cpp file.",
+                    PreviousButtonEnabled = true,
+                    NextButtonEnabled = false,
+                    FinishButtonEnabled = true,
+                    CancelButtonEnabled = true
+                }
+            });
+
+        protected override void BeforeWizardRun()
+        {
+            var className = Parameter[NewClass.SafeItemName];
+            className = Regex.Replace(className, @"[^a-zA-Z0-9_]", string.Empty);
+            className = Regex.Replace(className, @"^[\d-]*\s*", string.Empty);
+            var result = new Util.ClassNameValidationRule().Validate(className, null);
+            if (result != ValidationResult.ValidResult)
+                className = @"QtClass";
+
+            WizardData.ClassName = className;
+            WizardData.BaseClass = @"QObject";
+            WizardData.ClassHeaderFile = className + @".h";
+            WizardData.ClassSourceFile = className + @".cpp";
+            WizardData.ConstructorSignature = "QObject *parent";
+
+            Parameter[NewQtItem.QObject] = "";
+            Parameter[NewQtItem.BaseClassDecl] = "";
+            Parameter[NewQtItem.Signature] = "";
+            Parameter[NewQtItem.BaseClassInclude] = "";
+            Parameter[NewQtItem.BaseClassWithParent] = "";
+        }
+
+        protected override void BeforeTemplateExpansion()
+        {
+            Parameter[NewClass.SourceFileName] = WizardData.ClassSourceFile;
+            Parameter[NewClass.HeaderFileName] = WizardData.ClassHeaderFile;
+
+            var array = WizardData.ClassName.Split(new[] { "::" },
+                StringSplitOptions.RemoveEmptyEntries);
+            var className = array.LastOrDefault();
+            var baseClass = WizardData.BaseClass;
+
+            Parameter[NewQtItem.ClassName] = className;
+            Parameter[NewQtItem.BaseClass] = baseClass;
+
+            var include = new StringBuilder();
+            var pro = HelperFunctions.GetSelectedQtProject(Dte);
+            if (pro != null) {
+                var qtProject = QtProject.Create(pro);
+                if (qtProject != null && qtProject.UsesPrecompiledHeaders()) {
+                    include.AppendLine(string.Format("#include \"{0}\"", qtProject
+                        .GetPrecompiledHeaderThrough()));
+                }
+            }
+            include.AppendLine(string.Format("#include \"{0}\"", WizardData.ClassHeaderFile));
+            Parameter[NewQtItem.Include] = FormatParam(include);
+
+            if (!string.IsNullOrEmpty(baseClass)) {
+                Parameter[NewQtItem.QObject] = WizardData.InsertQObjectMacro
+                                                    ? "\r\n    Q_OBJECT\r\n" : "";
+                Parameter[NewQtItem.BaseClassDecl] = " : public " + baseClass;
+                Parameter[NewQtItem.Signature] = WizardData.ConstructorSignature;
+                Parameter[NewQtItem.BaseClassInclude] = "#include <" + baseClass + ">\r\n\r\n";
+                Parameter[NewQtItem.BaseClassWithParent] = string.IsNullOrEmpty(WizardData
+                    .ConstructorSignature) ? "" : "\r\n    : " + baseClass + "(parent)";
+            }
+
+            string nsBegin = string.Empty, nsEnd = string.Empty;
+            for (var i = 0; i < array.Length - 1; ++i) {
+                nsBegin += "namespace " + array[i] + " {\r\n";
+                nsEnd = "} // namespace " + array[i] + "\r\n" + nsEnd;
+            }
+            Parameter[Meta.NamespaceBegin] = nsBegin;
+            Parameter[Meta.NamespaceEnd] = nsEnd;
+        }
+
+        protected override void Expand()
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+            VCRulePropertyStorageHelper.SetQtModules(Dte, WizardData.DefaultModules);
+        }
+
+        public override void ProjectItemFinishedGenerating(ProjectItem projectItem)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+            QtProject.AdjustWhitespace(Dte, projectItem.Properties.Item("FullPath").Value.ToString());
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/ItemWizard/Translation/TranslationPage.xaml b/QtVsTools.Wizards/ItemWizard/Translation/TranslationPage.xaml
new file mode 100644
index 0000000..2f707b2
--- /dev/null
+++ b/QtVsTools.Wizards/ItemWizard/Translation/TranslationPage.xaml
@@ -0,0 +1,149 @@
+<!--
+    *****************************************************************************
+    **
+    ** Copyright (C) 2022 The Qt Company Ltd.
+    ** Contact: https://www.qt.io/licensing/
+    **
+    ** This file is part of the Qt VS Tools.
+    **
+    ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+    ** Commercial License Usage
+    ** Licensees holding valid commercial Qt licenses may use this file in
+    ** accordance with the commercial license agreement provided with the
+    ** Software or, alternatively, in accordance with the terms contained in
+    ** a written agreement between you and The Qt Company. For licensing terms
+    ** and conditions see https://www.qt.io/terms-conditions. For further
+    ** information use the contact form at https://www.qt.io/contact-us.
+    **
+    ** GNU General Public License Usage
+    ** Alternatively, this file may be used under the terms of the GNU
+    ** General Public License version 3 as published by the Free Software
+    ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+    ** included in the packaging of this file. Please review the following
+    ** information to ensure the GNU General Public License requirements will
+    ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+    **
+    ** $QT_END_LICENSE$
+    **
+    *****************************************************************************
+-->
+
+<common:WizardPage x:Class="QtVsTools.Wizards.ItemWizard.TranslationPage"
+    xmlns:common="clr-namespace:QtVsTools.Wizards.Common"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    KeepAlive="True"
+    mc:Ignorable="d"
+    d:DesignHeight="445"
+    d:DesignWidth="585" >
+    <Grid>
+        <Grid.ColumnDefinitions>
+            <ColumnDefinition Width="100" />
+            <ColumnDefinition Width="*" />
+        </Grid.ColumnDefinitions>
+
+        <Image Grid.Column="0"
+               HorizontalAlignment="Center"
+               Source="/QtVsTools.Wizards;component/Resources/Qt-logo-small.png"
+               VerticalAlignment="Top"
+               Margin="0,25,0,0"
+               RenderTransformOrigin="1,0">
+            <Image.RenderTransform>
+                <TransformGroup>
+                    <ScaleTransform ScaleY="0.86"
+                                    ScaleX="0.86" />
+                </TransformGroup>
+            </Image.RenderTransform>
+        </Image>
+
+        <Grid Grid.Column="1"
+              Margin="25,25,25,0">
+            <Grid.RowDefinitions>
+                <RowDefinition Height="Auto" />
+                <RowDefinition Height="*" />
+                <RowDefinition Height="Auto" />
+            </Grid.RowDefinitions>
+            <TextBlock TextWrapping="Wrap"
+                       Grid.Row="0">
+                <Run FontWeight="Bold"
+                     Text="{Binding Path=Header}" />
+                <LineBreak />
+                <LineBreak />
+                <Run Text="{Binding Path=Message}" />
+                <LineBreak />
+            </TextBlock>
+
+            <Grid Grid.Row="1"
+                  Margin="0,20,0,20">
+                <Grid.RowDefinitions>
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="*" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                </Grid.RowDefinitions>
+                <TextBlock Grid.Row="0"
+                           Margin="0,0,0,5"
+                           Text="Select a Language:" />
+                <Grid Grid.Row="1">
+                    <Grid Name="searchControlHost" />
+                </Grid>
+                <ListBox Grid.Row="2"
+                         Margin="0,10,0,8"
+                         Name="LanguageListBox"
+                         DisplayMemberPath="Value"
+                         SelectedValuePath="Key"
+                         ItemsSource="{Binding Path=Data.CultureInfos}"
+                         SelectedValue="{Binding Path=Data.CultureInfoName}"
+                         SelectionChanged="OnLanguageBoxSelectionChanged" />
+                <TextBlock Grid.Row="3"
+                           Margin="0,0,0,5"
+                           Text="Save as:"/>
+                <Grid Grid.Row="4">
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition Width="*" />
+                        <ColumnDefinition Width="Auto" />
+                    </Grid.ColumnDefinitions>
+                    <TextBox Text="{Binding Path=Data.TsFile}"/>
+                    <TextBlock Grid.Column="1"
+                               Margin="5,0,0,0"
+                               VerticalAlignment="Center">
+                        <Run FontWeight="Bold"
+                             Text="{Binding Path=Data.CultureInfoName}" />
+                        <Run Text=".ts" />
+                    </TextBlock>
+                </Grid>
+            </Grid>
+
+            <StackPanel Grid.Row="2"
+                        HorizontalAlignment="Right"
+                        Orientation="Horizontal"
+                        Margin="0,0,0,10">
+                <Button Click="OnPreviousButtonClick"
+                        Name="PreviousButton"
+                        IsEnabled="{Binding Path=PreviousButtonEnabled}"
+                        MinWidth="75">&lt; _Previous</Button>
+                <Button MinWidth="75"
+                        Name="NextButton"
+                        Click="OnNextButtonClick"
+                        IsEnabled="{Binding Path=NextButtonEnabled}"
+                        Margin="10,0,0,0">_Next &gt;</Button>
+                <Button MinWidth="75"
+                        Click="OnFinishButtonClick"
+                        Margin="10,0,0,0"
+                        IsDefault="True"
+                        IsEnabled="{Binding Path=FinishButtonEnabled}"
+                        Name="FinishButton"
+                        VerticalAlignment="Bottom">_Finish</Button>
+                <Button Click="OnCancelButtonClick"
+                        MinWidth="75"
+                        Margin="10,0,0,0"
+                        Name="CancelButton"
+                        IsEnabled="{Binding Path=CancelButtonEnabled}"
+                        IsCancel="True">_Cancel</Button>
+            </StackPanel>
+        </Grid>
+    </Grid>
+</common:WizardPage>
diff --git a/QtVsTools.Wizards/ItemWizard/Translation/TranslationPage.xaml.cs b/QtVsTools.Wizards/ItemWizard/Translation/TranslationPage.xaml.cs
new file mode 100644
index 0000000..adcc38b
--- /dev/null
+++ b/QtVsTools.Wizards/ItemWizard/Translation/TranslationPage.xaml.cs
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+
+namespace QtVsTools.Wizards.ItemWizard
+{
+    using QtVsTools.VisualStudio;
+    using Wizards.Common;
+
+    public partial class TranslationPage : WizardPage
+    {
+        private string SearchText { get; set; }
+
+        public TranslationPage()
+        {
+            InitializeComponent();
+            DataContext = this;
+            Loaded += OnTranslationPageLoaded;
+        }
+
+        private void OnTranslationPageLoaded(object sender, RoutedEventArgs e)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            var view = CollectionViewSource.GetDefaultView(LanguageListBox.ItemsSource);
+            view.Filter = obj =>
+            {
+                if (string.IsNullOrEmpty(SearchText))
+                    return true;
+
+                var item = (KeyValuePair<string, string>)obj;
+                return item.Value.IndexOf(SearchText, StringComparison.OrdinalIgnoreCase) >= 0;
+            };
+            LanguageListBox.SelectedIndex = 0;
+
+            var factory = VsServiceProvider
+                .GetService<SVsWindowSearchHostFactory, IVsWindowSearchHostFactory>();
+            var host = factory.CreateWindowSearchHost(searchControlHost);
+
+            host.SetupSearch(new ListBoxSearch(LanguageListBox, value => SearchText = value));
+            host.Activate(); // set focus
+        }
+
+        private void OnSearchBoxTextChanged(object sender, TextChangedEventArgs e)
+        {
+            CollectionViewSource.GetDefaultView(LanguageListBox.ItemsSource).Refresh();
+            if (LanguageListBox.Items.Count == 1 || LanguageListBox.SelectedItem == null)
+                LanguageListBox.SelectedIndex = 0;
+        }
+
+        private void OnLanguageBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
+        {
+            if (e.RemovedItems != null && (e.AddedItems == null || e.AddedItems.Count == 0)) {
+                if (LanguageListBox.Items.Count != 0)
+                    LanguageListBox.SelectedIndex = 0;
+            }
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/ItemWizard/Translation/TranslationWizard.cs b/QtVsTools.Wizards/ItemWizard/Translation/TranslationWizard.cs
new file mode 100644
index 0000000..0c6c8c5
--- /dev/null
+++ b/QtVsTools.Wizards/ItemWizard/Translation/TranslationWizard.cs
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using Microsoft.VisualStudio.Shell;
+using EnvDTE;
+
+namespace QtVsTools.Wizards.ItemWizard
+{
+    using QtVsTools.Common;
+    using Core;
+    using Wizards.Common;
+    using Wizards.ProjectWizard;
+    using Wizards.Util;
+
+    using static QtVsTools.Common.EnumExt;
+
+    public sealed class TsWizardData : WizardData
+    {
+        public string TsFile { get; set; }
+        public string CultureInfoName { get; set; }
+        public List<KeyValuePair<string, string>> CultureInfos { get; set; }
+    }
+
+    public sealed class TranslationWizard : ProjectTemplateWizard
+    {
+        LazyFactory Lazy { get; } = new LazyFactory();
+
+        protected override Options TemplateType => Options.ConsoleSystem | Options.GUISystem;
+
+        enum NewTranslationItem
+        {
+            [String("safeitemname")] SafeItemName,
+            [String("tsfilename")] TsFileName,
+            [String("cultureinfoname")] CultureInfoName
+        }
+
+        protected override WizardData WizardData => Lazy.Get(() =>
+            WizardData, () => new TsWizardData
+            {
+                DefaultModules = new List<string> { "core"}
+            });
+
+        protected override WizardWindow WizardWindow => Lazy.Get(() =>
+            WizardWindow, () => new WizardWindow(title: "Qt Translation File Wizard")
+            {
+                new TranslationPage
+                {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt Translation File Wizard",
+                    Message = @"This wizard will add a new Qt empty translation file to your "
+                        + @"project. The wizard creates a .ts for the selected language.",
+                    PreviousButtonEnabled = false,
+                    NextButtonEnabled = false,
+                    FinishButtonEnabled = true,
+                    CancelButtonEnabled = true
+                },
+            });
+
+        protected override void BeforeWizardRun()
+        {
+            var tmp = WizardData as TsWizardData;
+            tmp.TsFile = Parameter[NewTranslationItem.SafeItemName];
+            tmp.CultureInfos = CultureInfo.GetCultures(CultureTypes.AllCultures)
+                .ToDictionary(
+                    mc => mc.Name.Replace("-", "_"),
+                    mc => mc.EnglishName,
+                    StringComparer.OrdinalIgnoreCase
+                ).OrderBy(item => item.Value).ToList();
+        }
+
+        protected override void BeforeTemplateExpansion()
+        {
+            var tmp = WizardData as TsWizardData;
+            Parameter[NewTranslationItem.CultureInfoName] = tmp.CultureInfoName;
+            Parameter[NewTranslationItem.TsFileName] = tmp.TsFile + "_" + tmp.CultureInfoName + ".ts";
+        }
+
+        protected override void Expand()
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+            VCRulePropertyStorageHelper.SetQtModules(Dte, WizardData.DefaultModules);
+        }
+
+        public override void ProjectItemFinishedGenerating(ProjectItem projectItem)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+            QtProject.AdjustWhitespace(Dte, projectItem.Properties.Item("FullPath").Value.ToString());
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/ItemWizard/WidgetsClass/WidgetsClassWizard.cs b/QtVsTools.Wizards/ItemWizard/WidgetsClass/WidgetsClassWizard.cs
new file mode 100644
index 0000000..8fc0d97
--- /dev/null
+++ b/QtVsTools.Wizards/ItemWizard/WidgetsClass/WidgetsClassWizard.cs
@@ -0,0 +1,245 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Windows.Controls;
+using Microsoft.VisualStudio.Shell;
+using EnvDTE;
+
+namespace QtVsTools.Wizards.ItemWizard
+{
+    using QtVsTools.Common;
+    using Core;
+    using Wizards.Common;
+    using Wizards.ProjectWizard;
+    using Wizards.Util;
+
+    using static QtVsTools.Common.EnumExt;
+
+    public sealed class WidgetsClassWizard : ProjectTemplateWizard
+    {
+        LazyFactory Lazy { get; } = new LazyFactory();
+
+        protected override Options TemplateType => Options.GUISystem;
+
+        enum NewClass
+        {
+            [String("safeitemname")] SafeItemName,
+            [String("sourcefilename")] SourceFileName,
+            [String("headerfilename")] HeaderFileName,
+            [String("uifilename")] UiFileName
+        }
+
+        enum NewWidgetsItem
+        {
+            [String("classname")] ClassName,
+            [String("baseclass")] BaseClass,
+            [String("include")] Include,
+            [String("qobject")] QObject,
+            [String("ui_hdr")] UiHeaderName,
+            [String("centralwidget")] CentralWidget,
+            [String("forward_declare_class")] ForwardDeclClass,
+            [String("multiple_inheritance")] MultipleInheritance,
+            [String("ui_classname")] UiClassName,
+            [String("member")] Member
+        }
+
+        enum Meta
+        {
+            [String("namespacebegin")] NamespaceBegin,
+            [String("operator")] Operator,
+            [String("asterisk")] Asterisk,
+            [String("semicolon")] Semicolon,
+            [String("new")] New,
+            [String("delete")] Delete,
+            [String("namespaceend")] NamespaceEnd
+        }
+
+        protected override WizardData WizardData => Lazy.Get(() =>
+            WizardData, () => new WizardData
+            {
+                InsertQObjectMacro = true,
+                LowerCaseFileNames = false,
+                UsePrecompiledHeader = false,
+                DefaultModules = new List<string> { "core", "gui", "widgets" }
+            });
+
+        protected override WizardWindow WizardWindow => Lazy.Get(() =>
+            WizardWindow, () => new WizardWindow(title: "Qt Widgets Class Wizard")
+            {
+                new WizardIntroPage
+                {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt Widgets Class Wizard",
+                    Message = @"This wizard will add a new Qt Widgets class to your project. "
+                        + @"The wizard creates a .h and .cpp file. It also creates a new "
+                        + @"empty form." + System.Environment.NewLine
+                        + System.Environment.NewLine + "To continue, click Next.",
+                    PreviousButtonEnabled = false,
+                    NextButtonEnabled = true,
+                    FinishButtonEnabled = false,
+                    CancelButtonEnabled = true
+                },
+                new GuiPage
+                {
+                    Data = WizardData,
+                    IsClassWizardPage = true,
+                    Header = @"Welcome to the Qt Widgets Class Wizard",
+                    Message = @"This wizard will add a new Qt Widgets class to your project. "
+                        + @"The wizard creates a .h and .cpp file. It also creates a new "
+                        + @"empty form.",
+                    PreviousButtonEnabled = true,
+                    NextButtonEnabled = false,
+                    FinishButtonEnabled = true,
+                    CancelButtonEnabled = true
+                }
+            });
+
+        protected override void BeforeWizardRun()
+        {
+            var className = Parameter[NewClass.SafeItemName];
+            className = Regex.Replace(className, @"[^a-zA-Z0-9_]", string.Empty);
+            className = Regex.Replace(className, @"^[\d-]*\s*", string.Empty);
+            var result = new Util.ClassNameValidationRule().Validate(className, null);
+            if (result != ValidationResult.ValidResult)
+                className = @"QtWidgetsClass";
+
+            WizardData.ClassName = className;
+            WizardData.BaseClass = @"QMainWindow";
+            WizardData.ClassHeaderFile = className + @".h";
+            WizardData.ClassSourceFile = className + @".cpp";
+            WizardData.UiFile = WizardData.ClassName + @".ui";
+            WizardData.QrcFile = WizardData.ClassName + @".qrc";
+            WizardData.UiClassInclusion = UiClassInclusion.Member;
+
+            Parameter[NewWidgetsItem.ForwardDeclClass] = "";
+            Parameter[NewWidgetsItem.MultipleInheritance] = "";
+            Parameter[NewWidgetsItem.UiClassName] = "";
+            Parameter[NewWidgetsItem.Member] = "ui";
+
+            Parameter[Meta.Asterisk] ="";
+            Parameter[Meta.Operator] = ".";
+            Parameter[Meta.Semicolon] = ";";
+            Parameter[Meta.New] = "";
+            Parameter[Meta.Delete] = "";
+        }
+
+        protected override void BeforeTemplateExpansion()
+        {
+            Parameter[NewClass.SourceFileName] = WizardData.ClassSourceFile;
+            Parameter[NewClass.HeaderFileName] = WizardData.ClassHeaderFile;
+            Parameter[NewClass.UiFileName] = WizardData.UiFile;
+
+            var array = WizardData.ClassName.Split(new[] { "::" },
+                StringSplitOptions.RemoveEmptyEntries);
+            var className = array.LastOrDefault();
+
+            Parameter[NewWidgetsItem.ClassName] = className;
+            Parameter[NewWidgetsItem.BaseClass] = WizardData.BaseClass;
+
+            var include = new StringBuilder();
+            var pro = HelperFunctions.GetSelectedQtProject(Dte);
+            if (pro != null) {
+                var qtProject = QtProject.Create(pro);
+                if (qtProject != null && qtProject.UsesPrecompiledHeaders()) {
+                    include.AppendLine(string.Format("#include \"{0}\"", qtProject
+                        .GetPrecompiledHeaderThrough()));
+                }
+            }
+            include.AppendLine(string.Format("#include \"{0}\"", WizardData.ClassHeaderFile));
+            Parameter[NewWidgetsItem.Include] = FormatParam(include);
+
+            Parameter[NewWidgetsItem.QObject] = WizardData.InsertQObjectMacro
+                                                    ? "\r\n    Q_OBJECT\r\n" : "";
+
+            Parameter[NewWidgetsItem.UiHeaderName] = string.Format("ui_{0}.h",
+                Path.GetFileNameWithoutExtension(WizardData.UiFile));
+
+            if (WizardData.BaseClass == "QMainWindow") {
+                Parameter[NewWidgetsItem.CentralWidget] = FormatParam(
+                      @"  <widget class=""QMenuBar"" name=""menuBar"" />"
+                    + @"  <widget class=""QToolBar"" name=""mainToolBar"" />"
+                    + @"  <widget class=""QWidget"" name=""centralWidget"" />"
+                    + @"  <widget class=""QStatusBar"" name=""statusBar"" />"
+                );
+            }
+
+            switch (WizardData.UiClassInclusion) {
+            case UiClassInclusion.MemberPointer:
+                Parameter[NewWidgetsItem.ForwardDeclClass] =
+                    string.Format(
+                          "\r\nQT_BEGIN_NAMESPACE\r\n"
+                        + "namespace Ui {{ class {0}Class; }};\r\n"
+                        + "QT_END_NAMESPACE\r\n", className
+                    );
+                Parameter[Meta.Asterisk] = "*";
+                Parameter[Meta.Operator] = "->";
+                Parameter[Meta.New] = string.Format("\r\n    , {0}(new Ui::{1}Class())",
+                                                    Parameter[NewWidgetsItem.Member], className);
+                Parameter[Meta.Delete] = string.Format("\r\n    delete {0};\r\n",
+                                                       Parameter[NewWidgetsItem.Member]);
+                goto case UiClassInclusion.Member;
+            case UiClassInclusion.Member:
+                Parameter[NewWidgetsItem.UiClassName] = string.Format("Ui::{0}Class", className);
+                break;
+            case UiClassInclusion.MultipleInheritance:
+                Parameter[NewWidgetsItem.MultipleInheritance] =
+                    string.Format(", public Ui::{0}Class", className);
+                Parameter[NewWidgetsItem.Member] = "";
+                Parameter[Meta.Operator] = "";
+                Parameter[Meta.Semicolon] = "";
+                break;
+            }
+
+            string nsBegin = string.Empty, nsEnd = string.Empty;
+            for (var i = 0; i < array.Length - 1; ++i) {
+                nsBegin += "namespace " + array[i] + " {\r\n";
+                nsEnd = "} // namespace " + array[i] + "\r\n" + nsEnd;
+            }
+            Parameter[Meta.NamespaceBegin] = nsBegin;
+            Parameter[Meta.NamespaceEnd] = nsEnd;
+        }
+
+        protected override void Expand()
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+            VCRulePropertyStorageHelper.SetQtModules(Dte, WizardData.DefaultModules);
+        }
+
+        public override void ProjectItemFinishedGenerating(ProjectItem projectItem)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+            QtProject.AdjustWhitespace(Dte, projectItem.Properties.Item("FullPath").Value.ToString());
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/ProjectWizard/ConfigPage.xaml b/QtVsTools.Wizards/ProjectWizard/ConfigPage.xaml
new file mode 100644
index 0000000..034113e
--- /dev/null
+++ b/QtVsTools.Wizards/ProjectWizard/ConfigPage.xaml
@@ -0,0 +1,298 @@
+<!--
+*****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+*****************************************************************************
+-->
+<common:WizardPage x:Class="QtVsTools.Wizards.ProjectWizard.ConfigPage"
+    xmlns:common="clr-namespace:QtVsTools.Wizards.Common"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" KeepAlive="True"
+    mc:Ignorable="d" d:DesignHeight="445" d:DesignWidth="585">
+  <Grid>
+    <Grid.ColumnDefinitions>
+      <ColumnDefinition Width="100" />
+      <ColumnDefinition Width="*" />
+    </Grid.ColumnDefinitions>
+    <Image Grid.Column="0" HorizontalAlignment="Center"
+        Source="/QtVsTools.Wizards;component/Resources/Qt-logo-small.png" VerticalAlignment="Top"
+        Margin="0,25,0,0" RenderTransformOrigin="1,0">
+      <Image.RenderTransform>
+        <TransformGroup>
+          <ScaleTransform ScaleY="0.86" ScaleX="0.86" />
+        </TransformGroup>
+      </Image.RenderTransform>
+    </Image>
+    <Grid Grid.Column="1" Margin="25,25,10,0">
+      <Grid.RowDefinitions>
+        <RowDefinition Height="Auto" />
+        <RowDefinition Height="*" />
+        <RowDefinition Height="Auto" />
+      </Grid.RowDefinitions>
+      <TextBlock TextWrapping="Wrap" Grid.Row="0">
+        <Run FontWeight="Bold" Text="{Binding Path=Header}" />
+        <LineBreak />
+        <LineBreak />
+        <Run Text="{Binding Path=Message}" />
+        <LineBreak />
+      </TextBlock>
+      <Grid Grid.Row="1" Name="ModuleGrid">
+        <Grid.ColumnDefinitions>
+          <ColumnDefinition Width="*" />
+        </Grid.ColumnDefinitions>
+        <Grid.Resources>
+          <Style TargetType="ListBox">
+            <Setter Property="Background" Value="Transparent" />
+          </Style>
+        </Grid.Resources>
+        <Grid>
+          <Grid.RowDefinitions>
+            <RowDefinition Height="*" />
+            <RowDefinition Height="Auto" />
+          </Grid.RowDefinitions>
+          <DataGrid Margin="0,20,0,0" Name="ConfigTable" AutoGenerateColumns="False"
+              IsReadOnly="True" BorderThickness="1" BorderBrush="LightGray"
+              GridLinesVisibility="All" HorizontalGridLinesBrush="LightGray"
+              VerticalGridLinesBrush="LightGray" CanUserReorderColumns="False"
+              CanUserSortColumns="False" CanUserResizeRows="False" RowHeaderWidth="0"
+              FrozenColumnCount="1" Grid.Row="0">
+            <DataGrid.Resources>
+              <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
+              <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
+            </DataGrid.Resources>
+            <DataGrid.CellStyle>
+              <Style TargetType="DataGridCell">
+                <Setter Property="BorderThickness" Value="0" />
+                <Setter Property="FocusVisualStyle" Value="{x:Null}" />
+              </Style>
+            </DataGrid.CellStyle>
+            <DataGrid.Columns>
+              <DataGridTemplateColumn Header="Configuration">
+                <DataGridTemplateColumn.CellTemplate>
+                  <DataTemplate>
+                    <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+                      <Button Cursor="Hand" ButtonBase.Click="RemoveConfig_Click">
+                        <Button.Template>
+                          <ControlTemplate TargetType="Button">
+                            <Grid HorizontalAlignment="Center" VerticalAlignment="Center"
+                                Margin="2,0">
+                              <Ellipse Fill="Red" Width="13" Height="13" />
+                              <Rectangle Width="8" Height="2" Fill="White" />
+                            </Grid>
+                          </ControlTemplate>
+                        </Button.Template>
+                      </Button>
+                      <Button Cursor="Hand" ButtonBase.Click="DuplicateConfig_Click">
+                        <Button.Template>
+                          <ControlTemplate TargetType="Button">
+                            <Grid HorizontalAlignment="Center" VerticalAlignment="Center"
+                                Margin="2,0">
+                              <Ellipse Fill="#FF36B31A" Width="13" Height="13" />
+                              <Rectangle Width="8" Height="2" Fill="White" />
+                              <Rectangle Width="2" Height="8" Fill="White" />
+                            </Grid>
+                          </ControlTemplate>
+                        </Button.Template>
+                      </Button>
+                      <TextBox Text="{Binding Name}" Margin="2,8" BorderThickness="0"
+                          Background="Transparent" TextBoxBase.TextChanged="Name_TextChanged">
+                        <TextBox.Resources>
+                          <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
+                                           Color="LimeGreen" />
+                        </TextBox.Resources>
+                      </TextBox>
+                    </StackPanel>
+                  </DataTemplate>
+                </DataGridTemplateColumn.CellTemplate>
+              </DataGridTemplateColumn>
+              <DataGridTemplateColumn Header="Qt Version">
+                <DataGridTemplateColumn.CellTemplate>
+                  <DataTemplate>
+                    <ComboBox Text="{Binding QtVersionName}" IsEditable="True" Height="22"
+                        SelectedIndex="0" BorderThickness="0" Background="Transparent"
+                        FrameworkElement.Loaded="QtVersion_ComboBox_Loaded"
+                        TextBoxBase.TextChanged="QtVersion_TextChanged">
+                      <ComboBox.Resources>
+                        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
+                                         Color="LimeGreen" />
+                      </ComboBox.Resources>
+                    </ComboBox>
+                  </DataTemplate>
+                </DataGridTemplateColumn.CellTemplate>
+              </DataGridTemplateColumn>
+              <DataGridTemplateColumn Header="Target">
+                <DataGridTemplateColumn.CellTemplate>
+                  <DataTemplate>
+                    <ComboBox Text="{Binding Target}" IsEditable="True" Height="22"
+                        SelectedIndex="0" BorderThickness="0" Background="Transparent"
+                        FrameworkElement.Loaded="Target_ComboBox_Loaded"
+                        TextBoxBase.TextChanged="Target_TextChanged">
+                      <ComboBox.Resources>
+                        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
+                                         Color="LimeGreen" />
+                      </ComboBox.Resources>
+                    </ComboBox>
+                  </DataTemplate>
+                </DataGridTemplateColumn.CellTemplate>
+              </DataGridTemplateColumn>
+              <DataGridTemplateColumn Header="Platform">
+                <DataGridTemplateColumn.CellTemplate>
+                  <DataTemplate>
+                    <ComboBox Text="{Binding Platform}" IsEditable="True" Height="22"
+                        SelectedIndex="0" BorderThickness="0" Background="Transparent"
+                        FrameworkElement.Loaded="Platform_ComboBox_Loaded"
+                        TextBoxBase.TextChanged="Platform_TextChanged">
+                      <ComboBox.Resources>
+                        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
+                                         Color="LimeGreen" />
+                      </ComboBox.Resources>
+                    </ComboBox>
+                  </DataTemplate>
+                </DataGridTemplateColumn.CellTemplate>
+              </DataGridTemplateColumn>
+              <DataGridTemplateColumn Header="Debug">
+                <DataGridTemplateColumn.CellTemplate>
+                  <DataTemplate>
+                    <CheckBox VerticalAlignment="Center" HorizontalAlignment="Center"
+                        IsChecked="{Binding IsDebug}" Click="Debug_Click" />
+                  </DataTemplate>
+                </DataGridTemplateColumn.CellTemplate>
+              </DataGridTemplateColumn>
+              <DataGridTemplateColumn Header="Qt Modules" Width="*">
+                <DataGridTemplateColumn.CellTemplate>
+                  <DataTemplate>
+                    <ComboBox Name="Modules">
+                      <ComboBox.Template>
+                        <ControlTemplate TargetType="ComboBox">
+                          <Grid>
+                            <ListView Name="SelectedModules" ItemsSource="{Binding SelectedModules}"
+                                ScrollViewer.HorizontalScrollBarVisibility="Disabled"
+                                BorderThickness="0" IsEnabled="False">
+                              <ListView.ItemsPanel>
+                                <ItemsPanelTemplate>
+                                  <WrapPanel />
+                                </ItemsPanelTemplate>
+                              </ListView.ItemsPanel>
+                              <ListView.ItemTemplate>
+                                <DataTemplate>
+                                  <Grid>
+                                    <Rectangle Fill="#FF36B31A" RadiusX="4" RadiusY="4" Height="20" />
+                                    <Label Content="{Binding Name}" Foreground="White" />
+                                  </Grid>
+                                </DataTemplate>
+                              </ListView.ItemTemplate>
+                            </ListView>
+                            <ToggleButton Opacity="0" Name="ToggleButton" Focusable="false"
+                                IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
+                                ClickMode="Press" Cursor="Hand" />
+                            <Popup Name="Popup" Placement="Bottom"
+                                IsOpen="{TemplateBinding IsDropDownOpen}" AllowsTransparency="True"
+                                Focusable="False" PopupAnimation="Slide">
+                              <Grid Name="DropDown" SnapsToDevicePixels="True"
+                                  MinWidth="{TemplateBinding ActualWidth}"
+                                  MaxHeight="{TemplateBinding MaxDropDownHeight}">
+                                <Border x:Name="DropDownBorder" Background="White"
+                                    BorderThickness="2" BorderBrush="Gray" />
+                                <ListView Name="PopupListBox" BorderThickness="0"
+                                    ScrollViewer.VerticalScrollBarVisibility="Disabled"
+                                    ScrollViewer.HorizontalScrollBarVisibility="Auto"
+                                    Margin="10,10,10,10" ItemsSource="{Binding AllModules}">
+                                  <ListView.ItemsPanel>
+                                    <ItemsPanelTemplate>
+                                      <WrapPanel Orientation="Vertical" />
+                                    </ItemsPanelTemplate>
+                                  </ListView.ItemsPanel>
+                                  <ListView.ItemTemplate>
+                                    <DataTemplate>
+                                      <CheckBox Content="{Binding Name}"
+                                          IsChecked="{Binding IsSelected}"
+                                          IsEnabled="{Binding IsEnabled}" VerticalAlignment="Center"
+                                          VerticalContentAlignment="Center" Click="Module_Click"
+                                          Margin="4">
+                                        <CheckBox.ContentTemplate>
+                                          <DataTemplate>
+                                            <Grid>
+                                              <Rectangle Fill="#FF36B31A" RadiusX="4" RadiusY="4"
+                                                  Height="20" />
+                                              <Label Content="{Binding}" Foreground="White" />
+                                            </Grid>
+                                          </DataTemplate>
+                                        </CheckBox.ContentTemplate>
+                                      </CheckBox>
+                                    </DataTemplate>
+                                  </ListView.ItemTemplate>
+                                  <ListView.ItemContainerStyle>
+                                    <Style TargetType="ListViewItem">
+                                      <Style.Setters>
+                                        <Setter Property="Template">
+                                          <Setter.Value>
+                                            <ControlTemplate TargetType="ListViewItem">
+                                              <ContentPresenter
+                                                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
+                                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
+                                                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
+                                            </ControlTemplate>
+                                          </Setter.Value>
+                                        </Setter>
+                                      </Style.Setters>
+                                    </Style>
+                                  </ListView.ItemContainerStyle>
+                                </ListView>
+                              </Grid>
+                            </Popup>
+                          </Grid>
+                        </ControlTemplate>
+                      </ComboBox.Template>
+                    </ComboBox>
+                  </DataTemplate>
+                </DataGridTemplateColumn.CellTemplate>
+              </DataGridTemplateColumn>
+            </DataGrid.Columns>
+          </DataGrid>
+          <StackPanel Name="ErrorPanel" Orientation="Horizontal" Grid.Row="1" Margin="0,10"
+              Visibility="Hidden">
+            <Image Name="ErrorIcon" Height="16" Width="16" Margin="5,0" />
+            <Label Name="ErrorMsg" Foreground="Red" />
+          </StackPanel>
+        </Grid>
+      </Grid>
+      <StackPanel HorizontalAlignment="Right" Orientation="Horizontal" Grid.Row="2"
+          Margin="0,0,0,10">
+        <Button Click="OnPreviousButtonClick" Name="PreviousButton"
+            IsEnabled="{Binding Path=PreviousButtonEnabled}" MinWidth="75">&lt; _Previous</Button>
+        <Button MinWidth="75" Name="NextButton" Click="OnNextButtonClick"
+            IsEnabled="{Binding Path=NextButtonEnabled}" Margin="10,0,0,0">_Next &gt;</Button>
+        <Button MinWidth="75" Click="OnFinishButtonClick" Margin="10,0,0,0" IsDefault="True"
+            IsEnabled="{Binding Path=FinishButtonEnabled}" Name="FinishButton"
+            VerticalAlignment="Bottom">_Finish</Button>
+        <Button Click="OnCancelButtonClick" MinWidth="75" Margin="10,0,0,0" Name="CancelButton"
+            IsEnabled="{Binding Path=CancelButtonEnabled}" IsCancel="True">_Cancel</Button>
+      </StackPanel>
+    </Grid>
+  </Grid>
+</common:WizardPage>
diff --git a/QtVsTools.Wizards/ProjectWizard/ConfigPage.xaml.cs b/QtVsTools.Wizards/ProjectWizard/ConfigPage.xaml.cs
new file mode 100644
index 0000000..408cc45
--- /dev/null
+++ b/QtVsTools.Wizards/ProjectWizard/ConfigPage.xaml.cs
@@ -0,0 +1,489 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Interop;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using Microsoft.Win32;
+
+namespace QtVsTools.Wizards.ProjectWizard
+{
+    using Core;
+    using QtVsTools.Common;
+    using Wizards.Common;
+
+    public partial class ConfigPage : WizardPage
+    {
+        interface ICloneable<T> where T : ICloneable<T>
+        {
+            T Clone();
+        }
+
+        class Module : ICloneable<Module>
+        {
+            public string Name { get; set; }
+            public string Id { get; set; }
+            public bool IsSelected { get; set; }
+            public bool IsReadOnly { get; set; }
+            public bool IsEnabled => !IsReadOnly;
+
+            public Module Clone()
+            {
+                return new Module
+                {
+                    Name = Name,
+                    Id = Id,
+                    IsSelected = IsSelected,
+                    IsReadOnly = IsReadOnly
+                };
+            }
+        }
+
+        class Config : ICloneable<Config>, IWizardConfiguration
+        {
+            public string Name { get; set; }
+            public VersionInformation QtVersion { get; set; }
+            public string QtVersionName { get; set; }
+            public string QtVersionPath { get; set; }
+            public string Target { get; set; }
+            public string Platform { get; set; }
+            public bool IsDebug { get; set; }
+
+            public Dictionary<string, Module> Modules { get; set; }
+
+            public IEnumerable<Module> AllModules
+                => Modules.Values.OrderBy(module => module.Name);
+            public IEnumerable<Module> SelectedModules
+                => Modules.Values.Where((Module m) => m.IsSelected);
+
+            IEnumerable<string> IWizardConfiguration.Modules
+                => SelectedModules.SelectMany((Module m) => m.Id.Split(' '));
+
+            public Config Clone()
+            {
+                return new Config
+                {
+                    Name = Name,
+                    QtVersion = QtVersion,
+                    QtVersionName = QtVersionName,
+                    Target = Target,
+                    Platform = Platform,
+                    IsDebug = IsDebug,
+                    Modules = AllModules
+                        .Select((Module m) => m.Clone())
+                        .ToDictionary((Module m) => m.Name)
+                };
+            }
+        }
+
+        class CloneableList<T> : List<T> where T : ICloneable<T>
+        {
+            public CloneableList() : base()
+            { }
+
+            public CloneableList(IEnumerable<T> collection) : base(collection)
+            { }
+
+            public CloneableList<T> Clone()
+            {
+                return new CloneableList<T>(this.Select(x => x.Clone()));
+            }
+        }
+
+        const string QT_VERSION_DEFAULT = "<Default>";
+        const string QT_VERSION_BROWSE = "<Browse...>";
+
+        IEnumerable<string> qtVersionList = new[] { QT_VERSION_DEFAULT, QT_VERSION_BROWSE }
+            .Union(QtVersionManager.The().GetVersions());
+
+        readonly QtVersionManager qtVersionManager = QtVersionManager.The();
+        readonly VersionInformation defaultQtVersionInfo;
+
+        CloneableList<Config> defaultConfigs;
+        List<Config> currentConfigs;
+        bool initialNextButtonIsEnabled;
+        bool initialFinishButtonIsEnabled;
+
+        public ConfigPage()
+        {
+            InitializeComponent();
+
+            string defaultQtVersionName = qtVersionManager.GetDefaultVersion();
+            defaultQtVersionInfo = qtVersionManager.GetVersionInfo(defaultQtVersionName);
+
+            ErrorIcon.Source = Imaging.CreateBitmapSourceFromHIcon(
+                SystemIcons.Exclamation.Handle, Int32Rect.Empty,
+                BitmapSizeOptions.FromEmptyOptions());
+
+            DataContext = this;
+            Loaded += OnLoaded;
+        }
+
+        void OnLoaded(object sender, RoutedEventArgs e)
+        {
+            Loaded -= OnLoaded;
+
+            qtVersionList = new[] { QT_VERSION_DEFAULT, QT_VERSION_BROWSE }
+                .Union(QtVersionManager.The().GetVersions());
+
+            if (defaultQtVersionInfo == null) {
+                Validate();
+                return;
+            }
+
+            var qtModules = QtModules.Instance.GetAvailableModules(defaultQtVersionInfo.qtMajor)
+                .Where((QtModule mi) => mi.Selectable)
+                .Select((QtModule mi) => new Module()
+                {
+                    Name = mi.Name,
+                    Id = mi.proVarQT,
+                    IsSelected = Data.DefaultModules.Contains(mi.LibraryPrefix),
+                    IsReadOnly = Data.DefaultModules.Contains(mi.LibraryPrefix),
+                });
+
+            defaultConfigs = new CloneableList<Config> {
+                new Config {
+                    Name = "Debug",
+                    IsDebug = true,
+                    QtVersion = defaultQtVersionInfo,
+                    QtVersionName = defaultQtVersionInfo.name,
+                    Target = defaultQtVersionInfo.isWinRT()
+                        ? ProjectTargets.WindowsStore.Cast<string>()
+                        : ProjectTargets.Windows.Cast<string>(),
+                    Platform = defaultQtVersionInfo.is64Bit()
+                        ? ProjectPlatforms.X64.Cast<string>()
+                        : ProjectPlatforms.Win32.Cast<string>(),
+                    Modules = qtModules.ToDictionary((Module m) => m.Name),
+                },
+                new Config {
+                    Name = "Release",
+                    IsDebug = false,
+                    QtVersion = defaultQtVersionInfo,
+                    QtVersionName = defaultQtVersionInfo.name,
+                    Target = defaultQtVersionInfo.isWinRT()
+                        ? ProjectTargets.WindowsStore.Cast<string>()
+                        : ProjectTargets.Windows.Cast<string>(),
+                    Platform = defaultQtVersionInfo.is64Bit()
+                        ? ProjectPlatforms.X64.Cast<string>()
+                        : ProjectPlatforms.Win32.Cast<string>(),
+                    Modules = qtModules.ToDictionary((Module m) => m.Name),
+                }
+            };
+            currentConfigs = defaultConfigs.Clone();
+            ConfigTable.ItemsSource = currentConfigs;
+
+            initialNextButtonIsEnabled = NextButton.IsEnabled;
+            initialFinishButtonIsEnabled = FinishButton.IsEnabled;
+
+            Validate();
+        }
+
+        /// <summary>
+        /// Callback to validate selected configurations.
+        /// Must return an error message in case of failed validation.
+        /// Otherwise, return empty string or null.
+        /// </summary>
+        public Func<IEnumerable<IWizardConfiguration>, string> ValidateConfigs { get; set; }
+
+        void Validate()
+        {
+            if (currentConfigs == null) {
+                ErrorMsg.Content = "Register at least one Qt version using \"Qt VS Tools\"" +
+                    " -> \"Qt Options\".";
+                ErrorPanel.Visibility = Visibility.Visible;
+                NextButton.IsEnabled = false;
+                FinishButton.IsEnabled = false;
+            } else if (currentConfigs // "$(Configuration)|$(Platform)" must be unique
+                .GroupBy((Config c) => string.Format("{0}|{1}", c.Name, c.Platform))
+                .Where((IGrouping<string, Config> g) => g.Count() > 1)
+                .Any()) {
+                ErrorMsg.Content = "(Configuration, Platform) must be unique";
+                ErrorPanel.Visibility = Visibility.Visible;
+                NextButton.IsEnabled = false;
+                FinishButton.IsEnabled = false;
+            } else if (ValidateConfigs != null
+                && ValidateConfigs(currentConfigs) is string errorMsg
+                && !string.IsNullOrEmpty(errorMsg)) {
+                ErrorMsg.Content = errorMsg;
+                ErrorPanel.Visibility = Visibility.Visible;
+                NextButton.IsEnabled = false;
+                FinishButton.IsEnabled = false;
+            } else {
+                ErrorMsg.Content = string.Empty;
+                ErrorPanel.Visibility = Visibility.Hidden;
+                NextButton.IsEnabled = initialNextButtonIsEnabled;
+                FinishButton.IsEnabled = initialFinishButtonIsEnabled;
+            }
+        }
+
+        void RemoveConfig_Click(object sender, RoutedEventArgs e)
+        {
+            if (sender is Button buttonRemove
+                && GetBinding(buttonRemove) is Config config) {
+                currentConfigs.Remove(config);
+                if (!currentConfigs.Any()) {
+                    currentConfigs = defaultConfigs.Clone();
+                    ConfigTable.ItemsSource = currentConfigs;
+                }
+                ConfigTable.Items.Refresh();
+                Validate();
+            }
+        }
+
+        void DuplicateConfig_Click(object sender, RoutedEventArgs e)
+        {
+            if (sender is Button buttonDuplicate
+                && GetBinding(buttonDuplicate) is Config config) {
+                currentConfigs.Add(config.Clone());
+                ConfigTable.Items.Refresh();
+                Validate();
+            }
+        }
+
+        void Name_TextChanged(object sender, TextChangedEventArgs e)
+        {
+            if (sender is TextBox txt && GetBinding(txt) is Config cfg)
+                cfg.Name = txt.Text;
+            Validate();
+        }
+
+        void QtVersion_ComboBox_Loaded(object sender, RoutedEventArgs e)
+        {
+            if (sender is ComboBox comboBoxQtVersion
+                && GetBinding(comboBoxQtVersion) is Config config) {
+                comboBoxQtVersion.IsEnabled = false;
+                comboBoxQtVersion.ItemsSource = qtVersionList;
+                comboBoxQtVersion.Text = config.QtVersionName;
+                comboBoxQtVersion.IsEnabled = true;
+            }
+        }
+
+        void QtVersion_TextChanged(object sender, TextChangedEventArgs e)
+        {
+            if (sender is ComboBox comboBoxQtVersion
+                && comboBoxQtVersion.IsEnabled
+                && GetBinding(comboBoxQtVersion) is Config config
+                && config.QtVersionName != comboBoxQtVersion.Text) {
+                var oldQtVersion = config.QtVersion;
+                if (comboBoxQtVersion.Text == QT_VERSION_DEFAULT) {
+                    config.QtVersion = defaultQtVersionInfo;
+                    config.QtVersionName = defaultQtVersionInfo.name;
+                    config.QtVersionPath = defaultQtVersionInfo.qtDir;
+                    comboBoxQtVersion.Text = defaultQtVersionInfo.name;
+                } else if (comboBoxQtVersion.Text == QT_VERSION_BROWSE) {
+                    var openFileDialog = new OpenFileDialog
+                    {
+                        Filter = "qmake (qmake.exe)|qmake.exe"
+                    };
+                    if (openFileDialog.ShowDialog() == true) {
+                        IEnumerable<string> binPath = Path.GetDirectoryName(openFileDialog.FileName)
+                            .Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
+                        string lastDirName = binPath.LastOrDefault();
+                        if ("bin".Equals(lastDirName, StringComparison.InvariantCultureIgnoreCase))
+                            binPath = binPath.Take(binPath.Count() - 1);
+
+                        var qtVersion = string.Join(
+                            Path.DirectorySeparatorChar.ToString(), binPath);
+                        var versionInfo = VersionInformation.Get(qtVersion);
+                        if (versionInfo != null) {
+                            versionInfo.name = qtVersion;
+                            config.QtVersion = versionInfo;
+                            config.QtVersionName = versionInfo.name;
+                            config.QtVersionPath = config.QtVersion.qtDir;
+                        }
+                    }
+                    comboBoxQtVersion.Text = config.QtVersionName;
+                } else if (qtVersionManager.GetVersions().Contains(comboBoxQtVersion.Text)) {
+                    config.QtVersion = qtVersionManager.GetVersionInfo(comboBoxQtVersion.Text);
+                    config.QtVersionName = comboBoxQtVersion.Text;
+                    config.QtVersionPath = qtVersionManager.GetInstallPath(comboBoxQtVersion.Text);
+                } else {
+                    config.QtVersion = null;
+                    config.QtVersionName = config.QtVersionPath = comboBoxQtVersion.Text;
+                }
+
+                if (oldQtVersion != config.QtVersion) {
+                    if (config.QtVersion != null) {
+                        config.Target = config.QtVersion.isWinRT()
+                            ? ProjectTargets.WindowsStore.Cast<string>()
+                            : ProjectTargets.Windows.Cast<string>();
+                        config.Platform = config.QtVersion.is64Bit()
+                            ? ProjectPlatforms.X64.Cast<string>()
+                            : ProjectPlatforms.Win32.Cast<string>();
+                        config.Modules =
+                            QtModules.Instance.GetAvailableModules(config.QtVersion.qtMajor)
+                                .Where((QtModule mi) => mi.Selectable)
+                                .Select((QtModule mi) => new Module()
+                                {
+                                    Name = mi.Name,
+                                    Id = mi.proVarQT,
+                                    IsSelected = Data.DefaultModules.Contains(mi.LibraryPrefix),
+                                    IsReadOnly = Data.DefaultModules.Contains(mi.LibraryPrefix),
+                                }).ToDictionary((Module m) => m.Name);
+                    } else if (config.QtVersionPath.StartsWith("SSH:")) {
+                        config.Target = ProjectTargets.LinuxSSH.Cast<string>();
+                    } else if (config.QtVersionPath.StartsWith("WSL:")) {
+                        config.Target = ProjectTargets.LinuxWSL.Cast<string>();
+                    }
+                    ConfigTable.Items.Refresh();
+                }
+                Validate();
+            }
+        }
+
+        void Target_ComboBox_Loaded(object sender, RoutedEventArgs e)
+        {
+            if (sender is ComboBox comboBoxTarget
+                && GetBinding(comboBoxTarget) is Config config) {
+                comboBoxTarget.IsEnabled = false;
+                comboBoxTarget.ItemsSource = EnumExt.GetValues<string>(typeof(ProjectTargets));
+                comboBoxTarget.Text = config.Target;
+                comboBoxTarget.IsEnabled = true;
+            }
+        }
+
+        void Target_TextChanged(object sender, TextChangedEventArgs e)
+        {
+            if (sender is ComboBox comboBoxTarget
+                && comboBoxTarget.IsEnabled
+                && GetBinding(comboBoxTarget) is Config config
+                && config.Target != comboBoxTarget.Text) {
+                config.Target = comboBoxTarget.Text;
+                ConfigTable.Items.Refresh();
+                Validate();
+            }
+        }
+
+        void Platform_ComboBox_Loaded(object sender, RoutedEventArgs e)
+        {
+            if (sender is ComboBox comboBoxPlatform
+                && GetBinding(comboBoxPlatform) is Config config) {
+                comboBoxPlatform.IsEnabled = false;
+                comboBoxPlatform.ItemsSource = EnumExt.GetValues<string>(typeof(ProjectPlatforms));
+                comboBoxPlatform.Text = config.Platform;
+                comboBoxPlatform.IsEnabled = true;
+            }
+        }
+
+        void Platform_TextChanged(object sender, TextChangedEventArgs e)
+        {
+            if (sender is ComboBox comboBoxPlatform
+                && comboBoxPlatform.IsEnabled
+                && GetBinding(comboBoxPlatform) is Config config
+                && config.Platform != comboBoxPlatform.Text) {
+                config.Platform = comboBoxPlatform.Text;
+                ConfigTable.Items.Refresh();
+                Validate();
+            }
+        }
+
+        void Debug_Click(object sender, RoutedEventArgs e)
+        {
+            if (sender is CheckBox checkBox && GetBinding(checkBox) is Config config) {
+                config.IsDebug = checkBox.IsChecked ?? false;
+                if (config.IsDebug && config.Name.EndsWith("Release")) {
+                    config.Name = string.Format("{0}Debug",
+                        config.Name.Substring(0, config.Name.Length - "Release".Length));
+                    ConfigTable.Items.Refresh();
+                } else if (!config.IsDebug && config.Name.EndsWith("Debug")) {
+                    config.Name = string.Format("{0}Release",
+                        config.Name.Substring(0, config.Name.Length - "Debug".Length));
+                    ConfigTable.Items.Refresh();
+                }
+                Validate();
+            }
+        }
+
+        void Module_Click(object sender, RoutedEventArgs e)
+        {
+            if (sender is CheckBox checkBoxModule
+                && (checkBoxModule.TemplatedParent as ContentPresenter)?.Content is Module
+                && GetBinding(checkBoxModule) is Config config
+                && FindAncestor(checkBoxModule, "Modules") is ComboBox comboBoxModules
+                && FindDescendant(comboBoxModules, "SelectedModules") is ListView selectedModules) {
+                selectedModules.ItemsSource = config.SelectedModules;
+                Validate();
+            }
+        }
+
+        protected override void OnNextButtonClick(object sender, RoutedEventArgs e)
+        {
+            Data.Configs = currentConfigs.Cast<IWizardConfiguration>();
+            base.OnNextButtonClick(sender, e);
+        }
+
+        protected override void OnFinishButtonClick(object sender, RoutedEventArgs e)
+        {
+            Data.Configs = currentConfigs.Cast<IWizardConfiguration>();
+            base.OnFinishButtonClick(sender, e);
+        }
+
+        static object GetBinding(FrameworkElement control)
+        {
+            if (control.BindingGroup == null
+                || control.BindingGroup.Items == null
+                || control.BindingGroup.Items.Count == 0) {
+                return null;
+            }
+            return control.BindingGroup.Items[0];
+        }
+
+        static FrameworkElement FindAncestor(FrameworkElement control, string name)
+        {
+            while (control != null && control.Name != name) {
+                object parent = control.Parent
+                    ?? control.TemplatedParent
+                    ?? VisualTreeHelper.GetParent(control);
+                control = parent as FrameworkElement;
+            }
+            return control;
+        }
+
+        static FrameworkElement FindDescendant(FrameworkElement control, string name)
+        {
+            var stack = new Stack<FrameworkElement>(new[] { control });
+            while (stack.Any()) {
+                control = stack.Pop();
+                if (control?.Name == name && control is FrameworkElement result)
+                    return result;
+                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(control); ++i) {
+                    if (VisualTreeHelper.GetChild(control, i) is FrameworkElement child)
+                        stack.Push(child);
+                }
+            }
+            return null;
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/ProjectWizard/Console/ConsoleWizard.cs b/QtVsTools.Wizards/ProjectWizard/Console/ConsoleWizard.cs
new file mode 100644
index 0000000..76c8365
--- /dev/null
+++ b/QtVsTools.Wizards/ProjectWizard/Console/ConsoleWizard.cs
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Collections.Generic;
+
+namespace QtVsTools.Wizards.ProjectWizard
+{
+    using QtVsTools.Common;
+    using Wizards.Common;
+
+    public class ConsoleWizard : ProjectTemplateWizard
+    {
+        LazyFactory Lazy { get; } = new LazyFactory();
+
+        protected override Options TemplateType => Options.Application | Options.ConsoleSystem;
+
+        protected override WizardData WizardData => Lazy.Get(() =>
+            WizardData, () => new WizardData
+            {
+                DefaultModules = new List<string> { "QtCore" }
+            });
+
+        protected override WizardWindow WizardWindow => Lazy.Get(() =>
+            WizardWindow, () => new WizardWindow(title: "Qt Console Application Wizard")
+            {
+                new WizardIntroPage {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt Console Application Wizard",
+                    Message = @"This wizard generates a Qt console application "
+                        + @"project. The application derives from QCoreApplication "
+                        + @"and does not present a GUI." + System.Environment.NewLine
+                        + System.Environment.NewLine + "To continue, click Next.",
+                    PreviousButtonEnabled = false,
+                    NextButtonEnabled = true,
+                    FinishButtonEnabled = false,
+                    CancelButtonEnabled = true
+                },
+                new ConfigPage {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt Console Application Wizard",
+                    Message =
+                            @"Setup the configurations you want to include in your project. "
+                            + @"The recommended settings for this project are selected by default.",
+                    PreviousButtonEnabled = true,
+                    NextButtonEnabled = false,
+                    FinishButtonEnabled = true,
+                    CancelButtonEnabled = true,
+                    ValidateConfigs = ValidateConfigsForConsoleApp
+                }
+            });
+
+        string ValidateConfigsForConsoleApp(IEnumerable<IWizardConfiguration> configs)
+        {
+            foreach (var config in configs) {
+                if (config.Target.EqualTo(ProjectTargets.WindowsStore)) {
+                    return string.Format(
+                        "Console Application project not available for the '{0}' target.",
+                        config.Target);
+                }
+            }
+            return string.Empty;
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/ProjectWizard/Designer/DesignerPage.xaml b/QtVsTools.Wizards/ProjectWizard/Designer/DesignerPage.xaml
new file mode 100644
index 0000000..1a7b71f
--- /dev/null
+++ b/QtVsTools.Wizards/ProjectWizard/Designer/DesignerPage.xaml
@@ -0,0 +1,310 @@
+<!--
+    *****************************************************************************
+    **
+    ** Copyright (C) 2016 The Qt Company Ltd.
+    ** Contact: https://www.qt.io/licensing/
+    **
+    ** This file is part of the Qt VS Tools.
+    **
+    ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+    ** Commercial License Usage
+    ** Licensees holding valid commercial Qt licenses may use this file in
+    ** accordance with the commercial license agreement provided with the
+    ** Software or, alternatively, in accordance with the terms contained in
+    ** a written agreement between you and The Qt Company. For licensing terms
+    ** and conditions see https://www.qt.io/terms-conditions. For further
+    ** information use the contact form at https://www.qt.io/contact-us.
+    **
+    ** GNU General Public License Usage
+    ** Alternatively, this file may be used under the terms of the GNU
+    ** General Public License version 3 as published by the Free Software
+    ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+    ** included in the packaging of this file. Please review the following
+    ** information to ensure the GNU General Public License requirements will
+    ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+    **
+    ** $QT_END_LICENSE$
+    **
+    *****************************************************************************
+-->
+
+<common:WizardPage x:Class="QtVsTools.Wizards.ProjectWizard.DesignerPage"
+                  xmlns:common="clr-namespace:QtVsTools.Wizards.Common"
+                  xmlns:util="clr-namespace:QtVsTools.Wizards.Util"
+                  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+                  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+                  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+                  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+                  KeepAlive="True"
+                  mc:Ignorable="d"
+                  d:DesignHeight="445"
+                  d:DesignWidth="585">
+    <Grid>
+        <Grid.ColumnDefinitions>
+            <ColumnDefinition Width="100" />
+            <ColumnDefinition Width="*" />
+        </Grid.ColumnDefinitions>
+        <Image Grid.Column="0"
+               HorizontalAlignment="Center"
+               Source="/QtVsTools.Wizards;component/Resources/Qt-logo-small.png"
+               VerticalAlignment="Top"
+               Margin="0,25,0,0"
+               RenderTransformOrigin="1,0">
+            <Image.RenderTransform>
+                <TransformGroup>
+                    <ScaleTransform ScaleY="0.86"
+                                    ScaleX="0.86" />
+                </TransformGroup>
+            </Image.RenderTransform>
+        </Image>
+        <Grid Grid.Column="1"
+              Margin="25,25,10,0">
+            <Grid.RowDefinitions>
+                <RowDefinition Height="Auto" />
+                <RowDefinition Height="*" />
+                <RowDefinition Height="Auto" />
+            </Grid.RowDefinitions>
+            <TextBlock TextWrapping="Wrap"
+                       Grid.Row="0">
+                <Run FontWeight="Bold"
+                     Text="{Binding Path=Header}" />
+                <LineBreak />
+                <LineBreak />
+                <Run Text="{Binding Path=Message}" />
+                <LineBreak />
+            </TextBlock>
+            <Grid Grid.Row="1">
+                <Grid.RowDefinitions>
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                </Grid.RowDefinitions>
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="*" />
+                    <ColumnDefinition Width="*" />
+                </Grid.ColumnDefinitions>
+                <Grid.Resources>
+                    <Style TargetType="TextBox">
+                        <Style.Triggers>
+                            <Trigger Property="Validation.HasError"
+                                     Value="true">
+                                <Setter Property="ToolTip"
+                                        Value="{Binding RelativeSource={RelativeSource Self},
+                                         Path=(Validation.Errors)[0].ErrorContent}" />
+                            </Trigger>
+                        </Style.Triggers>
+                    </Style>
+                </Grid.Resources>
+                <TextBlock Grid.Row="0"
+                           Margin="0,0,10,5">
+                    <Run FontWeight="Bold"
+                         Text="Custom Widget "/>
+                    <Run Text="- Class Name:"/>
+                </TextBlock>
+                <TextBox Grid.Row="1"
+                         Margin="0,0,10,10"
+                         x:Name="ClassName"
+                         TextChanged="OnClassNameChanged">
+                    <TextBox.Text>
+                        <Binding Path="Data.ClassName"
+                                 NotifyOnValidationError="True"
+                                 UpdateSourceTrigger="PropertyChanged">
+                            <Binding.ValidationRules>
+                                <util:ClassNameValidationRule />
+                            </Binding.ValidationRules>
+                        </Binding>
+                    </TextBox.Text>
+                </TextBox>
+                <TextBlock Grid.Column="1"
+                           Grid.Row="0"
+                           Text="Base class:"
+                           Margin="0,0,0,5" />
+                <TextBox  Grid.Column="1"
+                          Grid.Row="1"
+                          Name="BaseClass"
+                          Margin="0,0,0,10">
+                    <TextBox.Text>
+                        <Binding Path="Data.BaseClass"
+                                 NotifyOnValidationError="True"
+                                 UpdateSourceTrigger="PropertyChanged">
+                            <Binding.ValidationRules>
+                                <util:ClassNameValidationRule AllowEmptyIdentifier="True"/>
+                            </Binding.ValidationRules>
+                        </Binding>
+                    </TextBox.Text>
+                </TextBox>
+                <TextBlock Grid.Row="2"
+                           Margin="0,0,10,5"
+                           Text="Header (.h) file:" />
+                <TextBox Grid.Row="3"
+                         Margin="0,0,10,30"
+                         Name="ClassHeaderFile">
+                    <TextBox.Text>
+                        <Binding Path="Data.ClassHeaderFile"
+                                 NotifyOnValidationError="True"
+                                 UpdateSourceTrigger="PropertyChanged">
+                            <Binding.ValidationRules>
+                                <util:FileNameValidationRule FileExt=".h" />
+                            </Binding.ValidationRules>
+                        </Binding>
+                    </TextBox.Text>
+                </TextBox>
+                <TextBlock Grid.Column="1"
+                           Grid.Row="2"
+                           Margin="0,0,0,5"
+                           Text="Source (.cpp) file:" />
+                <TextBox Grid.Column="1"
+                         Grid.Row="3"
+                         Margin="0,0,0,30"
+                         Name="ClassSourceFile">
+                    <TextBox.Text>
+                        <Binding Path="Data.ClassSourceFile"
+                                 NotifyOnValidationError="True"
+                                 UpdateSourceTrigger="PropertyChanged">
+                            <Binding.ValidationRules>
+                                <util:FileNameValidationRule FileExt=".cpp" />
+                            </Binding.ValidationRules>
+                        </Binding>
+                    </TextBox.Text>
+                </TextBox>
+                <TextBlock Grid.Column="0"
+                           Grid.Row="4"
+                           Margin="0,0,0,5"
+                           >
+                    <Run FontWeight="Bold"
+                         Text="Plugin"/>
+                    <Run Text=" - Class Name:"/>
+                </TextBlock>
+                <TextBox Grid.Column="0"
+                         Grid.Row="5"
+                         Margin="0,0,0,10"
+                         Name="PluginClass">
+                    <TextBox.Text>
+                        <Binding Path="Data.PluginClass"
+                                 NotifyOnValidationError="True"
+                                 UpdateSourceTrigger="PropertyChanged">
+                            <Binding.ValidationRules>
+                                <util:ClassNameValidationRule />
+                            </Binding.ValidationRules>
+                        </Binding>
+                    </TextBox.Text>
+                </TextBox>
+                <TextBlock Grid.Row="6"
+                           Margin="0,0,10,5"
+                           Text="Header (.h) file:" />
+                <TextBox Grid.Row="7"
+                         Margin="0,0,10,0"
+                         Name="PluginHeaderFile">
+                    <TextBox.Text>
+                        <Binding Path="Data.PluginHeaderFile"
+                                 NotifyOnValidationError="True"
+                                 UpdateSourceTrigger="PropertyChanged">
+                            <Binding.ValidationRules>
+                                <util:FileNameValidationRule FileExt=".h" />
+                            </Binding.ValidationRules>
+                        </Binding>
+                    </TextBox.Text>
+                </TextBox>
+                <TextBlock Grid.Column="1"
+                           Grid.Row="6"
+                           Margin="0,0,0,5"
+                           Text="Source (.cpp) file:" />
+                <TextBox Grid.Column="1"
+                         Grid.Row="7"
+                         Margin="0"
+                         Name="PluginSourceFile">
+                    <TextBox.Text>
+                        <Binding Path="Data.PluginSourceFile"
+                                 NotifyOnValidationError="True"
+                                 UpdateSourceTrigger="PropertyChanged">
+                            <Binding.ValidationRules>
+                                <util:FileNameValidationRule FileExt=".cpp" />
+                            </Binding.ValidationRules>
+                        </Binding>
+                    </TextBox.Text>
+                </TextBox>
+                <CheckBox Grid.Row="8"
+                          Content="Lower case file names"
+                          Margin="0,20,0,5"
+                          Name="LowerCaseFileNames"
+                          Click="OnLowerCaseFileNamesClick" />
+                <CheckBox Grid.Row="9"
+                          Content="Precompiled header"
+                          Margin="0,10,0,0"
+                          IsChecked="{Binding Path=Data.UsePrecompiledHeader}" />
+            </Grid>
+            <StackPanel HorizontalAlignment="Right"
+                        Orientation="Horizontal"
+                        Grid.Row="2"
+                        Margin="0,0,0,10">
+                <Button Click="OnPreviousButtonClick"
+                        Name="PreviousButton"
+                        IsEnabled="{Binding Path=PreviousButtonEnabled}"
+                        MinWidth="75">&lt; _Previous</Button>
+                <Button MinWidth="75"
+                        Name="NextButton"
+                        Click="OnNextButtonClick"
+                        IsEnabled="{Binding Path=NextButtonEnabled}"
+                        Margin="10,0,0,0">_Next &gt;</Button>
+                <Button MinWidth="75"
+                        Click="OnFinishButtonClick"
+                        Margin="10,0,0,0"
+                        IsDefault="True"
+                        Name="FinishButton"
+                        Content="_Finish"
+                        VerticalAlignment="Bottom">
+                    <Button.Style>
+                        <Style TargetType="Button">
+                            <Setter Property="IsEnabled"
+                                    Value="false" />
+                            <Style.Triggers>
+                                <MultiDataTrigger>
+                                    <MultiDataTrigger.Conditions>
+                                        <Condition Binding="{Binding Path=FinishButtonEnabled}"
+                                                   Value="true" />
+                                        <Condition Binding="{Binding ElementName=ClassName,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                        <Condition Binding="{Binding ElementName=BaseClass,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                        <Condition Binding="{Binding ElementName=ClassHeaderFile,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                        <Condition Binding="{Binding ElementName=ClassSourceFile,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                        <Condition Binding="{Binding ElementName=PluginClass,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                        <Condition Binding="{Binding ElementName=PluginHeaderFile,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                        <Condition Binding="{Binding ElementName=PluginSourceFile,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                    </MultiDataTrigger.Conditions>
+                                    <Setter Property="IsEnabled"
+                                            Value="true" />
+                                </MultiDataTrigger>
+                            </Style.Triggers>
+                        </Style>
+                    </Button.Style>
+                </Button>
+                <Button Click="OnCancelButtonClick"
+                        MinWidth="75"
+                        Margin="10,0,0,0"
+                        Name="CancelButton"
+                        IsEnabled="{Binding Path=CancelButtonEnabled}"
+                        IsCancel="True">_Cancel</Button>
+            </StackPanel>
+        </Grid>
+    </Grid>
+</common:WizardPage>
diff --git a/QtVsTools.Wizards/ProjectWizard/Designer/DesignerPage.xaml.cs b/QtVsTools.Wizards/ProjectWizard/Designer/DesignerPage.xaml.cs
new file mode 100644
index 0000000..fb1f10e
--- /dev/null
+++ b/QtVsTools.Wizards/ProjectWizard/Designer/DesignerPage.xaml.cs
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Windows;
+using System.Windows.Controls;
+
+namespace QtVsTools.Wizards.ProjectWizard
+{
+    using Wizards.Common;
+
+    public partial class DesignerPage : WizardPage
+    {
+        public DesignerPage()
+        {
+            InitializeComponent();
+            DataContext = this;
+        }
+
+        private void OnClassNameChanged(object sender, TextChangedEventArgs e)
+        {
+            UpdateFileNames();
+        }
+
+        private void OnLowerCaseFileNamesClick(object sender, RoutedEventArgs e)
+        {
+            UpdateFileNames();
+        }
+
+        private void UpdateFileNames()
+        {
+            var filename = ClassName.Text;
+            var pluginFilename = PluginClass.Text;
+            if (LowerCaseFileNames.IsChecked.GetValueOrDefault()) {
+                filename = filename.ToLower();
+                pluginFilename = pluginFilename.ToLower();
+            }
+
+            ClassHeaderFile.Text = filename + @".h";
+            ClassSourceFile.Text = filename + @".cpp";
+
+            PluginHeaderFile.Text = pluginFilename + @".h";
+            PluginSourceFile.Text = pluginFilename + @".cpp";
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/ProjectWizard/Designer/DesignerWizard.cs b/QtVsTools.Wizards/ProjectWizard/Designer/DesignerWizard.cs
new file mode 100644
index 0000000..f93f677
--- /dev/null
+++ b/QtVsTools.Wizards/ProjectWizard/Designer/DesignerWizard.cs
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Windows.Controls;
+using EnvDTE;
+
+namespace QtVsTools.Wizards.ProjectWizard
+{
+    using Core;
+    using Legacy = Core.Legacy;
+    using QtVsTools.Common;
+    using Wizards.Common;
+
+    using static QtVsTools.Common.EnumExt;
+
+    public class DesignerWizard : ProjectTemplateWizard
+    {
+        LazyFactory Lazy { get; } = new LazyFactory();
+
+        protected override Options TemplateType =>
+            Options.PluginProject | Options.DynamicLibrary | Options.GUISystem;
+
+        enum NewClass
+        {
+            [String("classname")] ClassName,
+            [String("baseclass")] BaseClass,
+            [String("sourcefilename")] SourceFileName,
+            [String("headerfilename")] HeaderFileName,
+            [String("include")] Include,
+        }
+
+        enum NewDesignerPlugin
+        {
+            [String("plugin_class")] ClassName,
+            [String("objname")] ObjectName,
+            [String("pluginsourcefilename")] SourceFileName,
+            [String("pluginheaderfilename")] HeaderFileName,
+            [String("plugin_json")] JsonFileName,
+        }
+
+        protected override WizardData WizardData => Lazy.Get(() =>
+            WizardData, () => new WizardData
+            {
+                DefaultModules = new List<string> {
+                    "QtCore", "QtGui", "QtWidgets", "QtDesigner"
+                }
+            });
+
+        protected override WizardWindow WizardWindow => Lazy.Get(() =>
+            WizardWindow, () => new WizardWindow(title: "Qt Custom Designer Widget")
+            {
+                new WizardIntroPage {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt Custom Designer Widget",
+                    Message = @"This wizard generates a custom designer widget which can be "
+                        + @"used in Qt Designer or Visual Studio."
+                        + System.Environment.NewLine + System.Environment.NewLine
+                        + "To continue, click Next.",
+                    PreviousButtonEnabled = false,
+                    NextButtonEnabled = true,
+                    FinishButtonEnabled = false,
+                    CancelButtonEnabled = true
+                },
+                new ConfigPage {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt Custom Designer Widget",
+                    Message =
+                            @"Setup the configurations you want to include in your project. "
+                            + @"The recommended settings for this project are selected by default.",
+                    PreviousButtonEnabled = true,
+                    NextButtonEnabled = true,
+                    FinishButtonEnabled = false,
+                    CancelButtonEnabled = true,
+                    ValidateConfigs = ValidateConfigsForDesignerWidget
+                },
+                new DesignerPage {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt Custom Designer Widget",
+                    Message = @"This wizard generates a custom designer widget which can be "
+                        + @"used in Qt Designer or Visual Studio.",
+                    PreviousButtonEnabled = true,
+                    NextButtonEnabled = false,
+                    FinishButtonEnabled = true,
+                    CancelButtonEnabled = true
+                }
+            }
+        );
+
+        string ValidateConfigsForDesignerWidget(IEnumerable<IWizardConfiguration> configs)
+        {
+            foreach (var config in configs) {
+                if (config.Target.EqualTo(ProjectTargets.WindowsStore)) {
+                    return string.Format(
+                        "Custom Designer Widget project not available for the '{0}' target.",
+                        config.Target);
+                }
+            }
+            return string.Empty;
+        }
+
+        protected override void BeforeWizardRun()
+        {
+            var className = Parameter[NewProject.SafeName];
+            className = Regex.Replace(className, @"[^a-zA-Z0-9_]", string.Empty);
+            className = Regex.Replace(className, @"^[\d-]*\s*", string.Empty);
+            var result = new Util.ClassNameValidationRule().Validate(className, null);
+            if (result != ValidationResult.ValidResult)
+                className = @"MyDesignerWidget";
+
+            WizardData.ClassName = className;
+            WizardData.BaseClass = @"QWidget";
+            WizardData.ClassHeaderFile = className + @".h";
+            WizardData.ClassSourceFile = className + @".cpp";
+
+            WizardData.PluginClass = className + @"Plugin";
+            WizardData.PluginHeaderFile = WizardData.PluginClass + @".h";
+            WizardData.PluginSourceFile = WizardData.PluginClass + @".cpp";
+        }
+
+        protected override void BeforeTemplateExpansion()
+        {
+            Parameter[NewClass.ClassName] = WizardData.ClassName;
+            Parameter[NewClass.BaseClass] = WizardData.BaseClass;
+            Parameter[NewClass.HeaderFileName] = WizardData.ClassHeaderFile;
+            Parameter[NewClass.SourceFileName] = WizardData.ClassSourceFile;
+
+            var include = new StringBuilder();
+            if (UsePrecompiledHeaders)
+                include.AppendLine(string.Format("#include \"{0}\"", PrecompiledHeader.Include));
+            include.AppendLine(string.Format("#include \"{0}\"", WizardData.ClassHeaderFile));
+            Parameter[NewClass.Include] = FormatParam(include);
+
+            Parameter[NewDesignerPlugin.ClassName] = WizardData.PluginClass;
+            Parameter[NewDesignerPlugin.HeaderFileName] = WizardData.PluginHeaderFile;
+            Parameter[NewDesignerPlugin.SourceFileName] = WizardData.PluginSourceFile;
+            Parameter[NewDesignerPlugin.JsonFileName] = WizardData.PluginClass.ToLower() + ".json";
+            Parameter[NewDesignerPlugin.ObjectName] = string.Format("{0}{1}",
+                WizardData.ClassName[0],
+                WizardData.ClassName.Substring(1));
+        }
+
+        protected override void OnProjectGenerated(Project project)
+        {
+            var qtPro = Core.QtProject.Create(project);
+            if (qtPro != null) {
+                QtProject.MarkAsQtPlugin(qtPro);
+                Legacy.QtProject.MarkAsDesignerPluginProject(qtPro);
+            }
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/ProjectWizard/Empty/EmptyWizard.cs b/QtVsTools.Wizards/ProjectWizard/Empty/EmptyWizard.cs
new file mode 100644
index 0000000..b223170
--- /dev/null
+++ b/QtVsTools.Wizards/ProjectWizard/Empty/EmptyWizard.cs
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Collections.Generic;
+
+namespace QtVsTools.Wizards.ProjectWizard
+{
+    using QtVsTools.Common;
+    using Wizards.Common;
+
+    public class EmptyWizard : ProjectTemplateWizard
+    {
+        LazyFactory Lazy { get; } = new LazyFactory();
+
+        protected override Options TemplateType => Options.Application | Options.GUISystem;
+
+        protected override WizardData WizardData => Lazy.Get(() =>
+            WizardData, () => new WizardData
+            {
+                DefaultModules = new List<string> { }
+            });
+
+        protected override WizardWindow WizardWindow => Lazy.Get(() =>
+            WizardWindow, () => new WizardWindow(title: "Qt Empty Application Wizard")
+            {
+                new WizardIntroPage {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt Empty Application Wizard",
+                    Message = @"This wizard generates an empty Qt application project."
+                        + System.Environment.NewLine
+                        + "Click Finish to create the project.",
+                    PreviousButtonEnabled = false,
+                    NextButtonEnabled = true,
+                    FinishButtonEnabled = false,
+                    CancelButtonEnabled = true
+                },
+                new ConfigPage {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt Empty Application Wizard",
+                    Message =
+                            @"Setup the configurations you want to include in your project. "
+                            + @"The recommended settings for this project are selected by default.",
+                    PreviousButtonEnabled = true,
+                    NextButtonEnabled = false,
+                    FinishButtonEnabled = true,
+                    CancelButtonEnabled = true,
+                }
+            });
+    }
+}
diff --git a/QtVsTools.Wizards/ProjectWizard/Gui/GuiWizard.cs b/QtVsTools.Wizards/ProjectWizard/Gui/GuiWizard.cs
new file mode 100644
index 0000000..a4f6f21
--- /dev/null
+++ b/QtVsTools.Wizards/ProjectWizard/Gui/GuiWizard.cs
@@ -0,0 +1,365 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Windows.Controls;
+using EnvDTE;
+
+namespace QtVsTools.Wizards.ProjectWizard
+{
+    using QtVsTools.Common;
+    using Core;
+    using Wizards.Common;
+
+    using static QtVsTools.Common.EnumExt;
+
+    public class GuiWizard : ProjectTemplateWizard
+    {
+        LazyFactory Lazy { get; } = new LazyFactory();
+
+        protected override Options TemplateType => Options.Application | Options.GUISystem;
+
+        readonly Func<IWizardConfiguration, bool> whereConfigTargetIsWindowsStore
+            = (IWizardConfiguration config) => config.Target.EqualTo(ProjectTargets.WindowsStore);
+
+        enum NewClass
+        {
+            [String("classname")] ClassName,
+            [String("baseclass")] BaseClass,
+            [String("sourcefilename")] SourceFileName,
+            [String("headerfilename")] HeaderFileName,
+            [String("include")] Include,
+        }
+
+        enum NewGuiProject
+        {
+            [String("centralwidget")] CentralWidget,
+            [String("qrcfilename")] QrcFileName,
+            [String("uifilename")] UiFileName,
+            [String("ui_hdr")] UiHeaderName,
+            [String("forward_declare_class")] ForwardDeclClass,
+            [String("multiple_inheritance")] MultipleInheritance,
+            [String("ui_classname")] UiClassName,
+            [String("member")] Member,
+        }
+
+        enum Meta
+        {
+            [String("namespace")] Namespace,
+            [String("namespacebegin")] NamespaceBegin,
+            [String("operator")] Operator,
+            [String("asterisk")] Asterisk,
+            [String("semicolon")] Semicolon,
+            [String("new")] New,
+            [String("delete")] Delete,
+            [String("namespaceend")] NamespaceEnd
+        }
+
+        protected override WizardData WizardData => Lazy.Get(() =>
+            WizardData, () => new WizardData
+            {
+                DefaultModules = new List<string> { "QtCore", "QtGui", "QtWidgets" }
+            });
+
+        protected override WizardWindow WizardWindow => Lazy.Get(() =>
+            WizardWindow, () => new WizardWindow(title: "Qt Widgets Application Wizard")
+            {
+                new WizardIntroPage
+                {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt Widgets Application Wizard",
+                    Message = @"This wizard generates a Qt Widgets application project. The "
+                        + @"application derives from QApplication and includes an empty "
+                        + @"widget." + System.Environment.NewLine
+                        + System.Environment.NewLine + "To continue, click Next.",
+                    PreviousButtonEnabled = false,
+                    NextButtonEnabled = true,
+                    FinishButtonEnabled = false,
+                    CancelButtonEnabled = true
+                },
+                new ConfigPage
+                {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt Widgets Application Wizard",
+                    Message =
+                            @"Setup the configurations you want to include in your project. "
+                            + @"The recommended settings for this project are selected by default.",
+                    PreviousButtonEnabled = true,
+                    NextButtonEnabled = true,
+                    FinishButtonEnabled = false,
+                    CancelButtonEnabled = true
+                },
+                new GuiPage
+                {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt Widgets Application Wizard",
+                    Message = @"This wizard generates a Qt Widgets application project. The "
+                        + @"application derives from QApplication and includes an empty "
+                        + @"widget.",
+                    PreviousButtonEnabled = true,
+                    NextButtonEnabled = false,
+                    FinishButtonEnabled = true,
+                    CancelButtonEnabled = true
+                }
+            });
+
+        readonly List<ItemDef> GuiExtraItems;
+        protected override IEnumerable<ItemDef> ExtraItems => GuiExtraItems;
+
+        public GuiWizard()
+        {
+            GuiExtraItems = new List<ItemDef>
+            {
+                new ItemDef
+                {
+                    ItemType = "AppxManifest",
+                    Include = "Package.appxmanifest",
+                    Filter = "Resource Files",
+                    WhereConfig = whereConfigTargetIsWindowsStore
+                },
+                new ItemDef
+                {
+                    ItemType = "Image",
+                    Include = "assets/logo_store.png",
+                    Filter = "Resource Files",
+                    WhereConfig = whereConfigTargetIsWindowsStore
+                },
+                new ItemDef
+                {
+                    ItemType = "Image",
+                    Include = "assets/logo_620x300.png",
+                    Filter = "Resource Files",
+                    WhereConfig = whereConfigTargetIsWindowsStore
+                },
+                new ItemDef
+                {
+                    ItemType = "Image",
+                    Include = "assets/logo_150x150.png",
+                    Filter = "Resource Files",
+                    WhereConfig = whereConfigTargetIsWindowsStore
+                },
+                new ItemDef
+                {
+                    ItemType = "Image",
+                    Include = "assets/logo_44x44.png",
+                    Filter = "Resource Files",
+                    WhereConfig = whereConfigTargetIsWindowsStore
+                },
+            };
+        }
+
+        protected override void BeforeWizardRun()
+        {
+            var className = Parameter[NewProject.SafeName];
+            className = Regex.Replace(className, @"[^a-zA-Z0-9_]", string.Empty);
+            className = Regex.Replace(className, @"^[\d-]*\s*", string.Empty);
+            var result = new Util.ClassNameValidationRule().Validate(className, null);
+            if (result != ValidationResult.ValidResult)
+                className = @"QtWidgetsApplication";
+
+            WizardData.ClassName = className;
+            WizardData.BaseClass = @"QMainWindow";
+            WizardData.ClassHeaderFile = className + @".h";
+            WizardData.ClassSourceFile = className + @".cpp";
+            WizardData.UiFile = WizardData.ClassName + @".ui";
+            WizardData.QrcFile = WizardData.ClassName + @".qrc";
+            WizardData.UiClassInclusion = UiClassInclusion.Member;
+
+            Parameter[NewGuiProject.ForwardDeclClass] = "";
+            Parameter[NewGuiProject.MultipleInheritance] = "";
+            Parameter[NewGuiProject.UiClassName] = "";
+            Parameter[NewGuiProject.Member] = "ui";
+
+            Parameter[Meta.Asterisk] ="";
+            Parameter[Meta.Operator] = ".";
+            Parameter[Meta.Semicolon] = ";";
+            Parameter[Meta.New] = "";
+            Parameter[Meta.Delete] = "";
+        }
+
+        protected override void BeforeTemplateExpansion()
+        {
+            var array = WizardData.ClassName.Split(new[] { "::" },
+                StringSplitOptions.RemoveEmptyEntries);
+            var className = array.LastOrDefault();
+
+            Parameter[NewClass.ClassName] = className;
+            Parameter[NewClass.BaseClass] = WizardData.BaseClass;
+            Parameter[NewClass.HeaderFileName] = WizardData.ClassHeaderFile;
+            Parameter[NewClass.SourceFileName] = WizardData.ClassSourceFile;
+            Parameter[NewGuiProject.UiFileName] = WizardData.UiFile;
+
+            var include = new StringBuilder();
+            if (UsePrecompiledHeaders)
+                include.AppendLine(string.Format("#include \"{0}\"", PrecompiledHeader.Include));
+            include.AppendLine(string.Format("#include \"{0}\"", WizardData.ClassHeaderFile));
+            Parameter[NewClass.Include] = FormatParam(include);
+
+            Parameter[NewGuiProject.UiHeaderName] = string.Format("ui_{0}.h",
+                Path.GetFileNameWithoutExtension(WizardData.UiFile));
+            Parameter[NewGuiProject.QrcFileName] = WizardData.QrcFile;
+
+            if (WizardData.BaseClass == "QMainWindow") {
+                Parameter[NewGuiProject.CentralWidget] = FormatParam(@"
+  <widget class=""QMenuBar"" name=""menuBar"" />
+  <widget class=""QToolBar"" name=""mainToolBar"" />
+  <widget class=""QWidget"" name=""centralWidget"" />
+  <widget class=""QStatusBar"" name=""statusBar"" />");
+            }
+
+            StringBuilder winRcFile = new StringBuilder();
+
+            if (WizardData.AddDefaultAppIcon) {
+                var projectIcon = Path.Combine(
+                    Parameter[NewProject.DestinationDirectory],
+                    Parameter[NewProject.SafeName] + ".ico");
+                var iconExists = File.Exists(projectIcon);
+                if (!iconExists) {
+                    try {
+                        var uri =
+                            new Uri(System.Reflection.Assembly.GetExecutingAssembly().EscapedCodeBase);
+                        var pkgInstallPath
+                            = Path.GetDirectoryName(Uri.UnescapeDataString(uri.AbsolutePath)) + @"\";
+                        var templateIcon
+                            = Path.Combine(pkgInstallPath, @"ProjectTemplates\VC\Qt\1033\gui\gui.ico");
+                        File.Copy(templateIcon, projectIcon);
+                        File.SetAttributes(projectIcon,
+                            File.GetAttributes(projectIcon) & (~FileAttributes.ReadOnly));
+                        iconExists = true;
+                    }  catch (Exception /*ex*/) {
+                        // Silently ignore any error, the project is working
+                        // without icon too.
+                    }
+                }
+
+                if (iconExists) {
+                    GuiExtraItems.Add(new ItemDef
+                    {
+                        ItemType = "None",
+                        Include = Parameter[NewProject.SafeName] + ".ico",
+                        Filter = "Resource Files"
+                    });
+                    winRcFile.AppendLine(
+                        string.Format("IDI_ICON1\t\tICON\t\tDISCARDABLE\t\"{0}.ico\"",
+                            /*{0}*/ Parameter[NewProject.SafeName]));
+                }
+            }
+
+            if (winRcFile.Length > 0) {
+                GuiExtraItems.Add(new ItemDef
+                {
+                    ItemType = "ResourceCompile",
+                    Include = Parameter[NewProject.SafeName] + ".rc",
+                    Filter = "Resource Files"
+                });
+                File.WriteAllText(
+                    Path.Combine(
+                        Parameter[NewProject.DestinationDirectory],
+                        Parameter[NewProject.SafeName] + ".rc"),
+                    winRcFile.ToString());
+            }
+
+            switch (WizardData.UiClassInclusion) {
+            case UiClassInclusion.MemberPointer:
+                Parameter[NewGuiProject.ForwardDeclClass] =
+                    string.Format(
+                          "\r\nQT_BEGIN_NAMESPACE\r\n"
+                        + "namespace Ui {{ class {0}Class; }};\r\n"
+                        + "QT_END_NAMESPACE\r\n", className
+                    );
+                Parameter[Meta.Asterisk] = "*";
+                Parameter[Meta.Operator] = "->";
+                Parameter[Meta.New] = string.Format("\r\n    , {0}(new Ui::{1}Class())",
+                                                    Parameter[NewGuiProject.Member], className);
+                Parameter[Meta.Delete] = string.Format("\r\n    delete {0};\r\n",
+                                                       Parameter[NewGuiProject.Member]);
+                goto case UiClassInclusion.Member;
+            case UiClassInclusion.Member:
+                Parameter[NewGuiProject.UiClassName] = string.Format("Ui::{0}Class", className);
+                break;
+            case UiClassInclusion.MultipleInheritance:
+                Parameter[NewGuiProject.MultipleInheritance] =
+                    string.Format(", public Ui::{0}Class", className);
+                Parameter[NewGuiProject.Member] = "";
+                Parameter[Meta.Operator] = "";
+                Parameter[Meta.Semicolon] = "";
+                break;
+            }
+
+            string ns = "",  nsBegin = "", nsEnd = "";
+            for (var i = 0; i < array.Length - 1; ++i) {
+                ns += array[i] + "::";
+                nsBegin += "namespace " + array[i] + " {\r\n";
+                nsEnd = "} // namespace " + array[i] + "\r\n" + nsEnd;
+            }
+            Parameter[Meta.Namespace] = ns;
+            Parameter[Meta.NamespaceBegin] = nsBegin;
+            Parameter[Meta.NamespaceEnd] = nsEnd;
+        }
+
+        protected override void OnProjectGenerated(Project project)
+        {
+            IWizardConfiguration configWinRT = Configurations
+                .Where(whereConfigTargetIsWindowsStore)
+                .FirstOrDefault();
+
+            if (configWinRT != null) {
+                var projDir = Parameter[NewProject.DestinationDirectory];
+                var qmakeTmpDir = Path.Combine(projDir, "qmake_tmp");
+                Directory.CreateDirectory(qmakeTmpDir);
+
+                var dummyPro = Path.Combine(qmakeTmpDir,
+                    string.Format("{0}.pro", Parameter[NewProject.SafeName]));
+                File.WriteAllText(dummyPro, "SOURCES = main.cpp\r\n");
+
+                var qmake = new QMakeImport(configWinRT.QtVersion, dummyPro);
+                qmake.Run(setVCVars: true);
+
+                var qmakeAssetsDir = Path.Combine(qmakeTmpDir, "assets");
+                var projAssetsDir = Path.Combine(projDir, "assets");
+                if (Directory.Exists(qmakeAssetsDir)) {
+                    if (Directory.Exists(projAssetsDir))
+                        Directory.Delete(projAssetsDir, recursive: true);
+                    Directory.Move(qmakeAssetsDir, projAssetsDir);
+                }
+
+                var manifestFile = Path.Combine(qmakeTmpDir, "Package.appxmanifest");
+                if (File.Exists(manifestFile)) {
+                    File.Move(manifestFile, Path.Combine(projDir, "Package.appxmanifest"));
+                }
+
+                Directory.Delete(qmakeTmpDir, recursive: true);
+            }
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/ProjectWizard/Library/LibraryClassPage.xaml b/QtVsTools.Wizards/ProjectWizard/Library/LibraryClassPage.xaml
new file mode 100644
index 0000000..aebfe6f
--- /dev/null
+++ b/QtVsTools.Wizards/ProjectWizard/Library/LibraryClassPage.xaml
@@ -0,0 +1,238 @@
+<!--
+    *****************************************************************************
+    **
+    ** Copyright (C) 2016 The Qt Company Ltd.
+    ** Contact: https://www.qt.io/licensing/
+    **
+    ** This file is part of the Qt VS Tools.
+    **
+    ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+    ** Commercial License Usage
+    ** Licensees holding valid commercial Qt licenses may use this file in
+    ** accordance with the commercial license agreement provided with the
+    ** Software or, alternatively, in accordance with the terms contained in
+    ** a written agreement between you and The Qt Company. For licensing terms
+    ** and conditions see https://www.qt.io/terms-conditions. For further
+    ** information use the contact form at https://www.qt.io/contact-us.
+    **
+    ** GNU General Public License Usage
+    ** Alternatively, this file may be used under the terms of the GNU
+    ** General Public License version 3 as published by the Free Software
+    ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+    ** included in the packaging of this file. Please review the following
+    ** information to ensure the GNU General Public License requirements will
+    ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+    **
+    ** $QT_END_LICENSE$
+    **
+    *****************************************************************************
+-->
+
+<common:WizardPage x:Class="QtVsTools.Wizards.ProjectWizard.LibraryClassPage"
+                  xmlns:common="clr-namespace:QtVsTools.Wizards.Common"
+                  xmlns:util="clr-namespace:QtVsTools.Wizards.Util"
+                  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+                  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+                  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+                  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+                  KeepAlive="True"
+                  mc:Ignorable="d"
+                  d:DesignHeight="445"
+                  d:DesignWidth="585">
+    <Grid>
+        <Grid.ColumnDefinitions>
+            <ColumnDefinition Width="100" />
+            <ColumnDefinition Width="*" />
+        </Grid.ColumnDefinitions>
+        <Image Grid.Column="0"
+               HorizontalAlignment="Center"
+               Source="/QtVsTools.Wizards;component/Resources/Qt-logo-small.png"
+               VerticalAlignment="Top"
+               Margin="0,25,0,0"
+               RenderTransformOrigin="1,0">
+            <Image.RenderTransform>
+                <TransformGroup>
+                    <ScaleTransform ScaleY="0.86"
+                                    ScaleX="0.86" />
+                </TransformGroup>
+            </Image.RenderTransform>
+        </Image>
+        <Grid Grid.Column="1"
+              Margin="25,25,10,0">
+            <Grid.RowDefinitions>
+                <RowDefinition Height="Auto" />
+                <RowDefinition Height="*" />
+                <RowDefinition Height="Auto" />
+            </Grid.RowDefinitions>
+            <TextBlock TextWrapping="Wrap"
+                       Grid.Row="0">
+                <Run FontWeight="Bold"
+                     Text="{Binding Path=Header}" />
+                <LineBreak />
+                <LineBreak />
+                <Run Text="{Binding Path=Message}" />
+                <LineBreak />
+            </TextBlock>
+            <Grid Grid.Row="1">
+                <Grid.RowDefinitions>
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                </Grid.RowDefinitions>
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="*" />
+                    <ColumnDefinition Width="*" />
+                </Grid.ColumnDefinitions>
+                <Grid.Resources>
+                    <Style TargetType="TextBox">
+                        <Style.Triggers>
+                            <Trigger Property="Validation.HasError"
+                                     Value="true">
+                                <Setter Property="ToolTip"
+                                        Value="{Binding RelativeSource={RelativeSource Self},
+                                         Path=(Validation.Errors)[0].ErrorContent}" />
+                            </Trigger>
+                        </Style.Triggers>
+                    </Style>
+                </Grid.Resources>
+                <TextBlock Grid.Row="0"
+                           Text="Class Name:"
+                           Margin="0,0,10,0" />
+                <TextBox Grid.Row="1"
+                         Margin="0,0,10,30"
+                         Name="ClassName"
+                         TextChanged="OnClassNameChanged"
+                         TabIndex="0">
+                    <TextBox.Text>
+                        <Binding Path="Data.ClassName"
+                                 NotifyOnValidationError="True"
+                                 UpdateSourceTrigger="PropertyChanged">
+                            <Binding.ValidationRules>
+                                <util:ClassNameValidationRule />
+                            </Binding.ValidationRules>
+                        </Binding>
+                    </TextBox.Text>
+                </TextBox>
+                <Grid Grid.Row="2"
+                      Grid.ColumnSpan="2">
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="Auto" />
+                        <RowDefinition Height="Auto" />
+                    </Grid.RowDefinitions>
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition Width="*" />
+                        <ColumnDefinition Width="*" />
+                    </Grid.ColumnDefinitions>
+                    <TextBlock Grid.Row="0"
+                               Margin="0,0,10,5"
+                               Text="Header (.h) file:" />
+                    <TextBox Grid.Row="1"
+                             Margin="0,0,10,0"
+                             Name="ClassHeaderFile"
+                             TabIndex="1">
+                        <TextBox.Text>
+                            <Binding Path="Data.ClassHeaderFile"
+                                     NotifyOnValidationError="True"
+                                     UpdateSourceTrigger="PropertyChanged">
+                                <Binding.ValidationRules>
+                                    <util:FileNameValidationRule FileExt=".h" />
+                                </Binding.ValidationRules>
+                            </Binding>
+                        </TextBox.Text>
+                    </TextBox>
+                    <TextBlock Grid.Row="0"
+                               Grid.Column="1"
+                               Margin="0,0,0,5"
+                               Text="Source (.cpp) file:" />
+                    <TextBox Grid.Row="1"
+                             Grid.Column="1"
+                             Margin="0,0,0,00"
+                             Name="ClassSourceFile"
+                             TabIndex="2">
+                        <TextBox.Text>
+                            <Binding Path="Data.ClassSourceFile"
+                                     NotifyOnValidationError="True"
+                                     UpdateSourceTrigger="PropertyChanged">
+                                <Binding.ValidationRules>
+                                    <util:FileNameValidationRule FileExt=".cpp" />
+                                </Binding.ValidationRules>
+                            </Binding>
+                        </TextBox.Text>
+                    </TextBox>
+                </Grid>
+                <CheckBox Grid.Row="3"
+                          Content="Lower case file names"
+                          Name="LowerCaseFileNames"
+                          Click="OnLowerCaseFileNamesClick"
+                          Margin="0,20,10,5"
+                          TabIndex="3" />
+                <CheckBox Grid.Row="4"
+                          Content="Precompiled header"
+                          IsChecked="{Binding Path=Data.UsePrecompiledHeader}"
+                          Margin="0,10,10,5"
+                          TabIndex="4" />
+                <CheckBox Grid.Row="5"
+                          Content="Create Static Library (.lib)"
+                          IsChecked="{Binding Path=Data.CreateStaticLibrary}"
+                          Margin="0,0,10,0"
+                          TabIndex="5" />
+            </Grid>
+            <StackPanel HorizontalAlignment="Right"
+                        Orientation="Horizontal"
+                        Grid.Row="2"
+                        Margin="0,0,0,10">
+                <Button Click="OnPreviousButtonClick"
+                        Name="PreviousButton"
+                        IsEnabled="{Binding Path=PreviousButtonEnabled}"
+                        MinWidth="75">&lt; _Previous</Button>
+                <Button MinWidth="75"
+                        Name="NextButton"
+                        Click="OnNextButtonClick"
+                        IsEnabled="{Binding Path=NextButtonEnabled}"
+                        Margin="10,0,0,0">_Next &gt;</Button>
+                <Button MinWidth="75"
+                        Click="OnFinishButtonClick"
+                        Margin="10,0,0,0"
+                        IsDefault="True"
+                        Name="FinishButton"
+                        Content="_Finish"
+                        VerticalAlignment="Bottom">
+                    <Button.Style>
+                        <Style TargetType="Button">
+                            <Setter Property="IsEnabled"
+                                    Value="false" />
+                            <Style.Triggers>
+                                <MultiDataTrigger>
+                                    <MultiDataTrigger.Conditions>
+                                        <Condition Binding="{Binding Path=FinishButtonEnabled}"
+                                                   Value="true" />
+                                        <Condition Binding="{Binding ElementName=ClassName,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                        <Condition Binding="{Binding ElementName=ClassHeaderFile,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                        <Condition Binding="{Binding ElementName=ClassSourceFile,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                    </MultiDataTrigger.Conditions>
+                                    <Setter Property="IsEnabled"
+                                            Value="true" />
+                                </MultiDataTrigger>
+                            </Style.Triggers>
+                        </Style>
+                    </Button.Style>
+                </Button>
+                <Button Click="OnCancelButtonClick"
+                        MinWidth="75"
+                        Margin="10,0,0,0"
+                        Name="CancelButton"
+                        IsEnabled="{Binding Path=CancelButtonEnabled}"
+                        IsCancel="True">_Cancel</Button>
+            </StackPanel>
+        </Grid>
+    </Grid>
+</common:WizardPage>
diff --git a/QtVsTools.Wizards/ProjectWizard/Library/LibraryClassPage.xaml.cs b/QtVsTools.Wizards/ProjectWizard/Library/LibraryClassPage.xaml.cs
new file mode 100644
index 0000000..93f8fd0
--- /dev/null
+++ b/QtVsTools.Wizards/ProjectWizard/Library/LibraryClassPage.xaml.cs
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Windows;
+using System.Windows.Controls;
+
+namespace QtVsTools.Wizards.ProjectWizard
+{
+    using Wizards.Common;
+
+    public partial class LibraryClassPage : WizardPage
+    {
+        public LibraryClassPage()
+        {
+            InitializeComponent();
+            DataContext = this;
+        }
+
+        private void OnClassNameChanged(object sender, TextChangedEventArgs e)
+        {
+            UpdateFileNames();
+        }
+
+        private void OnLowerCaseFileNamesClick(object sender, RoutedEventArgs e)
+        {
+            UpdateFileNames();
+        }
+
+        private void UpdateFileNames()
+        {
+            var filename = ClassName.Text;
+            if (LowerCaseFileNames.IsChecked.GetValueOrDefault())
+                filename = filename.ToLower();
+
+            ClassHeaderFile.Text = filename + @".h";
+            ClassSourceFile.Text = filename + @".cpp";
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/ProjectWizard/Library/LibraryWizard.cs b/QtVsTools.Wizards/ProjectWizard/Library/LibraryWizard.cs
new file mode 100644
index 0000000..0968343
--- /dev/null
+++ b/QtVsTools.Wizards/ProjectWizard/Library/LibraryWizard.cs
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Windows.Controls;
+
+namespace QtVsTools.Wizards.ProjectWizard
+{
+    using QtVsTools.Common;
+    using Wizards.Common;
+
+    using static QtVsTools.Common.EnumExt;
+
+    public class LibraryWizard : ProjectTemplateWizard
+    {
+        LazyFactory Lazy { get; } = new LazyFactory();
+
+        protected override Options TemplateType => Options.GUISystem
+            | (WizardData.CreateStaticLibrary ? Options.StaticLibrary : Options.DynamicLibrary);
+
+        enum NewLibClass
+        {
+            [String("classname")] ClassName,
+            [String("sourcefilename")] SourceFileName,
+            [String("headerfilename")] HeaderFileName,
+            [String("include")] Include,
+            [String("saveglobal")] GlobalHeader,
+            [String("pro_lib_define")] LibDefine,
+            [String("pro_lib_export")] LibExport,
+        }
+
+        protected override WizardData WizardData => Lazy.Get(() =>
+            WizardData, () => new WizardData
+            {
+                DefaultModules = new List<string> { "QtCore" }
+            });
+
+        readonly List<string> LibExtraDefines = new List<string>();
+        protected override IEnumerable<string> ExtraDefines => LibExtraDefines;
+
+        protected override WizardWindow WizardWindow => Lazy.Get(() =>
+            WizardWindow, () => new WizardWindow(title: "Qt Class Library Wizard")
+            {
+                new WizardIntroPage {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt Class Library Wizard",
+                    Message = @"This wizard generates a Qt Class Library project. The "
+                        + @"resulting library is linked dynamically with Qt."
+                        + System.Environment.NewLine + System.Environment.NewLine
+                        + @"To continue, click Next.",
+                    PreviousButtonEnabled = false,
+                    NextButtonEnabled = true,
+                    FinishButtonEnabled = false,
+                    CancelButtonEnabled = true
+                },
+                new ConfigPage {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt Class Library Wizard",
+                    Message =
+                            @"Setup the configurations you want to include in your project. "
+                            + @"The recommended settings for this project are selected by default.",
+                    PreviousButtonEnabled = true,
+                    NextButtonEnabled = true,
+                    FinishButtonEnabled = false,
+                    CancelButtonEnabled = true
+                },
+                new LibraryClassPage {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt Class Library Wizard",
+                    Message = @"This wizard generates a Qt Class Library project. The "
+                        + @"resulting library is linked dynamically with Qt.",
+                    PreviousButtonEnabled = true,
+                    NextButtonEnabled = false,
+                    FinishButtonEnabled = true,
+                    CancelButtonEnabled = true
+                }
+            });
+
+        protected override void BeforeWizardRun()
+        {
+            var safeprojectname = Parameter[NewProject.SafeName];
+            safeprojectname = Regex.Replace(safeprojectname, @"[^a-zA-Z0-9_]", string.Empty);
+            safeprojectname = Regex.Replace(safeprojectname, @"^[\d-]*\s*", string.Empty);
+            var result = new Util.ClassNameValidationRule().Validate(safeprojectname, null);
+            if (result != ValidationResult.ValidResult)
+                safeprojectname = @"QtClassLibrary";
+
+            WizardData.ClassName = safeprojectname;
+            WizardData.ClassHeaderFile = safeprojectname + @".h";
+            WizardData.ClassSourceFile = safeprojectname + @".cpp";
+        }
+
+        protected override void BeforeTemplateExpansion()
+        {
+            Parameter[NewLibClass.ClassName] = WizardData.ClassName;
+            Parameter[NewLibClass.HeaderFileName] = WizardData.ClassHeaderFile;
+            Parameter[NewLibClass.SourceFileName] = WizardData.ClassSourceFile;
+
+            var include = new StringBuilder();
+            if (UsePrecompiledHeaders)
+                include.AppendLine(string.Format("#include \"{0}\"", PrecompiledHeader.Include));
+            include.AppendLine(string.Format("#include \"{0}\"", WizardData.ClassHeaderFile));
+            Parameter[NewLibClass.Include] = FormatParam(include);
+
+            var safeprojectname = Parameter[NewProject.SafeName];
+            Parameter[NewLibClass.GlobalHeader] = safeprojectname.ToLower();
+            Parameter[NewLibClass.LibDefine] = safeprojectname.ToUpper() + "_LIB";
+            Parameter[NewLibClass.LibExport] = safeprojectname.ToUpper() + "_EXPORT";
+
+            LibExtraDefines.Add(Parameter[NewLibClass.LibDefine]);
+            if (WizardData.CreateStaticLibrary)
+                LibExtraDefines.Add("BUILD_STATIC");
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/ProjectWizard/ProjectTemplateWizard.cs b/QtVsTools.Wizards/ProjectWizard/ProjectTemplateWizard.cs
new file mode 100644
index 0000000..9ae6ae8
--- /dev/null
+++ b/QtVsTools.Wizards/ProjectWizard/ProjectTemplateWizard.cs
@@ -0,0 +1,722 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using Microsoft.Internal.VisualStudio.PlatformUI;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.TemplateWizard;
+using EnvDTE;
+
+
+namespace QtVsTools.Wizards.ProjectWizard
+{
+    using QtVsTools.Common;
+    using Core;
+    using Core.QtMsBuild;
+    using VisualStudio;
+    using Wizards.Common;
+
+    using WhereConfig = Func<IWizardConfiguration, bool>;
+
+    using static QtVsTools.Common.EnumExt;
+
+    public interface IWizardConfiguration
+    {
+        string Name { get; }
+        VersionInformation QtVersion { get; }
+        string QtVersionName { get; }
+        string QtVersionPath { get; }
+        string Target { get; }
+        string Platform { get; }
+        bool IsDebug { get; }
+        IEnumerable<string> Modules { get; }
+    }
+
+    public enum ProjectTargets
+    {
+        Windows,
+        [String("Windows Store")] WindowsStore,
+        [String("Linux (SSH)")] LinuxSSH,
+        [String("Linux (WSL)")] LinuxWSL
+    }
+
+    public enum ProjectPlatforms
+    {
+        [String("x64")] X64,
+        Win32,
+        ARM64,
+        ARM,
+    }
+
+    public abstract class ProjectTemplateWizard : IWizard
+    {
+        LazyFactory Lazy { get; } = new LazyFactory();
+
+        private readonly WhereConfig WhereConfig_SelectAll = (x => true);
+
+        protected struct ItemProperty
+        {
+            public string Key { get; }
+            public string Value { get; }
+            public WhereConfig WhereConfig { get; }
+
+            public ItemProperty(string key, string value, WhereConfig whereConfig = null)
+            {
+                Key = key;
+                Value = value;
+                WhereConfig = whereConfig;
+            }
+
+            public static implicit operator ItemProperty[](ItemProperty that)
+            {
+                return new[] { that };
+            }
+        }
+
+        protected class ItemGlobalDef
+        {
+            public string ItemType { get; set; }
+            public ItemProperty[] Properties { get; set; }
+        }
+
+        protected class ItemDef
+        {
+            public string ItemType { get; set; }
+            public string Include { get; set; }
+            public ItemProperty[] Properties { get; set; }
+            public string Filter { get; set; }
+            public WhereConfig WhereConfig { get; set; }
+        }
+
+        [Flags]
+        protected enum Options : uint
+        {
+            Application = 0x000,
+            DynamicLibrary = 0x001,
+            StaticLibrary = 0x002,
+            GUISystem = 0x004,
+            ConsoleSystem = 0x008,
+            PluginProject = 0x100
+        }
+
+        protected abstract Options TemplateType { get; }
+        protected abstract WizardData WizardData { get; }
+        protected abstract WizardWindow WizardWindow { get; }
+
+        protected virtual IDictionary<string, ItemGlobalDef> ItemGlobals => null;
+        protected virtual IEnumerable<ItemDef> ExtraItems => Enumerable.Empty<ItemDef>();
+        protected virtual IEnumerable<string> ExtraModules => Enumerable.Empty<string>();
+        protected virtual IEnumerable<string> ExtraDefines => Enumerable.Empty<string>();
+
+        protected virtual IEnumerable<IWizardConfiguration> Configurations => WizardData.Configs;
+        protected virtual bool UsePrecompiledHeaders => WizardData.UsePrecompiledHeader;
+
+        private Dictionary<string, string> ParameterValues { get; set; }
+        protected EnvDTE.DTE Dte { get; private set; }
+
+        protected virtual ItemDef PrecompiledHeader => Lazy.Get(() =>
+            PrecompiledHeader, () => new ItemDef
+            {
+                ItemType = "ClInclude",
+                Include = "stdafx.h",
+                Filter = "Header Files"
+            });
+
+        protected virtual ItemDef PrecompiledHeaderSource => Lazy.Get(() =>
+            PrecompiledHeaderSource, () => new ItemDef
+            {
+                ItemType = "ClCompile",
+                Include = "stdafx.cpp",
+                Properties = new ItemProperty("PrecompiledHeader", "Create"),
+                Filter = "Source Files",
+            });
+
+        protected class TemplateParameters
+        {
+            public ProjectTemplateWizard Template { get; set; }
+
+            string ParamKey(Enum param)
+            {
+                return string.Format("${0}$", param.Cast<string>());
+            }
+
+            public string this[Enum param]
+            {
+                get => Template.ParameterValues[ParamKey(param)];
+                set => Template.ParameterValues[ParamKey(param)] = value;
+            }
+        }
+
+        protected enum NewProject
+        {
+            // Read-only parameters
+            [String("projectname")] Name,
+            [String("safeprojectname")] SafeName,
+            [String("destinationdirectory")] DestinationDirectory,
+            [String("solutiondirectory")] SolutionDirectory,
+
+            // Custom parameters
+            ToolsVersion,
+            ProjectConfigurations,
+            Properties,
+            ProjectGuid,
+            Keyword,
+            Globals,
+            Configurations,
+            PropertySheets,
+            QtSettings,
+            BuildSettings,
+            ProjectItems,
+            FilterItems,
+        }
+
+        protected TemplateParameters Parameter => Lazy.Get(() =>
+            Parameter, () => new TemplateParameters { Template = this });
+
+        protected QtVersionManager VersionManager => QtVersionManager.The();
+
+        public virtual void ProjectItemFinishedGenerating(ProjectItem projectItem) { }
+        public virtual void BeforeOpeningFile(ProjectItem projectItem) { }
+        public virtual void RunFinished() { }
+        public virtual bool ShouldAddProjectItem(string filePath) => true;
+
+        protected virtual void BeforeWizardRun() { }
+        protected virtual void BeforeTemplateExpansion() { }
+        protected virtual void OnProjectGenerated(Project project) { }
+
+        public virtual void RunStarted(
+            object automationObject,
+            Dictionary<string, string> parameterValues,
+            WizardRunKind runKind,
+            object[] customParams)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            Dte = automationObject as DTE;
+            ParameterValues = parameterValues;
+
+            Debug.Assert(WizardWindow != null);
+
+            BeforeWizardRun();
+
+            var iVsUIShell = VsServiceProvider.GetService<SVsUIShell, IVsUIShell>();
+            if (iVsUIShell == null)
+                throw new NullReferenceException("IVsUIShell");
+
+            try {
+                iVsUIShell.EnableModeless(0);
+                iVsUIShell.GetDialogOwnerHwnd(out IntPtr hwnd);
+                WindowHelper.ShowModal(WizardWindow, hwnd);
+            } catch (QtVSException exception) {
+                exception.Log(false, true);
+                throw;
+            } finally {
+                iVsUIShell.EnableModeless(1);
+            }
+            if (!WizardWindow.DialogResult ?? false) {
+                try {
+                    Directory.Delete(Parameter[NewProject.DestinationDirectory]);
+                    Directory.Delete(Parameter[NewProject.SolutionDirectory]);
+                } catch { }
+                throw new WizardBackoutException();
+            }
+
+            BeforeTemplateExpansion();
+            Expand();
+        }
+
+        public virtual void ProjectFinishedGenerating(Project project)
+        {
+            OnProjectGenerated(project);
+        }
+
+        protected static bool IsLinux(IWizardConfiguration wizConfig)
+        {
+            return wizConfig.Target.EqualTo(ProjectTargets.LinuxSSH)
+                || wizConfig.Target.EqualTo(ProjectTargets.LinuxWSL);
+        }
+
+        protected static string GetLinuxCompilerPath(IWizardConfiguration wizConfig)
+        {
+            if (!IsLinux(wizConfig))
+                return string.Empty;
+            if (string.IsNullOrEmpty(wizConfig.QtVersionPath))
+                return string.Empty;
+            string[] linuxPaths = wizConfig.QtVersionPath.Split(':');
+            if (linuxPaths == null || linuxPaths.Length <= 2)
+                return string.Empty;
+            return linuxPaths[2];
+        }
+
+        protected virtual void Expand()
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            Debug.Assert(ParameterValues != null);
+            Debug.Assert(Dte != null);
+            Debug.Assert(Configurations != null);
+            Debug.Assert(ExtraItems != null);
+
+            StringBuilder xml;
+
+            ///////////////////////////////////////////////////////////////////////////////////////
+            // Tools version = VS version
+            //
+            Parameter[NewProject.ToolsVersion] = Dte.Version;
+
+            ///////////////////////////////////////////////////////////////////////////////////////
+            // Configurations
+            //
+            xml = new StringBuilder();
+            foreach (IWizardConfiguration c in Configurations) {
+                xml.AppendLine(string.Format(@"
+    <ProjectConfiguration Include=""{0}|{1}"">
+      <Configuration>{0}</Configuration>
+      <Platform>{1}</Platform>
+    </ProjectConfiguration>",
+                    /*{0}*/ c.Name,
+                    /*{1}*/ c.Platform));
+            }
+            Parameter[NewProject.ProjectConfigurations] = FormatParam(xml);
+
+            ///////////////////////////////////////////////////////////////////////////////////////
+            // Properties
+            //
+            xml = new StringBuilder();
+            foreach (IWizardConfiguration c in Configurations) {
+                xml.AppendLine(string.Format(@"
+  <PropertyGroup Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">",
+                    /*{0}*/ c.Name,
+                    /*{1}*/ c.Platform));
+                if (IsLinux(c)) {
+                    var compilerPath = GetLinuxCompilerPath(c);
+                    if (!string.IsNullOrEmpty(compilerPath))
+                        xml.AppendLine(string.Format(@"
+      <RemoteCCompileToolExe>{0}</RemoteCCompileToolExe>
+      <RemoteCppCompileToolExe>{0}</RemoteCppCompileToolExe>
+      <RemoteLdToolExe>{0}</RemoteLdToolExe>",
+                            /*{0}*/ compilerPath));
+                }
+                xml.AppendLine(@"
+  </PropertyGroup>");
+            }
+            Parameter[NewProject.Properties] = FormatParam(xml);
+
+            ///////////////////////////////////////////////////////////////////////////////////////
+            // Globals
+            //
+            xml = new StringBuilder();
+            Parameter[NewProject.ProjectGuid] = HelperFunctions.NewProjectGuid();
+            Parameter[NewProject.Keyword] = Resources.QtVSVersionTag;
+
+            ///////////////////////////////////////////////////////////////////////////////////////
+            // Globals: Windows
+            //
+            foreach (IWizardConfiguration c in Configurations
+                .Where(c => c.Target.EqualTo(ProjectTargets.Windows))) {
+                if (!string.IsNullOrEmpty(c.QtVersion.VC_WindowsTargetPlatformVersion)) {
+                    xml.AppendLine(string.Format(@"
+    <WindowsTargetPlatformVersion Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">{2}</WindowsTargetPlatformVersion>",
+                        /*{0}*/ c.Name,
+                        /*{1}*/ c.Platform,
+                        /*{2}*/ c.QtVersion.VC_WindowsTargetPlatformVersion));
+                }
+            }
+
+            ///////////////////////////////////////////////////////////////////////////////////////
+            // Globals: Windows Store
+            //
+            foreach (IWizardConfiguration c in Configurations
+                .Where(c => c.Target.EqualTo(ProjectTargets.WindowsStore))) {
+                xml.AppendLine(string.Format(@"
+    <ApplicationType Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">Windows Store</ApplicationType>
+    <WindowsTargetPlatformVersion Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">{2}</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformMinVersion Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">{3}</WindowsTargetPlatformMinVersion>
+    <MinimumVisualStudioVersion Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">{4}</MinimumVisualStudioVersion>
+    <ApplicationTypeRevision Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">{5}</ApplicationTypeRevision>
+    <DefaultLanguage Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">en</DefaultLanguage>
+    <AppContainerApplication Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">true</AppContainerApplication>",
+                    /*{0}*/ c.Name,
+                    /*{1}*/ c.Platform,
+                    /*{2}*/ c.QtVersion.VC_WindowsTargetPlatformVersion,
+                    /*{3}*/ c.QtVersion.VC_WindowsTargetPlatformMinVersion,
+                    /*{4}*/ c.QtVersion.VC_MinimumVisualStudioVersion,
+                    /*{5}*/ c.QtVersion.VC_ApplicationTypeRevision));
+            }
+
+            ///////////////////////////////////////////////////////////////////////////////////////
+            // Globals: Linux
+            //
+            foreach (IWizardConfiguration c in Configurations.Where(c => IsLinux(c))) {
+                xml.AppendLine(string.Format(@"
+    <ApplicationType Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">Linux</ApplicationType>
+    <ApplicationTypeRevision Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">1.0</ApplicationTypeRevision>
+    <TargetLinuxPlatform Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">Generic</TargetLinuxPlatform>
+    <LinuxProjectType Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">{{D51BCBC9-82E9-4017-911E-C93873C4EA2B}}</LinuxProjectType>",
+                    /*{0}*/ c.Name,
+                    /*{1}*/ c.Platform));
+            }
+
+            Parameter[NewProject.Globals] = FormatParam(xml);
+
+            ///////////////////////////////////////////////////////////////////////////////////////
+            // VC Configurations
+            //
+            xml = new StringBuilder();
+            foreach (IWizardConfiguration c in Configurations) {
+                if (!c.Target.TryCast(out ProjectTargets target))
+                    continue;
+                xml.AppendLine(string.Format(@"
+  <PropertyGroup Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"" Label=""Configuration"">",
+                    /*{0}*/ c.Name,
+                    /*{1}*/ c.Platform));
+                if (TemplateType.HasFlag(Options.DynamicLibrary)) {
+                    xml.AppendLine(@"
+    <ConfigurationType>DynamicLibrary</ConfigurationType>");
+                } else if (TemplateType.HasFlag(Options.StaticLibrary)) {
+                    xml.AppendLine(@"
+    <ConfigurationType>StaticLibrary</ConfigurationType>");
+                } else {
+                    xml.AppendLine(@"
+    <ConfigurationType>Application</ConfigurationType>");
+                }
+                switch (target) {
+                case ProjectTargets.Windows:
+                case ProjectTargets.WindowsStore:
+                    xml.AppendLine(string.Format(@"
+    <PlatformToolset>v{0}</PlatformToolset>",
+                        /*{0}*/ BuildConfig.PlatformToolset));
+                    break;
+                case ProjectTargets.LinuxSSH:
+                    xml.AppendLine(@"
+    <PlatformToolset>Remote_GCC_1_0</PlatformToolset>");
+                    break;
+                case ProjectTargets.LinuxWSL:
+                    xml.AppendLine(@"
+    <PlatformToolset>WSL_1_0</PlatformToolset>");
+                    break;
+                }
+                if (IsLinux(c)) {
+                    xml.AppendLine(string.Format(@"
+    <UseDebugLibraries>{0}</UseDebugLibraries>",
+                        /*{0}*/ c.IsDebug ? "true" : "false"));
+                } else if (target == ProjectTargets.WindowsStore) {
+                    xml.AppendLine(@"
+    <GenerateManifest>false</GenerateManifest>
+    <EmbedManifest>false</EmbedManifest>");
+                }
+                xml.AppendLine(@"
+  </PropertyGroup>");
+            }
+            Parameter[NewProject.Configurations] = FormatParam(xml);
+
+            ///////////////////////////////////////////////////////////////////////////////////////
+            // Property sheets
+            //
+            xml = new StringBuilder();
+            foreach (IWizardConfiguration c in Configurations) {
+                xml.AppendLine(string.Format(@"
+  <ImportGroup Label=""PropertySheets"" Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">
+    <Import Project=""$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"" Condition=""exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')"" Label=""LocalAppDataPlatform"" />
+    <Import Project=""$(QtMsBuild)\Qt.props"" />
+  </ImportGroup>",
+                    /*{0}*/ c.Name,
+                    /*{1}*/ c.Platform));
+            }
+            Parameter[NewProject.PropertySheets] = FormatParam(xml);
+
+            ///////////////////////////////////////////////////////////////////////////////////////
+            // Qt settings
+            //
+            xml = new StringBuilder();
+            foreach (IWizardConfiguration c in Configurations) {
+                xml.AppendLine(string.Format(@"
+  <PropertyGroup Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"" Label=""QtSettings"">
+    <QtInstall>{2}</QtInstall>
+    <QtModules>{3}</QtModules>
+    <QtBuildConfig>{4}</QtBuildConfig>",
+                    /*{0}*/ c.Name,
+                    /*{1}*/ c.Platform,
+                    /*{2}*/ c.QtVersionName,
+                    /*{3}*/ string.Join(";", c.Modules.Union(ExtraModules)),
+                    /*{4}*/ c.IsDebug ? "debug" : "release"));
+                if (c.Target.EqualTo(ProjectTargets.WindowsStore)) {
+                    xml.AppendLine(@"
+    <QtDeploy>true</QtDeploy>
+    <QtDeployToProjectDir>true</QtDeployToProjectDir>
+    <QtDeployVsContent>true</QtDeployVsContent>");
+                }
+                xml.AppendLine(@"
+  </PropertyGroup>");
+            }
+            Parameter[NewProject.QtSettings] = FormatParam(xml);
+
+            ///////////////////////////////////////////////////////////////////////////////////////
+            // Build settings
+            //
+            IEnumerable<ItemProperty> mocProperties
+                = ItemGlobals?[QtMoc.ItemTypeName]?.Properties ?? Enumerable.Empty<ItemProperty>();
+            IEnumerable<ItemProperty> clProperties
+                = ItemGlobals?["ClCompile"]?.Properties ?? Enumerable.Empty<ItemProperty>();
+            IEnumerable<ItemProperty> linkProperties
+                = ItemGlobals?["Link"]?.Properties ?? Enumerable.Empty<ItemProperty>();
+
+            xml = new StringBuilder();
+            foreach (IWizardConfiguration c in Configurations) {
+                xml.AppendLine(string.Format(@"
+  <ItemDefinitionGroup Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"" Label=""Configuration"">",
+                    /*{0}*/ c.Name,
+                    /*{1}*/ c.Platform));
+
+
+                ///////////////////////////////////////////////////////////////////////////////////
+                // Build settings: C++ compiler
+                //
+                if (!IsLinux(c)) {
+                    // Windows
+                    xml.AppendLine(@"
+    <ClCompile>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>");
+                    if (c.IsDebug) {
+                        xml.AppendLine(@"
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <Optimization>Disabled</Optimization>");
+                    } else {
+                        xml.AppendLine(@"
+      <DebugInformationFormat>None</DebugInformationFormat>
+      <Optimization>MaxSpeed</Optimization>");
+                    }
+                    if (c.Target.EqualTo(ProjectTargets.WindowsStore)) {
+                        xml.AppendLine(@"
+      <CompileAsWinRT>false</CompileAsWinRT>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <RuntimeTypeInfo>true</RuntimeTypeInfo>");
+                    }
+                    if (UsePrecompiledHeaders) {
+                        xml.AppendLine(string.Format(@"
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <PrecompiledHeaderFile>{0}</PrecompiledHeaderFile>",
+                            /*{0}*/ PrecompiledHeader.Include));
+                    }
+                    if (ExtraDefines?.Any() == true) {
+                        xml.AppendLine(string.Format(@"
+      <PreprocessorDefinitions>{0};%(PreprocessorDefinitions)</PreprocessorDefinitions>",
+                            /*{0}*/ string.Join(";", ExtraDefines)));
+                    }
+                    foreach (ItemProperty p in clProperties) {
+                        xml.AppendLine(string.Format(@"
+      <{0}>{1}</{0}>",
+                            /*{0}*/ p.Key,
+                            /*{1}*/ p.Value));
+                    }
+                    xml.AppendLine(@"
+    </ClCompile>");
+                } else {
+                    // Linux
+                    xml.AppendLine(@"
+    <ClCompile>
+      <PositionIndependentCode>true</PositionIndependentCode>
+    </ClCompile>");
+                }
+
+                ///////////////////////////////////////////////////////////////////////////////////
+                // Build settings: Linker
+                //
+                if (!IsLinux(c)) {
+                    // Windows
+                    xml.AppendLine(string.Format(@"
+    <Link>
+      <SubSystem>{0}</SubSystem>
+      <GenerateDebugInformation>{1}</GenerateDebugInformation>",
+                        /*{0}*/ TemplateType.HasFlag(Options.ConsoleSystem) ? "Console" : "Windows",
+                        /*{1}*/ c.IsDebug ? "true" : "false"));
+                    if (c.Target.EqualTo(ProjectTargets.WindowsStore)) {
+                        xml.AppendLine(string.Format(@"
+      <AdditionalOptions>/APPCONTAINER %(AdditionalOptions)</AdditionalOptions>
+      <GenerateManifest>false</GenerateManifest>
+      <GenerateWindowsMetadata>false</GenerateWindowsMetadata>
+      <TargetMachine>{0}</TargetMachine>",
+                            /*{0}*/ c.QtVersion.VC_Link_TargetMachine));
+                    }
+                    foreach (ItemProperty p in linkProperties) {
+                        xml.AppendLine(string.Format(@"
+      <{0}>{1}</{0}>",
+                            /*{0}*/ p.Key,
+                            /*{1}*/ p.Value));
+                    }
+                    xml.AppendLine(@"
+    </Link>");
+                }
+
+                ///////////////////////////////////////////////////////////////////////////////////
+                // Build settings: moc
+                //
+                if (UsePrecompiledHeaders || mocProperties.Any()) {
+                    xml.AppendLine(string.Format(@"
+    <{0}>", QtMoc.ItemTypeName));
+                    foreach (ItemProperty p in mocProperties) {
+                        xml.AppendLine(string.Format(@"
+      <{0}>{1}</{0}>",
+                            /*{0}*/ p.Key,
+                            /*{1}*/ p.Value));
+                    }
+                    if (UsePrecompiledHeaders) {
+                        xml.AppendLine(string.Format(@"
+      <{0}>{1};%({0})</{0}>",
+                            /*{0}*/ QtMoc.Property.PrependInclude,
+                            /*{1}*/ PrecompiledHeader.Include));
+                    }
+                    xml.AppendLine(string.Format(@"
+    </{0}>", QtMoc.ItemTypeName));
+                }
+
+                ///////////////////////////////////////////////////////////////////////////////////
+                // Build settings: remaining item types
+                //
+                if (ItemGlobals != null) {
+                    foreach (string itemType in ItemGlobals.Keys
+                        .Except(new[] { "ClCompile", "Link", QtMoc.ItemTypeName })) {
+                        xml.AppendLine(string.Format(@"
+    <{0}>",
+                            /*{0}*/ itemType));
+                        foreach (ItemProperty p in ItemGlobals[itemType].Properties) {
+                            xml.AppendLine(string.Format(@"
+      <{0}>{1}</{0}>",
+                                /*{0}*/ p.Key,
+                                /*{1}*/ p.Value));
+                        }
+                        xml.AppendLine(string.Format(@"
+    </{0}>",
+                            /*{0}*/ itemType));
+                    }
+                }
+                xml.AppendLine(@"
+  </ItemDefinitionGroup>");
+            }
+
+            Parameter[NewProject.BuildSettings] = FormatParam(xml);
+
+            ///////////////////////////////////////////////////////////////////////////////////////
+            // Project items
+            //
+            IEnumerable<ItemDef> projectItems = ExtraItems
+                .Where((ItemDef item) => item.WhereConfig == null
+                    || Configurations.Where(item.WhereConfig).Any())
+                .Union(UsePrecompiledHeaders
+                    ? new[] { PrecompiledHeader, PrecompiledHeaderSource }
+                    : Enumerable.Empty<ItemDef>());
+
+            xml = new StringBuilder();
+            foreach (ItemDef item in projectItems) {
+                bool itemHasProperties = (item.WhereConfig != null || item.Properties != null);
+                xml.Append(string.Format(@"
+    <{0} Include=""{1}""{2}",
+                    /*{0}*/ item.ItemType,
+                    /*{1}*/ item.Include,
+                    /*{2}*/ itemHasProperties ? ">" : " />"));
+
+                if (item.Properties != null) {
+                    foreach (ItemProperty property in item.Properties) {
+                        IEnumerable<IWizardConfiguration> configs = Configurations
+                            .Where(property.WhereConfig ?? WhereConfig_SelectAll);
+                        foreach (IWizardConfiguration config in configs) {
+                            xml.AppendLine(string.Format(@"
+      <{0} Condition=""'$(Configuration)|$(Platform)' == '{1}|{2}'"">{3}</{0}>",
+                                /*{0}*/ property.Key,
+                                /*{1}*/ config.Name,
+                                /*{2}*/ config.Platform,
+                                /*{3}*/ property.Value));
+                        }
+                    }
+                }
+
+                if (item.WhereConfig != null) {
+                    IEnumerable<IWizardConfiguration> excludedConfigs = Configurations
+                        .Where(config => !item.WhereConfig(config));
+                    foreach (var excludedConfig in excludedConfigs) {
+                        xml.AppendLine(string.Format(@"
+      <ExcludedFromBuild Condition=""'$(Configuration)|$(Platform)' == '{0}|{1}'"">true</ExcludedFromBuild>",
+                            /*{0}*/ excludedConfig.Name,
+                            /*{1}*/ excludedConfig.Platform));
+                    }
+                }
+
+                if (itemHasProperties) {
+                    xml.AppendLine(string.Format(@"
+    </{0}>",
+                        /*{0}*/ item.ItemType));
+                }
+            }
+            Parameter[NewProject.ProjectItems] = FormatParam(xml);
+
+            ///////////////////////////////////////////////////////////////////////////////////////
+            // Project items: filters
+            //
+            xml = new StringBuilder();
+            foreach (ItemDef item in projectItems) {
+                xml.Append(string.Format(@"
+    <{0} Include=""{1}"">",
+                    /*{0}*/ item.ItemType,
+                    /*{1}*/ item.Include));
+                xml.AppendLine(string.Format(@"
+      <Filter>{0}</Filter>",
+                    /*{0}*/ item.Filter));
+                xml.AppendLine(string.Format(@"
+    </{0}>",
+                    /*{0}*/ item.ItemType));
+            }
+            Parameter[NewProject.FilterItems] = FormatParam(xml);
+        }
+
+        // Matches empty lines; captures first newline
+        static readonly Regex patternEmptyLines
+            = new Regex(@"(?:^|(?<FIRST_NL>\r\n))(?:\r\n)+(?![\r\n]|$)|(?:\r\n)+$");
+
+        protected static string FormatParam(StringBuilder paramValue)
+        {
+            return FormatParam(paramValue.ToString());
+        }
+
+        protected static string FormatParam(string paramValue)
+        {
+            // Remove empty lines; replace with first newline (if any)
+            paramValue = patternEmptyLines.Replace(paramValue,
+                (Match m) => m.Groups["FIRST_NL"].Value);
+
+            return paramValue;
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/ProjectWizard/Quick/QuickWizard.cs b/QtVsTools.Wizards/ProjectWizard/Quick/QuickWizard.cs
new file mode 100644
index 0000000..87a0cc2
--- /dev/null
+++ b/QtVsTools.Wizards/ProjectWizard/Quick/QuickWizard.cs
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Collections.Generic;
+
+namespace QtVsTools.Wizards.ProjectWizard
+{
+    using QtVsTools.Common;
+    using Wizards.Common;
+
+    public class QuickWizard : ProjectTemplateWizard
+    {
+        LazyFactory Lazy { get; } = new LazyFactory();
+
+        protected override Options TemplateType => Options.Application | Options.GUISystem;
+
+        protected override WizardData WizardData => Lazy.Get(() =>
+            WizardData, () => new WizardData
+            {
+                DefaultModules = new List<string> { "QtQuick" }
+            });
+
+        protected override WizardWindow WizardWindow => Lazy.Get(() =>
+            WizardWindow, () => new WizardWindow(title: "Qt Quick Application Wizard")
+            {
+                new WizardIntroPage {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt Quick Application Wizard",
+                    Message = @"This wizard generates a Qt Quick application project."
+                        + System.Environment.NewLine
+                        + "Click Finish to create the project.",
+                    PreviousButtonEnabled = false,
+                    NextButtonEnabled = true,
+                    FinishButtonEnabled = false,
+                    CancelButtonEnabled = true
+                },
+                new ConfigPage {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt Quick Application Wizard",
+                    Message =
+                            @"Setup the configurations you want to include in your project. "
+                            + @"The recommended settings for this project are selected by default.",
+                    PreviousButtonEnabled = true,
+                    NextButtonEnabled = false,
+                    FinishButtonEnabled = true,
+                    CancelButtonEnabled = true,
+                }
+            });
+    }
+}
diff --git a/QtVsTools.Wizards/ProjectWizard/Server/ServerPage.xaml b/QtVsTools.Wizards/ProjectWizard/Server/ServerPage.xaml
new file mode 100644
index 0000000..8d7e946
--- /dev/null
+++ b/QtVsTools.Wizards/ProjectWizard/Server/ServerPage.xaml
@@ -0,0 +1,259 @@
+<!--
+    *****************************************************************************
+    **
+    ** Copyright (C) 2016 The Qt Company Ltd.
+    ** Contact: https://www.qt.io/licensing/
+    **
+    ** This file is part of the Qt VS Tools.
+    **
+    ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+    ** Commercial License Usage
+    ** Licensees holding valid commercial Qt licenses may use this file in
+    ** accordance with the commercial license agreement provided with the
+    ** Software or, alternatively, in accordance with the terms contained in
+    ** a written agreement between you and The Qt Company. For licensing terms
+    ** and conditions see https://www.qt.io/terms-conditions. For further
+    ** information use the contact form at https://www.qt.io/contact-us.
+    **
+    ** GNU General Public License Usage
+    ** Alternatively, this file may be used under the terms of the GNU
+    ** General Public License version 3 as published by the Free Software
+    ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+    ** included in the packaging of this file. Please review the following
+    ** information to ensure the GNU General Public License requirements will
+    ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+    **
+    ** $QT_END_LICENSE$
+    **
+    *****************************************************************************
+-->
+
+<common:WizardPage x:Class="QtVsTools.Wizards.ProjectWizard.ServerPage"
+                  xmlns:common="clr-namespace:QtVsTools.Wizards.Common"
+                  xmlns:util="clr-namespace:QtVsTools.Wizards.Util"
+                  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+                  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+                  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+                  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+                  KeepAlive="True"
+                  mc:Ignorable="d"
+                  d:DesignHeight="445"
+                  d:DesignWidth="585">
+    <Grid>
+        <Grid.ColumnDefinitions>
+            <ColumnDefinition Width="100" />
+            <ColumnDefinition Width="*" />
+        </Grid.ColumnDefinitions>
+        <Image Grid.Column="0"
+               HorizontalAlignment="Center"
+               Source="/QtVsTools.Wizards;component/Resources/Qt-logo-small.png"
+               VerticalAlignment="Top"
+               Margin="0,25,0,0"
+               RenderTransformOrigin="1,0">
+            <Image.RenderTransform>
+                <TransformGroup>
+                    <ScaleTransform ScaleY="0.86"
+                                    ScaleX="0.86" />
+                </TransformGroup>
+            </Image.RenderTransform>
+        </Image>
+        <Grid Grid.Column="1"
+              Margin="25,25,10,0">
+            <Grid.RowDefinitions>
+                <RowDefinition Height="Auto" />
+                <RowDefinition Height="*" />
+                <RowDefinition Height="Auto" />
+            </Grid.RowDefinitions>
+            <TextBlock TextWrapping="Wrap"
+                       Grid.Row="0">
+                <Run FontWeight="Bold"
+                     Text="{Binding Path=Header}" />
+                <LineBreak />
+                <LineBreak />
+                <Run Text="{Binding Path=Message}" />
+                <LineBreak />
+            </TextBlock>
+            <Grid Grid.Row="1">
+                <Grid.RowDefinitions>
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                </Grid.RowDefinitions>
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="*" />
+                    <ColumnDefinition Width="*" />
+                </Grid.ColumnDefinitions>
+                <Grid.Resources>
+                    <Style TargetType="TextBox">
+                        <Style.Triggers>
+                            <Trigger Property="Validation.HasError"
+                                     Value="true">
+                                <Setter Property="ToolTip"
+                                        Value="{Binding RelativeSource={RelativeSource Self},
+                                         Path=(Validation.Errors)[0].ErrorContent}" />
+                            </Trigger>
+                        </Style.Triggers>
+                    </Style>
+                </Grid.Resources>
+                <TextBlock Grid.Row="0"
+                           Text="Class Name:"
+                           Margin="0,0,10,0" />
+                <TextBox Grid.Row="1"
+                         Margin="0,0,10,30"
+                         Name="ClassName"
+                         TextChanged="OnClassNameChanged"
+                         TabIndex="0">
+                    <TextBox.Text>
+                        <Binding Path="Data.ClassName"
+                                 NotifyOnValidationError="True"
+                                 UpdateSourceTrigger="PropertyChanged">
+                            <Binding.ValidationRules>
+                                <util:ClassNameValidationRule />
+                            </Binding.ValidationRules>
+                        </Binding>
+                    </TextBox.Text>
+                </TextBox>
+                <Grid Grid.Row="2"
+                      Grid.ColumnSpan="2">
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="Auto" />
+                        <RowDefinition Height="Auto" />
+                        <RowDefinition Height="Auto" />
+                        <RowDefinition Height="Auto" />
+                    </Grid.RowDefinitions>
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition Width="*" />
+                        <ColumnDefinition Width="*" />
+                    </Grid.ColumnDefinitions>
+                    <TextBlock Grid.Row="0"
+                               Grid.Column="0"
+                               Margin="0,0,10,5"
+                               Text="Header (.h) file:" />
+                    <TextBox Grid.Row="1"
+                             Grid.Column="0"
+                             Margin="0,0,10,10"
+                             Name="ClassHeaderFile"
+                             TabIndex="1">
+                        <TextBox.Text>
+                            <Binding Path="Data.ClassHeaderFile"
+                                     NotifyOnValidationError="True"
+                                     UpdateSourceTrigger="PropertyChanged">
+                                <Binding.ValidationRules>
+                                    <util:FileNameValidationRule FileExt=".h" />
+                                </Binding.ValidationRules>
+                            </Binding>
+                        </TextBox.Text>
+                    </TextBox>
+                    <TextBlock Grid.Row="2"
+                               Grid.Column="0"
+                               Margin="0,0,10,5"
+                               Text="User Interface (.ui) file:" />
+                    <TextBox Grid.Row="3"
+                             Grid.Column="0"
+                             Margin="0,0,10,0"
+                             Name="UiFile"
+                             TabIndex="3">
+                        <TextBox.Text>
+                            <Binding Path="Data.UiFile"
+                                     NotifyOnValidationError="True"
+                                     UpdateSourceTrigger="PropertyChanged">
+                                <Binding.ValidationRules>
+                                    <util:FileNameValidationRule FileExt=".ui" />
+                                </Binding.ValidationRules>
+                            </Binding>
+                        </TextBox.Text>
+                    </TextBox>
+                    <TextBlock Grid.Row="0"
+                               Grid.Column="1"
+                               Margin="0,0,0,5"
+                               Text="Source (.cpp) file:" />
+                    <TextBox Grid.Row="1"
+                             Grid.Column="1"
+                             Margin="0,0,0,10"
+                             Name="ClassSourceFile"
+                             TabIndex="2">
+                        <TextBox.Text>
+                            <Binding Path="Data.ClassSourceFile"
+                                     NotifyOnValidationError="True"
+                                     UpdateSourceTrigger="PropertyChanged">
+                                <Binding.ValidationRules>
+                                    <util:FileNameValidationRule FileExt=".cpp" />
+                                </Binding.ValidationRules>
+                            </Binding>
+                        </TextBox.Text>
+                    </TextBox>
+                </Grid>
+                <CheckBox Grid.Row="3"
+                          Content="Lower case file names"
+                          Name="LowerCaseFileNames"
+                          Click="OnLowerCaseFileNamesClick"
+                          Margin="0,20,10,5"
+                          TabIndex="4" />
+                <CheckBox Grid.Row="4"
+                          Content="Precompiled header"
+                          IsChecked="{Binding Path=Data.UsePrecompiledHeader}"
+                          Margin="0,10,10,5"
+                          TabIndex="5" />
+            </Grid>
+            <StackPanel HorizontalAlignment="Right"
+                        Orientation="Horizontal"
+                        Grid.Row="2"
+                        Margin="0,0,0,10">
+                <Button Click="OnPreviousButtonClick"
+                        Name="PreviousButton"
+                        IsEnabled="{Binding Path=PreviousButtonEnabled}"
+                        MinWidth="75">&lt; _Previous</Button>
+                <Button MinWidth="75"
+                        Name="NextButton"
+                        Click="OnNextButtonClick"
+                        IsEnabled="{Binding Path=NextButtonEnabled}"
+                        Margin="10,0,0,0">_Next &gt;</Button>
+                <Button MinWidth="75"
+                        Click="OnFinishButtonClick"
+                        Margin="10,0,0,0"
+                        IsDefault="True"
+                        Name="FinishButton"
+                        Content="_Finish"
+                        VerticalAlignment="Bottom">
+                    <Button.Style>
+                        <Style TargetType="Button">
+                            <Setter Property="IsEnabled"
+                                    Value="false" />
+                            <Style.Triggers>
+                                <MultiDataTrigger>
+                                    <MultiDataTrigger.Conditions>
+                                        <Condition Binding="{Binding Path=FinishButtonEnabled}"
+                                                   Value="true" />
+                                        <Condition Binding="{Binding ElementName=ClassName,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                        <Condition Binding="{Binding ElementName=ClassHeaderFile,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                        <Condition Binding="{Binding ElementName=ClassSourceFile,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                        <Condition Binding="{Binding ElementName=UiFile,
+                                            Path=(Validation.HasError)}"
+                                                   Value="false" />
+                                    </MultiDataTrigger.Conditions>
+                                    <Setter Property="IsEnabled"
+                                            Value="true" />
+                                </MultiDataTrigger>
+                            </Style.Triggers>
+                        </Style>
+                    </Button.Style>
+                </Button>
+                <Button Click="OnCancelButtonClick"
+                        MinWidth="75"
+                        Margin="10,0,0,0"
+                        Name="CancelButton"
+                        IsEnabled="{Binding Path=CancelButtonEnabled}"
+                        IsCancel="True">_Cancel</Button>
+            </StackPanel>
+        </Grid>
+    </Grid>
+</common:WizardPage>
diff --git a/QtVsTools.Wizards/ProjectWizard/Server/ServerPage.xaml.cs b/QtVsTools.Wizards/ProjectWizard/Server/ServerPage.xaml.cs
new file mode 100644
index 0000000..f0681b8
--- /dev/null
+++ b/QtVsTools.Wizards/ProjectWizard/Server/ServerPage.xaml.cs
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Windows;
+using System.Windows.Controls;
+
+namespace QtVsTools.Wizards.ProjectWizard
+{
+    using Wizards.Common;
+
+    public partial class ServerPage : WizardPage
+    {
+        public ServerPage()
+        {
+            InitializeComponent();
+            DataContext = this;
+        }
+
+        private void OnClassNameChanged(object sender, TextChangedEventArgs e)
+        {
+            UpdateFileNames();
+        }
+
+        private void OnLowerCaseFileNamesClick(object sender, RoutedEventArgs e)
+        {
+            UpdateFileNames();
+        }
+
+        private void UpdateFileNames()
+        {
+            Data.LowerCaseFileNames = LowerCaseFileNames.IsChecked.GetValueOrDefault();
+            var filename = Data.LowerCaseFileNames ? ClassName.Text.ToLower() : ClassName.Text;
+
+            ClassHeaderFile.Text = filename + @".h";
+            ClassSourceFile.Text = filename + @".cpp";
+            UiFile.Text = filename + @".ui";
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/ProjectWizard/Server/ServerWizard.cs b/QtVsTools.Wizards/ProjectWizard/Server/ServerWizard.cs
new file mode 100644
index 0000000..2f77f13
--- /dev/null
+++ b/QtVsTools.Wizards/ProjectWizard/Server/ServerWizard.cs
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Windows.Controls;
+using Microsoft.VisualStudio.Shell;
+using EnvDTE;
+
+namespace QtVsTools.Wizards.ProjectWizard
+{
+    using QtVsTools.Common;
+    using Core;
+    using Wizards.Common;
+
+    using static QtVsTools.Common.EnumExt;
+
+    public class ServerWizard : ProjectTemplateWizard
+    {
+        LazyFactory Lazy { get; } = new LazyFactory();
+
+        protected override Options TemplateType => Options.DynamicLibrary | Options.GUISystem;
+
+        enum NewClass
+        {
+            [String("classname")] ClassName,
+            [String("sourcefilename")] SourceFileName,
+            [String("headerfilename")] HeaderFileName,
+            [String("include")] Include,
+        }
+
+        enum NewActiveQtProject
+        {
+            [String("pro_name")] Name,
+            [String("uifilename")] UiFileName,
+            [String("ui_hdr")] UiHeaderName,
+        }
+
+        protected override WizardData WizardData => Lazy.Get(() =>
+            WizardData, () => new WizardData
+            {
+                DefaultModules = new List<string> { "QtCore", "QtGui", "QtWidgets", "QtAxServer" }
+            });
+
+        protected override WizardWindow WizardWindow => Lazy.Get(() =>
+            WizardWindow, () => new WizardWindow(title: "Qt ActiveQt Server Wizard")
+            {
+                new WizardIntroPage {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt ActiveQt Server Wizard",
+                    Message = @"This wizard generates a Qt ActiveQt server project. It "
+                        + @"creates a simple ActiveQt widget with the required files."
+                        + System.Environment.NewLine + System.Environment.NewLine
+                        + "To continue, click Next.",
+                    PreviousButtonEnabled = false,
+                    NextButtonEnabled = true,
+                    FinishButtonEnabled = false,
+                    CancelButtonEnabled = true
+                },
+                new ConfigPage {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt ActiveQt Server Wizard",
+                    Message =
+                            @"Setup the configurations you want to include in your project. "
+                            + @"The recommended settings for this project are selected by default.",
+                    PreviousButtonEnabled = true,
+                    NextButtonEnabled = true,
+                    FinishButtonEnabled = false,
+                    CancelButtonEnabled = true,
+                    ValidateConfigs = ValidateConfigsForActiveQtServer
+                },
+                new ServerPage {
+                    Data = WizardData,
+                    Header = @"Welcome to the Qt ActiveQt Server Wizard",
+                    Message = @"This wizard generates a Qt ActiveQt server project. It "
+                        + @"creates a simple ActiveQt widget with the required files.",
+                    PreviousButtonEnabled = true,
+                    NextButtonEnabled = false,
+                    FinishButtonEnabled = true,
+                    CancelButtonEnabled = true
+                }
+            });
+
+        string ValidateConfigsForActiveQtServer(IEnumerable<IWizardConfiguration> configs)
+        {
+            foreach (var config in configs) {
+                if (config.Target.EqualTo(ProjectTargets.WindowsStore)) {
+                    return string.Format(
+                        "ActiveQt Server project not available for the '{0}' target.",
+                        config.Target);
+                }
+            }
+            return string.Empty;
+        }
+
+        protected override void BeforeWizardRun()
+        {
+            // midl.exe does not support spaces in project name. Fails while generating the
+            // IDL file (library attribute), e.g. 'library Active QtServer1Lib' is illegal.
+            if (Parameter[NewProject.SafeName].Contains(" "))
+                throw new QtVSException("Project name shall not contain spaces.");
+
+            var className = Parameter[NewProject.SafeName];
+            className = Regex.Replace(className, @"[^a-zA-Z0-9_]", string.Empty);
+            className = Regex.Replace(className, @"^[\d-]*\s*", string.Empty);
+            var result = new Util.ClassNameValidationRule().Validate(className, null);
+            if (result != ValidationResult.ValidResult)
+                className = @"ActiveQtServer";
+
+            WizardData.ClassName = className;
+            WizardData.ClassHeaderFile = className + @".h";
+            WizardData.ClassSourceFile = className + @".cpp";
+            WizardData.UiFile = WizardData.ClassName + @".ui";
+        }
+
+        protected override void BeforeTemplateExpansion()
+        {
+            Parameter[NewClass.ClassName] = WizardData.ClassName;
+            Parameter[NewClass.HeaderFileName] = WizardData.ClassHeaderFile;
+            Parameter[NewClass.SourceFileName] = WizardData.ClassSourceFile;
+            Parameter[NewActiveQtProject.UiFileName] = WizardData.UiFile;
+
+            var include = new StringBuilder();
+            if (UsePrecompiledHeaders)
+                include.AppendLine(string.Format("#include \"{0}\"", PrecompiledHeader.Include));
+            include.AppendLine(string.Format("#include \"{0}\"", WizardData.ClassHeaderFile));
+            Parameter[NewClass.Include] = FormatParam(include);
+
+            Parameter[NewActiveQtProject.UiHeaderName] = string.Format("ui_{0}.h",
+                Path.GetFileNameWithoutExtension(WizardData.UiFile));
+
+            Parameter[NewActiveQtProject.Name] = WizardData.LowerCaseFileNames
+                ? Parameter[NewProject.SafeName].ToLower()
+                : Parameter[NewProject.SafeName];
+        }
+
+        protected override void OnProjectGenerated(Project project)
+        {
+            var qtProject = QtProject.Create(project);
+            qtProject.AddActiveQtBuildStep("1.0", Parameter[NewProject.SafeName] + ".def");
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/QtVsTools.Wizards.csproj b/QtVsTools.Wizards/QtVsTools.Wizards.csproj
index 0b333de..34aa9ff 100644
--- a/QtVsTools.Wizards/QtVsTools.Wizards.csproj
+++ b/QtVsTools.Wizards/QtVsTools.Wizards.csproj
@@ -71,42 +71,43 @@
     <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
     <Reference Include="System" />
     <Reference Include="System.Drawing" />
-    <Reference Include="System.Xml.Linq" />
     <Reference Include="PresentationCore" />
     <Reference Include="PresentationFramework" />
+    <Reference Include="System.Xaml" />
     <Reference Include="WindowsBase" />
     <Reference Include="Microsoft.VisualStudio.VCCodeModel" />
-    <Reference Include="Microsoft.VisualStudio.ExtensionsExplorer.UI, Version=$(VisualStudioVersion).0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>$(DevEnvDir)PrivateAssemblies\Microsoft.VisualStudio.ExtensionsExplorer.UI.dll</HintPath>
-    </Reference>
   </ItemGroup>
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
-  // Version specific references
+  // General package references
   // -->
   <Import Project="$(SolutionDir)\references.props" />
   <ItemGroup>
-    <PackageReference Include="Microsoft.VisualStudio.SDK"
-      Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
-    <PackageReference Include="Microsoft.VSSDK.BuildTools"
-      Version="$(Version_Microsoft_VSSDK_BuildTools)" />
-    <PackageReference Include="Newtonsoft.Json"
-      Version="$(Version_Newtonsoft_Json)" />
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
   </ItemGroup>
-  <ItemGroup Condition="'$(VisualStudioVersion)'=='17.0'">
-    <PackageReference Include="$(Name_Microsoft_VisualStudio_VCProjectEngine)"
-      Version="$(Version_Microsoft_VisualStudio_VCProjectEngine)" />
-    <PackageReference Include="$(Name_Microsoft_VisualStudio_TemplateWizardInterface)"
-      Version="$(Version_Microsoft_VisualStudio_TemplateWizardInterface)" />
-  </ItemGroup>
-  <ItemGroup Condition="'$(VisualStudioVersion)'=='16.0'">
-    <Reference Include="Microsoft.VisualStudio.TemplateWizardInterface" />
-  </ItemGroup>
-  <ItemGroup Condition="'$(VisualStudioVersion)'=='15.0'">
-    <Reference Include="Microsoft.VisualStudio.VCProjectEngine" />
-    <Reference Include="Microsoft.VisualStudio.TemplateWizardInterface" />
-  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_TemplateWizardInterface)" Version="$(Version_Microsoft_VisualStudio_TemplateWizardInterface)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_TemplateWizardInterface)" Version="$(Version_Microsoft_VisualStudio_TemplateWizardInterface)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+        <Reference Include="$(Name_Microsoft_VisualStudio_VCProjectEngine)" />
+        <Reference Include="$(Name_Microsoft_VisualStudio_TemplateWizardInterface)" />
+      </ItemGroup>
+    </When>
+  </Choose>
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
   // Solution project references
@@ -123,58 +124,47 @@
   // -->
   <ItemGroup>
     <Content Include="Resources\QtProjectWizard.ico" />
-    <Resource Include="Resources\medium.png">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Resource>
     <Resource Include="Resources\Qt-logo-small.png">
       <CopyToOutputDirectory>Always</CopyToOutputDirectory>
     </Resource>
-    <Resource Include="Resources\small.png">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Resource>
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="Wizards\ClassWizard\AddClassPage.xaml.cs">
-      <DependentUpon>AddClassPage.xaml</DependentUpon>
+    <Compile Include="ItemWizard\Translation\TranslationPage.xaml.cs">
+      <DependentUpon>TranslationPage.xaml</DependentUpon>
     </Compile>
-    <Compile Include="Wizards\ClassWizard\AddClassWizard.cs" />
-    <Compile Include="Wizards\ClassWizard\Class.cs" />
-    <Compile Include="Wizards\ClassWizard\ClassKind.cs" />
-    <Compile Include="Wizards\ProjectWizard\ConfigPage.xaml.cs">
+    <Compile Include="ItemWizard\Translation\TranslationWizard.cs" />
+    <Compile Include="ProjectWizard\ConfigPage.xaml.cs">
       <DependentUpon>ConfigPage.xaml</DependentUpon>
     </Compile>
-    <Compile Include="Wizards\ProjectWizard\ProjectTemplateWizard.cs" />
-    <Compile Include="Wizards\ProjectWizard\Quick\QuickWizard.cs" />
-    <Compile Include="Wizards\Util\ClassNameValidationRule.cs" />
-    <Compile Include="Wizards\ProjectWizard\Console\ConsoleWizard.cs" />
-    <Compile Include="Wizards\ClassWizard\Core\CoreClassPage.xaml.cs">
-      <DependentUpon>CoreClassPage.xaml</DependentUpon>
+    <Compile Include="ProjectWizard\ProjectTemplateWizard.cs" />
+    <Compile Include="ProjectWizard\Quick\QuickWizard.cs" />
+    <Compile Include="Util\ClassNameValidationRule.cs" />
+    <Compile Include="ProjectWizard\Console\ConsoleWizard.cs" />
+    <Compile Include="ItemWizard\QtClass\QtClassPage.xaml.cs">
+      <DependentUpon>QtClassPage.xaml</DependentUpon>
     </Compile>
-    <Compile Include="Wizards\ClassWizard\Core\CoreClassWizard.cs" />
-    <Compile Include="Wizards\ProjectWizard\Designer\DesignerPage.xaml.cs">
+    <Compile Include="ProjectWizard\Designer\DesignerPage.xaml.cs">
       <DependentUpon>DesignerPage.xaml</DependentUpon>
     </Compile>
-    <Compile Include="Wizards\ProjectWizard\Designer\DesignerWizard.cs" />
-    <Compile Include="Wizards\Util\FileExistsInFilterValidationRule.cs" />
-    <Compile Include="Wizards\Util\FileNameValidationRule.cs" />
-    <Compile Include="Wizards\ClassWizard\Gui\GuiClassPage.xaml.cs">
-      <DependentUpon>GuiClassPage.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Wizards\ClassWizard\Gui\GuiClassWizard.cs" />
-    <Compile Include="Wizards\ProjectWizard\Gui\GuiPage.xaml.cs">
+    <Compile Include="ProjectWizard\Designer\DesignerWizard.cs" />
+    <Compile Include="Util\FileExistsInFilterValidationRule.cs" />
+    <Compile Include="Util\FileNameValidationRule.cs" />
+    <Compile Include="Common\GuiPage.xaml.cs">
       <DependentUpon>GuiPage.xaml</DependentUpon>
     </Compile>
-    <Compile Include="Wizards\ProjectWizard\Gui\GuiWizard.cs" />
-    <Compile Include="Wizards\ProjectWizard\Empty\EmptyWizard.cs" />
-    <Compile Include="Wizards\ClassWizard\IClassWizard.cs" />
-    <Compile Include="Wizards\WizardIntroPage.xaml.cs">
+    <Compile Include="ProjectWizard\Gui\GuiWizard.cs" />
+    <Compile Include="ProjectWizard\Empty\EmptyWizard.cs" />
+    <Compile Include="Common\WizardIntroPage.xaml.cs">
       <DependentUpon>WizardIntroPage.xaml</DependentUpon>
     </Compile>
-    <Compile Include="Wizards\ProjectWizard\Library\LibraryClassPage.xaml.cs">
+    <Compile Include="ProjectWizard\Library\LibraryClassPage.xaml.cs">
       <DependentUpon>LibraryClassPage.xaml</DependentUpon>
     </Compile>
-    <Compile Include="Wizards\ProjectWizard\Library\LibraryWizard.cs" />
-    <Compile Include="Wizards\Util\NativeMethods.cs" />
+    <Compile Include="ProjectWizard\Library\LibraryWizard.cs" />
+    <Compile Include="Util\NativeMethods.cs" />
+    <Compile Include="ItemWizard\QtClass\QtClassWizard.cs" />
+    <Compile Include="ItemWizard\WidgetsClass\WidgetsClassWizard.cs" />
+    <Compile Include="Util\VCRulePropertyStorageHelper.cs" />
     <T4Template Include="Properties\AssemblyInfo.cs">
       <Generator>TextTemplatingFileGenerator</Generator>
       <OutputFile>Properties\AssemblyInfo.tt.cs</OutputFile>
@@ -186,65 +176,58 @@
       <DesignTime>True</DesignTime>
       <DependentUpon>AssemblyInfo.cs</DependentUpon>
     </Compile>
-    <Compile Include="Wizards\ProjectWizard\Server\ServerPage.xaml.cs">
+    <Compile Include="ProjectWizard\Server\ServerPage.xaml.cs">
       <DependentUpon>ServerPage.xaml</DependentUpon>
     </Compile>
-    <Compile Include="Wizards\ProjectWizard\Server\ServerWizard.cs" />
-    <Compile Include="Wizards\Util\SortComboBoxItem.cs" />
-    <Compile Include="Wizards\ClassWizard\UiClassInclusion.cs" />
-    <Compile Include="Wizards\Util\UnsafeNativeMethods.cs" />
-    <Compile Include="Wizards\Util\VCLanguageManagerValidationRule.cs" />
-    <Compile Include="Wizards\WizardData.cs" />
-    <Compile Include="Wizards\WizardPage.cs" />
-    <Compile Include="Wizards\WizardResult.cs" />
-    <Compile Include="Wizards\WizardWindow.xaml.cs">
+    <Compile Include="ProjectWizard\Server\ServerWizard.cs" />
+    <Compile Include="Util\UiClassInclusionConverter.cs" />
+    <Compile Include="Common\UiClassInclusion.cs" />
+    <Compile Include="Util\UnsafeNativeMethods.cs" />
+    <Compile Include="Util\VCLanguageManagerValidationRule.cs" />
+    <Compile Include="Common\WizardData.cs" />
+    <Compile Include="Common\WizardPage.cs" />
+    <Compile Include="Common\WizardResult.cs" />
+    <Compile Include="Common\WizardWindow.xaml.cs">
       <DependentUpon>WizardWindow.xaml</DependentUpon>
     </Compile>
-    <Page Include="Wizards\ClassWizard\AddClassPage.xaml">
+    <Page Include="ItemWizard\QtClass\QtClassPage.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
     </Page>
-    <Page Include="Wizards\ClassWizard\Core\CoreClassPage.xaml">
+    <Page Include="ItemWizard\Translation\TranslationPage.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
     </Page>
-    <Page Include="Wizards\ProjectWizard\Designer\DesignerPage.xaml">
+    <Page Include="ProjectWizard\Designer\DesignerPage.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
     </Page>
-    <Page Include="Wizards\ClassWizard\Gui\GuiClassPage.xaml">
+    <Page Include="Common\GuiPage.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
     </Page>
-    <Page Include="Wizards\ProjectWizard\Gui\GuiPage.xaml">
-      <SubType>Designer</SubType>
-      <Generator>MSBuild:Compile</Generator>
-    </Page>
-    <Page Include="Wizards\ProjectWizard\ConfigPage.xaml">
+    <Page Include="ProjectWizard\ConfigPage.xaml">
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
     </Page>
-    <Page Include="Wizards\WizardIntroPage.xaml">
+    <Page Include="Common\WizardIntroPage.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
     </Page>
-    <Page Include="Wizards\ProjectWizard\Library\LibraryClassPage.xaml">
+    <Page Include="ProjectWizard\Library\LibraryClassPage.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
     </Page>
-    <Page Include="Resources\ExpanderStyle.xaml">
+    <Page Include="ProjectWizard\Server\ServerPage.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
     </Page>
-    <Page Include="Wizards\ProjectWizard\Server\ServerPage.xaml">
-      <SubType>Designer</SubType>
-      <Generator>MSBuild:Compile</Generator>
-    </Page>
-    <Page Include="Wizards\WizardWindow.xaml">
+    <Page Include="Common\WizardWindow.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
     </Page>
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\transform.targets" />
 </Project>
\ No newline at end of file
diff --git a/QtVsTools.Wizards/Util/ClassNameValidationRule.cs b/QtVsTools.Wizards/Util/ClassNameValidationRule.cs
new file mode 100644
index 0000000..a9304a8
--- /dev/null
+++ b/QtVsTools.Wizards/Util/ClassNameValidationRule.cs
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Globalization;
+using System.Text.RegularExpressions;
+using System.Windows.Controls;
+
+namespace QtVsTools.Wizards.Util
+{
+    internal class ClassNameValidationRule : VCLanguageManagerValidationRule
+    {
+        public ClassNameValidationRule()
+        {
+            SupportNamespaces = false;
+            AllowEmptyIdentifier = false;
+        }
+
+        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
+        {
+            if (value is string) {
+                var identifier = value as string;
+                if (AllowEmptyIdentifier && string.IsNullOrEmpty(identifier))
+                    return ValidationResult.ValidResult;
+
+                if (SupportNamespaces) {
+                    var index = identifier.LastIndexOf(@"::", System.StringComparison.Ordinal);
+                    if (index >= 0)
+                        identifier = identifier.Substring(index + 2);
+                }
+
+                if (Regex.IsMatch(identifier, pattern) && !Vclm.IsReservedName(identifier))
+                    return ValidationResult.ValidResult;
+            }
+            return new ValidationResult(false, @"Invalid identifier.");
+        }
+
+        public bool SupportNamespaces { get; set; }
+        public bool AllowEmptyIdentifier { get; set; }
+
+        const string pattern = @"^[a-zA-Z_][a-zA-Z0-9_]*$";
+    }
+}
diff --git a/QtVsTools.Wizards/Util/FileExistsInFilterValidationRule.cs b/QtVsTools.Wizards/Util/FileExistsInFilterValidationRule.cs
new file mode 100644
index 0000000..036c824
--- /dev/null
+++ b/QtVsTools.Wizards/Util/FileExistsInFilterValidationRule.cs
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Globalization;
+using System.Linq;
+using System.Windows.Controls;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+using EnvDTE;
+
+namespace QtVsTools.Wizards.Util
+{
+    using Core;
+    using VisualStudio;
+
+    internal class FileExistsinFilterValidationRule : VCLanguageManagerValidationRule
+    {
+        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
+        {
+            if (value is string) {
+                var dte = VsServiceProvider.GetService<SDTE, DTE>();
+                if (dte == null)
+                    return ValidationResult.ValidResult;
+
+                var project = HelperFunctions.GetSelectedProject(dte);
+                if (project == null)
+                    return ValidationResult.ValidResult;
+
+                var files = HelperFunctions.GetProjectFiles(project, Filter);
+                if (files.Count == 0)
+                    return ValidationResult.ValidResult;
+
+                var fileName = (value as string).ToUpperInvariant();
+                if (files.FirstOrDefault(x => x.ToUpperInvariant() == fileName) != null)
+                    return new ValidationResult(false, @"File already exists.");
+                return ValidationResult.ValidResult;
+            }
+            return new ValidationResult(false, @"Invalid file name.");
+        }
+
+        public FilesToList Filter { get; set; }
+    }
+}
diff --git a/QtVsTools.Wizards/Util/FileNameValidationRule.cs b/QtVsTools.Wizards/Util/FileNameValidationRule.cs
new file mode 100644
index 0000000..e3ea756
--- /dev/null
+++ b/QtVsTools.Wizards/Util/FileNameValidationRule.cs
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Windows.Controls;
+
+namespace QtVsTools.Wizards.Util
+{
+    internal class FileNameValidationRule : VCLanguageManagerValidationRule
+    {
+        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
+        {
+            if (value is string) {
+                var filename = value as string;
+                if (FileExt == @".ui" || FileExt == @".qrc") {
+                    filename = filename.ToLower().Replace(@".h", @".x");
+                    filename = filename.Replace(FileExt, @".h");
+                }
+
+                if (Vclm.ValidateFileName(filename)
+                    && !Path.GetInvalidFileNameChars().Any(filename.Contains)) {
+                    return ValidationResult.ValidResult;
+                }
+            }
+            return new ValidationResult(false, @"Invalid file name.");
+        }
+    }
+}
diff --git a/QtVsTools.Wizards/Util/NativeMethods.cs b/QtVsTools.Wizards/Util/NativeMethods.cs
new file mode 100644
index 0000000..00edfea
--- /dev/null
+++ b/QtVsTools.Wizards/Util/NativeMethods.cs
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
+
+namespace QtVsTools.Wizards.Util
+{
+    internal static class NativeMethods
+    {
+        [ResourceExposure(ResourceScope.None)]
+        [DllImport("user32.dll", CharSet = CharSet.Auto)]
+        internal static extern int GetWindowLong(IntPtr hwnd, int index);
+    }
+}
diff --git a/QtVsTools.Wizards/Util/UiClassInclusionConverter.cs b/QtVsTools.Wizards/Util/UiClassInclusionConverter.cs
new file mode 100644
index 0000000..64ee165
--- /dev/null
+++ b/QtVsTools.Wizards/Util/UiClassInclusionConverter.cs
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Globalization;
+using System.Windows.Data;
+
+namespace QtVsTools.Wizards.Util
+{
+    public class UiClassInclusionConverter : IValueConverter
+    {
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+            => value?.Equals(parameter);
+
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+            => value?.Equals(true) == true ? parameter : Binding.DoNothing;
+    }
+}
diff --git a/QtVsTools.Wizards/Util/UnsafeNativeMethods.cs b/QtVsTools.Wizards/Util/UnsafeNativeMethods.cs
new file mode 100644
index 0000000..8fc5f27
--- /dev/null
+++ b/QtVsTools.Wizards/Util/UnsafeNativeMethods.cs
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
+
+namespace QtVsTools.Wizards.Util
+{
+    internal static class UnsafeNativeMethods
+    {
+        [ResourceExposure(ResourceScope.None)]
+        [DllImport("user32.dll", CharSet = CharSet.Auto)]
+        internal static extern int SetWindowLong(IntPtr hwnd, int index, int value);
+    }
+}
diff --git a/QtVsTools.Wizards/Util/VCLanguageManagerValidationRule.cs b/QtVsTools.Wizards/Util/VCLanguageManagerValidationRule.cs
new file mode 100644
index 0000000..996e91c
--- /dev/null
+++ b/QtVsTools.Wizards/Util/VCLanguageManagerValidationRule.cs
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Windows.Controls;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.VCCodeModel;
+using EnvDTE;
+
+namespace QtVsTools.Wizards.Util
+{
+    using VisualStudio;
+
+    internal abstract class VCLanguageManagerValidationRule : ValidationRule
+    {
+        protected VCLanguageManagerValidationRule()
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            ValidatesOnTargetUpdated = true;
+
+            var dte = VsServiceProvider.GetService<DTE>();
+            Vclm = dte.GetObject("VCLanguageManager") as VCLanguageManager;
+        }
+
+        public string FileExt { get; set; }
+        public VCLanguageManager Vclm { get; }
+    }
+}
diff --git a/QtVsTools.Wizards/Util/VCRulePropertyStorageHelper.cs b/QtVsTools.Wizards/Util/VCRulePropertyStorageHelper.cs
new file mode 100644
index 0000000..e183a82
--- /dev/null
+++ b/QtVsTools.Wizards/Util/VCRulePropertyStorageHelper.cs
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.VCProjectEngine;
+using EnvDTE;
+
+namespace QtVsTools.Wizards.Util
+{
+    using Core;
+
+    static class VCRulePropertyStorageHelper
+    {
+        public static void SetQtModules(DTE dte, List<string> modules)
+        {
+            ThreadHelper.ThrowIfNotOnUIThread();
+
+            var newModules = modules.ToHashSet();
+            if (modules.Count == 0)
+                return;
+
+            var project = HelperFunctions.GetSelectedQtProject(dte);
+            if (project == null)
+                return;
+
+            var vcproject = project.Object as VCProject;
+            if (vcproject == null)
+                return;
+
+            // TODO: There is already code providing such functionality, though it seems overly
+            // complicated to use compared to this simple for loop (see VCPropertyStorageProvider).
+            foreach (VCConfiguration config in vcproject.Configurations as IVCCollection) {
+                var props = config.Rules.Item("QtRule10_Settings") as IVCRulePropertyStorage;
+                var updatedModules = props.GetUnevaluatedPropertyValue("QtModules")
+                    .Split(new char[] { ';' }, System.StringSplitOptions.RemoveEmptyEntries)
+                    .ToHashSet()
+                    .Union(newModules);
+                props.SetPropertyValue("QtModules", string.Join(";", updatedModules));
+            }
+        }
+    }
+}
diff --git a/README.md b/README.md
index fa5df16..cc2dbdd 100644
--- a/README.md
+++ b/README.md
@@ -58,7 +58,7 @@
 
 The following is required in order to build the Qt Visual Studio solution:
 
-- Visual Studio 2017, 2019 or 2022, with the following workloads:
+- Visual Studio 2017, 2019 or 2022, with the following workloads (A .vsconfig file per VS version can be found in the source tree):
     - Desktop development with C++
     - .NET desktop development
     - [Visual Studio extension development](https://docs.microsoft.com/en-us/visualstudio/extensibility/installing-the-visual-studio-sdk)
diff --git a/Templates/console/QtTemplate.Project.Console.csproj b/Templates/console/QtTemplate.Project.Console.csproj
index d4bbdfe..c4d6e31 100644
--- a/Templates/console/QtTemplate.Project.Console.csproj
+++ b/Templates/console/QtTemplate.Project.Console.csproj
@@ -76,16 +76,45 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Global references
+  // -->
   <ItemGroup>
-    <Reference Include="Microsoft.VisualStudio.CoreUtility">
-      <Private>False</Private>
-    </Reference>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Xml" />
     <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
   </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // General package references
+  // -->
+  <Import Project="$(SolutionDir)\references.props" />
+  <ItemGroup>
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Project items
+  // -->
   <ItemGroup>
     <T4Template Include="Properties\AssemblyInfo.cs">
       <Generator>TextTemplatingFileGenerator</Generator>
@@ -126,6 +155,6 @@
     </VSTemplate>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
   <Import Project="$(SolutionDir)\transform.targets" />
-</Project>
+  <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/Templates/console/console.vcxproj.filters b/Templates/console/console.vcxproj.filters
index df883a8..64ad4dd 100644
--- a/Templates/console/console.vcxproj.filters
+++ b/Templates/console/console.vcxproj.filters
@@ -3,7 +3,7 @@
   <ItemGroup>
     <Filter Include="Source Files">
       <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
-      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+      <Extensions>qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
     </Filter>
     <Filter Include="Header Files">
       <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
@@ -13,6 +13,10 @@
       <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
       <Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
     </Filter>
+    <Filter Include="Form Files">
+      <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
+      <Extensions>ui</Extensions>
+    </Filter>
     <Filter Include="Translation Files">
       <UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>
       <Extensions>ts</Extensions>
diff --git a/Templates/designer/QtTemplate.Project.Designer.csproj b/Templates/designer/QtTemplate.Project.Designer.csproj
index 0e19350..6e2e3b1 100644
--- a/Templates/designer/QtTemplate.Project.Designer.csproj
+++ b/Templates/designer/QtTemplate.Project.Designer.csproj
@@ -78,6 +78,45 @@
     <WarningLevel>4</WarningLevel>
     <UseVSHostingProcess>false</UseVSHostingProcess>
   </PropertyGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Global references
+  // -->
+  <ItemGroup>
+    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // General package references
+  // -->
+  <Import Project="$(SolutionDir)\references.props" />
+  <ItemGroup>
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Project items
+  // -->
   <ItemGroup>
     <T4Template Include="Properties\AssemblyInfo.cs">
       <Generator>TextTemplatingFileGenerator</Generator>
@@ -122,17 +161,7 @@
     <Content Include="widget.cpp" />
     <Content Include="widget.h" />
   </ItemGroup>
-  <ItemGroup>
-    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
-  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\transform.targets" />
   <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
 </Project>
diff --git a/Templates/designer/designer.vcxproj.filters b/Templates/designer/designer.vcxproj.filters
index 7b7bab4..c2f3f8d 100644
--- a/Templates/designer/designer.vcxproj.filters
+++ b/Templates/designer/designer.vcxproj.filters
@@ -3,7 +3,7 @@
   <ItemGroup>
     <Filter Include="Source Files">
       <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
-      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+      <Extensions>qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
     </Filter>
     <Filter Include="Header Files">
       <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
@@ -13,6 +13,10 @@
       <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
       <Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
     </Filter>
+    <Filter Include="Form Files">
+      <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
+      <Extensions>ui</Extensions>
+    </Filter>
     <Filter Include="Translation Files">
       <UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>
       <Extensions>ts</Extensions>
diff --git a/Templates/designer/plugin.h b/Templates/designer/plugin.h
index 1f88121..dfdacaa 100644
--- a/Templates/designer/plugin.h
+++ b/Templates/designer/plugin.h
@@ -9,7 +9,7 @@
     Q_INTERFACES(QDesignerCustomWidgetInterface)
 
 public:
-    $plugin_class$(QObject *parent = Q_NULLPTR);
+    $plugin_class$(QObject *parent = nullptr);
 
     bool isContainer() const;
     bool isInitialized() const;
diff --git a/Templates/designer/widget.h b/Templates/designer/widget.h
index abf56e1..8c3d96b 100644
--- a/Templates/designer/widget.h
+++ b/Templates/designer/widget.h
@@ -7,5 +7,5 @@
     Q_OBJECT
 
 public:
-    $classname$(QWidget *parent = Q_NULLPTR);
+    $classname$(QWidget *parent = nullptr);
 };
diff --git a/Templates/dialogbuttonbottom/QtTemplate.Item.DialogButtonBottom.csproj b/Templates/dialogbuttonbottom/QtTemplate.Item.DialogButtonBottom.csproj
index 5c6cf84..decad55 100644
--- a/Templates/dialogbuttonbottom/QtTemplate.Item.DialogButtonBottom.csproj
+++ b/Templates/dialogbuttonbottom/QtTemplate.Item.DialogButtonBottom.csproj
@@ -78,6 +78,45 @@
     <WarningLevel>4</WarningLevel>
     <UseVSHostingProcess>false</UseVSHostingProcess>
   </PropertyGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Global references
+  // -->
+  <ItemGroup>
+    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // General package references
+  // -->
+  <Import Project="$(SolutionDir)\references.props" />
+  <ItemGroup>
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Project items
+  // -->
   <ItemGroup>
     <T4Template Include="Properties\AssemblyInfo.cs">
       <Generator>TextTemplatingFileGenerator</Generator>
@@ -99,17 +138,7 @@
       <SubType>Designer</SubType>
     </VSTemplate>
   </ItemGroup>
-  <ItemGroup>
-    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
-  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\transform.targets" />
   <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
 </Project>
diff --git a/Templates/dialogbuttonright/QtTemplate.Item.DialogButtonRight.csproj b/Templates/dialogbuttonright/QtTemplate.Item.DialogButtonRight.csproj
index ad22581..aec8882 100644
--- a/Templates/dialogbuttonright/QtTemplate.Item.DialogButtonRight.csproj
+++ b/Templates/dialogbuttonright/QtTemplate.Item.DialogButtonRight.csproj
@@ -78,6 +78,45 @@
     <WarningLevel>4</WarningLevel>
     <UseVSHostingProcess>false</UseVSHostingProcess>
   </PropertyGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Global references
+  // -->
+  <ItemGroup>
+    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // General package references
+  // -->
+  <Import Project="$(SolutionDir)\references.props" />
+  <ItemGroup>
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Project items
+  // -->
   <ItemGroup>
     <T4Template Include="Properties\AssemblyInfo.cs">
       <Generator>TextTemplatingFileGenerator</Generator>
@@ -98,17 +137,7 @@
       <OutputSubPath>Qt</OutputSubPath>
     </VSTemplate>
   </ItemGroup>
-  <ItemGroup>
-    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
-  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\transform.targets" />
   <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
 </Project>
diff --git a/Templates/empty/QtTemplate.Project.Empty.csproj b/Templates/empty/QtTemplate.Project.Empty.csproj
index 536168f..1e7bd4e 100644
--- a/Templates/empty/QtTemplate.Project.Empty.csproj
+++ b/Templates/empty/QtTemplate.Project.Empty.csproj
@@ -78,6 +78,45 @@
     <WarningLevel>4</WarningLevel>
     <UseVSHostingProcess>false</UseVSHostingProcess>
   </PropertyGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Global references
+  // -->
+  <ItemGroup>
+    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // General package references
+  // -->
+  <Import Project="$(SolutionDir)\references.props" />
+  <ItemGroup>
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Project items
+  // -->
   <ItemGroup>
     <T4Template Include="Properties\AssemblyInfo.cs">
       <Generator>TextTemplatingFileGenerator</Generator>
@@ -113,17 +152,7 @@
       <DependentUpon>empty.vstemplate_TT</DependentUpon>
     </VSTemplate>
   </ItemGroup>
-  <ItemGroup>
-    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
-  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\transform.targets" />
   <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
 </Project>
diff --git a/Templates/gui/QtTemplate.Project.Gui.csproj b/Templates/gui/QtTemplate.Project.Gui.csproj
index 1b373ae..09a9d4f 100644
--- a/Templates/gui/QtTemplate.Project.Gui.csproj
+++ b/Templates/gui/QtTemplate.Project.Gui.csproj
@@ -76,16 +76,45 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Global references
+  // -->
   <ItemGroup>
-    <Reference Include="Microsoft.VisualStudio.CoreUtility">
-      <Private>False</Private>
-    </Reference>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Xml" />
     <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
   </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // General package references
+  // -->
+  <Import Project="$(SolutionDir)\references.props" />
+  <ItemGroup>
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Project items
+  // -->
   <ItemGroup>
     <T4Template Include="Properties\AssemblyInfo.cs">
       <Generator>TextTemplatingFileGenerator</Generator>
@@ -108,6 +137,7 @@
       <SubType>Designer</SubType>
     </None>
     <None Include="main.cpp" />
+    <None Include="widget.qrc" />
     <None Include="stdafx.cpp" />
     <None Include="stdafx.h" />
     <None Include="widget.cpp" />
@@ -130,13 +160,6 @@
     </VSTemplate>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
   <Import Project="$(SolutionDir)\transform.targets" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
-</Project>
+  <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/Templates/gui/gui.vcxproj.filters b/Templates/gui/gui.vcxproj.filters
index 90f5b7a..b6e7201 100644
--- a/Templates/gui/gui.vcxproj.filters
+++ b/Templates/gui/gui.vcxproj.filters
@@ -3,7 +3,7 @@
   <ItemGroup>
     <Filter Include="Source Files">
       <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
-      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+      <Extensions>qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
     </Filter>
     <Filter Include="Header Files">
       <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
diff --git a/Templates/gui/gui.vstemplate_TT b/Templates/gui/gui.vstemplate_TT
index 7a09db3..33fdd42 100644
--- a/Templates/gui/gui.vstemplate_TT
+++ b/Templates/gui/gui.vstemplate_TT
@@ -71,6 +71,8 @@
             <ProjectItem ReplaceParameters="true"
                          TargetFileName="$safeprojectname$.vcxproj.filters">gui.vcxproj.filters</ProjectItem>
             <ProjectItem ReplaceParameters="false">gui.ico</ProjectItem>
+            <ProjectItem ReplaceParameters="true"
+                         TargetFileName="$qrcfilename$">widget.qrc</ProjectItem>
         </Project>
     </TemplateContent>
     <WizardExtension>
diff --git a/Templates/gui/main.cpp b/Templates/gui/main.cpp
index 6478e3f..d3f5898 100644
--- a/Templates/gui/main.cpp
+++ b/Templates/gui/main.cpp
@@ -4,7 +4,7 @@
 int main(int argc, char *argv[])
 {
     QApplication a(argc, argv);
-    $classname$ w;
+    $namespace$$classname$ w;
     w.show();
     return a.exec();
 }
diff --git a/Templates/gui/widget.cpp b/Templates/gui/widget.cpp
index 28c285b..7718d6f 100644
--- a/Templates/gui/widget.cpp
+++ b/Templates/gui/widget.cpp
@@ -1,7 +1,11 @@
 $include$
 
-$classname$::$classname$(QWidget *parent)
-    : $baseclass$(parent)
+$namespacebegin$$classname$::$classname$(QWidget *parent)
+    : $baseclass$(parent)$new$
 {
-    ui.setupUi(this);
+    $member$$operator$setupUi(this);
 }
+
+$classname$::~$classname$()
+{$delete$}
+$namespaceend$
\ No newline at end of file
diff --git a/Templates/gui/widget.h b/Templates/gui/widget.h
index 578cb5e..68646a0 100644
--- a/Templates/gui/widget.h
+++ b/Templates/gui/widget.h
@@ -2,14 +2,16 @@
 
 #include <QtWidgets/$baseclass$>
 #include "$ui_hdr$"
-
-class $classname$ : public $baseclass$
+$forward_declare_class$
+$namespacebegin$class $classname$ : public $baseclass$$multiple_inheritance$
 {
     Q_OBJECT
 
 public:
-    $classname$(QWidget *parent = Q_NULLPTR);
+    $classname$(QWidget *parent = nullptr);
+    ~$classname$();
 
 private:
-    Ui::$classname$Class ui;
+    $ui_classname$ $asterisk$$member$$semicolon$
 };
+$namespaceend$
\ No newline at end of file
diff --git a/Templates/gui/widget.qrc b/Templates/gui/widget.qrc
new file mode 100644
index 0000000..f0fb159
--- /dev/null
+++ b/Templates/gui/widget.qrc
@@ -0,0 +1,4 @@
+<RCC>
+    <qresource prefix="$classname$">
+    </qresource>
+</RCC>
diff --git a/Templates/lib/QtTemplate.Project.Lib.csproj b/Templates/lib/QtTemplate.Project.Lib.csproj
index 1b7c02e..4065393 100644
--- a/Templates/lib/QtTemplate.Project.Lib.csproj
+++ b/Templates/lib/QtTemplate.Project.Lib.csproj
@@ -78,6 +78,45 @@
     <WarningLevel>4</WarningLevel>
     <UseVSHostingProcess>false</UseVSHostingProcess>
   </PropertyGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Global references
+  // -->
+  <ItemGroup>
+    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // General package references
+  // -->
+  <Import Project="$(SolutionDir)\references.props" />
+  <ItemGroup>
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Project items
+  // -->
   <ItemGroup>
     <T4Template Include="Properties\AssemblyInfo.cs">
       <Generator>TextTemplatingFileGenerator</Generator>
@@ -120,17 +159,7 @@
     <Content Include="stdafx.cpp" />
     <Content Include="stdafx.h" />
   </ItemGroup>
-  <ItemGroup>
-    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
-  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\transform.targets" />
   <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
 </Project>
diff --git a/Templates/lib/lib.vcxproj.filters b/Templates/lib/lib.vcxproj.filters
index 1630278..af524ae 100644
--- a/Templates/lib/lib.vcxproj.filters
+++ b/Templates/lib/lib.vcxproj.filters
@@ -3,7 +3,7 @@
   <ItemGroup>
     <Filter Include="Source Files">
       <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
-      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+      <Extensions>qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
     </Filter>
     <Filter Include="Header Files">
       <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
@@ -13,6 +13,10 @@
       <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
       <Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
     </Filter>
+    <Filter Include="Form Files">
+      <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
+      <Extensions>ui</Extensions>
+    </Filter>
     <Filter Include="Translation Files">
       <UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>
       <Extensions>ts</Extensions>
diff --git a/Templates/mainwindow/QtTemplate.Item.MainWindow.csproj b/Templates/mainwindow/QtTemplate.Item.MainWindow.csproj
index 9683ca1..c2b6ea5 100644
--- a/Templates/mainwindow/QtTemplate.Item.MainWindow.csproj
+++ b/Templates/mainwindow/QtTemplate.Item.MainWindow.csproj
@@ -78,6 +78,45 @@
     <WarningLevel>4</WarningLevel>
     <UseVSHostingProcess>false</UseVSHostingProcess>
   </PropertyGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Global references
+  // -->
+  <ItemGroup>
+    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // General package references
+  // -->
+  <Import Project="$(SolutionDir)\references.props" />
+  <ItemGroup>
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Project items
+  // -->
   <ItemGroup>
     <T4Template Include="Properties\AssemblyInfo.cs">
       <Generator>TextTemplatingFileGenerator</Generator>
@@ -99,17 +138,7 @@
       <SubType>Designer</SubType>
     </VSTemplate>
   </ItemGroup>
-  <ItemGroup>
-    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
-  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\transform.targets" />
   <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
 </Project>
diff --git a/Templates/qml/QtTemplate.Item.QMLFile.csproj b/Templates/qml/QtTemplate.Item.QMLFile.csproj
index 1d26bac..f65cecb 100644
--- a/Templates/qml/QtTemplate.Item.QMLFile.csproj
+++ b/Templates/qml/QtTemplate.Item.QMLFile.csproj
@@ -78,6 +78,45 @@
     <WarningLevel>4</WarningLevel>
     <UseVSHostingProcess>false</UseVSHostingProcess>
   </PropertyGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Global references
+  // -->
+  <ItemGroup>
+    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // General package references
+  // -->
+  <Import Project="$(SolutionDir)\references.props" />
+  <ItemGroup>
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Project items
+  // -->
   <ItemGroup>
     <T4Template Include="Properties\AssemblyInfo.cs">
       <Generator>TextTemplatingFileGenerator</Generator>
@@ -103,17 +142,7 @@
   <ItemGroup>
     <Content Include="qml.ico" />
   </ItemGroup>
-  <ItemGroup>
-    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
-  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\transform.targets" />
   <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
 </Project>
\ No newline at end of file
diff --git a/Templates/qmldir/QtTemplate.Item.QMLDir.csproj b/Templates/qmldir/QtTemplate.Item.QMLDir.csproj
index a3cdb07..d6f9d48 100644
--- a/Templates/qmldir/QtTemplate.Item.QMLDir.csproj
+++ b/Templates/qmldir/QtTemplate.Item.QMLDir.csproj
@@ -78,6 +78,45 @@
     <WarningLevel>4</WarningLevel>
     <UseVSHostingProcess>false</UseVSHostingProcess>
   </PropertyGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Global references
+  // -->
+  <ItemGroup>
+    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // General package references
+  // -->
+  <Import Project="$(SolutionDir)\references.props" />
+  <ItemGroup>
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Project items
+  // -->
   <ItemGroup>
     <T4Template Include="Properties\AssemblyInfo.cs">
       <Generator>TextTemplatingFileGenerator</Generator>
@@ -103,17 +142,7 @@
   <ItemGroup>
     <Content Include="qml.ico" />
   </ItemGroup>
-  <ItemGroup>
-    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
-  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\transform.targets" />
   <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
 </Project>
\ No newline at end of file
diff --git a/Templates/qtclass/Properties/AssemblyInfo.cs b/Templates/qtclass/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..127025e
--- /dev/null
+++ b/Templates/qtclass/Properties/AssemblyInfo.cs
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************
+<#@output extension="tt.cs" #>
+<#@include file="$(SolutionDir)\version.tt" #>
+**              <#=WARNING_GENERATED_FILE#>
+****************************************************************************/
+
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("QtClass")]
+[assembly: AssemblyDescription("The Qt Visual Studio Tools allow developers to use the standard development environment without having to worry about any Qt-related build steps or tools.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Qt Company Ltd.")]
+[assembly: AssemblyProduct("Qt Visual Studio Tools")]
+[assembly: AssemblyCopyright("Copyright (C) 2016-22 The Qt Company Ltd.")]
+[assembly: AssemblyTrademark("The Qt Company Ltd. Qt and their respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("f375c22e-8c6d-4800-ad3a-ff301113dac6")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("<#=QT_VS_TOOLS_VERSION_ASSEMBLY#>")]
+[assembly: AssemblyFileVersion("<#=QT_VS_TOOLS_VERSION_ASSEMBLY_FILE#>")]
diff --git a/Templates/qtclass/QtTemplate.Item.QtClass.csproj b/Templates/qtclass/QtTemplate.Item.QtClass.csproj
new file mode 100644
index 0000000..24cf073
--- /dev/null
+++ b/Templates/qtclass/QtTemplate.Item.QtClass.csproj
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+-->
+<Project ToolsVersion="$(VisualStudioVersion)" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <MinimumVisualStudioVersion>$(VisualStudioVersion)</MinimumVisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <ApplicationIcon>qtclass.ico</ApplicationIcon>
+  </PropertyGroup>
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectTypeGuids>{82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <ProjectGuid>{4981AAE8-9AC7-4758-87EA-FB2397D6C404}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>QtClass</RootNamespace>
+    <AssemblyName>QtClass</AssemblyName>
+    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <GeneratePkgDefFile>false</GeneratePkgDefFile>
+    <IncludeAssemblyInVSIXContainer>false</IncludeAssemblyInVSIXContainer>
+    <IncludeDebugSymbolsInVSIXContainer>false</IncludeDebugSymbolsInVSIXContainer>
+    <IncludeDebugSymbolsInLocalVSIXDeployment>false</IncludeDebugSymbolsInLocalVSIXDeployment>
+    <CreateVsixContainer>false</CreateVsixContainer>
+    <DeployExtension>false</DeployExtension>
+    <DeployVSTemplates>false</DeployVSTemplates>
+    <CopyVsixManifestToOutput>false</CopyVsixManifestToOutput>
+    <CopyBuildOutputToOutputDirectory>false</CopyBuildOutputToOutputDirectory>
+    <CopyOutputSymbolsToOutputDirectory>false</CopyOutputSymbolsToOutputDirectory>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Global references
+  // -->
+  <ItemGroup>
+    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // General package references
+  // -->
+  <Import Project="$(SolutionDir)\references.props" />
+  <ItemGroup>
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Project items
+  // -->
+  <ItemGroup>
+    <T4Template Include="Properties\AssemblyInfo.cs">
+      <Generator>TextTemplatingFileGenerator</Generator>
+      <OutputFile>Properties\AssemblyInfo.tt.cs</OutputFile>
+      <DependsOn>$(SolutionDir)\version.tt;$(SolutionDir)\common.tt</DependsOn>
+      <LastGenOutput>AssemblyInfo.tt.cs</LastGenOutput>
+    </T4Template>
+    <Compile Include="Properties\AssemblyInfo.tt.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>AssemblyInfo.cs</DependentUpon>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="header.h" />
+    <None Include="source.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <T4Template Include="qtclass.vstemplate_TT">
+      <Generator>TextTemplatingFileGenerator</Generator>
+      <OutputFile>qtclass.vstemplate</OutputFile>
+      <DependsOn>$(SolutionDir)\version.tt;$(SolutionDir)\common.tt</DependsOn>
+      <LastGenOutput>qtclass.vstemplate</LastGenOutput>
+      <SubType>Designer</SubType>
+    </T4Template>
+    <VSTemplate Include="qtclass.vstemplate">
+      <SubType>Designer</SubType>
+      <OutputSubPath>Qt</OutputSubPath>
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>qtclass.vstemplate_TT</DependentUpon>
+    </VSTemplate>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="qtclass.ico" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(SolutionDir)\transform.targets" />
+  <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/Templates/qtclass/header.h b/Templates/qtclass/header.h
new file mode 100644
index 0000000..8495cfc
--- /dev/null
+++ b/Templates/qtclass/header.h
@@ -0,0 +1,9 @@
+#pragma once
+
+$baseclassinclude$$namespacebegin$class $classname$ $baseclassdecl$
+{$qobject$
+public:
+    $classname$($signature$);
+    ~$classname$();
+};
+$namespaceend$
\ No newline at end of file
diff --git a/Templates/qtclass/qtclass.ico b/Templates/qtclass/qtclass.ico
new file mode 100644
index 0000000..1c4fb80
--- /dev/null
+++ b/Templates/qtclass/qtclass.ico
Binary files differ
diff --git a/Templates/qtclass/qtclass.vstemplate_TT b/Templates/qtclass/qtclass.vstemplate_TT
new file mode 100644
index 0000000..b0ab4d8
--- /dev/null
+++ b/Templates/qtclass/qtclass.vstemplate_TT
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    *****************************************************************************
+    **
+    ** Copyright (C) 2022 The Qt Company Ltd.
+    ** Contact: https://www.qt.io/licensing/
+    **
+    ** This file is part of the Qt VS Tools.
+    **
+    ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+    ** Commercial License Usage
+    ** Licensees holding valid commercial Qt licenses may use this file in
+    ** accordance with the commercial license agreement provided with the
+    ** Software or, alternatively, in accordance with the terms contained in
+    ** a written agreement between you and The Qt Company. For licensing terms
+    ** and conditions see https://www.qt.io/terms-conditions. For further
+    ** information use the contact form at https://www.qt.io/contact-us.
+    **
+    ** GNU General Public License Usage
+    ** Alternatively, this file may be used under the terms of the GNU
+    ** General Public License version 3 as published by the Free Software
+    ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+    ** included in the packaging of this file. Please review the following
+    ** information to ensure the GNU General Public License requirements will
+    ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+    **
+    ** $QT_END_LICENSE$
+    **
+    *****************************************************************************
+<#@output extension="vstemplate" #>
+<#@include file="$(SolutionDir)\version.tt" #>
+    **          <#=WARNING_GENERATED_FILE#>
+    *****************************************************************************
+-->
+
+<VSTemplate Version="3.0.0"
+            xmlns="http://schemas.microsoft.com/developer/vstemplate/2005"
+            xmlns:sdk="http://schemas.microsoft.com/developer/vstemplate-sdkextension/2010"
+            Type="Item" >
+    <TemplateData>
+        <Name>Qt Class</Name>
+        <Description>Adds a Qt class to the project.</Description>
+        <ProjectType>VC</ProjectType>
+        <CreateNewFolder>true</CreateNewFolder>
+        <DefaultName>QtClass</DefaultName>
+        <ProvideDefaultName>true</ProvideDefaultName>
+        <LocationField>Enabled</LocationField>
+        <EnableLocationBrowseButton>true</EnableLocationBrowseButton>
+        <Icon>qtclass.ico</Icon>
+        <LanguageTag>Cpp</LanguageTag>
+        <PlatformTag>Windows</PlatformTag>
+        <PlatformTag>Linux</PlatformTag>
+        <ProjectTypeTag>Qt</ProjectTypeTag>
+        <ProjectTypeTag>IoT</ProjectTypeTag>
+        <ProjectTypeTag>Desktop</ProjectTypeTag>
+        <ProjectTypeTag>Console</ProjectTypeTag>
+    </TemplateData>
+    <TemplateContent>
+        <ProjectItem OpenInEditor="true"
+                     ReplaceParameters="true"
+                     TargetFileName="$sourcefilename$">source.cpp</ProjectItem>
+        <ProjectItem ReplaceParameters="true"
+                     TargetFileName="$headerfilename$">header.h</ProjectItem>
+    </TemplateContent>
+    <WizardExtension>
+        <!-- BEGIN Generated Text <#=XML_COMMENT_END#>
+        <Assembly>QtVsTools.Wizards, Version=<#=QT_VS_TOOLS_VERSION_ASSEMBLY#>, Culture=neutral, PublicKeyToken=null</Assembly>
+        <#=XML_COMMENT_BEGIN#> END Generated Text -->
+        <FullClassName>QtVsTools.Wizards.ItemWizard.QtClassWizard</FullClassName>
+    </WizardExtension>
+</VSTemplate>
diff --git a/Templates/qtclass/source.cpp b/Templates/qtclass/source.cpp
new file mode 100644
index 0000000..7bdcd06
--- /dev/null
+++ b/Templates/qtclass/source.cpp
@@ -0,0 +1,8 @@
+$include$
+
+$namespacebegin$$classname$::$classname$($signature$)$baseclasswithparent$
+{}
+
+$classname$::~$classname$()
+{}
+$namespaceend$
\ No newline at end of file
diff --git a/Templates/quick/QtTemplate.Project.Quick.csproj b/Templates/quick/QtTemplate.Project.Quick.csproj
index 3137fb0..1fa7f47 100644
--- a/Templates/quick/QtTemplate.Project.Quick.csproj
+++ b/Templates/quick/QtTemplate.Project.Quick.csproj
@@ -78,6 +78,45 @@
     <WarningLevel>4</WarningLevel>
     <UseVSHostingProcess>false</UseVSHostingProcess>
   </PropertyGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Global references
+  // -->
+  <ItemGroup>
+    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // General package references
+  // -->
+  <Import Project="$(SolutionDir)\references.props" />
+  <ItemGroup>
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Project items
+  // -->
   <ItemGroup>
     <T4Template Include="Properties\AssemblyInfo.cs">
       <Generator>TextTemplatingFileGenerator</Generator>
@@ -114,9 +153,6 @@
       <DesignTime>True</DesignTime>
       <DependentUpon>quick.vstemplate_TT</DependentUpon>
     </VSTemplate>
-  </ItemGroup>
-  <ItemGroup>
-    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
   </ItemGroup>
   <ItemGroup>
     <Content Include="main.cpp" />
diff --git a/Templates/quick/quick.vcxproj.filters b/Templates/quick/quick.vcxproj.filters
index 1ed1ade..a26deb6 100644
--- a/Templates/quick/quick.vcxproj.filters
+++ b/Templates/quick/quick.vcxproj.filters
@@ -13,6 +13,10 @@
       <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
       <Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
     </Filter>
+    <Filter Include="Form Files">
+      <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
+      <Extensions>ui</Extensions>
+    </Filter>
     <Filter Include="Translation Files">
       <UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>
       <Extensions>ts</Extensions>
diff --git a/Templates/resource/QtTemplate.Item.Resource.csproj b/Templates/resource/QtTemplate.Item.Resource.csproj
index 6881f8a..7e22911 100644
--- a/Templates/resource/QtTemplate.Item.Resource.csproj
+++ b/Templates/resource/QtTemplate.Item.Resource.csproj
@@ -78,6 +78,45 @@
     <WarningLevel>4</WarningLevel>
     <UseVSHostingProcess>false</UseVSHostingProcess>
   </PropertyGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Global references
+  // -->
+  <ItemGroup>
+    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // General package references
+  // -->
+  <Import Project="$(SolutionDir)\references.props" />
+  <ItemGroup>
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Project items
+  // -->
   <ItemGroup>
     <T4Template Include="Properties\AssemblyInfo.cs">
       <Generator>TextTemplatingFileGenerator</Generator>
@@ -103,17 +142,7 @@
   <ItemGroup>
     <Content Include="resource.ico" />
   </ItemGroup>
-  <ItemGroup>
-    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
-  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\transform.targets" />
   <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
 </Project>
diff --git a/Templates/server/QtTemplate.Project.Server.csproj b/Templates/server/QtTemplate.Project.Server.csproj
index b30bb48..4c24a53 100644
--- a/Templates/server/QtTemplate.Project.Server.csproj
+++ b/Templates/server/QtTemplate.Project.Server.csproj
@@ -78,6 +78,45 @@
     <WarningLevel>4</WarningLevel>
     <UseVSHostingProcess>false</UseVSHostingProcess>
   </PropertyGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Global references
+  // -->
+  <ItemGroup>
+    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // General package references
+  // -->
+  <Import Project="$(SolutionDir)\references.props" />
+  <ItemGroup>
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Project items
+  // -->
   <ItemGroup>
     <T4Template Include="Properties\AssemblyInfo.cs">
       <Generator>TextTemplatingFileGenerator</Generator>
@@ -122,17 +161,7 @@
     <Content Include="stdafx.h" />
     <Content Include="widget.ui" />
   </ItemGroup>
-  <ItemGroup>
-    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
-  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\transform.targets" />
   <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
 </Project>
diff --git a/Templates/server/header.h b/Templates/server/header.h
index b3a1e6e..f404141 100644
--- a/Templates/server/header.h
+++ b/Templates/server/header.h
@@ -10,7 +10,7 @@
     Q_OBJECT
 
 public:
-    $classname$(QWidget *parent = Q_NULLPTR);
+    $classname$(QWidget *parent = nullptr);
 
 private:
     Ui::$classname$Class ui;
diff --git a/Templates/server/server.vcxproj.filters b/Templates/server/server.vcxproj.filters
index 1dca9ac..eb9be8d 100644
--- a/Templates/server/server.vcxproj.filters
+++ b/Templates/server/server.vcxproj.filters
@@ -3,7 +3,7 @@
   <ItemGroup>
     <Filter Include="Source Files">
       <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
-      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+      <Extensions>qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
     </Filter>
     <Filter Include="Header Files">
       <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
diff --git a/Templates/translation/Properties/AssemblyInfo.cs b/Templates/translation/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..7fcd1b7
--- /dev/null
+++ b/Templates/translation/Properties/AssemblyInfo.cs
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************
+<#@output extension="tt.cs" #>
+<#@include file="$(SolutionDir)\version.tt" #>
+**              <#=WARNING_GENERATED_FILE#>
+****************************************************************************/
+
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Translation")]
+[assembly: AssemblyDescription("The Qt Visual Studio Tools allow developers to use the standard development environment without having to worry about any Qt-related build steps or tools.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Qt Company Ltd.")]
+[assembly: AssemblyProduct("Qt Visual Studio Tools")]
+[assembly: AssemblyCopyright("Copyright (C) 2016-2022 The Qt Company Ltd.")]
+[assembly: AssemblyTrademark("The Qt Company Ltd. Qt and their respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("131278ae-99ef-45c0-8455-423ee8f123dc")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("<#=QT_VS_TOOLS_VERSION_ASSEMBLY#>")]
+[assembly: AssemblyFileVersion("<#=QT_VS_TOOLS_VERSION_ASSEMBLY_FILE#>")]
diff --git a/Templates/translation/QtTemplate.Item.Translation.csproj b/Templates/translation/QtTemplate.Item.Translation.csproj
new file mode 100644
index 0000000..3b9a576
--- /dev/null
+++ b/Templates/translation/QtTemplate.Item.Translation.csproj
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+-->
+<Project ToolsVersion="$(VisualStudioVersion)" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <MinimumVisualStudioVersion>$(VisualStudioVersion)</MinimumVisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <ApplicationIcon>translation.ico</ApplicationIcon>
+  </PropertyGroup>
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectTypeGuids>{82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <ProjectGuid>{202F4A6D-77CD-4992-AA53-01B585463287}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Translation</RootNamespace>
+    <AssemblyName>Translation</AssemblyName>
+    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <GeneratePkgDefFile>false</GeneratePkgDefFile>
+    <IncludeAssemblyInVSIXContainer>false</IncludeAssemblyInVSIXContainer>
+    <IncludeDebugSymbolsInVSIXContainer>false</IncludeDebugSymbolsInVSIXContainer>
+    <IncludeDebugSymbolsInLocalVSIXDeployment>false</IncludeDebugSymbolsInLocalVSIXDeployment>
+    <CreateVsixContainer>false</CreateVsixContainer>
+    <DeployExtension>false</DeployExtension>
+    <DeployVSTemplates>false</DeployVSTemplates>
+    <CopyVsixManifestToOutput>false</CopyVsixManifestToOutput>
+    <CopyBuildOutputToOutputDirectory>false</CopyBuildOutputToOutputDirectory>
+    <CopyOutputSymbolsToOutputDirectory>false</CopyOutputSymbolsToOutputDirectory>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Global references
+  // -->
+  <ItemGroup>
+    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // General package references
+  // -->
+  <Import Project="$(SolutionDir)\references.props" />
+  <ItemGroup>
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Project items
+  // -->
+  <ItemGroup>
+    <T4Template Include="Properties\AssemblyInfo.cs">
+      <Generator>TextTemplatingFileGenerator</Generator>
+      <OutputFile>Properties\AssemblyInfo.tt.cs</OutputFile>
+      <DependsOn>$(SolutionDir)\version.tt;$(SolutionDir)\common.tt</DependsOn>
+      <LastGenOutput>AssemblyInfo.tt.cs</LastGenOutput>
+    </T4Template>
+    <Compile Include="Properties\AssemblyInfo.tt.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>AssemblyInfo.cs</DependentUpon>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="translation.ts" />
+  </ItemGroup>
+  <ItemGroup>
+    <T4Template Include="translation.vstemplate_TT">
+      <Generator>TextTemplatingFileGenerator</Generator>
+      <OutputFile>translation.vstemplate</OutputFile>
+      <DependsOn>$(SolutionDir)\version.tt;$(SolutionDir)\common.tt</DependsOn>
+      <LastGenOutput>translation.vstemplate</LastGenOutput>
+    </T4Template>
+    <VSTemplate Include="translation.vstemplate">
+      <SubType>Designer</SubType>
+      <OutputSubPath>Qt</OutputSubPath>
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>translation.vstemplate_TT</DependentUpon>
+    </VSTemplate>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="translation.ico" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(SolutionDir)\transform.targets" />
+  <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/Templates/translation/translation.ico b/Templates/translation/translation.ico
new file mode 100644
index 0000000..1c4fb80
--- /dev/null
+++ b/Templates/translation/translation.ico
Binary files differ
diff --git a/Templates/translation/translation.ts b/Templates/translation/translation.ts
new file mode 100644
index 0000000..fda00e7
--- /dev/null
+++ b/Templates/translation/translation.ts
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS >
+<TS version="2.1" language="$cultureinfoname$">
+</TS>
diff --git a/Templates/translation/translation.vstemplate_TT b/Templates/translation/translation.vstemplate_TT
new file mode 100644
index 0000000..6ec4f47
--- /dev/null
+++ b/Templates/translation/translation.vstemplate_TT
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    *****************************************************************************
+    **
+    ** Copyright (C) 2022 The Qt Company Ltd.
+    ** Contact: https://www.qt.io/licensing/
+    **
+    ** This file is part of the Qt VS Tools.
+    **
+    ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+    ** Commercial License Usage
+    ** Licensees holding valid commercial Qt licenses may use this file in
+    ** accordance with the commercial license agreement provided with the
+    ** Software or, alternatively, in accordance with the terms contained in
+    ** a written agreement between you and The Qt Company. For licensing terms
+    ** and conditions see https://www.qt.io/terms-conditions. For further
+    ** information use the contact form at https://www.qt.io/contact-us.
+    **
+    ** GNU General Public License Usage
+    ** Alternatively, this file may be used under the terms of the GNU
+    ** General Public License version 3 as published by the Free Software
+    ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+    ** included in the packaging of this file. Please review the following
+    ** information to ensure the GNU General Public License requirements will
+    ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+    **
+    ** $QT_END_LICENSE$
+    **
+    *****************************************************************************
+<#@output extension="vstemplate" #>
+<#@include file="$(SolutionDir)\version.tt" #>
+    **          <#=WARNING_GENERATED_FILE#>
+    *****************************************************************************
+-->
+
+<VSTemplate Version="3.0.0"
+            xmlns="http://schemas.microsoft.com/developer/vstemplate/2005"
+            xmlns:sdk="http://schemas.microsoft.com/developer/vstemplate-sdkextension/2010"
+            Type="Item">
+    <TemplateData>
+        <Name>Qt Translation File</Name>
+        <Description>Qt Translation File (.ts)</Description>
+        <ProjectType>VC</ProjectType>
+        <DefaultName>Translation.ts</DefaultName>
+        <ProvideDefaultName>true</ProvideDefaultName>
+        <LocationField>Enabled</LocationField>
+        <EnableLocationBrowseButton>true</EnableLocationBrowseButton>
+        <Icon>translation.ico</Icon>
+        <LanguageTag>Cpp</LanguageTag>
+        <PlatformTag>Windows</PlatformTag>
+        <PlatformTag>Linux</PlatformTag>
+        <ProjectTypeTag>Qt</ProjectTypeTag>
+        <ProjectTypeTag>Desktop</ProjectTypeTag>
+        <AppliesTo>VisualC</AppliesTo>
+        <TemplateGroupID>QtVsTools</TemplateGroupID>
+        <TemplateID>QtVsTools-QTranslation</TemplateID>
+    </TemplateData>
+    <TemplateContent>
+        <ProjectItem OpenInEditor="false"
+                     ReplaceParameters="true"
+                     TargetFileName="$tsfilename$">translation.ts</ProjectItem>
+    </TemplateContent>
+    <WizardExtension>
+        <!-- BEGIN Generated Text <#=XML_COMMENT_END#>
+        <Assembly>QtVsTools.Wizards, Version=<#=QT_VS_TOOLS_VERSION_ASSEMBLY#>, Culture=neutral, PublicKeyToken=null</Assembly>
+        <#=XML_COMMENT_BEGIN#> END Generated Text -->
+        <FullClassName>QtVsTools.Wizards.ItemWizard.TranslationWizard</FullClassName>
+    </WizardExtension>
+</VSTemplate>
diff --git a/Templates/widget/QtTemplate.Item.Widget.csproj b/Templates/widget/QtTemplate.Item.Widget.csproj
index c31a8ea..b843926 100644
--- a/Templates/widget/QtTemplate.Item.Widget.csproj
+++ b/Templates/widget/QtTemplate.Item.Widget.csproj
@@ -78,6 +78,45 @@
     <WarningLevel>4</WarningLevel>
     <UseVSHostingProcess>false</UseVSHostingProcess>
   </PropertyGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Global references
+  // -->
+  <ItemGroup>
+    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // General package references
+  // -->
+  <Import Project="$(SolutionDir)\references.props" />
+  <ItemGroup>
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Project items
+  // -->
   <ItemGroup>
     <T4Template Include="Properties\AssemblyInfo.cs">
       <Generator>TextTemplatingFileGenerator</Generator>
@@ -98,17 +137,7 @@
       <OutputSubPath>Qt</OutputSubPath>
     </VSTemplate>
   </ItemGroup>
-  <ItemGroup>
-    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
-  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\transform.targets" />
   <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
 </Project>
diff --git a/Templates/widgetsclass/Properties/AssemblyInfo.cs b/Templates/widgetsclass/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..e8d8a9c
--- /dev/null
+++ b/Templates/widgetsclass/Properties/AssemblyInfo.cs
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************
+<#@output extension="tt.cs" #>
+<#@include file="$(SolutionDir)\version.tt" #>
+**              <#=WARNING_GENERATED_FILE#>
+****************************************************************************/
+
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("WidgetsClass")]
+[assembly: AssemblyDescription("The Qt Visual Studio Tools allow developers to use the standard development environment without having to worry about any Qt-related build steps or tools.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("The Qt Company Ltd.")]
+[assembly: AssemblyProduct("Qt Visual Studio Tools")]
+[assembly: AssemblyCopyright("Copyright (C) 2016-2022 The Qt Company Ltd.")]
+[assembly: AssemblyTrademark("The Qt Company Ltd. Qt and their respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("665d1b79-1498-4d1a-8376-58394e150276")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("<#=QT_VS_TOOLS_VERSION_ASSEMBLY#>")]
+[assembly: AssemblyFileVersion("<#=QT_VS_TOOLS_VERSION_ASSEMBLY_FILE#>")]
diff --git a/Templates/widgetsclass/QtTemplate.Item.WidgetsClass.csproj b/Templates/widgetsclass/QtTemplate.Item.WidgetsClass.csproj
new file mode 100644
index 0000000..5dbb07f
--- /dev/null
+++ b/Templates/widgetsclass/QtTemplate.Item.WidgetsClass.csproj
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+-->
+<Project ToolsVersion="$(VisualStudioVersion)" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <MinimumVisualStudioVersion>$(VisualStudioVersion)</MinimumVisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <ApplicationIcon>widgetsclass.ico</ApplicationIcon>
+  </PropertyGroup>
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectTypeGuids>{82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <ProjectGuid>{020422DA-33AB-4495-A439-7DAC2690795C}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>WidgetsClass</RootNamespace>
+    <AssemblyName>WidgetsClass</AssemblyName>
+    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <GeneratePkgDefFile>false</GeneratePkgDefFile>
+    <IncludeAssemblyInVSIXContainer>false</IncludeAssemblyInVSIXContainer>
+    <IncludeDebugSymbolsInVSIXContainer>false</IncludeDebugSymbolsInVSIXContainer>
+    <IncludeDebugSymbolsInLocalVSIXDeployment>false</IncludeDebugSymbolsInLocalVSIXDeployment>
+    <CreateVsixContainer>false</CreateVsixContainer>
+    <DeployExtension>false</DeployExtension>
+    <DeployVSTemplates>false</DeployVSTemplates>
+    <CopyVsixManifestToOutput>false</CopyVsixManifestToOutput>
+    <CopyBuildOutputToOutputDirectory>false</CopyBuildOutputToOutputDirectory>
+    <CopyOutputSymbolsToOutputDirectory>false</CopyOutputSymbolsToOutputDirectory>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Global references
+  // -->
+  <ItemGroup>
+    <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // General package references
+  // -->
+  <Import Project="$(SolutionDir)\references.props" />
+  <ItemGroup>
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+        <PackageReference Include="$(Name_Microsoft_VisualStudio_Validation)" Version="$(Version_Microsoft_VisualStudio_Validation)" />
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Project items
+  // -->
+  <ItemGroup>
+    <T4Template Include="Properties\AssemblyInfo.cs">
+      <Generator>TextTemplatingFileGenerator</Generator>
+      <OutputFile>Properties\AssemblyInfo.tt.cs</OutputFile>
+      <DependsOn>$(SolutionDir)\version.tt;$(SolutionDir)\common.tt</DependsOn>
+      <LastGenOutput>AssemblyInfo.tt.cs</LastGenOutput>
+    </T4Template>
+    <Compile Include="Properties\AssemblyInfo.tt.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>AssemblyInfo.cs</DependentUpon>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="widget.cpp" />
+    <None Include="widget.h" />
+    <None Include="widget.ui" />
+  </ItemGroup>
+  <ItemGroup>
+    <T4Template Include="widgetsclass.vstemplate_TT">
+      <Generator>TextTemplatingFileGenerator</Generator>
+      <OutputFile>widgetsclass.vstemplate</OutputFile>
+      <DependsOn>$(SolutionDir)\version.tt;$(SolutionDir)\common.tt</DependsOn>
+      <LastGenOutput>widgetsclass.vstemplate</LastGenOutput>
+    </T4Template>
+    <VSTemplate Include="widgetsclass.vstemplate">
+      <SubType>Designer</SubType>
+      <OutputSubPath>Qt</OutputSubPath>
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>widgetsclass.vstemplate_TT</DependentUpon>
+    </VSTemplate>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="widgetsclass.ico" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(SolutionDir)\transform.targets" />
+  <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/Templates/widgetsclass/widget.cpp b/Templates/widgetsclass/widget.cpp
new file mode 100644
index 0000000..7718d6f
--- /dev/null
+++ b/Templates/widgetsclass/widget.cpp
@@ -0,0 +1,11 @@
+$include$
+
+$namespacebegin$$classname$::$classname$(QWidget *parent)
+    : $baseclass$(parent)$new$
+{
+    $member$$operator$setupUi(this);
+}
+
+$classname$::~$classname$()
+{$delete$}
+$namespaceend$
\ No newline at end of file
diff --git a/Templates/widgetsclass/widget.h b/Templates/widgetsclass/widget.h
new file mode 100644
index 0000000..e0cb40e
--- /dev/null
+++ b/Templates/widgetsclass/widget.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <$baseclass$>
+#include "$ui_hdr$"
+$forward_declare_class$
+$namespacebegin$class $classname$ : public $baseclass$$multiple_inheritance$
+{$qobject$
+public:
+    $classname$(QWidget *parent = nullptr);
+    ~$classname$();
+
+private:
+    $ui_classname$ $asterisk$$member$$semicolon$
+};
+$namespaceend$
\ No newline at end of file
diff --git a/Templates/widgetsclass/widget.ui b/Templates/widgetsclass/widget.ui
new file mode 100644
index 0000000..74c429e
--- /dev/null
+++ b/Templates/widgetsclass/widget.ui
@@ -0,0 +1,22 @@
+<UI version="4.0" >
+ <class>$classname$Class</class>
+ <widget class="$baseclass$" name="$classname$Class" >
+  <property name="objectName" >
+   <string notr="true">$classname$Class</string>
+  </property>
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>600</width>
+    <height>400</height>
+   </rect>
+  </property>
+  <property name="windowTitle" >
+   <string>$classname$</string>
+  </property>$centralwidget$
+ </widget>
+ <layoutDefault spacing="6" margin="11" />
+ <pixmapfunction></pixmapfunction>
+ <connections/>
+</UI>
diff --git a/Templates/widgetsclass/widgetsclass.ico b/Templates/widgetsclass/widgetsclass.ico
new file mode 100644
index 0000000..1c4fb80
--- /dev/null
+++ b/Templates/widgetsclass/widgetsclass.ico
Binary files differ
diff --git a/Templates/widgetsclass/widgetsclass.vstemplate_TT b/Templates/widgetsclass/widgetsclass.vstemplate_TT
new file mode 100644
index 0000000..89c5e79
--- /dev/null
+++ b/Templates/widgetsclass/widgetsclass.vstemplate_TT
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    *****************************************************************************
+    **
+    ** Copyright (C) 2022 The Qt Company Ltd.
+    ** Contact: https://www.qt.io/licensing/
+    **
+    ** This file is part of the Qt VS Tools.
+    **
+    ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+    ** Commercial License Usage
+    ** Licensees holding valid commercial Qt licenses may use this file in
+    ** accordance with the commercial license agreement provided with the
+    ** Software or, alternatively, in accordance with the terms contained in
+    ** a written agreement between you and The Qt Company. For licensing terms
+    ** and conditions see https://www.qt.io/terms-conditions. For further
+    ** information use the contact form at https://www.qt.io/contact-us.
+    **
+    ** GNU General Public License Usage
+    ** Alternatively, this file may be used under the terms of the GNU
+    ** General Public License version 3 as published by the Free Software
+    ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+    ** included in the packaging of this file. Please review the following
+    ** information to ensure the GNU General Public License requirements will
+    ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+    **
+    ** $QT_END_LICENSE$
+    **
+    *****************************************************************************
+<#@output extension="vstemplate" #>
+<#@include file="$(SolutionDir)\version.tt" #>
+    **          <#=WARNING_GENERATED_FILE#>
+    *****************************************************************************
+-->
+
+<VSTemplate Version="3.0.0"
+            xmlns="http://schemas.microsoft.com/developer/vstemplate/2005"
+            xmlns:sdk="http://schemas.microsoft.com/developer/vstemplate-sdkextension/2010"
+            Type="Item" >
+    <TemplateData>
+        <Name>Qt Widgets Class</Name>
+        <Description>Adds a Qt Widgets class to the project.</Description>
+        <ProjectType>VC</ProjectType>
+        <DefaultName>QtWidgetsClass</DefaultName>
+        <ProvideDefaultName>true</ProvideDefaultName>
+        <LocationField>Enabled</LocationField>
+        <EnableLocationBrowseButton>true</EnableLocationBrowseButton>
+        <Icon>widgetsclass.ico</Icon>
+        <LanguageTag>Cpp</LanguageTag>
+        <PlatformTag>Windows</PlatformTag>
+        <PlatformTag>Linux</PlatformTag>
+        <ProjectTypeTag>Qt</ProjectTypeTag>
+        <ProjectTypeTag>Desktop</ProjectTypeTag>
+    </TemplateData>
+    <TemplateContent>
+        <ProjectItem OpenInEditor="true"
+                     ReplaceParameters="true"
+                     TargetFileName="$sourcefilename$">widget.cpp</ProjectItem>
+        <ProjectItem ReplaceParameters="true"
+                     TargetFileName="$headerfilename$">widget.h</ProjectItem>
+        <ProjectItem ReplaceParameters="true"
+                     TargetFileName="$uifilename$">widget.ui</ProjectItem>
+    </TemplateContent>
+    <WizardExtension>
+      <!-- BEGIN Generated Text <#=XML_COMMENT_END#>
+        <Assembly>QtVsTools.Wizards, Version=<#=QT_VS_TOOLS_VERSION_ASSEMBLY#>, Culture=neutral, PublicKeyToken=null</Assembly>
+        <#=XML_COMMENT_BEGIN#> END Generated Text -->
+      <FullClassName>QtVsTools.Wizards.ItemWizard.WidgetsClassWizard</FullClassName>
+    </WizardExtension>
+</VSTemplate>
diff --git a/Tests/BigSolution/generator/Program.cs b/Tests/BigSolution/generator/Program.cs
index 6100ac6..5624762 100644
--- a/Tests/BigSolution/generator/Program.cs
+++ b/Tests/BigSolution/generator/Program.cs
@@ -38,51 +38,27 @@
 {
     internal class Program
     {
-        static void Main(string[] args)
+        static void GenerateProject(
+            StringBuilder genSolutionProjectRef,
+            StringBuilder genSolutionProjectConfigs,
+            string pathToTemplateDir,
+            string pathToGeneratedDir,
+            int projectCount,
+            string projectGuid,
+            string projectName,
+            string projectRef,
+            IEnumerable<string> projectConfigsList)
         {
-            var projectCount = args.Length > 0 ? Convert.ToInt32(args[0]) : 400;
-            var pathToTemplateDir = Path.GetFullPath(@"..\..\..\template");
-            var pathToGeneratedDir = Path.GetFullPath(@"..\..\..\generated");
-            var templateFiles = Directory.GetFiles(
-                pathToTemplateDir, "*", SearchOption.AllDirectories);
-            var solutionFilePath = templateFiles
-                .Where(x => Path.GetExtension(x) == ".sln")
-                .First();
-            var solutionName = Path.GetFileName(solutionFilePath);
-            var solutionText = File.ReadAllText(solutionFilePath);
-            var projectFilePath = templateFiles
-                .Where(x => Path.GetExtension(x) == ".vcxproj")
-                .First();
-            var projectText = File.ReadAllText(projectFilePath);
-            var projectName = Path.GetFileNameWithoutExtension(projectFilePath);
-            var projectGuidMatch = Regex.Match(projectText, @"<ProjectGuid>({[^}]+})<");
-            var projectGuid = projectGuidMatch.Groups[1].Value;
-
-            var projectRef = Regex
-                .Match(solutionText,
-                    @"^Project.*" + projectGuid + @"""\r\nEndProject\r\n", RegexOptions.Multiline)
-                .Value;
-
-            var projectConfigsList = Regex
-                .Matches(solutionText,
-                    @"^\s+" + projectGuid + @".*\r\n", RegexOptions.Multiline)
-                .Cast<Match>()
-                .Select(x => x.Value);
-            var projectConfigs = string.Join("", projectConfigsList);
-
             var projectFiles = Directory.GetFiles(
                 Path.Combine(pathToTemplateDir, projectName),
                 "*", SearchOption.TopDirectoryOnly);
 
-            if (Directory.Exists(pathToGeneratedDir))
-                Directory.Delete(pathToGeneratedDir, true);
-
-            var genSolutionProjectRef = new StringBuilder();
-            var genSolutionProjectConfigs = new StringBuilder();
-
-            for (int i = 1; i <= projectCount; i++) {
+            bool singleProject = false;
+            for (int i = 1; !singleProject && i <= projectCount; i++) {
                 var idxStr = string.Format("{0:D3}", i);
                 var genProjectName = projectName.Replace("NNN", idxStr);
+                if (genProjectName == projectName)
+                    singleProject = true;
                 var genProjectDirPath = Path.Combine(pathToGeneratedDir, genProjectName);
                 var genProjectGuid = projectGuid.Replace("000", idxStr);
 
@@ -110,9 +86,66 @@
                     genSolutionProjectConfigs.Append(genProjectConfig);
                 }
             }
-            var genSolutionText = solutionText
-                .Replace(projectRef, genSolutionProjectRef.ToString())
-                .Replace(projectConfigs, genSolutionProjectConfigs.ToString());
+        }
+
+        static void Main(string[] args)
+        {
+            int projectCount;
+            if (args.Length == 0 || !int.TryParse(args[0], out projectCount)) {
+                string userProjectCount;
+                do {
+                    Console.Write("Project count: ");
+                    userProjectCount = Console.ReadLine();
+                } while (!int.TryParse(userProjectCount, out projectCount));
+            }
+            var pathToTemplateDir = Path.GetFullPath(@"..\..\..\template");
+            var pathToGeneratedDir = Path.GetFullPath(
+                $@"..\..\..\generated_{DateTime.Now.ToString("yyyyMMddhhmmssfff")}");
+            var templateFiles = Directory.GetFiles(
+                pathToTemplateDir, "*", SearchOption.AllDirectories);
+            var solutionFilePath = templateFiles
+                .Where(x => Path.GetExtension(x) == ".sln")
+                .First();
+            var solutionName = Path.GetFileName(solutionFilePath);
+            var solutionText = File.ReadAllText(solutionFilePath);
+            var projectFilePaths = templateFiles
+                .Where(x => Path.GetExtension(x) == ".vcxproj");
+            var genSolutionText = solutionText;
+            if (Directory.Exists(pathToGeneratedDir))
+                Directory.Delete(pathToGeneratedDir, true);
+            foreach (var projectFilePath in projectFilePaths) {
+                var genSolutionProjectRef = new StringBuilder();
+                var genSolutionProjectConfigs = new StringBuilder();
+                var projectText = File.ReadAllText(projectFilePath);
+                var projectName = Path.GetFileNameWithoutExtension(projectFilePath);
+                var projectGuidMatch = Regex.Match(projectText, @"<ProjectGuid>({[^}]+})<");
+                var projectGuid = projectGuidMatch.Groups[1].Value;
+                var projectRef = Regex
+                    .Match(solutionText,
+                        @"^Project.*" + projectGuid + @"""\r\nEndProject\r\n",
+                        RegexOptions.Multiline | RegexOptions.IgnoreCase)
+                    .Value;
+                var projectConfigsList = Regex
+                    .Matches(solutionText,
+                        @"^\s+" + projectGuid + @".*\r\n",
+                        RegexOptions.Multiline | RegexOptions.IgnoreCase)
+                    .Cast<Match>()
+                    .Select(x => x.Value);
+                var projectConfigs = string.Join("", projectConfigsList);
+                GenerateProject(
+                    genSolutionProjectRef,
+                    genSolutionProjectConfigs,
+                    pathToTemplateDir,
+                    pathToGeneratedDir,
+                    projectCount,
+                    projectGuid,
+                    projectName,
+                    projectRef,
+                    projectConfigsList);
+                genSolutionText = genSolutionText
+                    .Replace(projectRef, genSolutionProjectRef.ToString())
+                    .Replace(projectConfigs, genSolutionProjectConfigs.ToString());
+            }
             var genSolutionFilePath = Path.Combine(pathToGeneratedDir, solutionName);
             File.WriteAllText(genSolutionFilePath, genSolutionText);
         }
diff --git a/Tests/BigSolution/template/BigProjectNNN/BigProjectNNN.vcxproj b/Tests/BigSolution/template/BigProjectNNN/BigProjectNNN.vcxproj
index 2ec9d1f..886f40a 100644
--- a/Tests/BigSolution/template/BigProjectNNN/BigProjectNNN.vcxproj
+++ b/Tests/BigSolution/template/BigProjectNNN/BigProjectNNN.vcxproj
@@ -95,6 +95,14 @@
     <QtUic Include="BigProjectNNN.ui" />
     <QtRcc Include="BigProjectNNN.qrc" />
   </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\QtClassLibrary\QtClassLibrary.vcxproj">
+      <Project>{ce78ec51-c4a0-465b-a161-21c257bd057b}</Project>
+    </ProjectReference>
+    <ProjectReference Include="..\StaticLib\StaticLib.vcxproj">
+      <Project>{8463051a-b32c-43f0-9a77-9f223598aac9}</Project>
+    </ProjectReference>
+  </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
     <Import Project="$(QtMsBuild)\qt.targets" />
diff --git a/Tests/BigSolution/template/BigProjectNNN/BigProjectQtClassNNN.h b/Tests/BigSolution/template/BigProjectNNN/BigProjectQtClassNNN.h
index 66561fb..cb4d382 100644
--- a/Tests/BigSolution/template/BigProjectNNN/BigProjectQtClassNNN.h
+++ b/Tests/BigSolution/template/BigProjectNNN/BigProjectQtClassNNN.h
@@ -36,7 +36,7 @@
     Q_OBJECT
 
 public:
-    BigProjectQtClassNNN(QWidget *parent = Q_NULLPTR);
+    BigProjectQtClassNNN(QWidget *parent = nullptr);
 
 private:
     Ui::BigProjectNNNUi ui;
diff --git a/Tests/BigSolution/template/BigSolution.sln b/Tests/BigSolution/template/BigSolution.sln
index 66a56f1..ee2c8e6 100644
--- a/Tests/BigSolution/template/BigSolution.sln
+++ b/Tests/BigSolution/template/BigSolution.sln
@@ -3,6 +3,10 @@
 # Visual Studio Version 16
 VisualStudioVersion = 16.0.31229.387
 MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QtClassLibrary", "QtClassLibrary\QtClassLibrary.vcxproj", "{CE78EC51-C4A0-465B-A161-21C257BD057B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StaticLib", "StaticLib\StaticLib.vcxproj", "{8463051A-B32C-43F0-9A77-9F223598AAC9}"
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BigProjectNNN", "BigProjectNNN\BigProjectNNN.vcxproj", "{C032BE4B-48F7-465F-BA2A-44962223E000}"
 EndProject
 Global
@@ -11,6 +15,14 @@
 		Release|x64 = Release|x64
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{CE78EC51-C4A0-465B-A161-21C257BD057B}.Debug|x64.ActiveCfg = Debug|x64
+		{CE78EC51-C4A0-465B-A161-21C257BD057B}.Debug|x64.Build.0 = Debug|x64
+		{CE78EC51-C4A0-465B-A161-21C257BD057B}.Release|x64.ActiveCfg = Release|x64
+		{CE78EC51-C4A0-465B-A161-21C257BD057B}.Release|x64.Build.0 = Release|x64
+		{8463051A-B32C-43F0-9A77-9F223598AAC9}.Debug|x64.ActiveCfg = Debug|x64
+		{8463051A-B32C-43F0-9A77-9F223598AAC9}.Debug|x64.Build.0 = Debug|x64
+		{8463051A-B32C-43F0-9A77-9F223598AAC9}.Release|x64.ActiveCfg = Release|x64
+		{8463051A-B32C-43F0-9A77-9F223598AAC9}.Release|x64.Build.0 = Release|x64
 		{C032BE4B-48F7-465F-BA2A-44962223E000}.Debug|x64.ActiveCfg = Debug|x64
 		{C032BE4B-48F7-465F-BA2A-44962223E000}.Debug|x64.Build.0 = Debug|x64
 		{C032BE4B-48F7-465F-BA2A-44962223E000}.Release|x64.ActiveCfg = Release|x64
diff --git a/Tests/BigSolution/template/QtClassLibrary/QtClass.cpp b/Tests/BigSolution/template/QtClassLibrary/QtClass.cpp
new file mode 100644
index 0000000..e0be39f
--- /dev/null
+++ b/Tests/BigSolution/template/QtClassLibrary/QtClass.cpp
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtClass.h"
+
+QtClass::QtClass(QObject *parent)
+    : QObject(parent)
+{
+}
+
+QtClass::~QtClass()
+{
+}
diff --git a/Tests/BigSolution/template/QtClassLibrary/QtClass.h b/Tests/BigSolution/template/QtClassLibrary/QtClass.h
new file mode 100644
index 0000000..25117bf
--- /dev/null
+++ b/Tests/BigSolution/template/QtClassLibrary/QtClass.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#pragma once
+#include "qtclasslibrary_global.h"
+
+#include <QObject>
+
+class QTCLASSLIBRARY_EXPORT QtClass : public QObject
+{
+    Q_OBJECT
+
+public:
+    QtClass(QObject *parent);
+    ~QtClass();
+};
diff --git a/Tests/BigSolution/template/QtClassLibrary/QtClassLibrary.cpp b/Tests/BigSolution/template/QtClassLibrary/QtClassLibrary.cpp
new file mode 100644
index 0000000..2aea7ec
--- /dev/null
+++ b/Tests/BigSolution/template/QtClassLibrary/QtClassLibrary.cpp
@@ -0,0 +1,33 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "QtClassLibrary.h"
+
+QtClassLibrary::QtClassLibrary()
+{
+}
diff --git a/Tests/BigSolution/template/QtClassLibrary/QtClassLibrary.h b/Tests/BigSolution/template/QtClassLibrary/QtClassLibrary.h
new file mode 100644
index 0000000..076f26a
--- /dev/null
+++ b/Tests/BigSolution/template/QtClassLibrary/QtClassLibrary.h
@@ -0,0 +1,37 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#pragma once
+
+#include "qtclasslibrary_global.h"
+
+class QTCLASSLIBRARY_EXPORT QtClassLibrary
+{
+public:
+    QtClassLibrary();
+};
diff --git a/Tests/BigSolution/template/QtClassLibrary/QtClassLibrary.vcxproj b/Tests/BigSolution/template/QtClassLibrary/QtClassLibrary.vcxproj
new file mode 100644
index 0000000..54fd6da
--- /dev/null
+++ b/Tests/BigSolution/template/QtClassLibrary/QtClassLibrary.vcxproj
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="$(VisualStudioVersion)" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{CE78EC51-C4A0-465B-A161-21C257BD057B}</ProjectGuid>
+    <Keyword>QtVS_v304</Keyword>
+    <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">10.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">10.0</WindowsTargetPlatformVersion>
+    <QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')">$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
+    <Import Project="$(QtMsBuild)\qt_defaults.props" />
+  </ImportGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="QtSettings">
+    <QtInstall>$(DefaultQtVersion)</QtInstall>
+    <QtModules>core</QtModules>
+    <QtBuildConfig>debug</QtBuildConfig>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="QtSettings">
+    <QtInstall>$(DefaultQtVersion)</QtInstall>
+    <QtModules>core</QtModules>
+    <QtBuildConfig>release</QtBuildConfig>
+  </PropertyGroup>
+  <Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
+    <Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
+  </Target>
+  <ImportGroup Label="ExtensionSettings" />
+  <ImportGroup Label="Shared" />
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(QtMsBuild)\Qt.props" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(QtMsBuild)\Qt.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <AllProjectIncludesArePublic>true</AllProjectIncludesArePublic>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <AllProjectIncludesArePublic>true</AllProjectIncludesArePublic>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ProjectReference>
+      <UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>
+    </ProjectReference>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ProjectReference>
+      <UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>
+    </ProjectReference>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
+    <ClCompile>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <Optimization>Disabled</Optimization>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <PreprocessorDefinitions>QTCLASSLIBRARY_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
+    <ClCompile>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat>None</DebugInformationFormat>
+      <Optimization>MaxSpeed</Optimization>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <PreprocessorDefinitions>QTCLASSLIBRARY_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <QtMoc Include="QtClass.h" />
+    <ClInclude Include="qtclasslibrary_global.h" />
+    <ClInclude Include="QtClassLibrary.h" />
+    <ClCompile Include="QtClass.cpp" />
+    <ClCompile Include="QtClassLibrary.cpp" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
+    <Import Project="$(QtMsBuild)\qt.targets" />
+  </ImportGroup>
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/Tests/BigSolution/template/QtClassLibrary/QtClassLibrary.vcxproj.filters b/Tests/BigSolution/template/QtClassLibrary/QtClassLibrary.vcxproj.filters
new file mode 100644
index 0000000..5797d00
--- /dev/null
+++ b/Tests/BigSolution/template/QtClassLibrary/QtClassLibrary.vcxproj.filters
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+    <Filter Include="Translation Files">
+      <UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>
+      <Extensions>ts</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="qtclasslibrary_global.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClCompile Include="QtClassLibrary.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClInclude Include="QtClassLibrary.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <QtMoc Include="QtClass.h">
+      <Filter>Header Files</Filter>
+    </QtMoc>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="QtClass.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/Tests/BigSolution/template/QtClassLibrary/qtclasslibrary_global.h b/Tests/BigSolution/template/QtClassLibrary/qtclasslibrary_global.h
new file mode 100644
index 0000000..30029ba
--- /dev/null
+++ b/Tests/BigSolution/template/QtClassLibrary/qtclasslibrary_global.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtCore/qglobal.h>
+
+#ifndef BUILD_STATIC
+# if defined(QTCLASSLIBRARY_LIB)
+#  define QTCLASSLIBRARY_EXPORT Q_DECL_EXPORT
+# else
+#  define QTCLASSLIBRARY_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define QTCLASSLIBRARY_EXPORT
+#endif
diff --git a/Tests/BigSolution/template/StaticLib/Header.h b/Tests/BigSolution/template/StaticLib/Header.h
new file mode 100644
index 0000000..69b048e
--- /dev/null
+++ b/Tests/BigSolution/template/StaticLib/Header.h
@@ -0,0 +1,4 @@
+#pragma once
+
+void foobar();
+
diff --git a/Tests/BigSolution/template/StaticLib/StaticLib.cpp b/Tests/BigSolution/template/StaticLib/StaticLib.cpp
new file mode 100644
index 0000000..85cd0de
--- /dev/null
+++ b/Tests/BigSolution/template/StaticLib/StaticLib.cpp
@@ -0,0 +1,31 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+void foobar()
+{
+}
diff --git a/Tests/BigSolution/template/StaticLib/StaticLib.vcxproj b/Tests/BigSolution/template/StaticLib/StaticLib.vcxproj
new file mode 100644
index 0000000..e250860
--- /dev/null
+++ b/Tests/BigSolution/template/StaticLib/StaticLib.vcxproj
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <VCProjectVersion>16.0</VCProjectVersion>
+    <Keyword>Win32Proj</Keyword>
+    <ProjectGuid>{8463051a-b32c-43f0-9a77-9f223598aac9}</ProjectGuid>
+    <RootNamespace>StaticLib</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+    <AllProjectIncludesArePublic>true</AllProjectIncludesArePublic>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+    <AllProjectIncludesArePublic>true</AllProjectIncludesArePublic>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+    </ClCompile>
+    <Link>
+      <SubSystem>
+      </SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+    </ClCompile>
+    <Link>
+      <SubSystem>
+      </SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="StaticLib.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="Header.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/Tests/BigSolution/template/StaticLib/StaticLib.vcxproj.filters b/Tests/BigSolution/template/StaticLib/StaticLib.vcxproj.filters
new file mode 100644
index 0000000..55c2e2a
--- /dev/null
+++ b/Tests/BigSolution/template/StaticLib/StaticLib.vcxproj.filters
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="StaticLib.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="Header.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/Tests/BigSolution/template/loop_msbuild.bat b/Tests/BigSolution/template/loop_msbuild.bat
new file mode 100644
index 0000000..24854c0
--- /dev/null
+++ b/Tests/BigSolution/template/loop_msbuild.bat
@@ -0,0 +1,36 @@
+@ECHO OFF
+
+SET TOTAL=0
+SET FAIL=0
+SET RATE=0
+SET USER_QUIT=0
+SET PAD=..00
+
+:loop
+    CLS
+    SET RATE=%PAD%%RATE%
+    ECHO ################################################################################
+    ECHO # Total: %TOTAL%, Failed: %FAIL%...%RATE:~-4,-2%,%RATE:~-2%%%
+    ECHO ################################################################################
+    IF %USER_QUIT% EQU 1 GOTO quit
+    SET /A "TOTAL+=1"
+    msbuild %* ^
+        /m /bl /v:m /nologo ^
+    && (
+        DEL last_build_ok.binlog 2> NUL
+        COPY msbuild.binlog last_build_ok.binlog > NUL
+    ) || (
+        SET /A "FAIL+=1"
+        COPY msbuild.binlog error_build_%TOTAL%.binlog > NUL
+    )
+    SET /A "RATE=(FAIL*100*100)/(TOTAL)"
+    ECHO ################################################################################
+    CHOICE /C QNOP /N /T 1 /D N /M "# [N]ext / [O]pen Log / [P]ause / [Q]uit ?"
+    IF %ERRORLEVEL% EQU 3 (
+        START "" msbuild.binlog
+        PAUSE
+    )
+    IF %ERRORLEVEL% EQU 4 PAUSE
+    SET USER_QUIT=%ERRORLEVEL%
+    GOTO :loop
+:quit
diff --git a/Tests/ProjectFormats/100/QtProjectV100.cpp b/Tests/ProjectFormats/100/QtProjectV100.cpp
new file mode 100644
index 0000000..19581ed
--- /dev/null
+++ b/Tests/ProjectFormats/100/QtProjectV100.cpp
@@ -0,0 +1,10 @@
+#include "QtProjectV100.h"
+
+QtProjectV100::QtProjectV100(QWidget *parent)
+    : QMainWindow(parent)
+{
+    ui.setupUi(this);
+}
+
+QtProjectV100::~QtProjectV100()
+{}
diff --git a/Tests/ProjectFormats/100/QtProjectV100.h b/Tests/ProjectFormats/100/QtProjectV100.h
new file mode 100644
index 0000000..17c9eff
--- /dev/null
+++ b/Tests/ProjectFormats/100/QtProjectV100.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <QtWidgets/QMainWindow>
+#include "ui_QtProjectV100.h"
+
+class QtProjectV100 : public QMainWindow
+{
+    Q_OBJECT
+
+public:
+    QtProjectV100(QWidget *parent = nullptr);
+    ~QtProjectV100();
+
+private:
+    Ui::QtProjectV100Class ui;
+};
diff --git a/Tests/ProjectFormats/100/QtProjectV100.pro b/Tests/ProjectFormats/100/QtProjectV100.pro
new file mode 100644
index 0000000..bcf1b07
--- /dev/null
+++ b/Tests/ProjectFormats/100/QtProjectV100.pro
@@ -0,0 +1,6 @@
+QT += widgets
+HEADERS     = QtProjectV100.h
+FORMS       = QtProjectV100.ui
+RESOURCES   = QtProjectV100.qrc
+SOURCES     = QtProjectV100.cpp \
+              main.cpp
diff --git a/Tests/ProjectFormats/100/QtProjectV100.qrc b/Tests/ProjectFormats/100/QtProjectV100.qrc
new file mode 100644
index 0000000..c2c4dd0
--- /dev/null
+++ b/Tests/ProjectFormats/100/QtProjectV100.qrc
@@ -0,0 +1,4 @@
+<RCC>
+    <qresource prefix="QtProjectV100">
+    </qresource>
+</RCC>
diff --git a/Tests/ProjectFormats/100/QtProjectV100.ui b/Tests/ProjectFormats/100/QtProjectV100.ui
new file mode 100644
index 0000000..4fe7f33
--- /dev/null
+++ b/Tests/ProjectFormats/100/QtProjectV100.ui
@@ -0,0 +1,28 @@
+<UI version="4.0" >
+ <class>QtProjectV100Class</class>
+ <widget class="QMainWindow" name="QtProjectV100Class" >
+  <property name="objectName" >
+   <string notr="true">QtProjectV100Class</string>
+  </property>
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>600</width>
+    <height>400</height>
+   </rect>
+  </property>
+  <property name="windowTitle" >
+   <string>QtProjectV100</string>
+  </property>  <widget class="QMenuBar" name="menuBar" />
+  <widget class="QToolBar" name="mainToolBar" />
+  <widget class="QWidget" name="centralWidget" />
+  <widget class="QStatusBar" name="statusBar" />
+ </widget>
+ <layoutDefault spacing="6" margin="11" />
+ <pixmapfunction></pixmapfunction>
+ <resources>
+   <include location="QtProjectV100.qrc"/>
+ </resources>
+ <connections/>
+</UI>
diff --git a/Tests/ProjectFormats/100/QtProjectV100.vcxproj b/Tests/ProjectFormats/100/QtProjectV100.vcxproj
new file mode 100644
index 0000000..347aa54
--- /dev/null
+++ b/Tests/ProjectFormats/100/QtProjectV100.vcxproj
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{E5EA0EEF-BDC2-3484-A4F0-BA6C71E224CF}</ProjectGuid>
+    <RootNamespace>QtProjectV100</RootNamespace>
+    <Keyword>Qt4VSv1.0</Keyword>
+    <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformMinVersion>10.0.19041.0</WindowsTargetPlatformMinVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;" Label="Configuration">
+    <PlatformToolset>v142</PlatformToolset>
+    <OutputDirectory>release\</OutputDirectory>
+    <ATLMinimizesCRunTimeLibraryUsage>false</ATLMinimizesCRunTimeLibraryUsage>
+    <CharacterSet>NotSet</CharacterSet>
+    <ConfigurationType>Application</ConfigurationType>
+    <IntermediateDirectory>release\</IntermediateDirectory>
+    <PrimaryOutput>QtProjectV100</PrimaryOutput>
+  </PropertyGroup>
+  <PropertyGroup Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;" Label="Configuration">
+    <PlatformToolset>v142</PlatformToolset>
+    <OutputDirectory>debug\</OutputDirectory>
+    <ATLMinimizesCRunTimeLibraryUsage>false</ATLMinimizesCRunTimeLibraryUsage>
+    <CharacterSet>NotSet</CharacterSet>
+    <ConfigurationType>Application</ConfigurationType>
+    <IntermediateDirectory>debug\</IntermediateDirectory>
+    <PrimaryOutput>QtProjectV100</PrimaryOutput>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings" />
+  <ImportGroup Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists(&apos;$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props&apos;)" />
+  </ImportGroup>
+  <ImportGroup Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists(&apos;$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props&apos;)" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <OutDir Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">release\</OutDir>
+    <IntDir Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">release\</IntDir>
+    <TargetName Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">QtProjectV100</TargetName>
+    <IgnoreImportLibrary Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">true</IgnoreImportLibrary>
+    <LinkIncremental Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">false</LinkIncremental>
+    <OutDir Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">debug\</OutDir>
+    <IntDir Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">debug\</IntDir>
+    <TargetName Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">QtProjectV100</TargetName>
+    <IgnoreImportLibrary Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">true</IgnoreImportLibrary>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">
+    <ClCompile>
+      <AdditionalIncludeDirectories>.;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include\QtWidgets;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include\QtGui;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include\QtANGLE;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include\QtCore;release;.;/include;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\mkspecs\win32-msvc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions>
+      <AssemblerListingLocation>release\</AssemblerListingLocation>
+      <BrowseInformation>false</BrowseInformation>
+      <DebugInformationFormat>None</DebugInformationFormat>
+      <DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <ExceptionHandling>Sync</ExceptionHandling>
+      <ObjectFileName>release\</ObjectFileName>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;NDEBUG;QT_NO_DEBUG;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessToFile>false</PreprocessToFile>
+      <ProgramDataBaseFileName></ProgramDataBaseFileName>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <WarningLevel>Level3</WarningLevel>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>C:\lib\Qt\5.15.10\msvc2019_64\lib\Qt5Widgets.lib;C:\lib\Qt\5.15.10\msvc2019_64\lib\Qt5Gui.lib;C:\lib\Qt\5.15.10\msvc2019_64\lib\Qt5Core.lib;C:\lib\Qt\5.15.10\msvc2019_64\lib\qtmain.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>C:\openssl\lib;C:\Utils\my_sql\mysql-5.7.25-winx64\lib;C:\Utils\postgresql\pgsql\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalOptions>&quot;/MANIFESTDEPENDENCY:type=&apos;win32&apos; name=&apos;Microsoft.Windows.Common-Controls&apos; version=&apos;6.0.0.0&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos; processorArchitecture=&apos;*&apos;&quot; %(AdditionalOptions)</AdditionalOptions>
+      <DataExecutionPrevention>true</DataExecutionPrevention>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+      <IgnoreImportLibrary>true</IgnoreImportLibrary>
+      <LinkIncremental>false</LinkIncremental>
+      <OptimizeReferences>true</OptimizeReferences>
+      <OutputFile>$(OutDir)\QtProjectV100.exe</OutputFile>
+      <RandomizedBaseAddress>true</RandomizedBaseAddress>
+      <SubSystem>Windows</SubSystem>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+    </Link>
+    <Midl>
+      <DefaultCharType>Unsigned</DefaultCharType>
+      <EnableErrorChecks>None</EnableErrorChecks>
+      <WarningLevel>0</WarningLevel>
+    </Midl>
+    <ResourceCompile>
+      <PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;NDEBUG;QT_NO_DEBUG;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">
+    <ClCompile>
+      <AdditionalIncludeDirectories>.;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include\QtWidgets;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include\QtGui;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include\QtANGLE;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include\QtCore;debug;.;/include;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\mkspecs\win32-msvc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions>
+      <AssemblerListingLocation>debug\</AssemblerListingLocation>
+      <BrowseInformation>false</BrowseInformation>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <ExceptionHandling>Sync</ExceptionHandling>
+      <ObjectFileName>debug\</ObjectFileName>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessToFile>false</PreprocessToFile>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <WarningLevel>Level3</WarningLevel>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>C:\lib\Qt\5.15.10\msvc2019_64\lib\Qt5Widgetsd.lib;C:\lib\Qt\5.15.10\msvc2019_64\lib\Qt5Guid.lib;C:\lib\Qt\5.15.10\msvc2019_64\lib\Qt5Cored.lib;C:\lib\Qt\5.15.10\msvc2019_64\lib\qtmaind.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>C:\openssl\lib;C:\Utils\my_sql\mysql-5.7.25-winx64\lib;C:\Utils\postgresql\pgsql\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalOptions>&quot;/MANIFESTDEPENDENCY:type=&apos;win32&apos; name=&apos;Microsoft.Windows.Common-Controls&apos; version=&apos;6.0.0.0&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos; processorArchitecture=&apos;*&apos;&quot; %(AdditionalOptions)</AdditionalOptions>
+      <DataExecutionPrevention>true</DataExecutionPrevention>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <IgnoreImportLibrary>true</IgnoreImportLibrary>
+      <OutputFile>$(OutDir)\QtProjectV100.exe</OutputFile>
+      <RandomizedBaseAddress>true</RandomizedBaseAddress>
+      <SubSystem>Windows</SubSystem>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+    </Link>
+    <Midl>
+      <DefaultCharType>Unsigned</DefaultCharType>
+      <EnableErrorChecks>None</EnableErrorChecks>
+      <WarningLevel>0</WarningLevel>
+    </Midl>
+    <ResourceCompile>
+      <PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="QtProjectV100.cpp" />
+    <ClCompile Include="main.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <CustomBuild Include="QtProjectV100.h">
+      <AdditionalInputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">QtProjectV100.h;release\moc_predefs.h;C:\lib\Qt\5.15.10\msvc2019_64\bin\moc.exe;%(AdditionalInputs)</AdditionalInputs>
+      <Command Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">C:\lib\Qt\5.15.10\msvc2019_64\bin\moc.exe  -DUNICODE -D_UNICODE -DWIN32 -D_ENABLE_EXTENDED_ALIGNED_STORAGE -DWIN64 -DNDEBUG -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB --compiler-flavor=msvc --include C:/dev/tests/formats/100/release/moc_predefs.h -IC:/lib/Qt/5.15.10/msvc2019_64/mkspecs/win32-msvc -IC:/dev/tests/formats/100 -IC:/lib/Qt/5.15.10/msvc2019_64/include -IC:/lib/Qt/5.15.10/msvc2019_64/include/QtWidgets -IC:/lib/Qt/5.15.10/msvc2019_64/include/QtGui -IC:/lib/Qt/5.15.10/msvc2019_64/include/QtANGLE -IC:/lib/Qt/5.15.10/msvc2019_64/include/QtCore -I&quot;C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\ATLMFC\include&quot; -I&quot;C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\include&quot; -I&quot;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\ucrt&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\winrt&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\cppwinrt&quot; QtProjectV100.h -o release\moc_QtProjectV100.cpp</Command>
+      <Message Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">MOC QtProjectV100.h</Message>
+      <Outputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">release\moc_QtProjectV100.cpp;%(Outputs)</Outputs>
+      <AdditionalInputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">QtProjectV100.h;debug\moc_predefs.h;C:\lib\Qt\5.15.10\msvc2019_64\bin\moc.exe;%(AdditionalInputs)</AdditionalInputs>
+      <Command Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">C:\lib\Qt\5.15.10\msvc2019_64\bin\moc.exe  -DUNICODE -D_UNICODE -DWIN32 -D_ENABLE_EXTENDED_ALIGNED_STORAGE -DWIN64 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB --compiler-flavor=msvc --include C:/dev/tests/formats/100/debug/moc_predefs.h -IC:/lib/Qt/5.15.10/msvc2019_64/mkspecs/win32-msvc -IC:/dev/tests/formats/100 -IC:/lib/Qt/5.15.10/msvc2019_64/include -IC:/lib/Qt/5.15.10/msvc2019_64/include/QtWidgets -IC:/lib/Qt/5.15.10/msvc2019_64/include/QtGui -IC:/lib/Qt/5.15.10/msvc2019_64/include/QtANGLE -IC:/lib/Qt/5.15.10/msvc2019_64/include/QtCore -I&quot;C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\ATLMFC\include&quot; -I&quot;C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\include&quot; -I&quot;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\ucrt&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\winrt&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\cppwinrt&quot; QtProjectV100.h -o debug\moc_QtProjectV100.cpp</Command>
+      <Message Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">MOC QtProjectV100.h</Message>
+      <Outputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">debug\moc_QtProjectV100.cpp;%(Outputs)</Outputs>
+    </CustomBuild>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="debug\moc_QtProjectV100.cpp">
+      <ExcludedFromBuild Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">true</ExcludedFromBuild>
+    </ClCompile>
+    <ClCompile Include="release\moc_QtProjectV100.cpp">
+      <ExcludedFromBuild Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">true</ExcludedFromBuild>
+    </ClCompile>
+    <CustomBuild Include="debug\moc_predefs.h.cbt">
+      <FileType>Document</FileType>
+      <ExcludedFromBuild Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">true</ExcludedFromBuild>
+      <AdditionalInputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">..\..\..\..\lib\Qt\5.15.10\msvc2019_64\mkspecs\features\data\dummy.cpp;%(AdditionalInputs)</AdditionalInputs>
+      <Command Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">cl -BxC:\lib\Qt\5.15.10\msvc2019_64\bin\qmake.exe -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -Zi -MDd -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E ..\..\..\..\lib\Qt\5.15.10\msvc2019_64\mkspecs\features\data\dummy.cpp 2&gt;NUL &gt;debug\moc_predefs.h</Command>
+      <Message Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">Generate moc_predefs.h</Message>
+      <Outputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">debug\moc_predefs.h;%(Outputs)</Outputs>
+    </CustomBuild>
+    <CustomBuild Include="release\moc_predefs.h.cbt">
+      <FileType>Document</FileType>
+      <AdditionalInputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">..\..\..\..\lib\Qt\5.15.10\msvc2019_64\mkspecs\features\data\dummy.cpp;%(AdditionalInputs)</AdditionalInputs>
+      <Command Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">cl -BxC:\lib\Qt\5.15.10\msvc2019_64\bin\qmake.exe -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -O2 -MD -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E ..\..\..\..\lib\Qt\5.15.10\msvc2019_64\mkspecs\features\data\dummy.cpp 2&gt;NUL &gt;release\moc_predefs.h</Command>
+      <Message Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">Generate moc_predefs.h</Message>
+      <Outputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">release\moc_predefs.h;%(Outputs)</Outputs>
+      <ExcludedFromBuild Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">true</ExcludedFromBuild>
+    </CustomBuild>
+    <ClCompile Include="debug\qrc_QtProjectV100.cpp">
+      <ExcludedFromBuild Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">true</ExcludedFromBuild>
+    </ClCompile>
+    <ClCompile Include="release\qrc_QtProjectV100.cpp">
+      <ExcludedFromBuild Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">true</ExcludedFromBuild>
+    </ClCompile>
+    <ClInclude Include="ui_QtProjectV100.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <CustomBuild Include="QtProjectV100.ui">
+      <FileType>Document</FileType>
+      <AdditionalInputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">QtProjectV100.ui;C:\lib\Qt\5.15.10\msvc2019_64\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
+      <Command Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">C:\lib\Qt\5.15.10\msvc2019_64\bin\uic.exe QtProjectV100.ui -o ui_QtProjectV100.h</Command>
+      <Message Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">UIC QtProjectV100.ui</Message>
+      <Outputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">ui_QtProjectV100.h;%(Outputs)</Outputs>
+      <AdditionalInputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">QtProjectV100.ui;C:\lib\Qt\5.15.10\msvc2019_64\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
+      <Command Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">C:\lib\Qt\5.15.10\msvc2019_64\bin\uic.exe QtProjectV100.ui -o ui_QtProjectV100.h</Command>
+      <Message Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">UIC QtProjectV100.ui</Message>
+      <Outputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">ui_QtProjectV100.h;%(Outputs)</Outputs>
+    </CustomBuild>
+  </ItemGroup>
+  <ItemGroup>
+    <CustomBuild Include="QtProjectV100.qrc">
+      <FileType>Document</FileType>
+      <AdditionalInputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">QtProjectV100.qrc;C:\lib\Qt\5.15.10\msvc2019_64\bin\rcc.exe;%(AdditionalInputs)</AdditionalInputs>
+      <Command Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">C:\lib\Qt\5.15.10\msvc2019_64\bin\rcc.exe -name QtProjectV100 QtProjectV100.qrc -o release\qrc_QtProjectV100.cpp</Command>
+      <Message Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">RCC QtProjectV100.qrc</Message>
+      <Outputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">release\qrc_QtProjectV100.cpp;%(Outputs)</Outputs>
+      <AdditionalInputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">QtProjectV100.qrc;C:\lib\Qt\5.15.10\msvc2019_64\bin\rcc.exe;%(AdditionalInputs)</AdditionalInputs>
+      <Command Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">C:\lib\Qt\5.15.10\msvc2019_64\bin\rcc.exe -name QtProjectV100 QtProjectV100.qrc -o debug\qrc_QtProjectV100.cpp</Command>
+      <Message Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">RCC QtProjectV100.qrc</Message>
+      <Outputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">debug\qrc_QtProjectV100.cpp;%(Outputs)</Outputs>
+    </CustomBuild>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets" />
+</Project>
\ No newline at end of file
diff --git a/Tests/ProjectFormats/100/QtProjectV100.vcxproj.filters b/Tests/ProjectFormats/100/QtProjectV100.vcxproj.filters
new file mode 100644
index 0000000..0c6827d
--- /dev/null
+++ b/Tests/ProjectFormats/100/QtProjectV100.vcxproj.filters
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Form Files">
+      <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
+      <Extensions>ui</Extensions>
+      <ParseFiles>false</ParseFiles>
+    </Filter>
+    <Filter Include="Form Files">
+      <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
+      <Extensions>ui</Extensions>
+      <ParseFiles>false</ParseFiles>
+    </Filter>
+    <Filter Include="Generated Files">
+      <UniqueIdentifier>{71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}</UniqueIdentifier>
+      <Extensions>cpp;c;cxx;moc;h;def;odl;idl;res;</Extensions>
+    </Filter>
+    <Filter Include="Generated Files">
+      <UniqueIdentifier>{71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}</UniqueIdentifier>
+      <Extensions>cpp;c;cxx;moc;h;def;odl;idl;res;</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}</UniqueIdentifier>
+      <Extensions>qrc;*</Extensions>
+      <ParseFiles>false</ParseFiles>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}</UniqueIdentifier>
+      <Extensions>qrc;*</Extensions>
+      <ParseFiles>false</ParseFiles>
+    </Filter>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="QtProjectV100.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="main.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <CustomBuild Include="QtProjectV100.h">
+      <Filter>Header Files</Filter>
+    </CustomBuild>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="debug\moc_QtProjectV100.cpp">
+      <Filter>Generated Files</Filter>
+    </ClCompile>
+    <ClCompile Include="release\moc_QtProjectV100.cpp">
+      <Filter>Generated Files</Filter>
+    </ClCompile>
+    <CustomBuild Include="debug\moc_predefs.h.cbt">
+      <Filter>Generated Files</Filter>
+    </CustomBuild>
+    <CustomBuild Include="release\moc_predefs.h.cbt">
+      <Filter>Generated Files</Filter>
+    </CustomBuild>
+    <ClCompile Include="debug\qrc_QtProjectV100.cpp">
+      <Filter>Generated Files</Filter>
+    </ClCompile>
+    <ClCompile Include="release\qrc_QtProjectV100.cpp">
+      <Filter>Generated Files</Filter>
+    </ClCompile>
+    <ClInclude Include="ui_QtProjectV100.h">
+      <Filter>Generated Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <CustomBuild Include="QtProjectV100.ui">
+      <Filter>Form Files</Filter>
+    </CustomBuild>
+  </ItemGroup>
+  <ItemGroup>
+    <CustomBuild Include="QtProjectV100.qrc">
+      <Filter>Resource Files</Filter>
+    </CustomBuild>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/Tests/ProjectFormats/100/main.cpp b/Tests/ProjectFormats/100/main.cpp
new file mode 100644
index 0000000..1c6e872
--- /dev/null
+++ b/Tests/ProjectFormats/100/main.cpp
@@ -0,0 +1,10 @@
+#include "QtProjectV100.h"
+#include <QtWidgets/QApplication>
+
+int main(int argc, char *argv[])
+{
+    QApplication a(argc, argv);
+    QtProjectV100 w;
+    w.show();
+    return a.exec();
+}
diff --git a/Tests/ProjectFormats/200/QtProjectV200.cpp b/Tests/ProjectFormats/200/QtProjectV200.cpp
new file mode 100644
index 0000000..9247eb2
--- /dev/null
+++ b/Tests/ProjectFormats/200/QtProjectV200.cpp
@@ -0,0 +1,7 @@
+#include "QtProjectV200.h"
+
+QtProjectV200::QtProjectV200(QWidget *parent)
+	: QMainWindow(parent)
+{
+	ui.setupUi(this);
+}
diff --git a/Tests/ProjectFormats/200/QtProjectV200.h b/Tests/ProjectFormats/200/QtProjectV200.h
new file mode 100644
index 0000000..dc1b953
--- /dev/null
+++ b/Tests/ProjectFormats/200/QtProjectV200.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <QtWidgets/QMainWindow>
+#include "ui_QtProjectV200.h"
+
+class QtProjectV200 : public QMainWindow
+{
+	Q_OBJECT
+
+public:
+	QtProjectV200(QWidget *parent = Q_NULLPTR);
+
+private:
+	Ui::QtProjectV200Class ui;
+};
diff --git a/Tests/ProjectFormats/200/QtProjectV200.qrc b/Tests/ProjectFormats/200/QtProjectV200.qrc
new file mode 100644
index 0000000..f5921b2
--- /dev/null
+++ b/Tests/ProjectFormats/200/QtProjectV200.qrc
@@ -0,0 +1,4 @@
+<RCC>
+    <qresource prefix="QtProjectV200">
+    </qresource>
+</RCC>
diff --git a/Tests/ProjectFormats/200/QtProjectV200.sln b/Tests/ProjectFormats/200/QtProjectV200.sln
new file mode 100644
index 0000000..32e1cd1
--- /dev/null
+++ b/Tests/ProjectFormats/200/QtProjectV200.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QtProjectV200", "QtProjectV200.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.ActiveCfg = Debug|x64
+		{B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.Build.0 = Debug|x64
+		{B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.ActiveCfg = Release|x64
+		{B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/Tests/ProjectFormats/200/QtProjectV200.ui b/Tests/ProjectFormats/200/QtProjectV200.ui
new file mode 100644
index 0000000..8eed476
--- /dev/null
+++ b/Tests/ProjectFormats/200/QtProjectV200.ui
@@ -0,0 +1,29 @@
+<UI version="4.0" >
+ <class>QtProjectV200Class</class>
+ <widget class="QMainWindow" name="QtProjectV200Class" >
+  <property name="objectName" >
+   <string notr="true">QtProjectV200Class</string>
+  </property>
+  <property name="geometry" >
+   <rect>
+	<x>0</x>
+	<y>0</y>
+	<width>600</width>
+	<height>400</height>
+   </rect>
+  </property>
+  <property name="windowTitle" >
+   <string>QtProjectV200</string>
+  </property>
+  <widget class="QMenuBar" name="menuBar" />
+  <widget class="QToolBar" name="mainToolBar" />
+  <widget class="QWidget" name="centralWidget" />
+  <widget class="QStatusBar" name="statusBar" />
+ </widget>
+ <layoutDefault spacing="6" margin="11" />
+ <pixmapfunction></pixmapfunction>
+ <resources>
+   <include location="QtProjectV200.qrc"/>
+ </resources>
+ <connections/>
+</UI>
diff --git a/Tests/ProjectFormats/200/QtProjectV200.vcxproj b/Tests/ProjectFormats/200/QtProjectV200.vcxproj
new file mode 100644
index 0000000..1b4d671
--- /dev/null
+++ b/Tests/ProjectFormats/200/QtProjectV200.vcxproj
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{B12702AD-ABFB-343A-A199-8E24837244A3}</ProjectGuid>
+    <Keyword>Qt4VSv1.0</Keyword>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings" />
+  <ImportGroup Label="Shared" />
+  <ImportGroup Label="PropertySheets" />
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PreprocessorDefinitions>UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <Optimization>Disabled</Optimization>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
+      <AdditionalLibraryDirectories>$(QTDIR)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>qtmaind.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5Widgetsd.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PreprocessorDefinitions>UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <DebugInformationFormat />
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
+      <AdditionalLibraryDirectories>$(QTDIR)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+      <AdditionalDependencies>qtmain.lib;Qt5Core.lib;Qt5Gui.lib;Qt5Widgets.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="GeneratedFiles\Debug\moc_QtProjectV200.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+    </ClCompile>
+    <ClCompile Include="GeneratedFiles\qrc_QtProjectV200.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+      </PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+      </PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="GeneratedFiles\Release\moc_QtProjectV200.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+    </ClCompile>
+    <ClCompile Include="main.cpp" />
+    <ClCompile Include="QtProjectV200.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <CustomBuild Include="QtProjectV200.h">
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Moc%27ing QtProjectV200.h...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -D_UNICODE -DWIN32 -D_ENABLE_EXTENDED_ALIGNED_STORAGE -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets"</Command>
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Moc%27ing QtProjectV200.h...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -D_UNICODE -DWIN32 -D_ENABLE_EXTENDED_ALIGNED_STORAGE -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets"</Command>
+    </CustomBuild>
+  </ItemGroup>
+  <ItemGroup>
+    <CustomBuild Include="QtProjectV200.ui">
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Uic%27ing %(Identity)...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Uic%27ing %(Identity)...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
+    </CustomBuild>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="GeneratedFiles\ui_QtProjectV200.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <CustomBuild Include="QtProjectV200.qrc">
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(FullPath);%(AdditionalInputs)</AdditionalInputs>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Rcc%27ing %(Identity)...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\GeneratedFiles\qrc_%(Filename).cpp;%(Outputs)</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\rcc.exe" -name "%(Filename)" -no-compress "%(FullPath)" -o .\GeneratedFiles\qrc_%(Filename).cpp</Command>
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(FullPath);%(AdditionalInputs)</AdditionalInputs>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Rcc%27ing %(Identity)...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\qrc_%(Filename).cpp;%(Outputs)</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\rcc.exe" -name "%(Filename)" -no-compress "%(FullPath)" -o .\GeneratedFiles\qrc_%(Filename).cpp</Command>
+    </CustomBuild>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+  <ProjectExtensions>
+    <VisualStudio>
+      <UserProperties MocDir=".\GeneratedFiles\$(ConfigurationName)" UicDir=".\GeneratedFiles" RccDir=".\GeneratedFiles" lupdateOptions="" lupdateOnBuild="0" lreleaseOptions="" Qt5Version_x0020_x64="msvc2019_64" MocOptions="" />
+    </VisualStudio>
+  </ProjectExtensions>
+</Project>
\ No newline at end of file
diff --git a/Tests/ProjectFormats/200/QtProjectV200.vcxproj.filters b/Tests/ProjectFormats/200/QtProjectV200.vcxproj.filters
new file mode 100644
index 0000000..81ea645
--- /dev/null
+++ b/Tests/ProjectFormats/200/QtProjectV200.vcxproj.filters
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}</UniqueIdentifier>
+      <Extensions>qrc;*</Extensions>
+      <ParseFiles>false</ParseFiles>
+    </Filter>
+    <Filter Include="Form Files">
+      <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
+      <Extensions>ui</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}</UniqueIdentifier>
+      <Extensions>qrc;*</Extensions>
+      <ParseFiles>false</ParseFiles>
+    </Filter>
+    <Filter Include="Generated Files">
+      <UniqueIdentifier>{71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}</UniqueIdentifier>
+      <Extensions>moc;h;cpp</Extensions>
+      <SourceControlFiles>False</SourceControlFiles>
+    </Filter>
+    <Filter Include="Generated Files\Debug">
+      <UniqueIdentifier>{61dba4ef-747b-4196-a5ef-706b88f740b6}</UniqueIdentifier>
+      <Extensions>cpp;moc</Extensions>
+      <SourceControlFiles>False</SourceControlFiles>
+    </Filter>
+    <Filter Include="Generated Files\Release">
+      <UniqueIdentifier>{52c84570-5db2-40f2-bcf4-841a0b66e6ee}</UniqueIdentifier>
+      <Extensions>cpp;moc</Extensions>
+      <SourceControlFiles>False</SourceControlFiles>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="main.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="QtProjectV200.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="GeneratedFiles\Debug\moc_QtProjectV200.cpp">
+      <Filter>Generated Files\Debug</Filter>
+    </ClCompile>
+    <ClCompile Include="GeneratedFiles\Release\moc_QtProjectV200.cpp">
+      <Filter>Generated Files\Release</Filter>
+    </ClCompile>
+    <ClCompile Include="GeneratedFiles\qrc_QtProjectV200.cpp">
+      <Filter>Generated Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <CustomBuild Include="QtProjectV200.h">
+      <Filter>Header Files</Filter>
+    </CustomBuild>
+    <CustomBuild Include="QtProjectV200.ui">
+      <Filter>Form Files</Filter>
+    </CustomBuild>
+    <CustomBuild Include="QtProjectV200.qrc">
+      <Filter>Resource Files</Filter>
+    </CustomBuild>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="GeneratedFiles\ui_QtProjectV200.h">
+      <Filter>Generated Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/Tests/ProjectFormats/200/main.cpp b/Tests/ProjectFormats/200/main.cpp
new file mode 100644
index 0000000..a033029
--- /dev/null
+++ b/Tests/ProjectFormats/200/main.cpp
@@ -0,0 +1,10 @@
+#include "QtProjectV200.h"
+#include <QtWidgets/QApplication>
+
+int main(int argc, char *argv[])
+{
+	QApplication a(argc, argv);
+	QtProjectV200 w;
+	w.show();
+	return a.exec();
+}
diff --git a/Tests/ProjectFormats/300/QtProjectV300.cpp b/Tests/ProjectFormats/300/QtProjectV300.cpp
new file mode 100644
index 0000000..f896a7a
--- /dev/null
+++ b/Tests/ProjectFormats/300/QtProjectV300.cpp
@@ -0,0 +1,7 @@
+#include "QtProjectV300.h"
+
+QtProjectV300::QtProjectV300(QWidget *parent)
+	: QMainWindow(parent)
+{
+	ui.setupUi(this);
+}
diff --git a/Tests/ProjectFormats/300/QtProjectV300.h b/Tests/ProjectFormats/300/QtProjectV300.h
new file mode 100644
index 0000000..ceb967c
--- /dev/null
+++ b/Tests/ProjectFormats/300/QtProjectV300.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <QtWidgets/QMainWindow>
+#include "ui_QtProjectV300.h"
+
+class QtProjectV300 : public QMainWindow
+{
+	Q_OBJECT
+
+public:
+	QtProjectV300(QWidget *parent = Q_NULLPTR);
+
+private:
+	Ui::QtProjectV300Class ui;
+};
diff --git a/Tests/ProjectFormats/300/QtProjectV300.qrc b/Tests/ProjectFormats/300/QtProjectV300.qrc
new file mode 100644
index 0000000..505a26b
--- /dev/null
+++ b/Tests/ProjectFormats/300/QtProjectV300.qrc
@@ -0,0 +1,4 @@
+<RCC>
+    <qresource prefix="QtProjectV300">
+    </qresource>
+</RCC>
diff --git a/Tests/ProjectFormats/300/QtProjectV300.sln b/Tests/ProjectFormats/300/QtProjectV300.sln
new file mode 100644
index 0000000..d48f3dd
--- /dev/null
+++ b/Tests/ProjectFormats/300/QtProjectV300.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.32106.194
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QtProjectV300", "QtProjectV300.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.ActiveCfg = Debug|x64
+		{B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.Build.0 = Debug|x64
+		{B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.ActiveCfg = Release|x64
+		{B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {862404ED-03D5-41D1-B5BB-72FD8BD05038}
+	EndGlobalSection
+EndGlobal
diff --git a/Tests/ProjectFormats/300/QtProjectV300.ui b/Tests/ProjectFormats/300/QtProjectV300.ui
new file mode 100644
index 0000000..74ffe53
--- /dev/null
+++ b/Tests/ProjectFormats/300/QtProjectV300.ui
@@ -0,0 +1,29 @@
+<UI version="4.0" >
+ <class>QtProjectV300Class</class>
+ <widget class="QMainWindow" name="QtProjectV300Class" >
+  <property name="objectName" >
+   <string notr="true">QtProjectV300Class</string>
+  </property>
+  <property name="geometry" >
+   <rect>
+	<x>0</x>
+	<y>0</y>
+	<width>600</width>
+	<height>400</height>
+   </rect>
+  </property>
+  <property name="windowTitle" >
+   <string>QtProjectV300</string>
+  </property>
+  <widget class="QMenuBar" name="menuBar" />
+  <widget class="QToolBar" name="mainToolBar" />
+  <widget class="QWidget" name="centralWidget" />
+  <widget class="QStatusBar" name="statusBar" />
+ </widget>
+ <layoutDefault spacing="6" margin="11" />
+ <pixmapfunction></pixmapfunction>
+ <resources>
+   <include location="QtProjectV300.qrc"/>
+ </resources>
+ <connections/>
+</UI>
diff --git a/Tests/ProjectFormats/300/QtProjectV300.vcxproj b/Tests/ProjectFormats/300/QtProjectV300.vcxproj
new file mode 100644
index 0000000..276f090
--- /dev/null
+++ b/Tests/ProjectFormats/300/QtProjectV300.vcxproj
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{B12702AD-ABFB-343A-A199-8E24837244A3}</ProjectGuid>
+    <Keyword>QtVS_v300</Keyword>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+    <QtInstall>msvc2019_64</QtInstall>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+    <QtInstall>msvc2019_64</QtInstall>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <PropertyGroup Condition="'$(QtMsBuild)'=='' or !Exists('$(QtMsBuild)\qt.targets')">
+    <QtMsBuild>$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
+    <Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
+  </Target>
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')">
+    <Import Project="$(QtMsBuild)\qt.props" />
+  </ImportGroup>
+  <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <QtModules>core;gui;widgets</QtModules>
+  </PropertyGroup>
+  <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <QtModules>core;gui;widgets</QtModules>
+  </PropertyGroup>
+  <ImportGroup Label="ExtensionSettings" />
+  <ImportGroup Label="Shared" />
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <Optimization>Disabled</Optimization>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat />
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="main.cpp" />
+    <ClCompile Include="QtProjectV300.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <QtMoc Include="QtProjectV300.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <QtUic Include="QtProjectV300.ui" />
+  </ItemGroup>
+  <ItemGroup>
+    <QtRcc Include="QtProjectV300.qrc" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
+    <Import Project="$(QtMsBuild)\qt.targets" />
+  </ImportGroup>
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/Tests/ProjectFormats/300/QtProjectV300.vcxproj.filters b/Tests/ProjectFormats/300/QtProjectV300.vcxproj.filters
new file mode 100644
index 0000000..8c77244
--- /dev/null
+++ b/Tests/ProjectFormats/300/QtProjectV300.vcxproj.filters
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}</UniqueIdentifier>
+      <Extensions>qrc;*</Extensions>
+      <ParseFiles>false</ParseFiles>
+    </Filter>
+    <Filter Include="Form Files">
+      <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
+      <Extensions>ui</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}</UniqueIdentifier>
+      <Extensions>qrc;*</Extensions>
+      <ParseFiles>false</ParseFiles>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="main.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="QtProjectV300.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <QtMoc Include="QtProjectV300.h">
+      <Filter>Header Files</Filter>
+    </QtMoc>
+  </ItemGroup>
+  <ItemGroup>
+    <QtUic Include="QtProjectV300.ui">
+      <Filter>Form Files</Filter>
+    </QtUic>
+  </ItemGroup>
+  <ItemGroup>
+    <QtRcc Include="QtProjectV300.qrc">
+      <Filter>Resource Files</Filter>
+    </QtRcc>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/Tests/ProjectFormats/300/main.cpp b/Tests/ProjectFormats/300/main.cpp
new file mode 100644
index 0000000..48ff587
--- /dev/null
+++ b/Tests/ProjectFormats/300/main.cpp
@@ -0,0 +1,10 @@
+#include "QtProjectV300.h"
+#include <QtWidgets/QApplication>
+
+int main(int argc, char *argv[])
+{
+	QApplication a(argc, argv);
+	QtProjectV300 w;
+	w.show();
+	return a.exec();
+}
diff --git a/Tests/ProjectFormats/301/QtProjectV301.cpp b/Tests/ProjectFormats/301/QtProjectV301.cpp
new file mode 100644
index 0000000..7a1e8ea
--- /dev/null
+++ b/Tests/ProjectFormats/301/QtProjectV301.cpp
@@ -0,0 +1,7 @@
+#include "QtProjectV301.h"
+
+QtProjectV301::QtProjectV301(QWidget *parent)
+	: QMainWindow(parent)
+{
+	ui.setupUi(this);
+}
diff --git a/Tests/ProjectFormats/301/QtProjectV301.h b/Tests/ProjectFormats/301/QtProjectV301.h
new file mode 100644
index 0000000..bfe8d95
--- /dev/null
+++ b/Tests/ProjectFormats/301/QtProjectV301.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <QtWidgets/QMainWindow>
+#include "ui_QtProjectV301.h"
+
+class QtProjectV301 : public QMainWindow
+{
+	Q_OBJECT
+
+public:
+	QtProjectV301(QWidget *parent = Q_NULLPTR);
+
+private:
+	Ui::QtProjectV301Class ui;
+};
diff --git a/Tests/ProjectFormats/301/QtProjectV301.qrc b/Tests/ProjectFormats/301/QtProjectV301.qrc
new file mode 100644
index 0000000..3c3a0f3
--- /dev/null
+++ b/Tests/ProjectFormats/301/QtProjectV301.qrc
@@ -0,0 +1,4 @@
+<RCC>
+    <qresource prefix="QtProjectV301">
+    </qresource>
+</RCC>
diff --git a/Tests/ProjectFormats/301/QtProjectV301.sln b/Tests/ProjectFormats/301/QtProjectV301.sln
new file mode 100644
index 0000000..909bab4
--- /dev/null
+++ b/Tests/ProjectFormats/301/QtProjectV301.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.32106.194
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QtProjectV301", "QtProjectV301.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.ActiveCfg = Debug|x64
+		{B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.Build.0 = Debug|x64
+		{B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.ActiveCfg = Release|x64
+		{B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {AD220BEA-2E4C-4346-9387-E61F9D9E6181}
+	EndGlobalSection
+EndGlobal
diff --git a/Tests/ProjectFormats/301/QtProjectV301.ui b/Tests/ProjectFormats/301/QtProjectV301.ui
new file mode 100644
index 0000000..c25f457
--- /dev/null
+++ b/Tests/ProjectFormats/301/QtProjectV301.ui
@@ -0,0 +1,29 @@
+<UI version="4.0" >
+ <class>QtProjectV301Class</class>
+ <widget class="QMainWindow" name="QtProjectV301Class" >
+  <property name="objectName" >
+   <string notr="true">QtProjectV301Class</string>
+  </property>
+  <property name="geometry" >
+   <rect>
+	<x>0</x>
+	<y>0</y>
+	<width>600</width>
+	<height>400</height>
+   </rect>
+  </property>
+  <property name="windowTitle" >
+   <string>QtProjectV301</string>
+  </property>
+  <widget class="QMenuBar" name="menuBar" />
+  <widget class="QToolBar" name="mainToolBar" />
+  <widget class="QWidget" name="centralWidget" />
+  <widget class="QStatusBar" name="statusBar" />
+ </widget>
+ <layoutDefault spacing="6" margin="11" />
+ <pixmapfunction></pixmapfunction>
+ <resources>
+   <include location="QtProjectV301.qrc"/>
+ </resources>
+ <connections/>
+</UI>
diff --git a/Tests/ProjectFormats/301/QtProjectV301.vcxproj b/Tests/ProjectFormats/301/QtProjectV301.vcxproj
new file mode 100644
index 0000000..78b4aa7
--- /dev/null
+++ b/Tests/ProjectFormats/301/QtProjectV301.vcxproj
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{B12702AD-ABFB-343A-A199-8E24837244A3}</ProjectGuid>
+    <Keyword>QtVS_v301</Keyword>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <PropertyGroup Condition="'$(QtMsBuild)'=='' or !Exists('$(QtMsBuild)\qt.targets')">
+    <QtMsBuild>$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
+    <Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
+  </Target>
+  <ImportGroup Label="ExtensionSettings" />
+  <ImportGroup Label="Shared" />
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
+    <Import Project="$(QtMsBuild)\qt_defaults.props" />
+  </ImportGroup>
+  <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <QtInstall>msvc2019_64</QtInstall>
+    <QtModules>core;gui;widgets</QtModules>
+  </PropertyGroup>
+  <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <QtInstall>msvc2019_64</QtInstall>
+    <QtModules>core;gui;widgets</QtModules>
+  </PropertyGroup>
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')">
+    <Import Project="$(QtMsBuild)\qt.props" />
+  </ImportGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <Optimization>Disabled</Optimization>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat />
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="main.cpp" />
+    <ClCompile Include="QtProjectV301.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <QtMoc Include="QtProjectV301.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <QtUic Include="QtProjectV301.ui" />
+  </ItemGroup>
+  <ItemGroup>
+    <QtRcc Include="QtProjectV301.qrc" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
+    <Import Project="$(QtMsBuild)\qt.targets" />
+  </ImportGroup>
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/Tests/ProjectFormats/301/QtProjectV301.vcxproj.filters b/Tests/ProjectFormats/301/QtProjectV301.vcxproj.filters
new file mode 100644
index 0000000..62f11c2
--- /dev/null
+++ b/Tests/ProjectFormats/301/QtProjectV301.vcxproj.filters
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}</UniqueIdentifier>
+      <Extensions>qrc;*</Extensions>
+      <ParseFiles>false</ParseFiles>
+    </Filter>
+    <Filter Include="Form Files">
+      <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
+      <Extensions>ui</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}</UniqueIdentifier>
+      <Extensions>qrc;*</Extensions>
+      <ParseFiles>false</ParseFiles>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="main.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="QtProjectV301.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <QtMoc Include="QtProjectV301.h">
+      <Filter>Header Files</Filter>
+    </QtMoc>
+  </ItemGroup>
+  <ItemGroup>
+    <QtUic Include="QtProjectV301.ui">
+      <Filter>Form Files</Filter>
+    </QtUic>
+  </ItemGroup>
+  <ItemGroup>
+    <QtRcc Include="QtProjectV301.qrc">
+      <Filter>Resource Files</Filter>
+    </QtRcc>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/Tests/ProjectFormats/301/main.cpp b/Tests/ProjectFormats/301/main.cpp
new file mode 100644
index 0000000..f12d171
--- /dev/null
+++ b/Tests/ProjectFormats/301/main.cpp
@@ -0,0 +1,10 @@
+#include "QtProjectV301.h"
+#include <QtWidgets/QApplication>
+
+int main(int argc, char *argv[])
+{
+	QApplication a(argc, argv);
+	QtProjectV301 w;
+	w.show();
+	return a.exec();
+}
diff --git a/Tests/ProjectFormats/302/QtProjectV302.cpp b/Tests/ProjectFormats/302/QtProjectV302.cpp
new file mode 100644
index 0000000..a7d523a
--- /dev/null
+++ b/Tests/ProjectFormats/302/QtProjectV302.cpp
@@ -0,0 +1,7 @@
+#include "QtProjectV302.h"
+
+QtProjectV302::QtProjectV302(QWidget *parent)
+    : QMainWindow(parent)
+{
+    ui.setupUi(this);
+}
diff --git a/Tests/ProjectFormats/302/QtProjectV302.h b/Tests/ProjectFormats/302/QtProjectV302.h
new file mode 100644
index 0000000..3cef345
--- /dev/null
+++ b/Tests/ProjectFormats/302/QtProjectV302.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <QtWidgets/QMainWindow>
+#include "ui_QtProjectV302.h"
+
+class QtProjectV302 : public QMainWindow
+{
+    Q_OBJECT
+
+public:
+    QtProjectV302(QWidget *parent = Q_NULLPTR);
+
+private:
+    Ui::QtProjectV302Class ui;
+};
diff --git a/Tests/ProjectFormats/302/QtProjectV302.qrc b/Tests/ProjectFormats/302/QtProjectV302.qrc
new file mode 100644
index 0000000..de388f6
--- /dev/null
+++ b/Tests/ProjectFormats/302/QtProjectV302.qrc
@@ -0,0 +1,4 @@
+<RCC>
+    <qresource prefix="QtProjectV302">
+    </qresource>
+</RCC>
diff --git a/Tests/ProjectFormats/302/QtProjectV302.sln b/Tests/ProjectFormats/302/QtProjectV302.sln
new file mode 100644
index 0000000..5cc4823
--- /dev/null
+++ b/Tests/ProjectFormats/302/QtProjectV302.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.32106.194
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QtProjectV302", "QtProjectV302.vcxproj", "{10A7CC05-6663-4C63-906F-E56EDF8218CA}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{10A7CC05-6663-4C63-906F-E56EDF8218CA}.Debug|x64.ActiveCfg = Debug|x64
+		{10A7CC05-6663-4C63-906F-E56EDF8218CA}.Debug|x64.Build.0 = Debug|x64
+		{10A7CC05-6663-4C63-906F-E56EDF8218CA}.Release|x64.ActiveCfg = Release|x64
+		{10A7CC05-6663-4C63-906F-E56EDF8218CA}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {4FB5DF86-4C19-4C53-B0CC-EAA09A44D321}
+	EndGlobalSection
+EndGlobal
diff --git a/Tests/ProjectFormats/302/QtProjectV302.ui b/Tests/ProjectFormats/302/QtProjectV302.ui
new file mode 100644
index 0000000..4e0ff07
--- /dev/null
+++ b/Tests/ProjectFormats/302/QtProjectV302.ui
@@ -0,0 +1,28 @@
+<UI version="4.0" >
+ <class>QtProjectV302Class</class>
+ <widget class="QMainWindow" name="QtProjectV302Class" >
+  <property name="objectName" >
+   <string notr="true">QtProjectV302Class</string>
+  </property>
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>600</width>
+    <height>400</height>
+   </rect>
+  </property>
+  <property name="windowTitle" >
+   <string>QtProjectV302</string>
+  </property>  <widget class="QMenuBar" name="menuBar" />
+  <widget class="QToolBar" name="mainToolBar" />
+  <widget class="QWidget" name="centralWidget" />
+  <widget class="QStatusBar" name="statusBar" />
+ </widget>
+ <layoutDefault spacing="6" margin="11" />
+ <pixmapfunction></pixmapfunction>
+ <resources>
+   <include location="QtProjectV302.qrc"/>
+ </resources>
+ <connections/>
+</UI>
diff --git a/Tests/ProjectFormats/302/QtProjectV302.vcxproj b/Tests/ProjectFormats/302/QtProjectV302.vcxproj
new file mode 100644
index 0000000..05b8241
--- /dev/null
+++ b/Tests/ProjectFormats/302/QtProjectV302.vcxproj
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{10A7CC05-6663-4C63-906F-E56EDF8218CA}</ProjectGuid>
+    <Keyword>QtVS_v302</Keyword>
+    <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">10.0.19041.0</WindowsTargetPlatformVersion>
+    <QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')"
+      >$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <Target Name="QtMsBuildNotFound"
+    BeforeTargets="CustomBuild;ClCompile"
+    Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
+    <Message Importance="High"
+      Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
+  </Target>
+  <ImportGroup Label="ExtensionSettings" />
+  <ImportGroup Label="Shared" />
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
+    <Import Project="$(QtMsBuild)\qt_defaults.props" />
+  </ImportGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="QtSettings">
+    <QtInstall>msvc2019_64</QtInstall>
+    <QtModules>core;gui;widgets</QtModules>
+    <QtBuildConfig>debug</QtBuildConfig>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="QtSettings">
+    <QtInstall>msvc2019_64</QtInstall>
+    <QtModules>core;gui;widgets</QtModules>
+    <QtBuildConfig>release</QtBuildConfig>
+  </PropertyGroup>
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')">
+    <Import Project="$(QtMsBuild)\qt.props" />
+  </ImportGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
+    <ClCompile>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <Optimization>Disabled</Optimization>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
+    <ClCompile>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat>None</DebugInformationFormat>
+      <Optimization>MaxSpeed</Optimization>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <QtRcc Include="QtProjectV302.qrc"/>
+    <QtUic Include="QtProjectV302.ui"/>
+    <QtMoc Include="QtProjectV302.h"/>
+    <ClCompile Include="QtProjectV302.cpp"/>
+    <ClCompile Include="main.cpp"/>
+
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
+    <Import Project="$(QtMsBuild)\qt.targets" />
+  </ImportGroup>
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/Tests/ProjectFormats/302/QtProjectV302.vcxproj.filters b/Tests/ProjectFormats/302/QtProjectV302.vcxproj.filters
new file mode 100644
index 0000000..c68f29a
--- /dev/null
+++ b/Tests/ProjectFormats/302/QtProjectV302.vcxproj.filters
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+    <Filter Include="Form Files">
+      <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
+      <Extensions>ui</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}</UniqueIdentifier>
+      <Extensions>qrc;*</Extensions>
+      <ParseFiles>false</ParseFiles>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <QtUic Include="QtProjectV302.ui">
+      <Filter>Resource Files</Filter>
+    </QtUic>
+    <QtMoc Include="QtProjectV302.h">
+      <Filter>Header Files</Filter>
+    </QtMoc>
+    <ClCompile Include="QtProjectV302.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ResourceCompile Include="$pro_name$.rc">
+    </ResourceCompile>
+    <None Include="$pro_name$.ico">
+      <Filter>Resource Files</Filter>
+    </None>
+    <None Include="$pro_name$.def">
+      <Filter>Resource Files</Filter>
+    </None>
+
+  </ItemGroup>
+</Project>
diff --git a/Tests/ProjectFormats/302/main.cpp b/Tests/ProjectFormats/302/main.cpp
new file mode 100644
index 0000000..aa6a9e2
--- /dev/null
+++ b/Tests/ProjectFormats/302/main.cpp
@@ -0,0 +1,10 @@
+#include "QtProjectV302.h"
+#include <QtWidgets/QApplication>
+
+int main(int argc, char *argv[])
+{
+    QApplication a(argc, argv);
+    QtProjectV302 w;
+    w.show();
+    return a.exec();
+}
diff --git a/Tests/ProjectFormats/303/QtProjectV303.cpp b/Tests/ProjectFormats/303/QtProjectV303.cpp
new file mode 100644
index 0000000..9c2b3ff
--- /dev/null
+++ b/Tests/ProjectFormats/303/QtProjectV303.cpp
@@ -0,0 +1,7 @@
+#include "QtProjectV303.h"
+
+QtProjectV303::QtProjectV303(QWidget *parent)
+    : QMainWindow(parent)
+{
+    ui.setupUi(this);
+}
diff --git a/Tests/ProjectFormats/303/QtProjectV303.h b/Tests/ProjectFormats/303/QtProjectV303.h
new file mode 100644
index 0000000..777c5fd
--- /dev/null
+++ b/Tests/ProjectFormats/303/QtProjectV303.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <QtWidgets/QMainWindow>
+#include "ui_QtProjectV303.h"
+
+class QtProjectV303 : public QMainWindow
+{
+    Q_OBJECT
+
+public:
+    QtProjectV303(QWidget *parent = Q_NULLPTR);
+
+private:
+    Ui::QtProjectV303Class ui;
+};
diff --git a/Tests/ProjectFormats/303/QtProjectV303.qrc b/Tests/ProjectFormats/303/QtProjectV303.qrc
new file mode 100644
index 0000000..7af7692
--- /dev/null
+++ b/Tests/ProjectFormats/303/QtProjectV303.qrc
@@ -0,0 +1,4 @@
+<RCC>
+    <qresource prefix="QtProjectV303">
+    </qresource>
+</RCC>
diff --git a/Tests/ProjectFormats/303/QtProjectV303.sln b/Tests/ProjectFormats/303/QtProjectV303.sln
new file mode 100644
index 0000000..641c2a5
--- /dev/null
+++ b/Tests/ProjectFormats/303/QtProjectV303.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.32106.194
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QtProjectV303", "QtProjectV303.vcxproj", "{812E4050-B861-4918-A0DC-53053B848372}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{812E4050-B861-4918-A0DC-53053B848372}.Debug|x64.ActiveCfg = Debug|x64
+		{812E4050-B861-4918-A0DC-53053B848372}.Debug|x64.Build.0 = Debug|x64
+		{812E4050-B861-4918-A0DC-53053B848372}.Release|x64.ActiveCfg = Release|x64
+		{812E4050-B861-4918-A0DC-53053B848372}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {7F50220B-20CF-415F-80A5-DA078F8F82BF}
+	EndGlobalSection
+EndGlobal
diff --git a/Tests/ProjectFormats/303/QtProjectV303.ui b/Tests/ProjectFormats/303/QtProjectV303.ui
new file mode 100644
index 0000000..8295da9
--- /dev/null
+++ b/Tests/ProjectFormats/303/QtProjectV303.ui
@@ -0,0 +1,28 @@
+<UI version="4.0" >
+ <class>QtProjectV303Class</class>
+ <widget class="QMainWindow" name="QtProjectV303Class" >
+  <property name="objectName" >
+   <string notr="true">QtProjectV303Class</string>
+  </property>
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>600</width>
+    <height>400</height>
+   </rect>
+  </property>
+  <property name="windowTitle" >
+   <string>QtProjectV303</string>
+  </property>  <widget class="QMenuBar" name="menuBar" />
+  <widget class="QToolBar" name="mainToolBar" />
+  <widget class="QWidget" name="centralWidget" />
+  <widget class="QStatusBar" name="statusBar" />
+ </widget>
+ <layoutDefault spacing="6" margin="11" />
+ <pixmapfunction></pixmapfunction>
+ <resources>
+   <include location="QtProjectV303.qrc"/>
+ </resources>
+ <connections/>
+</UI>
diff --git a/Tests/ProjectFormats/303/QtProjectV303.vcxproj b/Tests/ProjectFormats/303/QtProjectV303.vcxproj
new file mode 100644
index 0000000..9c3febf
--- /dev/null
+++ b/Tests/ProjectFormats/303/QtProjectV303.vcxproj
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{812E4050-B861-4918-A0DC-53053B848372}</ProjectGuid>
+    <Keyword>QtVS_v303</Keyword>
+    <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">10.0.19041.0</WindowsTargetPlatformVersion>
+    <QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')"
+      >$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <Target Name="QtMsBuildNotFound"
+    BeforeTargets="CustomBuild;ClCompile"
+    Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
+    <Message Importance="High"
+      Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
+  </Target>
+  <ImportGroup Label="ExtensionSettings" />
+  <ImportGroup Label="Shared" />
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
+    <Import Project="$(QtMsBuild)\qt_defaults.props" />
+  </ImportGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="QtSettings">
+    <QtInstall>msvc2019_64</QtInstall>
+    <QtModules>core;gui;widgets</QtModules>
+    <QtBuildConfig>debug</QtBuildConfig>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="QtSettings">
+    <QtInstall>msvc2019_64</QtInstall>
+    <QtModules>core;gui;widgets</QtModules>
+    <QtBuildConfig>release</QtBuildConfig>
+  </PropertyGroup>
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')">
+    <Import Project="$(QtMsBuild)\qt.props" />
+  </ImportGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
+    <ClCompile>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <Optimization>Disabled</Optimization>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
+    <ClCompile>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat>None</DebugInformationFormat>
+      <Optimization>MaxSpeed</Optimization>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <QtRcc Include="QtProjectV303.qrc"/>
+    <QtUic Include="QtProjectV303.ui"/>
+    <QtMoc Include="QtProjectV303.h"/>
+    <ClCompile Include="QtProjectV303.cpp"/>
+    <ClCompile Include="main.cpp"/>
+
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
+    <Import Project="$(QtMsBuild)\qt.targets" />
+  </ImportGroup>
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/Tests/ProjectFormats/303/QtProjectV303.vcxproj.filters b/Tests/ProjectFormats/303/QtProjectV303.vcxproj.filters
new file mode 100644
index 0000000..ebb32d8
--- /dev/null
+++ b/Tests/ProjectFormats/303/QtProjectV303.vcxproj.filters
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+    <Filter Include="Form Files">
+      <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
+      <Extensions>ui</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}</UniqueIdentifier>
+      <Extensions>qrc;*</Extensions>
+      <ParseFiles>false</ParseFiles>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <QtRcc Include="QtProjectV303.qrc">
+      <Filter>Resource Files</Filter>
+    </QtRcc>
+    <QtUic Include="QtProjectV303.ui">
+      <Filter>Resource Files</Filter>
+    </QtUic>
+    <QtMoc Include="QtProjectV303.h">
+      <Filter>Header Files</Filter>
+    </QtMoc>
+    <ClCompile Include="QtProjectV303.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ResourceCompile Include="$pro_name$.rc">
+    </ResourceCompile>
+    <None Include="$pro_name$.ico">
+      <Filter>Resource Files</Filter>
+    </None>
+    <None Include="$pro_name$.def">
+      <Filter>Resource Files</Filter>
+    </None>
+
+  </ItemGroup>
+</Project>
diff --git a/Tests/ProjectFormats/303/main.cpp b/Tests/ProjectFormats/303/main.cpp
new file mode 100644
index 0000000..7d8e068
--- /dev/null
+++ b/Tests/ProjectFormats/303/main.cpp
@@ -0,0 +1,10 @@
+#include "QtProjectV303.h"
+#include <QtWidgets/QApplication>
+
+int main(int argc, char *argv[])
+{
+    QApplication a(argc, argv);
+    QtProjectV303 w;
+    w.show();
+    return a.exec();
+}
diff --git a/Tests/ProjectFormats/304/QtProjectV304.cpp b/Tests/ProjectFormats/304/QtProjectV304.cpp
new file mode 100644
index 0000000..5f32d67
--- /dev/null
+++ b/Tests/ProjectFormats/304/QtProjectV304.cpp
@@ -0,0 +1,10 @@
+#include "QtProjectV304.h"
+
+QtProjectV304::QtProjectV304(QWidget *parent)
+    : QMainWindow(parent)
+{
+    ui.setupUi(this);
+}
+
+QtProjectV304::~QtProjectV304()
+{}
diff --git a/Tests/ProjectFormats/304/QtProjectV304.h b/Tests/ProjectFormats/304/QtProjectV304.h
new file mode 100644
index 0000000..ecd09cd
--- /dev/null
+++ b/Tests/ProjectFormats/304/QtProjectV304.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <QtWidgets/QMainWindow>
+#include "ui_QtProjectV304.h"
+
+class QtProjectV304 : public QMainWindow
+{
+    Q_OBJECT
+
+public:
+    QtProjectV304(QWidget *parent = nullptr);
+    ~QtProjectV304();
+
+private:
+    Ui::QtProjectV304Class ui;
+};
diff --git a/Tests/ProjectFormats/304/QtProjectV304.qrc b/Tests/ProjectFormats/304/QtProjectV304.qrc
new file mode 100644
index 0000000..3466c73
--- /dev/null
+++ b/Tests/ProjectFormats/304/QtProjectV304.qrc
@@ -0,0 +1,4 @@
+<RCC>
+    <qresource prefix="QtProjectV304">
+    </qresource>
+</RCC>
diff --git a/Tests/ProjectFormats/304/QtProjectV304.sln b/Tests/ProjectFormats/304/QtProjectV304.sln
new file mode 100644
index 0000000..3ebf58a
--- /dev/null
+++ b/Tests/ProjectFormats/304/QtProjectV304.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31919.166
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QtProjectV304", "QtProjectV304.vcxproj", "{923588D5-2AA5-4B0F-8110-56BEEBB531D5}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{923588D5-2AA5-4B0F-8110-56BEEBB531D5}.Debug|x64.ActiveCfg = Debug|x64
+		{923588D5-2AA5-4B0F-8110-56BEEBB531D5}.Debug|x64.Build.0 = Debug|x64
+		{923588D5-2AA5-4B0F-8110-56BEEBB531D5}.Release|x64.ActiveCfg = Release|x64
+		{923588D5-2AA5-4B0F-8110-56BEEBB531D5}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {AE3F49BF-2193-402A-AA0C-E77FF9B63160}
+	EndGlobalSection
+EndGlobal
diff --git a/Tests/ProjectFormats/304/QtProjectV304.ui b/Tests/ProjectFormats/304/QtProjectV304.ui
new file mode 100644
index 0000000..73f83d6
--- /dev/null
+++ b/Tests/ProjectFormats/304/QtProjectV304.ui
@@ -0,0 +1,28 @@
+<UI version="4.0" >
+ <class>QtProjectV304Class</class>
+ <widget class="QMainWindow" name="QtProjectV304Class" >
+  <property name="objectName" >
+   <string notr="true">QtProjectV304Class</string>
+  </property>
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>600</width>
+    <height>400</height>
+   </rect>
+  </property>
+  <property name="windowTitle" >
+   <string>QtProjectV304</string>
+  </property>  <widget class="QMenuBar" name="menuBar" />
+  <widget class="QToolBar" name="mainToolBar" />
+  <widget class="QWidget" name="centralWidget" />
+  <widget class="QStatusBar" name="statusBar" />
+ </widget>
+ <layoutDefault spacing="6" margin="11" />
+ <pixmapfunction></pixmapfunction>
+ <resources>
+   <include location="QtProjectV304.qrc"/>
+ </resources>
+ <connections/>
+</UI>
diff --git a/Tests/ProjectFormats/304/QtProjectV304.vcxproj b/Tests/ProjectFormats/304/QtProjectV304.vcxproj
new file mode 100644
index 0000000..9c43ee5
--- /dev/null
+++ b/Tests/ProjectFormats/304/QtProjectV304.vcxproj
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="17.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{923588D5-2AA5-4B0F-8110-56BEEBB531D5}</ProjectGuid>
+    <Keyword>QtVS_v304</Keyword>
+    <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">10.0.19041.0</WindowsTargetPlatformVersion>
+    <QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')"
+      >$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v143</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v143</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
+    <Import Project="$(QtMsBuild)\qt_defaults.props" />
+  </ImportGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="QtSettings">
+    <QtInstall>5.15.10_msvc2019_64</QtInstall>
+    <QtModules>core;gui;widgets</QtModules>
+    <QtBuildConfig>debug</QtBuildConfig>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="QtSettings">
+    <QtInstall>5.15.10_msvc2019_64</QtInstall>
+    <QtModules>core;gui;widgets</QtModules>
+    <QtBuildConfig>release</QtBuildConfig>
+  </PropertyGroup>
+  <Target Name="QtMsBuildNotFound"
+    BeforeTargets="CustomBuild;ClCompile"
+    Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
+    <Message Importance="High"
+      Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
+  </Target>
+  <ImportGroup Label="ExtensionSettings" />
+  <ImportGroup Label="Shared" />
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(QtMsBuild)\Qt.props" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(QtMsBuild)\Qt.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
+    <ClCompile>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <Optimization>Disabled</Optimization>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
+    <ClCompile>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat>None</DebugInformationFormat>
+      <Optimization>MaxSpeed</Optimization>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <QtRcc Include="QtProjectV304.qrc"/>
+    <QtUic Include="QtProjectV304.ui"/>
+    <QtMoc Include="QtProjectV304.h"/>
+    <ClCompile Include="QtProjectV304.cpp"/>
+    <ClCompile Include="main.cpp"/>
+
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
+    <Import Project="$(QtMsBuild)\qt.targets" />
+  </ImportGroup>
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/Tests/ProjectFormats/304/QtProjectV304.vcxproj.filters b/Tests/ProjectFormats/304/QtProjectV304.vcxproj.filters
new file mode 100644
index 0000000..a001b10
--- /dev/null
+++ b/Tests/ProjectFormats/304/QtProjectV304.vcxproj.filters
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+    <Filter Include="Form Files">
+      <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
+      <Extensions>ui</Extensions>
+    </Filter>
+    <Filter Include="Translation Files">
+      <UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>
+      <Extensions>ts</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <QtRcc Include="QtProjectV304.qrc">
+      <Filter>Resource Files</Filter>
+    </QtRcc>
+    <QtUic Include="QtProjectV304.ui">
+      <Filter>Form Files</Filter>
+    </QtUic>
+    <QtMoc Include="QtProjectV304.h">
+      <Filter>Header Files</Filter>
+    </QtMoc>
+    <ClCompile Include="QtProjectV304.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ResourceCompile Include="$pro_name$.rc">
+    </ResourceCompile>
+    <None Include="$pro_name$.ico">
+      <Filter>Resource Files</Filter>
+    </None>
+    <None Include="$pro_name$.def">
+      <Filter>Resource Files</Filter>
+    </None>
+
+  </ItemGroup>
+</Project>
diff --git a/Tests/ProjectFormats/304/main.cpp b/Tests/ProjectFormats/304/main.cpp
new file mode 100644
index 0000000..d448992
--- /dev/null
+++ b/Tests/ProjectFormats/304/main.cpp
@@ -0,0 +1,10 @@
+#include "QtProjectV304.h"
+#include <QtWidgets/QApplication>
+
+int main(int argc, char *argv[])
+{
+    QApplication a(argc, argv);
+    QtProjectV304 w;
+    w.show();
+    return a.exec();
+}
diff --git a/Tests/ProjectFormats/ProjectFormats.md b/Tests/ProjectFormats/ProjectFormats.md
new file mode 100644
index 0000000..5702dc4
--- /dev/null
+++ b/Tests/ProjectFormats/ProjectFormats.md
@@ -0,0 +1,1324 @@
+# Qt VS Tools - Project format versions
+
+## Contents
+
+* [Project format v1.0](#project-format-v1.0)
+* [Project format v2.0](#project-format-v2.0)
+* [Project format v3.0](#project-format-v3.0)
+* [Project format v3.1](#project-format-v3.1)
+* [Project format v3.2](#project-format-v3.2)
+* [Project format v3.3](#project-format-v3.3)
+* [Project format v3.4](#project-format-v3.4)
+* [Example projects](#example-projects)
+    * [v1.0](#v1.0)
+    * [v2.0](#v2.0)
+    * [v3.0](#v3.0)
+    * [v3.1](#v3.1)
+    * [v3.2](#v3.2)
+    * [v3.3](#v3.3)
+    * [v3.4](#v3.4)
+
+## Project format v1.0
+
+Output of `qmake` using the VC template:
+
+    qmake -tp vc
+
+### Project file outline
+
+- ItemGroup **ProjectConfiguration**
+- PropertyGroup **Globals**
+    - Keyword **Qt4VSv1.0**
+- Import **Microsoft.Cpp.Default.props**
+- PropertyGroup **Configuration**
+- Import **Microsoft.Cpp.props**
+- ImportGroup **ExtensionSettings**
+- ImportGroup **PropertySheets**
+- PropertyGroup **UserMacros**
+- PropertyGroup
+    - Property **OutDir**
+    - Property **IntDir**
+    - ...
+- ItemDefinitionGroup
+    - **ClCompile**
+    -  **Link**
+    - ...
+- ItemGroup
+    - **CustomBuild** (*MOC header*)
+    - *N* x **ClCompile** (*MOC-generated CPP source*), where N = number of configurations
+        - (*N* - 1) x **ExcludedFromBuild** (*configuration*)
+    - **CustomBuild** (*QRC resources*)
+    - *N* x **ClCompile** (*RCC-generated CPP source*), where N = number of configurations
+        - (*N* - 1) x **ExcludedFromBuild** (*configuration*)
+    - **CustomBuild** (*UI form*)
+    - **ClInclude** (*UIC-generated header*)
+    - **ClInclude** (*other headers*)
+    - **ClCompile** (*other CPP sources*)
+    - ...
+- Import **Microsoft.Cpp.targets**
+- ImportGroup **ExtensionTargets**
+
+## Project format v2.0
+**[Qt Visual Studio Tools v2.1.1](https://download.qt.io/official_releases/vsaddin/2.1.1/)**
+
+### Project file outline
+
+- ItemGroup **ProjectConfiguration**
+- PropertyGroup **Globals**
+    - Keyword **Qt4VSv1.0**
+- Import **Microsoft.Cpp.Default.props**
+- PropertyGroup **Configuration**
+- Import **Microsoft.Cpp.props**
+- ImportGroup **ExtensionSettings**
+- ImportGroup **Shared**
+- ImportGroup **PropertySheets**
+- PropertyGroup **UserMacros**
+- PropertyGroup
+    - Property **OutDir**
+    - Property **IntDir**
+    - ...
+- ItemDefinitionGroup
+    - **ClCompile**
+    -  **Link**
+    - ...
+- ItemGroup
+    - **CustomBuild** (*MOC header*)
+    - *N* x **ClCompile** (*MOC-generated CPP source*), where N = number of configurations
+        - (*N* - 1) x **ExcludedFromBuild** (*configuration*)
+    - **CustomBuild** (*QRC resources*)
+    - *N* x **ClCompile** (*RCC-generated CPP source*), where N = number of configurations
+        - (*N* - 1) x **ExcludedFromBuild** (*configuration*)
+    - **CustomBuild** (*UI form*)
+    - **ClInclude** (*UIC-generated header*)
+    - **ClInclude** (*other headers*)
+    - **ClCompile** (*other CPP sources*)
+    - ...
+- Import **Microsoft.Cpp.targets**
+- ImportGroup **ExtensionTargets**
+- ProjectExtensions / VisualStudio
+    - UserProperties
+        - **MocDir**
+        - **UicDir**
+        - **RccDir**
+        - **lupdateOptions**
+        - **lupdateOnBuild**
+        - **lreleaseOptions**
+        - **Qt5Version_x0020_x64**
+        - **MocOptions**
+
+## Project format v3.0
+**[Qt Visual Studio Tools v2.4.0](https://download.qt.io/official_releases/vsaddin/2.4.0/)**
+
+**`Edit Qt settings in property pages (V3 format)`**  
+`commit 805e9ed6f14fb0a4d9dd8ce6a23631ca215b304a`  
+`Author: Miguel Costa <miguel.costa@qt.io>`  
+`Date:   Thu Jun 20 13:54:49 2019 +0200`
+
+    Qt settings are now configured in the project property pages. This
+    includes the possibility to have different versions of the Qt settings
+    per project configuration. Previously, the Qt settings were edited in a
+    custom dialog, allowing only a single version of the settings that
+    would apply to all project configurations.
+
+    This change breaks the current version of the support for Qt VS Tools
+    projects. A new version (V3) of the project format is introduced. This
+    new format allows Qt settings to be stored in the same way as other
+    project properties. Previous versions will still work and a later change
+    will introduce the possibility to convert from previous versions to V3.
+
+### Project file outline
+
+- ItemGroup **ProjectConfiguration**
+- PropertyGroup **Globals**
+    - Keyword **QtVS_v300**
+- Import **Microsoft.Cpp.Default.props**
+- PropertyGroup **Configuration**
+- Import **Microsoft.Cpp.props**
+- PropertyGroup **if %QTMSBUILD% undefined**
+    - Property **QtMsBuild** = $(MSBuildProjectDirectory)\QtMsBuild
+- PropertyGroup
+    - Property **OutDir**
+    - Property **IntDir**
+    - ...
+- Target **QtMsBuildNotFound**
+- Import **qt.props**
+- PropertyGroup **QtSettings**
+- ImportGroup **ExtensionSettings**
+- ImportGroup **Shared**
+- ImportGroup **PropertySheets**
+- PropertyGroup **UserMacros**
+- ItemDefinitionGroup
+    - **ClCompile**
+    - **Link**
+    - **QtMoc**
+    - **QtRcc**
+    - **QtUic**
+    - ...
+- ItemGroup
+    - **QtMoc** (*MOC header*)
+    - **QtRcc** (*QRC resources*)
+    - **QtUic** (*UI form*)
+    - **ClInclude** (*other headers*)
+    - **ClCompile** (*other CPP sources*)
+    - ...
+- Import **Microsoft.Cpp.targets**
+- Import **qt.targets**
+- ImportGroup **ExtensionTargets**
+
+## Project format v3.1
+**[Qt Visual Studio Tools v2.4.2](https://download.qt.io/official_releases/vsaddin/2.4.2/)**
+
+**`Implement project format v3.1`**  
+`commit fdbec35c590f524f6f9ce8f2e6a7328f2f3df508`  
+`Author: Miguel Costa <miguel.costa@qt.io>`  
+`Date:   Wed Sep 18 18:47:30 2019 +0200`
+
+    This change introduces a revision of the v3 project format, which will
+    now allow Qt settings to reference user macros defined in imported
+    property sheets. This includes the following changes to the order of
+    property evaluation:
+     - "QtSettings" property group moved to after the import of user
+     property sheets;
+     - QtInstall property moved from the "Configuration" property group
+    to the "QtSettings" property group;
+     - Import of qt.props moved to after the "QtSettings" property group.
+
+### Project file outline
+
+- ItemGroup **ProjectConfiguration**
+- PropertyGroup **Globals**
+    - Keyword **QtVS_v301**
+- Import **Microsoft.Cpp.Default.props**
+- PropertyGroup **Configuration**
+    - Property **QtInstall**
+- Import **Microsoft.Cpp.props**
+- PropertyGroup (*if `%QTMSBUILD%` undefined*)
+    - Property **QtMsBuild** = $(MSBuildProjectDirectory)\QtMsBuild
+- PropertyGroup
+    - Property **OutDir**
+    - Property **IntDir**
+    - ...
+- Target **QtMsBuildNotFound**
+- ImportGroup **ExtensionSettings**
+- ImportGroup **Shared**
+- ImportGroup **PropertySheets**
+- PropertyGroup **UserMacros**
+- Import **qt.props**
+- PropertyGroup **QtSettings**
+- ItemDefinitionGroup
+    - **ClCompile**
+    - **Link**
+    - **QtMoc**
+    - **QtRcc**
+    - **QtUic**
+    - ...
+- ItemGroup
+    - **QtMoc** (*MOC header*)
+    - **QtRcc** (*QRC resources*)
+    - **QtUic** (*UI form*)
+    - **ClInclude** (*other headers*)
+    - **ClCompile** (*other CPP sources*)
+    - ...
+- Import **Microsoft.Cpp.targets**
+- Import **qt.targets**
+- ImportGroup **ExtensionTargets**
+
+## Project format v3.2
+**[Qt Visual Studio Tools v2.5.1](https://download.qt.io/official_releases/vsaddin/2.5.1/)**
+
+**`Fix incompatibilities with property sheets`**  
+`commit 1a93741cadaa26b49cc4dc02d09ea7249cbea6fe`  
+`Author: Miguel Costa <miguel.costa@qt.io>`  
+`Date:   Thu Nov 21 16:21:35 2019 +0100`
+
+    Updated the format of Qt projects to better match the requirements for
+    Visual Studio C++ projects (*) that enable integrating with the IDE, in
+    particular, that allow external property sheets to be referenced.
+(*) https://docs.microsoft.com/en-us/cpp/build/reference/cxproj-file-structure#per-configuration-propertygroup-elements
+
+### Project file outline
+
+- ItemGroup **ProjectConfiguration**
+- PropertyGroup **Globals**
+    - Keyword **QtVS_v302**
+    - Property (*if `%QTMSBUILD%` undefined*) **QtMsBuild** = $(MSBuildProjectDirectory)\QtMsBuild
+- Import **Microsoft.Cpp.Default.props**
+- PropertyGroup **Configuration**
+    - Property **QtInstall**
+- Import **Microsoft.Cpp.props**
+- Target **QtMsBuildNotFound**
+- ImportGroup **ExtensionSettings**
+- ImportGroup **Shared**
+- ImportGroup **PropertySheets**
+- PropertyGroup **UserMacros**
+- Import **qt_defaults.props**
+- PropertyGroup **QtSettings**
+- Import **qt.props**
+- ItemDefinitionGroup
+    - **ClCompile**
+    - **Link**
+    - **QtMoc**
+    - **QtRcc**
+    - **QtUic**
+    - ...
+- ItemGroup
+    - **QtMoc** (*MOC header*)
+    - **QtRcc** (*QRC resources*)
+    - **QtUic** (*UI form*)
+    - **ClInclude** (*other headers*)
+    - **ClCompile** (*other CPP sources*)
+    - ...
+- Import **Microsoft.Cpp.targets**
+- Import **qt.targets**
+- ImportGroup **ExtensionTargets**
+
+## Project format v3.3
+**[Qt Visual Studio Tools v2.6.0](https://download.qt.io/official_releases/vsaddin/2.6.0/)**
+
+**`Fix ignoring VC property changes (project format v3.3)`**  
+`commit 621efbcc92be6e1a9869a15a850b9bd8cccf2e97`  
+`Author: Miguel Costa <miguel.costa@qt.io>`  
+`Date:   Tue Jun 9 10:24:54 2020 +0200`
+
+    This change introduces project format version 3.3, which fixes issues
+    related to modified values of VC properties (e.g. $(IntDir)) being
+    ignored when evaluating Qt build settings.
+
+    MSBuild evaluates properties by order of definition; dependencies are
+    resolved by using the latest evaluation of referred properties. As such,
+    any subsequent changes to the value of dependencies will not be
+    reflected in previously evaluated properties.
+
+    Redefinitions of VC properties are stored in uncategorized property
+    groups (i.e. <PropertyGroup> elements without a Label attrib) inside the
+    MSBuild project file; if no available group is found, Visual Studio will
+    create a new one. The incorrect evaluation of Qt properties happens when
+    new property groups are created after the definition of Qt properties,
+    such that the evaluation of Qt properties will be using outdated values
+    of VC properties.
+
+    Project format version 3.3 addresses this issue by adding property
+    groups for VC property storage in a correct location, with respect to
+    Qt build settings definitions.
+
+### Project file outline
+
+- ItemGroup **ProjectConfiguration**
+- PropertyGroup **Globals**
+    - Keyword **QtVS_v303**
+    - Property (*if `%QTMSBUILD%` undefined*) **QtMsBuild** = $(MSBuildProjectDirectory)\QtMsBuild
+- Import **Microsoft.Cpp.Default.props**
+- PropertyGroup **Configuration**
+    - Property **QtInstall**
+- Import **Microsoft.Cpp.props**
+- Target **QtMsBuildNotFound**
+- ImportGroup **ExtensionSettings**
+- ImportGroup **Shared**
+- ImportGroup **PropertySheets**
+- PropertyGroup **UserMacros**
+- Import **qt_defaults.props**
+- PropertyGroup
+    - Property **OutDir**
+    - Property **IntDir**
+    - ...
+- PropertyGroup **QtSettings**
+- Import **qt.props**
+- ItemDefinitionGroup
+    - **ClCompile**
+    - **Link**
+    - **QtMoc**
+    - **QtRcc**
+    - **QtUic**
+    - ...
+- ItemGroup
+    - **QtMoc** (*MOC header*)
+    - **QtRcc** (*QRC resources*)
+    - **QtUic** (*UI form*)
+    - **ClInclude** (*other headers*)
+    - **ClCompile** (*other CPP sources*)
+    - ...
+- Import **Microsoft.Cpp.targets**
+- Import **qt.targets**
+- ImportGroup **ExtensionTargets**
+
+## Project format v3.4
+**>= [Qt Visual Studio Tools v2.7.1](https://download.qt.io/official_releases/vsaddin/2.7.1/)**
+
+**`Integrate Qt.props in the VS Property Manager`**  
+`commit cb9ec156845a9efc163a9c67d7a54c8ca790e805`  
+`Author: Miguel Costa <miguel.costa@qt.io>`  
+`Date:   Fri Dec 11 16:58:06 2020 +0100`
+
+    The Qt property definitions file (Qt.props) will now be shown in the
+    evaluation list of the Property Manager window. This allows the user to
+    customize the order of evaluation of Qt.props in relation to other
+    property files loaded during the build, thereby defining the correct
+    dependency between Qt properties and other build settings. Previously,
+    the order of evaluation of Qt.props was fixed and could only be changed
+    by manually editing the project file's XML.
+
+    Allowing Qt.props to be manipulated in the Property Manager window will
+    enable the user to define properties and default metadata within the
+    Qt.props itself. To ensure these custom definitions are not lost when
+    installing Qt/MSBuild files, the Qt.props file will no longer be
+    replaced during start-up.
+
+### Project file outline
+
+- ItemGroup **ProjectConfiguration**
+- PropertyGroup **Globals**
+    - Keyword **QtVS_v304**
+    - Property (*if `%QTMSBUILD%` undefined*) **QtMsBuild** = $(MSBuildProjectDirectory)\QtMsBuild
+- Import **Microsoft.Cpp.Default.props**
+- PropertyGroup **Configuration**
+    - Property **QtInstall**
+- Import **Microsoft.Cpp.props**
+- Import **qt_defaults.props**
+- PropertyGroup **QtSettings**
+- Target **QtMsBuildNotFound**
+- ImportGroup **ExtensionSettings**
+- ImportGroup **Shared**
+- ImportGroup **PropertySheets**
+    - Import **Qt.props**
+- PropertyGroup **UserMacros**
+- PropertyGroup
+    - Property **OutDir**
+    - Property **IntDir**
+    - ...
+- ItemDefinitionGroup
+    - **ClCompile**
+    - **Link**
+    - **QtMoc**
+    - **QtRcc**
+    - **QtUic**
+    - ...
+- ItemGroup
+    - **QtMoc** (*MOC header*)
+    - **QtRcc** (*QRC resources*)
+    - **QtUic** (*UI form*)
+    - **ClInclude** (*other headers*)
+    - **ClCompile** (*other CPP sources*)
+    - ...
+- Import **Microsoft.Cpp.targets**
+- Import **qt.targets**
+- ImportGroup **ExtensionTargets**
+
+## Example projects
+
+### v1.0
+
+#### `.vcxproj`
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{E5EA0EEF-BDC2-3484-A4F0-BA6C71E224CF}</ProjectGuid>
+    <RootNamespace>QtProjectV100</RootNamespace>
+    <Keyword>Qt4VSv1.0</Keyword>
+    <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformMinVersion>10.0.19041.0</WindowsTargetPlatformMinVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;" Label="Configuration">
+    <PlatformToolset>v142</PlatformToolset>
+    <OutputDirectory>release\</OutputDirectory>
+    <ATLMinimizesCRunTimeLibraryUsage>false</ATLMinimizesCRunTimeLibraryUsage>
+    <CharacterSet>NotSet</CharacterSet>
+    <ConfigurationType>Application</ConfigurationType>
+    <IntermediateDirectory>release\</IntermediateDirectory>
+    <PrimaryOutput>QtProjectV100</PrimaryOutput>
+  </PropertyGroup>
+  <PropertyGroup Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;" Label="Configuration">
+    <PlatformToolset>v142</PlatformToolset>
+    <OutputDirectory>debug\</OutputDirectory>
+    <ATLMinimizesCRunTimeLibraryUsage>false</ATLMinimizesCRunTimeLibraryUsage>
+    <CharacterSet>NotSet</CharacterSet>
+    <ConfigurationType>Application</ConfigurationType>
+    <IntermediateDirectory>debug\</IntermediateDirectory>
+    <PrimaryOutput>QtProjectV100</PrimaryOutput>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings" />
+  <ImportGroup Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists(&apos;$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props&apos;)" />
+  </ImportGroup>
+  <ImportGroup Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists(&apos;$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props&apos;)" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <OutDir Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">release\</OutDir>
+    <IntDir Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">release\</IntDir>
+    <TargetName Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">QtProjectV100</TargetName>
+    <IgnoreImportLibrary Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">true</IgnoreImportLibrary>
+    <LinkIncremental Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">false</LinkIncremental>
+    <OutDir Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">debug\</OutDir>
+    <IntDir Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">debug\</IntDir>
+    <TargetName Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">QtProjectV100</TargetName>
+    <IgnoreImportLibrary Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">true</IgnoreImportLibrary>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">
+    <ClCompile>
+      <AdditionalIncludeDirectories>.;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include\QtWidgets;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include\QtGui;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include\QtANGLE;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include\QtCore;release;.;/include;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\mkspecs\win32-msvc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions>
+      <AssemblerListingLocation>release\</AssemblerListingLocation>
+      <BrowseInformation>false</BrowseInformation>
+      <DebugInformationFormat>None</DebugInformationFormat>
+      <DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <ExceptionHandling>Sync</ExceptionHandling>
+      <ObjectFileName>release\</ObjectFileName>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;NDEBUG;QT_NO_DEBUG;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessToFile>false</PreprocessToFile>
+      <ProgramDataBaseFileName></ProgramDataBaseFileName>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <WarningLevel>Level3</WarningLevel>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>C:\lib\Qt\5.15.10\msvc2019_64\lib\Qt5Widgets.lib;C:\lib\Qt\5.15.10\msvc2019_64\lib\Qt5Gui.lib;C:\lib\Qt\5.15.10\msvc2019_64\lib\Qt5Core.lib;C:\lib\Qt\5.15.10\msvc2019_64\lib\qtmain.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>C:\openssl\lib;C:\Utils\my_sql\mysql-5.7.25-winx64\lib;C:\Utils\postgresql\pgsql\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalOptions>&quot;/MANIFESTDEPENDENCY:type=&apos;win32&apos; name=&apos;Microsoft.Windows.Common-Controls&apos; version=&apos;6.0.0.0&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos; processorArchitecture=&apos;*&apos;&quot; %(AdditionalOptions)</AdditionalOptions>
+      <DataExecutionPrevention>true</DataExecutionPrevention>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+      <IgnoreImportLibrary>true</IgnoreImportLibrary>
+      <LinkIncremental>false</LinkIncremental>
+      <OptimizeReferences>true</OptimizeReferences>
+      <OutputFile>$(OutDir)\QtProjectV100.exe</OutputFile>
+      <RandomizedBaseAddress>true</RandomizedBaseAddress>
+      <SubSystem>Windows</SubSystem>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+    </Link>
+    <Midl>
+      <DefaultCharType>Unsigned</DefaultCharType>
+      <EnableErrorChecks>None</EnableErrorChecks>
+      <WarningLevel>0</WarningLevel>
+    </Midl>
+    <ResourceCompile>
+      <PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;NDEBUG;QT_NO_DEBUG;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">
+    <ClCompile>
+      <AdditionalIncludeDirectories>.;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include\QtWidgets;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include\QtGui;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include\QtANGLE;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\include\QtCore;debug;.;/include;..\..\..\..\lib\Qt\5.15.10\msvc2019_64\mkspecs\win32-msvc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>-Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)</AdditionalOptions>
+      <AssemblerListingLocation>debug\</AssemblerListingLocation>
+      <BrowseInformation>false</BrowseInformation>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <DisableSpecificWarnings>4577;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <ExceptionHandling>Sync</ExceptionHandling>
+      <ObjectFileName>debug\</ObjectFileName>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessToFile>false</PreprocessToFile>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <WarningLevel>Level3</WarningLevel>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>C:\lib\Qt\5.15.10\msvc2019_64\lib\Qt5Widgetsd.lib;C:\lib\Qt\5.15.10\msvc2019_64\lib\Qt5Guid.lib;C:\lib\Qt\5.15.10\msvc2019_64\lib\Qt5Cored.lib;C:\lib\Qt\5.15.10\msvc2019_64\lib\qtmaind.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>C:\openssl\lib;C:\Utils\my_sql\mysql-5.7.25-winx64\lib;C:\Utils\postgresql\pgsql\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalOptions>&quot;/MANIFESTDEPENDENCY:type=&apos;win32&apos; name=&apos;Microsoft.Windows.Common-Controls&apos; version=&apos;6.0.0.0&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos; processorArchitecture=&apos;*&apos;&quot; %(AdditionalOptions)</AdditionalOptions>
+      <DataExecutionPrevention>true</DataExecutionPrevention>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <IgnoreImportLibrary>true</IgnoreImportLibrary>
+      <OutputFile>$(OutDir)\QtProjectV100.exe</OutputFile>
+      <RandomizedBaseAddress>true</RandomizedBaseAddress>
+      <SubSystem>Windows</SubSystem>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+    </Link>
+    <Midl>
+      <DefaultCharType>Unsigned</DefaultCharType>
+      <EnableErrorChecks>None</EnableErrorChecks>
+      <WarningLevel>0</WarningLevel>
+    </Midl>
+    <ResourceCompile>
+      <PreprocessorDefinitions>_WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="QtProjectV100.cpp" />
+    <ClCompile Include="main.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <CustomBuild Include="QtProjectV100.h">
+      <AdditionalInputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">QtProjectV100.h;release\moc_predefs.h;C:\lib\Qt\5.15.10\msvc2019_64\bin\moc.exe;%(AdditionalInputs)</AdditionalInputs>
+      <Command Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">C:\lib\Qt\5.15.10\msvc2019_64\bin\moc.exe  -DUNICODE -D_UNICODE -DWIN32 -D_ENABLE_EXTENDED_ALIGNED_STORAGE -DWIN64 -DNDEBUG -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB --compiler-flavor=msvc --include C:/dev/tests/formats/100/release/moc_predefs.h -IC:/lib/Qt/5.15.10/msvc2019_64/mkspecs/win32-msvc -IC:/dev/tests/formats/100 -IC:/lib/Qt/5.15.10/msvc2019_64/include -IC:/lib/Qt/5.15.10/msvc2019_64/include/QtWidgets -IC:/lib/Qt/5.15.10/msvc2019_64/include/QtGui -IC:/lib/Qt/5.15.10/msvc2019_64/include/QtANGLE -IC:/lib/Qt/5.15.10/msvc2019_64/include/QtCore -I&quot;C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\ATLMFC\include&quot; -I&quot;C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\include&quot; -I&quot;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\ucrt&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\winrt&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\cppwinrt&quot; QtProjectV100.h -o release\moc_QtProjectV100.cpp</Command>
+      <Message Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">MOC QtProjectV100.h</Message>
+      <Outputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">release\moc_QtProjectV100.cpp;%(Outputs)</Outputs>
+      <AdditionalInputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">QtProjectV100.h;debug\moc_predefs.h;C:\lib\Qt\5.15.10\msvc2019_64\bin\moc.exe;%(AdditionalInputs)</AdditionalInputs>
+      <Command Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">C:\lib\Qt\5.15.10\msvc2019_64\bin\moc.exe  -DUNICODE -D_UNICODE -DWIN32 -D_ENABLE_EXTENDED_ALIGNED_STORAGE -DWIN64 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB --compiler-flavor=msvc --include C:/dev/tests/formats/100/debug/moc_predefs.h -IC:/lib/Qt/5.15.10/msvc2019_64/mkspecs/win32-msvc -IC:/dev/tests/formats/100 -IC:/lib/Qt/5.15.10/msvc2019_64/include -IC:/lib/Qt/5.15.10/msvc2019_64/include/QtWidgets -IC:/lib/Qt/5.15.10/msvc2019_64/include/QtGui -IC:/lib/Qt/5.15.10/msvc2019_64/include/QtANGLE -IC:/lib/Qt/5.15.10/msvc2019_64/include/QtCore -I&quot;C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\ATLMFC\include&quot; -I&quot;C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\include&quot; -I&quot;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\ucrt&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\winrt&quot; -I&quot;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\cppwinrt&quot; QtProjectV100.h -o debug\moc_QtProjectV100.cpp</Command>
+      <Message Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">MOC QtProjectV100.h</Message>
+      <Outputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">debug\moc_QtProjectV100.cpp;%(Outputs)</Outputs>
+    </CustomBuild>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="debug\moc_QtProjectV100.cpp">
+      <ExcludedFromBuild Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">true</ExcludedFromBuild>
+    </ClCompile>
+    <ClCompile Include="release\moc_QtProjectV100.cpp">
+      <ExcludedFromBuild Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">true</ExcludedFromBuild>
+    </ClCompile>
+    <CustomBuild Include="debug\moc_predefs.h.cbt">
+      <FileType>Document</FileType>
+      <ExcludedFromBuild Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">true</ExcludedFromBuild>
+      <AdditionalInputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">..\..\..\..\lib\Qt\5.15.10\msvc2019_64\mkspecs\features\data\dummy.cpp;%(AdditionalInputs)</AdditionalInputs>
+      <Command Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">cl -BxC:\lib\Qt\5.15.10\msvc2019_64\bin\qmake.exe -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -Zi -MDd -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E ..\..\..\..\lib\Qt\5.15.10\msvc2019_64\mkspecs\features\data\dummy.cpp 2&gt;NUL &gt;debug\moc_predefs.h</Command>
+      <Message Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">Generate moc_predefs.h</Message>
+      <Outputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">debug\moc_predefs.h;%(Outputs)</Outputs>
+    </CustomBuild>
+    <CustomBuild Include="release\moc_predefs.h.cbt">
+      <FileType>Document</FileType>
+      <AdditionalInputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">..\..\..\..\lib\Qt\5.15.10\msvc2019_64\mkspecs\features\data\dummy.cpp;%(AdditionalInputs)</AdditionalInputs>
+      <Command Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">cl -BxC:\lib\Qt\5.15.10\msvc2019_64\bin\qmake.exe -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -O2 -MD -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E ..\..\..\..\lib\Qt\5.15.10\msvc2019_64\mkspecs\features\data\dummy.cpp 2&gt;NUL &gt;release\moc_predefs.h</Command>
+      <Message Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">Generate moc_predefs.h</Message>
+      <Outputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">release\moc_predefs.h;%(Outputs)</Outputs>
+      <ExcludedFromBuild Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">true</ExcludedFromBuild>
+    </CustomBuild>
+    <ClCompile Include="debug\qrc_QtProjectV100.cpp">
+      <ExcludedFromBuild Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">true</ExcludedFromBuild>
+    </ClCompile>
+    <ClCompile Include="release\qrc_QtProjectV100.cpp">
+      <ExcludedFromBuild Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">true</ExcludedFromBuild>
+    </ClCompile>
+    <ClInclude Include="ui_QtProjectV100.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <CustomBuild Include="QtProjectV100.ui">
+      <FileType>Document</FileType>
+      <AdditionalInputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">QtProjectV100.ui;C:\lib\Qt\5.15.10\msvc2019_64\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
+      <Command Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">C:\lib\Qt\5.15.10\msvc2019_64\bin\uic.exe QtProjectV100.ui -o ui_QtProjectV100.h</Command>
+      <Message Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">UIC QtProjectV100.ui</Message>
+      <Outputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">ui_QtProjectV100.h;%(Outputs)</Outputs>
+      <AdditionalInputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">QtProjectV100.ui;C:\lib\Qt\5.15.10\msvc2019_64\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
+      <Command Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">C:\lib\Qt\5.15.10\msvc2019_64\bin\uic.exe QtProjectV100.ui -o ui_QtProjectV100.h</Command>
+      <Message Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">UIC QtProjectV100.ui</Message>
+      <Outputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">ui_QtProjectV100.h;%(Outputs)</Outputs>
+    </CustomBuild>
+  </ItemGroup>
+  <ItemGroup>
+    <CustomBuild Include="QtProjectV100.qrc">
+      <FileType>Document</FileType>
+      <AdditionalInputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">QtProjectV100.qrc;C:\lib\Qt\5.15.10\msvc2019_64\bin\rcc.exe;%(AdditionalInputs)</AdditionalInputs>
+      <Command Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">C:\lib\Qt\5.15.10\msvc2019_64\bin\rcc.exe -name QtProjectV100 QtProjectV100.qrc -o release\qrc_QtProjectV100.cpp</Command>
+      <Message Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">RCC QtProjectV100.qrc</Message>
+      <Outputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Release|x64&apos;">release\qrc_QtProjectV100.cpp;%(Outputs)</Outputs>
+      <AdditionalInputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">QtProjectV100.qrc;C:\lib\Qt\5.15.10\msvc2019_64\bin\rcc.exe;%(AdditionalInputs)</AdditionalInputs>
+      <Command Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">C:\lib\Qt\5.15.10\msvc2019_64\bin\rcc.exe -name QtProjectV100 QtProjectV100.qrc -o debug\qrc_QtProjectV100.cpp</Command>
+      <Message Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">RCC QtProjectV100.qrc</Message>
+      <Outputs Condition="&apos;$(Configuration)|$(Platform)&apos;==&apos;Debug|x64&apos;">debug\qrc_QtProjectV100.cpp;%(Outputs)</Outputs>
+    </CustomBuild>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets" />
+</Project>
+```
+
+### v2.0
+
+#### `.vcxproj`
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{B12702AD-ABFB-343A-A199-8E24837244A3}</ProjectGuid>
+    <Keyword>Qt4VSv1.0</Keyword>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings" />
+  <ImportGroup Label="Shared" />
+  <ImportGroup Label="PropertySheets" />
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PreprocessorDefinitions>UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <Optimization>Disabled</Optimization>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
+      <AdditionalLibraryDirectories>$(QTDIR)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>qtmaind.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5Widgetsd.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PreprocessorDefinitions>UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <DebugInformationFormat />
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
+      <AdditionalLibraryDirectories>$(QTDIR)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+      <AdditionalDependencies>qtmain.lib;Qt5Core.lib;Qt5Gui.lib;Qt5Widgets.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="GeneratedFiles\Debug\moc_QtProjectV200.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+    </ClCompile>
+    <ClCompile Include="GeneratedFiles\qrc_QtProjectV200.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+      </PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+      </PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="GeneratedFiles\Release\moc_QtProjectV200.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+    </ClCompile>
+    <ClCompile Include="main.cpp" />
+    <ClCompile Include="QtProjectV200.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <CustomBuild Include="QtProjectV200.h">
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Moc%27ing QtProjectV200.h...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -D_UNICODE -DWIN32 -D_ENABLE_EXTENDED_ALIGNED_STORAGE -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets"</Command>
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Moc%27ing QtProjectV200.h...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -D_UNICODE -DWIN32 -D_ENABLE_EXTENDED_ALIGNED_STORAGE -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets"</Command>
+    </CustomBuild>
+  </ItemGroup>
+  <ItemGroup>
+    <CustomBuild Include="QtProjectV200.ui">
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Uic%27ing %(Identity)...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Uic%27ing %(Identity)...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
+    </CustomBuild>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="GeneratedFiles\ui_QtProjectV200.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <CustomBuild Include="QtProjectV200.qrc">
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(FullPath);%(AdditionalInputs)</AdditionalInputs>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Rcc%27ing %(Identity)...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\GeneratedFiles\qrc_%(Filename).cpp;%(Outputs)</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\rcc.exe" -name "%(Filename)" -no-compress "%(FullPath)" -o .\GeneratedFiles\qrc_%(Filename).cpp</Command>
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(FullPath);%(AdditionalInputs)</AdditionalInputs>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Rcc%27ing %(Identity)...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\qrc_%(Filename).cpp;%(Outputs)</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\rcc.exe" -name "%(Filename)" -no-compress "%(FullPath)" -o .\GeneratedFiles\qrc_%(Filename).cpp</Command>
+    </CustomBuild>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+  <ProjectExtensions>
+    <VisualStudio>
+      <UserProperties MocDir=".\GeneratedFiles\$(ConfigurationName)" UicDir=".\GeneratedFiles" RccDir=".\GeneratedFiles" lupdateOptions="" lupdateOnBuild="0" lreleaseOptions="" Qt5Version_x0020_x64="msvc2019_64" MocOptions="" />
+    </VisualStudio>
+  </ProjectExtensions>
+</Project>
+```
+
+### v3.0
+
+#### `.vcxproj`
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{B12702AD-ABFB-343A-A199-8E24837244A3}</ProjectGuid>
+    <Keyword>QtVS_v300</Keyword>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+    <QtInstall>msvc2019_64</QtInstall>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+    <QtInstall>msvc2019_64</QtInstall>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <PropertyGroup Condition="'$(QtMsBuild)'=='' or !Exists('$(QtMsBuild)\qt.targets')">
+    <QtMsBuild>$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
+    <Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
+  </Target>
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')">
+    <Import Project="$(QtMsBuild)\qt.props" />
+  </ImportGroup>
+  <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <QtModules>core;gui;widgets</QtModules>
+  </PropertyGroup>
+  <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <QtModules>core;gui;widgets</QtModules>
+  </PropertyGroup>
+  <ImportGroup Label="ExtensionSettings" />
+  <ImportGroup Label="Shared" />
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <Optimization>Disabled</Optimization>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat />
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="main.cpp" />
+    <ClCompile Include="QtProjectV300.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <QtMoc Include="QtProjectV300.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <QtUic Include="QtProjectV300.ui" />
+  </ItemGroup>
+  <ItemGroup>
+    <QtRcc Include="QtProjectV300.qrc" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
+    <Import Project="$(QtMsBuild)\qt.targets" />
+  </ImportGroup>
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
+```
+
+### v3.1
+
+#### `.vcxproj`
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{B12702AD-ABFB-343A-A199-8E24837244A3}</ProjectGuid>
+    <Keyword>QtVS_v301</Keyword>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <PropertyGroup Condition="'$(QtMsBuild)'=='' or !Exists('$(QtMsBuild)\qt.targets')">
+    <QtMsBuild>$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
+    <Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
+  </Target>
+  <ImportGroup Label="ExtensionSettings" />
+  <ImportGroup Label="Shared" />
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
+    <Import Project="$(QtMsBuild)\qt_defaults.props" />
+  </ImportGroup>
+  <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <QtInstall>msvc2019_64</QtInstall>
+    <QtModules>core;gui;widgets</QtModules>
+  </PropertyGroup>
+  <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <QtInstall>msvc2019_64</QtInstall>
+    <QtModules>core;gui;widgets</QtModules>
+  </PropertyGroup>
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')">
+    <Import Project="$(QtMsBuild)\qt.props" />
+  </ImportGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <Optimization>Disabled</Optimization>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat />
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="main.cpp" />
+    <ClCompile Include="QtProjectV301.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <QtMoc Include="QtProjectV301.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <QtUic Include="QtProjectV301.ui" />
+  </ItemGroup>
+  <ItemGroup>
+    <QtRcc Include="QtProjectV301.qrc" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
+    <Import Project="$(QtMsBuild)\qt.targets" />
+  </ImportGroup>
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
+```
+
+### v3.2
+
+#### `.vcxproj`
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{10A7CC05-6663-4C63-906F-E56EDF8218CA}</ProjectGuid>
+    <Keyword>QtVS_v302</Keyword>
+    <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">10.0.19041.0</WindowsTargetPlatformVersion>
+    <QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')"
+      >$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <Target Name="QtMsBuildNotFound"
+    BeforeTargets="CustomBuild;ClCompile"
+    Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
+    <Message Importance="High"
+      Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
+  </Target>
+  <ImportGroup Label="ExtensionSettings" />
+  <ImportGroup Label="Shared" />
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
+    <Import Project="$(QtMsBuild)\qt_defaults.props" />
+  </ImportGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="QtSettings">
+    <QtInstall>msvc2019_64</QtInstall>
+    <QtModules>core;gui;widgets</QtModules>
+    <QtBuildConfig>debug</QtBuildConfig>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="QtSettings">
+    <QtInstall>msvc2019_64</QtInstall>
+    <QtModules>core;gui;widgets</QtModules>
+    <QtBuildConfig>release</QtBuildConfig>
+  </PropertyGroup>
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')">
+    <Import Project="$(QtMsBuild)\qt.props" />
+  </ImportGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
+    <ClCompile>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <Optimization>Disabled</Optimization>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
+    <ClCompile>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat>None</DebugInformationFormat>
+      <Optimization>MaxSpeed</Optimization>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <QtRcc Include="QtProjectV302.qrc"/>
+    <QtUic Include="QtProjectV302.ui"/>
+    <QtMoc Include="QtProjectV302.h"/>
+    <ClCompile Include="QtProjectV302.cpp"/>
+    <ClCompile Include="main.cpp"/>
+
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
+    <Import Project="$(QtMsBuild)\qt.targets" />
+  </ImportGroup>
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
+```
+
+### v3.3
+
+#### `.vcxproj`
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{812E4050-B861-4918-A0DC-53053B848372}</ProjectGuid>
+    <Keyword>QtVS_v303</Keyword>
+    <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">10.0.19041.0</WindowsTargetPlatformVersion>
+    <QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')"
+      >$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <Target Name="QtMsBuildNotFound"
+    BeforeTargets="CustomBuild;ClCompile"
+    Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
+    <Message Importance="High"
+      Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
+  </Target>
+  <ImportGroup Label="ExtensionSettings" />
+  <ImportGroup Label="Shared" />
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
+    <Import Project="$(QtMsBuild)\qt_defaults.props" />
+  </ImportGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="QtSettings">
+    <QtInstall>msvc2019_64</QtInstall>
+    <QtModules>core;gui;widgets</QtModules>
+    <QtBuildConfig>debug</QtBuildConfig>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="QtSettings">
+    <QtInstall>msvc2019_64</QtInstall>
+    <QtModules>core;gui;widgets</QtModules>
+    <QtBuildConfig>release</QtBuildConfig>
+  </PropertyGroup>
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')">
+    <Import Project="$(QtMsBuild)\qt.props" />
+  </ImportGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
+    <ClCompile>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <Optimization>Disabled</Optimization>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
+    <ClCompile>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat>None</DebugInformationFormat>
+      <Optimization>MaxSpeed</Optimization>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <QtRcc Include="QtProjectV303.qrc"/>
+    <QtUic Include="QtProjectV303.ui"/>
+    <QtMoc Include="QtProjectV303.h"/>
+    <ClCompile Include="QtProjectV303.cpp"/>
+    <ClCompile Include="main.cpp"/>
+
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
+    <Import Project="$(QtMsBuild)\qt.targets" />
+  </ImportGroup>
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
+```
+
+### v3.4
+
+#### `.vcxproj`
+```xml
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="17.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{923588D5-2AA5-4B0F-8110-56BEEBB531D5}</ProjectGuid>
+    <Keyword>QtVS_v304</Keyword>
+    <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">10.0.19041.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">10.0.19041.0</WindowsTargetPlatformVersion>
+    <QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')"
+      >$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v143</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v143</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
+    <Import Project="$(QtMsBuild)\qt_defaults.props" />
+  </ImportGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="QtSettings">
+    <QtInstall>5.15.10_msvc2019_64</QtInstall>
+    <QtModules>core;gui;widgets</QtModules>
+    <QtBuildConfig>debug</QtBuildConfig>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="QtSettings">
+    <QtInstall>5.15.10_msvc2019_64</QtInstall>
+    <QtModules>core;gui;widgets</QtModules>
+    <QtBuildConfig>release</QtBuildConfig>
+  </PropertyGroup>
+  <Target Name="QtMsBuildNotFound"
+    BeforeTargets="CustomBuild;ClCompile"
+    Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
+    <Message Importance="High"
+      Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
+  </Target>
+  <ImportGroup Label="ExtensionSettings" />
+  <ImportGroup Label="Shared" />
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(QtMsBuild)\Qt.props" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(QtMsBuild)\Qt.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
+    <ClCompile>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <Optimization>Disabled</Optimization>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
+    <ClCompile>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat>None</DebugInformationFormat>
+      <Optimization>MaxSpeed</Optimization>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <QtRcc Include="QtProjectV304.qrc"/>
+    <QtUic Include="QtProjectV304.ui"/>
+    <QtMoc Include="QtProjectV304.h"/>
+    <ClCompile Include="QtProjectV304.cpp"/>
+    <ClCompile Include="main.cpp"/>
+
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
+    <Import Project="$(QtMsBuild)\qt.targets" />
+  </ImportGroup>
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
+```
diff --git a/Tests/Test_QtMsBuild.Tasks/Properties/AssemblyInfo.cs b/Tests/Test_QtMsBuild.Tasks/Properties/AssemblyInfo.cs
index d2a7f58..2b3b56c 100644
--- a/Tests/Test_QtMsBuild.Tasks/Properties/AssemblyInfo.cs
+++ b/Tests/Test_QtMsBuild.Tasks/Properties/AssemblyInfo.cs
@@ -1,5 +1,4 @@
 using System.Reflection;
-using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 
 [assembly: AssemblyTitle("Test_QtMsBuild.Tasks")]
diff --git a/Tests/Test_QtMsBuild.Tasks/TestTaskLoggingHelper.cs b/Tests/Test_QtMsBuild.Tasks/TestTaskLoggingHelper.cs
index b4c1272..0c5d72a 100644
--- a/Tests/Test_QtMsBuild.Tasks/TestTaskLoggingHelper.cs
+++ b/Tests/Test_QtMsBuild.Tasks/TestTaskLoggingHelper.cs
@@ -26,11 +26,11 @@
 **
 ****************************************************************************/
 
-using Microsoft.Build.Framework;
 using System;
 using System.Collections.Generic;
-using System.IO;
 using System.Diagnostics;
+using System.IO;
+using Microsoft.Build.Framework;
 
 namespace QtVsTools.Test.QtMsBuild.Tasks
 {
diff --git a/Tests/Test_QtMsBuild.Tasks/Test_Join.cs b/Tests/Test_QtMsBuild.Tasks/Test_Join.cs
index 0ae7973..3743125 100644
--- a/Tests/Test_QtMsBuild.Tasks/Test_Join.cs
+++ b/Tests/Test_QtMsBuild.Tasks/Test_Join.cs
@@ -26,19 +26,20 @@
 **
 ****************************************************************************/
 
-using Microsoft.VisualStudio.TestTools.UnitTesting;
 using System.Linq;
 using System.Collections.Generic;
 using Microsoft.Build.Framework;
 using Microsoft.Build.Utilities;
-using QtVsTools.QtMsBuild.Tasks;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
 
 namespace QtVsTools.Test.QtMsBuild.Tasks
 {
+    using QtVsTools.QtMsBuild.Tasks;
+
     [TestClass]
     public class Test_Join
     {
-        ITaskItem[] LeftItems = new TaskItem[]
+        readonly ITaskItem[] LeftItems = new TaskItem[]
         {
                 new TaskItem("A", new Dictionary<string, string> {
                     { "X", "foo" },
@@ -53,8 +54,7 @@
                     { "Y", "3.14159" },
                 }),
         };
-
-        ITaskItem[] RightItems = new TaskItem[]
+        readonly ITaskItem[] RightItems = new TaskItem[]
         {
                 new TaskItem("A", new Dictionary<string, string> {
                     { "Z", "foo" },
@@ -90,9 +90,8 @@
             //                  ---------------
 
             var criteria = new string[] { "Y" };
-            ITaskItem[] result;
             Assert.IsTrue(
-                Join.Execute(LeftItems, RightItems, out result, criteria));
+                Join.Execute(LeftItems, RightItems, out ITaskItem[] result, criteria));
             Assert.IsTrue(result != null && result.Length == 3);
 
             Assert.IsTrue(result[0].GetMetadata("X") == "foo");
@@ -124,9 +123,8 @@
             //                      -------------------
 
             var criteria = new string[] { "ROW_NUMBER" };
-            ITaskItem[] result;
             Assert.IsTrue(
-                Join.Execute(LeftItems, RightItems, out result, criteria));
+                Join.Execute(LeftItems, RightItems, out ITaskItem[] result, criteria));
             Assert.IsTrue(result != null && result.Length == 3);
 
             Assert.IsTrue(result[0].GetMetadata("X") == "foo");
@@ -158,9 +156,8 @@
             //                      -------------------
 
             var criteria = new string[] { "ROW_NUMBER", "Y" };
-            ITaskItem[] result;
             Assert.IsTrue(
-                Join.Execute(LeftItems, RightItems, out result, criteria));
+                Join.Execute(LeftItems, RightItems, out ITaskItem[] result, criteria));
             Assert.IsTrue(result != null && result.Length == 0);
         }
 
@@ -187,9 +184,8 @@
                 .ToArray();
 
             var criteria = new string[] { "ROW_NUMBER", "Y" };
-            ITaskItem[] result;
             Assert.IsTrue(
-                Join.Execute(newLeftItems, RightItems, out result, criteria));
+                Join.Execute(newLeftItems, RightItems, out ITaskItem[] result, criteria));
             Assert.IsTrue(result != null && result.Length == 1);
 
             Assert.IsTrue(result[0].GetMetadata("X") == "zzz");
@@ -212,9 +208,8 @@
             // ---------------------    A  | bar | 99          B  | bar | 99 | bar
             //                        ---------------------  ----------------------
 
-            ITaskItem[] result;
             Assert.IsTrue(
-                Join.Execute(LeftItems, RightItems, out result));
+                Join.Execute(LeftItems, RightItems, out ITaskItem[] result));
             Assert.IsTrue(result != null && result.Length == 4);
 
             Assert.IsTrue(result[0].GetMetadata("X") == "foo");
diff --git a/Tests/Test_QtMsBuild.Tasks/Test_QtMsBuild.Tasks.csproj b/Tests/Test_QtMsBuild.Tasks/Test_QtMsBuild.Tasks.csproj
index 77bbb75..b4ae05a 100644
--- a/Tests/Test_QtMsBuild.Tasks/Test_QtMsBuild.Tasks.csproj
+++ b/Tests/Test_QtMsBuild.Tasks/Test_QtMsBuild.Tasks.csproj
@@ -76,17 +76,35 @@
   </ItemGroup>
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
-  // Version specific references
+  // General package references
   // -->
   <Import Project="$(SolutionDir)\references.props" />
   <ItemGroup>
-    <PackageReference Include="Microsoft.Build" Version="$(Version_Microsoft_Build)" />
-    <PackageReference Include="Microsoft.Build.Framework" Version="$(Version_Microsoft_Build_Framework)" />
-    <PackageReference Include="Microsoft.Build.Tasks.Core" Version="$(Version_Microsoft_Build_Tasks_Core)" />
-    <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="$(Version_Microsoft_Bcl_AsyncInterfaces)" />
-    <PackageReference Include="MSTest.TestAdapter" Version="$(Version_MSTest_TestAdapter)" />
-    <PackageReference Include="MSTest.TestFramework" Version="$(Version_MSTest_TestFramework)" />
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+    <PackageReference Include="$(Name_Microsoft_Build)" Version="$(Version_Microsoft_Build)" />
+    <PackageReference Include="$(Name_Microsoft_Build_Tasks_Core)" Version="$(Version_Microsoft_Build_Tasks_Core)" />
+    <PackageReference Include="$(Name_MSTest_TestAdapter)" Version="$(Version_MSTest_TestAdapter)" />
+    <PackageReference Include="$(Name_MSTest_TestFramework)" Version="$(Version_MSTest_TestFramework)" />
   </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
   // Solution project references
@@ -105,6 +123,7 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="TestTaskLoggingHelper.cs" />
     <Compile Include="Test_Join.cs" />
+    <Compile Include="Test_QtRunTask.cs" />
   </ItemGroup>
   <Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
diff --git a/Tests/Test_QtMsBuild.Tasks/Test_QtRunTask.cs b/Tests/Test_QtMsBuild.Tasks/Test_QtRunTask.cs
new file mode 100644
index 0000000..969e582
--- /dev/null
+++ b/Tests/Test_QtMsBuild.Tasks/Test_QtRunTask.cs
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace QtVsTools.Test.QtMsBuild.Tasks
+{
+    using QtVsTools.QtMsBuild.Tasks;
+
+    [TestClass]
+    public class Test_QtRunTask
+    {
+        [TestMethod]
+        public void CLCommandLine()
+        {
+            var argv = Environment.GetCommandLineArgs();
+            var path = argv[0];
+            if (string.IsNullOrEmpty(Path.GetPathRoot(path)))
+                Assert.Inconclusive("Executable path is not rooted.");
+
+            do
+                path = Path.GetFullPath(Path.GetDirectoryName(path));
+            while (path != Path.GetPathRoot(path)
+                && !File.Exists(Path.Combine(path, "devenv.exe")));
+
+            if (!File.Exists(Path.Combine(path, "devenv.exe")))
+                Assert.Inconclusive("devenv.exe not found");
+
+            string vsPath = Path.GetDirectoryName(Path.GetDirectoryName(path));
+            string vcTargetsPath = Path.Combine(vsPath, "MSBuild", "Microsoft", "VC");
+            if (Directory.Exists(Path.Combine(vcTargetsPath, "v170")))
+                vcTargetsPath = Path.Combine(vcTargetsPath, "v170");
+            else if (Directory.Exists(Path.Combine(vcTargetsPath, "v160")))
+                vcTargetsPath = Path.Combine(vcTargetsPath, "v160");
+            else if (Directory.Exists(Path.Combine(vcTargetsPath, "v150")))
+                vcTargetsPath = Path.Combine(vcTargetsPath, "v150");
+            else
+                Assert.Inconclusive("MSBuild VC targets directory not found");
+
+            ITaskItem[] sourceItems = new TaskItem[]
+            {
+                new TaskItem("main.cpp", new Dictionary<string, string> {
+                    { "EnforceTypeConversionRules", "false" },
+                })
+            };
+
+            Assert.IsTrue(
+                QtRunTask.Execute(
+                    sourceItems,
+                    $@"{vcTargetsPath}\Microsoft.Build.CPPTasks.Common.dll",
+                    "Microsoft.Build.CPPTasks.CLCommandLine",
+                    "Sources",
+                    out ITaskItem[] result,
+                    "CommandLines",
+                    "CommandLine"));
+            Assert.IsTrue(result != null && result.Length == 1);
+            Assert.IsTrue(result[0].GetMetadata("CommandLine").Contains("/Zc:rvalueCast-"));
+        }
+    }
+}
diff --git a/Tests/Test_QtVsTools.Core/Properties/AssemblyInfo.cs b/Tests/Test_QtVsTools.Core/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..4c2fa40
--- /dev/null
+++ b/Tests/Test_QtVsTools.Core/Properties/AssemblyInfo.cs
@@ -0,0 +1,20 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("Test_QtVsTools.Core")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Test_QtVsTools.Core")]
+[assembly: AssemblyCopyright("Copyright ©  2022")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+
+[assembly: Guid("4b8fc08c-4901-45d4-bc00-c0c461292ff2")]
+
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Tests/Test_QtVsTools.Core/Test_LazyFactory.cs b/Tests/Test_QtVsTools.Core/Test_LazyFactory.cs
new file mode 100644
index 0000000..953f024
--- /dev/null
+++ b/Tests/Test_QtVsTools.Core/Test_LazyFactory.cs
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Collections.Concurrent;
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace QtVsTools.Test.Core
+{
+    using Common;
+
+    [TestClass]
+    public class Test_LazyFactory
+    {
+        class LazyClass
+        {
+            LazyFactory Lazy { get; } = new LazyFactory();
+
+            public ConcurrentBag<int> InitThread { get; } = new ConcurrentBag<int>();
+            public string LazyProperty => Lazy.Get(() =>
+                LazyProperty, () =>
+                {
+                    InitThread.Add(Thread.CurrentThread.ManagedThreadId);
+                    return "LAZYVALUE";
+                });
+        }
+
+        [TestMethod]
+        public void Test_ThreadSafety()
+        {
+            var lazyObject = new LazyClass();
+            var task = Task.Run(async () =>
+            {
+                var tasks = new Task[3000];
+                for (int i = 0; i < tasks.Length; i++) {
+                    var n = i;
+                    tasks[i] = Task.Run(() =>
+                    {
+                        Debug.WriteLine($"Lazy value #{n} is {lazyObject.LazyProperty}");
+                    });
+                }
+                await Task.WhenAll(tasks);
+            });
+            while (!task.IsCompleted)
+                Thread.Sleep(100);
+
+            Assert.IsTrue(lazyObject.InitThread.Count ==  1);
+        }
+    }
+}
diff --git a/Tests/Test_QtVsTools.Core/Test_QtVsTools.Core.csproj b/Tests/Test_QtVsTools.Core/Test_QtVsTools.Core.csproj
new file mode 100644
index 0000000..b6ab30a
--- /dev/null
+++ b/Tests/Test_QtVsTools.Core/Test_QtVsTools.Core.csproj
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="$(VisualStudioVersion)" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <!--
+    *****************************************************************************
+    **
+    ** Copyright (C) 2022 The Qt Company Ltd.
+    ** Contact: https://www.qt.io/licensing/
+    **
+    ** This file is part of the Qt VS Tools.
+    **
+    ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+    ** Commercial License Usage
+    ** Licensees holding valid commercial Qt licenses may use this file in
+    ** accordance with the commercial license agreement provided with the
+    ** Software or, alternatively, in accordance with the terms contained in
+    ** a written agreement between you and The Qt Company. For licensing terms
+    ** and conditions see https://www.qt.io/terms-conditions. For further
+    ** information use the contact form at https://www.qt.io/contact-us.
+    **
+    ** GNU General Public License Usage
+    ** Alternatively, this file may be used under the terms of the GNU
+    ** General Public License version 3 as published by the Free Software
+    ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+    ** included in the packaging of this file. Please review the following
+    ** information to ensure the GNU General Public License requirements will
+    ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+    **
+    ** $QT_END_LICENSE$
+    **
+    *****************************************************************************
+-->
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{4B8FC08C-4901-45D4-BC00-C0C461292FF2}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>QtVsTools.Test.Core</RootNamespace>
+    <AssemblyName>Test_QtVsTools.Core</AssemblyName>
+    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+    <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
+    <IsCodedUITest>False</IsCodedUITest>
+    <TestProjectType>UnitTest</TestProjectType>
+    <NuGetPackageImportStamp>
+    </NuGetPackageImportStamp>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Global references
+  // -->
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // General package references
+  // -->
+  <Import Project="$(SolutionDir)\references.props" />
+  <ItemGroup>
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+    <PackageReference Include="$(Name_Microsoft_Build)" Version="$(Version_Microsoft_Build)" />
+    <PackageReference Include="$(Name_Microsoft_Build_Tasks_Core)" Version="$(Version_Microsoft_Build_Tasks_Core)" />
+    <PackageReference Include="$(Name_MSTest_TestAdapter)" Version="$(Version_MSTest_TestAdapter)" />
+    <PackageReference Include="$(Name_MSTest_TestFramework)" Version="$(Version_MSTest_TestFramework)" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Solution project references
+  // -->
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\QtVsTools.Core\QtVsTools.Core.csproj">
+      <Project>{2621ad55-c4e9-4884-81e9-da0d00b4c6e5}</Project>
+      <Name>QtVsTools.Core</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Project items
+  // -->
+  <ItemGroup>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Test_LazyFactory.cs" />
+  </ItemGroup>
+  <Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(SolutionDir)\transform.targets" />
+</Project>
\ No newline at end of file
diff --git a/Tests/Test_QtVsTools.Package/Properties/AssemblyInfo.cs b/Tests/Test_QtVsTools.Package/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..e33cba0
--- /dev/null
+++ b/Tests/Test_QtVsTools.Package/Properties/AssemblyInfo.cs
@@ -0,0 +1,20 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("Test_QtVsTools.Package")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Test_QtVsTools.Package")]
+[assembly: AssemblyCopyright("Copyright ©  2022")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+
+[assembly: Guid("afd33401-2f15-4e72-ab35-42c3ee12e897")]
+
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Tests/Test_QtVsTools.Package/QtVsTestClient.cs b/Tests/Test_QtVsTools.Package/QtVsTestClient.cs
new file mode 100644
index 0000000..a98f68b
--- /dev/null
+++ b/Tests/Test_QtVsTools.Package/QtVsTestClient.cs
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.IO.Pipes;
+using System.Linq;
+using System.Text;
+
+namespace QtVsTools.Test
+{
+    public class QtVsTestClient : IDisposable
+    {
+        public NamedPipeClientStream Stream { get; }
+
+        public QtVsTestClient(int vsProcId)
+        {
+            Stream = new NamedPipeClientStream(".", $"QtVSTest_{vsProcId}", PipeDirection.InOut);
+        }
+
+        public static QtVsTestClient Attach(int? vsProcId = null)
+        {
+            if (vsProcId == null) {
+                var procs = Process.GetProcessesByName("devenv");
+                var vsProc = procs
+                    .Where(p => p.Id != Process.GetCurrentProcess().Id
+                        && !p.MainWindowTitle.StartsWith("vstools"))
+                    .FirstOrDefault();
+                if (vsProc == null)
+                    throw new InvalidOperationException("VS process not found");
+                vsProcId = vsProc.Id;
+            }
+            var client = new QtVsTestClient(vsProcId.Value);
+            client.Connect();
+            return client;
+        }
+
+        public void Connect() => Stream.Connect();
+
+        public void Dispose() => Stream?.Dispose();
+
+        public string RunMacro(string macroCode)
+        {
+            if (!Stream.IsConnected)
+                Connect();
+
+            var macroData = Encoding.UTF8.GetBytes(macroCode);
+            int macroDataSize = macroData.Length;
+            byte[] sizeData = BitConverter.GetBytes(macroDataSize);
+
+            Stream.Write(sizeData, 0, sizeof(int));
+            Stream.Write(macroData, 0, macroData.Length);
+            Stream.Flush();
+            if (!Stream.IsConnected)
+                return Error("Disconnected");
+
+            Stream.WaitForPipeDrain();
+            if (!Stream.IsConnected)
+                return Error("Disconnected");
+
+            for (int i = 0; i < sizeof(int); i++) {
+                int c = Stream.ReadByte();
+                if (c == -1)
+                    return Error("Disconnected");
+                if (c < Byte.MinValue || c > Byte.MaxValue)
+                    return Error("Pipe error");
+                sizeData[i] = (byte)c;
+            }
+
+            int replyDataSize = BitConverter.ToInt32(sizeData, 0);
+            byte[] replyData = new byte[replyDataSize];
+            int bytesRead = 0;
+            while (bytesRead < replyDataSize) {
+                if (!Stream.IsConnected)
+                    return Error("Disconnected");
+                bytesRead += Stream.Read(replyData, bytesRead, replyDataSize - bytesRead);
+            }
+
+            return Encoding.UTF8.GetString(replyData);
+        }
+
+        public string RunMacroFile(string macroPath)
+        {
+            return LoadAndRunMacro(macroPath);
+        }
+
+        public string StoreMacro(string macroName, string macroCode)
+        {
+            if (string.IsNullOrEmpty(macroName))
+                return Error("Invalid macro name");
+            return RunMacro($"//# macro {macroName}\r\n{macroCode}");
+        }
+
+        public string StoreMacroFile(string macroName, string macroPath)
+        {
+            if (string.IsNullOrEmpty(macroName))
+                return Error("Invalid macro name");
+            return LoadAndRunMacro(macroPath, $"//# macro {macroName}");
+        }
+
+        string LoadAndRunMacro(string macroPath, string macroHeader = null)
+        {
+            var macroCode = File.ReadAllText(macroPath, Encoding.UTF8);
+            if (string.IsNullOrEmpty(macroCode))
+                return Error("Macro load failed");
+            if (!string.IsNullOrEmpty(macroHeader))
+                return RunMacro($"{macroHeader}\r\n{macroCode}");
+            else
+                return RunMacro(macroCode);
+        }
+
+        public const string MacroOk = "(ok)";
+        public const string MacroWarn = "(warn)";
+        public const string MacroError = "(error)";
+
+        static string Error(string msg) => $"{MacroError}\r\n{msg}";
+    }
+}
diff --git a/Tests/Test_QtVsTools.Package/Test_QtVersionsPage.cs b/Tests/Test_QtVsTools.Package/Test_QtVersionsPage.cs
new file mode 100644
index 0000000..7e57e2e
--- /dev/null
+++ b/Tests/Test_QtVsTools.Package/Test_QtVersionsPage.cs
@@ -0,0 +1,247 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+using System.Linq;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.Win32;
+
+namespace QtVsTools.Test.Package
+{
+    [TestClass]
+    public class Test_QtVersionsPage
+    {
+        // UI automation property conditions
+        string SetGlobals => @"
+//# using System.IO
+var elementSubtree = (TreeScope.Element | TreeScope.Subtree);
+var isButton = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button);
+var isDataGrid = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.DataGrid);
+var isEdit = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit);
+var isText = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Text);
+var isWindow = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window);";
+
+        // Open menu: Tools > Options...
+        string OpenVsOptions => @"
+//# ui context VSROOT => ""MenuBar"", ""Tools""
+//# ui pattern Invoke
+//# ui context => ""Options...""
+//# ui pattern Invoke";
+
+        // Select options: page Qt > Versions
+        string SelectQtVersionsPage => @"
+//# ui context VSROOT => ""Options"", ""Qt""
+//# ui pattern ExpandCollapse qtOptions
+qtOptions.Expand();
+//# ui context => ""Versions""
+//# ui pattern SelectionItem qtVersions
+qtVersions.Select();";
+
+        // Get reference to data grid with Qt versions
+        string GetQtVersionsTable => @"
+//# ui context VSROOT => ""Options""
+//# ui find => elementSubtree, isDataGrid
+//# ui pattern Grid qtVersionsTable";
+
+        // Add new row to versions table
+        string AddNewRow => @"
+var lastRow = qtVersionsTable.Current.RowCount - 1;
+UiContext = qtVersionsTable.GetItem(lastRow, 1);
+//# ui find => elementSubtree, isButton
+//# ui pattern Invoke
+{
+    //# ui context VSROOT => ""Options""
+    //# ui find => elementSubtree, isDataGrid
+    //# ui pattern Grid qtVersionsTableAux
+    qtVersionsTable = qtVersionsTableAux;
+}
+UiContext = qtVersionsTable.GetItem(lastRow, 1);
+//# ui find => elementSubtree, isEdit
+//# ui pattern Value newVersionName
+newVersionName.SetValue(""TEST_"" + Path.GetRandomFileName());";
+
+        // Set UI context to the path field of the new row
+        string SelectNewRowPath => @"
+UiContext = qtVersionsTable.GetItem(lastRow, 3);
+//# ui find => elementSubtree, isEdit";
+
+        // Save changes to the versions table and close the VS options dialog
+        //  * Any error message will be copied to 'Result'
+        string SaveChanges => @"
+//# ui context VSROOT => ""Options"", ""OK""
+//# ui pattern Invoke
+//# thread ui
+try {
+    //# ui context VSROOT 100 => ""Options""
+    //# ui find => elementSubtree, isWindow
+} catch (TimeoutException) {
+    return;
+}
+if (UiContext == null)
+    return;
+//# ui find => elementSubtree, isText
+Result = UiContext.Current.Name;
+//# ui context VSROOT => ""Options""
+//# ui find => elementSubtree, isWindow
+//# ui context => ""OK""
+//# ui pattern Invoke
+//# ui context VSROOT => ""Options"", ""Cancel""
+//# ui pattern Invoke";
+
+        // Add new variable 'qtPath' with the path to the Qt version in the top row
+        //  * This is assumed to be a valid path to an existing Qt version
+        string GetFirstRowPath => @"
+if (qtVersionsTable.Current.RowCount <= 1) {
+    Result = MACRO_ERROR_MSG(""No Qt version registered."");
+    return;
+}
+UiContext = qtVersionsTable.GetItem(0, 3);
+//# ui find => elementSubtree, isEdit
+//# ui pattern Value path
+string qtPath = path.Current.Value;
+if (Path.GetFileName(qtPath).Equals(""qmake.exe"", StringComparison.InvariantCultureIgnoreCase))
+    qtPath = Path.GetDirectoryName(qtPath);
+if (Path.GetFileName(qtPath).Equals(""bin"", StringComparison.InvariantCultureIgnoreCase))
+    qtPath = Path.GetDirectoryName(qtPath);";
+
+        [TestMethod]
+        // Add new (empty) row => error
+        public void Test_EmptyVersion()
+        {
+            string result;
+            using (var vs = QtVsTestClient.Attach()) {
+                result = vs.RunMacro($@"
+                    {SetGlobals}
+                    {OpenVsOptions}
+                    {SelectQtVersionsPage}
+                    {GetQtVersionsTable}
+                    {AddNewRow}
+                    {SaveChanges}");
+            }
+            Assert.IsTrue(result.Contains("Invalid Qt versions"), result);
+        }
+
+        [TestMethod]
+        // Add new row and copy the path from the top row => OK
+        public void Test_AddNewVersion()
+        {
+            string result;
+            using (var vs = QtVsTestClient.Attach()) {
+                result = vs.RunMacro($@"
+                    {SetGlobals}
+                    {OpenVsOptions}
+                    {SelectQtVersionsPage}
+                    {GetQtVersionsTable}
+                    {GetFirstRowPath}
+                    {AddNewRow}
+                    {SelectNewRowPath}
+                    //# ui pattern Value newVersionPath
+                    newVersionPath.SetValue(qtPath);
+                    {SaveChanges}");
+            }
+            Assert.IsTrue(result.StartsWith(QtVsTestClient.MacroOk), result);
+        }
+
+        [TestMethod]
+        // Add new row, copy the path from the top row, and append "qmake.exe" => OK
+        public void Test_AddBinToPath()
+        {
+            string result;
+            using (var vs = QtVsTestClient.Attach()) {
+                result = vs.RunMacro($@"
+                    {SetGlobals}
+                    {OpenVsOptions}
+                    {SelectQtVersionsPage}
+                    {GetQtVersionsTable}
+                    {GetFirstRowPath}
+                    {AddNewRow}
+                    {SelectNewRowPath}
+                    //# ui pattern Value newVersionPath
+                    newVersionPath.SetValue(Path.Combine(qtPath, ""bin""));
+                    {SaveChanges}");
+            }
+            Assert.IsTrue(result.StartsWith(QtVsTestClient.MacroOk), result);
+        }
+
+        [TestMethod]
+        // Add new row, copy the path from the top row, and append "bin\qmake.exe" => OK
+        public void Test_AddBinQMakeToPath()
+        {
+            string result;
+            using (var vs = QtVsTestClient.Attach()) {
+                result = vs.RunMacro($@"
+                    {SetGlobals}
+                    {OpenVsOptions}
+                    {SelectQtVersionsPage}
+                    {GetQtVersionsTable}
+                    {GetFirstRowPath}
+                    {AddNewRow}
+                    {SelectNewRowPath}
+                    //# ui pattern Value newVersionPath
+                    newVersionPath.SetValue(Path.Combine(qtPath, ""bin"", ""qmake.exe""));
+                    {SaveChanges}");
+            }
+            Assert.IsTrue(result.StartsWith(QtVsTestClient.MacroOk), result);
+        }
+
+        [TestMethod]
+        // Add new row, copy the path from the top row, and append "include" => ERROR
+        public void Test_AddIncludeToPath()
+        {
+            string result;
+            using (var vs = QtVsTestClient.Attach()) {
+                result = vs.RunMacro($@"
+                    {SetGlobals}
+                    {OpenVsOptions}
+                    {SelectQtVersionsPage}
+                    {GetQtVersionsTable}
+                    {GetFirstRowPath}
+                    {AddNewRow}
+                    {SelectNewRowPath}
+                    //# ui pattern Value newVersionPath
+                    newVersionPath.SetValue(Path.Combine(qtPath, ""include""));
+                    {SaveChanges}");
+            }
+            Assert.IsTrue(result.Contains("Invalid Qt versions"), result);
+        }
+
+        [ClassCleanup]
+        // Remove registry keys created during tests
+        public static void RemoveTestKeys()
+        {
+            var qtVersions = Registry.CurrentUser
+                .OpenSubKey(@"Software\Digia\Versions", writable: true);
+            using (qtVersions) {
+                var allVersions = qtVersions.GetSubKeyNames();
+                var testVersions = allVersions.Where(k => k.StartsWith("TEST"));
+                foreach (var testVersion in testVersions)
+                    qtVersions.DeleteSubKey(testVersion);
+                qtVersions.Close();
+            }
+        }
+    }
+}
diff --git a/Tests/Test_QtVsTools.Package/Test_QtVsTools.Package.csproj b/Tests/Test_QtVsTools.Package/Test_QtVsTools.Package.csproj
new file mode 100644
index 0000000..e2c41f0
--- /dev/null
+++ b/Tests/Test_QtVsTools.Package/Test_QtVsTools.Package.csproj
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="$(VisualStudioVersion)" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <!--
+    *****************************************************************************
+    **
+    ** Copyright (C) 2022 The Qt Company Ltd.
+    ** Contact: https://www.qt.io/licensing/
+    **
+    ** This file is part of the Qt VS Tools.
+    **
+    ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+    ** Commercial License Usage
+    ** Licensees holding valid commercial Qt licenses may use this file in
+    ** accordance with the commercial license agreement provided with the
+    ** Software or, alternatively, in accordance with the terms contained in
+    ** a written agreement between you and The Qt Company. For licensing terms
+    ** and conditions see https://www.qt.io/terms-conditions. For further
+    ** information use the contact form at https://www.qt.io/contact-us.
+    **
+    ** GNU General Public License Usage
+    ** Alternatively, this file may be used under the terms of the GNU
+    ** General Public License version 3 as published by the Free Software
+    ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+    ** included in the packaging of this file. Please review the following
+    ** information to ensure the GNU General Public License requirements will
+    ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+    **
+    ** $QT_END_LICENSE$
+    **
+    *****************************************************************************
+-->
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{AFD33401-2F15-4E72-AB35-42C3EE12E897}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Test_QtVsTools.Package</RootNamespace>
+    <AssemblyName>Test_QtVsTools.Package</AssemblyName>
+    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+    <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
+    <IsCodedUITest>False</IsCodedUITest>
+    <TestProjectType>UnitTest</TestProjectType>
+    <NuGetPackageImportStamp>
+    </NuGetPackageImportStamp>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Global references
+  // -->
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // General package references
+  // -->
+  <Import Project="$(SolutionDir)\references.props" />
+  <ItemGroup>
+    <PackageReference Include="$(Name_Microsoft_VSSDK_BuildTools)" Version="$(Version_Microsoft_VSSDK_BuildTools)" />
+    <PackageReference Include="$(Name_Microsoft_VisualStudio_SDK)" Version="$(Version_Microsoft_VisualStudio_SDK)" ExcludeAssets="runtime" />
+    <PackageReference Include="$(Name_Microsoft_Build)" Version="$(Version_Microsoft_Build)" />
+    <PackageReference Include="$(Name_Microsoft_Build_Tasks_Core)" Version="$(Version_Microsoft_Build_Tasks_Core)" />
+    <PackageReference Include="$(Name_MSTest_TestAdapter)" Version="$(Version_MSTest_TestAdapter)" />
+    <PackageReference Include="$(Name_MSTest_TestFramework)" Version="$(Version_MSTest_TestFramework)" />
+  </ItemGroup>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Version specific package references
+  // -->
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)'=='17.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='16.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+    <When Condition="'$(VisualStudioVersion)'=='15.0'">
+      <ItemGroup>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <!--
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Project items
+  // -->
+  <ItemGroup>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Test_QtVersionsPage.cs" />
+    <Compile Include="QtVsTestClient.cs" />
+  </ItemGroup>
+  <Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(SolutionDir)\transform.targets" />
+</Project>
\ No newline at end of file
diff --git a/Tests/Test_QtVsTools.PriorityQueue/Properties/AssemblyInfo.cs b/Tests/Test_QtVsTools.PriorityQueue/Properties/AssemblyInfo.cs
index 8561057..91ed9f8 100644
--- a/Tests/Test_QtVsTools.PriorityQueue/Properties/AssemblyInfo.cs
+++ b/Tests/Test_QtVsTools.PriorityQueue/Properties/AssemblyInfo.cs
@@ -27,7 +27,6 @@
 ****************************************************************************/
 
 using System.Reflection;
-using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 
 [assembly: AssemblyTitle("Test_QtVsTools.PriorityQueue")]
diff --git a/Tests/Test_QtVsTools.PriorityQueue/Test_PriorityQueue.cs b/Tests/Test_QtVsTools.PriorityQueue/Test_PriorityQueue.cs
index b5a2a4b..51f8213 100644
--- a/Tests/Test_QtVsTools.PriorityQueue/Test_PriorityQueue.cs
+++ b/Tests/Test_QtVsTools.PriorityQueue/Test_PriorityQueue.cs
@@ -89,12 +89,11 @@
         public void TestTryPeek()
         {
             var q = new PunisherQueue<string>();
-            string s;
-            Assert.IsTrue(!q.TryPeek(out s));
+            Assert.IsTrue(!q.TryPeek(out _));
             q.Enqueue("a");
             q.Enqueue("b");
             q.Enqueue("c");
-            Assert.IsTrue(q.TryPeek(out s) && s == "a");
+            Assert.IsTrue(q.TryPeek(out string s) && s == "a");
             Assert.IsTrue(string.Join("", q) == "abc");
         }
 
@@ -121,12 +120,11 @@
         public void TestTryDequeue()
         {
             var q = new PunisherQueue<string>();
-            string s;
-            Assert.IsTrue(!q.TryDequeue(out s));
+            Assert.IsTrue(!q.TryDequeue(out _));
             q.Enqueue("a");
             q.Enqueue("b");
             q.Enqueue("c");
-            Assert.IsTrue(q.TryDequeue(out s) && s == "a");
+            Assert.IsTrue(q.TryDequeue(out string s) && s == "a");
             Assert.IsTrue(string.Join("", q) == "bc");
         }
 
@@ -168,7 +166,7 @@
         {
             var q = new PunisherQueue<string>();
             int n = 0;
-            Task.Run(() =>
+            _ = Task.Run(() =>
             {
                 for (int i = 0; i < 10000; ++i) {
                     q.Enqueue(Path.GetRandomFileName());
@@ -177,8 +175,7 @@
                 }
             });
             for (int i = 0; i < 10000; ++i) {
-                string s;
-                if (!q.TryDequeue(out s))
+                if (!q.TryDequeue(out _))
                     --i;
                 --n;
                 Thread.Yield();
diff --git a/Tests/Test_QtVsTools.PriorityQueue/Test_QtVsTools.PriorityQueue.csproj b/Tests/Test_QtVsTools.PriorityQueue/Test_QtVsTools.PriorityQueue.csproj
index 7cc709b..94ebaeb 100644
--- a/Tests/Test_QtVsTools.PriorityQueue/Test_QtVsTools.PriorityQueue.csproj
+++ b/Tests/Test_QtVsTools.PriorityQueue/Test_QtVsTools.PriorityQueue.csproj
@@ -76,12 +76,12 @@
   </ItemGroup>
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
-  // Version specific references
+  // General package references
   // -->
   <Import Project="$(SolutionDir)\references.props" />
   <ItemGroup>
-    <PackageReference Include="MSTest.TestAdapter" Version="$(Version_MSTest_TestAdapter)" />
-    <PackageReference Include="MSTest.TestFramework" Version="$(Version_MSTest_TestFramework)" />
+    <PackageReference Include="$(Name_MSTest_TestAdapter)" Version="$(Version_MSTest_TestAdapter)" />
+    <PackageReference Include="$(Name_MSTest_TestFramework)" Version="$(Version_MSTest_TestFramework)" />
   </ItemGroup>
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/Tests/Test_QtVsTools.RegExpr/Properties/AssemblyInfo.cs b/Tests/Test_QtVsTools.RegExpr/Properties/AssemblyInfo.cs
index 68ec694..2ab45a1 100644
--- a/Tests/Test_QtVsTools.RegExpr/Properties/AssemblyInfo.cs
+++ b/Tests/Test_QtVsTools.RegExpr/Properties/AssemblyInfo.cs
@@ -27,7 +27,6 @@
 ****************************************************************************/
 
 using System.Reflection;
-using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 
 [assembly: AssemblyTitle("Test_QtVsTools.RegExpr")]
diff --git a/Tests/Test_QtVsTools.RegExpr/Test_MacroParser.cs b/Tests/Test_QtVsTools.RegExpr/Test_MacroParser.cs
index 5f29dc4..f8d8ad5 100644
--- a/Tests/Test_QtVsTools.RegExpr/Test_MacroParser.cs
+++ b/Tests/Test_QtVsTools.RegExpr/Test_MacroParser.cs
@@ -26,7 +26,6 @@
 **
 ****************************************************************************/
 
-using System;
 using System.Diagnostics;
 using System.Linq;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -38,7 +37,7 @@
     [TestClass]
     public class Test_MacroParser
     {
-        MacroParser Parser = MacroParser.Get();
+        readonly MacroParser Parser = MacroParser.Get();
 
         [TestMethod]
         public void TestMacro()
diff --git a/Tests/Test_QtVsTools.RegExpr/Test_QtVsTools.RegExpr.csproj b/Tests/Test_QtVsTools.RegExpr/Test_QtVsTools.RegExpr.csproj
index 5622e2d..7a257c8 100644
--- a/Tests/Test_QtVsTools.RegExpr/Test_QtVsTools.RegExpr.csproj
+++ b/Tests/Test_QtVsTools.RegExpr/Test_QtVsTools.RegExpr.csproj
@@ -76,12 +76,12 @@
   </ItemGroup>
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
-  // Version specific references
+  // General package references
   // -->
   <Import Project="$(SolutionDir)\references.props" />
   <ItemGroup>
-    <PackageReference Include="MSTest.TestAdapter" Version="$(Version_MSTest_TestAdapter)" />
-    <PackageReference Include="MSTest.TestFramework" Version="$(Version_MSTest_TestFramework)" />
+    <PackageReference Include="$(Name_MSTest_TestAdapter)" Version="$(Version_MSTest_TestAdapter)" />
+    <PackageReference Include="$(Name_MSTest_TestFramework)" Version="$(Version_MSTest_TestFramework)" />
   </ItemGroup>
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/Tests/Test_QtVsTools.RegExpr/Test_SubTokens.cs b/Tests/Test_QtVsTools.RegExpr/Test_SubTokens.cs
index 8118ea7..847557a 100644
--- a/Tests/Test_QtVsTools.RegExpr/Test_SubTokens.cs
+++ b/Tests/Test_QtVsTools.RegExpr/Test_SubTokens.cs
@@ -26,7 +26,6 @@
 **
 ****************************************************************************/
 
-using System;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 
 namespace QtVsTools.Test.RegExpr
diff --git a/Tests/Test_QtVsTools.RegExpr/Test_XmlIntParser.cs b/Tests/Test_QtVsTools.RegExpr/Test_XmlIntParser.cs
index bca023e..85aa5f6 100644
--- a/Tests/Test_QtVsTools.RegExpr/Test_XmlIntParser.cs
+++ b/Tests/Test_QtVsTools.RegExpr/Test_XmlIntParser.cs
@@ -26,7 +26,6 @@
 **
 ****************************************************************************/
 
-using System;
 using System.Diagnostics;
 using System.Linq;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -224,7 +223,7 @@
             return xmlInt.Render(CharSpace.Repeat());
         }
 
-        Parser Parser = GetParser();
+        readonly Parser Parser = GetParser();
 
         [TestMethod]
         public void TestConst()
diff --git a/doc/config/qtvstools-project.qdocconf b/doc/config/qtvstools-project.qdocconf
index 845c88c..a5fe990 100644
--- a/doc/config/qtvstools-project.qdocconf
+++ b/doc/config/qtvstools-project.qdocconf
@@ -6,6 +6,9 @@
 project             = "QtVSTools"
 description         = "Qt VS Tools Manual"
 
+#Words to ignore for auto-linking
+ignorewords += MainWindow
+
 sourcedirs         += ..
 imagedirs          += ../images
 outputdir           = $OUTDIR
@@ -22,7 +25,7 @@
 qhp.QtVSTools.indexRoot                                 =
 
 qhp.QtVSTools.subprojects                               = manual
-qhp.QtVSTools.subprojects.manual.indexTitle             = Qt VS Tools Manual
+qhp.QtVSTools.subprojects.manual.indexTitle             = All Topics
 qhp.QtVSTools.subprojects.manual.title                  = Qt VS Tools Manual
 qhp.QtVSTools.subprojects.manual.type                   = manual
 
@@ -33,7 +36,10 @@
             $QDOC_INDEX_DIR/qtgui/qtgui.index \
             $QDOC_INDEX_DIR/qthelp/qthelp.index \
             $QDOC_INDEX_DIR/qtlinguist/qtlinguist.index \
+            $QDOC_INDEX_DIR/qtqml/qtqml.index \
             $QDOC_INDEX_DIR/qtquick/qtquick.index \
+            $QDOC_INDEX_DIR/qtqmlmodels/qtqmlmodels.index \
+            $QDOC_INDEX_DIR/qtquickcontrols/qtquickcontrols.index \
             $QDOC_INDEX_DIR/qtwidgets/qtwidgets.index
 
 # Doxygen compatibility commands
diff --git a/doc/config/style/qt5-sidebar.html b/doc/config/style/qt5-sidebar.html
index 60760ac..1b0e0ec 100644
--- a/doc/config/style/qt5-sidebar.html
+++ b/doc/config/style/qt5-sidebar.html
@@ -1,15 +1,50 @@
 <div class="sectionlist normallist">
     <div class="heading">
-        <a name="reference"></a>
-        <h2 id="reference">Qt VS Tools Manual</h2>
+        <h2>Getting Started</h2>
     </div>
     <div class="indexboxcont indexboxbar">
         <ul>
-            <li><a href="qtvstools-getting-started.html">Getting Started</a></li>
-            <li><a href="qtvstools-managing-projects.html">Managing Projects</a></li>
-            <li><a href="qtvstools-form-files.html">Adding Form Files to Projects</a></li>
-            <li><a href="qtvstools-managing-resources.html">Managing Resources</a></li>
-            <li><a href="qtvstools-translation-files.html">Creating Qt Translation Files for Projects</a></li>
-            <li><a href="qtvstools-faq.html">FAQ</a></li>
+            <li><a href="qtvstools-qt-widgets-application.html">Tutorial: Qt Widgets Application</a></li>
+            <li><a href="qtvstools-qt-quick-application.html">Tutorial: Qt Quick Application</a></li>
         </ul>
     </div>
+</div>
+<div class="sectionlist normallist">
+    <div class="heading">
+        <h2>Configuring Builds</h2>
+    </div>
+    <ul>
+            <li><a href="qtvstools-managing-qt-versions.html">Managing Qt Versions</a></li>
+            <li><a href="qtvstools-building.html">Building</a></li>
+            <li><a href="qtvstools-cross-compiling.html">Cross-Compiling</a></li>
+            <li><a href="qtvstools-importing-and-exporting-projects.html">Importing and Exporting Projects</a></li>
+    </ul>
+</div>
+<div class="sectionlist normallist">
+    <div class="heading">
+        <h2>Managing Projects</h2>
+    </div>
+    <ul>
+            <li><a href="qtvstools-creating-projects.html">Creating Projects</a></li>
+            <li><a href="qtvstools-creating-files.html">Creating Files</a></li>
+    </ul>
+</div>
+<div class="sectionlist normallist">
+    <ul>
+            <li><a href="qtvstools-intellisense-info.html">Updating IntelliSense Info</a></li>
+    </ul>
+</div>
+<div class="sectionlist normallist">
+    <div class="heading">
+        <h2>Debugging</h2>
+    </div>
+    <ul>
+            <li><a href="qtvstools-debugging-qt-quick.html">Debugging Qt Quick Applications</a></li>
+            <li><a href="qtvstools-debugging-linux.html">Debugging on Linux</a></li>
+    </ul>
+</div>
+<div class="sectionlist normallist">
+    <ul>
+            <li><a href="qtvstools-getting-help.html">Getting Help</a></li>
+    </ul>
+</div>
diff --git a/doc/images/front-advanced.png b/doc/images/front-advanced.png
new file mode 100644
index 0000000..87780aa
--- /dev/null
+++ b/doc/images/front-advanced.png
Binary files differ
diff --git a/doc/images/front-coding.png b/doc/images/front-coding.png
new file mode 100644
index 0000000..edfc550
--- /dev/null
+++ b/doc/images/front-coding.png
Binary files differ
diff --git a/doc/images/front-gs.png b/doc/images/front-gs.png
new file mode 100644
index 0000000..27706a8
--- /dev/null
+++ b/doc/images/front-gs.png
Binary files differ
diff --git a/doc/images/front-help.png b/doc/images/front-help.png
new file mode 100644
index 0000000..d2f9d42
--- /dev/null
+++ b/doc/images/front-help.png
Binary files differ
diff --git a/doc/images/front-preview.png b/doc/images/front-preview.png
new file mode 100644
index 0000000..fe7aab3
--- /dev/null
+++ b/doc/images/front-preview.png
Binary files differ
diff --git a/doc/images/front-projects.png b/doc/images/front-projects.png
new file mode 100644
index 0000000..69414f4
--- /dev/null
+++ b/doc/images/front-projects.png
Binary files differ
diff --git a/doc/images/qtvstools-msbuild-diagram.png b/doc/images/qtvstools-msbuild-diagram.png
new file mode 100644
index 0000000..e136170
--- /dev/null
+++ b/doc/images/qtvstools-msbuild-diagram.png
Binary files differ
diff --git a/doc/images/qtvstools-options-qt-general.png b/doc/images/qtvstools-options-qt-general.png
new file mode 100644
index 0000000..6d1e62a
--- /dev/null
+++ b/doc/images/qtvstools-options-qt-general.png
Binary files differ
diff --git a/doc/images/qtvstools-qt-project-settings.png b/doc/images/qtvstools-qt-project-settings.png
index c7f7bc2..1367921 100644
--- a/doc/images/qtvstools-qt-project-settings.png
+++ b/doc/images/qtvstools-qt-project-settings.png
Binary files differ
diff --git a/doc/images/qtvstools-qt-translation-file-wizard.png b/doc/images/qtvstools-qt-translation-file-wizard.png
new file mode 100644
index 0000000..c39e3c5
--- /dev/null
+++ b/doc/images/qtvstools-qt-translation-file-wizard.png
Binary files differ
diff --git a/doc/images/qtvstools-qt-widget-class-wizard.png b/doc/images/qtvstools-qt-widget-class-wizard.png
index e6a30dd..37aba74 100644
--- a/doc/images/qtvstools-qt-widget-class-wizard.png
+++ b/doc/images/qtvstools-qt-widget-class-wizard.png
Binary files differ
diff --git a/doc/images/qtvstools-qtquick-app-modules.png b/doc/images/qtvstools-qtquick-app-modules.png
new file mode 100644
index 0000000..9c8054d
--- /dev/null
+++ b/doc/images/qtvstools-qtquick-app-modules.png
Binary files differ
diff --git a/doc/images/qtvstools-quick-addressbook-entries.png b/doc/images/qtvstools-quick-addressbook-entries.png
new file mode 100644
index 0000000..e283e38
--- /dev/null
+++ b/doc/images/qtvstools-quick-addressbook-entries.png
Binary files differ
diff --git a/doc/images/qtvstools-quick-addressbook-mainwindow.png b/doc/images/qtvstools-quick-addressbook-mainwindow.png
new file mode 100644
index 0000000..94b5a82
--- /dev/null
+++ b/doc/images/qtvstools-quick-addressbook-mainwindow.png
Binary files differ
diff --git a/doc/images/qtvstools-quick-addressbook-popup.png b/doc/images/qtvstools-quick-addressbook-popup.png
new file mode 100644
index 0000000..d5de412
--- /dev/null
+++ b/doc/images/qtvstools-quick-addressbook-popup.png
Binary files differ
diff --git a/doc/images/qtvstools-remote-debugging.png b/doc/images/qtvstools-remote-debugging.png
new file mode 100644
index 0000000..2a083a7
--- /dev/null
+++ b/doc/images/qtvstools-remote-debugging.png
Binary files differ
diff --git a/doc/qtvstools-online.qdocconf b/doc/qtvstools-online.qdocconf
index 95d3f7c..6cb5590 100644
--- a/doc/qtvstools-online.qdocconf
+++ b/doc/qtvstools-online.qdocconf
@@ -3,7 +3,7 @@
 HTML.footer = \
     "   </div>\n" \
     "   <p class=\"copy-notice\">\n" \
-    "   <acronym title=\"Copyright\">&copy;</acronym> 2016 The Qt Company Ltd.\n" \
+    "   <acronym title=\"Copyright\">&copy;</acronym> 2022 The Qt Company Ltd.\n" \
     "   Documentation contributions included herein are the copyrights of\n" \
     "   their respective owners. " \
     "   The documentation provided herein is licensed under the terms of the" \
diff --git a/doc/src/qtvstools.qdoc b/doc/src/qtvstools.qdoc
index 1b0eda9..85ef0fa 100644
--- a/doc/src/qtvstools.qdoc
+++ b/doc/src/qtvstools.qdoc
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
 ** Contact: https://www.qt.io/licensing/
 **
 ** This file is part of the documentation of the Qt Toolkit.
@@ -36,10 +36,93 @@
     or tools. You can install and update Qt VS Tools directly from Microsoft
     Visual Studio.
 
+    \table
+        \row
+            \li {4,1} \b {\l{All Topics}}
+        \row
+            \li \inlineimage front-gs.png
+            \li \inlineimage front-advanced.png
+            \li \inlineimage front-projects.png
+        \row
+            \li \b {\l{Getting Started}}
+                \list
+                    \li \l {Tutorial: Qt Widgets Application}
+                    \li \l {Tutorial: Qt Quick Application}
+                \endlist
+            \li \b {\l {Configuring Builds}}
+                \list
+                    \li \l {Managing Qt Versions}
+                    \li \l {Building}
+                    \li \l {Cross-Compiling}
+                    \li \l {Importing and Exporting Projects}
+                \endlist
+            \li \b {\l {Managing Projects}}
+                \list
+                    \li \l {Creating Projects}
+                    \li \l {Creating Files}
+                \endlist
+        \row
+            \li \inlineimage front-coding.png
+            \li \inlineimage front-preview.png
+            \li \inlineimage front-help.png
+        \row
+        \li \b {\l {Updating IntelliSense Info}}
+        \li \b {\l {Debugging}}
+            \list
+                \li \l {Debugging Qt Quick Applications}
+                \li \l {Debugging on Linux}
+            \endlist
+        \li \b {\l {Getting Help}}
+    \endtable
+*/
+
+/*!
+    \page qtvstools-toc.html
+    \title All Topics
+
+    \list
+        \li \l {Getting Started}
+            \list
+                \li \l {Tutorial: Qt Widgets Application}
+                \li \l {Tutorial: Qt Quick Application}
+            \endlist
+        \li \l {Configuring Builds}
+            \list
+                \li \l {Managing Qt Versions}
+                \li \l {Building}
+                \li \l {Cross-Compiling}
+                \li \l {Importing and Exporting Projects}
+            \endlist
+        \li \l {Managing Projects}
+            \list
+                \li \l {Creating Projects}
+                \li \l {Creating Files}
+                    \list
+                        \li \l {Adding Form Files}
+                        \li \l {Managing Resources}
+                        \li \l {Creating Qt Translation Files}
+                    \endlist
+            \endlist
+        \li \l {Updating IntelliSense Info}
+        \li \l {Debugging}
+            \list
+                \li \l {Debugging Qt Quick Applications}
+                \li \l {Debugging on Linux}
+            \endlist
+        \li \l {Getting Help}
+    \endlist
+*/
+
+/*!
+    \page qtvstools-getting-started.html
+    \previouspage Qt VS Tools Manual
+    \nextpage Tutorial: Qt Widgets Application
+    \title Getting Started
+
     The main features of Qt VS Tools are:
 
     \list
-        \li Wizards for creating new Qt projects and classes.
+        \li Wizards for creating new Qt and Qt Quick projects and files.
         \li Automated build setup for the \l {Using the Meta-Object Compiler
             (moc)}{Meta-Object Compiler (moc)}, \l {User Interface Compiler
             (uic)}, and \l {Resource Compiler (rcc)}.
@@ -55,36 +138,6 @@
         \li Debugging extensions for Qt data types.
     \endlist
 
-    \section1 Table of Contents
-
-    \list
-        \li \l {Getting Started}
-        \li \l {Managing Qt Versions}
-        \li \l {Building}
-        \li \l {Cross-Compiling}
-        \li \l {Creating Projects}
-        \li \l {Importing and Exporting Projects}
-        \li \l {Adding Form Files to Projects}
-        \li \l {Managing Resources}
-        \li \l {Creating Qt Translation Files for Projects}
-        \li \l {Updating IntelliSense Info}
-        \li \l {Getting Help}
-    \endlist
-*/
-
-/*!
-    \page qtvstools-getting-started.html
-    \previouspage Qt VS Tools Manual
-    \nextpage Managing Qt Versions
-    \title Getting Started
-
-    This tutorial illustrates how to use Qt VS Tools to create a \l {Qt Widgets}
-    application. You will create a project using a project wizard and design a
-    widget-based UI using \QD. In addition, you will learn how to convert a
-    Microsoft Visual Studio project file into a qmake compatible \c .pro file.
-
-    You can use Qt VS Tools to develop also \l{Qt Quick} applications.
-
     \section1 Install Qt VS Tools
 
     In Microsoft Visual Studio, select \uicontrol Extensions >
@@ -97,6 +150,40 @@
     To create a Qt VS Tools project, you must add at least one
     \l{Managing Qt Versions}{Qt version}.
 
+    \section1 Create a Project
+
+    Follow the tutorials to create your first applications:
+
+    \list
+        \li \l {Tutorial: Qt Widgets Application}
+        \li \l {Tutorial: Qt Quick Application}
+    \endlist
+
+    For all the options you have, see \l {Creating Projects}.
+*/
+
+/*!
+    \page qtvstools-qt-widgets-application.html
+    \previouspage Getting Started
+    \nextpage Tutorial: Qt Quick Application
+    \title Tutorial: Qt Widgets Application
+
+    This tutorial illustrates how to use Qt VS Tools to create a \l {Qt Widgets}
+    application. You will create a project using a project wizard and design a
+    widget-based UI using \QD. In addition, you will learn how to convert a
+    Microsoft Visual Studio project file into a qmake compatible \c .pro file.
+
+    You can use Qt VS Tools to develop also \l{Qt Quick} applications.
+
+    \section1 Before You Start
+
+    Before you start, you have to:
+
+    \list
+        \li \l {Install Qt VS Tools}
+        \li \l {Add a Qt Version}
+    \endlist
+
     \section1 Create a Qt Widgets Application Project
 
     To create a Qt Widgets application project in Visual Studio:
@@ -104,8 +191,9 @@
     \list 1
         \li Select \uicontrol File > \uicontrol New > \uicontrol Project, and
             search for \uicontrol {Qt Widgets Application}.
-        \li In the \uicontrol Name field, enter \e AddressBook, and then select
-            \uicontrol OK.
+        \li Select the project wizard, and then select \uicontrol Next.
+        \li In the \uicontrol {Project name} field, enter \e AddressBook,
+            and then select \uicontrol OK.
         \li To acknowledge the \uicontrol Welcome dialog, select
             \uicontrol Next.
         \li Set up the \uicontrol Debug build configuration and select the
@@ -407,9 +495,366 @@
 */
 
 /*!
+    \page qtvstools-qt-quick-application.html
+    \previouspage Tutorial: Qt Widgets Application
+    \nextpage Configuring Builds
+    \title Tutorial: Qt Quick Application
+
+    This tutorial illustrates how to use Qt VS Tools to create a \l {Qt Quick}
+    application. You will create a project using a project wizard and design a
+    Qt Quick UI. In addition, you will learn how to add QML module definitions
+    and QML files to your projects.
+
+    You can use Qt VS Tools to develop also \l{Qt Widgets} applications.
+
+    \section1 Before You Start
+
+    Before you start, you have to:
+
+    \list
+        \li \l {Install Qt VS Tools}
+        \li \l {Add a Qt Version}
+    \endlist
+
+    \section1 Create a Qt Quick Application Project
+
+    To create a Qt Quick application project in Visual Studio:
+
+    \list 1
+        \li Select \uicontrol File > \uicontrol New > \uicontrol Project, and
+            search for \uicontrol {Qt Quick Application}.
+        \li Select the project wizard, and then select \uicontrol Next.
+        \li In the \uicontrol {Project name} field, enter \e QuickAddressBook,
+            and then select \uicontrol Create.
+        \li To acknowledge the \uicontrol Welcome dialog, select
+            \uicontrol Next.
+        \li To set up debug and release build configurations, click in
+            \uicontrol {Quick Modules}, and select the \uicontrol {Quick} and
+            \uicontrol {Quick Controls2} modules to include in the project:
+            \image qtvstools-qtquick-app-modules.png "Selecting Qt modules in Qt Quick Application Wizard"
+        \li Select \uicontrol Finish to create the project.
+    \endlist
+
+    You now have a small working Qt Quick application. Select \uicontrol Build >
+    \uicontrol {Build Solution} to build it, and then select \uicontrol Debug >
+    \uicontrol {Start Debugging} to run it. For now, the result is an empty
+    window.
+
+    \section1 Design the Main Window
+
+    The wizard created a main QML file for you, which declares a root object of
+    the type \l Window. You can modify the file to design the application's main
+    window.
+
+    Specify values for the Window \c color and \c title properties to set the
+    background color and title of the application main window:
+
+    \quotefromfile QuickAddressBook/main.qml
+    \skipto Window {
+    \printuntil title
+
+    \section2 Add a Button
+
+    To create the \uicontrol Add button, declare an object of the \l Button type
+    from the \l {Qt Quick Controls} module. Set the value of the button \c text
+    property to \e Add and the value of the \c font.pointSize property to \e 24:
+
+    \skipto Button {
+    \printuntil font.pointSize
+
+    When you run the application, you should now see this:
+
+    \image qtvstools-quick-addressbook-mainwindow.png QuickAddressBook's main window
+
+    \section2 Connect the Button to an Action
+
+    QML has a signal and handler mechanism, where the signal is the event and
+    the signal is responded to through a signal handler. When a signal is
+    emitted, the corresponding signal handler is invoked. Placing logic such
+    as a script or other operations in the handler allows the component to
+    respond to the event.
+
+    To receive a notification when a particular signal is emitted for a
+    particular object, the object definition should declare a signal handler
+    named \c on<Signal>, where \c <Signal> is the name of the signal, with
+    the first letter capitalized. The signal handler should contain the
+    JavaScript code to be executed when the signal handler is invoked.
+
+    The \l Button type has a \c clicked signal, which is emitted when the users
+    click the button. To invoke a popup for adding an address book entry when
+    the users select the \uicontrol Add button in the main window, you must
+    connect the \c onClicked signal handler of the button to the \c open()
+    method of the popup. You will add the popup as a separate QML type later.
+
+    \printuntil }
+
+    \section2 Add a List Model
+
+    \image qtvstools-quick-addressbook-entries.png QuickAddressBook entries
+
+    Within the Window, declare an object of the \l ListModel type with the
+    \c id \e addressList for storing the contact data. A list model defines
+    a free-form list data source:
+
+    \quotefromfile QuickAddressBook/main.qml
+    \skipto ListModel {
+    \printuntil }
+
+    \section2 Declare a Popup
+
+    Declare an object of the custom \c NewAddressPopup type that
+    defines the popup where the users will add address book entries.
+    Use the \c onAddressAdded signal handler to determine that address
+    book entries are appended to the \e addressList model:
+
+    \printuntil }
+    \printuntil }
+
+    You will create the \c NewAddressPopup type later.
+
+    \section2 Position the Button
+
+    Declare an object of \l ColumnLayout type to position the \l Button object
+    and an instance of the \l Repeater type:
+
+    \printuntil }
+
+    Anchor the column layout to the left and right edges of its parent to make
+    the application scalable on different screen sizes. Set the \c spacing
+    between the rows in the column to \e 0.
+
+    \section2 Add a Repeater
+
+    The \l Repeater type is used to create a large number of similar items. It
+    has a model and a delegate: for each entry in the model, the delegate is
+    instantiated in a context seeded with data from the model. A repeater is
+    usually enclosed in an instance of a positioner type such as a
+    \l ColumnLayout to visually position the multiple delegate items created
+    by the repeater.
+
+    Specify \e addressList as the \c model to use for the repeater:
+
+    \printuntil anchors.right
+
+    Declare an object of the custom \c AddressBookItem type that the
+    repeater will use to instantiate address book entries:
+
+    \printuntil id:
+
+    You will create the \c AddressBookItem type later.
+
+    \section2 Connect the Remove Button to an Action
+
+    Use the \c onRemoved signal handler to specify that an address book entry
+    is removed from the list when the users click the \uicontrol Remove button
+    for an address book entry.
+
+    \printuntil }
+
+    \section1 Add a Popup
+
+    Now that the main window is ready, you can move on to create the popup
+    where users can add address book entries. The data that the
+    users enter is instantiated by the repeater in the main window, as
+    specified by the \c AddressBookItem type.
+
+    \image qtvstools-quick-addressbook-popup.png QuickAddressBook's popup
+
+    You can use a Qt file wizard in Visual Studio to create a custom type
+    that defines the popup.
+
+    To create custom QML types, you must first add a QML Module Definition
+    (\c qmldir) file to the project.
+
+    \section2 Add a QML Module Definition
+
+    A QML module definition (\c qmldir) maps each custom QML type to its
+    corresponding source file.
+
+    To add a QML module definition, select \uicontrol Project >
+    \uicontrol {Add New Item} > \uicontrol Qt >
+    \uicontrol {Qt QML Module Definition} > \uicontrol Add.
+
+    In the \c qmldir file, add QML type definitions for \e AddressBookItem and
+    \e NewAddressPopup:
+
+    \quotefile QuickAddressBook/qmldir
+
+    Next, you will create the QML types.
+
+    \section2 Create a Popup
+
+    To add a custom QML type to the project:
+
+    \list 1
+        \li Select \uicontrol Project > \uicontrol {Add New File} >
+            \uicontrol Qt > \uicontrol {Qt QML File} > \uicontrol Add.
+        \li In the \uicontrol Name field, enter \e NewAddressPopup.
+        \li Select \uicontrol Finish to create a custom QML type.
+    \endlist
+
+    \section2 Design the Popup
+
+    In \e NewAddressPopup.qml, declare a root object of the type \l Popup to
+    create a popup that can be opened within a \l Window. A popup does not
+    provide a layout of its own, so you will use a \l ColumnLayout and a
+    \l RowLayout to position the \uicontrol Name and \uicontrol {E-Mail Address}
+    fields.
+
+    \quotefromfile QuickAddressBook/QuickAddressBookTypes/NewAddressPopup.qml
+    \skipto Popup {
+    \printuntil id:
+
+    Set the \c modal property to \c true to specify that the popup is modal. Set
+    the \c focus property to \c true to specify that the popup requests focus:
+
+    \printuntil focus:
+
+    Specify values for the \c width, \c x, and \c y properties to determine the
+    position and size of the popup on top of the main window:
+
+    \printuntil y:
+
+    \section2 Reset Popup Controls
+
+    When the popup opens, the \uicontrol Name and \uicontrol {E-Mail Address}
+    fields should display placeholder text and any values entered previously
+    should be cleared. You use the \c onOpened signal handler to reset the
+    values of the fields and give focus to the \uicontrol Name field:
+
+    \printuntil }
+
+    \section2 Position Fields
+
+    Use an instance of the \l ColumnLayout type to position the \l TextField
+    objects that specify the \uicontrol Name and \uicontrol {E-Mail Address}
+    fields of the popup:
+
+    \skipto ColumnLayout {
+    \printuntil id: addrField
+    \printuntil }
+    \printuntil }
+
+    \section2 Position Buttons
+
+    Use an instance of a \l RowLayout type to position two \l Button objects
+    that specify the \uicontrol Add and \uicontrol Cancel buttons:
+
+    \printuntil Layout.fillWidth: true
+
+    \section2 Connect Buttons to Actions
+
+    When the users click the \uicontrol Add button, the values they entered to
+    the \uicontrol Name and \uicontrol {E-Mail Address} fields are added to the
+    address list in the main window and the popup is closed.
+
+    To enable this, add the \c {addressAdded(string newName, string newAddr)}
+    signal:
+
+    \quotefromfile QuickAddressBook/QuickAddressBookTypes/NewAddressPopup.qml
+    \skipto addressAdded(
+    \printuntil )
+
+    Connect the \c onClicked signal handler of the \uicontrol Add button to
+    the \c addressAdded() signal and to the popup's \c close() method:
+
+    \skipto Button {
+    \printuntil }
+    \printuntil }
+
+    For the \uicontrol Cancel button, connect the \c onClicked signal handler to
+    the to the popup's \c close() method to close the popup without saving the
+    data:
+
+    \printuntil }
+
+    \section1 Define an Address Book Entry
+
+    Address book entries are presented in the main window as specified by a
+    custom \c AddressBookItem type.
+
+    Select \uicontrol Project > \uicontrol {Add New File} > \uicontrol Qt >
+    \uicontrol {Qt QML File} > \uicontrol Add, to create a new QML file
+    called \e AddressBookItem.qml.
+
+    \section2 Design the Entry
+
+    First, you will declare a root object of type \l Rectangle. It is one of the
+    basic building blocks you can use to create an application in QML. Give it
+    an \c id to be able to refer to it later.
+
+    \quotefromfile QuickAddressBook/QuickAddressBookTypes/AddressBookItem.qml
+    \skipto Rectangle {
+    \printuntil id:
+
+    To use alternating colors for rows, set the value of the \c color property:
+
+    \printuntil color:
+
+    Anchor the rectangle to the left and right edges of its parent to make
+    the application scalable on different screen sizes. Bind the rectangle
+    \c height property to the height of the text items it will contain:
+
+    \printuntil height:
+
+    \section2 Connect the Remove Button to an Action
+
+    Add the \c removed() signal that you will connect to the \onClicked
+    signal handler of the remove button. This removes an address book entry
+    from the main window when users click the button:
+
+    \printuntil signal removed()
+
+    \section2 Position the Button and Text
+
+    Use instances of the \l RoundButton and \l Text types within an instance of
+    a \l RowLayout type to define an address book entry:
+
+    \printuntil }
+
+    \section2 Format the Text
+
+    Set the value of the \c text property to combine the values of the \c name
+    and \c addr fields from the popup and to use bold and italic formatting for
+    the values:
+
+    \printuntil }
+
+    Your application is now complete.
+
+    \section1 Create Project Files
+
+    To build the application on other platforms, you need to create a \c .pro
+    file for the project, as instructed in \l{Create Qt Project Files}.
+
+*/
+
+/*!
+    \page qtvstools-managing-projects.html
+    \previouspage Importing and Exporting Projects
+    \nextpage Creating Projects
+    \title Managing Projects
+
+    Qt VS Tools provides wizards for creating several types of Qt and Qt Quick
+    projects and files that you can add to the projects, such as classes, form
+    files, or custom QML types.
+
+    You can use the integrated Qt Resource editor to manage the resources in
+    Qt projects.
+
+    In addition, you can create a Qt translation source (TS) file and start
+    \QL from Visual Studio to translate the strings in your application.
+
+    \list
+        \li \l {Creating Projects}
+        \li \l {Creating Files}
+    \endlist
+*/
+
+/*!
     \page qtvstools-creating-projects.html
-    \previouspage Cross-Compiling
-    \nextpage Importing and Exporting Projects
+    \previouspage Managing Projects
+    \nextpage Creating Files
     \title Creating Projects
 
     Once you have installed Qt VS Tools, you can search for and then select
@@ -439,11 +884,158 @@
     To start writing Qt code and building your projects, you must tell Visual
     Studio where to find the \l{Managing Qt Versions}{Qt version} that you want
     to use.
+
+    The application tutorials contain examples of using the project templates:
+
+    \list
+        \li \l {Tutorial: Qt Widgets Application}
+        \li \l {Tutorial: Qt Quick Application}
+    \endlist
+*/
+
+/*!
+    \page qtvstools-creating-files.html
+    \previouspage Creating Projects
+    \nextpage Adding Form Files
+    \title Creating Files
+
+    You can use file templates to add the following types of files to projects
+    by selecting \uicontrol Project > \uicontrol {Add New Item} >
+    \uicontrol Installed > \uicontrol {Visual C++} > \uicontrol Qt:
+
+    \list
+        \li \uicontrol {Qt Class} adds a Qt class to an Application project.
+        \li \uicontrol {Qt Dialog Form File (Button Bottom)} adds a dialog with
+            \uicontrol OK and \uicontrol Cancel buttons at its bottom to a
+            Qt Widgets Application project.
+        \li \uicontrol {Qt Dialog Form File (Button Right)} adds a dialog with
+            buttons at its right edge to a Qt Widgets Application project.
+        \li \uicontrol {Qt MainWindow Form File} adds a form file to a
+            Qt Widgets Application project.
+        \li \uicontrol {Qt QML File} adds a custom QML type to a Qt Quick
+            Application project.
+        \li \uicontrol {Qt QML Module Definition} adds a qmldir file that
+            specifies the custom QML types used in a Qt Quick Application
+            project.
+        \li \uicontrol {Qt Resource File} adds a Qt resource file (.qrc) to
+            an Application project.
+        \li \uicontrol {Qt Translation File} adds a Qt translation file (.ts)
+            to an Application project.
+        \li \uicontrol {Qt Widget Class} adds a Qt Widgets class to a
+            Qt Widgets Application project.
+        \li \uicontrol {Qt Widget Form File} adds a Qt Widgets form file (.ui)
+            to an Application project.
+    \endlist
+
+    The following sections describe how to add different types of files to
+    projects:
+
+    \list
+        \li \l {Adding Form Files}
+        \li \l {Managing Resources}
+        \li \l {Creating Qt Translation Files}
+    \endlist
+
+    The application tutorials contain examples of using file templates to add
+    files to projects:
+
+    \list
+        \li \l {Tutorial: Qt Widgets Application}
+        \li \l {Tutorial: Qt Quick Application}
+    \endlist
+*/
+
+/*!
+    \page qtvstools-configuring-builds.html
+    \previouspage Tutorial: Qt Quick Application
+    \nextpage Managing Qt Versions
+    \title Configuring Builds
+
+    In Visual Studio, C++ projects are built using the Project System,
+    where MSBuild provides the project file format and build framework.
+    Qt VS Tools make use of the extensibility of MSBuild to provide
+    design-time and build-time integration of Qt in Visual Studio projects.
+
+    Qt uses \c .pro files with \l {qmake Manual}{qmake} to build projects,
+    whereas Visual Studio uses \c .vcproj files. Qt VS Tools enables you to
+    import Qt project files into Visual Studio and export them back into
+    Qt build files. In addition, you can convert Qt VS Tools projects into
+    a qmake project, or the other way around.
+
+    \list
+        \li \l {Managing Qt Versions}
+        \li \l {Building}
+        \li \l {Cross-Compiling}
+        \li \l {Importing and Exporting Projects}
+   \endlist
+
+    \section1 MSBuild Configurations
+
+    At very general level, MSBuild might be described as follows:
+
+    \list
+        \li An MSBuild project consists of references to source files and
+            descriptions of actions to take in order to process those source
+            files that are called \e targets.
+        \li The build process runs in the context of a project configuration,
+            such as \e Debug or \e Release. A project may contain any number
+            of configurations.
+        \li Data associated to source files and the project itself is accessible
+            through \e properties. MSBuild properties are name-value definitions,
+            specified per configuration. That is, each configuration has its own
+            set of property definitions.
+    \endlist
+
+    \image qtvstools-msbuild-diagram.png "Diagram showing Visual Studio Project and MSBuild"
+
+    \section2 Properties
+
+    Properties may apply to the project itself or to a specific file in the
+    project, and can be defined either globally or locally:
+
+    \list
+        \li Project scope properties are always global. For example, the
+            project's output directory or target file name.
+        \li Properties applied to source files can be defined globally, in
+            which case the same value will apply to all files. For example,
+            the default compiler warning level could be defined globally at
+            level 3.
+        \li Such a global, file-scope definition may be overridden for a
+            specific file by a locally defined property with the same name.
+            For example, one of the source files needs to be compiled with
+            warning level 4.
+        \li Global definitions are stored in the project file or imported from
+            property sheet files.
+        \li Local property definitions are stored in the project file, within
+            the associated source file references.
+    \endlist
+
+    \section2 Qt Settings
+
+    Qt Visual Studio Tools integrate with the MSBuild project system by
+    providing a set of Qt-specific targets that describe how to process
+    files such as moc headers by using the appropriate Qt tools.
+
+    \image qtvstools-qt-project-settings.png "Qt Project Settings"
+
+    Qt settings are fully-fledged project properties, which ensures that:
+
+    \list
+        \li Changes in Qt settings are synchronized with all the other
+            properties in the project.
+        \li You can specify Qt settings, such as Qt versions and modules,
+            separately for each build configuration.
+        \li You can override compiler properties for files generated by
+            Qt tools in project settings
+        \li You can share Qt settings within a team or organization by
+            exporting and importing them to and from shared \e {property sheet}
+            files (\c .props).
+    \endlist
 */
 
 /*!
     \page qtvstools-managing-qt-versions.html
-    \previouspage Getting Started
+    \previouspage Configuring Builds
     \nextpage Building
     \title Managing Qt Versions
 
@@ -529,7 +1121,7 @@
 /*!
     \page qtvstools-cross-compiling.html
     \previouspage Building
-    \nextpage Creating Projects
+    \nextpage Importing and Exporting Projects
     \title Cross-Compiling
 
     Qt VS Tools supports cross-compilation of Qt projects by integrating
@@ -589,8 +1181,8 @@
 
 /*!
     \page qtvstools-importing-and-exporting-projects.html
-    \previouspage Creating Projects
-    \nextpage Adding Form Files to Projects
+    \previouspage Cross-Compiling
+    \nextpage Managing Projects
     \title Importing and Exporting Projects
 
     Qt and Visual Studio use different file formats to save projects. If you
@@ -659,16 +1251,16 @@
 
 /*!
     \page qtvstools-form-files.html
-    \previouspage Importing and Exporting Projects
+    \previouspage Creating Files
     \nextpage Managing Resources
-    \title Adding Form Files to Projects
+    \title Adding Form Files
 
     You can start \QD from Qt VS Tools by double-clicking a \c .ui file. For
     more information about using \QD, see the \l{Qt Designer Manual}.
 
     To add a new \c .ui file to the project, select \uicontrol Project >
-    \uicontrol {Add Qt Class} > \uicontrol Installed > \uicontrol {Visual C++} >
-    \uicontrol Qt > \uicontrol {Qt Widget Class}.
+    \uicontrol {Add New Item} > \uicontrol Installed > \uicontrol {Visual C++} >
+    \uicontrol Qt > \uicontrol {Qt Widgets Form File}.
 
     \image qtvstools-qt-widget-class-wizard.png
 
@@ -679,8 +1271,8 @@
 
 /*!
     \page qtvstools-managing-resources.html
-    \previouspage Adding Form Files to Projects
-    \nextpage Creating Qt Translation Files for Projects
+    \previouspage Adding Form Files
+    \nextpage Creating Qt Translation Files
     \title Managing Resources
 
     Adding new resources to a Qt project is similar to adding resources to a
@@ -727,18 +1319,20 @@
     \page qtvstools-translation-files.html
     \previouspage Managing Resources
     \nextpage Updating IntelliSense Info
-    \title Creating Qt Translation Files for Projects
+    \title Creating Qt Translation Files
 
     To add a new translation file to the project:
 
+    \image qtvstools-qt-translation-file-wizard.png
+
     \list 1
-        \li Select \uicontrol Extensions > \uicontrol {Qt VS Tools} >
-            \uicontrol {Create New Translation File}.
-        \li In the \uicontrol Language field, select a language from the list of
-            supported languages.
-        \li In the \uicontrol Filename field, enter a filename for the
-            translation file.
-        \li Select \uicontrol OK to create the file and have it listed in
+        \li Select \uicontrol Project > \uicontrol {Add New Item} > \uicontrol Installed >
+            \uicontrol {Visual C++} > \uicontrol Qt > \uicontrol {Qt Translation File}.
+        \li In \uicontrol {Select a Language}, you can choose a language from the list
+            of supported languages. You can use \uicontrol Search to filter for a specific
+            language.
+        \li In the \uicontrol {Save as} field, enter a filename for the translation file.
+        \li Select \uicontrol Finish to create the file and have it listed in
             \uicontrol {Translation Files} in Visual Studio's Solution Explorer.
         \li Right-click a translation file to open a context menu with options
             for running \c lupdate and \c lrelease.
@@ -761,7 +1355,7 @@
 
 /*!
     \page qtvstools-getting-help.html
-    \previouspage Updating IntelliSense Info
+    \previouspage Debugging on Linux
     \title Getting Help
 
     By default, Qt VS Tools tries to display Qt online documentation when you
@@ -790,8 +1384,8 @@
 
 /*!
     \page qtvstools-intellisense-info.html
-    \previouspage Creating Qt Translation Files for Projects
-    \nextpage Getting Help
+    \previouspage Creating Qt Translation Files
+    \nextpage Debugging
     \title Updating IntelliSense Info
 
     Visual Studio provides IntelliSense code editing features for C++ types
@@ -822,6 +1416,164 @@
         \li \uicontrol {Verbosity of background build log} determines the amount
             of info recorded in the background build log.
     \endlist
-
 */
 
+/*!
+    \page qtvstools-debugging.html
+    \previouspage Updating IntelliSense Info
+    \nextpage Debugging Qt Quick Applications
+    \title Debugging
+
+    Visual Studio supports debugging Qt C++ applications using the Visual Studio
+    debugger and Qt Quick applications using the \e {QML debug engine}. To debug
+    applications on Linux, you can use GDB.
+
+    You can debug Qt and Qt Quick applications in Visual Studio by setting
+    breakpoints in C++ and QML files and stepping through the execution of code.
+    While in break mode, you can watch variables and change their values, as
+    well as evaluate arbitrary expressions. For Qt Quick applications, a QML
+    debugging session runs concurrently to a C++ debugging session, which
+    enables you to set breakpoints and watch variables in both C++ and QML
+    during the same debugging session.
+
+    To start a debugging session, select \uicontrol Debug >
+    \uicontrol {Start Debugging} or press \key F5.
+
+    \list
+        \li \l {Debugging Qt Quick Applications}
+        \li \l {Debugging on Linux}
+    \endlist
+*/
+
+/*!
+    \page qtvstools-debugging-qt-quick.html
+    \previouspage Debugging
+    \nextpage Debugging on Linux
+    \title Debugging Qt Quick Applications
+
+    A \e {QML debug engine} extends the Visual Studio debugger with features of
+    the \l{QML Debugging Infrastructure}{QML debugging infrastructure}, which is
+    a part of the \l{Qt QML} module that provides services for debugging,
+    inspecting, and profiling applications via a TCP port. The debug engine
+    implements interfaces from the Active Debugging 7 (AD7) extensibility
+    framework for the Visual Studio debugger.
+
+    If a Qt project contains QML resource files, starting a debugging session
+    (for example, by pressing \key F5) launches the native application and
+    connects to the QML debugging infrastructure of that application. This can
+    be seen in the Processes window of the Visual Studio debugger. Two processes
+    are listed: a native process that corresponds to the actual physical
+    process created for the C++ debugging session and a QML process that does
+    not correspond to any physical process that is running on the machine, but
+    rather represents the connection to the QML debugging runtime within the
+    native process.
+
+    The presence of both a native process and a QML process enables setting
+    breakpoints both in C++ or QML code. The Visual Studio debugger forwards
+    breakpoint requests to the appropriate debug engine. A filled circular
+    breakpoint marker in QML code indicates a valid breakpoint. This means that
+    a breakpoint request for that file position was sent to the QML runtime
+    and was confirmed by it.
+
+    When a breakpoint is hit, Visual Studio shows the current state of the call
+    stack. Unlike other scenarios of debugging applications that mix several
+    languages, such as .NET and native debugging, the QML debug engine does not
+    provide true mixed mode debugging. It runs concurrently with the native
+    debug engine and is not considered to be related to the native process by
+    the Visual Studio debugger. Therefore, even though you can debug both C++
+    and QML in the same debugging session, the stack that is shown when a QML
+    breakpoint is hit includes only QML function calls. The C++ context of those
+    calls will not be available.
+
+    As in the case of native debugging, while in break mode, it is possible to
+    view and modify the values of local variables in the context of the
+    currently active call stack frame, as well as to create watches for any
+    variable or expression. In the Immediate window, you can evaluate any
+    expression in the context of the current stack frame.
+
+    Move the mouse over a QML expression to display an instant watch window.
+    The value of that expression in the current context is displayed and can
+    be modified.
+
+    \section1 Enabling QML Debugging
+
+    QML debugging is enabled by default. To disable processing of all QML
+    debug events by the QML debug engine, select \uicontrol Extensions >
+    \uicontrol {Qt VS Tools} > \uicontrol Options > \uicontrol Qt
+    \uicontrol General > \uicontrol {QML Debugging}, and set
+    \uicontrol {Process debug events} to \uicontrol False.
+    This effectively excludes the QML debug engine from the debugging
+    environment and disables debugging of QML code for all projects.
+
+    \image qtvstools-options-qt-general.png "Qt General Options"
+
+    To increase or decrease the timeout for debugging connections in
+    milliseconds, edit the value of \uicontrol {Runtime connection timeout}.
+    To remove the timeout, set the value to \uicontrol Disabled.
+
+    For more information about debugging Qt Quick applications on Linux devices,
+    see \l {Remote QML Debugging}.
+*/
+
+/*!
+    \page qtvstools-debugging-linux.html
+    \previouspage Debugging Qt Quick Applications
+    \nextpage Getting Help
+    \title Debugging on Linux
+
+    If you have set up Qt VS Tools for \l {Cross-Compiling}{cross-compilation}
+    on Linux, you can debug applications running on a Linux devices. First
+    launch the application using \c gdbserver and then configure GDB to connect
+    to the device and start a remote debugging session.
+
+    \image qtvstools-remote-debugging.png
+
+    For this to work, the GDB installed in the WSL must support the target
+    device architecture. A simple way to achieve this is to install
+    \c gdb-multiarch. To ensure the Visual Studio uses the correct debugger,
+    create a symbolic link from \c gdb to \c gdb-multiarch.
+
+    To set up the remote debugging session in Visual Studio, you must
+    pass additional commands to GDB. Select \uicontrol Project >
+    \uicontrol Properties > \uicontrol Debugging, and then select
+    \uicontrol {GDB Debugger} in \uicontrol {Debugger to launch}. In
+    \uicontrol {Additional Debugger Commands}, add the following commands:
+
+    \badcode
+    target extended-remote <IP_address>:<port>
+    set remote exec-file <path_to_executable>
+    \endcode
+
+    Before starting the remote debugging session, set the required environment
+    variables and launch \c gdbserver on the device:
+
+    \list
+        \li \l{https://man7.org/linux/man-pages/man8/ld.so.8.html}
+            {LD_LIBRARY_PATH} specifies the path to the directory
+            where Qt binaries are installed.
+        \li \l {Qt for Embedded Linux}{QT_QPA_PLATFORM} specifies the platform
+            plugin, such as EGLFS, LinuxFB, DirectFB, or Wayland.
+        \li \c QT_QPA_PLATFORM_PLUGIN_PATH specifies the path to the
+            directory where the platform plugin is installed.
+        \li For the \l {EGLFS} platform, \c QT_QPA_EGLFS_PHYSICAL_WIDTH and
+            \c QT_QPA_EGLFS_PHYSICAL_HEIGHT specify the screen width and
+            height in millimeters.
+        \li \l{QML Import Path}{QML2_IMPORT_PATH} specifies the path to the
+            directory where QML modules are installed.
+    \endlist
+
+    Press \key F5 to start the remote debugging session.
+
+    \section1 Remote QML Debugging
+
+    To debug Qt Quick applications on Linux devices, \l{Enabling QML Debugging}
+    {enable QML debugging} and set up program arguments for starting a QML
+    debugging session. \uicontrol Project > \uicontrol Properties >
+    \uicontrol Debugging, and then select \uicontrol {GDB Debugger} in
+    \uicontrol {Debugger to launch}. In
+    \uicontrol {Additional Debugger Commands}, add the following command:
+
+    \badcode
+    -qmljsdebugger=port:<port>,host:<IP_address>,block
+    \endcode
+*/
diff --git a/doc/tutorial/AddressBook/adddialog.h b/doc/tutorial/AddressBook/adddialog.h
index 68b312d..13d05f2 100644
--- a/doc/tutorial/AddressBook/adddialog.h
+++ b/doc/tutorial/AddressBook/adddialog.h
@@ -48,6 +48,6 @@
     Q_OBJECT
 
 public:
-    AddDialog(QWidget *parent = Q_NULLPTR);
+    AddDialog(QWidget *parent = nullptr);
     ~AddDialog();
 };
diff --git a/doc/tutorial/QuickAddressBook/QuickAddressBook.sln b/doc/tutorial/QuickAddressBook/QuickAddressBook.sln
new file mode 100644
index 0000000..b774435
--- /dev/null
+++ b/doc/tutorial/QuickAddressBook/QuickAddressBook.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31919.166
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QuickAddressBook", "QuickAddressBook.vcxproj", "{09DCDDDF-9469-4F20-84EF-7D8481C6FFE1}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{09DCDDDF-9469-4F20-84EF-7D8481C6FFE1}.Debug|x64.ActiveCfg = Debug|x64
+		{09DCDDDF-9469-4F20-84EF-7D8481C6FFE1}.Debug|x64.Build.0 = Debug|x64
+		{09DCDDDF-9469-4F20-84EF-7D8481C6FFE1}.Release|x64.ActiveCfg = Release|x64
+		{09DCDDDF-9469-4F20-84EF-7D8481C6FFE1}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {7D002559-106F-4ED4-A8D0-DCF37C96FDA8}
+	EndGlobalSection
+EndGlobal
diff --git a/doc/tutorial/QuickAddressBook/QuickAddressBook.vcxproj b/doc/tutorial/QuickAddressBook/QuickAddressBook.vcxproj
new file mode 100644
index 0000000..005fe3f
--- /dev/null
+++ b/doc/tutorial/QuickAddressBook/QuickAddressBook.vcxproj
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+-->
+<Project ToolsVersion="$(VisualStudioVersion)" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{09DCDDDF-9469-4F20-84EF-7D8481C6FFE1}</ProjectGuid>
+    <Keyword>QtVS_v304</Keyword>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion Condition="'$(VisualStudioVersion)'=='15.0'">10.0.17763.0</WindowsTargetPlatformVersion>
+    <QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')">$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+  </PropertyGroup>
+  <PropertyGroup>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='15.0'">v141</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='16.0'">v142</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='17.0'">v143</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
+    <Import Project="$(QtMsBuild)\qt_defaults.props" />
+  </ImportGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="QtSettings">
+    <QtInstall>$(DefaultQtVersion)</QtInstall>
+    <QtModules>quick</QtModules>
+    <QtBuildConfig>debug</QtBuildConfig>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="QtSettings">
+    <QtInstall>$(DefaultQtVersion)</QtInstall>
+    <QtModules>quick</QtModules>
+    <QtBuildConfig>release</QtBuildConfig>
+  </PropertyGroup>
+  <Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
+    <Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
+  </Target>
+  <ImportGroup Label="ExtensionSettings" />
+  <ImportGroup Label="Shared" />
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(QtMsBuild)\Qt.props" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(QtMsBuild)\Qt.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
+    <ClCompile>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <Optimization>Disabled</Optimization>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
+    <ClCompile>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat>None</DebugInformationFormat>
+      <Optimization>MaxSpeed</Optimization>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="main.cpp" />
+    <None Include="qmldir" />
+    <None Include="QuickAddressBookTypes\AddressBookItem.qml" />
+    <None Include="main.qml" />
+    <None Include="QuickAddressBookTypes\NewAddressPopup.qml" />
+  </ItemGroup>
+  <ItemGroup>
+    <QtRcc Include="qml.qrc" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
+    <Import Project="$(QtMsBuild)\qt.targets" />
+  </ImportGroup>
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
diff --git a/doc/tutorial/QuickAddressBook/QuickAddressBook.vcxproj.filters b/doc/tutorial/QuickAddressBook/QuickAddressBook.vcxproj.filters
new file mode 100644
index 0000000..ae4de39
--- /dev/null
+++ b/doc/tutorial/QuickAddressBook/QuickAddressBook.vcxproj.filters
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+    <Filter Include="Translation Files">
+      <UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>
+      <Extensions>ts</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="main.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <None Include="main.qml">
+      <Filter>Source Files</Filter>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="QuickAddressBookTypes\AddressBookItem.qml">
+      <Filter>Source Files</Filter>
+    </None>
+    <None Include="qmldir">
+      <Filter>Source Files</Filter>
+    </None>
+    <None Include="QuickAddressBookTypes\NewAddressPopup.qml">
+      <Filter>Source Files</Filter>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <QtRcc Include="qml.qrc">
+      <Filter>Resource Files</Filter>
+    </QtRcc>
+  </ItemGroup>
+</Project>
diff --git a/doc/tutorial/QuickAddressBook/QuickAddressBookTypes/AddressBookItem.qml b/doc/tutorial/QuickAddressBook/QuickAddressBookTypes/AddressBookItem.qml
new file mode 100644
index 0000000..7374265
--- /dev/null
+++ b/doc/tutorial/QuickAddressBook/QuickAddressBookTypes/AddressBookItem.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.9
+import QtQuick.Window 2.2
+import QtQuick.Controls 2.5
+import QtQuick.Layouts 1.12
+
+Rectangle {
+    id: addressBookItem
+    color: (index % 2) == 0 ? "dimgray" : "lightgray"
+    anchors.left: parent.left
+    anchors.right: parent.right
+    height: itemText.height + 12
+
+    signal removed()
+
+    RowLayout {
+        spacing: 12
+        anchors.left: parent.left
+        anchors.leftMargin: spacing
+        RoundButton {
+            id: deleteButton
+            text: "🗙"
+            font.pointSize: 12
+            palette.buttonText: "red"
+            onClicked: addressBookItem.removed()
+        }
+        Text {
+            id: itemText
+            font.pointSize: 24
+            text: "<b>" + name + "</b><br><i>" + addr + "</i>"
+        }
+    }
+}
diff --git a/doc/tutorial/QuickAddressBook/QuickAddressBookTypes/NewAddressPopup.qml b/doc/tutorial/QuickAddressBook/QuickAddressBookTypes/NewAddressPopup.qml
new file mode 100644
index 0000000..6513ec3
--- /dev/null
+++ b/doc/tutorial/QuickAddressBook/QuickAddressBookTypes/NewAddressPopup.qml
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.9
+import QtQuick.Window 2.2
+import QtQuick.Controls 2.5
+import QtQuick.Layouts 1.12
+
+Popup {
+    id: newAddressPopup
+    modal: true
+    focus: true
+    width: parent.width * 0.9
+    x: (parent.width - width) / 2
+    y: 35
+    onOpened: {
+        nameField.text = "";
+        addrField.text = "";
+        nameField.focus = true;
+    }
+
+    signal addressAdded(string newName, string newAddr)
+
+    ColumnLayout {
+        anchors.fill: parent
+        TextField {
+            id: nameField
+            placeholderText: qsTr("Name")
+            font.pointSize: 24
+            background: Rectangle { color: "lightgray" }
+            Layout.preferredWidth: newAddressPopup / 2
+            Layout.fillWidth: true
+        }
+        TextField {
+            id: addrField
+            placeholderText: qsTr("E-Mail Address")
+            font.pointSize: 24
+            background: Rectangle { color: "lightgray" }
+            Layout.preferredWidth: newAddressPopup / 2
+            Layout.fillWidth: true
+        }
+        RowLayout {
+            anchors.left: parent.left; anchors.right: parent.right
+            Button {
+                text: "Add"
+                enabled: nameField.length > 0 && addrField.length > 0
+                font.pointSize: 24
+                Layout.preferredWidth: newAddressPopup / 2
+                Layout.fillWidth: true
+                onClicked: {
+                    newAddressPopup.addressAdded(nameField.text, addrField.text)
+                    newAddressPopup.close()
+                }
+            }
+            Button {
+                text: "Cancel"
+                font.pointSize: 24
+                Layout.preferredWidth: newAddressPopup / 2
+                Layout.fillWidth: true
+                onClicked: newAddressPopup.close()
+            }
+        }
+    }
+}
diff --git a/doc/tutorial/QuickAddressBook/main.cpp b/doc/tutorial/QuickAddressBook/main.cpp
new file mode 100644
index 0000000..a02a02f
--- /dev/null
+++ b/doc/tutorial/QuickAddressBook/main.cpp
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+
+int main(int argc, char *argv[])
+{
+#if defined(Q_OS_WIN)
+    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+#endif
+
+    QGuiApplication app(argc, argv);
+
+    QQmlApplicationEngine engine;
+    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+    if (engine.rootObjects().isEmpty())
+        return -1;
+
+    return app.exec();
+}
diff --git a/doc/tutorial/QuickAddressBook/main.qml b/doc/tutorial/QuickAddressBook/main.qml
new file mode 100644
index 0000000..01e6e68
--- /dev/null
+++ b/doc/tutorial/QuickAddressBook/main.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt VS Tools.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.9
+import QtQuick.Window 2.2
+import QtQuick.Controls 2.5
+import QtQuick.Layouts 1.12
+import "QuickAddressBookTypes"
+
+Window {
+    id: mainWindow
+    visible: true
+    width: 480
+    height: 640
+    color: "darkgray"
+    title: qsTr("Address Book")
+
+    ListModel {
+        id: addressList
+    }
+
+    NewAddressPopup {
+        id: newAddressPopup
+        onAddressAdded: addressList.append({name: newName, addr: newAddr})
+    }
+
+    ColumnLayout {
+        id: mainWindowLayout
+        anchors.left: parent.left; anchors.right: parent.right
+        spacing: 0
+        Button {
+            id: addButton
+            anchors.left: parent.left
+            anchors.right: parent.right
+            text: "Add..."
+            font.pointSize: 24
+            onClicked: newAddressPopup.open()
+        }
+        Repeater {
+            id: addressListViewer
+            model: addressList
+            anchors.left: parent.left
+            anchors.right: parent.right
+            AddressBookItem {
+                id: addressBookItem
+                onRemoved: addressList.remove(index)
+            }
+        }
+    }
+}
diff --git a/doc/tutorial/QuickAddressBook/qml.qrc b/doc/tutorial/QuickAddressBook/qml.qrc
new file mode 100644
index 0000000..f5a34f3
--- /dev/null
+++ b/doc/tutorial/QuickAddressBook/qml.qrc
@@ -0,0 +1,8 @@
+<RCC>
+    <qresource prefix="/">
+        <file>main.qml</file>
+        <file>qmldir</file>
+        <file>QuickAddressBookTypes/AddressBookItem.qml</file>
+        <file>QuickAddressBookTypes/NewAddressPopup.qml</file>
+    </qresource>
+</RCC>
diff --git a/doc/tutorial/QuickAddressBook/qmldir b/doc/tutorial/QuickAddressBook/qmldir
new file mode 100644
index 0000000..23d4e49
--- /dev/null
+++ b/doc/tutorial/QuickAddressBook/qmldir
@@ -0,0 +1,2 @@
+AddressBookItem    1.0    AddressBookItem.qml
+NewAddressPopup    1.0    NewAddressPopup.qml
diff --git a/references.props b/references.props
index 0f4a231..b38e5f9 100644
--- a/references.props
+++ b/references.props
@@ -2,124 +2,73 @@
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <!--
   /////////////////////////////////////////////////////////////////////////////////////////////////
-  // References versions
+  // Package References names/version
   // -->
   <!-- // Common -->
   <PropertyGroup>
-    <Version_Microsoft_Bcl_AsyncInterfaces
-      >5.0.0</Version_Microsoft_Bcl_AsyncInterfaces>
-    <Version_Stub_System_Data_SQLite_Core_NetFramework
-      >1.0.115</Version_Stub_System_Data_SQLite_Core_NetFramework>
-    <Version_System_Collections_Immutable
-      >5.0.0</Version_System_Collections_Immutable>
-    <Version_System_ComponentModel_Composition
-      >5.0.0</Version_System_ComponentModel_Composition>
-    <Version_Newtonsoft_Json
-      >13.0.1</Version_Newtonsoft_Json>
-    <Version_MSTest_TestAdapter
-      >2.2.8</Version_MSTest_TestAdapter>
-    <Version_MSTest_TestFramework
-      >2.2.8</Version_MSTest_TestFramework>
+    <Name_Microsoft_Build>Microsoft.Build</Name_Microsoft_Build>
+    <Name_Microsoft_Build_Tasks_Core>Microsoft.Build.Tasks.Core</Name_Microsoft_Build_Tasks_Core>
+    <Name_Microsoft_VSSDK_BuildTools>Microsoft.VSSDK.BuildTools</Name_Microsoft_VSSDK_BuildTools>
+    <Name_Microsoft_VisualStudio_SDK>Microsoft.VisualStudio.SDK</Name_Microsoft_VisualStudio_SDK>
+    <Name_Microsoft_Bcl_AsyncInterfaces>Microsoft.Bcl.AsyncInterfaces</Name_Microsoft_Bcl_AsyncInterfaces>
+    <Name_Microsoft_VisualStudio_Validation>Microsoft.VisualStudio.Validation</Name_Microsoft_VisualStudio_Validation>
+    <Name_Microsoft_VisualStudio_RpcContracts>Microsoft.VisualStudio.RpcContracts</Name_Microsoft_VisualStudio_RpcContracts>
+    <Name_Microsoft_VisualStudio_ProjectSystem>Microsoft.VisualStudio.ProjectSystem</Name_Microsoft_VisualStudio_ProjectSystem>
+    <Name_Microsoft_VisualStudio_VCProjectEngine>Microsoft.VisualStudio.VCProjectEngine</Name_Microsoft_VisualStudio_VCProjectEngine>
+    <Name_Microsoft_VisualStudio_Shell_15>Microsoft.VisualStudio.Shell.15.0</Name_Microsoft_VisualStudio_Shell_15>
+    <Name_Microsoft_VisualStudio_Shell_Framework>Microsoft.VisualStudio.Shell.Framework</Name_Microsoft_VisualStudio_Shell_Framework>
+    <Name_Microsoft_VisualStudio_TemplateWizardInterface>Microsoft.VisualStudio.TemplateWizardInterface</Name_Microsoft_VisualStudio_TemplateWizardInterface>
+
+    <Name_MSTest_TestAdapter>MSTest.TestAdapter</Name_MSTest_TestAdapter>
+    <Version_MSTest_TestAdapter>2.2.8</Version_MSTest_TestAdapter>
+
+    <Name_MSTest_TestFramework>MSTest.TestFramework</Name_MSTest_TestFramework>
+    <Version_MSTest_TestFramework>2.2.8</Version_MSTest_TestFramework>
+
+    <Name_Newtonsoft_Json>Newtonsoft.Json</Name_Newtonsoft_Json>
+    <Version_Newtonsoft_Json>13.0.1</Version_Newtonsoft_Json>
+
+    <Name_Stub_System_Data_SQLite_Core_NetFramework>Stub.System.Data.SQLite.Core.NetFramework</Name_Stub_System_Data_SQLite_Core_NetFramework>
+    <Version_Stub_System_Data_SQLite_Core_NetFramework>1.0.115.5</Version_Stub_System_Data_SQLite_Core_NetFramework>
   </PropertyGroup>
-  <PropertyGroup>
-    <Name_DummyPackage
-      >Stub.System.Data.SQLite.Core.NetFramework</Name_DummyPackage>
-    <Version_DummyPackage
-      >$(Version_Stub_System_Data_SQLite_Core_NetFramework)</Version_DummyPackage>
-  </PropertyGroup>
+
   <!-- // Visual Studio 2022 -->
   <PropertyGroup Condition="'$(VisualStudioVersion)'=='17.0'">
-    <Version_Microsoft_Build
-      >16.11.0</Version_Microsoft_Build>
-    <Version_Microsoft_Build_Framework
-      >16.11.0</Version_Microsoft_Build_Framework>
-    <Version_Microsoft_Build_Tasks_Core
-      >16.11.0</Version_Microsoft_Build_Tasks_Core>
-    <Version_Microsoft_VisualStudio_SDK
-      >17.0.0-previews-4-31709-430</Version_Microsoft_VisualStudio_SDK>
-    <Version_Microsoft_VSSDK_BuildTools
-      >17.0.5232</Version_Microsoft_VSSDK_BuildTools>
-    <Version_Microsoft_VisualStudio_ProjectSystem
-      >17.0.667-pre</Version_Microsoft_VisualStudio_ProjectSystem>
-    <Version_Microsoft_VisualStudio_Validation
-      >17.0.34</Version_Microsoft_VisualStudio_Validation>
-    <Version_Microsoft_VisualStudio_Shell_Framework
-      >17.0.0-previews-5-31722-452</Version_Microsoft_VisualStudio_Shell_Framework>
-    <Name_Microsoft_VisualStudio_VCProjectEngine
-      >Microsoft.VisualStudio.VCProjectEngine</Name_Microsoft_VisualStudio_VCProjectEngine>
-    <Version_Microsoft_VisualStudio_VCProjectEngine
-      >17.0.0-previews-4-31709-430</Version_Microsoft_VisualStudio_VCProjectEngine>
-    <Name_Microsoft_VisualStudio_TemplateWizardInterface
-      >Microsoft.VisualStudio.TemplateWizardInterface</Name_Microsoft_VisualStudio_TemplateWizardInterface>
-    <Version_Microsoft_VisualStudio_TemplateWizardInterface
-      >17.0.0-previews-1-31410-258</Version_Microsoft_VisualStudio_TemplateWizardInterface>
-    <Name_Microsoft_VisualStudio_Threading
-      >$(Name_DummyPackage)</Name_Microsoft_VisualStudio_Threading>
-    <Version_Microsoft_VisualStudio_Threading
-      >$(Version_DummyPackage)</Version_Microsoft_VisualStudio_Threading>
-    <Version_System_Collections_Immutable
-      >5.0.0</Version_System_Collections_Immutable>
+    <Version_Microsoft_Build>17.0.0</Version_Microsoft_Build>
+    <Version_Microsoft_Build_Tasks_Core>17.0.0</Version_Microsoft_Build_Tasks_Core>
+    <Version_Microsoft_VSSDK_BuildTools>17.0.5234</Version_Microsoft_VSSDK_BuildTools>
+    <Version_Microsoft_Bcl_AsyncInterfaces>6.0.0</Version_Microsoft_Bcl_AsyncInterfaces>
+    <Version_Microsoft_VisualStudio_SDK>17.0.32112.339</Version_Microsoft_VisualStudio_SDK>
+    <Version_Microsoft_VisualStudio_ProjectSystem>17.0.1313-pre</Version_Microsoft_VisualStudio_ProjectSystem>
+    <Version_Microsoft_VisualStudio_TemplateWizardInterface>17.0.31902.203</Version_Microsoft_VisualStudio_TemplateWizardInterface>
+    <Version_Microsoft_VisualStudio_Shell_15>17.0.32112.339</Version_Microsoft_VisualStudio_Shell_15>
   </PropertyGroup>
+
   <!-- // Visual Studio 2019 -->
   <PropertyGroup Condition="'$(VisualStudioVersion)'=='16.0'">
-    <Version_Microsoft_Build
-      >16.8.0</Version_Microsoft_Build>
-    <Version_Microsoft_Build_Framework
-      >16.8.0</Version_Microsoft_Build_Framework>
-    <Version_Microsoft_Build_Tasks_Core
-      >16.8.0</Version_Microsoft_Build_Tasks_Core>
-    <Version_Microsoft_VisualStudio_SDK
-      >16.0.206</Version_Microsoft_VisualStudio_SDK>
-    <Version_Microsoft_VSSDK_BuildTools
-      >16.4.1060</Version_Microsoft_VSSDK_BuildTools>
-    <Version_Microsoft_VisualStudio_ProjectSystem
-      >16.2.133-pre</Version_Microsoft_VisualStudio_ProjectSystem>
-    <Version_Microsoft_VisualStudio_Validation
-      >16.8.33</Version_Microsoft_VisualStudio_Validation>
-    <Version_Microsoft_VisualStudio_Shell_Framework
-      >16.4.29519.181</Version_Microsoft_VisualStudio_Shell_Framework>
-    <Name_Microsoft_VisualStudio_VCProjectEngine
-      >Microsoft.VisualStudio.VCProjectEngine</Name_Microsoft_VisualStudio_VCProjectEngine>
-    <Version_Microsoft_VisualStudio_VCProjectEngine
-      >16.7.30328.74</Version_Microsoft_VisualStudio_VCProjectEngine>
-    <Name_Microsoft_VisualStudio_TemplateWizardInterface
-      >$(Name_DummyPackage)</Name_Microsoft_VisualStudio_TemplateWizardInterface>
-    <Version_Microsoft_VisualStudio_TemplateWizardInterface
-      >$(Version_DummyPackage)</Version_Microsoft_VisualStudio_TemplateWizardInterface>
-    <Name_Microsoft_VisualStudio_Threading
-      >$(Name_DummyPackage)</Name_Microsoft_VisualStudio_Threading>
-    <Version_Microsoft_VisualStudio_Threading
-      >$(Version_DummyPackage)</Version_Microsoft_VisualStudio_Threading>
-    <Version_System_Collections_Immutable
-      >1.5.0</Version_System_Collections_Immutable>
+    <Version_Microsoft_Build>16.11.0</Version_Microsoft_Build>
+    <Version_Microsoft_Build_Tasks_Core>16.11.0</Version_Microsoft_Build_Tasks_Core>
+    <Version_Microsoft_VSSDK_BuildTools>16.11.35</Version_Microsoft_VSSDK_BuildTools>
+    <Version_Microsoft_Bcl_AsyncInterfaces>5.0.0</Version_Microsoft_Bcl_AsyncInterfaces>
+    <Version_Microsoft_VisualStudio_SDK>16.10.31321.278</Version_Microsoft_VisualStudio_SDK>
+    <Version_Microsoft_VisualStudio_Validation>16.10.35</Version_Microsoft_VisualStudio_Validation>
+    <Version_Microsoft_VisualStudio_RpcContracts>17.0.51</Version_Microsoft_VisualStudio_RpcContracts>
+    <Version_Microsoft_VisualStudio_ProjectSystem>16.2.133-pre</Version_Microsoft_VisualStudio_ProjectSystem>
+    <Version_Microsoft_VisualStudio_VCProjectEngine>16.10.31320.204</Version_Microsoft_VisualStudio_VCProjectEngine>
+    <Version_Microsoft_VisualStudio_TemplateWizardInterface>16.10.31320.204</Version_Microsoft_VisualStudio_TemplateWizardInterface>
+    <Version_Microsoft_VisualStudio_Shell_15>16.10.31321.278</Version_Microsoft_VisualStudio_Shell_15>
   </PropertyGroup>
+
   <!-- // Visual Studio 2017 -->
   <PropertyGroup Condition="'$(VisualStudioVersion)'=='15.0'">
-    <Version_Microsoft_Build
-      >15.9.20</Version_Microsoft_Build>
-    <Version_Microsoft_Build_Framework
-      >15.9.20</Version_Microsoft_Build_Framework>
-    <Version_Microsoft_Build_Tasks_Core
-      >15.9.20</Version_Microsoft_Build_Tasks_Core>
-    <Version_Microsoft_VisualStudio_SDK
-      >15.0.1</Version_Microsoft_VisualStudio_SDK>
-    <Version_Microsoft_VSSDK_BuildTools
-      >15.9.3039</Version_Microsoft_VSSDK_BuildTools>
-    <Version_Microsoft_VisualStudio_ProjectSystem
-      >15.8.243</Version_Microsoft_VisualStudio_ProjectSystem>
-    <Version_Microsoft_VisualStudio_Validation
-      >15.5.31</Version_Microsoft_VisualStudio_Validation>
-    <Version_Microsoft_VisualStudio_Shell_Framework
-      >15.9.28307</Version_Microsoft_VisualStudio_Shell_Framework>
-    <Name_Microsoft_VisualStudio_TemplateWizardInterface
-      >$(Name_DummyPackage)</Name_Microsoft_VisualStudio_TemplateWizardInterface>
-    <Version_Microsoft_VisualStudio_TemplateWizardInterface
-      >$(Version_DummyPackage)</Version_Microsoft_VisualStudio_TemplateWizardInterface>
-    <Name_Microsoft_VisualStudio_Threading
-      >Microsoft.VisualStudio.Threading</Name_Microsoft_VisualStudio_Threading>
-    <Version_Microsoft_VisualStudio_Threading
-      >15.8.209</Version_Microsoft_VisualStudio_Threading>
-    <Version_System_Collections_Immutable
-      >1.5.0</Version_System_Collections_Immutable>
+    <Version_Microsoft_Build>15.9.20</Version_Microsoft_Build>
+    <Version_Microsoft_VisualStudio_SDK>15.0.1</Version_Microsoft_VisualStudio_SDK>
+    <Version_Microsoft_Build_Tasks_Core>15.9.20</Version_Microsoft_Build_Tasks_Core>
+    <Version_Microsoft_VSSDK_BuildTools>15.9.3039</Version_Microsoft_VSSDK_BuildTools>
+    <Version_Microsoft_Bcl_AsyncInterfaces>5.0.0</Version_Microsoft_Bcl_AsyncInterfaces>
+    <Version_Microsoft_VisualStudio_ProjectSystem>15.8.243</Version_Microsoft_VisualStudio_ProjectSystem>
+    <Version_Microsoft_VisualStudio_Shell_Framework>15.9.28307</Version_Microsoft_VisualStudio_Shell_Framework>
+    <Version_Microsoft_VisualStudio_Shell_15>15.9.28307</Version_Microsoft_VisualStudio_Shell_15>
   </PropertyGroup>
+
 </Project>
diff --git a/version.targets b/version.targets
index d6516b3..43fc5f6 100644
--- a/version.targets
+++ b/version.targets
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup Condition="'$(QtVSToolsVersion)' == ''">
-    <QtVSToolsVersion>2.8.1</QtVSToolsVersion>
+    <QtVSToolsVersion>2.9.0</QtVSToolsVersion>
   </PropertyGroup>
 </Project>
diff --git a/vsconfig/2017.vsconfig b/vsconfig/2017.vsconfig
new file mode 100644
index 0000000..6142b6e
--- /dev/null
+++ b/vsconfig/2017.vsconfig
@@ -0,0 +1,48 @@
+{
+  "version": "1.0",
+  "components": [
+    "Microsoft.VisualStudio.Component.CoreEditor",
+    "Microsoft.VisualStudio.Workload.CoreEditor",
+    "Microsoft.VisualStudio.Component.Roslyn.Compiler",
+    "Microsoft.Component.MSBuild",
+    "Microsoft.VisualStudio.Component.Static.Analysis.Tools",
+    "Microsoft.VisualStudio.Component.Roslyn.LanguageServices",
+    "Microsoft.VisualStudio.Component.PortableLibrary",
+    "Microsoft.Net.Component.4.6.1.SDK",
+    "Microsoft.Net.Component.4.6.1.TargetingPack",
+    "Microsoft.Net.ComponentGroup.DevelopmentPrerequisites",
+    "Microsoft.Component.ClickOnce",
+    "Microsoft.VisualStudio.Component.SQL.CLR",
+    "Microsoft.VisualStudio.Component.VisualStudioData",
+    "Microsoft.VisualStudio.Component.TextTemplating",
+    "Microsoft.VisualStudio.Component.ManagedDesktop.Core",
+    "Microsoft.VisualStudio.Component.ManagedDesktop.Prerequisites",
+    "Microsoft.Net.Component.4.TargetingPack",
+    "Microsoft.Net.Component.4.5.TargetingPack",
+    "Microsoft.Net.Component.4.5.1.TargetingPack",
+    "Microsoft.Net.Component.4.5.2.TargetingPack",
+    "Microsoft.Net.Component.4.6.TargetingPack",
+    "Microsoft.Net.ComponentGroup.TargetingPacks.Common",
+    "Microsoft.VisualStudio.Component.NuGet",
+    "Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions",
+    "Microsoft.VisualStudio.Workload.ManagedDesktop",
+    "Microsoft.VisualStudio.Component.VC.CoreIde",
+    "Microsoft.VisualStudio.Component.VC.Redist.14.Latest",
+    "Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core",
+    "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
+    "Microsoft.VisualStudio.Component.Graphics.Win81",
+    "Microsoft.VisualStudio.Component.Graphics.Tools",
+    "Microsoft.VisualStudio.Component.VC.DiagnosticTools",
+    "Microsoft.VisualStudio.Component.Windows10SDK.17763",
+    "Microsoft.VisualStudio.Component.VC.CMake.Project",
+    "Microsoft.VisualStudio.Component.VC.ATL",
+    "Microsoft.VisualStudio.Workload.NativeDesktop",
+    "Microsoft.VisualStudio.Component.Windows10SDK",
+    "Microsoft.VisualStudio.Component.VSSDK",
+    "Microsoft.VisualStudio.ComponentGroup.VisualStudioExtension.Prerequisites",
+    "Microsoft.VisualStudio.Workload.VisualStudioExtension",
+    "Component.MDD.Linux",
+    "Component.Linux.CMake",
+    "Microsoft.VisualStudio.Workload.NativeCrossPlat"
+  ]
+}
\ No newline at end of file
diff --git a/vsconfig/2019.vsconfig b/vsconfig/2019.vsconfig
new file mode 100644
index 0000000..2bdc9aa
--- /dev/null
+++ b/vsconfig/2019.vsconfig
@@ -0,0 +1,44 @@
+{
+  "version": "1.0",
+  "components": [
+    "Microsoft.VisualStudio.Component.CoreEditor",
+    "Microsoft.VisualStudio.Workload.CoreEditor",
+    "Microsoft.NetCore.Component.Runtime.5.0",
+    "Microsoft.NetCore.Component.Runtime.3.1",
+    "Microsoft.NetCore.Component.SDK",
+    "Microsoft.VisualStudio.Component.NuGet",
+    "Microsoft.VisualStudio.Component.Roslyn.Compiler",
+    "Microsoft.VisualStudio.Component.Roslyn.LanguageServices",
+    "Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions",
+    "Microsoft.Net.Component.4.8.SDK",
+    "Microsoft.Net.Component.4.7.2.TargetingPack",
+    "Microsoft.Net.ComponentGroup.DevelopmentPrerequisites",
+    "Microsoft.VisualStudio.Component.TypeScript.4.3",
+    "Microsoft.VisualStudio.Component.JavaScript.TypeScript",
+    "Microsoft.Component.MSBuild",
+    "Microsoft.VisualStudio.Component.TextTemplating",
+    "Microsoft.Net.Component.4.6.TargetingPack",
+    "Microsoft.VisualStudio.Component.DiagnosticTools",
+    "Microsoft.VisualStudio.Component.Debugger.JustInTime",
+    "Component.Microsoft.VisualStudio.LiveShare",
+    "Microsoft.VisualStudio.Component.IntelliCode",
+    "Microsoft.VisualStudio.Component.VC.CoreIde",
+    "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
+    "Microsoft.VisualStudio.Component.Graphics.Tools",
+    "Microsoft.VisualStudio.Component.VC.DiagnosticTools",
+    "Microsoft.VisualStudio.Component.Windows10SDK.19041",
+    "Microsoft.VisualStudio.Component.VC.Redist.14.Latest",
+    "Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core",
+    "Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions.CMake",
+    "Microsoft.VisualStudio.Component.VC.CMake.Project",
+    "Microsoft.VisualStudio.Component.VC.ATL",
+    "Microsoft.VisualStudio.Component.VC.ASAN",
+    "Microsoft.VisualStudio.Workload.NativeDesktop",
+    "Microsoft.VisualStudio.Component.VSSDK",
+    "Microsoft.VisualStudio.ComponentGroup.VisualStudioExtension.Prerequisites",
+    "Microsoft.VisualStudio.Workload.VisualStudioExtension",
+    "Component.MDD.Linux",
+    "Component.Linux.CMake",
+    "Microsoft.VisualStudio.Workload.NativeCrossPlat"
+  ]
+}
\ No newline at end of file
diff --git a/vsconfig/2022.vsconfig b/vsconfig/2022.vsconfig
new file mode 100644
index 0000000..ed6e494
--- /dev/null
+++ b/vsconfig/2022.vsconfig
@@ -0,0 +1,42 @@
+{
+  "version": "1.0",
+  "components": [
+    "Microsoft.VisualStudio.Component.CoreEditor",
+    "Microsoft.VisualStudio.Workload.CoreEditor",
+    "Microsoft.Net.Component.4.8.SDK",
+    "Microsoft.Net.Component.4.7.2.TargetingPack",
+    "Microsoft.Net.ComponentGroup.DevelopmentPrerequisites",
+    "Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions",
+    "Microsoft.VisualStudio.Component.Roslyn.Compiler",
+    "Microsoft.Component.MSBuild",
+    "Microsoft.VisualStudio.Component.Roslyn.LanguageServices",
+    "Microsoft.VisualStudio.Component.TextTemplating",
+    "Microsoft.VisualStudio.Component.NuGet",
+    "Microsoft.NetCore.Component.Runtime.6.0",
+    "Microsoft.NetCore.Component.SDK",
+    "Microsoft.VisualStudio.Component.DiagnosticTools",
+    "Microsoft.VisualStudio.Component.Debugger.JustInTime",
+    "Microsoft.VisualStudio.Component.IntelliCode",
+    "Microsoft.VisualStudio.Component.VC.CoreIde",
+    "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
+    "Microsoft.VisualStudio.Component.Graphics.Tools",
+    "Microsoft.VisualStudio.Component.VC.DiagnosticTools",
+    "Microsoft.VisualStudio.Component.Windows10SDK.19041",
+    "Microsoft.VisualStudio.Component.VC.Redist.14.Latest",
+    "Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core",
+    "Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions.CMake",
+    "Microsoft.VisualStudio.Component.VC.CMake.Project",
+    "Microsoft.VisualStudio.Component.VC.ATL",
+    "Microsoft.VisualStudio.Component.VC.TestAdapterForBoostTest",
+    "Microsoft.VisualStudio.Component.VC.TestAdapterForGoogleTest",
+    "Microsoft.VisualStudio.Component.VC.ASAN",
+    "Microsoft.VisualStudio.Workload.NativeDesktop",
+    "Microsoft.Net.Component.4.6.TargetingPack",
+    "Microsoft.VisualStudio.Component.VSSDK",
+    "Microsoft.VisualStudio.ComponentGroup.VisualStudioExtension.Prerequisites",
+    "Microsoft.VisualStudio.Workload.VisualStudioExtension",
+    "Component.MDD.Linux",
+    "Component.Linux.CMake",
+    "Microsoft.VisualStudio.Workload.NativeCrossPlat"
+  ]
+}
\ No newline at end of file
diff --git a/vstools.bat b/vstools.bat
index ad05fd5..656576f 100644
--- a/vstools.bat
+++ b/vstools.bat
@@ -12,7 +12,9 @@
 SET VSWHERE=%VSWHERE_EXE%
 SET VSWHERE=%VSWHERE:(=^(%
 SET VSWHERE=%VSWHERE:)=^)%
-SET QUERY=-latest -prerelease
+SET QUERY_LATEST=-latest -prerelease
+SET QUERY_ALL=-prerelease
+SET QUERY=%QUERY_LATEST%
 SET VSWHERE_MAJOR=2
 SET VSWHERE_MINOR=7
 SET VSWHERE_PATCH=1
@@ -37,6 +39,7 @@
 SET DO_INSTALL=%FALSE%
 SET TRANSFORM_INCREMENTAL=true
 SET START_VS=%FALSE%
+SET LIST_VERSIONS=%FALSE%
 
 SET PLATFORM_VS2017="Any CPU"
 SET PLATFORM_VS2019="Any CPU"
@@ -101,6 +104,10 @@
         SET VS_LATEST=%VS2017%
         SET VS_VERSIONS_DEFAULT=%FALSE%
         SET FLAG_VS2017=
+    ) ELSE IF "%1"=="-list" (
+        SET LIST_VERSIONS=%TRUE%
+    ) ELSE IF "%1"=="-all" (
+        SET QUERY=%QUERY_ALL%
     ) ELSE IF "%1"=="-help" (
         GOTO :usage
     ) ELSE (
@@ -203,15 +210,28 @@
     IF %VERBOSE% ECHO ## catalog_productLineVersion: %%e
 
     IF %VERBOSE% ECHO ##   %VSWHERE% -path "%%p" -property displayName
-    FOR /F %ALL% %%n IN (`"%VSWHERE% -path "%%p" -property displayName"`) DO (
-    IF %VERBOSE% ECHO ## displayName: %%n
+    FOR /F %ALL% %%u IN (`"%VSWHERE% -path "%%p" -property displayName"`) DO (
+    IF %VERBOSE% ECHO ## displayName: %%u
+
+    IF %VERBOSE% ECHO ##   %VSWHERE% -path "%%p" -property isPrerelease
+    FOR /F %ALL% %%b IN (`"%VSWHERE% -path "%%p" -property isPrerelease"`) DO (
+    IF %VERBOSE% ECHO ## isPrerelease: %%b
+
+    FOR /F %ALL% %%n IN (`"(ECHO %%b | FINDSTR /C:1 > NUL) && (ECHO %%u PREVIEW) || ECHO %%u"`) DO (
+    IF %VERBOSE% ECHO ## friendlyName: %%n
 
     IF %VERBOSE% ECHO ##   %VSWHERE% -path "%%p" -property installationVersion
     FOR /F %ALL% %%i IN (`"%VSWHERE% -path "%%p" -property installationVersion"`) DO (
     IF %VERBOSE% ECHO ## installationVersion: %%i
 
     FOR /F %ALL% %%f IN (`CMD /C "ECHO %%PLATFORM_VS%%e%%"`) DO (
-        IF %VERBOSE% ECHO ## platform: %%f
+    IF %VERBOSE% ECHO ## platform: %%f
+
+    IF %LIST_VERSIONS% (
+        IF %VERBOSE% ECHO ## listVersion
+        ECHO %%n ^(%%i^)
+        ECHO ^[%%p^]
+    ) ELSE (
 
         IF "%%e"=="2022" (
             IF %VERBOSE% ECHO ## CALL "%%p\VC\Auxiliary\Build\vcvars64.bat"
@@ -368,9 +388,9 @@
             EXIT /B 0
         )
 
-        ECHO.
         )
-    ))))
+        ECHO.
+    )))))))
     ENDLOCAL
 )
 
@@ -397,6 +417,8 @@
 ECHO  -init .......... Initialize vstools solution for the specified version of VS
 ECHO                   If multiple versions are specified, the last one is selected
 ECHO  -startvs ....... Open vstools solution in selected VS version
+ECHO  -list .......... Print list of Visual Studio installations
+ECHO  -help .......... Print tool usage instructions
 ECHO.
 ECHO  If no operation is specified, -build is assumed by default.
 ECHO.
@@ -409,6 +431,9 @@
 ECHO  -install .................... Install extension to selected VS version(s)
 ECHO                                Only valid with -build or -rebuild
 ECHO  -startvs .................... Open vstools solution in selected VS version
+ECHO                                If multiple versions are specified, the last one is selected
+ECHO  -all ........................ Include all VS installations
+ECHO                                By default, the latest installation is selected
 ECHO  -verbose .................... Print more detailed log information
 ECHO  -bl ......................... Generate MSBuild binary log
 ECHO                                Only valid with -build or -rebuild
diff --git a/vstools.sln b/vstools.sln
index 8bbcdd4..b69cbcd 100644
--- a/vstools.sln
+++ b/vstools.sln
@@ -35,13 +35,19 @@
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QtTemplate.Item.QMLDir", "Templates\qmldir\QtTemplate.Item.QMLDir.csproj", "{7AF6C34B-65D2-4010-92F6-420E59DDE9BF}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QtTemplate.Item.QtClass", "Templates\qtclass\QtTemplate.Item.QtClass.csproj", "{4981AAE8-9AC7-4758-87EA-FB2397D6C404}"
+EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QtTemplate.Project.Quick", "Templates\quick\QtTemplate.Project.Quick.csproj", "{4833E4C7-FFFF-4DA5-A7A5-36C6C3840F16}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QtTemplate.Item.Resource", "Templates\resource\QtTemplate.Item.Resource.csproj", "{BDA1CD69-624B-4D9D-9B88-ACBEB14AC471}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QtTemplate.Project.Server", "Templates\server\QtTemplate.Project.Server.csproj", "{8AE9D385-A379-4F5F-A703-3DF643DA6742}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QtTemplate.Item.Translation", "Templates\translation\QtTemplate.Item.Translation.csproj", "{202F4A6D-77CD-4992-AA53-01B585463287}"
+EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QtTemplate.Item.Widget", "Templates\widget\QtTemplate.Item.Widget.csproj", "{40ADFD6A-64EA-4C77-9D4B-3A91D6AB76B4}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QtTemplate.Item.WidgetsClass", "Templates\widgetsclass\QtTemplate.Item.WidgetsClass.csproj", "{020422DA-33AB-4495-A439-7DAC2690795C}"
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Item", "Item", "{A7918293-56E9-465A-AE1C-0724576ADD66}"
 EndProject
@@ -92,6 +98,10 @@
 	EndProjectSection
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_QtMsBuild.Tasks", "Tests\Test_QtMsBuild.Tasks\Test_QtMsBuild.Tasks.csproj", "{E809DDE3-AE76-4F7A-8DC5-775AC4900138}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_QtVsTools.Core", "Tests\Test_QtVsTools.Core\Test_QtVsTools.Core.csproj", "{4B8FC08C-4901-45D4-BC00-C0C461292FF2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_QtVsTools.Package", "tests\Test_QtVsTools.Package\Test_QtVsTools.Package.csproj", "{AFD33401-2F15-4E72-AB35-42C3EE12E897}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -376,6 +386,24 @@
 		{7AF6C34B-65D2-4010-92F6-420E59DDE9BF}.Tests|x64.Build.0 = Release|Any CPU
 		{7AF6C34B-65D2-4010-92F6-420E59DDE9BF}.Tests|x86.ActiveCfg = Release|Any CPU
 		{7AF6C34B-65D2-4010-92F6-420E59DDE9BF}.Tests|x86.Build.0 = Release|Any CPU
+		{4981AAE8-9AC7-4758-87EA-FB2397D6C404}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4981AAE8-9AC7-4758-87EA-FB2397D6C404}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4981AAE8-9AC7-4758-87EA-FB2397D6C404}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{4981AAE8-9AC7-4758-87EA-FB2397D6C404}.Debug|x64.Build.0 = Debug|Any CPU
+		{4981AAE8-9AC7-4758-87EA-FB2397D6C404}.Debug|x86.ActiveCfg = Debug|x86
+		{4981AAE8-9AC7-4758-87EA-FB2397D6C404}.Debug|x86.Build.0 = Debug|x86
+		{4981AAE8-9AC7-4758-87EA-FB2397D6C404}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4981AAE8-9AC7-4758-87EA-FB2397D6C404}.Release|Any CPU.Build.0 = Release|Any CPU
+		{4981AAE8-9AC7-4758-87EA-FB2397D6C404}.Release|x64.ActiveCfg = Release|Any CPU
+		{4981AAE8-9AC7-4758-87EA-FB2397D6C404}.Release|x64.Build.0 = Release|Any CPU
+		{4981AAE8-9AC7-4758-87EA-FB2397D6C404}.Release|x86.ActiveCfg = Release|x86
+		{4981AAE8-9AC7-4758-87EA-FB2397D6C404}.Release|x86.Build.0 = Release|x86
+		{4981AAE8-9AC7-4758-87EA-FB2397D6C404}.Tests|Any CPU.ActiveCfg = Debug|Any CPU
+		{4981AAE8-9AC7-4758-87EA-FB2397D6C404}.Tests|Any CPU.Build.0 = Debug|Any CPU
+		{4981AAE8-9AC7-4758-87EA-FB2397D6C404}.Tests|x64.ActiveCfg = Debug|Any CPU
+		{4981AAE8-9AC7-4758-87EA-FB2397D6C404}.Tests|x64.Build.0 = Debug|Any CPU
+		{4981AAE8-9AC7-4758-87EA-FB2397D6C404}.Tests|x86.ActiveCfg = Debug|x86
+		{4981AAE8-9AC7-4758-87EA-FB2397D6C404}.Tests|x86.Build.0 = Debug|x86
 		{4833E4C7-FFFF-4DA5-A7A5-36C6C3840F16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{4833E4C7-FFFF-4DA5-A7A5-36C6C3840F16}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{4833E4C7-FFFF-4DA5-A7A5-36C6C3840F16}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -448,6 +476,24 @@
 		{40ADFD6A-64EA-4C77-9D4B-3A91D6AB76B4}.Tests|x64.Build.0 = Release|Any CPU
 		{40ADFD6A-64EA-4C77-9D4B-3A91D6AB76B4}.Tests|x86.ActiveCfg = Release|Any CPU
 		{40ADFD6A-64EA-4C77-9D4B-3A91D6AB76B4}.Tests|x86.Build.0 = Release|Any CPU
+		{020422DA-33AB-4495-A439-7DAC2690795C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{020422DA-33AB-4495-A439-7DAC2690795C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{020422DA-33AB-4495-A439-7DAC2690795C}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{020422DA-33AB-4495-A439-7DAC2690795C}.Debug|x64.Build.0 = Debug|Any CPU
+		{020422DA-33AB-4495-A439-7DAC2690795C}.Debug|x86.ActiveCfg = Debug|x86
+		{020422DA-33AB-4495-A439-7DAC2690795C}.Debug|x86.Build.0 = Debug|x86
+		{020422DA-33AB-4495-A439-7DAC2690795C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{020422DA-33AB-4495-A439-7DAC2690795C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{020422DA-33AB-4495-A439-7DAC2690795C}.Release|x64.ActiveCfg = Release|Any CPU
+		{020422DA-33AB-4495-A439-7DAC2690795C}.Release|x64.Build.0 = Release|Any CPU
+		{020422DA-33AB-4495-A439-7DAC2690795C}.Release|x86.ActiveCfg = Release|x86
+		{020422DA-33AB-4495-A439-7DAC2690795C}.Release|x86.Build.0 = Release|x86
+		{020422DA-33AB-4495-A439-7DAC2690795C}.Tests|Any CPU.ActiveCfg = Debug|Any CPU
+		{020422DA-33AB-4495-A439-7DAC2690795C}.Tests|Any CPU.Build.0 = Debug|Any CPU
+		{020422DA-33AB-4495-A439-7DAC2690795C}.Tests|x64.ActiveCfg = Debug|Any CPU
+		{020422DA-33AB-4495-A439-7DAC2690795C}.Tests|x64.Build.0 = Debug|Any CPU
+		{020422DA-33AB-4495-A439-7DAC2690795C}.Tests|x86.ActiveCfg = Debug|x86
+		{020422DA-33AB-4495-A439-7DAC2690795C}.Tests|x86.Build.0 = Debug|x86
 		{B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|Any CPU.ActiveCfg = Debug|Win32
 		{B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|Any CPU.Build.0 = Debug|Win32
 		{B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.ActiveCfg = Debug|x64
@@ -571,6 +617,54 @@
 		{E809DDE3-AE76-4F7A-8DC5-775AC4900138}.Tests|x64.Build.0 = Release|Any CPU
 		{E809DDE3-AE76-4F7A-8DC5-775AC4900138}.Tests|x86.ActiveCfg = Release|Any CPU
 		{E809DDE3-AE76-4F7A-8DC5-775AC4900138}.Tests|x86.Build.0 = Release|Any CPU
+		{202F4A6D-77CD-4992-AA53-01B585463287}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{202F4A6D-77CD-4992-AA53-01B585463287}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{202F4A6D-77CD-4992-AA53-01B585463287}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{202F4A6D-77CD-4992-AA53-01B585463287}.Debug|x64.Build.0 = Debug|Any CPU
+		{202F4A6D-77CD-4992-AA53-01B585463287}.Debug|x86.ActiveCfg = Debug|x86
+		{202F4A6D-77CD-4992-AA53-01B585463287}.Debug|x86.Build.0 = Debug|x86
+		{202F4A6D-77CD-4992-AA53-01B585463287}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{202F4A6D-77CD-4992-AA53-01B585463287}.Release|Any CPU.Build.0 = Release|Any CPU
+		{202F4A6D-77CD-4992-AA53-01B585463287}.Release|x64.ActiveCfg = Release|Any CPU
+		{202F4A6D-77CD-4992-AA53-01B585463287}.Release|x64.Build.0 = Release|Any CPU
+		{202F4A6D-77CD-4992-AA53-01B585463287}.Release|x86.ActiveCfg = Release|x86
+		{202F4A6D-77CD-4992-AA53-01B585463287}.Release|x86.Build.0 = Release|x86
+		{202F4A6D-77CD-4992-AA53-01B585463287}.Tests|Any CPU.ActiveCfg = Debug|Any CPU
+		{202F4A6D-77CD-4992-AA53-01B585463287}.Tests|Any CPU.Build.0 = Debug|Any CPU
+		{202F4A6D-77CD-4992-AA53-01B585463287}.Tests|x64.ActiveCfg = Debug|Any CPU
+		{202F4A6D-77CD-4992-AA53-01B585463287}.Tests|x64.Build.0 = Debug|Any CPU
+		{202F4A6D-77CD-4992-AA53-01B585463287}.Tests|x86.ActiveCfg = Debug|x86
+		{202F4A6D-77CD-4992-AA53-01B585463287}.Tests|x86.Build.0 = Debug|x86
+		{4B8FC08C-4901-45D4-BC00-C0C461292FF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4B8FC08C-4901-45D4-BC00-C0C461292FF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4B8FC08C-4901-45D4-BC00-C0C461292FF2}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{4B8FC08C-4901-45D4-BC00-C0C461292FF2}.Debug|x64.Build.0 = Debug|Any CPU
+		{4B8FC08C-4901-45D4-BC00-C0C461292FF2}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{4B8FC08C-4901-45D4-BC00-C0C461292FF2}.Debug|x86.Build.0 = Debug|Any CPU
+		{4B8FC08C-4901-45D4-BC00-C0C461292FF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4B8FC08C-4901-45D4-BC00-C0C461292FF2}.Release|x64.ActiveCfg = Release|Any CPU
+		{4B8FC08C-4901-45D4-BC00-C0C461292FF2}.Release|x86.ActiveCfg = Release|Any CPU
+		{4B8FC08C-4901-45D4-BC00-C0C461292FF2}.Tests|Any CPU.ActiveCfg = Debug|Any CPU
+		{4B8FC08C-4901-45D4-BC00-C0C461292FF2}.Tests|Any CPU.Build.0 = Debug|Any CPU
+		{4B8FC08C-4901-45D4-BC00-C0C461292FF2}.Tests|x64.ActiveCfg = Debug|Any CPU
+		{4B8FC08C-4901-45D4-BC00-C0C461292FF2}.Tests|x64.Build.0 = Debug|Any CPU
+		{4B8FC08C-4901-45D4-BC00-C0C461292FF2}.Tests|x86.ActiveCfg = Debug|Any CPU
+		{4B8FC08C-4901-45D4-BC00-C0C461292FF2}.Tests|x86.Build.0 = Debug|Any CPU
+		{AFD33401-2F15-4E72-AB35-42C3EE12E897}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AFD33401-2F15-4E72-AB35-42C3EE12E897}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AFD33401-2F15-4E72-AB35-42C3EE12E897}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{AFD33401-2F15-4E72-AB35-42C3EE12E897}.Debug|x64.Build.0 = Debug|Any CPU
+		{AFD33401-2F15-4E72-AB35-42C3EE12E897}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{AFD33401-2F15-4E72-AB35-42C3EE12E897}.Debug|x86.Build.0 = Debug|Any CPU
+		{AFD33401-2F15-4E72-AB35-42C3EE12E897}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AFD33401-2F15-4E72-AB35-42C3EE12E897}.Release|x64.ActiveCfg = Release|Any CPU
+		{AFD33401-2F15-4E72-AB35-42C3EE12E897}.Release|x86.ActiveCfg = Release|Any CPU
+		{AFD33401-2F15-4E72-AB35-42C3EE12E897}.Tests|Any CPU.ActiveCfg = Debug|Any CPU
+		{AFD33401-2F15-4E72-AB35-42C3EE12E897}.Tests|Any CPU.Build.0 = Debug|Any CPU
+		{AFD33401-2F15-4E72-AB35-42C3EE12E897}.Tests|x64.ActiveCfg = Debug|Any CPU
+		{AFD33401-2F15-4E72-AB35-42C3EE12E897}.Tests|x64.Build.0 = Debug|Any CPU
+		{AFD33401-2F15-4E72-AB35-42C3EE12E897}.Tests|x86.ActiveCfg = Debug|Any CPU
+		{AFD33401-2F15-4E72-AB35-42C3EE12E897}.Tests|x86.Build.0 = Debug|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -586,10 +680,12 @@
 		{20055427-1352-44FB-8442-BF7F15F9C59E} = {A7918293-56E9-465A-AE1C-0724576ADD66}
 		{DC1AE91B-45CE-4C5B-8F77-CDB58566038F} = {A7918293-56E9-465A-AE1C-0724576ADD66}
 		{7AF6C34B-65D2-4010-92F6-420E59DDE9BF} = {A7918293-56E9-465A-AE1C-0724576ADD66}
+		{4981AAE8-9AC7-4758-87EA-FB2397D6C404} = {A7918293-56E9-465A-AE1C-0724576ADD66}
 		{4833E4C7-FFFF-4DA5-A7A5-36C6C3840F16} = {DD307619-BF80-4E5D-AE54-196057187702}
 		{BDA1CD69-624B-4D9D-9B88-ACBEB14AC471} = {A7918293-56E9-465A-AE1C-0724576ADD66}
 		{8AE9D385-A379-4F5F-A703-3DF643DA6742} = {DD307619-BF80-4E5D-AE54-196057187702}
 		{40ADFD6A-64EA-4C77-9D4B-3A91D6AB76B4} = {A7918293-56E9-465A-AE1C-0724576ADD66}
+		{020422DA-33AB-4495-A439-7DAC2690795C} = {A7918293-56E9-465A-AE1C-0724576ADD66}
 		{A7918293-56E9-465A-AE1C-0724576ADD66} = {9D9290B2-9E87-46EA-84EA-02836F699BB8}
 		{DD307619-BF80-4E5D-AE54-196057187702} = {9D9290B2-9E87-46EA-84EA-02836F699BB8}
 		{B12702AD-ABFB-343A-A199-8E24837244A3} = {9B109DDA-0521-46AD-B087-B7CBCB33FEE5}
@@ -602,6 +698,9 @@
 		{A5320606-37B8-4F15-97E2-16314109CAF9} = {D6FB29A4-8921-46F5-B170-B15538AB4D69}
 		{12857847-9877-466C-B056-DD286A219093} = {D6FB29A4-8921-46F5-B170-B15538AB4D69}
 		{E809DDE3-AE76-4F7A-8DC5-775AC4900138} = {D6FB29A4-8921-46F5-B170-B15538AB4D69}
+		{202F4A6D-77CD-4992-AA53-01B585463287} = {A7918293-56E9-465A-AE1C-0724576ADD66}
+		{4B8FC08C-4901-45D4-BC00-C0C461292FF2} = {D6FB29A4-8921-46F5-B170-B15538AB4D69}
+		{AFD33401-2F15-4E72-AB35-42C3EE12E897} = {D6FB29A4-8921-46F5-B170-B15538AB4D69}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {17FF4AFE-273C-47CD-8D84-F0D023B10BE5}
diff --git "a/\320\241\320\261\320\276\321\200\320\272\320\260.md" "b/\320\241\320\261\320\276\321\200\320\272\320\260.md"
index dd25307..b3d918f 100644
--- "a/\320\241\320\261\320\276\321\200\320\272\320\260.md"
+++ "b/\320\241\320\261\320\276\321\200\320\272\320\260.md"
@@ -63,7 +63,7 @@
 `Сборка под VS2022:`
 Обязательно наличие VS 2022 
 
-Установить переменную среды QTBUILD_STATIC_VS2022  (Пример QTBUILD_STATIC_VS2022=C:\build\qt_5.12.9_msvc2022_x64) для VS 2012 только QT x64
+Установить переменную среды QTBUILD_STATIC_VS2022  (Пример QTBUILD_STATIC_VS2022=C:\build\qt_5.12.9_msvc2022_x64) для VS 2022 только QT x64
 
 В директории через cmd вызвать
 vstools -vs2022 -init -config Release или Debug -rebuild -deploy Path -startvs

--
Gitblit v1.9.1