From 46fd3ed1ce7b2264fcdef8199794828094dfcd88 Mon Sep 17 00:00:00 2001 From: David Machaj <46852402+dmachaj@users.noreply.github.com> Date: Fri, 25 Apr 2025 11:39:39 -0700 Subject: [PATCH 01/42] All cppwinrt vcxproj should build with /W4 and /WX (warnings turned up, treated as error). Fix existing violations. (#1487) Why is this change being made? The most recent PR introduced a warning for non-Clang consumers. Many projects build with warnings-as-errors so this is a build break for those projects. Because cppwinrt is widely used by many such projects it should itself build with warnings as errors enabled so that this doesn't happen again in the future. Plus it is general goodness to build with warnings cranked up and blocking. Briefly summarize what changed I added /WX to every single vcxproj in this repo (which required a whole lot of redundant edits). Many of them didn't have /W4 so I added it wherever it was missing. The project files definitely need some refactoring to reduce duplication. But for this change I decided to modify them as-is without also including a refactoring. I also fixed the newly-blocking warnings. MSVC only had the one new warning to fix. Clang had a whole bunch of previously-unknown warnings that needed to be fixed or suppressed to get the build passing again. I also removed a typo'd (warning is singular, not plural) that was trying to disable warnings in one specific project. It has no warnings so we might as well baseline them as blocking. I also added a new clang-only test file to try and exercise the LTO public visibility annotation. How was this change tested? It builds locally (x64 Debug+Release, MSVC + Clang). --- Directory.Build.Props | 1 + cppwinrt/component_writers.h | 2 +- cppwinrt/cppwinrt.vcxproj | 12 ++++++++++ natvis/cppwinrtvisualizer.vcxproj | 6 +++++ prebuild/prebuild.vcxproj | 12 ++++++++++ scratch/scratch.vcxproj | 2 ++ strings/base_activation.h | 3 +-- strings/base_fast_forward.h | 16 +++++++++++-- strings/base_macros.h | 6 ++++- strings/base_string.h | 4 ++-- .../ConsoleApplication1.vcxproj | 1 + test/nuget/TestApp/TestApp.vcxproj | 1 + .../nuget/TestProxyStub/TestProxyStub.vcxproj | 3 ++- .../TestRuntimeComponent1.vcxproj | 1 + .../TestRuntimeComponent2.vcxproj | 1 + .../TestRuntimeComponent3.vcxproj | 1 + .../TestRuntimeComponentCX.vcxproj | 12 ++++++++++ ...entCXReferencingWinRTStaticLibrary.vcxproj | 12 ++++++++++ .../TestRuntimeComponentEmpty.vcxproj | 1 + ...untimeComponentNamespaceUnderscore.vcxproj | 1 + .../TestStaticLibrary1.vcxproj | 6 +++++ .../TestStaticLibrary2.vcxproj | 6 +++++ .../TestStaticLibrary3.vcxproj | 6 +++++ .../TestStaticLibrary4.vcxproj | 12 ++++++++++ .../TestStaticLibrary5.vcxproj | 12 ++++++++++ .../TestStaticLibrary6.vcxproj | 12 ++++++++++ .../TestStaticLibrary7.vcxproj | 1 + test/old_tests/Component/Component.vcxproj | 12 ++++++++++ test/old_tests/Composable/Base.cpp | 2 +- test/old_tests/Composable/Composable.vcxproj | 12 ++++++++++ test/old_tests/UnitTests/Boxing2.cpp | 10 ++++---- test/old_tests/UnitTests/Composable.cpp | 2 +- .../IInspectable_GetRuntimeClassName.cpp | 7 ++++++ test/old_tests/UnitTests/Tests.vcxproj | 12 ++++++++++ test/old_tests/UnitTests/array.cpp | 2 +- test/old_tests/UnitTests/produce.cpp | 7 ++++++ test/old_tests/UnitTests/smart_pointers.cpp | 6 +++++ test/test/disconnected.cpp | 2 +- test/test/event_deferral.cpp | 14 +++++++---- test/test/inspectable_interop.cpp | 7 ++++++ test/test/multi_threaded_map.cpp | 2 +- test/test/out_params.cpp | 4 ++-- test/test/return_params_abi.cpp | 7 ++++++ test/test/struct_delegate.cpp | 2 +- test/test/test.vcxproj | 12 ++++++++++ test/test_component/Class.cpp | 7 ++++++ test/test_component/test_component.vcxproj | 12 ++++++++++ test/test_component_base/HierarchyA.cpp | 4 ++-- test/test_component_base/HierarchyB.cpp | 2 +- .../test_component_base.vcxproj | 12 ++++++++++ .../Nested.HierarchyD.cpp | 2 +- .../test_component_derived.vcxproj | 12 ++++++++++ .../test_component_fast.vcxproj | 12 ++++++++++ .../test_component_folders.vcxproj | 12 ++++++++++ .../test_component_no_pch.vcxproj | 12 ++++++++++ test/test_cpp20/array_span.cpp | 2 +- test/test_cpp20/clang_only.cpp | 23 +++++++++++++++++++ test/test_cpp20/test_cpp20.vcxproj | 19 +++++++++++++++ .../custom_error.cpp | 2 +- .../test_cpp20_no_sourcelocation.vcxproj | 2 ++ test/test_fast/Nomadic.cpp | 8 +++++++ test/test_fast/test_fast.vcxproj | 12 ++++++++++ test/test_fast_fwd/test_fast_fwd.vcxproj | 12 ++++++++++ .../test_module_lock_custom.vcxproj | 12 ++++++++++ test/test_module_lock_none/main.cpp | 7 ++++++ .../test_module_lock_none.vcxproj | 12 ++++++++++ test/test_slow/test_slow.vcxproj | 12 ++++++++++ .../ConsoleApplication.vcxproj | 1 + .../WindowsApplication.vcxproj | 1 + .../BlankApp/BlankApp.vcxproj | 1 + .../Windows Universal/CoreApp/CoreApp.vcxproj | 1 + .../StaticLibrary/StaticLibrary.vcxproj | 1 + .../WindowsRuntimeComponent.vcxproj | 1 + 73 files changed, 458 insertions(+), 33 deletions(-) create mode 100644 test/test_cpp20/clang_only.cpp diff --git a/Directory.Build.Props b/Directory.Build.Props index 0a8e5b37b..9088021c1 100644 --- a/Directory.Build.Props +++ b/Directory.Build.Props @@ -49,6 +49,7 @@ Level4 + true true true stdcpp17 diff --git a/cppwinrt/component_writers.h b/cppwinrt/component_writers.h index 6865d49ef..cb748917d 100644 --- a/cppwinrt/component_writers.h +++ b/cppwinrt/component_writers.h @@ -754,7 +754,7 @@ catch (...) { return winrt::to_hresult(); } using implements_type = typename %_base::implements_type; using implements_type::implements_type; %% - hstring GetRuntimeClassName() const + hstring GetRuntimeClassName() const override { return L"%.%"; } diff --git a/cppwinrt/cppwinrt.vcxproj b/cppwinrt/cppwinrt.vcxproj index 069f8103a..b8beed890 100644 --- a/cppwinrt/cppwinrt.vcxproj +++ b/cppwinrt/cppwinrt.vcxproj @@ -176,6 +176,8 @@ Disabled ..\inc;$(OutputPath);$(WinMDPackageDir); MultiThreadedDebug + Level4 + true Console @@ -193,6 +195,8 @@ Disabled ..\inc;$(OutputPath);$(WinMDPackageDir); MultiThreadedDebug + Level4 + true Console @@ -210,6 +214,8 @@ Disabled ..\inc;$(OutputPath);$(WinMDPackageDir); MultiThreadedDebug + Level4 + true Console @@ -230,6 +236,8 @@ ..\inc;$(OutputPath);$(WinMDPackageDir); MultiThreaded Guard + Level4 + true Console @@ -253,6 +261,8 @@ ..\inc;$(OutputPath);$(WinMDPackageDir); MultiThreaded Guard + Level4 + true Console @@ -276,6 +286,8 @@ ..\inc;$(OutputPath);$(WinMDPackageDir); MultiThreaded Guard + Level4 + true Console diff --git a/natvis/cppwinrtvisualizer.vcxproj b/natvis/cppwinrtvisualizer.vcxproj index cc17bf500..af3fbcf1f 100644 --- a/natvis/cppwinrtvisualizer.vcxproj +++ b/natvis/cppwinrtvisualizer.vcxproj @@ -103,6 +103,7 @@ Use Level4 + true Disabled VSDEBUGENG_USE_CPP11_SCOPED_ENUMS;WIN32;_DEBUG;VISUALIZER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) $(IntDir);..\cppwinrt;..\strings;$(DIASDKInc);%(AdditionalIncludeDirectories) @@ -127,6 +128,7 @@ Use Level4 + true Disabled VSDEBUGENG_USE_CPP11_SCOPED_ENUMS;_DEBUG;VISUALIZER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) $(IntDir);..\cppwinrt;..\strings;$(DIASDKInc);%(AdditionalIncludeDirectories) @@ -150,6 +152,7 @@ Use Level4 + true Disabled VSDEBUGENG_USE_CPP11_SCOPED_ENUMS;_DEBUG;VISUALIZER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) $(IntDir);..\cppwinrt;..\strings;$(DIASDKInc);%(AdditionalIncludeDirectories) @@ -173,6 +176,7 @@ Use Level4 + true MaxSpeed true true @@ -202,6 +206,7 @@ Use Level4 + true MaxSpeed true true @@ -231,6 +236,7 @@ Use Level4 + true MaxSpeed true true diff --git a/prebuild/prebuild.vcxproj b/prebuild/prebuild.vcxproj index 6e0bc4b71..9fad91fd8 100644 --- a/prebuild/prebuild.vcxproj +++ b/prebuild/prebuild.vcxproj @@ -88,6 +88,8 @@ Disabled ..\cppwinrt MultiThreadedDebug + Level4 + true Console @@ -98,6 +100,8 @@ Disabled ..\cppwinrt MultiThreadedDebug + Level4 + true Console @@ -108,6 +112,8 @@ Disabled ..\cppwinrt MultiThreadedDebug + Level4 + true Console @@ -121,6 +127,8 @@ ..\cppwinrt MultiThreaded Guard + Level4 + true Console @@ -136,6 +144,8 @@ ..\cppwinrt MultiThreaded Guard + Level4 + true Console @@ -151,6 +161,8 @@ ..\cppwinrt MultiThreaded Guard + Level4 + true Console diff --git a/scratch/scratch.vcxproj b/scratch/scratch.vcxproj index 98ed21948..84f6ce3d8 100644 --- a/scratch/scratch.vcxproj +++ b/scratch/scratch.vcxproj @@ -53,6 +53,8 @@ $(OutputPath);Generated Files; + Level4 + true Console diff --git a/strings/base_activation.h b/strings/base_activation.h index be24c6ad9..586df32e9 100644 --- a/strings/base_activation.h +++ b/strings/base_activation.h @@ -257,8 +257,7 @@ namespace winrt::impl } private: - - size_t& m_count; + [[maybe_unused]] size_t& m_count; // Field is unused when WINRT_NO_MODULE_LOCK is defined. }; struct factory_cache_entry_base diff --git a/strings/base_fast_forward.h b/strings/base_fast_forward.h index 7291ab2af..3ca34dba7 100644 --- a/strings/base_fast_forward.h +++ b/strings/base_fast_forward.h @@ -10,10 +10,14 @@ #define WINRT_IMPL_FF_NOVTABLE #endif -#if defined(__clang__) && __has_attribute(__lto_visibility_public__) +#if defined(__clang__) && defined(__has_attribute) +#if __has_attribute(__lto_visibility_public__) #define WINRT_IMPL_FF_PUBLIC __attribute__((lto_visibility_public)) #else #define WINRT_IMPL_FF_PUBLIC +#endif // __has_attribute(__lto_visibility_public__) +#else +#define WINRT_IMPL_FF_PUBLIC #endif #if !defined(WINRT_FAST_ABI_SIZE) @@ -59,7 +63,7 @@ namespace winrt::impl std::atomic m_references{ 1 }; fast_abi_forwarder(void* owner, guid const& iid, std::size_t offset) noexcept : - m_vfptr(s_vtable), m_owner(static_cast(owner)), m_iid(iid), m_offset(offset) + m_vfptr(s_vtable), m_owner(static_cast(owner)), m_offset(offset), m_iid(iid) { m_owner->AddRef(); } @@ -112,6 +116,11 @@ namespace winrt::impl return self->m_owner->GetTrustLevel(level); } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmicrosoft-cast" +#endif static inline void* const s_vtable[] = { QueryInterface, @@ -121,6 +130,9 @@ namespace winrt::impl GetRuntimeClassName, GetTrustLevel, % }; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif }; // Enforce assumptions made by thunk asm code diff --git a/strings/base_macros.h b/strings/base_macros.h index 42e958649..0c4357b1e 100644 --- a/strings/base_macros.h +++ b/strings/base_macros.h @@ -61,10 +61,14 @@ #define WINRT_IMPL_NOVTABLE #endif -#if defined(__clang__) && __has_attribute(__lto_visibility_public__) +#if defined(__clang__) && defined(__has_attribute) +#if __has_attribute(__lto_visibility_public__) #define WINRT_IMPL_PUBLIC __attribute__((lto_visibility_public)) #else #define WINRT_IMPL_PUBLIC +#endif // __has_attribute(__lto_visibility_public__) +#else +#define WINRT_IMPL_PUBLIC #endif #define WINRT_IMPL_ABI_DECL WINRT_IMPL_NOVTABLE WINRT_IMPL_PUBLIC diff --git a/strings/base_string.h b/strings/base_string.h index e70eed925..81229e3d5 100644 --- a/strings/base_string.h +++ b/strings/base_string.h @@ -574,8 +574,8 @@ namespace winrt::impl // when non-const (e.g. ranges::filter_view) so taking a const reference // as parameter wouldn't work for all scenarios. auto const size = std::formatted_size(args...); - WINRT_ASSERT(size < UINT_MAX); - auto const size32 = static_cast(size); + WINRT_ASSERT(size < INT_MAX); + auto const size32 = static_cast(size); hstring_builder builder(size32); WINRT_VERIFY_(size32, std::format_to_n(builder.data(), size32, args...).size); diff --git a/test/nuget/ConsoleApplication1/ConsoleApplication1.vcxproj b/test/nuget/ConsoleApplication1/ConsoleApplication1.vcxproj index 819c788d8..38f3ee4cc 100644 --- a/test/nuget/ConsoleApplication1/ConsoleApplication1.vcxproj +++ b/test/nuget/ConsoleApplication1/ConsoleApplication1.vcxproj @@ -70,6 +70,7 @@ $(IntDir)pch.pch _CONSOLE;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) Level4 + true %(AdditionalOptions) /permissive- /bigobj diff --git a/test/nuget/TestApp/TestApp.vcxproj b/test/nuget/TestApp/TestApp.vcxproj index 84029a4c9..f14bd9f0b 100644 --- a/test/nuget/TestApp/TestApp.vcxproj +++ b/test/nuget/TestApp/TestApp.vcxproj @@ -70,6 +70,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj diff --git a/test/nuget/TestProxyStub/TestProxyStub.vcxproj b/test/nuget/TestProxyStub/TestProxyStub.vcxproj index 899a5c11c..69e41cfba 100644 --- a/test/nuget/TestProxyStub/TestProxyStub.vcxproj +++ b/test/nuget/TestProxyStub/TestProxyStub.vcxproj @@ -35,7 +35,6 @@ 10.0.22621.0 10.0.18362.0 - false false @@ -55,6 +54,8 @@ Use pch.h %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) + Level4 + true Windows diff --git a/test/nuget/TestRuntimeComponent1/TestRuntimeComponent1.vcxproj b/test/nuget/TestRuntimeComponent1/TestRuntimeComponent1.vcxproj index 1b7621ea0..b1ee4f43f 100644 --- a/test/nuget/TestRuntimeComponent1/TestRuntimeComponent1.vcxproj +++ b/test/nuget/TestRuntimeComponent1/TestRuntimeComponent1.vcxproj @@ -74,6 +74,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj 28204 _WINRT_DLL;%(PreprocessorDefinitions) diff --git a/test/nuget/TestRuntimeComponent2/TestRuntimeComponent2.vcxproj b/test/nuget/TestRuntimeComponent2/TestRuntimeComponent2.vcxproj index 48f9acfb0..c27db2602 100644 --- a/test/nuget/TestRuntimeComponent2/TestRuntimeComponent2.vcxproj +++ b/test/nuget/TestRuntimeComponent2/TestRuntimeComponent2.vcxproj @@ -75,6 +75,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj 28204 _WINRT_DLL;%(PreprocessorDefinitions) diff --git a/test/nuget/TestRuntimeComponent3/TestRuntimeComponent3.vcxproj b/test/nuget/TestRuntimeComponent3/TestRuntimeComponent3.vcxproj index 8a876e601..01c84d830 100644 --- a/test/nuget/TestRuntimeComponent3/TestRuntimeComponent3.vcxproj +++ b/test/nuget/TestRuntimeComponent3/TestRuntimeComponent3.vcxproj @@ -75,6 +75,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj 28204 _WINRT_DLL;%(PreprocessorDefinitions) diff --git a/test/nuget/TestRuntimeComponentCX/TestRuntimeComponentCX.vcxproj b/test/nuget/TestRuntimeComponentCX/TestRuntimeComponentCX.vcxproj index 237b9fcf3..819cff52b 100644 --- a/test/nuget/TestRuntimeComponentCX/TestRuntimeComponentCX.vcxproj +++ b/test/nuget/TestRuntimeComponentCX/TestRuntimeComponentCX.vcxproj @@ -103,6 +103,8 @@ /bigobj /Zc:twoPhase- %(AdditionalOptions) 28204 true + Level4 + true Console @@ -119,6 +121,8 @@ /bigobj /Zc:twoPhase- %(AdditionalOptions) 28204 true + Level4 + true Console @@ -135,6 +139,8 @@ /bigobj /Zc:twoPhase- %(AdditionalOptions) 28204 true + Level4 + true Console @@ -151,6 +157,8 @@ /bigobj /Zc:twoPhase- %(AdditionalOptions) 28204 true + Level4 + true Console @@ -167,6 +175,8 @@ /bigobj /Zc:twoPhase- %(AdditionalOptions) 28204 true + Level4 + true Console @@ -183,6 +193,8 @@ /bigobj /Zc:twoPhase- %(AdditionalOptions) 28204 true + Level4 + true Console diff --git a/test/nuget/TestRuntimeComponentCXReferencingWinRTStaticLibrary/TestRuntimeComponentCXReferencingWinRTStaticLibrary.vcxproj b/test/nuget/TestRuntimeComponentCXReferencingWinRTStaticLibrary/TestRuntimeComponentCXReferencingWinRTStaticLibrary.vcxproj index 68b71c94e..6ce188345 100644 --- a/test/nuget/TestRuntimeComponentCXReferencingWinRTStaticLibrary/TestRuntimeComponentCXReferencingWinRTStaticLibrary.vcxproj +++ b/test/nuget/TestRuntimeComponentCXReferencingWinRTStaticLibrary/TestRuntimeComponentCXReferencingWinRTStaticLibrary.vcxproj @@ -117,6 +117,8 @@ $(IntDir)pch.pch $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) /bigobj /Zc:twoPhase- %(AdditionalOptions) + Level4 + true 28204 @@ -132,6 +134,8 @@ $(IntDir)pch.pch $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) /bigobj /Zc:twoPhase- %(AdditionalOptions) + Level4 + true 28204 @@ -147,6 +151,8 @@ $(IntDir)pch.pch $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) /bigobj /Zc:twoPhase- %(AdditionalOptions) + Level4 + true 28204 @@ -162,6 +168,8 @@ $(IntDir)pch.pch $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) /bigobj /Zc:twoPhase- %(AdditionalOptions) + Level4 + true 28204 @@ -177,6 +185,8 @@ $(IntDir)pch.pch $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) /bigobj /Zc:twoPhase- %(AdditionalOptions) + Level4 + true 28204 @@ -192,6 +202,8 @@ $(IntDir)pch.pch $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) /bigobj /Zc:twoPhase- %(AdditionalOptions) + Level4 + true 28204 diff --git a/test/nuget/TestRuntimeComponentEmpty/TestRuntimeComponentEmpty.vcxproj b/test/nuget/TestRuntimeComponentEmpty/TestRuntimeComponentEmpty.vcxproj index 7572238eb..60786eddb 100644 --- a/test/nuget/TestRuntimeComponentEmpty/TestRuntimeComponentEmpty.vcxproj +++ b/test/nuget/TestRuntimeComponentEmpty/TestRuntimeComponentEmpty.vcxproj @@ -75,6 +75,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj 28204 _WINRT_DLL;%(PreprocessorDefinitions) diff --git a/test/nuget/TestRuntimeComponentNamespaceUnderscore/TestRuntimeComponentNamespaceUnderscore.vcxproj b/test/nuget/TestRuntimeComponentNamespaceUnderscore/TestRuntimeComponentNamespaceUnderscore.vcxproj index 693a97596..fb8146340 100644 --- a/test/nuget/TestRuntimeComponentNamespaceUnderscore/TestRuntimeComponentNamespaceUnderscore.vcxproj +++ b/test/nuget/TestRuntimeComponentNamespaceUnderscore/TestRuntimeComponentNamespaceUnderscore.vcxproj @@ -75,6 +75,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj _WINRT_DLL;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) diff --git a/test/nuget/TestStaticLibrary1/TestStaticLibrary1.vcxproj b/test/nuget/TestStaticLibrary1/TestStaticLibrary1.vcxproj index a34e7429c..13ac4e201 100644 --- a/test/nuget/TestStaticLibrary1/TestStaticLibrary1.vcxproj +++ b/test/nuget/TestStaticLibrary1/TestStaticLibrary1.vcxproj @@ -81,6 +81,7 @@ Use Level4 + true Disabled true WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) @@ -98,6 +99,7 @@ Use Level4 + true Disabled true _DEBUG;_LIB;%(PreprocessorDefinitions) @@ -115,6 +117,7 @@ Use Level4 + true Disabled true _DEBUG;_LIB;%(PreprocessorDefinitions) @@ -132,6 +135,7 @@ Use Level4 + true MaxSpeed true true @@ -153,6 +157,7 @@ Use Level4 + true MaxSpeed true true @@ -174,6 +179,7 @@ Use Level4 + true MaxSpeed true true diff --git a/test/nuget/TestStaticLibrary2/TestStaticLibrary2.vcxproj b/test/nuget/TestStaticLibrary2/TestStaticLibrary2.vcxproj index 5f3ee5220..b419d183e 100644 --- a/test/nuget/TestStaticLibrary2/TestStaticLibrary2.vcxproj +++ b/test/nuget/TestStaticLibrary2/TestStaticLibrary2.vcxproj @@ -81,6 +81,7 @@ Use Level4 + true Disabled true WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) @@ -98,6 +99,7 @@ Use Level4 + true Disabled true _DEBUG;_LIB;%(PreprocessorDefinitions) @@ -115,6 +117,7 @@ Use Level4 + true Disabled true _DEBUG;_LIB;%(PreprocessorDefinitions) @@ -132,6 +135,7 @@ Use Level4 + true MaxSpeed true true @@ -153,6 +157,7 @@ Use Level4 + true MaxSpeed true true @@ -174,6 +179,7 @@ Use Level4 + true MaxSpeed true true diff --git a/test/nuget/TestStaticLibrary3/TestStaticLibrary3.vcxproj b/test/nuget/TestStaticLibrary3/TestStaticLibrary3.vcxproj index c79a847a3..210802841 100644 --- a/test/nuget/TestStaticLibrary3/TestStaticLibrary3.vcxproj +++ b/test/nuget/TestStaticLibrary3/TestStaticLibrary3.vcxproj @@ -81,6 +81,7 @@ Use Level4 + true Disabled true WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) @@ -98,6 +99,7 @@ Use Level4 + true Disabled true _DEBUG;_LIB;%(PreprocessorDefinitions) @@ -115,6 +117,7 @@ Use Level4 + true Disabled true _DEBUG;_LIB;%(PreprocessorDefinitions) @@ -132,6 +135,7 @@ Use Level4 + true MaxSpeed true true @@ -153,6 +157,7 @@ Use Level4 + true MaxSpeed true true @@ -174,6 +179,7 @@ Use Level4 + true MaxSpeed true true diff --git a/test/nuget/TestStaticLibrary4/TestStaticLibrary4.vcxproj b/test/nuget/TestStaticLibrary4/TestStaticLibrary4.vcxproj index b3efe02c4..357d0ca70 100644 --- a/test/nuget/TestStaticLibrary4/TestStaticLibrary4.vcxproj +++ b/test/nuget/TestStaticLibrary4/TestStaticLibrary4.vcxproj @@ -102,6 +102,8 @@ Use false true + Level4 + true Console @@ -114,6 +116,8 @@ Use false true + Level4 + true Console @@ -126,6 +130,8 @@ Use false true + Level4 + true Console @@ -138,6 +144,8 @@ Use false true + Level4 + true Console @@ -150,6 +158,8 @@ Use false true + Level4 + true Console @@ -162,6 +172,8 @@ Use false true + Level4 + true Console diff --git a/test/nuget/TestStaticLibrary5/TestStaticLibrary5.vcxproj b/test/nuget/TestStaticLibrary5/TestStaticLibrary5.vcxproj index bfc6db45c..d93446a05 100644 --- a/test/nuget/TestStaticLibrary5/TestStaticLibrary5.vcxproj +++ b/test/nuget/TestStaticLibrary5/TestStaticLibrary5.vcxproj @@ -102,6 +102,8 @@ Use false true + Level4 + true Console @@ -114,6 +116,8 @@ Use false true + Level4 + true Console @@ -126,6 +130,8 @@ Use false true + Level4 + true Console @@ -138,6 +144,8 @@ Use false true + Level4 + true Console @@ -150,6 +158,8 @@ Use false true + Level4 + true Console @@ -162,6 +172,8 @@ Use false true + Level4 + true Console diff --git a/test/nuget/TestStaticLibrary6/TestStaticLibrary6.vcxproj b/test/nuget/TestStaticLibrary6/TestStaticLibrary6.vcxproj index 89a0e55c9..626e60dab 100644 --- a/test/nuget/TestStaticLibrary6/TestStaticLibrary6.vcxproj +++ b/test/nuget/TestStaticLibrary6/TestStaticLibrary6.vcxproj @@ -102,6 +102,8 @@ Use false true + Level4 + true Console @@ -114,6 +116,8 @@ Use false true + Level4 + true Console @@ -126,6 +130,8 @@ Use false true + Level4 + true Console @@ -138,6 +144,8 @@ Use false true + Level4 + true Console @@ -150,6 +158,8 @@ Use false true + Level4 + true Console @@ -162,6 +172,8 @@ Use false true + Level4 + true Console diff --git a/test/nuget/TestStaticLibrary7/TestStaticLibrary7.vcxproj b/test/nuget/TestStaticLibrary7/TestStaticLibrary7.vcxproj index 0fdf11744..85d6bec7f 100644 --- a/test/nuget/TestStaticLibrary7/TestStaticLibrary7.vcxproj +++ b/test/nuget/TestStaticLibrary7/TestStaticLibrary7.vcxproj @@ -76,6 +76,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) diff --git a/test/old_tests/Component/Component.vcxproj b/test/old_tests/Component/Component.vcxproj index 6c7df9527..162c8fec7 100644 --- a/test/old_tests/Component/Component.vcxproj +++ b/test/old_tests/Component/Component.vcxproj @@ -140,6 +140,8 @@ false MultiThreadedDebug NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 @@ -174,6 +176,8 @@ false MultiThreadedDebug NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 @@ -209,6 +213,8 @@ $(ProjectDir);$(OutputPath);Generated Files;..\Composable\Generated Files MultiThreaded NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 @@ -242,6 +248,8 @@ $(ProjectDir);$(OutputPath);Generated Files;..\Composable\Generated Files MultiThreaded NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 @@ -278,6 +286,8 @@ false MultiThreadedDebug NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 @@ -311,6 +321,8 @@ $(ProjectDir);$(OutputPath);Generated Files;..\Composable\Generated Files MultiThreaded NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 diff --git a/test/old_tests/Composable/Base.cpp b/test/old_tests/Composable/Base.cpp index a1a1678ff..af2423569 100644 --- a/test/old_tests/Composable/Base.cpp +++ b/test/old_tests/Composable/Base.cpp @@ -43,7 +43,7 @@ namespace winrt::Composable::implementation int32_t Base::ProtectedMethod() { - return 0xDEADBEEF; + return static_cast(0xDEADBEEF); } hstring Base::Name() const diff --git a/test/old_tests/Composable/Composable.vcxproj b/test/old_tests/Composable/Composable.vcxproj index 4e49a255e..fcfd095fc 100644 --- a/test/old_tests/Composable/Composable.vcxproj +++ b/test/old_tests/Composable/Composable.vcxproj @@ -140,6 +140,8 @@ false MultiThreadedDebug NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 precomp.hpp @@ -174,6 +176,8 @@ false MultiThreadedDebug NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 precomp.hpp @@ -209,6 +213,8 @@ $(ProjectDir);$(OutDir);Generated Files MultiThreaded NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 precomp.hpp @@ -242,6 +248,8 @@ $(ProjectDir);$(OutDir);Generated Files MultiThreaded NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 precomp.hpp @@ -278,6 +286,8 @@ false MultiThreadedDebug NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 precomp.hpp @@ -311,6 +321,8 @@ $(ProjectDir);$(OutDir);Generated Files MultiThreaded NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 precomp.hpp diff --git a/test/old_tests/UnitTests/Boxing2.cpp b/test/old_tests/UnitTests/Boxing2.cpp index cd912ce58..43ca7efd9 100644 --- a/test/old_tests/UnitTests/Boxing2.cpp +++ b/test/old_tests/UnitTests/Boxing2.cpp @@ -41,19 +41,19 @@ namespace REQUIRE(unbox_value_or(wrong_type, v2) == v2); } - REQUIRE(object.as() == v1); - REQUIRE(object.try_as() == v1); - REQUIRE(nothing.try_as() == std::nullopt); + REQUIRE(object.template as() == v1); + REQUIRE(object.template try_as() == v1); + REQUIRE(nothing.template try_as() == std::nullopt); REQUIRE(wrong_type.try_as() == std::nullopt); T result{ v2 }; - object.as(result); + object.template as(result); REQUIRE(result == v1); result = v1; REQUIRE(v1 != empty()); // Test must pass a v1 that is not equal to the empty value. - REQUIRE(!nothing.try_as(result)); + REQUIRE(!nothing.template try_as(result)); REQUIRE(result == empty()); // try_as explicitly empties the result on failure result = v1; diff --git a/test/old_tests/UnitTests/Composable.cpp b/test/old_tests/UnitTests/Composable.cpp index 080e3769c..a9d354c08 100644 --- a/test/old_tests/UnitTests/Composable.cpp +++ b/test/old_tests/UnitTests/Composable.cpp @@ -14,7 +14,7 @@ namespace constexpr auto Base_OverridableMethod{ L"Base::OverridableMethod"sv }; constexpr auto Base_OverridableVirtualMethod{ L"Base::OverridableVirtualMethod"sv }; constexpr auto Base_OverridableNoexceptMethod{ 42 }; - constexpr auto Base_ProtectedMethod{ 0xDEADBEEF }; + constexpr auto Base_ProtectedMethod{ static_cast(0xDEADBEEF) }; constexpr auto Derived_VirtualMethod{ L"Derived::VirtualMethod"sv }; constexpr auto Derived_OverridableVirtualMethod{ L"Derived::OverridableVirtualMethod"sv }; diff --git a/test/old_tests/UnitTests/IInspectable_GetRuntimeClassName.cpp b/test/old_tests/UnitTests/IInspectable_GetRuntimeClassName.cpp index 7db7ed869..53b5260fb 100644 --- a/test/old_tests/UnitTests/IInspectable_GetRuntimeClassName.cpp +++ b/test/old_tests/UnitTests/IInspectable_GetRuntimeClassName.cpp @@ -18,10 +18,17 @@ struct Test_GetRuntimeClassName_NoOverride : implements { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Woverloaded-virtual" +#endif hstring GetRuntimeClassName() { return L"GetRuntimeClassName"; } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif }; TEST_CASE("Test_GetRuntimeClassName_NoOverride") diff --git a/test/old_tests/UnitTests/Tests.vcxproj b/test/old_tests/UnitTests/Tests.vcxproj index a0711f41d..c5169ad4d 100644 --- a/test/old_tests/UnitTests/Tests.vcxproj +++ b/test/old_tests/UnitTests/Tests.vcxproj @@ -206,6 +206,8 @@ false false MultiThreadedDebug + Level4 + true 4100;4297;4458 @@ -225,6 +227,8 @@ false false MultiThreadedDebug + Level4 + true 4100;4297;4458 @@ -244,6 +248,8 @@ false false MultiThreadedDebug + Level4 + true 4100;4297;4458 @@ -261,6 +267,8 @@ _HAS_AUTO_PTR_ETC;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) $(OutputPath);..\Composable\Generated Files;..\Component\Generated Files;..\Composable;..\Reflection\Generated Files;..\..\; MultiThreaded + Level4 + true 4100;4297;4458 @@ -280,6 +288,8 @@ _HAS_AUTO_PTR_ETC;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) $(OutputPath);..\Composable\Generated Files;..\Component\Generated Files;..\Composable;..\Reflection\Generated Files;..\..\; MultiThreaded + Level4 + true 4100;4297;4458 @@ -299,6 +309,8 @@ _HAS_AUTO_PTR_ETC;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) $(OutputPath);..\Composable\Generated Files;..\Component\Generated Files;..\Composable;..\Reflection\Generated Files;..\..\; MultiThreaded + Level4 + true 4100;4297;4458 diff --git a/test/old_tests/UnitTests/array.cpp b/test/old_tests/UnitTests/array.cpp index f6a7654f3..2b5952004 100644 --- a/test/old_tests/UnitTests/array.cpp +++ b/test/old_tests/UnitTests/array.cpp @@ -17,7 +17,7 @@ using namespace Windows::Security::Cryptography::Certificates; // // This is a helper to create a data reader for use in testing arrays. // -static IAsyncOperation CreateDataReader(std::initializer_list values) +static IAsyncOperation CreateDataReader(std::initializer_list /*values*/) { InMemoryRandomAccessStream stream; DataWriter writer(stream); diff --git a/test/old_tests/UnitTests/produce.cpp b/test/old_tests/UnitTests/produce.cpp index 149466002..9ac76ad18 100644 --- a/test/old_tests/UnitTests/produce.cpp +++ b/test/old_tests/UnitTests/produce.cpp @@ -124,10 +124,17 @@ struct produce_IInspectable_No_RuntimeClassName : implements { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Woverloaded-virtual" +#endif hstring GetRuntimeClassName() { return L"produce_IInspectable_RuntimeClassName"; } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif }; TEST_CASE("produce_IInspectable_RuntimeClassName") diff --git a/test/old_tests/UnitTests/smart_pointers.cpp b/test/old_tests/UnitTests/smart_pointers.cpp index fc760fb48..92dca1396 100644 --- a/test/old_tests/UnitTests/smart_pointers.cpp +++ b/test/old_tests/UnitTests/smart_pointers.cpp @@ -7,6 +7,12 @@ using namespace Windows::Foundation; using namespace Windows::Foundation::Collections; using namespace Component; + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wself-assign-overloaded" +#pragma clang diagnostic ignored "-Wself-move" +#endif + namespace { struct Type : implements diff --git a/test/test/disconnected.cpp b/test/test/disconnected.cpp index 53dfbd142..be356fcb3 100644 --- a/test/test/disconnected.cpp +++ b/test/test/disconnected.cpp @@ -148,7 +148,7 @@ struct non_agile_abandoned_action : implements disconnect) : m_disconnect(disconnect) {} - static fire_and_forget final_release(std::unique_ptr self) + static fire_and_forget final_release(std::unique_ptr /*self*/) { // The C++/WinRT m_handler is agile but not context-aware, // so we need to make sure to release it from the context it diff --git a/test/test/event_deferral.cpp b/test/test/event_deferral.cpp index 9b83a2602..e5b538ca2 100644 --- a/test/test/event_deferral.cpp +++ b/test/test/event_deferral.cpp @@ -38,7 +38,7 @@ namespace // This exercises the short-circuit logic in deferrable_event_args. auto NoDeferralHandler() { - return [=](Class const& sender, DeferrableEventArgs const& args) + return [this](Class const& sender, DeferrableEventArgs const& args) { REQUIRE(sender == c); args.IncrementCounter(); @@ -50,7 +50,7 @@ namespace // deferrable_event_args. auto PointlessDeferralHandler() { - return [=](Class const& sender, DeferrableEventArgs const& args) + return [this](Class const& sender, DeferrableEventArgs const& args) { REQUIRE(sender == c); auto deferral = args.GetDeferral(); @@ -61,15 +61,19 @@ namespace auto TakeDeferralHandler(int startState, int finishState) { - return [=](Class sender, DeferrableEventArgs args) -> fire_and_forget + return [this, startState, finishState](Class sender, DeferrableEventArgs args) -> fire_and_forget { + // Captures will go out of scope after the first co_await call. Copy anything needed after that point. + const auto startStateCopy = startState; + const auto finishStateCopy = finishState; + REQUIRE(sender == c); auto deferral = args.GetDeferral(); co_await resume_background(); - wait_for_state(startState); + wait_for_state(startStateCopy); args.IncrementCounter(); deferral.Complete(); - go_to_state(finishState); + go_to_state(finishStateCopy); }; } }; diff --git a/test/test/inspectable_interop.cpp b/test/test/inspectable_interop.cpp index e9094ca77..6a8db907a 100644 --- a/test/test/inspectable_interop.cpp +++ b/test/test/inspectable_interop.cpp @@ -41,11 +41,18 @@ namespace #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Woverloaded-virtual" +#endif +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Woverloaded-virtual" #endif Windows::Foundation::TrustLevel GetTrustLevel() const noexcept { return Windows::Foundation::TrustLevel::PartialTrust; } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif #ifdef __GNUC__ #pragma GCC diagnostic pop #endif diff --git a/test/test/multi_threaded_map.cpp b/test/test/multi_threaded_map.cpp index b2b143f11..d0f68c1e2 100644 --- a/test/test/multi_threaded_map.cpp +++ b/test/test/multi_threaded_map.cpp @@ -90,7 +90,7 @@ namespace using const_reverse_iterator = std::reverse_iterator; using node_type = typename inner::node_type; - mapped_type& operator[](const key_type& key) + mapped_type& operator[](const key_type& /*key*/) { auto guard = concurrency_guard::lock_nonconst(); concurrency_guard::call_hook(collection_action::at); diff --git a/test/test/out_params.cpp b/test/test/out_params.cpp index 7aafb63ae..7fd2f536e 100644 --- a/test/test/out_params.cpp +++ b/test/test/out_params.cpp @@ -134,7 +134,7 @@ TEST_CASE("out_params") REQUIRE(value[3] == nullptr); } { - std::array value{ {L"First", L"Second"} }; + std::array value{ { { L"First" }, { L"Second"} } }; object.RefStructArray(value); REQUIRE(value[0].First == L"1"); REQUIRE(value[0].Second == L"2"); @@ -260,7 +260,7 @@ TEST_CASE("out_params") REQUIRE(value[3] == nullptr); } { - std::array value{ {L"First", L"Second"} }; + std::array value{ { { L"First" }, { L"Second"} } }; REQUIRE_THROWS_AS(object.RefStructArray(value), hresult_invalid_argument); REQUIRE(value[0].First == L""); REQUIRE(value[0].Second == L""); diff --git a/test/test/return_params_abi.cpp b/test/test/return_params_abi.cpp index 1d4af9a9f..5e7c11cd3 100644 --- a/test/test/return_params_abi.cpp +++ b/test/test/return_params_abi.cpp @@ -12,12 +12,19 @@ using namespace winrt; namespace { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif hstring to_hstring(::IInspectable* raw) { winrt::IInspectable object; copy_from_abi(object, raw); return object.as().ToString(); } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif } TEST_CASE("return_params_abi") diff --git a/test/test/struct_delegate.cpp b/test/test/struct_delegate.cpp index 26fcd9e64..785a0fb0a 100644 --- a/test/test/struct_delegate.cpp +++ b/test/test/struct_delegate.cpp @@ -1,5 +1,5 @@ #include "pch.h" -#include "winrt/test_component.delegates.h" +#include "winrt/test_component.Delegates.h" using namespace winrt; using namespace test_component; diff --git a/test/test/test.vcxproj b/test/test/test.vcxproj index f1035ab6c..7840f17eb 100644 --- a/test/test/test.vcxproj +++ b/test/test/test.vcxproj @@ -92,6 +92,8 @@ $(OutputPath);Generated Files;..;..\..\cppwinrt _MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console @@ -112,6 +114,8 @@ $(OutputPath);Generated Files;..;..\..\cppwinrt _MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -130,6 +134,8 @@ $(OutputPath);Generated Files;..;..\..\cppwinrt _MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -148,6 +154,8 @@ $(OutputPath);Generated Files;..;..\..\cppwinrt _MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -168,6 +176,8 @@ $(OutputPath);Generated Files;..;..\..\cppwinrt _MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console @@ -190,6 +200,8 @@ $(OutputPath);Generated Files;..;..\..\cppwinrt _MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console diff --git a/test/test_component/Class.cpp b/test/test_component/Class.cpp index 4f36df5c1..3f68d96c3 100644 --- a/test/test_component/Class.cpp +++ b/test/test_component/Class.cpp @@ -519,7 +519,14 @@ namespace winrt::test_component::implementation namespace { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif void ValidateStaticEventAutoRevoke() { auto x = winrt::test_component::Simple::StaticEvent(winrt::auto_revoke, [](auto&&, auto&&) {}); } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif } \ No newline at end of file diff --git a/test/test_component/test_component.vcxproj b/test/test_component/test_component.vcxproj index 9751fb5a2..3ffdb8f97 100644 --- a/test/test_component/test_component.vcxproj +++ b/test/test_component/test_component.vcxproj @@ -114,6 +114,8 @@ .;$(OutputPath);Generated Files /Zc:threadSafeInit- /we4640 %(AdditionalOptions) MultiThreadedDebug + Level4 + true exports.def @@ -150,6 +152,8 @@ .;$(OutputPath);Generated Files /Zc:threadSafeInit- /we4640 %(AdditionalOptions) MultiThreadedDebug + Level4 + true exports.def @@ -199,6 +203,8 @@ .;$(OutputPath);Generated Files /Zc:threadSafeInit- /we4640 %(AdditionalOptions) MultiThreadedDebug + Level4 + true exports.def @@ -237,6 +243,8 @@ .;$(OutputPath);Generated Files /Zc:threadSafeInit- /we4640 %(AdditionalOptions) MultiThreaded + Level4 + true true @@ -277,6 +285,8 @@ .;$(OutputPath);Generated Files /Zc:threadSafeInit- /we4640 %(AdditionalOptions) MultiThreaded + Level4 + true true @@ -330,6 +340,8 @@ .;$(OutputPath);Generated Files /Zc:threadSafeInit- /we4640 %(AdditionalOptions) MultiThreaded + Level4 + true true diff --git a/test/test_component_base/HierarchyA.cpp b/test/test_component_base/HierarchyA.cpp index 887b31bc9..45b3e6098 100644 --- a/test/test_component_base/HierarchyA.cpp +++ b/test/test_component_base/HierarchyA.cpp @@ -3,11 +3,11 @@ namespace winrt::test_component_base::implementation { - HierarchyA::HierarchyA(hstring const& name) + HierarchyA::HierarchyA(hstring const& /*name*/) { throw hresult_not_implemented(); } - HierarchyA::HierarchyA(int32_t dummy, hstring const& name) + HierarchyA::HierarchyA(int32_t /*dummy*/, hstring const& /*name*/) { throw hresult_not_implemented(); } diff --git a/test/test_component_base/HierarchyB.cpp b/test/test_component_base/HierarchyB.cpp index 30b9f09ff..b56988f73 100644 --- a/test/test_component_base/HierarchyB.cpp +++ b/test/test_component_base/HierarchyB.cpp @@ -5,7 +5,7 @@ namespace winrt::test_component_base::implementation { - HierarchyB::HierarchyB(hstring const& name) + HierarchyB::HierarchyB(hstring const& /*name*/) { throw hresult_not_implemented(); } diff --git a/test/test_component_base/test_component_base.vcxproj b/test/test_component_base/test_component_base.vcxproj index 947c53e8f..90577a2c5 100644 --- a/test/test_component_base/test_component_base.vcxproj +++ b/test/test_component_base/test_component_base.vcxproj @@ -114,6 +114,8 @@ $(ProjectDir);$(OutputPath);Generated Files 4100 MultiThreadedDebug + Level4 + true exports.def @@ -162,6 +164,8 @@ $(ProjectDir);$(OutputPath);Generated Files 4100 MultiThreadedDebug + Level4 + true exports.def @@ -224,6 +228,8 @@ $(ProjectDir);$(OutputPath);Generated Files 4100 MultiThreadedDebug + Level4 + true exports.def @@ -274,6 +280,8 @@ $(ProjectDir);$(OutputPath);Generated Files 4100 MultiThreaded + Level4 + true true @@ -326,6 +334,8 @@ $(ProjectDir);$(OutputPath);Generated Files 4100 MultiThreaded + Level4 + true true @@ -392,6 +402,8 @@ $(ProjectDir);$(OutputPath);Generated Files 4100 MultiThreaded + Level4 + true true diff --git a/test/test_component_derived/Nested.HierarchyD.cpp b/test/test_component_derived/Nested.HierarchyD.cpp index bad2cf1ce..8011e73e6 100644 --- a/test/test_component_derived/Nested.HierarchyD.cpp +++ b/test/test_component_derived/Nested.HierarchyD.cpp @@ -3,7 +3,7 @@ namespace winrt::test_component_derived::Nested::implementation { - HierarchyD::HierarchyD(hstring const& name) + HierarchyD::HierarchyD(hstring const& /*name*/) { throw hresult_not_implemented(); } diff --git a/test/test_component_derived/test_component_derived.vcxproj b/test/test_component_derived/test_component_derived.vcxproj index a1c856c90..837d8821e 100644 --- a/test/test_component_derived/test_component_derived.vcxproj +++ b/test/test_component_derived/test_component_derived.vcxproj @@ -112,6 +112,8 @@ Disabled $(ProjectDir);$(OutputPath);Generated Files;..\test_component_base\Generated Files + Level4 + true 4100 MultiThreadedDebug @@ -161,6 +163,8 @@ Disabled $(ProjectDir);$(OutputPath);Generated Files;..\test_component_base\Generated Files + Level4 + true 4100 MultiThreadedDebug @@ -224,6 +228,8 @@ Disabled $(ProjectDir);$(OutputPath);Generated Files;..\test_component_base\Generated Files + Level4 + true 4100 MultiThreadedDebug @@ -275,6 +281,8 @@ true true $(ProjectDir);$(OutputPath);Generated Files;..\test_component_base\Generated Files + Level4 + true 4100 MultiThreaded @@ -328,6 +336,8 @@ true true $(ProjectDir);$(OutputPath);Generated Files;..\test_component_base\Generated Files + Level4 + true 4100 MultiThreaded @@ -395,6 +405,8 @@ true true $(ProjectDir);$(OutputPath);Generated Files;..\test_component_base\Generated Files + Level4 + true 4100 MultiThreaded diff --git a/test/test_component_fast/test_component_fast.vcxproj b/test/test_component_fast/test_component_fast.vcxproj index 5d646cf78..ed5a36222 100644 --- a/test/test_component_fast/test_component_fast.vcxproj +++ b/test/test_component_fast/test_component_fast.vcxproj @@ -114,6 +114,8 @@ Disabled $(ProjectDir);$(OutputPath);Generated Files /DWINRT_FAST_ABI_SIZE=50 %(AdditionalOptions) + Level4 + true 4100 MultiThreadedDebug @@ -163,6 +165,8 @@ Disabled $(ProjectDir);$(OutputPath);Generated Files /DWINRT_FAST_ABI_SIZE=50 %(AdditionalOptions) + Level4 + true 4100 MultiThreadedDebug @@ -226,6 +230,8 @@ Disabled $(ProjectDir);$(OutputPath);Generated Files /DWINRT_FAST_ABI_SIZE=50 %(AdditionalOptions) + Level4 + true 4100 MultiThreadedDebug @@ -277,6 +283,8 @@ true $(ProjectDir);$(OutputPath);Generated Files /DWINRT_FAST_ABI_SIZE=50 %(AdditionalOptions) + Level4 + true 4100 MultiThreaded @@ -330,6 +338,8 @@ true $(ProjectDir);$(OutputPath);Generated Files /DWINRT_FAST_ABI_SIZE=50 %(AdditionalOptions) + Level4 + true 4100 MultiThreaded @@ -397,6 +407,8 @@ true $(ProjectDir);$(OutputPath);Generated Files /DWINRT_FAST_ABI_SIZE=50 %(AdditionalOptions) + Level4 + true 4100 MultiThreaded diff --git a/test/test_component_folders/test_component_folders.vcxproj b/test/test_component_folders/test_component_folders.vcxproj index 6d642096f..14c12f8f9 100644 --- a/test/test_component_folders/test_component_folders.vcxproj +++ b/test/test_component_folders/test_component_folders.vcxproj @@ -112,6 +112,8 @@ Disabled $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 MultiThreadedDebug @@ -160,6 +162,8 @@ Disabled $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 MultiThreadedDebug @@ -222,6 +226,8 @@ Disabled $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 MultiThreadedDebug @@ -272,6 +278,8 @@ true true $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 MultiThreaded @@ -324,6 +332,8 @@ true true $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 MultiThreaded @@ -390,6 +400,8 @@ true true $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 MultiThreaded diff --git a/test/test_component_no_pch/test_component_no_pch.vcxproj b/test/test_component_no_pch/test_component_no_pch.vcxproj index 0b1a98271..117be2d00 100644 --- a/test/test_component_no_pch/test_component_no_pch.vcxproj +++ b/test/test_component_no_pch/test_component_no_pch.vcxproj @@ -112,6 +112,8 @@ Disabled $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 NotUsing MultiThreadedDebug @@ -161,6 +163,8 @@ Disabled $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 NotUsing MultiThreadedDebug @@ -224,6 +228,8 @@ Disabled $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 NotUsing MultiThreadedDebug @@ -275,6 +281,8 @@ true true $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 NotUsing MultiThreaded @@ -328,6 +336,8 @@ true true $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 NotUsing MultiThreaded @@ -395,6 +405,8 @@ true true $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 NotUsing MultiThreaded diff --git a/test/test_cpp20/array_span.cpp b/test/test_cpp20/array_span.cpp index dff5a2ec5..8cebc4a1e 100644 --- a/test/test_cpp20/array_span.cpp +++ b/test/test_cpp20/array_span.cpp @@ -10,7 +10,7 @@ using namespace Windows::Data::Json; // // This is a helper to create a data reader for use in testing arrays. // -static IAsyncOperation CreateDataReader(std::initializer_list values) +static IAsyncOperation CreateDataReader(std::initializer_list /*values*/) { InMemoryRandomAccessStream stream; DataWriter writer(stream); diff --git a/test/test_cpp20/clang_only.cpp b/test/test_cpp20/clang_only.cpp new file mode 100644 index 000000000..45aa4b380 --- /dev/null +++ b/test/test_cpp20/clang_only.cpp @@ -0,0 +1,23 @@ +#include "pch.h" +#include + +#ifdef __clang__ + +using namespace winrt; +using namespace Windows::Foundation; +using namespace Windows::Storage::Pickers; + +TEST_CASE("clang_lto_visibility") +{ + // A previous bug report (https://github.com/microsoft/cppwinrt/pull/1482) represented a problem when some linker + // options (-O3 -flto -fwhole-program-vtables) were used with cppwinrt generated code. The lack of public annotation + // caused methods to be removed from the binary, leading to a crash. This test case aims to be a regression test for + // that problem. + FileOpenPicker picker{}; + picker.ViewMode(PickerViewMode::Thumbnail); + picker.FileTypeFilter().Append(L".png"); // This line would trigger the crash. + + REQUIRE(true); +} + +#endif // __clang__ \ No newline at end of file diff --git a/test/test_cpp20/test_cpp20.vcxproj b/test/test_cpp20/test_cpp20.vcxproj index 832297f7f..4eaee0a18 100644 --- a/test/test_cpp20/test_cpp20.vcxproj +++ b/test/test_cpp20/test_cpp20.vcxproj @@ -93,6 +93,9 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true + %(AdditionalOptions) -O3 -flto -fwhole-program-vtables Console @@ -114,6 +117,9 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true + %(AdditionalOptions) -flto -fwhole-program-vtables Console @@ -133,6 +139,9 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true + %(AdditionalOptions) -flto -fwhole-program-vtables Console @@ -152,6 +161,9 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true + %(AdditionalOptions) -flto -fwhole-program-vtables Console @@ -173,6 +185,9 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true + %(AdditionalOptions) -O3 -flto -fwhole-program-vtables Console @@ -196,6 +211,9 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true + %(AdditionalOptions) -O3 -flto -fwhole-program-vtables Console @@ -217,6 +235,7 @@ + diff --git a/test/test_cpp20_no_sourcelocation/custom_error.cpp b/test/test_cpp20_no_sourcelocation/custom_error.cpp index 43e5f16d9..d9905ea04 100644 --- a/test/test_cpp20_no_sourcelocation/custom_error.cpp +++ b/test/test_cpp20_no_sourcelocation/custom_error.cpp @@ -53,7 +53,7 @@ TEST_CASE("custom_error_logger") REQUIRE(s_loggerArgs.functionName == nullptr); REQUIRE(s_loggerArgs.returnAddress); - REQUIRE(s_loggerArgs.result == 0x80000018); // E_ILLEGAL_DELEGATE_ASSIGNMENT) + REQUIRE(s_loggerArgs.result == static_cast(0x80000018)); // E_ILLEGAL_DELEGATE_ASSIGNMENT) // Remove global handler winrt_throw_hresult_handler = nullptr; diff --git a/test/test_cpp20_no_sourcelocation/test_cpp20_no_sourcelocation.vcxproj b/test/test_cpp20_no_sourcelocation/test_cpp20_no_sourcelocation.vcxproj index 86a56a3b9..85c3e1532 100644 --- a/test/test_cpp20_no_sourcelocation/test_cpp20_no_sourcelocation.vcxproj +++ b/test/test_cpp20_no_sourcelocation/test_cpp20_no_sourcelocation.vcxproj @@ -89,6 +89,8 @@ WINRT_NO_SOURCE_LOCATION;%(PreprocessorDefinitions) + Level4 + true diff --git a/test/test_fast/Nomadic.cpp b/test/test_fast/Nomadic.cpp index 98753c06d..c29150e17 100644 --- a/test/test_fast/Nomadic.cpp +++ b/test/test_fast/Nomadic.cpp @@ -11,7 +11,15 @@ hstring invoke_by_interface_vtable_offset(Nomadic const& nomadic, ptrdiff_t offs // that IInspectable has 6 functions in total (including those inherited from IUnknown) auto insp = static_cast<::IInspectable*>(get_abi(nomadic)); auto vtable = *reinterpret_cast(insp); + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmicrosoft-cast" +#endif auto fn_ptr = static_cast(vtable[6 + offset]); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif HSTRING hstr; check_hresult(fn_ptr(insp, &hstr)); diff --git a/test/test_fast/test_fast.vcxproj b/test/test_fast/test_fast.vcxproj index 27a7ea350..c01907348 100644 --- a/test/test_fast/test_fast.vcxproj +++ b/test/test_fast/test_fast.vcxproj @@ -92,6 +92,8 @@ $(OutputPath);Generated Files;..\; WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console @@ -113,6 +115,8 @@ $(OutputPath);Generated Files;..\; WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -132,6 +136,8 @@ $(OutputPath);Generated Files;..\; WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -151,6 +157,8 @@ $(OutputPath);Generated Files;..\; WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -172,6 +180,8 @@ $(OutputPath);Generated Files;..\; WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console @@ -195,6 +205,8 @@ $(OutputPath);Generated Files;..\; WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console diff --git a/test/test_fast_fwd/test_fast_fwd.vcxproj b/test/test_fast_fwd/test_fast_fwd.vcxproj index d4b63c3fb..6d049b1a9 100644 --- a/test/test_fast_fwd/test_fast_fwd.vcxproj +++ b/test/test_fast_fwd/test_fast_fwd.vcxproj @@ -59,6 +59,8 @@ true $(CppWinRTDir);$(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) + Level4 + true Console @@ -86,6 +88,8 @@ pch.h true WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) + Level4 + true Console @@ -106,6 +110,8 @@ Disabled $(CppWinRTDir);$(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) + Level4 + true Console @@ -123,6 +129,8 @@ Disabled $(CppWinRTDir);$(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) + Level4 + true Console @@ -146,6 +154,8 @@ pch.h true WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) + Level4 + true Console @@ -166,6 +176,8 @@ true $(CppWinRTDir);$(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) + Level4 + true Console diff --git a/test/test_module_lock_custom/test_module_lock_custom.vcxproj b/test/test_module_lock_custom/test_module_lock_custom.vcxproj index 6671a1156..64da0d8bc 100644 --- a/test/test_module_lock_custom/test_module_lock_custom.vcxproj +++ b/test/test_module_lock_custom/test_module_lock_custom.vcxproj @@ -92,6 +92,8 @@ $(OutputPath);Generated Files;..\; NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console @@ -113,6 +115,8 @@ $(OutputPath);Generated Files;..\; NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -132,6 +136,8 @@ $(OutputPath);Generated Files;..\; NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -151,6 +157,8 @@ $(OutputPath);Generated Files;..\; NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -172,6 +180,8 @@ $(OutputPath);Generated Files;..\; NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console @@ -195,6 +205,8 @@ $(OutputPath);Generated Files;..\; NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console diff --git a/test/test_module_lock_none/main.cpp b/test/test_module_lock_none/main.cpp index ca8eab7ac..9648ad8be 100644 --- a/test/test_module_lock_none/main.cpp +++ b/test/test_module_lock_none/main.cpp @@ -57,11 +57,18 @@ TEST_CASE("module_lock_none") // Validates that test_component_base is pinned by virtue of it defining WINRT_NO_MODULE_LOCK. +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-mismatch" +#endif auto can_unload = reinterpret_cast(GetProcAddress(LoadLibraryA("test_component_base.dll"), "DllCanUnloadNow")); REQUIRE(can_unload() == S_FALSE); auto cannot_unload = reinterpret_cast(GetProcAddress(LoadLibraryA("test_component_derived.dll"), "DllCanUnloadNow")); REQUIRE(cannot_unload() == S_OK); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif } int main(int const argc, char** argv) diff --git a/test/test_module_lock_none/test_module_lock_none.vcxproj b/test/test_module_lock_none/test_module_lock_none.vcxproj index 381edbdfe..d9242a281 100644 --- a/test/test_module_lock_none/test_module_lock_none.vcxproj +++ b/test/test_module_lock_none/test_module_lock_none.vcxproj @@ -92,6 +92,8 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console @@ -113,6 +115,8 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -132,6 +136,8 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -151,6 +157,8 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -172,6 +180,8 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console @@ -195,6 +205,8 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console diff --git a/test/test_slow/test_slow.vcxproj b/test/test_slow/test_slow.vcxproj index eb6c7fc60..5b753a17a 100644 --- a/test/test_slow/test_slow.vcxproj +++ b/test/test_slow/test_slow.vcxproj @@ -92,6 +92,8 @@ $(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console @@ -112,6 +114,8 @@ $(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -130,6 +134,8 @@ $(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -148,6 +154,8 @@ $(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -168,6 +176,8 @@ $(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console @@ -190,6 +200,8 @@ $(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console diff --git a/vsix/ProjectTemplates/VC/Windows Desktop/ConsoleApplication/ConsoleApplication.vcxproj b/vsix/ProjectTemplates/VC/Windows Desktop/ConsoleApplication/ConsoleApplication.vcxproj index f82376473..f205306b8 100644 --- a/vsix/ProjectTemplates/VC/Windows Desktop/ConsoleApplication/ConsoleApplication.vcxproj +++ b/vsix/ProjectTemplates/VC/Windows Desktop/ConsoleApplication/ConsoleApplication.vcxproj @@ -67,6 +67,7 @@ $(IntDir)pch.pch _CONSOLE;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) Level4 + true %(AdditionalOptions) /permissive- /bigobj diff --git a/vsix/ProjectTemplates/VC/Windows Desktop/WindowsApplication/WindowsApplication.vcxproj b/vsix/ProjectTemplates/VC/Windows Desktop/WindowsApplication/WindowsApplication.vcxproj index 8b8cb03ce..e4a05cdc7 100644 --- a/vsix/ProjectTemplates/VC/Windows Desktop/WindowsApplication/WindowsApplication.vcxproj +++ b/vsix/ProjectTemplates/VC/Windows Desktop/WindowsApplication/WindowsApplication.vcxproj @@ -67,6 +67,7 @@ $(IntDir)pch.pch _CONSOLE;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) Level4 + true %(AdditionalOptions) /permissive- /bigobj diff --git a/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/BlankApp.vcxproj b/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/BlankApp.vcxproj index 30630610e..ae3d074f2 100644 --- a/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/BlankApp.vcxproj +++ b/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/BlankApp.vcxproj @@ -76,6 +76,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) diff --git a/vsix/ProjectTemplates/VC/Windows Universal/CoreApp/CoreApp.vcxproj b/vsix/ProjectTemplates/VC/Windows Universal/CoreApp/CoreApp.vcxproj index 841ff85c9..2d891ef11 100644 --- a/vsix/ProjectTemplates/VC/Windows Universal/CoreApp/CoreApp.vcxproj +++ b/vsix/ProjectTemplates/VC/Windows Universal/CoreApp/CoreApp.vcxproj @@ -75,6 +75,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) diff --git a/vsix/ProjectTemplates/VC/Windows Universal/StaticLibrary/StaticLibrary.vcxproj b/vsix/ProjectTemplates/VC/Windows Universal/StaticLibrary/StaticLibrary.vcxproj index ec8126558..2afea1c00 100644 --- a/vsix/ProjectTemplates/VC/Windows Universal/StaticLibrary/StaticLibrary.vcxproj +++ b/vsix/ProjectTemplates/VC/Windows Universal/StaticLibrary/StaticLibrary.vcxproj @@ -81,6 +81,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) diff --git a/vsix/ProjectTemplates/VC/Windows Universal/WindowsRuntimeComponent/WindowsRuntimeComponent.vcxproj b/vsix/ProjectTemplates/VC/Windows Universal/WindowsRuntimeComponent/WindowsRuntimeComponent.vcxproj index 78c477177..da87bf2fb 100644 --- a/vsix/ProjectTemplates/VC/Windows Universal/WindowsRuntimeComponent/WindowsRuntimeComponent.vcxproj +++ b/vsix/ProjectTemplates/VC/Windows Universal/WindowsRuntimeComponent/WindowsRuntimeComponent.vcxproj @@ -80,6 +80,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj _WINRT_DLL;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) From 4c9e03fe1e3d7cbfbf742ec237e9af5b30add68a Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sun, 4 May 2025 13:51:28 -0500 Subject: [PATCH 02/42] fix indent in generated code (#1489) Fix a line that was indented too much in the generated code. --- cppwinrt/code_writers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index ae2920d56..ffc0ee948 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -1868,7 +1868,7 @@ namespace cppwinrt { auto param_name = param.Name(); - w.write("\n if (%) *% = detach_abi(winrt_impl_%);", param_name, param_name, param_name); + w.write("\n if (%) *% = detach_abi(winrt_impl_%);", param_name, param_name, param_name); } } } From 1a678d68b9e3ad25722318127d15057d377dac16 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 09:06:52 -0700 Subject: [PATCH 03/42] Bump actions/checkout from 4 to 5 (#1502) Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8544bcf77..11fc05c26 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: config: Release runs-on: windows-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Download nuget run: | @@ -102,7 +102,7 @@ jobs: config: Release runs-on: windows-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Fetch cppwinrt executables if: matrix.arch != 'arm64' @@ -250,7 +250,7 @@ jobs: CMAKE_COLOR_DIAGNOSTICS: 1 CLICOLOR_FORCE: 1 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install cross compiler run: | @@ -283,7 +283,7 @@ jobs: Deployment: [Component, Standalone] runs-on: windows-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Download nuget run: | @@ -323,7 +323,7 @@ jobs: config: [Release] runs-on: windows-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Fetch cppwinrt executables uses: actions/download-artifact@v4 @@ -368,7 +368,7 @@ jobs: name: Build nuget package with MSVC runs-on: windows-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Package run: | From a338c862c43e16ee8c3ba77bcae92d821be2deb5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 09:35:09 -0700 Subject: [PATCH 04/42] Bump actions/download-artifact from 4 to 5 (#1501) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 5. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 11fc05c26..866fddd7d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -106,14 +106,14 @@ jobs: - name: Fetch cppwinrt executables if: matrix.arch != 'arm64' - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-bin path: _build/${{ matrix.arch }}/${{ matrix.config }}/ - name: Fetch x86 cppwinrt executables (arm64 only) if: matrix.arch == 'arm64' - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: msvc-build-${{ matrix.compiler}}-x86-Release-bin path: _build/x86/Release/ @@ -326,7 +326,7 @@ jobs: - uses: actions/checkout@v5 - name: Fetch cppwinrt executables - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-bin path: _build/${{ matrix.arch }}/${{ matrix.config }}/ From 34fba98b48cc4cf98e069f7f2c1f7f51122894cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Sep 2025 13:59:36 -0500 Subject: [PATCH 05/42] Bump actions/stale from 9 to 10 (#1507) --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index c081bdf43..b686df568 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -13,7 +13,7 @@ jobs: pull-requests: write steps: - - uses: actions/stale@v9 + - uses: actions/stale@v10 with: repo-token: ${{ secrets.GITHUB_TOKEN }} days-before-stale: 10 From ebace4abb8f48b6b9a612e8b84667e6044976a47 Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Thu, 16 Oct 2025 09:33:43 -0700 Subject: [PATCH 06/42] Fix CI build by using latest Windows SDK in C# project (#1516) * Attempt "latest SDK" setting * Update TargetPlatformVersion to use WindowsSDKVersion * Fix TargetPlatformVersion trimming in project file --- .../TestRuntimeComponentCSharp.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/nuget/TestRuntimeComponentCSharp/TestRuntimeComponentCSharp.csproj b/test/nuget/TestRuntimeComponentCSharp/TestRuntimeComponentCSharp.csproj index d756e19b7..167b32ad9 100644 --- a/test/nuget/TestRuntimeComponentCSharp/TestRuntimeComponentCSharp.csproj +++ b/test/nuget/TestRuntimeComponentCSharp/TestRuntimeComponentCSharp.csproj @@ -11,7 +11,7 @@ TestRuntimeComponentCSharp en-US UAP - 10.0.22621.0 + $(WindowsSDKVersion.TrimEnd('\')) 10.0.18362.0 14 512 @@ -93,4 +93,4 @@ --> - \ No newline at end of file + From dcaa98c8d2abeb47ab5ce9ef1f96171e93d0ff9b Mon Sep 17 00:00:00 2001 From: antmor <43587397+antmor@users.noreply.github.com> Date: Thu, 30 Oct 2025 10:59:16 -0700 Subject: [PATCH 07/42] Remove throwing/originating errors in expected scenarios (Lookup/TryLookup and Cancel) (#1512) * non-originating error compiles * fix with test cases * and remove ignore * add runsettings to run tests from visual studio tester, modified readme, make shouldOrigiante a template param. * change map shouldOriginate to template parameter. Note, could be a breakig change for usages of map that are not default (i.e. custom std::less) if so, might need to split up templates into separate template, or spin out into separate pr. changed bool to template parameter in hresult_error, as the char*-to-bool decaying conversion failed the old tests. also fixed runsettings, added note in readme. * settle on avoid_originate as naming scheme * add a printf only to Lookup so we can add SFINAE or something like that. * weird templating magic required... still not working, has error 1>G:\source\repos\cppwinrt\_build\x64\Debug\winrt\Windows.Foundation.Collections.h(868,51): error C3878: syntax error: unexpected token '>' following 'simple-type-specifier' 1>(compiling source file '/Class.cpp') 1> G:\source\repos\cppwinrt\_build\x64\Debug\winrt\Windows.Foundation.Collections.h(868,51): 1> missing one of: '(' '{' ? * trylookup exists to avoid throwing an error, and let's avoid avoid_originate now. * remove test. * cleaned up and correctness. * undo changes to untouched files * spacing changes , change do declval. * added special tag to parameter list to make sure not to break existing TryLookup impls, added test to verify this. * address avoid_oritinate comment, no need for a different name, resuse existing hresult_cancelled * change out async to a new name, with it being true by default. add new unittest to test nullable lookup. * Address hresult comments by adding tests and removing source_locatoin, special-cased further by checking the typename. * add unittest without specialization, make sure that the behaviour is opt-in --------- Co-authored-by: Chris Guzak --- .runsettings | 24 +++++ README.md | 5 + cppwinrt/code_writers.h | 80 ++++++++++++++-- strings/base_collections_base.h | 15 +++ strings/base_coroutine_foundation.h | 22 ++++- strings/base_coroutine_threadpool.h | 11 +++ strings/base_error.h | 8 ++ strings/base_meta.h | 16 ++++ test/old_tests/UnitTests/Errors.cpp | 1 + test/old_tests/UnitTests/TryLookup.cpp | 127 ++++++++++++++++++++++++- test/test/async_check_cancel.cpp | 80 +++++++++++++++- test/test_cpp20/custom_error.cpp | 63 +++++++++++- 12 files changed, 437 insertions(+), 15 deletions(-) create mode 100644 .runsettings diff --git a/.runsettings b/.runsettings new file mode 100644 index 000000000..5f10e44f8 --- /dev/null +++ b/.runsettings @@ -0,0 +1,24 @@ + + + + .\TestResults + 60000 + true + + + + + + + Single + (?i:Test) + true + on + true + Verbose + AdditionalInfo + ShortInfo + , + 20000 + + \ No newline at end of file diff --git a/README.md b/README.md index 1749fea0c..19e1493dc 100644 --- a/README.md +++ b/README.md @@ -34,3 +34,8 @@ a dev command prompt at the root of the repo _after_ following the above build i * Run `build_prior_projection.cmd` in the dev command prompt as well * Run `prepare_versionless_diffs.cmd` which removes version stamps on both current and prior projection * Use a directory-level differencing tool to compare `_build\$(arch)\$(flavor)\winrt` and `_reference\$(arch)\$(flavor)\winrt` + +## Testing +This repository uses the [Catch2](https://github.com/catchorg/Catch2) testing framework. +- From a Visual Studio command line, you should run `build_tests_all.cmd` to build and run the tests. To Debug the tests, you can debug the associated `_build\$(arch)\$(flavor)\.exe` under the debugger of your choice. +- Optionally, you can install the [Catch2Adapter](https://marketplace.visualstudio.com/items?itemName=JohnnyHendriks.ext01) to run the tests from Visual Studio. \ No newline at end of file diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index ffc0ee948..35e9935d0 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -1873,7 +1873,37 @@ namespace cppwinrt } } - static void write_produce_method(writer& w, MethodDef const& method) + static void write_produce_upcall_TryLookup(writer& w, std::string_view const& upcall, method_signature const& method_signature) + { + auto name = method_signature.return_param_name(); + + w.write("auto out_param_val = %(%, trylookup_from_abi);", + upcall, + bind(method_signature)); + w.write(R"( + if (out_param_val.has_value()) + { + *% = detach_from<%>(std::move(*out_param_val)); + } + else + { + return impl::error_out_of_bounds; + } +)", + name, method_signature.return_signature()); + + for (auto&& [param, param_signature] : method_signature.params()) + { + if (param.Flags().Out() && !param_signature->Type().is_szarray() && is_object(param_signature->Type())) + { + auto param_name = param.Name(); + + w.write("\n if (%) *% = detach_abi(winrt_impl_%);", param_name, param_name, param_name); + } + } + } + + static void write_produce_method(writer& w, MethodDef const& method, TypeDef const& type) { std::string_view format; @@ -1902,13 +1932,45 @@ namespace cppwinrt method_signature signature{ method }; auto async_types_guard = w.push_async_types(signature.is_async()); std::string upcall = "this->shim()."; - upcall += get_name(method); + auto name = get_name(method); + upcall += name; - w.write(format, - get_abi_name(method), - bind(signature), - bind(signature), - bind(upcall, signature)); + auto typeName = type.TypeName(); + if (((typeName == "IMapView`2") || (typeName == "IMap`2")) + && (name == "Lookup")) + { + // Special-case IMap*::Lookup to look for a TryLookup here, to avoid extranous throw/originates + std::string tryLookupUpCall = "this->shim().TryLookup"; + format = R"( int32_t __stdcall %(%) noexcept final try + { +% typename D::abi_guard guard(this->shim()); + if constexpr (has_TryLookup_v) + { + % + } + else + { + % + } + return 0; + } + catch (...) { return to_hresult(); } +)"; + w.write(format, + get_abi_name(method), + bind(signature), + bind(signature), // clear_abi + bind(tryLookupUpCall, signature), + bind(upcall, signature)); + } + else + { + w.write(format, + get_abi_name(method), + bind(signature), + bind(signature), + bind(upcall, signature)); + } } static void write_fast_produce_methods(writer& w, TypeDef const& default_interface) @@ -1951,7 +2013,7 @@ namespace cppwinrt break; } - w.write_each(info.type.MethodList()); + w.write_each(info.type.MethodList(), info.type); } } @@ -1973,7 +2035,7 @@ namespace cppwinrt bind(generics), type, type, - bind_each(type.MethodList()), + bind_each(type.MethodList(), type), bind(type)); } diff --git a/strings/base_collections_base.h b/strings/base_collections_base.h index f3ede9ed4..fec3de660 100644 --- a/strings/base_collections_base.h +++ b/strings/base_collections_base.h @@ -506,6 +506,20 @@ WINRT_EXPORT namespace winrt template struct map_view_base : iterable_base, Version> { + // specialization of Lookup that avoids throwing the hresult + std::optional TryLookup(K const& key, trylookup_from_abi_t) const + { + [[maybe_unused]] auto guard = static_cast(*this).acquire_shared(); + auto pair = static_cast(*this).get_container().find(static_cast(*this).wrap_value(key)); + + if (pair == static_cast(*this).get_container().end()) + { + return std::nullopt; + } + + return static_cast(*this).unwrap_value(pair->second); + } + V Lookup(K const& key) const { [[maybe_unused]] auto guard = static_cast(*this).acquire_shared(); @@ -536,6 +550,7 @@ WINRT_EXPORT namespace winrt first = nullptr; second = nullptr; } + }; template diff --git a/strings/base_coroutine_foundation.h b/strings/base_coroutine_foundation.h index 670a65403..87aaed24e 100644 --- a/strings/base_coroutine_foundation.h +++ b/strings/base_coroutine_foundation.h @@ -351,6 +351,10 @@ namespace winrt::impl return m_promise->enable_cancellation_propagation(value); } + bool originate_on_cancel(bool value = true) const noexcept + { + return m_promise->originate_on_cancel(value); + } private: Promise* m_promise; @@ -484,7 +488,14 @@ namespace winrt::impl if (m_status.load(std::memory_order_relaxed) == AsyncStatus::Started) { m_status.store(AsyncStatus::Canceled, std::memory_order_relaxed); - m_exception = std::make_exception_ptr(hresult_canceled()); + if (cancellable_promise::originate_on_cancel()) + { + m_exception = std::make_exception_ptr(hresult_canceled()); + } + else + { + m_exception = std::make_exception_ptr(hresult_canceled(hresult_error::no_originate)); + } cancel = std::move(m_cancel); } } @@ -628,7 +639,14 @@ namespace winrt::impl { if (Status() == AsyncStatus::Canceled) { - throw winrt::hresult_canceled(); + if (cancellable_promise::originate_on_cancel()) + { + throw winrt::hresult_canceled(); + } + else + { + throw winrt::hresult_canceled(hresult_error::no_originate); + } } return std::forward(expression); diff --git a/strings/base_coroutine_threadpool.h b/strings/base_coroutine_threadpool.h index 0faaa1acd..7fa8789c7 100644 --- a/strings/base_coroutine_threadpool.h +++ b/strings/base_coroutine_threadpool.h @@ -180,12 +180,23 @@ WINRT_EXPORT namespace winrt return m_propagate_cancellation; } + bool originate_on_cancel(bool value = true) noexcept + { + return std::exchange(m_originate_on_cancel, value); + } + + bool should_originate_on_cancel() const noexcept + { + return m_originate_on_cancel; + } + private: static inline auto const cancelling_ptr = reinterpret_cast(1); std::atomic m_canceller{ nullptr }; void* m_context{ nullptr }; bool m_propagate_cancellation{ false }; + bool m_originate_on_cancel{ true }; // By default, will call RoOriginateError before throwing a cancel error code. }; template diff --git a/strings/base_error.h b/strings/base_error.h index 85de70f63..41929336b 100644 --- a/strings/base_error.h +++ b/strings/base_error.h @@ -84,6 +84,9 @@ WINRT_EXPORT namespace winrt { struct hresult_error { + struct no_originate_t {}; + static constexpr no_originate_t no_originate{}; + using from_abi_t = take_ownership_from_abi_t; static constexpr auto from_abi{ take_ownership_from_abi }; @@ -109,6 +112,10 @@ WINRT_EXPORT namespace winrt originate(code, nullptr, sourceInformation); } + explicit hresult_error(hresult const code, no_originate_t) noexcept : m_code(verify_error(code)) + { + } + hresult_error(hresult const code, param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : m_code(verify_error(code)) { originate(code, get_abi(message), sourceInformation); @@ -325,6 +332,7 @@ WINRT_EXPORT namespace winrt struct hresult_canceled : hresult_error { hresult_canceled(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_canceled, sourceInformation) {} + hresult_canceled(hresult_error::no_originate_t) noexcept : hresult_error(impl::error_canceled, hresult_error::no_originate) {} hresult_canceled(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_canceled, message, sourceInformation) {} hresult_canceled(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_canceled, take_ownership_from_abi, sourceInformation) {} }; diff --git a/strings/base_meta.h b/strings/base_meta.h index 25deb42ec..7dbb4c386 100644 --- a/strings/base_meta.h +++ b/strings/base_meta.h @@ -10,6 +10,10 @@ WINRT_EXPORT namespace winrt struct take_ownership_from_abi_t {}; inline constexpr take_ownership_from_abi_t take_ownership_from_abi{}; + // Map implementations can implement TryLookup with trylookup_from_abi_t as an optimization + struct trylookup_from_abi_t {}; + inline constexpr trylookup_from_abi_t trylookup_from_abi{}; + template struct com_ptr; @@ -298,4 +302,16 @@ namespace winrt::impl return (func(Types{}) || ...); } }; + + template + struct has_TryLookup + { + template ().TryLookup(std::declval(), trylookup_from_abi))> static constexpr bool get_value(int) { return true; } + template static constexpr bool get_value(...) { return false; } + public: + static constexpr bool value = get_value(0); + }; + + template + inline constexpr bool has_TryLookup_v = has_TryLookup::value; } diff --git a/test/old_tests/UnitTests/Errors.cpp b/test/old_tests/UnitTests/Errors.cpp index 472d633f1..f8656a508 100644 --- a/test/old_tests/UnitTests/Errors.cpp +++ b/test/old_tests/UnitTests/Errors.cpp @@ -233,6 +233,7 @@ TEST_CASE("Errors") // Make sure trimming works. hresult_error e(E_FAIL, L":) is \u263A \n \t "); + auto x = e.message(); REQUIRE(e.message() == L":) is \u263A"); // Make sure delegates propagate correctly. diff --git a/test/old_tests/UnitTests/TryLookup.cpp b/test/old_tests/UnitTests/TryLookup.cpp index 3c6c54580..350fa9006 100644 --- a/test/old_tests/UnitTests/TryLookup.cpp +++ b/test/old_tests/UnitTests/TryLookup.cpp @@ -143,4 +143,129 @@ TEST_CASE("TryLookup TryRemove error") REQUIRE(!map.TryLookup(123)); REQUIRE(!map.TryRemove(123)); -} \ No newline at end of file +} + +TEST_CASE("trylookup_from_abi specialization") +{ + // A map that throws a specific error, used to verify various edge cases. + // and implements tryLookup, to take advantage of an optimization to avoid a throw. + struct map_with_try_lookup : implements> + { + hresult codeToThrow{ S_OK }; + bool shouldThrowOnTryLookup{ false }; + std::optional TryLookup(int, trylookup_from_abi_t) + { + if (shouldThrowOnTryLookup) + { + throw_hresult(codeToThrow); + } + else + { + return { std::nullopt }; + } + } + int Lookup(int) { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + int32_t Size() { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + bool HasKey(int) { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + void Split(IMapView&, IMapView&) { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + }; + + auto self = make_self(); + IMapView map = *self; + + // Make sure that we use the TryLookup specialization, and don't throw an unexpected exception. + self->shouldThrowOnTryLookup = false; + REQUIRE(!map.TryLookup(123)); + // make sure regular lookup stll throws bounds + REQUIRE_THROWS_AS(map.Lookup(123), hresult_out_of_bounds); + + // Simulate a non-agile map that is being accessed from the wrong thread. + // "Try" operations should throw rather than erroneously report "not found". + // Because they didn't even try. The operation never got off the ground. + self->shouldThrowOnTryLookup = true; + self->codeToThrow = RPC_E_WRONG_THREAD; + REQUIRE_THROWS_AS(map.TryLookup(123), hresult_wrong_thread); + // regular lookup should throw the same error + REQUIRE_THROWS_AS(map.Lookup(123), hresult_wrong_thread); +} + +TEST_CASE("trylookup_from_abi NOT opt-in, no special tag") +{ + // Makes sure that an existing TryLookup method is not called without the trylookup_from_abi_t tag. + struct map_without_try_lookup : implements> + { + hresult codeToThrow{ S_OK }; + std::optional TryLookup(int) // notice no trylookup_from_abi_t, so no opt-in + { + // throw an unexpectd hresult, this should not be called. + throw_hresult(RPC_E_WRONG_THREAD); + } + int Lookup(int) { return 42; } // Behave as if the item was found + + int32_t Size() { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + bool HasKey(int) { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + void Split(IMapView&, IMapView&) { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + }; + + auto self = make_self(); + IMapView map = *self; + + // Make sure that we don't use the TryLookup specialization, we use the Successful Lookup + REQUIRE(map.TryLookup(123).value() == 42); + REQUIRE(map.Lookup(123) == 42); +} + +TEST_CASE("trylookup_from_abi specialization with IInspectable") +{ + // A map that throws a specific error, used to verify various edge cases. + // and implements tryLookup, to take advantage of an optimization to avoid a throw. + struct map_with_try_lookup : implements> + { + hresult codeToThrow{ S_OK }; + bool shouldThrowOnTryLookup{ false }; + bool returnNullptr{ false }; + std::optional TryLookup(int, trylookup_from_abi_t) + { + if (returnNullptr) + { + return { nullptr }; + } + else if (shouldThrowOnTryLookup) + { + throw_hresult(codeToThrow); + } + else + { + return { std::nullopt }; + } + } + IInspectable Lookup(int) { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + int32_t Size() { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + bool HasKey(int) { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + void Split(IMapView&, IMapView&) { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + }; + + auto self = make_self(); + IMapView map = *self; + + // Ensure that we return a value on nullptr, a nullptr is a valid IInspectable in the Map + self->returnNullptr = true; + REQUIRE(map.TryLookup(123) == IInspectable{nullptr}); + REQUIRE(map.Lookup(123) == IInspectable{nullptr}); + + // Make sure that we use the TryLookup specialization, and don't throw an unexpected exception. + self->shouldThrowOnTryLookup = false; + self->returnNullptr = false; + REQUIRE(map.TryLookup(123) == IInspectable{nullptr}); + // make sure regular lookup stll throws bounds + REQUIRE_THROWS_AS(map.Lookup(123), hresult_out_of_bounds); + + // Simulate a non-agile map that is being accessed from the wrong thread. + // "Try" operations should throw rather than erroneously report "not found". + // Because they didn't even try. The operation never got off the ground. + self->shouldThrowOnTryLookup = true; + self->codeToThrow = RPC_E_WRONG_THREAD; + REQUIRE_THROWS_AS(map.TryLookup(123), hresult_wrong_thread); + // regular lookup should throw the same error + REQUIRE_THROWS_AS(map.Lookup(123), hresult_wrong_thread); +} diff --git a/test/test/async_check_cancel.cpp b/test/test/async_check_cancel.cpp index 7547609f6..d88fdcaf0 100644 --- a/test/test/async_check_cancel.cpp +++ b/test/test/async_check_cancel.cpp @@ -11,6 +11,28 @@ namespace using std::experimental::suspend_never; #endif + static bool s_exceptionLoggerCalled = false; + + static struct { + uint32_t lineNumber; + char const* fileName; + char const* functionName; + void* returnAddress; + winrt::hresult result; + } s_exceptionLoggerArgs{}; + + void __stdcall exceptionLogger(uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept + { + s_exceptionLoggerArgs = { + /*.lineNumber =*/ lineNumber, + /*.fileName =*/ fileName, + /*.functionName =*/ functionName, + /*.returnAddress =*/ returnAddress, + /*.result =*/ result, + }; + s_exceptionLoggerCalled = true; + } + // // Checks that manual cancellation checks work. // @@ -61,6 +83,7 @@ namespace co_return 1; } + IAsyncOperationWithProgress OperationWithProgress(HANDLE event, bool& canceled) { co_await resume_on_signal(event); @@ -77,6 +100,59 @@ namespace co_return 1; } + IAsyncAction OperationCancelLogged(HANDLE event, bool& canceled) + { + REQUIRE(!s_exceptionLoggerCalled); + REQUIRE(!winrt_throw_hresult_handler); + winrt_throw_hresult_handler = exceptionLogger; + + co_await resume_on_signal(event); + auto cancel = co_await get_cancellation_token(); + + if (cancel()) + { + REQUIRE(!canceled); + canceled = true; + REQUIRE(s_exceptionLoggerCalled); + REQUIRE(s_exceptionLoggerArgs.result == HRESULT_FROM_WIN32(ERROR_CANCELLED)); + } + + winrt_throw_hresult_handler = nullptr; + s_exceptionLoggerCalled = false; + + co_await suspend_never(); + + REQUIRE(false); + co_return; + } + + IAsyncAction OperationAvoidLoggingCancel(HANDLE event, bool& canceled) + { + REQUIRE(!s_exceptionLoggerCalled); + REQUIRE(!winrt_throw_hresult_handler); + winrt_throw_hresult_handler = exceptionLogger; + + auto cancel = co_await get_cancellation_token(); + cancel.originate_on_cancel(false); + + co_await resume_on_signal(event); + + if (cancel()) + { + REQUIRE(!canceled); + canceled = true; + REQUIRE(!s_exceptionLoggerCalled); + } + + winrt_throw_hresult_handler = nullptr; + s_exceptionLoggerCalled = false; + + co_await suspend_never(); + + REQUIRE(false); + co_return; + } + template void Check(F make) { @@ -96,7 +172,7 @@ namespace async.Cancel(); SetEvent(start.get()); - REQUIRE(WaitForSingleObject(completed.get(), 1000) == WAIT_OBJECT_0); + REQUIRE(WaitForSingleObject(completed.get(), IsDebuggerPresent() ? INFINITE : 1000) == WAIT_OBJECT_0); REQUIRE(async.Status() == AsyncStatus::Canceled); REQUIRE(async.ErrorCode() == HRESULT_FROM_WIN32(ERROR_CANCELLED)); @@ -115,4 +191,6 @@ TEST_CASE("async_check_cancel") Check(ActionWithProgress); Check(Operation); Check(OperationWithProgress); + Check(OperationCancelLogged); + Check(OperationAvoidLoggingCancel); } diff --git a/test/test_cpp20/custom_error.cpp b/test/test_cpp20/custom_error.cpp index d7b055e47..b925628d9 100644 --- a/test/test_cpp20/custom_error.cpp +++ b/test/test_cpp20/custom_error.cpp @@ -37,9 +37,9 @@ namespace #if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 170000 // not available in libc++ before LLVM 16 -TEST_CASE("custom_error_logger", "[!shouldfail]") +TEST_CASE("custom_error_logger_on_throw", "[!shouldfail]") #else -TEST_CASE("custom_error_logger") +TEST_CASE("custom_error_logger_on_throw") #endif { // Set up global handler @@ -72,3 +72,62 @@ TEST_CASE("custom_error_logger") winrt_throw_hresult_handler = nullptr; s_loggerCalled = false; } +template +void HresultOnLine80(Args... args) +{ + // Validate that handler translated on creating an HRESULT +#line 80 // Force next line to be reported as line number 80 + winrt::hresult_canceled(std::forward(args)...); +} + +#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 170000 +// not available in libc++ before LLVM 16 +TEST_CASE("custom_error_logger_on_originate", "[!shouldfail]") +#else +TEST_CASE("custom_error_logger_on_originate") +#endif +{ + // Set up global handler + REQUIRE(!s_loggerCalled); + REQUIRE(!winrt_throw_hresult_handler); + winrt_throw_hresult_handler = logger; + + HresultOnLine80(); + REQUIRE(s_loggerCalled); + // In C++20 these fields should be filled in by std::source_location + REQUIRE(s_loggerArgs.lineNumber == 80); + const auto fileNameSv = std::string_view(s_loggerArgs.fileName); + REQUIRE(!fileNameSv.empty()); + REQUIRE(fileNameSv.find("custom_error.cpp") != std::string::npos); +#ifdef _DEBUG + const auto functionNameSv = std::string_view(s_loggerArgs.functionName); + REQUIRE(!functionNameSv.empty()); + // Every compiler has a slightly different naming approach for this function, and even the same + // compiler can change its mind over time. Instead of matching the entire function name just + // match against the part we care about. + REQUIRE((functionNameSv.find("HresultOnLine80") != std::string_view::npos)); +#else + REQUIRE(s_loggerArgs.functionName == nullptr); +#endif // _DEBUG + + REQUIRE(s_loggerArgs.returnAddress); + REQUIRE(s_loggerArgs.result == HRESULT_FROM_WIN32(ERROR_CANCELLED)); // E_ILLEGAL_DELEGATE_ASSIGNMENT) + + s_loggerCalled = false; + s_loggerArgs.lineNumber = 0; + // verify HRESULT with a custom message + HresultOnLine80(L"with custom message"); + REQUIRE(s_loggerCalled); + REQUIRE(s_loggerArgs.lineNumber == 80); + + s_loggerCalled = false; + s_loggerArgs.lineNumber = 0; + // verify that no_originate does _not_ call the logger. + HresultOnLine80(winrt::hresult_error::no_originate); + REQUIRE(!s_loggerCalled); + REQUIRE(s_loggerArgs.lineNumber == 0); + + // Remove global handler + winrt_throw_hresult_handler = nullptr; + s_loggerCalled = false; +} From 584a0e09b2cce0450bb5b0e2c3ee122c383a34bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Nov 2025 08:49:08 -0600 Subject: [PATCH 08/42] Bump actions/download-artifact from 5 to 6 (#1519) --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 866fddd7d..6f2745772 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -106,14 +106,14 @@ jobs: - name: Fetch cppwinrt executables if: matrix.arch != 'arm64' - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v6 with: name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-bin path: _build/${{ matrix.arch }}/${{ matrix.config }}/ - name: Fetch x86 cppwinrt executables (arm64 only) if: matrix.arch == 'arm64' - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v6 with: name: msvc-build-${{ matrix.compiler}}-x86-Release-bin path: _build/x86/Release/ @@ -326,7 +326,7 @@ jobs: - uses: actions/checkout@v5 - name: Fetch cppwinrt executables - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v6 with: name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-bin path: _build/${{ matrix.arch }}/${{ matrix.config }}/ From a0fcdc8a6db6283b19c16da04a920bf4de202c32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Nov 2025 10:41:58 -0600 Subject: [PATCH 09/42] Bump actions/upload-artifact from 4 to 5 (#1518) --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6f2745772..37611ce0e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,7 +66,7 @@ jobs: cmd /c "$env:VSDevCmd" "&" msbuild /m /clp:ForceConsoleColor "$env:msbuild_config_props" cppwinrt.sln /t:cppwinrt - name: Upload built executables - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-bin path: | @@ -230,7 +230,7 @@ jobs: - name: Upload arm64 test executables if: matrix.arch == 'arm64' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: msvc-tests-${{ matrix.test_exe }}-${{ matrix.compiler }}-${{ matrix.arch }}-${{ matrix.config }}-bin path: | @@ -269,7 +269,7 @@ jobs: cmake --build build/cross_x64/ --target install -j2 - name: Upload cppwinrt.exe - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: cross-build-${{ matrix.arch }}-bin path: install/bin/cppwinrt.exe @@ -383,7 +383,7 @@ jobs: } - name: Upload nuget package artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: package path: "*.nupkg" From 1ccb7e1494b9c55f45f2a306d9a4dbc62317dc4c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 17:48:07 -0800 Subject: [PATCH 10/42] Bump actions/checkout from 5 to 6 (#1523) Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 37611ce0e..4ece2a7df 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: config: Release runs-on: windows-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Download nuget run: | @@ -102,7 +102,7 @@ jobs: config: Release runs-on: windows-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Fetch cppwinrt executables if: matrix.arch != 'arm64' @@ -250,7 +250,7 @@ jobs: CMAKE_COLOR_DIAGNOSTICS: 1 CLICOLOR_FORCE: 1 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install cross compiler run: | @@ -283,7 +283,7 @@ jobs: Deployment: [Component, Standalone] runs-on: windows-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Download nuget run: | @@ -323,7 +323,7 @@ jobs: config: [Release] runs-on: windows-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Fetch cppwinrt executables uses: actions/download-artifact@v6 @@ -368,7 +368,7 @@ jobs: name: Build nuget package with MSVC runs-on: windows-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Package run: | From ac422060b70014180021d73974fc99ed0676ee3a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Jan 2026 11:18:32 -0600 Subject: [PATCH 11/42] Bump actions/upload-artifact from 5 to 6 (#1525) --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4ece2a7df..d0b327169 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,7 +66,7 @@ jobs: cmd /c "$env:VSDevCmd" "&" msbuild /m /clp:ForceConsoleColor "$env:msbuild_config_props" cppwinrt.sln /t:cppwinrt - name: Upload built executables - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-bin path: | @@ -230,7 +230,7 @@ jobs: - name: Upload arm64 test executables if: matrix.arch == 'arm64' - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: msvc-tests-${{ matrix.test_exe }}-${{ matrix.compiler }}-${{ matrix.arch }}-${{ matrix.config }}-bin path: | @@ -269,7 +269,7 @@ jobs: cmake --build build/cross_x64/ --target install -j2 - name: Upload cppwinrt.exe - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: cross-build-${{ matrix.arch }}-bin path: install/bin/cppwinrt.exe @@ -383,7 +383,7 @@ jobs: } - name: Upload nuget package artifact - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: package path: "*.nupkg" From 6d87b8463a5608aca62b3f439f30dbe38dc11620 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Jan 2026 11:45:29 -0600 Subject: [PATCH 12/42] Bump actions/download-artifact from 6 to 7 (#1526) --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d0b327169..aeed4106c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -106,14 +106,14 @@ jobs: - name: Fetch cppwinrt executables if: matrix.arch != 'arm64' - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v7 with: name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-bin path: _build/${{ matrix.arch }}/${{ matrix.config }}/ - name: Fetch x86 cppwinrt executables (arm64 only) if: matrix.arch == 'arm64' - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v7 with: name: msvc-build-${{ matrix.compiler}}-x86-Release-bin path: _build/x86/Release/ @@ -326,7 +326,7 @@ jobs: - uses: actions/checkout@v6 - name: Fetch cppwinrt executables - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v7 with: name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-bin path: _build/${{ matrix.arch }}/${{ matrix.config }}/ From a7a5cd97ccc16bf606a20108bc9bda33f09bdb7f Mon Sep 17 00:00:00 2001 From: Vineeth Thomas Alex Date: Tue, 3 Feb 2026 13:48:20 -0600 Subject: [PATCH 13/42] Enable PreFast for build stage in OneBranch pipeline (#1533) Re-enable PreFast for build stage in pipeline. --- .pipelines/OneBranch.Official.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/OneBranch.Official.yml b/.pipelines/OneBranch.Official.yml index 552ec761b..56fada628 100644 --- a/.pipelines/OneBranch.Official.yml +++ b/.pipelines/OneBranch.Official.yml @@ -45,8 +45,6 @@ extends: compiled: enabled: true tsaEnabled: true - prefast: - enabled: true stages: - stage: build @@ -59,6 +57,8 @@ extends: BuildConfiguration: $(BuildConfiguration) BuildVersion: $(BuildVersion) OfficialBuild: true + ob_sdl_prefast_enabled: true + ob_sdl_prefast_runDuring: "Guardian" # Enabling PreFast only for build stage - stage: vpack dependsOn: build From 3a596b513eb14d374c55d8f79a15906fbdfafc3f Mon Sep 17 00:00:00 2001 From: Vineeth Thomas Alex Date: Tue, 3 Feb 2026 16:57:59 -0600 Subject: [PATCH 14/42] Update PreFast run stage in OneBranchBuild.yml to "Guardian" to avoid race condition with build. (#1534) * Remove PreFast settings from OneBranch pipeline Removed PreFast parameters from build configuration. * Update PreFast run stage in OneBranchBuild.yml Changed PreFast run stage from 'Build' to 'Guardian' to enable it only during the Guardian stage. * Correct indentation for PreFast configuration Fix indentation for ob_sdl_prefast_runDuring in OneBranchBuild.yml --- .pipelines/OneBranch.Official.yml | 3 --- .pipelines/jobs/OneBranchBuild.yml | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.pipelines/OneBranch.Official.yml b/.pipelines/OneBranch.Official.yml index 56fada628..996f2a607 100644 --- a/.pipelines/OneBranch.Official.yml +++ b/.pipelines/OneBranch.Official.yml @@ -57,8 +57,6 @@ extends: BuildConfiguration: $(BuildConfiguration) BuildVersion: $(BuildVersion) OfficialBuild: true - ob_sdl_prefast_enabled: true - ob_sdl_prefast_runDuring: "Guardian" # Enabling PreFast only for build stage - stage: vpack dependsOn: build @@ -68,7 +66,6 @@ extends: type: windows variables: ob_outputDirectory: '$(Build.SourcesDirectory)\out' - ob_createvpack_enabled: true ob_createvpack_packagename: CppWinRT.Compiler ob_createvpack_owneralias: cpp4uwpt diff --git a/.pipelines/jobs/OneBranchBuild.yml b/.pipelines/jobs/OneBranchBuild.yml index b5c060cb9..dfee85edf 100644 --- a/.pipelines/jobs/OneBranchBuild.yml +++ b/.pipelines/jobs/OneBranchBuild.yml @@ -32,7 +32,7 @@ jobs: ob_sdl_codeSignValidation_excludes: '-|**\*.exe;-|**\*.dll' ob_sdl_prefast_enabled: true - ob_sdl_prefast_runDuring: 'Build' + ob_sdl_prefast_runDuring: "Guardian" ob_sdl_checkCompliantCompilerWarnings: true ob_symbolsPublishing_enabled: ${{ parameters.OfficialBuild }} From 0f3e9f7b8d80a86f2ab3e9f8da47e217c5736ad1 Mon Sep 17 00:00:00 2001 From: Vineeth Thomas Alex Date: Thu, 5 Feb 2026 13:06:33 -0600 Subject: [PATCH 15/42] Remove Windows pool from build stage (#1535) * Remove Windows pool from build stage Removed Windows pool configuration from build stage, since template job defines pool * Remove prefast in OneBranch.PullRequest.yml Prefast is enabled in the build stage template job * Add -SkipDuplicate option to NuGet push arguments * Update .pipelines/jobs/OneBranchNuGet.yml Co-authored-by: Ryan Shepherd * Update NuGet push command arguments Removed the -SkipDuplicate option from the NuGet push command. * Set pre-release NuGet version in VSIX build * Change ob_sdl_prefast_runDuring to 'Guardian' --------- Co-authored-by: Ryan Shepherd --- .pipelines/OneBranch.Official.yml | 3 --- .pipelines/OneBranch.PullRequest.yml | 2 -- .pipelines/jobs/OneBranchNuGet.yml | 9 ++++++--- .pipelines/jobs/OneBranchVsix.yml | 7 ++++++- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.pipelines/OneBranch.Official.yml b/.pipelines/OneBranch.Official.yml index 996f2a607..cf2928151 100644 --- a/.pipelines/OneBranch.Official.yml +++ b/.pipelines/OneBranch.Official.yml @@ -48,9 +48,6 @@ extends: stages: - stage: build - pool: - type: windows - jobs: - template: .pipelines/jobs/OneBranchBuild.yml@self parameters: diff --git a/.pipelines/OneBranch.PullRequest.yml b/.pipelines/OneBranch.PullRequest.yml index bc08bbddf..ea4884329 100644 --- a/.pipelines/OneBranch.PullRequest.yml +++ b/.pipelines/OneBranch.PullRequest.yml @@ -41,8 +41,6 @@ extends: enabled: false sbom: enabled: true - prefast: - enabled: true stages: - stage: build diff --git a/.pipelines/jobs/OneBranchNuGet.yml b/.pipelines/jobs/OneBranchNuGet.yml index 02133ee03..867202891 100644 --- a/.pipelines/jobs/OneBranchNuGet.yml +++ b/.pipelines/jobs/OneBranchNuGet.yml @@ -15,10 +15,13 @@ jobs: variables: ob_outputDirectory: '$(Build.SourcesDirectory)\out' - PackageVersion: ${{ parameters.BuildVersion }} + ${{ if eq(parameters.OfficialBuild, true) }}: + PackageVersion: ${{ parameters.BuildVersion }} + ${{ else }}: + PackageVersion: ${{ parameters.BuildVersion }}-unofficial ob_sdl_prefast_enabled: true - ob_sdl_prefast_runDuring: 'Build' + ob_sdl_prefast_runDuring: 'Guardian' ob_sdl_checkCompliantCompilerWarnings: true steps: @@ -72,4 +75,4 @@ jobs: displayName: 'Publish NuGet package' inputs: command: 'custom' - arguments: 'push $(ob_outputDirectory)\packages\Microsoft.Windows.CppWinRT.$(PackageVersion).nupkg -NonInteractive -Source https://microsoft.pkgs.visualstudio.com/_packaging/CppWinRT/nuget/v3/index.json -ApiKey VSTS' \ No newline at end of file + arguments: 'push $(ob_outputDirectory)\packages\Microsoft.Windows.CppWinRT.$(PackageVersion).nupkg -NonInteractive -Source https://microsoft.pkgs.visualstudio.com/_packaging/CppWinRT/nuget/v3/index.json -ApiKey VSTS' diff --git a/.pipelines/jobs/OneBranchVsix.yml b/.pipelines/jobs/OneBranchVsix.yml index 18b74403b..1b03f71d0 100644 --- a/.pipelines/jobs/OneBranchVsix.yml +++ b/.pipelines/jobs/OneBranchVsix.yml @@ -27,6 +27,11 @@ jobs: VsixFilename: Microsoft.Windows.CppWinRT variables: + ${{ if eq(parameters.OfficialBuild, true) }}: + PackageVersion: ${{ parameters.BuildVersion }} + ${{ else }}: + PackageVersion: ${{ parameters.BuildVersion }}-unofficial + ob_outputDirectory: $(Build.SourcesDirectory)\out ob_artifactSuffix: $(VsVersion)_$(Deployment) @@ -91,7 +96,7 @@ jobs: displayName: Build VSIX inputs: solution: $(Build.SourcesDirectory)\vsix\vsix.sln - msbuildArgs: /t:vsix_$(VsVersion) /m /p:CppWinRTVersion=${{ parameters.BuildVersion }},clean_intermediate_files=true,Deployment=$(Deployment),NatvisDirx86=$(Build.SourcesDirectory)\x86\$(Deployment)\,NatvisDirx64=$(Build.SourcesDirectory)\x64\$(Deployment)\,NatvisDirarm64=$(Build.SourcesDirectory)\arm64\$(Deployment)\,NupkgDir=$(Pipeline.Workspace)\nuget\packages /bl:$(ob_outputDirectory)\output.binlog + msbuildArgs: /t:vsix_$(VsVersion) /m /p:CppWinRTVersion=$(PackageVersion),clean_intermediate_files=true,Deployment=$(Deployment),NatvisDirx86=$(Build.SourcesDirectory)\x86\$(Deployment)\,NatvisDirx64=$(Build.SourcesDirectory)\x64\$(Deployment)\,NatvisDirarm64=$(Build.SourcesDirectory)\arm64\$(Deployment)\,NupkgDir=$(Pipeline.Workspace)\nuget\packages /bl:$(ob_outputDirectory)\output.binlog platform: 'Any CPU' configuration: ${{ parameters.BuildConfiguration }} From 1a5cd652058cb2e3162732da42c7a478c2b8ccc8 Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Tue, 10 Feb 2026 11:59:31 -0800 Subject: [PATCH 16/42] Only sign the VSIX contents instead of the entire temp directory (#1537) --- .pipelines/jobs/OneBranchVsix.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/jobs/OneBranchVsix.yml b/.pipelines/jobs/OneBranchVsix.yml index 1b03f71d0..8c49ccf5b 100644 --- a/.pipelines/jobs/OneBranchVsix.yml +++ b/.pipelines/jobs/OneBranchVsix.yml @@ -114,7 +114,7 @@ jobs: command: sign signing_profile: external_distribution files_to_sign: '**\*.dll' - search_root: '$(Agent.TempDirectory)' + search_root: '$(Agent.TempDirectory)\$(VsixFilename)' - task: ArchiveFiles@2 displayName: 'Repack signed VSIX contents' From da8a3761306c037e6ba5b0d29e6e2a4923c4488c Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Tue, 10 Feb 2026 12:00:40 -0800 Subject: [PATCH 17/42] Fix handling of NuGet package version in VSIX (#1536) * Allow vsix to have prerelease nupkg * Fix nuget template invocation * Missed one case of NuGet vs VSIX version --- .pipelines/OneBranch.Official.yml | 6 ++++-- .pipelines/OneBranch.PullRequest.yml | 3 ++- .pipelines/jobs/OneBranchNuGet.yml | 7 ++----- .pipelines/jobs/OneBranchVsix.yml | 9 +++------ .pipelines/variables/version.yml | 12 +++++++++++- build_vsix.cmd | 4 ++-- vsix/Dev16/Component/source.extension.vsixmanifest | 2 +- vsix/Dev16/Standalone/source.extension.vsixmanifest | 2 +- vsix/Dev16/vsix.Dev16.csproj | 4 ++-- vsix/Dev17/Component/source.extension.vsixmanifest | 2 +- vsix/Dev17/Standalone/source.extension.vsixmanifest | 2 +- vsix/Dev17/vsix.Dev17.csproj | 4 ++-- vsix/Extension.targets | 4 +++- 13 files changed, 35 insertions(+), 26 deletions(-) diff --git a/.pipelines/OneBranch.Official.yml b/.pipelines/OneBranch.Official.yml index cf2928151..64f762d81 100644 --- a/.pipelines/OneBranch.Official.yml +++ b/.pipelines/OneBranch.Official.yml @@ -6,6 +6,8 @@ parameters: # parameters are shown up in ADO UI in a build queue time variables: - template: variables/version.yml + parameters: + OfficialBuild: true - template: variables/OneBranchVariables.yml parameters: debug: ${{ parameters.debug }} @@ -132,8 +134,7 @@ extends: jobs: - template: .pipelines/jobs/OneBranchNuGet.yml@self parameters: - BuildConfiguration: $(BuildConfiguration) - BuildVersion: $(BuildVersion) + NugetPackageVersion: $(NugetPackageVersion) OfficialBuild: true - stage: Test @@ -151,4 +152,5 @@ extends: parameters: BuildConfiguration: $(BuildConfiguration) BuildVersion: $(BuildVersion) + NugetPackageVersion: $(NugetPackageVersion) OfficialBuild: true diff --git a/.pipelines/OneBranch.PullRequest.yml b/.pipelines/OneBranch.PullRequest.yml index ea4884329..9e18821b4 100644 --- a/.pipelines/OneBranch.PullRequest.yml +++ b/.pipelines/OneBranch.PullRequest.yml @@ -56,7 +56,7 @@ extends: - template: .pipelines/jobs/OneBranchNuGet.yml@self parameters: BuildConfiguration: $(BuildConfiguration) - BuildVersion: $(BuildVersion) + NugetPackageVersion: $(NugetPackageVersion) - stage: Test dependsOn: build @@ -73,3 +73,4 @@ extends: parameters: BuildConfiguration: $(BuildConfiguration) BuildVersion: $(BuildVersion) + NugetPackageVersion: $(NugetPackageVersion) diff --git a/.pipelines/jobs/OneBranchNuGet.yml b/.pipelines/jobs/OneBranchNuGet.yml index 867202891..36ec3144b 100644 --- a/.pipelines/jobs/OneBranchNuGet.yml +++ b/.pipelines/jobs/OneBranchNuGet.yml @@ -2,7 +2,7 @@ parameters: - name: BuildConfiguration type: string - - name: BuildVersion + - name: NugetPackageVersion type: string - name: OfficialBuild type: boolean @@ -15,10 +15,7 @@ jobs: variables: ob_outputDirectory: '$(Build.SourcesDirectory)\out' - ${{ if eq(parameters.OfficialBuild, true) }}: - PackageVersion: ${{ parameters.BuildVersion }} - ${{ else }}: - PackageVersion: ${{ parameters.BuildVersion }}-unofficial + PackageVersion: ${{ parameters.NugetPackageVersion }} ob_sdl_prefast_enabled: true ob_sdl_prefast_runDuring: 'Guardian' diff --git a/.pipelines/jobs/OneBranchVsix.yml b/.pipelines/jobs/OneBranchVsix.yml index 8c49ccf5b..696b7e292 100644 --- a/.pipelines/jobs/OneBranchVsix.yml +++ b/.pipelines/jobs/OneBranchVsix.yml @@ -3,6 +3,8 @@ parameters: type: string - name: BuildVersion type: string + - name: NugetPackageVersion + type: string - name: OfficialBuild type: boolean default: false @@ -27,11 +29,6 @@ jobs: VsixFilename: Microsoft.Windows.CppWinRT variables: - ${{ if eq(parameters.OfficialBuild, true) }}: - PackageVersion: ${{ parameters.BuildVersion }} - ${{ else }}: - PackageVersion: ${{ parameters.BuildVersion }}-unofficial - ob_outputDirectory: $(Build.SourcesDirectory)\out ob_artifactSuffix: $(VsVersion)_$(Deployment) @@ -96,7 +93,7 @@ jobs: displayName: Build VSIX inputs: solution: $(Build.SourcesDirectory)\vsix\vsix.sln - msbuildArgs: /t:vsix_$(VsVersion) /m /p:CppWinRTVersion=$(PackageVersion),clean_intermediate_files=true,Deployment=$(Deployment),NatvisDirx86=$(Build.SourcesDirectory)\x86\$(Deployment)\,NatvisDirx64=$(Build.SourcesDirectory)\x64\$(Deployment)\,NatvisDirarm64=$(Build.SourcesDirectory)\arm64\$(Deployment)\,NupkgDir=$(Pipeline.Workspace)\nuget\packages /bl:$(ob_outputDirectory)\output.binlog + msbuildArgs: /t:vsix_$(VsVersion) /m /p:CppWinRTVersion=${{ parameters.BuildVersion }},NugetPackageVersion=${{ parameters.NugetPackageVersion }},clean_intermediate_files=true,Deployment=$(Deployment),NatvisDirx86=$(Build.SourcesDirectory)\x86\$(Deployment)\,NatvisDirx64=$(Build.SourcesDirectory)\x64\$(Deployment)\,NatvisDirarm64=$(Build.SourcesDirectory)\arm64\$(Deployment)\,NupkgDir=$(Pipeline.Workspace)\nuget\packages /bl:$(ob_outputDirectory)\output.binlog platform: 'Any CPU' configuration: ${{ parameters.BuildConfiguration }} diff --git a/.pipelines/variables/version.yml b/.pipelines/variables/version.yml index 576d896eb..15382e7df 100644 --- a/.pipelines/variables/version.yml +++ b/.pipelines/variables/version.yml @@ -1,7 +1,17 @@ +parameters: + - name: OfficialBuild + type: boolean + default: false + variables: MajorVersion: "2" MinorVersion: "0" VersionDate: $[format('{0:yyMMdd}', pipeline.startTime)] VersionCounter: $[counter(variables['VersionDate'], 1)] BuildVersion: $(MajorVersion).$(MinorVersion).$(VersionDate).$(VersionCounter) - PatchVersion: $(VersionDate)$(VersionCounter) \ No newline at end of file + PatchVersion: $(VersionDate)$(VersionCounter) + + ${{ if eq(parameters.OfficialBuild, true) }}: + NugetPackageVersion: $(BuildVersion) + ${{ else }}: + NugetPackageVersion: $(BuildVersion)-unofficial diff --git a/build_vsix.cmd b/build_vsix.cmd index 9908462ef..aefc84df1 100644 --- a/build_vsix.cmd +++ b/build_vsix.cmd @@ -30,7 +30,7 @@ call msbuild /p:Configuration=%target_configuration%,Platform=x86,Deployment=%ta call msbuild /p:Configuration=%target_configuration%,Platform=arm64,Deployment=%target_deployment%,CppWinRTBuildVersion=%target_version% natvis\cppwinrtvisualizer.sln rem Build nuget -.nuget\nuget.exe pack nuget\Microsoft.Windows.CppWinRT.nuspec -NonInteractive -OutputDirectory %this_dir%_build -Properties Configuration=%target_configuration%;cppwinrt_exe=%this_dir%_build\x86\%target_configuration%\cppwinrt.exe;cppwinrt_fast_fwd_x86=%this_dir%_build\x86\%target_configuration%\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_x64=%this_dir%_build\x64\%target_configuration%\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_arm64=%this_dir%_build\arm64\%target_configuration%\cppwinrt_fast_forwarder.lib -version %target_version% -Verbosity Detailed +.nuget\nuget.exe pack nuget\Microsoft.Windows.CppWinRT.nuspec -NonInteractive -OutputDirectory %this_dir%_build -Properties Configuration=%target_configuration%;cppwinrt_exe=%this_dir%_build\x86\%target_configuration%\cppwinrt.exe;cppwinrt_fast_fwd_x86=%this_dir%_build\x86\%target_configuration%\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_x64=%this_dir%_build\x64\%target_configuration%\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_arm64=%this_dir%_build\arm64\%target_configuration%\cppwinrt_fast_forwarder.lib;target_version=%target_version% -version %target_version% -Verbosity Detailed rem Build vsix -call msbuild /restore /p:Configuration=%target_configuration%,Platform="Any CPU",Deployment=%target_deployment%,CppWinRTVersion=%target_version%,NatvisDirx86=%this_dir%natvis\x86\%target_configuration%\%target_deployment%,NatvisDirx64=%this_dir%natvis\x64\%target_configuration%\%target_deployment%,NatvisDirarm64=%this_dir%natvis\arm64\%target_configuration%\%target_deployment%,NupkgDir=%this_dir%_build vsix\vsix.sln +call msbuild /restore /p:Configuration=%target_configuration%,Platform="Any CPU",Deployment=%target_deployment%,CppWinRTVersion=%target_version%,NugetPackageVersion=%target_version%,NatvisDirx86=%this_dir%natvis\x86\%target_configuration%\%target_deployment%,NatvisDirx64=%this_dir%natvis\x64\%target_configuration%\%target_deployment%,NatvisDirarm64=%this_dir%natvis\arm64\%target_configuration%\%target_deployment%,NupkgDir=%this_dir%_build vsix\vsix.sln diff --git a/vsix/Dev16/Component/source.extension.vsixmanifest b/vsix/Dev16/Component/source.extension.vsixmanifest index afd96cf1f..a7ab21972 100644 --- a/vsix/Dev16/Component/source.extension.vsixmanifest +++ b/vsix/Dev16/Component/source.extension.vsixmanifest @@ -29,7 +29,7 @@ - + diff --git a/vsix/Dev16/Standalone/source.extension.vsixmanifest b/vsix/Dev16/Standalone/source.extension.vsixmanifest index e3c2ac995..b38c06cf8 100644 --- a/vsix/Dev16/Standalone/source.extension.vsixmanifest +++ b/vsix/Dev16/Standalone/source.extension.vsixmanifest @@ -29,7 +29,7 @@ - + diff --git a/vsix/Dev16/vsix.Dev16.csproj b/vsix/Dev16/vsix.Dev16.csproj index 72b9b4098..94a6836c3 100644 --- a/vsix/Dev16/vsix.Dev16.csproj +++ b/vsix/Dev16/vsix.Dev16.csproj @@ -41,8 +41,8 @@ %(Filename)%(Extension) true - - Packages\Microsoft.Windows.CppWinRT.$(CppWinRTVersion).nupkg + + Packages\Microsoft.Windows.CppWinRT.$(NugetPackageVersion).nupkg true diff --git a/vsix/Dev17/Component/source.extension.vsixmanifest b/vsix/Dev17/Component/source.extension.vsixmanifest index bcbfa9c8b..063dfcbc7 100644 --- a/vsix/Dev17/Component/source.extension.vsixmanifest +++ b/vsix/Dev17/Component/source.extension.vsixmanifest @@ -35,7 +35,7 @@ - + diff --git a/vsix/Dev17/Standalone/source.extension.vsixmanifest b/vsix/Dev17/Standalone/source.extension.vsixmanifest index 56ea4b86f..89e178c82 100644 --- a/vsix/Dev17/Standalone/source.extension.vsixmanifest +++ b/vsix/Dev17/Standalone/source.extension.vsixmanifest @@ -35,7 +35,7 @@ - + diff --git a/vsix/Dev17/vsix.Dev17.csproj b/vsix/Dev17/vsix.Dev17.csproj index 3326ce6fa..02f3e0bb8 100644 --- a/vsix/Dev17/vsix.Dev17.csproj +++ b/vsix/Dev17/vsix.Dev17.csproj @@ -44,8 +44,8 @@ %(Filename)%(Extension) true - - Packages\Microsoft.Windows.CppWinRT.$(CppWinRTVersion).nupkg + + Packages\Microsoft.Windows.CppWinRT.$(NugetPackageVersion).nupkg true diff --git a/vsix/Extension.targets b/vsix/Extension.targets index 7a7b6c2b8..442f03a53 100644 --- a/vsix/Extension.targets +++ b/vsix/Extension.targets @@ -1,8 +1,10 @@ + + @@ -27,7 +29,7 @@ - + From 129c9258fedbae96a0155f634bf56b68f6f75053 Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Wed, 11 Feb 2026 11:55:11 -0800 Subject: [PATCH 18/42] Fix accidentally deleted parameter (#1538) --- .pipelines/OneBranch.Official.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pipelines/OneBranch.Official.yml b/.pipelines/OneBranch.Official.yml index 64f762d81..7a73b263b 100644 --- a/.pipelines/OneBranch.Official.yml +++ b/.pipelines/OneBranch.Official.yml @@ -134,6 +134,7 @@ extends: jobs: - template: .pipelines/jobs/OneBranchNuGet.yml@self parameters: + BuildConfiguration: $(BuildConfiguration) NugetPackageVersion: $(NugetPackageVersion) OfficialBuild: true From dcbdcc856f43be2f119a7b83005387894959e0db Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 1 Mar 2026 08:15:25 -0800 Subject: [PATCH 19/42] Delete stale.yml (#1543) --- .github/workflows/stale.yml | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 .github/workflows/stale.yml diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml deleted file mode 100644 index b686df568..000000000 --- a/.github/workflows/stale.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Mark stale issues and pull requests - -on: - schedule: - - cron: '0 0 * * *' - -jobs: - stale: - - runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write - - steps: - - uses: actions/stale@v10 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - days-before-stale: 10 - days-before-close: 5 - stale-issue-message: 'This issue is stale because it has been open 10 days with no activity. Remove stale label or comment or this will be closed in 5 days.' - stale-pr-message: 'This pull request is stale because it has been open 10 days with no activity. Remove stale label or comment or this will be closed in 5 days.' - stale-issue-label: 'no-issue-activity' - stale-pr-label: 'no-pr-activity' From 6bf188e1ab4ec5d089f093043f7df34de76bb31f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Mar 2026 08:24:20 -0800 Subject: [PATCH 20/42] Bump actions/download-artifact from 7 to 8 (#1541) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 7 to 8. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v7...v8) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '8' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aeed4106c..eb37051b5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -106,14 +106,14 @@ jobs: - name: Fetch cppwinrt executables if: matrix.arch != 'arm64' - uses: actions/download-artifact@v7 + uses: actions/download-artifact@v8 with: name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-bin path: _build/${{ matrix.arch }}/${{ matrix.config }}/ - name: Fetch x86 cppwinrt executables (arm64 only) if: matrix.arch == 'arm64' - uses: actions/download-artifact@v7 + uses: actions/download-artifact@v8 with: name: msvc-build-${{ matrix.compiler}}-x86-Release-bin path: _build/x86/Release/ @@ -326,7 +326,7 @@ jobs: - uses: actions/checkout@v6 - name: Fetch cppwinrt executables - uses: actions/download-artifact@v7 + uses: actions/download-artifact@v8 with: name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-bin path: _build/${{ matrix.arch }}/${{ matrix.config }}/ From 751a57bd33b92d67ada681d9084fa6a452364317 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Mar 2026 08:34:58 -0800 Subject: [PATCH 21/42] Bump actions/upload-artifact from 6 to 7 (#1542) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eb37051b5..6356b8095 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,7 +66,7 @@ jobs: cmd /c "$env:VSDevCmd" "&" msbuild /m /clp:ForceConsoleColor "$env:msbuild_config_props" cppwinrt.sln /t:cppwinrt - name: Upload built executables - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-bin path: | @@ -230,7 +230,7 @@ jobs: - name: Upload arm64 test executables if: matrix.arch == 'arm64' - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: msvc-tests-${{ matrix.test_exe }}-${{ matrix.compiler }}-${{ matrix.arch }}-${{ matrix.config }}-bin path: | @@ -269,7 +269,7 @@ jobs: cmake --build build/cross_x64/ --target install -j2 - name: Upload cppwinrt.exe - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: cross-build-${{ matrix.arch }}-bin path: install/bin/cppwinrt.exe @@ -383,7 +383,7 @@ jobs: } - name: Upload nuget package artifact - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: package path: "*.nupkg" From bb0a408e7764f6b5ed8ac050459d07896c3f5f91 Mon Sep 17 00:00:00 2001 From: Yexuan Xiao Date: Tue, 10 Mar 2026 07:56:46 +0800 Subject: [PATCH 22/42] Simplify the definition of the consume function (#1544) --- cppwinrt/code_writers.h | 59 +++++++++-------------------------------- strings/base_windows.h | 57 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 47 deletions(-) diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index 35e9935d0..1d0f8fe92 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -619,10 +619,15 @@ namespace cppwinrt } } - static void write_abi_args(writer& w, method_signature const& method_signature) + static void write_abi_args(writer& w, method_signature const& method_signature, bool start_comma) { separator s{ w }; + if (start_comma) + { + s(); + } + for (auto&& [param, param_signature] : method_signature.params()) { s(); @@ -1135,19 +1140,7 @@ namespace cppwinrt // immediately while preserving the error code and local variables. format = R"( template auto consume_%::%(%) const noexcept {% - if constexpr (!std::is_same_v) - { - winrt::hresult _winrt_cast_result_code; - auto const _winrt_casted_result = impl::try_as_with_reason<%, D const*>(static_cast(this), _winrt_cast_result_code); - check_hresult(_winrt_cast_result_code); - auto const _winrt_abi_type = *(abi_t<%>**)&_winrt_casted_result; - _winrt_abi_type->%(%); - } - else - { - auto const _winrt_abi_type = *(abi_t<%>**)this; - _winrt_abi_type->%(%); - }% + consume_noexcept_remove_overload<%, D>(static_cast(this), &abi_t<%>::%%);% } )"; } @@ -1155,19 +1148,7 @@ namespace cppwinrt { format = R"( template auto consume_%::%(%) const noexcept {% - if constexpr (!std::is_same_v) - { - winrt::hresult _winrt_cast_result_code; - auto const _winrt_casted_result = impl::try_as_with_reason<%, D const*>(static_cast(this), _winrt_cast_result_code); - check_hresult(_winrt_cast_result_code); - auto const _winrt_abi_type = *(abi_t<%>**)&_winrt_casted_result; - WINRT_VERIFY_(0, _winrt_abi_type->%(%)); - } - else - { - auto const _winrt_abi_type = *(abi_t<%>**)this; - WINRT_VERIFY_(0, _winrt_abi_type->%(%)); - }% + consume_noexcept<%, D>(static_cast(this), &abi_t<%>::%%);% } )"; } @@ -1176,19 +1157,7 @@ namespace cppwinrt { format = R"( template auto consume_%::%(%) const {% - if constexpr (!std::is_same_v) - { - winrt::hresult _winrt_cast_result_code; - auto const _winrt_casted_result = impl::try_as_with_reason<%, D const*>(static_cast(this), _winrt_cast_result_code); - check_hresult(_winrt_cast_result_code); - auto const _winrt_abi_type = *(abi_t<%>**)&_winrt_casted_result; - check_hresult(_winrt_abi_type->%(%)); - } - else - { - auto const _winrt_abi_type = *(abi_t<%>**)this; - check_hresult(_winrt_abi_type->%(%)); - }% + consume_general<%, D>(static_cast(this), &abi_t<%>::%%);% } )"; } @@ -1202,12 +1171,8 @@ namespace cppwinrt bind(signature, false), type, type, - type, - get_abi_name(method), - bind(signature), - type, get_abi_name(method), - bind(signature), + bind(signature, true), bind(signature)); if (is_add_overload(method)) @@ -2750,7 +2715,7 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable bind(signature, true), type_name, bind_list(", ", generics), - bind(signature), + bind(signature, false), bind(signature)); } else @@ -2822,7 +2787,7 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable bind(signature), bind(signature, true), type_name, - bind(signature), + bind(signature, false), bind(signature)); } } diff --git a/strings/base_windows.h b/strings/base_windows.h index bf28440ef..831e1b1fe 100644 --- a/strings/base_windows.h +++ b/strings/base_windows.h @@ -451,3 +451,60 @@ WINRT_EXPORT namespace winrt::Windows::Foundation IInspectable(void* ptr, take_ownership_from_abi_t) noexcept : IUnknown(ptr, take_ownership_from_abi) {} }; } + +WINRT_EXPORT namespace winrt::impl +{ + template + void consume_noexcept_remove_overload(Derive const* d, MemberPointer mptr, Args&&... args) noexcept + { + if constexpr (!std::is_same_v) + { + winrt::hresult _winrt_cast_result_code; + auto const _winrt_casted_result = try_as_with_reason(d, _winrt_cast_result_code); + check_hresult(_winrt_cast_result_code); + auto const _winrt_abi_type = *(abi_t**)&_winrt_casted_result; + (_winrt_abi_type->*mptr)(std::forward(args)...); + } + else + { + auto const _winrt_abi_type = *(abi_t**)d; + (_winrt_abi_type->*mptr)(std::forward(args)...); + } + } + + template + void consume_noexcept(Derive const* d, MemberPointer mptr, Args&&... args) noexcept + { + if constexpr (!std::is_same_v) + { + winrt::hresult _winrt_cast_result_code; + auto const _winrt_casted_result = try_as_with_reason(d, _winrt_cast_result_code); + check_hresult(_winrt_cast_result_code); + auto const _winrt_abi_type = *(abi_t**)&_winrt_casted_result; + WINRT_VERIFY_(0, (_winrt_abi_type->*mptr)(std::forward(args)...)); + } + else + { + auto const _winrt_abi_type = *(abi_t**)d; + WINRT_VERIFY_(0, (_winrt_abi_type->*mptr)(std::forward(args)...)); + } + } + + template + void consume_general(Derive const* d, MemberPointer mptr, Args&&... args) + { + if constexpr (!std::is_same_v) + { + winrt::hresult _winrt_cast_result_code; + auto const _winrt_casted_result = try_as_with_reason(d, _winrt_cast_result_code); + check_hresult(_winrt_cast_result_code); + auto const _winrt_abi_type = *(abi_t**)&_winrt_casted_result; + check_hresult((_winrt_abi_type->*mptr)(std::forward(args)...)); + } + else + { + auto const _winrt_abi_type = *(abi_t**)d; + check_hresult((_winrt_abi_type->*mptr)(std::forward(args)...)); + } + } +} From 8864ac6ef07952e2ed10c3cec1445474b748a332 Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Mon, 16 Mar 2026 00:23:52 -0400 Subject: [PATCH 23/42] Remove experimental coroutines support (#1521) * Remove experimental coroutines support Replace CppWinRTEnableLegacyCoroutines with CppWinRTEnableCpp17Coroutines Remove base_coroutine_system_winui.h, hasn't worked since PR 0.8 Support and test building with no coroutines Remove implementation selection machinery * Fix clang-cl mismatching signedness error * Require coroutine support for C++/WinRT Add error message for missing coroutine support in C++. * Revert "Require coroutine support for C++/WinRT" This reverts commit de710f17fe9b7da34bf228b8b296f34c483e9a33. * Include an error message if /await is used --------- Co-authored-by: Ryan Shepherd --- .github/workflows/ci.yml | 2 +- .pipelines/jobs/OneBranchTest.yml | 4 + Directory.Build.Props | 4 +- build_test_all.cmd | 1 + cppwinrt.sln | 18 ++ cppwinrt/code_writers.h | 4 - nuget/CppWinrtRules.Project.xml | 6 +- nuget/Microsoft.Windows.CppWinRT.targets | 2 +- run_tests.cmd | 1 + strings/base_coroutine_foundation.h | 28 ++- strings/base_coroutine_system.h | 6 +- strings/base_coroutine_system_winui.h | 50 ----- strings/base_coroutine_threadpool.h | 59 +++--- strings/base_coroutine_ui_core.h | 6 +- strings/base_deferral.h | 16 +- strings/base_includes.h | 28 +-- strings/base_macros.h | 2 +- test/CMakeLists.txt | 1 + test/old_tests/UnitTests/async.cpp | 14 +- test/old_tests/UnitTests/weak.cpp | 8 +- test/test/async_auto_cancel.cpp | 16 +- test/test/async_cancel_callback.cpp | 14 +- test/test/async_check_cancel.cpp | 18 +- test/test/when.cpp | 8 +- test/test_nocoro/CMakeLists.txt | 35 ++++ test/test_nocoro/get.cpp | 74 +++++++ test/test_nocoro/main.cpp | 22 +++ test/test_nocoro/pch.cpp | 1 + test/test_nocoro/pch.h | 6 + test/test_nocoro/test_nocoro.vcxproj | 241 +++++++++++++++++++++++ 30 files changed, 489 insertions(+), 206 deletions(-) delete mode 100644 strings/base_coroutine_system_winui.h create mode 100644 test/test_nocoro/CMakeLists.txt create mode 100644 test/test_nocoro/get.cpp create mode 100644 test/test_nocoro/main.cpp create mode 100644 test/test_nocoro/pch.cpp create mode 100644 test/test_nocoro/pch.h create mode 100644 test/test_nocoro/test_nocoro.vcxproj diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6356b8095..a42f2c5b7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,7 +92,7 @@ jobs: compiler: [MSVC, clang-cl] arch: [x86, x64, arm64] config: [Debug, Release] - test_exe: [test, test_cpp20, test_cpp20_no_sourcelocation, test_fast, test_slow, test_old, test_module_lock_custom, test_module_lock_none] + test_exe: [test, test_nocoro, test_cpp20, test_cpp20_no_sourcelocation, test_fast, test_slow, test_old, test_module_lock_custom, test_module_lock_none] exclude: - arch: arm64 config: Debug diff --git a/.pipelines/jobs/OneBranchTest.yml b/.pipelines/jobs/OneBranchTest.yml index 0aa5c934b..2fb3a4bd1 100644 --- a/.pipelines/jobs/OneBranchTest.yml +++ b/.pipelines/jobs/OneBranchTest.yml @@ -17,6 +17,10 @@ jobs: TestExe: 'test' TestProject: 'test' BuildPlatform: 'x86' + test_nocoro.x86: + TestExe: 'test_nocoro' + TestProject: 'test_nocoro' + BuildPlatform: 'x86' test_cpp20.x86: TestExe: 'test_cpp20' TestProject: 'test_cpp20' diff --git a/Directory.Build.Props b/Directory.Build.Props index 9088021c1..5f530da91 100644 --- a/Directory.Build.Props +++ b/Directory.Build.Props @@ -30,7 +30,7 @@ ClangCL - + 20 false @@ -60,7 +60,7 @@ CATCH_CONFIG_COLOUR_ANSI;%(PreprocessorDefinitions) true /bigobj - /await %(AdditionalOptions) + /await:strict %(AdditionalOptions) -Wno-unused-command-line-argument -fno-delayed-template-parsing -mcx16 diff --git a/build_test_all.cmd b/build_test_all.cmd index 4372acfd5..649f4dc69 100644 --- a/build_test_all.cmd +++ b/build_test_all.cmd @@ -28,6 +28,7 @@ call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platfor call msbuild /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% test\nuget\NugetTest.sln call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test +call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test_nocoro call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test_cpp20 call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test_cpp20_no_sourcelocation call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test_fast diff --git a/cppwinrt.sln b/cppwinrt.sln index 5964f976b..3bcfb33bc 100644 --- a/cppwinrt.sln +++ b/cppwinrt.sln @@ -119,6 +119,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_cpp20_no_sourcelocatio {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_nocoro", "test\test_nocoro\test_nocoro.vcxproj", "{9E392830-805A-4AAF-932D-C493143EFACA}" + ProjectSection(ProjectDependencies) = postProject + {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} + EndProjectSection +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D15C8430-A7CD-4616-BD84-243B26A9F1C2}" ProjectSection(SolutionItems) = preProject build_nuget.cmd = build_nuget.cmd @@ -394,6 +399,18 @@ Global {D4C8F881-84D5-4A7B-8BDE-AB4E34A05374}.Release|x64.Build.0 = Release|x64 {D4C8F881-84D5-4A7B-8BDE-AB4E34A05374}.Release|x86.ActiveCfg = Release|Win32 {D4C8F881-84D5-4A7B-8BDE-AB4E34A05374}.Release|x86.Build.0 = Release|Win32 + {9E392830-805A-4AAF-932D-C493143EFACA}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {9E392830-805A-4AAF-932D-C493143EFACA}.Debug|ARM64.Build.0 = Debug|ARM64 + {9E392830-805A-4AAF-932D-C493143EFACA}.Debug|x64.ActiveCfg = Debug|x64 + {9E392830-805A-4AAF-932D-C493143EFACA}.Debug|x64.Build.0 = Debug|x64 + {9E392830-805A-4AAF-932D-C493143EFACA}.Debug|x86.ActiveCfg = Debug|Win32 + {9E392830-805A-4AAF-932D-C493143EFACA}.Debug|x86.Build.0 = Debug|Win32 + {9E392830-805A-4AAF-932D-C493143EFACA}.Release|ARM64.ActiveCfg = Release|ARM64 + {9E392830-805A-4AAF-932D-C493143EFACA}.Release|ARM64.Build.0 = Release|ARM64 + {9E392830-805A-4AAF-932D-C493143EFACA}.Release|x64.ActiveCfg = Release|x64 + {9E392830-805A-4AAF-932D-C493143EFACA}.Release|x64.Build.0 = Release|x64 + {9E392830-805A-4AAF-932D-C493143EFACA}.Release|x86.ActiveCfg = Release|Win32 + {9E392830-805A-4AAF-932D-C493143EFACA}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -417,6 +434,7 @@ Global {08C40663-B6A3-481E-8755-AE32BAD99501} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} {D4C8F881-84D5-4A7B-8BDE-AB4E34A05374} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} + {9E392830-805A-4AAF-932D-C493143EFACA} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {2783B8FD-EA3B-4D6B-9F81-662D289E02AA} diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index 1d0f8fe92..e24cfd302 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -3442,10 +3442,6 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable { w.write(strings::base_coroutine_system); } - else if (namespace_name == "Microsoft.System") - { - w.write(strings::base_coroutine_system_winui); - } else if (namespace_name == "Windows.UI.Core") { w.write(strings::base_coroutine_ui_core); diff --git a/nuget/CppWinrtRules.Project.xml b/nuget/CppWinrtRules.Project.xml index 7f69fcd74..73f32c6d3 100644 --- a/nuget/CppWinrtRules.Project.xml +++ b/nuget/CppWinrtRules.Project.xml @@ -81,9 +81,9 @@ Description="Enables or disables the default for copying binaries to the output folder to be false" Category="General" /> - diff --git a/nuget/Microsoft.Windows.CppWinRT.targets b/nuget/Microsoft.Windows.CppWinRT.targets index 7fe83b14d..188e56835 100644 --- a/nuget/Microsoft.Windows.CppWinRT.targets +++ b/nuget/Microsoft.Windows.CppWinRT.targets @@ -882,7 +882,7 @@ $(XamlMetaDataProviderPch) %(AdditionalOptions) /bigobj - %(AdditionalOptions) /await + %(AdditionalOptions) /await:strict %(AdditionalIncludeDirectories);$(GeneratedFilesDir) diff --git a/run_tests.cmd b/run_tests.cmd index 77d883642..58e3c5524 100644 --- a/run_tests.cmd +++ b/run_tests.cmd @@ -9,6 +9,7 @@ if "%target_platform%"=="" set target_platform=x64 if "%target_configuration%"=="" set target_configuration=Debug call :run_test test +call :run_test test_nocoro call :run_test test_cpp20 call :run_test test_cpp20_no_sourcelocation call :run_test test_fast diff --git a/strings/base_coroutine_foundation.h b/strings/base_coroutine_foundation.h index 87aaed24e..a5816a85b 100644 --- a/strings/base_coroutine_foundation.h +++ b/strings/base_coroutine_foundation.h @@ -99,12 +99,13 @@ namespace winrt::impl return async.GetResults(); } +#ifdef WINRT_IMPL_COROUTINES struct ignore_apartment_context {}; template struct disconnect_aware_handler : private std::conditional_t { - disconnect_aware_handler(Awaiter* awaiter, coroutine_handle<> handle) noexcept + disconnect_aware_handler(Awaiter* awaiter, std::coroutine_handle<> handle) noexcept : m_awaiter(awaiter), m_handle(handle) { } disconnect_aware_handler(disconnect_aware_handler&& other) = default; @@ -123,7 +124,7 @@ namespace winrt::impl private: movable_primitive m_awaiter; - movable_primitive, nullptr> m_handle; + movable_primitive, nullptr> m_handle; void Complete() { @@ -149,7 +150,6 @@ namespace winrt::impl } }; -#ifdef WINRT_IMPL_COROUTINES template struct await_adapter : cancellable_awaiter> { @@ -175,7 +175,7 @@ namespace winrt::impl } template - bool await_suspend(coroutine_handle handle) + bool await_suspend(std::coroutine_handle handle) { this->set_cancellable_promise_from_handle(handle); return register_completed_callback(handle); @@ -189,7 +189,7 @@ namespace winrt::impl } private: - bool register_completed_callback(coroutine_handle<> handle) + bool register_completed_callback(std::coroutine_handle<> handle) { if constexpr (!preserve_context) { @@ -294,7 +294,6 @@ WINRT_EXPORT namespace winrt::Windows::Foundation return{ async }; } } -#endif WINRT_EXPORT namespace winrt { @@ -327,7 +326,7 @@ namespace winrt::impl return true; } - void await_suspend(coroutine_handle<>) const noexcept + void await_suspend(std::coroutine_handle<>) const noexcept { } @@ -373,7 +372,7 @@ namespace winrt::impl return true; } - void await_suspend(coroutine_handle<>) const noexcept + void await_suspend(std::coroutine_handle<>) const noexcept { } @@ -411,7 +410,7 @@ namespace winrt::impl if (remaining == 0) { std::atomic_thread_fence(std::memory_order_acquire); - coroutine_handle::from_promise(*static_cast(this)).destroy(); + std::coroutine_handle::from_promise(*static_cast(this)).destroy(); } return remaining; @@ -577,7 +576,7 @@ namespace winrt::impl } } - suspend_never initial_suspend() const noexcept + std::suspend_never initial_suspend() const noexcept { return{}; } @@ -595,7 +594,7 @@ namespace winrt::impl { } - bool await_suspend(coroutine_handle<>) const noexcept + bool await_suspend(std::coroutine_handle<>) const noexcept { promise->set_completed(); uint32_t const remaining = promise->subtract_reference(); @@ -705,11 +704,7 @@ namespace winrt::impl }; } -#ifdef __cpp_lib_coroutine namespace std -#else -namespace std::experimental -#endif { template struct coroutine_traits @@ -844,7 +839,6 @@ namespace std::experimental WINRT_EXPORT namespace winrt { -#ifdef WINRT_IMPL_COROUTINES template Windows::Foundation::IAsyncAction when_all(T... async) { @@ -890,5 +884,5 @@ WINRT_EXPORT namespace winrt impl::check_status_canceled(shared->status); co_return shared->result.GetResults(); } -#endif } +#endif diff --git a/strings/base_coroutine_system.h b/strings/base_coroutine_system.h index b893bd1b5..f79fe0671 100644 --- a/strings/base_coroutine_system.h +++ b/strings/base_coroutine_system.h @@ -1,4 +1,5 @@ +#ifdef WINRT_IMPL_COROUTINES WINRT_EXPORT namespace winrt { [[nodiscard]] inline auto resume_foreground( @@ -23,7 +24,7 @@ WINRT_EXPORT namespace winrt return m_queued; } - bool await_suspend(impl::coroutine_handle<> handle) + bool await_suspend(std::coroutine_handle<> handle) { return m_dispatcher.TryEnqueue(m_priority, [handle, this] { @@ -41,10 +42,9 @@ WINRT_EXPORT namespace winrt return awaitable{ dispatcher, priority }; }; -#ifdef WINRT_IMPL_COROUTINES inline auto operator co_await(Windows::System::DispatcherQueue const& dispatcher) { return resume_foreground(dispatcher); } -#endif } +#endif diff --git a/strings/base_coroutine_system_winui.h b/strings/base_coroutine_system_winui.h deleted file mode 100644 index ecb3cf766..000000000 --- a/strings/base_coroutine_system_winui.h +++ /dev/null @@ -1,50 +0,0 @@ - -WINRT_EXPORT namespace winrt -{ - [[nodiscard]] inline auto resume_foreground( - Microsoft::System::DispatcherQueue const& dispatcher, - Microsoft::System::DispatcherQueuePriority const priority = Microsoft::System::DispatcherQueuePriority::Normal) noexcept - { - struct awaitable - { - awaitable(Microsoft::System::DispatcherQueue const& dispatcher, Microsoft::System::DispatcherQueuePriority const priority) noexcept : - m_dispatcher(dispatcher), - m_priority(priority) - { - } - - bool await_ready() const noexcept - { - return false; - } - - bool await_resume() const noexcept - { - return m_queued; - } - - bool await_suspend(impl::coroutine_handle<> handle) - { - return m_dispatcher.TryEnqueue(m_priority, [handle, this] - { - m_queued = true; - handle(); - }); - } - - private: - Microsoft::System::DispatcherQueue const& m_dispatcher; - Microsoft::System::DispatcherQueuePriority const m_priority; - bool m_queued{}; - }; - - return awaitable{ dispatcher, priority }; - }; - -#ifdef WINRT_IMPL_COROUTINES - inline auto operator co_await(Microsoft::System::DispatcherQueue const& dispatcher) - { - return resume_foreground(dispatcher); - } -#endif -} diff --git a/strings/base_coroutine_threadpool.h b/strings/base_coroutine_threadpool.h index 7fa8789c7..e59fcadb2 100644 --- a/strings/base_coroutine_threadpool.h +++ b/strings/base_coroutine_threadpool.h @@ -1,6 +1,7 @@ namespace winrt::impl { +#ifdef WINRT_IMPL_COROUTINES inline auto submit_threadpool_callback(void(__stdcall* callback)(void*, void* context), void* context) { if (!WINRT_IMPL_TrySubmitThreadpoolCallback(callback, context, nullptr)) @@ -11,13 +12,14 @@ namespace winrt::impl inline void __stdcall resume_background_callback(void*, void* context) noexcept { - coroutine_handle<>::from_address(context)(); + std::coroutine_handle<>::from_address(context)(); }; - inline auto resume_background(coroutine_handle<> handle) + inline auto resume_background(std::coroutine_handle<> handle) { submit_threadpool_callback(resume_background_callback, handle.address()); } +#endif inline std::pair get_apartment_type() noexcept { @@ -48,6 +50,7 @@ namespace winrt::impl return false; } +#ifdef WINRT_IMPL_COROUTINES struct resume_apartment_context { resume_apartment_context() = default; @@ -64,11 +67,11 @@ namespace winrt::impl inline int32_t __stdcall resume_apartment_callback(com_callback_args* args) noexcept { - coroutine_handle<>::from_address(args->data)(); + std::coroutine_handle<>::from_address(args->data)(); return 0; }; - [[nodiscard]] inline bool resume_apartment_sync(com_ptr const& context, coroutine_handle<> handle, int32_t* failure) + [[nodiscard]] inline bool resume_apartment_sync(com_ptr const& context, std::coroutine_handle<> handle, int32_t* failure) { com_callback_args args{}; args.data = handle.address(); @@ -85,10 +88,10 @@ namespace winrt::impl struct threadpool_resume { - threadpool_resume(com_ptr const& context, coroutine_handle<> handle, int32_t* failure) : + threadpool_resume(com_ptr const& context, std::coroutine_handle<> handle, int32_t* failure) : m_context(context), m_handle(handle), m_failure(failure) { } com_ptr m_context; - coroutine_handle<> m_handle; + std::coroutine_handle<> m_handle; int32_t* m_failure; }; @@ -101,14 +104,14 @@ namespace winrt::impl } } - inline void resume_apartment_on_threadpool(com_ptr const& context, coroutine_handle<> handle, int32_t* failure) + inline void resume_apartment_on_threadpool(com_ptr const& context, std::coroutine_handle<> handle, int32_t* failure) { auto state = std::make_unique(context, handle, failure); submit_threadpool_callback(fallback_submit_threadpool_callback, state.get()); state.release(); } - [[nodiscard]] inline auto resume_apartment(resume_apartment_context const& context, coroutine_handle<> handle, int32_t* failure) + [[nodiscard]] inline auto resume_apartment(resume_apartment_context const& context, std::coroutine_handle<> handle, int32_t* failure) { WINRT_ASSERT(context.valid()); if ((context.m_context == nullptr) || (context.m_context == try_capture(WINRT_IMPL_CoGetObjectContext))) @@ -130,8 +133,10 @@ namespace winrt::impl return resume_apartment_sync(context.m_context, handle, failure); } } +#endif } +#ifdef WINRT_IMPL_COROUTINES WINRT_EXPORT namespace winrt { struct cancellable_promise @@ -217,7 +222,7 @@ WINRT_EXPORT namespace winrt protected: template - void set_cancellable_promise_from_handle(impl::coroutine_handle const& handle) + void set_cancellable_promise_from_handle(std::coroutine_handle const& handle) { if constexpr (std::is_base_of_v) { @@ -237,10 +242,7 @@ WINRT_EXPORT namespace winrt cancellable_promise* m_promise = nullptr; }; -} -WINRT_EXPORT namespace winrt -{ [[nodiscard]] inline auto resume_background() noexcept { struct awaitable @@ -254,7 +256,7 @@ WINRT_EXPORT namespace winrt { } - void await_suspend(impl::coroutine_handle<> handle) const + void await_suspend(std::coroutine_handle<> handle) const { impl::resume_background(handle); } @@ -281,7 +283,7 @@ WINRT_EXPORT namespace winrt { } - void await_suspend(impl::coroutine_handle<> resume) + void await_suspend(std::coroutine_handle<> resume) { m_resume = resume; @@ -301,7 +303,7 @@ WINRT_EXPORT namespace winrt } T const& m_context; - impl::coroutine_handle<> m_resume{ nullptr }; + std::coroutine_handle<> m_resume{ nullptr }; }; return awaitable{ context }; @@ -336,7 +338,7 @@ namespace winrt::impl check_hresult(failure); } - bool await_suspend(impl::coroutine_handle<> handle) + bool await_suspend(std::coroutine_handle<> handle) { auto context_copy = context; return impl::resume_apartment(context_copy.context, handle, &failure); @@ -381,7 +383,7 @@ namespace winrt::impl } template - void await_suspend(impl::coroutine_handle handle) + void await_suspend(std::coroutine_handle handle) { set_cancellable_promise_from_handle(handle); @@ -445,7 +447,7 @@ namespace winrt::impl handle_type m_timer; Windows::Foundation::TimeSpan m_duration; - impl::coroutine_handle<> m_handle; + std::coroutine_handle<> m_handle; std::atomic m_state{ state::idle }; }; @@ -489,7 +491,7 @@ namespace winrt::impl } template - void await_suspend(impl::coroutine_handle resume) + void await_suspend(std::coroutine_handle resume) { set_cancellable_promise_from_handle(resume); @@ -559,31 +561,27 @@ namespace winrt::impl Windows::Foundation::TimeSpan m_timeout; void* m_handle; uint32_t m_result{}; - impl::coroutine_handle<> m_resume{ nullptr }; + std::coroutine_handle<> m_resume{ nullptr }; std::atomic m_state{ state::idle }; }; } WINRT_EXPORT namespace winrt { -#ifdef WINRT_IMPL_COROUTINES inline impl::apartment_awaiter operator co_await(apartment_context const& context) { return{ context }; } -#endif [[nodiscard]] inline impl::timespan_awaiter resume_after(Windows::Foundation::TimeSpan duration) noexcept { return impl::timespan_awaiter{ duration }; } -#ifdef WINRT_IMPL_COROUTINES inline impl::timespan_awaiter operator co_await(Windows::Foundation::TimeSpan duration) { return resume_after(duration); } -#endif [[nodiscard]] inline impl::signal_awaiter resume_on_signal(void* handle, Windows::Foundation::TimeSpan timeout = {}) noexcept { @@ -613,7 +611,7 @@ WINRT_EXPORT namespace winrt { } - void await_suspend(impl::coroutine_handle<> handle) + void await_suspend(std::coroutine_handle<> handle) { if (!WINRT_IMPL_TrySubmitThreadpoolCallback(callback, handle.address(), &m_environment)) { @@ -625,7 +623,7 @@ WINRT_EXPORT namespace winrt static void __stdcall callback(void*, void* context) noexcept { - impl::coroutine_handle<>::from_address(context)(); + std::coroutine_handle<>::from_address(context)(); } struct pool_traits @@ -673,11 +671,7 @@ WINRT_EXPORT namespace winrt struct fire_and_forget {}; } -#ifdef __cpp_lib_coroutine namespace std -#else -namespace std::experimental -#endif { template struct coroutine_traits @@ -693,12 +687,12 @@ namespace std::experimental { } - suspend_never initial_suspend() const noexcept + std::suspend_never initial_suspend() const noexcept { return{}; } - suspend_never final_suspend() const noexcept + std::suspend_never final_suspend() const noexcept { return{}; } @@ -710,3 +704,4 @@ namespace std::experimental }; }; } +#endif diff --git a/strings/base_coroutine_ui_core.h b/strings/base_coroutine_ui_core.h index dab34c8de..7efed5174 100644 --- a/strings/base_coroutine_ui_core.h +++ b/strings/base_coroutine_ui_core.h @@ -1,4 +1,5 @@ +#ifdef WINRT_IMPL_COROUTINES WINRT_EXPORT namespace winrt { [[nodiscard]] inline auto resume_foreground( @@ -22,7 +23,7 @@ WINRT_EXPORT namespace winrt { } - void await_suspend(impl::coroutine_handle<> handle) const + void await_suspend(std::coroutine_handle<> handle) const { m_dispatcher.RunAsync(m_priority, [handle] { @@ -39,10 +40,9 @@ WINRT_EXPORT namespace winrt return awaitable{ dispatcher, priority }; }; -#ifdef WINRT_IMPL_COROUTINES inline auto operator co_await(Windows::UI::Core::CoreDispatcher const& dispatcher) { return resume_foreground(dispatcher); } -#endif } +#endif diff --git a/strings/base_deferral.h b/strings/base_deferral.h index ceab1cd4b..6976db4a6 100644 --- a/strings/base_deferral.h +++ b/strings/base_deferral.h @@ -1,7 +1,7 @@ +#ifdef WINRT_IMPL_COROUTINES WINRT_EXPORT namespace winrt { -#ifdef WINRT_IMPL_COROUTINES template struct deferrable_event_args { @@ -22,9 +22,9 @@ WINRT_EXPORT namespace winrt [[nodiscard]] Windows::Foundation::IAsyncAction wait_for_deferrals() { - struct awaitable : impl::suspend_always + struct awaitable : std::suspend_always { - bool await_suspend(coroutine_handle handle) + bool await_suspend(std::coroutine_handle<> handle) { return m_deferrable.await_suspend(handle); } @@ -37,11 +37,9 @@ WINRT_EXPORT namespace winrt private: - using coroutine_handle = impl::coroutine_handle<>; - void one_deferral_completed() { - coroutine_handle resume = nullptr; + std::coroutine_handle<> resume = nullptr; { slim_lock_guard const guard(m_lock); @@ -62,7 +60,7 @@ WINRT_EXPORT namespace winrt } } - bool await_suspend(coroutine_handle handle) noexcept + bool await_suspend(std::coroutine_handle<> handle) noexcept { slim_lock_guard const guard(m_lock); m_handle = handle; @@ -71,7 +69,7 @@ WINRT_EXPORT namespace winrt slim_mutex m_lock; int32_t m_outstanding_deferrals = 0; - coroutine_handle m_handle = nullptr; + std::coroutine_handle<> m_handle = nullptr; }; -#endif } +#endif diff --git a/strings/base_includes.h b/strings/base_includes.h index 819e3c98f..a3bf308d1 100644 --- a/strings/base_includes.h +++ b/strings/base_includes.h @@ -48,31 +48,7 @@ #endif #ifdef __cpp_lib_coroutine - #include - -namespace winrt::impl -{ - template - using coroutine_handle = std::coroutine_handle; - - using suspend_always = std::suspend_always; - using suspend_never = std::suspend_never; -} - -#elif __has_include() - -#include - -namespace winrt::impl -{ - template - using coroutine_handle = std::experimental::coroutine_handle; - - using suspend_always = std::experimental::suspend_always; - using suspend_never = std::experimental::suspend_never; -} - -#else -#error C++/WinRT requires coroutine support, which is currently missing. Try enabling C++20 in your compiler. +#elif defined(_RESUMABLE_FUNCTIONS_SUPPORTED) +#error "C++/WinRT no longer supports pre-standardization coroutines. If you use co_await, switch to /await:strict or upgrade to C++20. If you do not, remove /await from the compiler flags." #endif diff --git a/strings/base_macros.h b/strings/base_macros.h index 0c4357b1e..3dc01fa2d 100644 --- a/strings/base_macros.h +++ b/strings/base_macros.h @@ -23,7 +23,7 @@ #pragma warning(disable : 4268) #endif -#if defined(__cpp_lib_coroutine) || defined(__cpp_coroutines) || defined(_RESUMABLE_FUNCTIONS_SUPPORTED) +#if defined(__cpp_lib_coroutine) #define WINRT_IMPL_COROUTINES #endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ed1515526..e5ca6e0fb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -105,6 +105,7 @@ set(SKIP_LARGE_PCH FALSE CACHE BOOL "Skip building large precompiled headers.") add_subdirectory(test) +add_subdirectory(test_nocoro) add_subdirectory(test_cpp20) add_subdirectory(test_cpp20_no_sourcelocation) diff --git a/test/old_tests/UnitTests/async.cpp b/test/old_tests/UnitTests/async.cpp index 037e16ab7..7a7382004 100644 --- a/test/old_tests/UnitTests/async.cpp +++ b/test/old_tests/UnitTests/async.cpp @@ -14,12 +14,6 @@ using namespace std::chrono; namespace { -#ifdef __cpp_lib_coroutine - using std::suspend_never; -#else - using std::experimental::suspend_never; -#endif - IAsyncAction NoSuspend_IAsyncAction() { co_await 0s; @@ -1118,7 +1112,7 @@ namespace { signal_done d{ go }; co_await resume_on_signal(go); - co_await suspend_never{}; + co_await std::suspend_never{}; REQUIRE(false); } @@ -1126,7 +1120,7 @@ namespace { signal_done d{ go }; co_await resume_on_signal(go); - co_await suspend_never{}; + co_await std::suspend_never{}; REQUIRE(false); } @@ -1134,7 +1128,7 @@ namespace { signal_done d{ go }; co_await resume_on_signal(go); - co_await suspend_never{}; + co_await std::suspend_never{}; REQUIRE(false); co_return 0; } @@ -1143,7 +1137,7 @@ namespace { signal_done d{ go }; co_await resume_on_signal(go); - co_await suspend_never{}; + co_await std::suspend_never{}; REQUIRE(false); co_return 0; } diff --git a/test/old_tests/UnitTests/weak.cpp b/test/old_tests/UnitTests/weak.cpp index 55c40dbe6..46b89bf6f 100644 --- a/test/old_tests/UnitTests/weak.cpp +++ b/test/old_tests/UnitTests/weak.cpp @@ -99,13 +99,13 @@ namespace // Returns an IAsyncAction that has not completed. // Call the resume() handle to complete it. - winrt::Windows::Foundation::IAsyncAction SuspendAction(impl::coroutine_handle<>& resume) + winrt::Windows::Foundation::IAsyncAction SuspendAction(std::coroutine_handle<>& resume) { struct awaiter { - impl::coroutine_handle<>& resume; + std::coroutine_handle<>& resume; bool await_ready() { return false; } - void await_suspend(impl::coroutine_handle<> handle) { resume = handle; } + void await_suspend(std::coroutine_handle<> handle) { resume = handle; } void await_resume() {} }; @@ -516,7 +516,7 @@ TEST_CASE("weak,coroutine") // Start a coroutine but don't complete it yet. // Confirm that weak references resolve. - impl::coroutine_handle<> resume; + std::coroutine_handle<> resume; weak = winrt::weak_ref(SuspendAction(resume)); REQUIRE(weak.get() != nullptr); // Now complete the coroutine. Confirm that weak references no longer resolve. diff --git a/test/test/async_auto_cancel.cpp b/test/test/async_auto_cancel.cpp index bffcb6e44..b0a541535 100644 --- a/test/test/async_auto_cancel.cpp +++ b/test/test/async_auto_cancel.cpp @@ -5,12 +5,6 @@ using namespace Windows::Foundation; namespace { -#ifdef __cpp_lib_coroutine - using std::suspend_never; -#else - using std::experimental::suspend_never; -#endif - // // Checks that the coroutine is automatically canceled when reaching a suspension point. // @@ -18,21 +12,21 @@ namespace IAsyncAction Action(HANDLE event) { co_await resume_on_signal(event); - co_await suspend_never(); + co_await std::suspend_never(); REQUIRE(false); } IAsyncActionWithProgress ActionWithProgress(HANDLE event) { co_await resume_on_signal(event); - co_await suspend_never(); + co_await std::suspend_never(); REQUIRE(false); } IAsyncOperation Operation(HANDLE event) { co_await resume_on_signal(event); - co_await suspend_never(); + co_await std::suspend_never(); REQUIRE(false); co_return 1; } @@ -40,7 +34,7 @@ namespace IAsyncOperationWithProgress OperationWithProgress(HANDLE event) { co_await resume_on_signal(event); - co_await suspend_never(); + co_await std::suspend_never(); REQUIRE(false); co_return 1; } @@ -54,7 +48,7 @@ namespace auto cancel = co_await get_cancellation_token(); cancel.callback(nullptr); - co_await suspend_never(); + co_await std::suspend_never(); REQUIRE(false); } diff --git a/test/test/async_cancel_callback.cpp b/test/test/async_cancel_callback.cpp index c99e1dad4..75a3aac0c 100644 --- a/test/test/async_cancel_callback.cpp +++ b/test/test/async_cancel_callback.cpp @@ -5,12 +5,6 @@ using namespace Windows::Foundation; namespace { -#ifdef __cpp_lib_coroutine - using std::suspend_never; -#else - using std::experimental::suspend_never; -#endif - // // Checks that the cancellation callback is invoked. // @@ -29,7 +23,7 @@ namespace }(); co_await resume_on_signal(event); - co_await suspend_never(); + co_await std::suspend_never(); REQUIRE(false); } @@ -44,7 +38,7 @@ namespace }); co_await resume_on_signal(event); - co_await suspend_never(); + co_await std::suspend_never(); REQUIRE(false); } @@ -59,7 +53,7 @@ namespace }); co_await resume_on_signal(event); - co_await suspend_never(); + co_await std::suspend_never(); REQUIRE(false); co_return 1; } @@ -75,7 +69,7 @@ namespace }); co_await resume_on_signal(event); - co_await suspend_never(); + co_await std::suspend_never(); REQUIRE(false); co_return 1; } diff --git a/test/test/async_check_cancel.cpp b/test/test/async_check_cancel.cpp index d88fdcaf0..c98519f06 100644 --- a/test/test/async_check_cancel.cpp +++ b/test/test/async_check_cancel.cpp @@ -5,12 +5,6 @@ using namespace Windows::Foundation; namespace { -#ifdef __cpp_lib_coroutine - using std::suspend_never; -#else - using std::experimental::suspend_never; -#endif - static bool s_exceptionLoggerCalled = false; static struct { @@ -48,7 +42,7 @@ namespace canceled = true; } - co_await suspend_never(); + co_await std::suspend_never(); REQUIRE(false); } @@ -63,7 +57,7 @@ namespace canceled = true; } - co_await suspend_never(); + co_await std::suspend_never(); REQUIRE(false); } @@ -78,7 +72,7 @@ namespace canceled = true; } - co_await suspend_never(); + co_await std::suspend_never(); REQUIRE(false); co_return 1; } @@ -95,7 +89,7 @@ namespace canceled = true; } - co_await suspend_never(); + co_await std::suspend_never(); REQUIRE(false); co_return 1; } @@ -120,7 +114,7 @@ namespace winrt_throw_hresult_handler = nullptr; s_exceptionLoggerCalled = false; - co_await suspend_never(); + co_await std::suspend_never(); REQUIRE(false); co_return; @@ -147,7 +141,7 @@ namespace winrt_throw_hresult_handler = nullptr; s_exceptionLoggerCalled = false; - co_await suspend_never(); + co_await std::suspend_never(); REQUIRE(false); co_return; diff --git a/test/test/when.cpp b/test/test/when.cpp index 35c9287a8..0b1151abc 100644 --- a/test/test/when.cpp +++ b/test/test/when.cpp @@ -5,13 +5,7 @@ using namespace concurrency; using namespace winrt; using namespace Windows::Foundation; -#ifdef __cpp_lib_coroutine -using std::suspend_never; -#else -using std::experimental::suspend_never; -#endif - -struct CommaStruct : suspend_never +struct CommaStruct : std::suspend_never { // If the comma operator is invoked, we will get a build failure. CommaStruct operator,(CommaStruct) = delete; diff --git a/test/test_nocoro/CMakeLists.txt b/test/test_nocoro/CMakeLists.txt new file mode 100644 index 000000000..ee234f146 --- /dev/null +++ b/test/test_nocoro/CMakeLists.txt @@ -0,0 +1,35 @@ +set(CMAKE_CXX_STANDARD 17) + +file(GLOB TEST_SRCS + LIST_DIRECTORIES false + CONFIGURE_DEPENDS + *.cpp +) +list(FILTER TEST_SRCS EXCLUDE REGEX "/(main|pch)\\.cpp") + + +list(APPEND BROKEN_TESTS + # No broken tests. +) + +# Exclude broken tests +foreach(TEST_SRCS_EXCLUDE_ITEM IN LISTS BROKEN_TESTS) + list(FILTER TEST_SRCS EXCLUDE REGEX "/${TEST_SRCS_EXCLUDE_ITEM}\\.cpp") +endforeach() + +add_executable(test_nocoro main.cpp ${TEST_SRCS}) + +target_compile_definitions(test_nocoro PRIVATE WINRT_NO_SOURCE_LOCATION) + +target_precompile_headers(test_nocoro PRIVATE pch.h) +set_source_files_properties( + main.cpp + PROPERTIES SKIP_PRECOMPILE_HEADERS true +) + +add_dependencies(test_nocoro build-cppwinrt-projection) + +add_test( + NAME test_nocoro + COMMAND "$" ${TEST_COLOR_ARG} +) diff --git a/test/test_nocoro/get.cpp b/test/test_nocoro/get.cpp new file mode 100644 index 000000000..11339e10b --- /dev/null +++ b/test/test_nocoro/get.cpp @@ -0,0 +1,74 @@ +#include "pch.h" + +using namespace winrt; +using namespace Windows::Foundation; + +template +struct async_completion_source : implements, IAsyncOperation, IAsyncInfo> +{ + void set_result(TResult result) + { + m_result = std::move(result); + m_status = AsyncStatus::Completed; + m_completed(*this, m_status); + } + + void Completed(AsyncOperationCompletedHandler completed) + { + m_completed = completed; + } + + AsyncOperationCompletedHandler Completed() const noexcept + { + return m_completed; + } + + TResult GetResults() + { + return m_result.value(); + } + + uint32_t Id() const + { + return 1; + } + + AsyncStatus Status() const + { + return m_status; + } + + hresult ErrorCode() const + { + return hresult(0); // S_OK + } + + void Cancel() const + { + throw hresult_error(0x80070032); // E_NOT_SUPPORTED + } + + void Close() const + { + } + +private: + AsyncStatus m_status = AsyncStatus::Started; + AsyncOperationCompletedHandler m_completed; + std::optional m_result; +}; + +TEST_CASE("get") +{ + auto acs = winrt::make_self>(); + + std::thread worker([acs] + { + std::this_thread::sleep_for(1s); + acs->set_result(0xDEADBEEF); + }); + + worker.detach(); + + REQUIRE(acs.as>().get() == 0xDEADBEEF); +} diff --git a/test/test_nocoro/main.cpp b/test/test_nocoro/main.cpp new file mode 100644 index 000000000..7590df7e1 --- /dev/null +++ b/test/test_nocoro/main.cpp @@ -0,0 +1,22 @@ +#include +#define CATCH_CONFIG_RUNNER +#include "catch.hpp" +#include "winrt/base.h" + +using namespace winrt; + +int main(int const argc, char** argv) +{ + init_apartment(); + std::set_terminate([] { reportFatal("Abnormal termination"); ExitProcess(1); }); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); + return Catch::Session().run(argc, argv); +} + +CATCH_TRANSLATE_EXCEPTION(hresult_error const& e) +{ + return to_string(e.message()); +} diff --git a/test/test_nocoro/pch.cpp b/test/test_nocoro/pch.cpp new file mode 100644 index 000000000..1d9f38c57 --- /dev/null +++ b/test/test_nocoro/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/test/test_nocoro/pch.h b/test/test_nocoro/pch.h new file mode 100644 index 000000000..7ff48a37c --- /dev/null +++ b/test/test_nocoro/pch.h @@ -0,0 +1,6 @@ +#pragma once + +#include "catch.hpp" +#include "winrt/Windows.Foundation.h" + +using namespace std::literals; diff --git a/test/test_nocoro/test_nocoro.vcxproj b/test/test_nocoro/test_nocoro.vcxproj new file mode 100644 index 000000000..7efc28066 --- /dev/null +++ b/test/test_nocoro/test_nocoro.vcxproj @@ -0,0 +1,241 @@ + + + + + Debug + ARM64 + + + Debug + Win32 + + + Release + ARM64 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {9E392830-805A-4AAF-932D-C493143EFACA} + unittests + test_nocoro + false + + + + Application + true + + + Application + true + + + Application + false + true + + + Application + false + true + + + Application + true + + + Application + false + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + MaxSpeed + true + true + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreaded + Level4 + true + + + Console + true + true + + + + + + + + + + + + + Disabled + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreadedDebug + Level4 + true + + + Console + + + + + + + + + + + + + Disabled + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreadedDebug + Level4 + true + + + Console + + + + + + + + + + + + + Disabled + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreadedDebug + Level4 + true + + + Console + + + + + + + + + + + + + MaxSpeed + true + true + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreaded + Level4 + true + + + Console + true + true + + + + + + + + + + + + + MaxSpeed + true + true + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreaded + Level4 + true + + + Console + true + true + + + + + + + + + + + + + + + + + NotUsing + + + Create + + + + + + \ No newline at end of file From 481f8f40816dd7c49a073de4b5d09191e5140e7f Mon Sep 17 00:00:00 2001 From: Yexuan Xiao Date: Tue, 17 Mar 2026 13:54:27 +0800 Subject: [PATCH 24/42] =?UTF-8?q?Add=20missing=20headers=20and=20std=20qua?= =?UTF-8?q?lification,=20use=20std::numeric=5Flimits=20in=E2=80=A6=20(#154?= =?UTF-8?q?6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add missing headers and std qualification, use std::numeric_limits instead of macros, and use std::memcpy/std::swprintf instead of the non-standard memcpy_s/swprintf_s * Remove a accidentally added redundant comment * Add some headers as suggested by Copilot * Use std::copy_n instead of std::memcpy, and protect std::numeric_limits::max from the max macro --- cppwinrt/cmd_reader.h | 31 +-- cppwinrt/code_writers.h | 84 +++--- cppwinrt/component_writers.h | 20 +- cppwinrt/helpers.h | 30 +-- cppwinrt/text_writer.h | 27 +- cppwinrt/type_writers.h | 22 +- strings/base_abi.h | 96 +++---- strings/base_activation.h | 74 +++--- strings/base_agile_ref.h | 4 +- strings/base_array.h | 64 ++--- strings/base_chrono.h | 10 +- strings/base_collections.h | 6 +- strings/base_collections_base.h | 50 ++-- strings/base_collections_map.h | 6 +- strings/base_collections_vector.h | 18 +- strings/base_com_ptr.h | 8 +- strings/base_coroutine_foundation.h | 14 +- strings/base_coroutine_threadpool.h | 52 ++-- strings/base_deferral.h | 2 +- strings/base_delegate.h | 18 +- strings/base_error.h | 22 +- strings/base_events.h | 26 +- strings/base_extern.h | 98 +++---- strings/base_fast_forward.h | 42 +-- strings/base_identity.h | 240 +++++++++--------- strings/base_implements.h | 150 +++++------ strings/base_includes.h | 5 + strings/base_iterator.h | 10 +- strings/base_lock.h | 2 +- strings/base_marshaler.h | 20 +- strings/base_natvis.h | 34 +-- strings/base_reference_produce.h | 126 ++++----- strings/base_security.h | 2 +- strings/base_std_hash.h | 22 +- strings/base_string.h | 84 +++--- strings/base_string_input.h | 8 +- strings/base_string_operators.h | 6 +- strings/base_types.h | 52 ++-- strings/base_version.h | 4 +- strings/base_windows.h | 6 +- strings/base_xaml_component_connector.h | 4 +- strings/base_xaml_component_connector_winui.h | 4 +- strings/base_xaml_typename.h | 16 +- 43 files changed, 814 insertions(+), 805 deletions(-) diff --git a/cppwinrt/cmd_reader.h b/cppwinrt/cmd_reader.h index 7faf49e4f..e2787b7d4 100644 --- a/cppwinrt/cmd_reader.h +++ b/cppwinrt/cmd_reader.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -203,7 +204,7 @@ namespace cppwinrt while (true) { - DWORD actual_size = GetModuleFileNameA(nullptr, path.data(), 1 + static_cast(path.size())); + DWORD actual_size = GetModuleFileNameA(nullptr, path.data(), 1 + static_cast(path.size())); if (actual_size < 1 + path.size()) { @@ -237,12 +238,12 @@ namespace cppwinrt } auto key = open_sdk(); - uint32_t index{}; + std::uint32_t index{}; std::array subkey; std::array version_parts{}; std::string result; - while (0 == RegEnumKeyA(key.handle, index++, subkey.data(), static_cast(subkey.size()))) + while (0 == RegEnumKeyA(key.handle, index++, subkey.data(), static_cast(subkey.size()))) { if (!std::regex_match(subkey.data(), match, rx)) { @@ -258,7 +259,7 @@ namespace cppwinrt char* next_part = subkey.data(); bool force_newer = false; - for (size_t i = 0; ; ++i) + for (std::size_t i = 0; ; ++i) { auto version_part = strtoul(next_part, &next_part, 10); @@ -312,19 +313,19 @@ namespace cppwinrt struct option { - static constexpr uint32_t no_min = 0; - static constexpr uint32_t no_max = UINT_MAX; + static constexpr std::uint32_t no_min = 0; + static constexpr std::uint32_t no_max = (std::numeric_limits::max)(); std::string_view name; - uint32_t min{ no_min }; - uint32_t max{ no_max }; + std::uint32_t min{ no_min }; + std::uint32_t max{ no_max }; std::string_view arg{}; std::string_view desc{}; }; struct reader { - template + template reader(C const argc, V const argv, const option(& options)[numOptions]) { #ifdef _DEBUG @@ -449,9 +450,9 @@ namespace cppwinrt #if defined(_WIN32) || defined(_WIN64) std::array local{}; #ifdef _WIN64 - ExpandEnvironmentStringsA("%windir%\\System32\\WinMetadata", local.data(), static_cast(local.size())); + ExpandEnvironmentStringsA("%windir%\\System32\\WinMetadata", local.data(), static_cast(local.size())); #else - ExpandEnvironmentStringsA("%windir%\\SysNative\\WinMetadata", local.data(), static_cast(local.size())); + ExpandEnvironmentStringsA("%windir%\\SysNative\\WinMetadata", local.data(), static_cast(local.size())); #endif add_directory(local.data()); #else /* defined(_WIN32) || defined(_WIN64) */ @@ -586,7 +587,7 @@ namespace cppwinrt std::filesystem::path response_path{ std::string{ arg } }; std::string extension = response_path.extension().generic_string(); std::transform(extension.begin(), extension.end(), extension.begin(), - [](auto c) { return static_cast(::tolower(c)); }); + [](auto c) { return static_cast(std::tolower(c)); }); // Check if misuse of @ prefix, so if directory or metadata file instead of response file. if (is_directory(response_path) || extension == ".winmd") @@ -597,12 +598,12 @@ namespace cppwinrt std::ifstream response_file(absolute(response_path)); while (getline(response_file, line_buf)) { - size_t argc = 0; + std::size_t argc = 0; std::vector argv; parse_command_line(line_buf.data(), argv, &argc); - for (size_t i = 0; i < argc; i++) + for (std::size_t i = 0; i < argc; i++) { extract_option(argv[i], options, last); } @@ -610,7 +611,7 @@ namespace cppwinrt } template - static void parse_command_line(Character* cmdstart, std::vector& argv, size_t* argument_count) + static void parse_command_line(Character* cmdstart, std::vector& argv, std::size_t* argument_count) { std::string arg; diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index e24cfd302..0a4c4638e 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -359,17 +359,17 @@ namespace cppwinrt using std::get; w.write_printf("0x%08X,0x%04X,0x%04X,{ 0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X }", - get(get(args[0].value).value), - get(get(args[1].value).value), - get(get(args[2].value).value), - get(get(args[3].value).value), - get(get(args[4].value).value), - get(get(args[5].value).value), - get(get(args[6].value).value), - get(get(args[7].value).value), - get(get(args[8].value).value), - get(get(args[9].value).value), - get(get(args[10].value).value)); + get(get(args[0].value).value), + get(get(args[1].value).value), + get(get(args[2].value).value), + get(get(args[3].value).value), + get(get(args[4].value).value), + get(get(args[5].value).value), + get(get(args[6].value).value), + get(get(args[7].value).value), + get(get(args[8].value).value), + get(get(args[9].value).value), + get(get(args[10].value).value)); } static void write_guid_comment(writer& w, std::vector const& args) @@ -377,17 +377,17 @@ namespace cppwinrt using std::get; w.write_printf("%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", - get(get(args[0].value).value), - get(get(args[1].value).value), - get(get(args[2].value).value), - get(get(args[3].value).value), - get(get(args[4].value).value), - get(get(args[5].value).value), - get(get(args[6].value).value), - get(get(args[7].value).value), - get(get(args[8].value).value), - get(get(args[9].value).value), - get(get(args[10].value).value)); + get(get(args[0].value).value), + get(get(args[1].value).value), + get(get(args[2].value).value), + get(get(args[3].value).value), + get(get(args[4].value).value), + get(get(args[5].value).value), + get(get(args[6].value).value), + get(get(args[7].value).value), + get(get(args[8].value).value), + get(get(args[9].value).value), + get(get(args[10].value).value)); } static void write_category(writer& w, TypeDef const& type, std::string_view const& category) @@ -561,15 +561,15 @@ namespace cppwinrt if (param.Flags().In()) { - format = "uint32_t%, %"; + format = "std::uint32_t%, %"; } else if (param_signature->ByRef()) { - format = "uint32_t*%, %*"; + format = "std::uint32_t*%, %*"; } else { - format = "uint32_t%, %"; + format = "std::uint32_t%, %"; } w.write(format, bind(param), bind(param_signature->Type())); @@ -605,7 +605,7 @@ namespace cppwinrt if (type.is_szarray()) { - w.write("uint32_t* __%Size, %**", method_signature.return_param_name(), type); + w.write("std::uint32_t* __%Size, %**", method_signature.return_param_name(), type); } else { @@ -748,7 +748,7 @@ namespace cppwinrt break; } - auto format = R"( virtual int32_t __stdcall %(%) noexcept = 0; + auto format = R"( virtual std::int32_t __stdcall %(%) noexcept = 0; )"; for (auto&& method : info.type.MethodList()) @@ -788,7 +788,7 @@ namespace cppwinrt } - auto format = R"( virtual int32_t __stdcall %(%) noexcept = 0; + auto format = R"( virtual std::int32_t __stdcall %(%) noexcept = 0; )"; auto abi_guard = w.push_abi_types(true); @@ -821,7 +821,7 @@ namespace cppwinrt { struct WINRT_IMPL_ABI_DECL type : unknown_abi { - virtual int32_t __stdcall Invoke(%) noexcept = 0; + virtual std::int32_t __stdcall Invoke(%) noexcept = 0; }; }; )"; @@ -1054,7 +1054,7 @@ namespace cppwinrt if (category == param_category::array_type) { auto format = R"( - uint32_t %_impl_size{}; + std::uint32_t %_impl_size{}; %* %{};)"; auto abi_guard = w.push_abi_types(true); @@ -1317,7 +1317,7 @@ namespace cppwinrt w.write(R"( auto data() const { - uint8_t* data{}; + std::uint8_t* data{}; static_cast(*this).template as()->Buffer(&data); return data; } @@ -1328,8 +1328,8 @@ namespace cppwinrt w.write(R"( auto data() const { - uint8_t* data{}; - uint32_t capacity{}; + std::uint8_t* data{}; + std::uint32_t capacity{}; check_hresult(static_cast(*this).template as()->GetBuffer(&data, &capacity)); return data; } @@ -1480,7 +1480,7 @@ namespace cppwinrt using iterator_concept = std::input_iterator_tag; using iterator_category = std::input_iterator_tag; using value_type = T; - using difference_type = ptrdiff_t; + using difference_type = std::ptrdiff_t; using pointer = void; using reference = T; )"); @@ -1491,7 +1491,7 @@ namespace cppwinrt using iterator_concept = std::input_iterator_tag; using iterator_category = std::input_iterator_tag; using value_type = Windows::Foundation::IInspectable; - using difference_type = ptrdiff_t; + using difference_type = std::ptrdiff_t; using pointer = void; using reference = Windows::Foundation::IInspectable; )"); @@ -1874,7 +1874,7 @@ namespace cppwinrt if (is_noexcept(method)) { - format = R"( int32_t __stdcall %(%) noexcept final + format = R"( std::int32_t __stdcall %(%) noexcept final { % typename D::abi_guard guard(this->shim()); % @@ -1884,7 +1884,7 @@ namespace cppwinrt } else { - format = R"( int32_t __stdcall %(%) noexcept final try + format = R"( std::int32_t __stdcall %(%) noexcept final try { % typename D::abi_guard guard(this->shim()); % @@ -1906,7 +1906,7 @@ namespace cppwinrt { // Special-case IMap*::Lookup to look for a TryLookup here, to avoid extranous throw/originates std::string tryLookupUpCall = "this->shim().TryLookup"; - format = R"( int32_t __stdcall %(%) noexcept final try + format = R"( std::int32_t __stdcall %(%) noexcept final try { % typename D::abi_guard guard(this->shim()); if constexpr (has_TryLookup_v) @@ -2596,7 +2596,7 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable { delegate(H&& handler) : implements_delegate<%, H>(std::forward(handler)) {} - int32_t __stdcall Invoke(%) noexcept final try + std::int32_t __stdcall Invoke(%) noexcept final try { % % return 0; @@ -2801,7 +2801,7 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable static void write_struct_equality(writer& w, std::vector> const& fields) { - for (size_t i = 0; i != fields.size(); ++i) + for (std::size_t i = 0; i != fields.size(); ++i) { w.write(" left.% == right.%", fields[i].first, fields[i].first); @@ -2877,9 +2877,9 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable return false; }; - for (size_t left = 0; left < structs.size(); ++left) + for (std::size_t left = 0; left < structs.size(); ++left) { - for (size_t right = left + 1; right < structs.size(); ++right) + for (std::size_t right = left + 1; right < structs.size(); ++right) { if (depends(w, structs[left], structs[right])) { diff --git a/cppwinrt/component_writers.h b/cppwinrt/component_writers.h index cb748917d..3966cad6c 100644 --- a/cppwinrt/component_writers.h +++ b/cppwinrt/component_writers.h @@ -172,7 +172,7 @@ void* __stdcall %_get_activation_factory([[maybe_unused]] std::wstring_view cons } format = R"( -int32_t __stdcall WINRT_CanUnloadNow() noexcept +std::int32_t __stdcall WINRT_CanUnloadNow() noexcept { #ifdef _WRL_MODULE_H_ #ifdef _MSC_VER @@ -187,7 +187,7 @@ int32_t __stdcall WINRT_CanUnloadNow() noexcept return %_can_unload_now() ? 0 : 1; } -int32_t __stdcall WINRT_GetActivationFactory(void* classId, void** factory) noexcept try +std::int32_t __stdcall WINRT_GetActivationFactory(void* classId, void** factory) noexcept try { std::wstring_view const name{ *reinterpret_cast(&classId) }; *factory = %_get_activation_factory(name); @@ -640,7 +640,7 @@ catch (...) { return winrt::to_hresult(); } } )"; - size_t offset = get_bases(type).size(); + std::size_t offset = get_bases(type).size(); auto interfaces = get_interfaces(w, type); for (auto&& [name, info] : interfaces) @@ -685,7 +685,7 @@ catch (...) { return winrt::to_hresult(); } if (has_base) { auto format = R"( - int32_t query_interface_tearoff(guid const& id, void** result) const noexcept override + std::int32_t query_interface_tearoff(guid const& id, void** result) const noexcept override {% return B::query_interface_tearoff(id, result); } @@ -701,7 +701,7 @@ catch (...) { return winrt::to_hresult(); } } auto format = R"( - int32_t query_interface_tearoff(guid const& id, void** result) const noexcept override + std::int32_t query_interface_tearoff(guid const& id, void** result) const noexcept override {% return impl::error_no_interface; } @@ -779,8 +779,8 @@ catch (...) { return winrt::to_hresult(); } { composable_base_name = w.write_temp("using composable_base = %;", base_type); auto base_interfaces = get_interfaces(w, base_type); - uint32_t base_interfaces_count{}; - uint32_t protected_base_interfaces_count{}; + std::uint32_t base_interfaces_count{}; + std::uint32_t protected_base_interfaces_count{}; external_requires = ",\n impl::require(::toupper(c)); }); + std::transform(upper.begin(), upper.end(), upper.begin(), [](char c) {return static_cast(std::toupper(c)); }); auto include_path = get_generated_component_filename(type); @@ -1240,7 +1240,7 @@ namespace winrt::@::implementation static void write_component_fast_abi_thunk(writer& w) { - for (uint32_t slot = 6; slot < 1024; ++slot) + for (std::uint32_t slot = 6; slot < 1024; ++slot) { auto format = R"( extern "C" void __stdcall winrt_ff_thunk%(); )"; @@ -1251,7 +1251,7 @@ namespace winrt::@::implementation static void write_component_fast_abi_vtable(writer& w) { - for (uint32_t slot = 6; slot < 1024; ++slot) + for (std::uint32_t slot = 6; slot < 1024; ++slot) { auto format = R"( #if WINRT_FAST_ABI_SIZE > % diff --git a/cppwinrt/helpers.h b/cppwinrt/helpers.h index 522d0bcd1..2dc152a74 100644 --- a/cppwinrt/helpers.h +++ b/cppwinrt/helpers.h @@ -31,7 +31,7 @@ namespace cppwinrt ++params.first; } - for (uint32_t i{}; i != size(m_signature.Params()); ++i) + for (std::uint32_t i{}; i != size(m_signature.Params()); ++i) { m_params.emplace_back(params.first + i, &m_signature.Params().first[i]); } @@ -193,7 +193,7 @@ namespace cppwinrt } template - auto get_attribute_value(CustomAttribute const& attribute, uint32_t const arg) + auto get_attribute_value(CustomAttribute const& attribute, std::uint32_t const arg) { return get_attribute_value(attribute.Value().FixedArgs()[arg]); } @@ -330,15 +330,15 @@ namespace cppwinrt struct contract_version { std::string_view name; - uint32_t version; + std::uint32_t version; }; struct previous_contract { std::string_view contract_from; std::string_view contract_to; - uint32_t version_low; - uint32_t version_high; + std::uint32_t version_low; + std::uint32_t version_high; }; struct contract_history @@ -359,7 +359,7 @@ namespace cppwinrt assert(args.size() == 2); contract_version result{}; - result.version = get_integer_attribute(args[1]); + result.version = get_integer_attribute(args[1]); call(std::get(args[0].value).value, [&](ElemSig::SystemType t) { @@ -388,8 +388,8 @@ namespace cppwinrt previous_contract result{}; result.contract_from = get_attribute_value(args[0]); - result.version_low = get_integer_attribute(args[1]); - result.version_high = get_integer_attribute(args[2]); + result.version_low = get_integer_attribute(args[1]); + result.version_high = get_integer_attribute(args[2]); if (args.size() == 4) { result.contract_to = get_attribute_value(args[3]); @@ -452,7 +452,7 @@ namespace cppwinrt // is not a contract version if (current_contract.name.empty()) { - current_contract.version = get_attribute_value(attribute, 0); + current_contract.version = get_attribute_value(attribute, 0); } } } @@ -509,7 +509,7 @@ namespace cppwinrt } assert(result.previous_contracts.back().contract_to == result.current_contract.name); - for (size_t size = result.previous_contracts.size() - 1; size; --size) + for (std::size_t size = result.previous_contracts.size() - 1; size; --size) { auto& last = result.previous_contracts[size]; auto itr = std::find_if(result.previous_contracts.begin(), result.previous_contracts.begin() + size, [&](auto const& prev) @@ -537,7 +537,7 @@ namespace cppwinrt // in relative to the contract history of the class. E.g. if a class goes from contract 'A' to 'B' to 'C', // 'relativeContract' would be '0' for an interface introduced in contract 'A', '1' for an interface introduced // in contract 'B', etc. This is only set/valid for 'fastabi' interfaces - std::pair relative_version{}; + std::pair relative_version{}; std::vector> generic_param_stack{}; }; @@ -660,7 +660,7 @@ namespace cppwinrt } auto history = get_contract_history(type); - size_t count = 0; + std::size_t count = 0; for (auto& pair : result) { if (pair.second.exclusive && !pair.second.base && !pair.second.overridable) @@ -676,12 +676,12 @@ namespace cppwinrt }); if (itr != history.previous_contracts.end()) { - pair.second.relative_version.first = static_cast(itr - history.previous_contracts.begin()); + pair.second.relative_version.first = static_cast(itr - history.previous_contracts.begin()); } else { assert(history.current_contract.name == introduced.name); - pair.second.relative_version.first = static_cast(history.previous_contracts.size()); + pair.second.relative_version.first = static_cast(history.previous_contracts.size()); } } } @@ -863,7 +863,7 @@ namespace cppwinrt { if (auto visibility = std::get_if(&std::get(arg.value).value)) { - info.visible = std::get(visibility->value) == 2; + info.visible = std::get(visibility->value) == 2; break; } } diff --git a/cppwinrt/text_writer.h b/cppwinrt/text_writer.h index 0b7c07a4e..a274d11ce 100644 --- a/cppwinrt/text_writer.h +++ b/cppwinrt/text_writer.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -66,7 +67,7 @@ namespace cppwinrt #if defined(_DEBUG) if (debug_trace) { - ::printf("%.*s", static_cast(value.size()), value.data()); + std::printf("%.*s", static_cast(value.size()), value.data()); } #endif } @@ -78,7 +79,7 @@ namespace cppwinrt #if defined(_DEBUG) if (debug_trace) { - ::printf("%c", value); + std::printf("%c", value); } #endif } @@ -139,12 +140,12 @@ namespace cppwinrt { char buffer[128]; #if defined(_WIN32) || defined(_WIN64) - size_t const size = sprintf_s(buffer, format, args...); + std::size_t const size = sprintf_s(buffer, format, args...); #else - size_t size = snprintf(buffer, sizeof(buffer), format, args...); + std::size_t size = std::snprintf(buffer, sizeof(buffer), format, args...); if (size > sizeof(buffer) - 1) { - fprintf(stderr, "\n*** WARNING: writer_base::write_printf -- buffer too small\n"); + std::fprintf(stderr, "\n*** WARNING: writer_base::write_printf -- buffer too small\n"); size = sizeof(buffer) - 1; } #endif @@ -167,8 +168,8 @@ namespace cppwinrt void flush_to_console(bool to_stdout = true) noexcept { - fprintf(to_stdout ? stdout : stderr, "%.*s", static_cast(m_first.size()), m_first.data()); - fprintf(to_stdout ? stdout : stderr, "%.*s", static_cast(m_second.size()), m_second.data()); + std::fprintf(to_stdout ? stdout : stderr, "%.*s", static_cast(m_first.size()), m_first.data()); + std::fprintf(to_stdout ? stdout : stderr, "%.*s", static_cast(m_second.size()), m_second.data()); m_first.clear(); m_second.clear(); } @@ -243,9 +244,9 @@ namespace cppwinrt private: - static constexpr uint32_t count_placeholders(std::string_view const& format) noexcept + static constexpr std::uint32_t count_placeholders(std::string_view const& format) noexcept { - uint32_t count{}; + std::uint32_t count{}; bool escape{}; for (auto c : format) @@ -332,7 +333,7 @@ namespace cppwinrt { struct indent_guard { - indent_guard(indented_writer_base& w, int32_t offset = 1) noexcept : m_writer(w), m_offset(offset) + indent_guard(indented_writer_base& w, std::int32_t offset = 1) noexcept : m_writer(w), m_offset(offset) { m_writer.m_indent += m_offset; } @@ -344,13 +345,13 @@ namespace cppwinrt private: indented_writer_base& m_writer; - int32_t m_offset{}; + std::int32_t m_offset{}; }; void write_indent() { - for (int32_t i = 0; i < m_indent; i++) + for (std::int32_t i = 0; i < m_indent; i++) { writer_base::write_impl(" "); } @@ -418,7 +419,7 @@ namespace cppwinrt return result; } - int32_t m_indent{}; + std::int32_t m_indent{}; }; diff --git a/cppwinrt/type_writers.h b/cppwinrt/type_writers.h index 0fa3e5f8d..df17450f1 100644 --- a/cppwinrt/type_writers.h +++ b/cppwinrt/type_writers.h @@ -232,12 +232,12 @@ namespace cppwinrt return member_value_guard(this, &writer::delegate_types, value); } - void write_value(int32_t value) + void write_value(std::int32_t value) { write_printf("%d", value); } - void write_value(uint32_t value) + void write_value(std::uint32_t value) { write_printf("%#0x", value); } @@ -309,7 +309,7 @@ namespace cppwinrt { if ((name == "DateTime" || name == "TimeSpan") && ns == "Windows.Foundation") { - write("int64_t"); + write("std::int64_t"); } else if ((name == "Point" || name == "Size" || name == "Rect") && ns == "Windows.Foundation") { @@ -473,14 +473,14 @@ namespace cppwinrt { if (type == ElementType::Boolean) { write("bool"); } else if (type == ElementType::Char) { write("char16_t"); } - else if (type == ElementType::I1) { write("int8_t"); } - else if (type == ElementType::U1) { write("uint8_t"); } - else if (type == ElementType::I2) { write("int16_t"); } - else if (type == ElementType::U2) { write("uint16_t"); } - else if (type == ElementType::I4) { write("int32_t"); } - else if (type == ElementType::U4) { write("uint32_t"); } - else if (type == ElementType::I8) { write("int64_t"); } - else if (type == ElementType::U8) { write("uint64_t"); } + else if (type == ElementType::I1) { write("std::int8_t"); } + else if (type == ElementType::U1) { write("std::uint8_t"); } + else if (type == ElementType::I2) { write("std::int16_t"); } + else if (type == ElementType::U2) { write("std::uint16_t"); } + else if (type == ElementType::I4) { write("std::int32_t"); } + else if (type == ElementType::U4) { write("std::uint32_t"); } + else if (type == ElementType::I8) { write("std::int64_t"); } + else if (type == ElementType::U8) { write("std::uint64_t"); } else if (type == ElementType::R4) { write("float"); } else if (type == ElementType::R8) { write("double"); } else if (type == ElementType::String) diff --git a/strings/base_abi.h b/strings/base_abi.h index ec42fefe6..72946a3fa 100644 --- a/strings/base_abi.h +++ b/strings/base_abi.h @@ -5,9 +5,9 @@ namespace winrt::impl { struct WINRT_IMPL_ABI_DECL type { - virtual int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept = 0; - virtual uint32_t __stdcall AddRef() noexcept = 0; - virtual uint32_t __stdcall Release() noexcept = 0; + virtual std::int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept = 0; + virtual std::uint32_t __stdcall AddRef() noexcept = 0; + virtual std::uint32_t __stdcall Release() noexcept = 0; }; }; @@ -17,9 +17,9 @@ namespace winrt::impl { struct WINRT_IMPL_ABI_DECL type : unknown_abi { - virtual int32_t __stdcall GetIids(uint32_t* count, guid** ids) noexcept = 0; - virtual int32_t __stdcall GetRuntimeClassName(void** name) noexcept = 0; - virtual int32_t __stdcall GetTrustLevel(Windows::Foundation::TrustLevel* level) noexcept = 0; + virtual std::int32_t __stdcall GetIids(std::uint32_t* count, guid** ids) noexcept = 0; + virtual std::int32_t __stdcall GetRuntimeClassName(void** name) noexcept = 0; + virtual std::int32_t __stdcall GetTrustLevel(Windows::Foundation::TrustLevel* level) noexcept = 0; }; }; @@ -29,7 +29,7 @@ namespace winrt::impl { struct WINRT_IMPL_ABI_DECL type : inspectable_abi { - virtual int32_t __stdcall ActivateInstance(void** instance) noexcept = 0; + virtual std::int32_t __stdcall ActivateInstance(void** instance) noexcept = 0; }; }; @@ -37,109 +37,109 @@ namespace winrt::impl struct WINRT_IMPL_ABI_DECL IAgileReference : unknown_abi { - virtual int32_t __stdcall Resolve(guid const& id, void** object) noexcept = 0; + virtual std::int32_t __stdcall Resolve(guid const& id, void** object) noexcept = 0; }; struct WINRT_IMPL_ABI_DECL IMarshal : unknown_abi { - virtual int32_t __stdcall GetUnmarshalClass(guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags, guid* pCid) noexcept = 0; - virtual int32_t __stdcall GetMarshalSizeMax(guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags, uint32_t* pSize) noexcept = 0; - virtual int32_t __stdcall MarshalInterface(void* pStm, guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags) noexcept = 0; - virtual int32_t __stdcall UnmarshalInterface(void* pStm, guid const& riid, void** ppv) noexcept = 0; - virtual int32_t __stdcall ReleaseMarshalData(void* pStm) noexcept = 0; - virtual int32_t __stdcall DisconnectObject(uint32_t dwReserved) noexcept = 0; + virtual std::int32_t __stdcall GetUnmarshalClass(guid const& riid, void* pv, std::uint32_t dwDestContext, void* pvDestContext, std::uint32_t mshlflags, guid* pCid) noexcept = 0; + virtual std::int32_t __stdcall GetMarshalSizeMax(guid const& riid, void* pv, std::uint32_t dwDestContext, void* pvDestContext, std::uint32_t mshlflags, std::uint32_t* pSize) noexcept = 0; + virtual std::int32_t __stdcall MarshalInterface(void* pStm, guid const& riid, void* pv, std::uint32_t dwDestContext, void* pvDestContext, std::uint32_t mshlflags) noexcept = 0; + virtual std::int32_t __stdcall UnmarshalInterface(void* pStm, guid const& riid, void** ppv) noexcept = 0; + virtual std::int32_t __stdcall ReleaseMarshalData(void* pStm) noexcept = 0; + virtual std::int32_t __stdcall DisconnectObject(std::uint32_t dwReserved) noexcept = 0; }; struct WINRT_IMPL_ABI_DECL IGlobalInterfaceTable : unknown_abi { - virtual int32_t __stdcall RegisterInterfaceInGlobal(void* object, guid const& iid, uint32_t* cookie) noexcept = 0; - virtual int32_t __stdcall RevokeInterfaceFromGlobal(uint32_t cookie) noexcept = 0; - virtual int32_t __stdcall GetInterfaceFromGlobal(uint32_t cookie, guid const& iid, void** object) noexcept = 0; + virtual std::int32_t __stdcall RegisterInterfaceInGlobal(void* object, guid const& iid, std::uint32_t* cookie) noexcept = 0; + virtual std::int32_t __stdcall RevokeInterfaceFromGlobal(std::uint32_t cookie) noexcept = 0; + virtual std::int32_t __stdcall GetInterfaceFromGlobal(std::uint32_t cookie, guid const& iid, void** object) noexcept = 0; }; struct WINRT_IMPL_ABI_DECL IStaticLifetime : inspectable_abi { - virtual int32_t __stdcall unused() noexcept = 0; - virtual int32_t __stdcall GetCollection(void** value) noexcept = 0; + virtual std::int32_t __stdcall unused() noexcept = 0; + virtual std::int32_t __stdcall GetCollection(void** value) noexcept = 0; }; struct WINRT_IMPL_ABI_DECL IStaticLifetimeCollection : inspectable_abi { - virtual int32_t __stdcall Lookup(void*, void**) noexcept = 0; - virtual int32_t __stdcall unused() noexcept = 0; - virtual int32_t __stdcall unused2() noexcept = 0; - virtual int32_t __stdcall unused3() noexcept = 0; - virtual int32_t __stdcall Insert(void*, void*, bool*) noexcept = 0; - virtual int32_t __stdcall Remove(void*) noexcept = 0; - virtual int32_t __stdcall unused4() noexcept = 0; + virtual std::int32_t __stdcall Lookup(void*, void**) noexcept = 0; + virtual std::int32_t __stdcall unused() noexcept = 0; + virtual std::int32_t __stdcall unused2() noexcept = 0; + virtual std::int32_t __stdcall unused3() noexcept = 0; + virtual std::int32_t __stdcall Insert(void*, void*, bool*) noexcept = 0; + virtual std::int32_t __stdcall Remove(void*) noexcept = 0; + virtual std::int32_t __stdcall unused4() noexcept = 0; }; struct WINRT_IMPL_ABI_DECL IWeakReference : unknown_abi { - virtual int32_t __stdcall Resolve(guid const& iid, void** objectReference) noexcept = 0; + virtual std::int32_t __stdcall Resolve(guid const& iid, void** objectReference) noexcept = 0; }; struct WINRT_IMPL_ABI_DECL IWeakReferenceSource : unknown_abi { - virtual int32_t __stdcall GetWeakReference(IWeakReference** weakReference) noexcept = 0; + virtual std::int32_t __stdcall GetWeakReference(IWeakReference** weakReference) noexcept = 0; }; struct WINRT_IMPL_ABI_DECL IRestrictedErrorInfo : unknown_abi { - virtual int32_t __stdcall GetErrorDetails(bstr* description, int32_t* error, bstr* restrictedDescription, bstr* capabilitySid) noexcept = 0; - virtual int32_t __stdcall GetReference(bstr* reference) noexcept = 0; + virtual std::int32_t __stdcall GetErrorDetails(bstr* description, std::int32_t* error, bstr* restrictedDescription, bstr* capabilitySid) noexcept = 0; + virtual std::int32_t __stdcall GetReference(bstr* reference) noexcept = 0; }; struct WINRT_IMPL_ABI_DECL IErrorInfo : unknown_abi { - virtual int32_t __stdcall GetGUID(guid* value) noexcept = 0; - virtual int32_t __stdcall GetSource(bstr* value) noexcept = 0; - virtual int32_t __stdcall GetDescription(bstr* value) noexcept = 0; - virtual int32_t __stdcall GetHelpFile(bstr* value) noexcept = 0; - virtual int32_t __stdcall GetHelpContext(uint32_t* value) noexcept = 0; + virtual std::int32_t __stdcall GetGUID(guid* value) noexcept = 0; + virtual std::int32_t __stdcall GetSource(bstr* value) noexcept = 0; + virtual std::int32_t __stdcall GetDescription(bstr* value) noexcept = 0; + virtual std::int32_t __stdcall GetHelpFile(bstr* value) noexcept = 0; + virtual std::int32_t __stdcall GetHelpContext(std::uint32_t* value) noexcept = 0; }; struct WINRT_IMPL_ABI_DECL ILanguageExceptionErrorInfo2 : unknown_abi { - virtual int32_t __stdcall GetLanguageException(void** exception) noexcept = 0; - virtual int32_t __stdcall GetPreviousLanguageExceptionErrorInfo(ILanguageExceptionErrorInfo2** previous) noexcept = 0; - virtual int32_t __stdcall CapturePropagationContext(void* exception) noexcept = 0; - virtual int32_t __stdcall GetPropagationContextHead(ILanguageExceptionErrorInfo2** head) noexcept = 0; + virtual std::int32_t __stdcall GetLanguageException(void** exception) noexcept = 0; + virtual std::int32_t __stdcall GetPreviousLanguageExceptionErrorInfo(ILanguageExceptionErrorInfo2** previous) noexcept = 0; + virtual std::int32_t __stdcall CapturePropagationContext(void* exception) noexcept = 0; + virtual std::int32_t __stdcall GetPropagationContextHead(ILanguageExceptionErrorInfo2** head) noexcept = 0; }; struct ICallbackWithNoReentrancyToApplicationSTA; struct WINRT_IMPL_ABI_DECL IContextCallback : unknown_abi { - virtual int32_t __stdcall ContextCallback(int32_t(__stdcall* callback)(com_callback_args*), com_callback_args* args, guid const& iid, int method, void* reserved) noexcept = 0; + virtual std::int32_t __stdcall ContextCallback(std::int32_t(__stdcall* callback)(com_callback_args*), com_callback_args* args, guid const& iid, int method, void* reserved) noexcept = 0; }; struct WINRT_IMPL_ABI_DECL IServerSecurity : unknown_abi { - virtual int32_t __stdcall QueryBlanket(uint32_t*, uint32_t*, wchar_t**, uint32_t*, uint32_t*, void**, uint32_t*) noexcept = 0; - virtual int32_t __stdcall ImpersonateClient() noexcept = 0; - virtual int32_t __stdcall RevertToSelf() noexcept = 0; - virtual int32_t __stdcall IsImpersonating() noexcept = 0; + virtual std::int32_t __stdcall QueryBlanket(std::uint32_t*, std::uint32_t*, wchar_t**, std::uint32_t*, std::uint32_t*, void**, std::uint32_t*) noexcept = 0; + virtual std::int32_t __stdcall ImpersonateClient() noexcept = 0; + virtual std::int32_t __stdcall RevertToSelf() noexcept = 0; + virtual std::int32_t __stdcall IsImpersonating() noexcept = 0; }; struct WINRT_IMPL_ABI_DECL IBufferByteAccess : unknown_abi { - virtual int32_t __stdcall Buffer(uint8_t** value) noexcept = 0; + virtual std::int32_t __stdcall Buffer(std::uint8_t** value) noexcept = 0; }; struct WINRT_IMPL_ABI_DECL IMemoryBufferByteAccess : unknown_abi { - virtual int32_t __stdcall GetBuffer(uint8_t** value, uint32_t* capacity) noexcept = 0; + virtual std::int32_t __stdcall GetBuffer(std::uint8_t** value, std::uint32_t* capacity) noexcept = 0; }; template <> struct abi { - using type = int64_t; + using type = std::int64_t; }; template <> struct abi { - using type = int64_t; + using type = std::int64_t; }; template <> inline constexpr guid guid_v{ 0x00000000, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } }; diff --git a/strings/base_activation.h b/strings/base_activation.h index 586df32e9..1a195d865 100644 --- a/strings/base_activation.h +++ b/strings/base_activation.h @@ -30,7 +30,7 @@ namespace winrt::impl if (hr == impl::error_not_initialized) { - auto usage = reinterpret_cast(WINRT_IMPL_GetProcAddress(load_library(L"combase.dll"), "CoIncrementMTAUsage")); + auto usage = reinterpret_cast(WINRT_IMPL_GetProcAddress(load_library(L"combase.dll"), "CoIncrementMTAUsage")); if (!usage) { @@ -65,7 +65,7 @@ namespace winrt::impl continue; } - auto library_call = reinterpret_cast(WINRT_IMPL_GetProcAddress(library.get(), "DllGetActivationFactory")); + auto library_call = reinterpret_cast(WINRT_IMPL_GetProcAddress(library.get(), "DllGetActivationFactory")); if (!library_call) { @@ -127,17 +127,17 @@ WINRT_EXPORT namespace winrt namespace winrt::impl { - inline int32_t interlocked_read_32(int32_t const volatile* target) noexcept + inline std::int32_t interlocked_read_32(std::int32_t const volatile* target) noexcept { #if defined _M_IX86 || defined _M_X64 - int32_t const result = *target; + std::int32_t const result = *target; _ReadWriteBarrier(); return result; #elif defined _M_ARM64 #if defined(__GNUC__) - int32_t const result = *target; + std::int32_t const result = *target; #else - int32_t const result = __iso_volatile_load32(reinterpret_cast(target)); + std::int32_t const result = __iso_volatile_load32(reinterpret_cast(target)); #endif WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER return result; @@ -147,17 +147,17 @@ namespace winrt::impl } #if defined _WIN64 - inline int64_t interlocked_read_64(int64_t const volatile* target) noexcept + inline std::int64_t interlocked_read_64(std::int64_t const volatile* target) noexcept { #if defined _M_X64 - int64_t const result = *target; + std::int64_t const result = *target; _ReadWriteBarrier(); return result; #elif defined _M_ARM64 #if defined(__GNUC__) - int64_t const result = *target; + std::int64_t const result = *target; #else - int64_t const result = __iso_volatile_load64(target); + std::int64_t const result = __iso_volatile_load64(target); #endif WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER return result; @@ -177,14 +177,14 @@ namespace winrt::impl T* interlocked_read_pointer(T* const volatile* target) noexcept { #ifdef _WIN64 - return (T*)interlocked_read_64((int64_t*)target); + return (T*)interlocked_read_64((std::int64_t*)target); #else - return (T*)interlocked_read_32((int32_t*)target); + return (T*)interlocked_read_32((std::int32_t*)target); #endif } #ifdef _WIN64 - inline constexpr uint32_t memory_allocation_alignment{ 16 }; + inline constexpr std::uint32_t memory_allocation_alignment{ 16 }; #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4324) // structure was padded due to alignment specifier @@ -197,34 +197,34 @@ namespace winrt::impl { struct { - uint64_t reserved1; - uint64_t reserved2; + std::uint64_t reserved1; + std::uint64_t reserved2; } reserved1; struct { - uint64_t reserved1 : 16; - uint64_t reserved2 : 48; - uint64_t reserved3 : 4; - uint64_t reserved4 : 60; + std::uint64_t reserved1 : 16; + std::uint64_t reserved2 : 48; + std::uint64_t reserved3 : 4; + std::uint64_t reserved4 : 60; } reserved2; }; #ifdef _MSC_VER #pragma warning(pop) #endif #else - inline constexpr uint32_t memory_allocation_alignment{ 8 }; + inline constexpr std::uint32_t memory_allocation_alignment{ 8 }; struct slist_entry { slist_entry* next; }; union slist_header { - uint64_t reserved1; + std::uint64_t reserved1; struct { slist_entry reserved1; - uint16_t reserved2; - uint16_t reserved3; + std::uint16_t reserved2; + std::uint16_t reserved3; } reserved2; }; #endif @@ -234,11 +234,11 @@ namespace winrt::impl factory_count_guard(factory_count_guard const&) = delete; factory_count_guard& operator=(factory_count_guard const&) = delete; - explicit factory_count_guard(size_t& count) noexcept : m_count(count) + explicit factory_count_guard(std::size_t& count) noexcept : m_count(count) { #ifndef WINRT_NO_MODULE_LOCK #ifdef _WIN64 - _InterlockedIncrement64((int64_t*)&m_count); + _InterlockedIncrement64((std::int64_t*)&m_count); #else _InterlockedIncrement((long*)&m_count); #endif @@ -249,7 +249,7 @@ namespace winrt::impl { #ifndef WINRT_NO_MODULE_LOCK #ifdef _WIN64 - _InterlockedDecrement64((int64_t*)&m_count); + _InterlockedDecrement64((std::int64_t*)&m_count); #else _InterlockedDecrement((long*)&m_count); #endif @@ -257,7 +257,7 @@ namespace winrt::impl } private: - [[maybe_unused]] size_t& m_count; // Field is unused when WINRT_NO_MODULE_LOCK is defined. + [[maybe_unused]] std::size_t& m_count; // Field is unused when WINRT_NO_MODULE_LOCK is defined. }; struct factory_cache_entry_base @@ -265,7 +265,7 @@ namespace winrt::impl struct alignas(sizeof(void*) * 2) object_and_count { unknown_abi* object; - size_t count; + std::size_t count; }; object_and_count m_value; @@ -286,16 +286,16 @@ namespace winrt::impl #if defined(__GNUC__) bool exchanged = __sync_bool_compare_and_swap((__int128*)this, *(__int128*)¤t_value, (__int128)0); #else - bool exchanged = 1 == _InterlockedCompareExchange128((int64_t*)this, 0, 0, (int64_t*)¤t_value); + bool exchanged = 1 == _InterlockedCompareExchange128((std::int64_t*)this, 0, 0, (std::int64_t*)¤t_value); #endif if (exchanged) { pointer_value->Release(); } #else - int64_t const result = _InterlockedCompareExchange64((int64_t*)this, 0, *(int64_t*)¤t_value); + std::int64_t const result = _InterlockedCompareExchange64((std::int64_t*)this, 0, *(std::int64_t*)¤t_value); - if (result == *(int64_t*)¤t_value) + if (result == *(std::int64_t*)¤t_value) { pointer_value->Release(); } @@ -330,7 +330,7 @@ namespace winrt::impl // entry->next must be read before entry->clear() is called since the InterlockedCompareExchange // inside clear() will allow another thread to add the entry back to the cache. slist_entry* next = entry->next; - reinterpret_cast(reinterpret_cast(entry) - offsetof(factory_cache_entry_base, m_next))->clear(); + reinterpret_cast(reinterpret_cast(entry) - offsetof(factory_cache_entry_base, m_next))->clear(); entry = next; } } @@ -443,7 +443,7 @@ namespace winrt::impl template struct produce : produce_base { - int32_t __stdcall ActivateInstance(void** instance) noexcept final try + std::int32_t __stdcall ActivateInstance(void** instance) noexcept final try { *instance = nullptr; typename D::abi_guard guard(this->shim()); @@ -456,7 +456,7 @@ namespace winrt::impl WINRT_EXPORT namespace winrt { - enum class apartment_type : int32_t + enum class apartment_type : std::int32_t { multi_threaded = 0, single_threaded = 2, @@ -464,7 +464,7 @@ WINRT_EXPORT namespace winrt inline void init_apartment(apartment_type const type = apartment_type::multi_threaded) { - hresult const result = WINRT_IMPL_CoInitializeEx(nullptr, static_cast(type)); + hresult const result = WINRT_IMPL_CoInitializeEx(nullptr, static_cast(type)); if (result < 0) { @@ -519,13 +519,13 @@ WINRT_EXPORT namespace winrt } template - auto try_create_instance(guid const& clsid, uint32_t context = 0x1 /*CLSCTX_INPROC_SERVER*/, void* outer = nullptr) + auto try_create_instance(guid const& clsid, std::uint32_t context = 0x1 /*CLSCTX_INPROC_SERVER*/, void* outer = nullptr) { return try_capture(WINRT_IMPL_CoCreateInstance, clsid, outer, context); } template - auto create_instance(guid const& clsid, uint32_t context = 0x1 /*CLSCTX_INPROC_SERVER*/, void* outer = nullptr) + auto create_instance(guid const& clsid, std::uint32_t context = 0x1 /*CLSCTX_INPROC_SERVER*/, void* outer = nullptr) { return capture(WINRT_IMPL_CoCreateInstance, clsid, outer, context); } diff --git a/strings/base_agile_ref.h b/strings/base_agile_ref.h index b85cb7e61..88fbea065 100644 --- a/strings/base_agile_ref.h +++ b/strings/base_agile_ref.h @@ -10,12 +10,12 @@ WINRT_EXPORT namespace winrt { struct lock { - constexpr uint32_t operator++() noexcept + constexpr std::uint32_t operator++() noexcept { return 1; } - constexpr uint32_t operator--() noexcept + constexpr std::uint32_t operator--() noexcept { return 0; } diff --git a/strings/base_array.h b/strings/base_array.h index a4f570614..9544dcf8c 100644 --- a/strings/base_array.h +++ b/strings/base_array.h @@ -5,7 +5,7 @@ WINRT_EXPORT namespace winrt struct array_view { using value_type = T; - using size_type = uint32_t; + using size_type = std::uint32_t; using reference = value_type&; using const_reference = value_type const&; using pointer = value_type*; @@ -32,11 +32,11 @@ WINRT_EXPORT namespace winrt {} #ifdef __cpp_lib_span - template + template array_view(std::span span) noexcept : array_view(span.data(), static_cast(span.size())) { - WINRT_ASSERT(span.size() <= UINT_MAX); + WINRT_ASSERT(span.size() <= (std::numeric_limits::max)()); } operator std::span() const noexcept @@ -62,12 +62,12 @@ WINRT_EXPORT namespace winrt { } - template + template array_view(std::array& value) noexcept : array_view(value.data(), static_cast(value.size())) {} - template + template array_view(std::array const& value) noexcept : array_view(value.data(), static_cast(value.size())) {} @@ -231,15 +231,15 @@ WINRT_EXPORT namespace winrt } }; - template array_view(C(&value)[N]) -> array_view; + template array_view(C(&value)[N]) -> array_view; template array_view(std::vector& value) -> array_view; template array_view(std::vector const& value) -> array_view; - template array_view(std::array& value) -> array_view; - template array_view(std::array const& value) -> array_view; + template array_view(std::array& value) -> array_view; + template array_view(std::array const& value) -> array_view; #ifdef __cpp_lib_span - template array_view(std::span& value) -> array_view; - template array_view(std::span const& value) -> array_view; + template array_view(std::span& value) -> array_view; + template array_view(std::span const& value) -> array_view; #endif template @@ -265,7 +265,7 @@ WINRT_EXPORT namespace winrt com_array(count, value_type()) {} - com_array(void* ptr, uint32_t const count, take_ownership_from_abi_t) noexcept : + com_array(void* ptr, std::uint32_t const count, take_ownership_from_abi_t) noexcept : array_view(static_cast(ptr), static_cast(ptr) + count) { } @@ -288,21 +288,21 @@ WINRT_EXPORT namespace winrt com_array(value.begin(), value.end()) {} - template + template explicit com_array(std::array const& value) : com_array(value.begin(), value.end()) {} #ifdef __cpp_lib_span - template + template explicit com_array(std::span span) noexcept : com_array(span.data(), span.data() + span.size()) { - WINRT_ASSERT(span.size() <= UINT_MAX); + WINRT_ASSERT(span.size() <= (std::numeric_limits::max)()); } #endif - template + template explicit com_array(U const(&value)[N]) : com_array(value, value + N) {} @@ -374,17 +374,17 @@ WINRT_EXPORT namespace winrt } } - std::pair> detach_abi() noexcept + std::pair> detach_abi() noexcept { #ifdef _MSC_VER // https://github.com/microsoft/cppwinrt/pull/1165 - std::pair> result; - memset(&result, 0, sizeof(result)); + std::pair> result; + std::memset(&result, 0, sizeof(result)); result.first = this->size(); result.second = *reinterpret_cast*>(this); - memset(this, 0, sizeof(com_array)); + std::memset(this, 0, sizeof(com_array)); #else - std::pair> result(this->size(), *reinterpret_cast*>(this)); + std::pair> result(this->size(), *reinterpret_cast*>(this)); this->m_data = nullptr; this->m_size = 0; #endif @@ -392,19 +392,19 @@ WINRT_EXPORT namespace winrt } template - friend std::pair> detach_abi(com_array& object) noexcept; + friend std::pair> detach_abi(com_array& object) noexcept; }; - template com_array(uint32_t, C const&) -> com_array>; + template com_array(std::uint32_t, C const&) -> com_array>; template ::difference_type>> com_array(InIt, InIt) -> com_array::value_type>>; template com_array(std::vector const&) -> com_array>; - template com_array(std::array const&) -> com_array>; - template com_array(C const(&)[N]) -> com_array>; + template com_array(std::array const&) -> com_array>; + template com_array(C const(&)[N]) -> com_array>; template com_array(std::initializer_list) -> com_array>; #ifdef __cpp_lib_span - template com_array(std::span const& value) -> com_array>; + template com_array(std::span const& value) -> com_array>; #endif @@ -471,7 +471,7 @@ WINRT_EXPORT namespace winrt } template - std::pair> detach_abi(com_array& object) noexcept + std::pair> detach_abi(com_array& object) noexcept { return object.detach_abi(); } @@ -496,10 +496,10 @@ namespace winrt::impl ~array_size_proxy() noexcept { WINRT_ASSERT(m_value.data() || (!m_value.data() && m_size == 0)); - *reinterpret_cast(reinterpret_cast(&m_value) + 1) = m_size; + *reinterpret_cast(reinterpret_cast(&m_value) + 1) = m_size; } - operator uint32_t*() noexcept + operator std::uint32_t*() noexcept { return &m_size; } @@ -512,7 +512,7 @@ namespace winrt::impl private: com_array& m_value; - uint32_t m_size{ 0 }; + std::uint32_t m_size{ 0 }; }; template @@ -524,7 +524,7 @@ namespace winrt::impl template struct com_array_proxy { - com_array_proxy(uint32_t* size, winrt::impl::arg_out* value) noexcept : m_size(size), m_value(value) + com_array_proxy(std::uint32_t* size, winrt::impl::arg_out* value) noexcept : m_size(size), m_value(value) {} ~com_array_proxy() noexcept @@ -545,7 +545,7 @@ namespace winrt::impl private: - uint32_t* m_size; + std::uint32_t* m_size; arg_out* m_value; com_array m_temp; }; @@ -554,7 +554,7 @@ namespace winrt::impl WINRT_EXPORT namespace winrt { template - auto detach_abi(uint32_t* __valueSize, impl::arg_out* value) noexcept + auto detach_abi(std::uint32_t* __valueSize, impl::arg_out* value) noexcept { return impl::com_array_proxy(__valueSize, value); } diff --git a/strings/base_chrono.h b/strings/base_chrono.h index d48cd703b..7934ac5b2 100644 --- a/strings/base_chrono.h +++ b/strings/base_chrono.h @@ -3,17 +3,17 @@ WINRT_EXPORT namespace winrt { struct file_time { - uint64_t value{}; + std::uint64_t value{}; file_time() noexcept = default; - constexpr explicit file_time(uint64_t const value) noexcept : value(value) + constexpr explicit file_time(std::uint64_t const value) noexcept : value(value) { } #ifdef _FILETIME_ constexpr file_time(FILETIME const& value) noexcept - : value(value.dwLowDateTime | (static_cast(value.dwHighDateTime) << 32)) + : value(value.dwLowDateTime | (static_cast(value.dwHighDateTime) << 32)) { } @@ -26,7 +26,7 @@ WINRT_EXPORT namespace winrt struct clock { - using rep = int64_t; + using rep = std::int64_t; using period = impl::filetime_period; using duration = Windows::Foundation::TimeSpan; using time_point = Windows::Foundation::DateTime; @@ -52,7 +52,7 @@ WINRT_EXPORT namespace winrt static file_time to_file_time(time_point const& time) noexcept { - return file_time{ static_cast(time.time_since_epoch().count()) }; + return file_time{ static_cast(time.time_since_epoch().count()) }; } static time_point from_file_time(file_time const& time) noexcept diff --git a/strings/base_collections.h b/strings/base_collections.h index cba0864b3..4e1af51eb 100644 --- a/strings/base_collections.h +++ b/strings/base_collections.h @@ -101,10 +101,10 @@ namespace winrt::impl private: - uint32_t const m_snapshot; + std::uint32_t const m_snapshot; }; - uint32_t get_version() const noexcept + std::uint32_t get_version() const noexcept { return m_version; } @@ -116,7 +116,7 @@ namespace winrt::impl private: - std::atomic m_version{}; + std::atomic m_version{}; }; template diff --git a/strings/base_collections_base.h b/strings/base_collections_base.h index fec3de660..6fe10fa64 100644 --- a/strings/base_collections_base.h +++ b/strings/base_collections_base.h @@ -191,7 +191,7 @@ WINRT_EXPORT namespace winrt return m_current != m_end; } - uint32_t GetMany(array_view values) + std::uint32_t GetMany(array_view values) { [[maybe_unused]] auto guard = m_owner->acquire_exclusive(); this->check_version(*m_owner); @@ -213,15 +213,15 @@ WINRT_EXPORT namespace winrt } } - uint32_t GetMany(array_view values, std::random_access_iterator_tag) + std::uint32_t GetMany(array_view values, std::random_access_iterator_tag) { - uint32_t const actual = (std::min)(static_cast(m_end - m_current), values.size()); + std::uint32_t const actual = (std::min)(static_cast(m_end - m_current), values.size()); m_owner->copy_n(m_current, actual, values.begin()); m_current += actual; return actual; } - uint32_t GetMany(array_view values, std::input_iterator_tag) + std::uint32_t GetMany(array_view values, std::input_iterator_tag) { auto output = values.begin(); @@ -232,7 +232,7 @@ WINRT_EXPORT namespace winrt ++m_current; } - return static_cast(output - values.begin()); + return static_cast(output - values.begin()); } using iterator_type = decltype(std::declval().get_container().begin()); @@ -246,7 +246,7 @@ WINRT_EXPORT namespace winrt template struct vector_view_base : iterable_base { - T GetAt(uint32_t const index) const + T GetAt(std::uint32_t const index) const { [[maybe_unused]] auto guard = static_cast(*this).acquire_shared(); if (index >= container_size()) @@ -257,13 +257,13 @@ WINRT_EXPORT namespace winrt return static_cast(*this).unwrap_value(*std::next(static_cast(*this).get_container().begin(), index)); } - uint32_t Size() const noexcept + std::uint32_t Size() const noexcept { [[maybe_unused]] auto guard = static_cast(*this).acquire_shared(); return container_size(); } - bool IndexOf(T const& value, uint32_t& index) const noexcept + bool IndexOf(T const& value, std::uint32_t& index) const noexcept { [[maybe_unused]] auto guard = static_cast(*this).acquire_shared(); auto first = std::find_if(static_cast(*this).get_container().begin(), static_cast(*this).get_container().end(), [&](auto&& match) @@ -271,11 +271,11 @@ WINRT_EXPORT namespace winrt return value == static_cast(*this).unwrap_value(match); }); - index = static_cast(first - static_cast(*this).get_container().begin()); + index = static_cast(first - static_cast(*this).get_container().begin()); return index < container_size(); } - uint32_t GetMany(uint32_t const startIndex, array_view values) const + std::uint32_t GetMany(std::uint32_t const startIndex, array_view values) const { [[maybe_unused]] auto guard = static_cast(*this).acquire_shared(); if (startIndex >= container_size()) @@ -283,16 +283,16 @@ WINRT_EXPORT namespace winrt return 0; } - uint32_t const actual = (std::min)(container_size() - startIndex, values.size()); + std::uint32_t const actual = (std::min)(container_size() - startIndex, values.size()); this->copy_n(static_cast(*this).get_container().begin() + startIndex, actual, values.begin()); return actual; } private: - uint32_t container_size() const noexcept + std::uint32_t container_size() const noexcept { - return static_cast(std::distance(static_cast(*this).get_container().begin(), static_cast(*this).get_container().end())); + return static_cast(std::distance(static_cast(*this).get_container().begin(), static_cast(*this).get_container().end())); } }; @@ -304,7 +304,7 @@ WINRT_EXPORT namespace winrt return static_cast(*this); } - void SetAt(uint32_t const index, T const& value) + void SetAt(std::uint32_t const index, T const& value) { impl::removed_value::value_type> oldValue; @@ -320,7 +320,7 @@ WINRT_EXPORT namespace winrt pos = static_cast(*this).wrap_value(value); } - void InsertAt(uint32_t const index, T const& value) + void InsertAt(std::uint32_t const index, T const& value) { [[maybe_unused]] auto guard = static_cast(*this).acquire_exclusive(); if (index > static_cast(*this).get_container().size()) @@ -332,7 +332,7 @@ WINRT_EXPORT namespace winrt static_cast(*this).get_container().insert(static_cast(*this).get_container().begin() + index, static_cast(*this).wrap_value(value)); } - void RemoveAt(uint32_t const index) + void RemoveAt(std::uint32_t const index) { impl::removed_value::value_type> removedValue; @@ -425,19 +425,19 @@ WINRT_EXPORT namespace winrt m_changed.remove(cookie); } - void SetAt(uint32_t const index, T const& value) + void SetAt(std::uint32_t const index, T const& value) { vector_base::SetAt(index, value); call_changed(Windows::Foundation::Collections::CollectionChange::ItemChanged, index); } - void InsertAt(uint32_t const index, T const& value) + void InsertAt(std::uint32_t const index, T const& value) { vector_base::InsertAt(index, value); call_changed(Windows::Foundation::Collections::CollectionChange::ItemInserted, index); } - void RemoveAt(uint32_t const index) + void RemoveAt(std::uint32_t const index) { vector_base::RemoveAt(index); call_changed(Windows::Foundation::Collections::CollectionChange::ItemRemoved, index); @@ -469,7 +469,7 @@ WINRT_EXPORT namespace winrt protected: - void call_changed(Windows::Foundation::Collections::CollectionChange const change, uint32_t const index) + void call_changed(Windows::Foundation::Collections::CollectionChange const change, std::uint32_t const index) { m_changed(static_cast(*this), make(change, index)); } @@ -480,7 +480,7 @@ WINRT_EXPORT namespace winrt struct args : implements { - args(Windows::Foundation::Collections::CollectionChange const change, uint32_t const index) noexcept : + args(Windows::Foundation::Collections::CollectionChange const change, std::uint32_t const index) noexcept : m_change(change), m_index(index) { @@ -491,7 +491,7 @@ WINRT_EXPORT namespace winrt return m_change; } - uint32_t Index() const noexcept + std::uint32_t Index() const noexcept { return m_index; } @@ -499,7 +499,7 @@ WINRT_EXPORT namespace winrt private: Windows::Foundation::Collections::CollectionChange const m_change; - uint32_t const m_index; + std::uint32_t const m_index; }; }; @@ -533,10 +533,10 @@ WINRT_EXPORT namespace winrt return static_cast(*this).unwrap_value(pair->second); } - uint32_t Size() const noexcept + std::uint32_t Size() const noexcept { [[maybe_unused]] auto guard = static_cast(*this).acquire_shared(); - return static_cast(static_cast(*this).get_container().size()); + return static_cast(static_cast(*this).get_container().size()); } bool HasKey(K const& key) const noexcept diff --git a/strings/base_collections_map.h b/strings/base_collections_map.h index f4bd74baf..fa769fb88 100644 --- a/strings/base_collections_map.h +++ b/strings/base_collections_map.h @@ -120,11 +120,11 @@ namespace std { template struct tuple_size> - : integral_constant + : integral_constant { }; - template + template struct tuple_element> { static_assert(Idx < 2, "key-value pair index out of bounds"); @@ -134,7 +134,7 @@ namespace std namespace winrt::Windows::Foundation::Collections { - template + template std::tuple_element_t> get(IKeyValuePair const& kvp) { static_assert(Idx < 2, "key-value pair index out of bounds"); diff --git a/strings/base_collections_vector.h b/strings/base_collections_vector.h index cef7ef2d3..3e9c1b254 100644 --- a/strings/base_collections_vector.h +++ b/strings/base_collections_vector.h @@ -90,12 +90,12 @@ namespace winrt::impl return result{ this }; } - auto GetAt(uint32_t const index) const + auto GetAt(std::uint32_t const index) const { struct result { base_type const* container; - uint32_t const index; + std::uint32_t const index; operator T() const { @@ -113,7 +113,7 @@ namespace winrt::impl using base_type::IndexOf; - bool IndexOf(Windows::Foundation::IInspectable const& value, uint32_t& index) const + bool IndexOf(Windows::Foundation::IInspectable const& value, std::uint32_t& index) const { if constexpr (is_com_interface_v) { @@ -139,7 +139,7 @@ namespace winrt::impl using base_type::GetMany; - uint32_t GetMany(uint32_t const startIndex, array_view values) const + std::uint32_t GetMany(std::uint32_t const startIndex, array_view values) const { [[maybe_unused]] auto guard = this->acquire_shared(); if (startIndex >= m_values.size()) @@ -147,7 +147,7 @@ namespace winrt::impl return 0; } - uint32_t const actual = (std::min)(static_cast(m_values.size() - startIndex), values.size()); + std::uint32_t const actual = (std::min)(static_cast(m_values.size() - startIndex), values.size()); std::transform(m_values.begin() + startIndex, m_values.begin() + startIndex + actual, values.begin(), [&](auto && value) { @@ -179,14 +179,14 @@ namespace winrt::impl using base_type::SetAt; - void SetAt(uint32_t const index, Windows::Foundation::IInspectable const& value) + void SetAt(std::uint32_t const index, Windows::Foundation::IInspectable const& value) { SetAt(index, unbox_value(value)); } using base_type::InsertAt; - void InsertAt(uint32_t const index, Windows::Foundation::IInspectable const& value) + void InsertAt(std::uint32_t const index, Windows::Foundation::IInspectable const& value) { InsertAt(index, unbox_value(value)); } @@ -268,11 +268,11 @@ namespace winrt::impl return m_current != m_end; } - uint32_t GetMany(array_view values) + std::uint32_t GetMany(array_view values) { [[maybe_unused]] auto guard = m_owner->acquire_exclusive(); check_version(*m_owner); - uint32_t const actual = (std::min)(static_cast(std::distance(m_current, m_end)), values.size()); + std::uint32_t const actual = (std::min)(static_cast(std::distance(m_current, m_end)), values.size()); std::transform(m_current, m_current + actual, values.begin(), [&](auto && value) { diff --git a/strings/base_com_ptr.h b/strings/base_com_ptr.h index 14a9a0851..27496789a 100644 --- a/strings/base_com_ptr.h +++ b/strings/base_com_ptr.h @@ -19,19 +19,19 @@ namespace winrt::impl }; template - int32_t capture_to(void**result, F function, Args&& ...args) + std::int32_t capture_to(void**result, F function, Args&& ...args) { return function(args..., guid_of(), capture_decay{ result }); } template || std::is_union_v, int> = 0> - int32_t capture_to(void** result, O* object, M method, Args&& ...args) + std::int32_t capture_to(void** result, O* object, M method, Args&& ...args) { return (object->*method)(args..., guid_of(), capture_decay{ result }); } template - int32_t capture_to(void** result, com_ptr const& object, M method, Args&& ...args); + std::int32_t capture_to(void** result, com_ptr const& object, M method, Args&& ...args); } WINRT_EXPORT namespace winrt @@ -352,7 +352,7 @@ WINRT_EXPORT namespace winrt namespace winrt::impl { template - int32_t capture_to(void** result, com_ptr const& object, M method, Args&& ...args) + std::int32_t capture_to(void** result, com_ptr const& object, M method, Args&& ...args) { return (object.get()->*(method))(args..., guid_of(), capture_decay{ result }); } diff --git a/strings/base_coroutine_foundation.h b/strings/base_coroutine_foundation.h index a5816a85b..4f1c8d0b6 100644 --- a/strings/base_coroutine_foundation.h +++ b/strings/base_coroutine_foundation.h @@ -47,7 +47,7 @@ namespace winrt::impl } template - auto wait_for_completed(Async const& async, uint32_t const timeout) + auto wait_for_completed(Async const& async, std::uint32_t const timeout) { struct shared_type { @@ -72,8 +72,8 @@ namespace winrt::impl { check_sta_blocking_wait(); auto const milliseconds = std::chrono::duration_cast(timeout).count(); - WINRT_ASSERT((milliseconds >= 0) && (static_cast(milliseconds) < 0xFFFFFFFFull)); // Within uint32_t range and not INFINITE - return wait_for_completed(async, static_cast(milliseconds)); + WINRT_ASSERT((milliseconds >= 0) && (static_cast(milliseconds) < 0xFFFFFFFFull)); // Within std::uint32_t range and not INFINITE + return wait_for_completed(async, static_cast(milliseconds)); } inline void check_status_canceled(Windows::Foundation::AsyncStatus status) @@ -158,7 +158,7 @@ namespace winrt::impl std::conditional_t async; Windows::Foundation::AsyncStatus status = Windows::Foundation::AsyncStatus::Started; - int32_t failure = 0; + std::int32_t failure = 0; std::atomic suspending = true; void enable_cancellation(cancellable_promise* promise) @@ -405,7 +405,7 @@ namespace winrt::impl unsigned long __stdcall Release() noexcept { - uint32_t const remaining = this->subtract_reference(); + std::uint32_t const remaining = this->subtract_reference(); if (remaining == 0) { @@ -450,7 +450,7 @@ namespace winrt::impl return m_completed; } - uint32_t Id() const noexcept + std::uint32_t Id() const noexcept { return 1; } @@ -597,7 +597,7 @@ namespace winrt::impl bool await_suspend(std::coroutine_handle<>) const noexcept { promise->set_completed(); - uint32_t const remaining = promise->subtract_reference(); + std::uint32_t const remaining = promise->subtract_reference(); if (remaining == 0) { diff --git a/strings/base_coroutine_threadpool.h b/strings/base_coroutine_threadpool.h index e59fcadb2..6748906ca 100644 --- a/strings/base_coroutine_threadpool.h +++ b/strings/base_coroutine_threadpool.h @@ -21,10 +21,10 @@ namespace winrt::impl } #endif - inline std::pair get_apartment_type() noexcept + inline std::pair get_apartment_type() noexcept { - int32_t aptType; - int32_t aptTypeQualifier; + std::int32_t aptType; + std::int32_t aptTypeQualifier; if (0 == WINRT_IMPL_CoGetApartmentType(&aptType, &aptTypeQualifier)) { return { aptType, aptTypeQualifier }; @@ -62,16 +62,16 @@ namespace winrt::impl } com_ptr m_context = try_capture(WINRT_IMPL_CoGetObjectContext); - movable_primitive m_context_type = get_apartment_type().first; + movable_primitive m_context_type = get_apartment_type().first; }; - inline int32_t __stdcall resume_apartment_callback(com_callback_args* args) noexcept + inline std::int32_t __stdcall resume_apartment_callback(com_callback_args* args) noexcept { std::coroutine_handle<>::from_address(args->data)(); return 0; }; - [[nodiscard]] inline bool resume_apartment_sync(com_ptr const& context, std::coroutine_handle<> handle, int32_t* failure) + [[nodiscard]] inline bool resume_apartment_sync(com_ptr const& context, std::coroutine_handle<> handle, std::int32_t* failure) { com_callback_args args{}; args.data = handle.address(); @@ -88,11 +88,11 @@ namespace winrt::impl struct threadpool_resume { - threadpool_resume(com_ptr const& context, std::coroutine_handle<> handle, int32_t* failure) : + threadpool_resume(com_ptr const& context, std::coroutine_handle<> handle, std::int32_t* failure) : m_context(context), m_handle(handle), m_failure(failure) { } com_ptr m_context; std::coroutine_handle<> m_handle; - int32_t* m_failure; + std::int32_t* m_failure; }; inline void __stdcall fallback_submit_threadpool_callback(void*, void* p) noexcept @@ -104,14 +104,14 @@ namespace winrt::impl } } - inline void resume_apartment_on_threadpool(com_ptr const& context, std::coroutine_handle<> handle, int32_t* failure) + inline void resume_apartment_on_threadpool(com_ptr const& context, std::coroutine_handle<> handle, std::int32_t* failure) { auto state = std::make_unique(context, handle, failure); submit_threadpool_callback(fallback_submit_threadpool_callback, state.get()); state.release(); } - [[nodiscard]] inline auto resume_apartment(resume_apartment_context const& context, std::coroutine_handle<> handle, int32_t* failure) + [[nodiscard]] inline auto resume_apartment(resume_apartment_context const& context, std::coroutine_handle<> handle, std::int32_t* failure) { WINRT_ASSERT(context.valid()); if ((context.m_context == nullptr) || (context.m_context == try_capture(WINRT_IMPL_CoGetObjectContext))) @@ -326,7 +326,7 @@ namespace winrt::impl struct apartment_awaiter { apartment_context const& context; - int32_t failure = 0; + std::int32_t failure = 0; bool await_ready() const noexcept { @@ -403,7 +403,7 @@ namespace winrt::impl void create_threadpool_timer() { m_timer.attach(check_pointer(WINRT_IMPL_CreateThreadpoolTimer(callback, this, nullptr))); - int64_t relative_count = -m_duration.count(); + std::int64_t relative_count = -m_duration.count(); WINRT_IMPL_SetThreadpoolTimer(m_timer.get(), &relative_count, 0, 0); state expected = state::idle; @@ -417,7 +417,7 @@ namespace winrt::impl { if (WINRT_IMPL_SetThreadpoolTimerEx(m_timer.get(), nullptr, 0, 0)) { - int64_t now = 0; + std::int64_t now = 0; WINRT_IMPL_SetThreadpoolTimer(m_timer.get(), &now, 0, 0); } } @@ -513,8 +513,8 @@ namespace winrt::impl void create_threadpool_wait() { m_wait.attach(check_pointer(WINRT_IMPL_CreateThreadpoolWait(callback, this, nullptr))); - int64_t relative_count = -m_timeout.count(); - int64_t* file_time = relative_count != 0 ? &relative_count : nullptr; + std::int64_t relative_count = -m_timeout.count(); + std::int64_t* file_time = relative_count != 0 ? &relative_count : nullptr; WINRT_IMPL_SetThreadpoolWait(m_wait.get(), m_handle, file_time); state expected = state::idle; @@ -528,12 +528,12 @@ namespace winrt::impl { if (WINRT_IMPL_SetThreadpoolWaitEx(m_wait.get(), nullptr, nullptr, nullptr)) { - int64_t now = 0; + std::int64_t now = 0; WINRT_IMPL_SetThreadpoolWait(m_wait.get(), WINRT_IMPL_GetCurrentProcess(), &now); } } - static void __stdcall callback(void*, void* context, void*, uint32_t result) noexcept + static void __stdcall callback(void*, void* context, void*, std::uint32_t result) noexcept { auto that = static_cast(context); that->m_result = result; @@ -560,7 +560,7 @@ namespace winrt::impl handle_type m_wait; Windows::Foundation::TimeSpan m_timeout; void* m_handle; - uint32_t m_result{}; + std::uint32_t m_result{}; std::coroutine_handle<> m_resume{ nullptr }; std::atomic m_state{ state::idle }; }; @@ -596,7 +596,7 @@ WINRT_EXPORT namespace winrt m_environment.Pool = m_pool.get(); } - void thread_limits(uint32_t const high, uint32_t const low) + void thread_limits(std::uint32_t const high, std::uint32_t const low) { WINRT_IMPL_SetThreadpoolThreadMaximum(m_pool.get(), high); check_bool(WINRT_IMPL_SetThreadpoolThreadMinimum(m_pool.get(), low)); @@ -643,7 +643,7 @@ WINRT_EXPORT namespace winrt struct environment // TP_CALLBACK_ENVIRON { - uint32_t Version{ 3 }; + std::uint32_t Version{ 3 }; void* Pool{}; void* CleanupGroup{}; void* CleanupGroupCancelCallback{}; @@ -652,16 +652,16 @@ WINRT_EXPORT namespace winrt void* FinalizationCallback{}; union { - uint32_t Flags{}; + std::uint32_t Flags{}; struct { - uint32_t LongFunction : 1; - uint32_t Persistent : 1; - uint32_t Private : 30; + std::uint32_t LongFunction : 1; + std::uint32_t Persistent : 1; + std::uint32_t Private : 30; } s; } u; - int32_t CallbackPriority{ 1 }; - uint32_t Size{ sizeof(environment) }; + std::int32_t CallbackPriority{ 1 }; + std::uint32_t Size{ sizeof(environment) }; }; handle_type m_pool; diff --git a/strings/base_deferral.h b/strings/base_deferral.h index 6976db4a6..cc6f724e5 100644 --- a/strings/base_deferral.h +++ b/strings/base_deferral.h @@ -68,7 +68,7 @@ WINRT_EXPORT namespace winrt } slim_mutex m_lock; - int32_t m_outstanding_deferrals = 0; + std::int32_t m_outstanding_deferrals = 0; std::coroutine_handle<> m_handle = nullptr; }; } diff --git a/strings/base_delegate.h b/strings/base_delegate.h index 3d1457c2e..1cfe58710 100644 --- a/strings/base_delegate.h +++ b/strings/base_delegate.h @@ -8,17 +8,17 @@ namespace winrt::impl struct implements_delegate_base { - WINRT_IMPL_NOINLINE uint32_t increment_reference() noexcept + WINRT_IMPL_NOINLINE std::uint32_t increment_reference() noexcept { return ++m_references; } - WINRT_IMPL_NOINLINE uint32_t decrement_reference() noexcept + WINRT_IMPL_NOINLINE std::uint32_t decrement_reference() noexcept { return --m_references; } - WINRT_IMPL_NOINLINE uint32_t query_interface(guid const& id, void** result, unknown_abi* derivedAbiPtr, guid const& derivedId) noexcept + WINRT_IMPL_NOINLINE std::uint32_t query_interface(guid const& id, void** result, unknown_abi* derivedAbiPtr, guid const& derivedId) noexcept { if (id == derivedId || is_guid_of(id) || is_guid_of(id)) { @@ -47,17 +47,17 @@ namespace winrt::impl { } - int32_t __stdcall QueryInterface(guid const& id, void** result) noexcept final + std::int32_t __stdcall QueryInterface(guid const& id, void** result) noexcept final { return query_interface(id, result, static_cast*>(this), guid_of()); } - uint32_t __stdcall AddRef() noexcept final + std::uint32_t __stdcall AddRef() noexcept final { return increment_reference(); } - uint32_t __stdcall Release() noexcept final + std::uint32_t __stdcall Release() noexcept final { auto const remaining = decrement_reference(); @@ -133,17 +133,17 @@ namespace winrt::impl } } - int32_t __stdcall QueryInterface(guid const& id, void** result) noexcept final + std::int32_t __stdcall QueryInterface(guid const& id, void** result) noexcept final { return query_interface(id, result, static_cast(this), guid_of()); } - uint32_t __stdcall AddRef() noexcept final + std::uint32_t __stdcall AddRef() noexcept final { return increment_reference(); } - uint32_t __stdcall Release() noexcept final + std::uint32_t __stdcall Release() noexcept final { auto const remaining = decrement_reference(); diff --git a/strings/base_error.h b/strings/base_error.h index 41929336b..c58635e5d 100644 --- a/strings/base_error.h +++ b/strings/base_error.h @@ -41,11 +41,11 @@ namespace winrt::impl using bstr_handle = handle_type; - inline hstring trim_hresult_message(wchar_t const* const message, uint32_t size) noexcept + inline hstring trim_hresult_message(wchar_t const* const message, std::uint32_t size) noexcept { wchar_t const* back = message + size - 1; - while (size&& iswspace(*back)) + while (size && std::iswspace(*back)) { --size; --back; @@ -58,7 +58,7 @@ namespace winrt::impl { handle_type message; - uint32_t const size = WINRT_IMPL_FormatMessageW(0x00001300, // FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS + std::uint32_t const size = WINRT_IMPL_FormatMessageW(0x00001300, // FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS nullptr, code, 0x00000400, // MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) @@ -69,14 +69,14 @@ namespace winrt::impl return trim_hresult_message(message.get(), size); } - constexpr int32_t hresult_from_win32(uint32_t const x) noexcept + constexpr std::int32_t hresult_from_win32(std::uint32_t const x) noexcept { - return (int32_t)(x) <= 0 ? (int32_t)(x) : (int32_t)(((x) & 0x0000FFFF) | (7 << 16) | 0x80000000); + return (std::int32_t)(x) <= 0 ? (std::int32_t)(x) : (std::int32_t)(((x) & 0x0000FFFF) | (7 << 16) | 0x80000000); } - constexpr int32_t hresult_from_nt(uint32_t const x) noexcept + constexpr std::int32_t hresult_from_nt(std::uint32_t const x) noexcept { - return ((int32_t)((x) | 0x10000000)); + return ((std::int32_t)((x) | 0x10000000)); } } @@ -164,7 +164,7 @@ WINRT_EXPORT namespace winrt { if (m_info) { - int32_t code{}; + std::int32_t code{}; impl::bstr_handle fallback; impl::bstr_handle message; impl::bstr_handle unused; @@ -236,7 +236,7 @@ WINRT_EXPORT namespace winrt #endif impl::bstr_handle m_debug_reference; - uint32_t m_debug_magic{ 0xAABBCCDD }; + std::uint32_t m_debug_magic{ 0xAABBCCDD }; hresult m_code{ impl::error_fail }; com_ptr m_info; @@ -471,7 +471,7 @@ WINRT_EXPORT namespace winrt } catch (...) { - abort(); + std::abort(); } } @@ -532,7 +532,7 @@ WINRT_EXPORT namespace winrt [[noreturn]] inline void terminate() noexcept { WINRT_IMPL_RoFailFastWithErrorContext(to_hresult()); - abort(); + std::abort(); } } diff --git a/strings/base_events.h b/strings/base_events.h index 77952474e..f7e2e6976 100644 --- a/strings/base_events.h +++ b/strings/base_events.h @@ -3,7 +3,7 @@ WINRT_EXPORT namespace winrt { struct event_token { - int64_t value{}; + std::int64_t value{}; explicit operator bool() const noexcept { @@ -22,7 +22,7 @@ WINRT_EXPORT namespace winrt template struct event_revoker { - using method_type = int32_t(__stdcall impl::abi_t::*)(winrt::event_token); + using method_type = std::int32_t(__stdcall impl::abi_t::*)(winrt::event_token); event_revoker() noexcept = default; event_revoker(event_revoker const&) = delete; @@ -77,7 +77,7 @@ WINRT_EXPORT namespace winrt template struct factory_event_revoker { - using method_type = int32_t(__stdcall impl::abi_t::*)(winrt::event_token); + using method_type = std::int32_t(__stdcall impl::abi_t::*)(winrt::event_token); factory_event_revoker() noexcept = default; factory_event_revoker(factory_event_revoker const&) = delete; @@ -267,7 +267,7 @@ namespace winrt::impl using pointer = value_type*; using iterator = value_type*; - explicit event_array(uint32_t const count) noexcept : m_size(count) + explicit event_array(std::uint32_t const count) noexcept : m_size(count) { std::uninitialized_fill_n(data(), count, value_type()); } @@ -306,7 +306,7 @@ namespace winrt::impl return data() + m_size; } - uint32_t size() const noexcept + std::uint32_t size() const noexcept { return m_size; } @@ -324,11 +324,11 @@ namespace winrt::impl } atomic_ref_count m_references{ 1 }; - uint32_t m_size{ 0 }; + std::uint32_t m_size{ 0 }; }; template - com_ptr> make_event_array(uint32_t const capacity) + com_ptr> make_event_array(std::uint32_t const capacity) { void* raw = ::operator new(sizeof(event_array) + (sizeof(T)* capacity)); #ifdef _MSC_VER @@ -339,12 +339,12 @@ namespace winrt::impl WINRT_IMPL_NOINLINE inline bool report_failed_invoke() { - int32_t const code = to_hresult(); + std::int32_t const code = to_hresult(); WINRT_IMPL_RoTransformError(code, 0, nullptr); - if (code == static_cast(0x80010108) || // RPC_E_DISCONNECTED - code == static_cast(0x800706BA) || // HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) - code == static_cast(0x89020001)) // JSCRIPT_E_CANTEXECUTE + if (code == static_cast(0x80010108) || // RPC_E_DISCONNECTED + code == static_cast(0x800706BA) || // HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) + code == static_cast(0x89020001)) // JSCRIPT_E_CANTEXECUTE { return false; } @@ -402,7 +402,7 @@ WINRT_EXPORT namespace winrt return; } - uint32_t available_slots = m_targets->size() - 1; + std::uint32_t available_slots = m_targets->size() - 1; delegate_array new_targets; bool removed = false; @@ -516,7 +516,7 @@ WINRT_EXPORT namespace winrt event_token get_token(delegate_type const& delegate) const noexcept { - return event_token{ reinterpret_cast(WINRT_IMPL_EncodePointer(get_abi(delegate))) }; + return event_token{ reinterpret_cast(WINRT_IMPL_EncodePointer(get_abi(delegate))) }; } using delegate_array = com_ptr>; diff --git a/strings/base_extern.h b/strings/base_extern.h index 2412f9f2c..84e2943c4 100644 --- a/strings/base_extern.h +++ b/strings/base_extern.h @@ -1,8 +1,8 @@ -__declspec(selectany) int32_t(__stdcall* winrt_to_hresult_handler)(void* address) noexcept {}; +__declspec(selectany) std::int32_t(__stdcall* winrt_to_hresult_handler)(void* address) noexcept {}; __declspec(selectany) winrt::hstring(__stdcall* winrt_to_message_handler)(void* address) {}; -__declspec(selectany) void(__stdcall* winrt_throw_hresult_handler)(uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept {}; -__declspec(selectany) int32_t(__stdcall* winrt_activation_handler)(void* classId, winrt::guid const& iid, void** factory) noexcept {}; +__declspec(selectany) void(__stdcall* winrt_throw_hresult_handler)(std::uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept {}; +__declspec(selectany) std::int32_t(__stdcall* winrt_activation_handler)(void* classId, winrt::guid const& iid, void** factory) noexcept {}; #if defined(_MSC_VER) #ifdef _M_HYBRID @@ -24,88 +24,88 @@ __declspec(selectany) int32_t(__stdcall* winrt_activation_handler)(void* classId extern "C" { - int32_t __stdcall WINRT_IMPL_RoGetActivationFactory(void* classId, winrt::guid const& iid, void** factory) noexcept WINRT_IMPL_LINK(RoGetActivationFactory, 12); - int32_t __stdcall WINRT_IMPL_RoGetAgileReference(uint32_t options, winrt::guid const& iid, void* object, void** reference) noexcept WINRT_IMPL_LINK(RoGetAgileReference, 16); - int32_t __stdcall WINRT_IMPL_SetThreadpoolTimerEx(winrt::impl::ptp_timer, void*, uint32_t, uint32_t) noexcept WINRT_IMPL_LINK(SetThreadpoolTimerEx, 16); - int32_t __stdcall WINRT_IMPL_SetThreadpoolWaitEx(winrt::impl::ptp_wait, void*, void*, void*) noexcept WINRT_IMPL_LINK(SetThreadpoolWaitEx, 16); - int32_t __stdcall WINRT_IMPL_RoOriginateLanguageException(int32_t error, void* message, void* exception) noexcept WINRT_IMPL_LINK(RoOriginateLanguageException, 12); - int32_t __stdcall WINRT_IMPL_RoCaptureErrorContext(int32_t error) noexcept WINRT_IMPL_LINK(RoCaptureErrorContext, 4); - void __stdcall WINRT_IMPL_RoFailFastWithErrorContext(int32_t) noexcept WINRT_IMPL_LINK(RoFailFastWithErrorContext, 4); - int32_t __stdcall WINRT_IMPL_RoTransformError(int32_t, int32_t, void*) noexcept WINRT_IMPL_LINK(RoTransformError, 12); + std::int32_t __stdcall WINRT_IMPL_RoGetActivationFactory(void* classId, winrt::guid const& iid, void** factory) noexcept WINRT_IMPL_LINK(RoGetActivationFactory, 12); + std::int32_t __stdcall WINRT_IMPL_RoGetAgileReference(std::uint32_t options, winrt::guid const& iid, void* object, void** reference) noexcept WINRT_IMPL_LINK(RoGetAgileReference, 16); + std::int32_t __stdcall WINRT_IMPL_SetThreadpoolTimerEx(winrt::impl::ptp_timer, void*, std::uint32_t, std::uint32_t) noexcept WINRT_IMPL_LINK(SetThreadpoolTimerEx, 16); + std::int32_t __stdcall WINRT_IMPL_SetThreadpoolWaitEx(winrt::impl::ptp_wait, void*, void*, void*) noexcept WINRT_IMPL_LINK(SetThreadpoolWaitEx, 16); + std::int32_t __stdcall WINRT_IMPL_RoOriginateLanguageException(std::int32_t error, void* message, void* exception) noexcept WINRT_IMPL_LINK(RoOriginateLanguageException, 12); + std::int32_t __stdcall WINRT_IMPL_RoCaptureErrorContext(std::int32_t error) noexcept WINRT_IMPL_LINK(RoCaptureErrorContext, 4); + void __stdcall WINRT_IMPL_RoFailFastWithErrorContext(std::int32_t) noexcept WINRT_IMPL_LINK(RoFailFastWithErrorContext, 4); + std::int32_t __stdcall WINRT_IMPL_RoTransformError(std::int32_t, std::int32_t, void*) noexcept WINRT_IMPL_LINK(RoTransformError, 12); - void* __stdcall WINRT_IMPL_LoadLibraryExW(wchar_t const* name, void* unused, uint32_t flags) noexcept WINRT_IMPL_LINK(LoadLibraryExW, 12); - int32_t __stdcall WINRT_IMPL_FreeLibrary(void* library) noexcept WINRT_IMPL_LINK(FreeLibrary, 4); + void* __stdcall WINRT_IMPL_LoadLibraryExW(wchar_t const* name, void* unused, std::uint32_t flags) noexcept WINRT_IMPL_LINK(LoadLibraryExW, 12); + std::int32_t __stdcall WINRT_IMPL_FreeLibrary(void* library) noexcept WINRT_IMPL_LINK(FreeLibrary, 4); void* __stdcall WINRT_IMPL_GetProcAddress(void* library, char const* name) noexcept WINRT_IMPL_LINK(GetProcAddress, 8); - int32_t __stdcall WINRT_IMPL_SetErrorInfo(uint32_t reserved, void* info) noexcept WINRT_IMPL_LINK(SetErrorInfo, 8); - int32_t __stdcall WINRT_IMPL_GetErrorInfo(uint32_t reserved, void** info) noexcept WINRT_IMPL_LINK(GetErrorInfo, 8); - int32_t __stdcall WINRT_IMPL_CoInitializeEx(void*, uint32_t type) noexcept WINRT_IMPL_LINK(CoInitializeEx, 8); + std::int32_t __stdcall WINRT_IMPL_SetErrorInfo(std::uint32_t reserved, void* info) noexcept WINRT_IMPL_LINK(SetErrorInfo, 8); + std::int32_t __stdcall WINRT_IMPL_GetErrorInfo(std::uint32_t reserved, void** info) noexcept WINRT_IMPL_LINK(GetErrorInfo, 8); + std::int32_t __stdcall WINRT_IMPL_CoInitializeEx(void*, std::uint32_t type) noexcept WINRT_IMPL_LINK(CoInitializeEx, 8); void __stdcall WINRT_IMPL_CoUninitialize() noexcept WINRT_IMPL_LINK(CoUninitialize, 0); - int32_t __stdcall WINRT_IMPL_CoCreateFreeThreadedMarshaler(void* outer, void** marshaler) noexcept WINRT_IMPL_LINK(CoCreateFreeThreadedMarshaler, 8); - int32_t __stdcall WINRT_IMPL_CoCreateInstance(winrt::guid const& clsid, void* outer, uint32_t context, winrt::guid const& iid, void** object) noexcept WINRT_IMPL_LINK(CoCreateInstance, 20); - int32_t __stdcall WINRT_IMPL_CoGetCallContext(winrt::guid const& iid, void** object) noexcept WINRT_IMPL_LINK(CoGetCallContext, 8); - int32_t __stdcall WINRT_IMPL_CoGetObjectContext(winrt::guid const& iid, void** object) noexcept WINRT_IMPL_LINK(CoGetObjectContext, 8); - int32_t __stdcall WINRT_IMPL_CoGetApartmentType(int32_t* type, int32_t* qualifier) noexcept WINRT_IMPL_LINK(CoGetApartmentType, 8); + std::int32_t __stdcall WINRT_IMPL_CoCreateFreeThreadedMarshaler(void* outer, void** marshaler) noexcept WINRT_IMPL_LINK(CoCreateFreeThreadedMarshaler, 8); + std::int32_t __stdcall WINRT_IMPL_CoCreateInstance(winrt::guid const& clsid, void* outer, std::uint32_t context, winrt::guid const& iid, void** object) noexcept WINRT_IMPL_LINK(CoCreateInstance, 20); + std::int32_t __stdcall WINRT_IMPL_CoGetCallContext(winrt::guid const& iid, void** object) noexcept WINRT_IMPL_LINK(CoGetCallContext, 8); + std::int32_t __stdcall WINRT_IMPL_CoGetObjectContext(winrt::guid const& iid, void** object) noexcept WINRT_IMPL_LINK(CoGetObjectContext, 8); + std::int32_t __stdcall WINRT_IMPL_CoGetApartmentType(std::int32_t* type, std::int32_t* qualifier) noexcept WINRT_IMPL_LINK(CoGetApartmentType, 8); void* __stdcall WINRT_IMPL_CoTaskMemAlloc(std::size_t size) noexcept WINRT_IMPL_LINK(CoTaskMemAlloc, 4); void __stdcall WINRT_IMPL_CoTaskMemFree(void* ptr) noexcept WINRT_IMPL_LINK(CoTaskMemFree, 4); winrt::impl::bstr __stdcall WINRT_IMPL_SysAllocString(wchar_t const* value) noexcept WINRT_IMPL_LINK(SysAllocString, 4); void __stdcall WINRT_IMPL_SysFreeString(winrt::impl::bstr string) noexcept WINRT_IMPL_LINK(SysFreeString, 4); - uint32_t __stdcall WINRT_IMPL_SysStringLen(winrt::impl::bstr string) noexcept WINRT_IMPL_LINK(SysStringLen, 4); - int32_t __stdcall WINRT_IMPL_IIDFromString(wchar_t const* string, winrt::guid* iid) noexcept WINRT_IMPL_LINK(IIDFromString, 8); - int32_t __stdcall WINRT_IMPL_MultiByteToWideChar(uint32_t codepage, uint32_t flags, char const* in_string, int32_t in_size, wchar_t* out_string, int32_t out_size) noexcept WINRT_IMPL_LINK(MultiByteToWideChar, 24); - int32_t __stdcall WINRT_IMPL_WideCharToMultiByte(uint32_t codepage, uint32_t flags, wchar_t const* int_string, int32_t in_size, char* out_string, int32_t out_size, char const* default_char, int32_t* default_used) noexcept WINRT_IMPL_LINK(WideCharToMultiByte, 32); - void* __stdcall WINRT_IMPL_HeapAlloc(void* heap, uint32_t flags, size_t bytes) noexcept WINRT_IMPL_LINK(HeapAlloc, 12); - int32_t __stdcall WINRT_IMPL_HeapFree(void* heap, uint32_t flags, void* value) noexcept WINRT_IMPL_LINK(HeapFree, 12); + std::uint32_t __stdcall WINRT_IMPL_SysStringLen(winrt::impl::bstr string) noexcept WINRT_IMPL_LINK(SysStringLen, 4); + std::int32_t __stdcall WINRT_IMPL_IIDFromString(wchar_t const* string, winrt::guid* iid) noexcept WINRT_IMPL_LINK(IIDFromString, 8); + std::int32_t __stdcall WINRT_IMPL_MultiByteToWideChar(std::uint32_t codepage, std::uint32_t flags, char const* in_string, std::int32_t in_size, wchar_t* out_string, std::int32_t out_size) noexcept WINRT_IMPL_LINK(MultiByteToWideChar, 24); + std::int32_t __stdcall WINRT_IMPL_WideCharToMultiByte(std::uint32_t codepage, std::uint32_t flags, wchar_t const* int_string, std::int32_t in_size, char* out_string, std::int32_t out_size, char const* default_char, std::int32_t* default_used) noexcept WINRT_IMPL_LINK(WideCharToMultiByte, 32); + void* __stdcall WINRT_IMPL_HeapAlloc(void* heap, std::uint32_t flags, std::size_t bytes) noexcept WINRT_IMPL_LINK(HeapAlloc, 12); + std::int32_t __stdcall WINRT_IMPL_HeapFree(void* heap, std::uint32_t flags, void* value) noexcept WINRT_IMPL_LINK(HeapFree, 12); void* __stdcall WINRT_IMPL_GetProcessHeap() noexcept WINRT_IMPL_LINK(GetProcessHeap, 0); - uint32_t __stdcall WINRT_IMPL_FormatMessageW(uint32_t flags, void const* source, uint32_t code, uint32_t language, wchar_t* buffer, uint32_t size, va_list* arguments) noexcept WINRT_IMPL_LINK(FormatMessageW, 28); - uint32_t __stdcall WINRT_IMPL_GetLastError() noexcept WINRT_IMPL_LINK(GetLastError, 0); + std::uint32_t __stdcall WINRT_IMPL_FormatMessageW(std::uint32_t flags, void const* source, std::uint32_t code, std::uint32_t language, wchar_t* buffer, std::uint32_t size, va_list* arguments) noexcept WINRT_IMPL_LINK(FormatMessageW, 28); + std::uint32_t __stdcall WINRT_IMPL_GetLastError() noexcept WINRT_IMPL_LINK(GetLastError, 0); void __stdcall WINRT_IMPL_GetSystemTimePreciseAsFileTime(void* result) noexcept WINRT_IMPL_LINK(GetSystemTimePreciseAsFileTime, 4); - uintptr_t __stdcall WINRT_IMPL_VirtualQuery(void* address, void* buffer, uintptr_t length) noexcept WINRT_IMPL_LINK(VirtualQuery, 12); + std::uintptr_t __stdcall WINRT_IMPL_VirtualQuery(void* address, void* buffer, std::uintptr_t length) noexcept WINRT_IMPL_LINK(VirtualQuery, 12); void* __stdcall WINRT_IMPL_EncodePointer(void* ptr) noexcept WINRT_IMPL_LINK(EncodePointer, 4); - int32_t __stdcall WINRT_IMPL_OpenProcessToken(void* process, uint32_t access, void** token) noexcept WINRT_IMPL_LINK(OpenProcessToken, 12); + std::int32_t __stdcall WINRT_IMPL_OpenProcessToken(void* process, std::uint32_t access, void** token) noexcept WINRT_IMPL_LINK(OpenProcessToken, 12); void* __stdcall WINRT_IMPL_GetCurrentProcess() noexcept WINRT_IMPL_LINK(GetCurrentProcess, 0); - int32_t __stdcall WINRT_IMPL_DuplicateToken(void* existing, uint32_t level, void** duplicate) noexcept WINRT_IMPL_LINK(DuplicateToken, 12); - int32_t __stdcall WINRT_IMPL_OpenThreadToken(void* thread, uint32_t access, int32_t self, void** token) noexcept WINRT_IMPL_LINK(OpenThreadToken, 16); + std::int32_t __stdcall WINRT_IMPL_DuplicateToken(void* existing, std::uint32_t level, void** duplicate) noexcept WINRT_IMPL_LINK(DuplicateToken, 12); + std::int32_t __stdcall WINRT_IMPL_OpenThreadToken(void* thread, std::uint32_t access, std::int32_t self, void** token) noexcept WINRT_IMPL_LINK(OpenThreadToken, 16); void* __stdcall WINRT_IMPL_GetCurrentThread() noexcept WINRT_IMPL_LINK(GetCurrentThread, 0); - int32_t __stdcall WINRT_IMPL_SetThreadToken(void** thread, void* token) noexcept WINRT_IMPL_LINK(SetThreadToken, 8); + std::int32_t __stdcall WINRT_IMPL_SetThreadToken(void** thread, void* token) noexcept WINRT_IMPL_LINK(SetThreadToken, 8); void __stdcall WINRT_IMPL_AcquireSRWLockExclusive(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(AcquireSRWLockExclusive, 4); void __stdcall WINRT_IMPL_AcquireSRWLockShared(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(AcquireSRWLockShared, 4); - uint8_t __stdcall WINRT_IMPL_TryAcquireSRWLockExclusive(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(TryAcquireSRWLockExclusive, 4); - uint8_t __stdcall WINRT_IMPL_TryAcquireSRWLockShared(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(TryAcquireSRWLockShared, 4); + std::uint8_t __stdcall WINRT_IMPL_TryAcquireSRWLockExclusive(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(TryAcquireSRWLockExclusive, 4); + std::uint8_t __stdcall WINRT_IMPL_TryAcquireSRWLockShared(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(TryAcquireSRWLockShared, 4); void __stdcall WINRT_IMPL_ReleaseSRWLockExclusive(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(ReleaseSRWLockExclusive, 4); void __stdcall WINRT_IMPL_ReleaseSRWLockShared(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(ReleaseSRWLockShared, 4); - int32_t __stdcall WINRT_IMPL_SleepConditionVariableSRW(winrt::impl::condition_variable* cv, winrt::impl::srwlock* lock, uint32_t milliseconds, uint32_t flags) noexcept WINRT_IMPL_LINK(SleepConditionVariableSRW, 16); + std::int32_t __stdcall WINRT_IMPL_SleepConditionVariableSRW(winrt::impl::condition_variable* cv, winrt::impl::srwlock* lock, std::uint32_t milliseconds, std::uint32_t flags) noexcept WINRT_IMPL_LINK(SleepConditionVariableSRW, 16); void __stdcall WINRT_IMPL_WakeConditionVariable(winrt::impl::condition_variable* cv) noexcept WINRT_IMPL_LINK(WakeConditionVariable, 4); void __stdcall WINRT_IMPL_WakeAllConditionVariable(winrt::impl::condition_variable* cv) noexcept WINRT_IMPL_LINK(WakeAllConditionVariable, 4); void* __stdcall WINRT_IMPL_InterlockedPushEntrySList(void* head, void* entry) noexcept WINRT_IMPL_LINK(InterlockedPushEntrySList, 8); void* __stdcall WINRT_IMPL_InterlockedFlushSList(void* head) noexcept WINRT_IMPL_LINK(InterlockedFlushSList, 4); - void* __stdcall WINRT_IMPL_CreateEventW(void*, int32_t, int32_t, void*) noexcept WINRT_IMPL_LINK(CreateEventW, 16); - int32_t __stdcall WINRT_IMPL_SetEvent(void*) noexcept WINRT_IMPL_LINK(SetEvent, 4); - int32_t __stdcall WINRT_IMPL_CloseHandle(void* hObject) noexcept WINRT_IMPL_LINK(CloseHandle, 4); - uint32_t __stdcall WINRT_IMPL_WaitForSingleObject(void* handle, uint32_t milliseconds) noexcept WINRT_IMPL_LINK(WaitForSingleObject, 8); + void* __stdcall WINRT_IMPL_CreateEventW(void*, std::int32_t, std::int32_t, void*) noexcept WINRT_IMPL_LINK(CreateEventW, 16); + std::int32_t __stdcall WINRT_IMPL_SetEvent(void*) noexcept WINRT_IMPL_LINK(SetEvent, 4); + std::int32_t __stdcall WINRT_IMPL_CloseHandle(void* hObject) noexcept WINRT_IMPL_LINK(CloseHandle, 4); + std::uint32_t __stdcall WINRT_IMPL_WaitForSingleObject(void* handle, std::uint32_t milliseconds) noexcept WINRT_IMPL_LINK(WaitForSingleObject, 8); - int32_t __stdcall WINRT_IMPL_TrySubmitThreadpoolCallback(void(__stdcall *callback)(void*, void* context), void* context, void*) noexcept WINRT_IMPL_LINK(TrySubmitThreadpoolCallback, 12); + std::int32_t __stdcall WINRT_IMPL_TrySubmitThreadpoolCallback(void(__stdcall *callback)(void*, void* context), void* context, void*) noexcept WINRT_IMPL_LINK(TrySubmitThreadpoolCallback, 12); winrt::impl::ptp_timer __stdcall WINRT_IMPL_CreateThreadpoolTimer(void(__stdcall *callback)(void*, void* context, void*), void* context, void*) noexcept WINRT_IMPL_LINK(CreateThreadpoolTimer, 12); - void __stdcall WINRT_IMPL_SetThreadpoolTimer(winrt::impl::ptp_timer timer, void* time, uint32_t period, uint32_t window) noexcept WINRT_IMPL_LINK(SetThreadpoolTimer, 16); + void __stdcall WINRT_IMPL_SetThreadpoolTimer(winrt::impl::ptp_timer timer, void* time, std::uint32_t period, std::uint32_t window) noexcept WINRT_IMPL_LINK(SetThreadpoolTimer, 16); void __stdcall WINRT_IMPL_CloseThreadpoolTimer(winrt::impl::ptp_timer timer) noexcept WINRT_IMPL_LINK(CloseThreadpoolTimer, 4); - winrt::impl::ptp_wait __stdcall WINRT_IMPL_CreateThreadpoolWait(void(__stdcall *callback)(void*, void* context, void*, uint32_t result), void* context, void*) noexcept WINRT_IMPL_LINK(CreateThreadpoolWait, 12); + winrt::impl::ptp_wait __stdcall WINRT_IMPL_CreateThreadpoolWait(void(__stdcall *callback)(void*, void* context, void*, std::uint32_t result), void* context, void*) noexcept WINRT_IMPL_LINK(CreateThreadpoolWait, 12); void __stdcall WINRT_IMPL_SetThreadpoolWait(winrt::impl::ptp_wait wait, void* handle, void* timeout) noexcept WINRT_IMPL_LINK(SetThreadpoolWait, 12); void __stdcall WINRT_IMPL_CloseThreadpoolWait(winrt::impl::ptp_wait wait) noexcept WINRT_IMPL_LINK(CloseThreadpoolWait, 4); - winrt::impl::ptp_io __stdcall WINRT_IMPL_CreateThreadpoolIo(void* object, void(__stdcall *callback)(void*, void* context, void* overlapped, uint32_t result, std::size_t bytes, void*) noexcept, void* context, void*) noexcept WINRT_IMPL_LINK(CreateThreadpoolIo, 16); + winrt::impl::ptp_io __stdcall WINRT_IMPL_CreateThreadpoolIo(void* object, void(__stdcall *callback)(void*, void* context, void* overlapped, std::uint32_t result, std::size_t bytes, void*) noexcept, void* context, void*) noexcept WINRT_IMPL_LINK(CreateThreadpoolIo, 16); void __stdcall WINRT_IMPL_StartThreadpoolIo(winrt::impl::ptp_io io) noexcept WINRT_IMPL_LINK(StartThreadpoolIo, 4); void __stdcall WINRT_IMPL_CancelThreadpoolIo(winrt::impl::ptp_io io) noexcept WINRT_IMPL_LINK(CancelThreadpoolIo, 4); void __stdcall WINRT_IMPL_CloseThreadpoolIo(winrt::impl::ptp_io io) noexcept WINRT_IMPL_LINK(CloseThreadpoolIo, 4); winrt::impl::ptp_pool __stdcall WINRT_IMPL_CreateThreadpool(void* reserved) noexcept WINRT_IMPL_LINK(CreateThreadpool, 4); - void __stdcall WINRT_IMPL_SetThreadpoolThreadMaximum(winrt::impl::ptp_pool pool, uint32_t value) noexcept WINRT_IMPL_LINK(SetThreadpoolThreadMaximum, 8); - int32_t __stdcall WINRT_IMPL_SetThreadpoolThreadMinimum(winrt::impl::ptp_pool pool, uint32_t value) noexcept WINRT_IMPL_LINK(SetThreadpoolThreadMinimum, 8); + void __stdcall WINRT_IMPL_SetThreadpoolThreadMaximum(winrt::impl::ptp_pool pool, std::uint32_t value) noexcept WINRT_IMPL_LINK(SetThreadpoolThreadMaximum, 8); + std::int32_t __stdcall WINRT_IMPL_SetThreadpoolThreadMinimum(winrt::impl::ptp_pool pool, std::uint32_t value) noexcept WINRT_IMPL_LINK(SetThreadpoolThreadMinimum, 8); void __stdcall WINRT_IMPL_CloseThreadpool(winrt::impl::ptp_pool pool) noexcept WINRT_IMPL_LINK(CloseThreadpool, 4); - int32_t __stdcall WINRT_CanUnloadNow() noexcept; - int32_t __stdcall WINRT_GetActivationFactory(void* classId, void** factory) noexcept; + std::int32_t __stdcall WINRT_CanUnloadNow() noexcept; + std::int32_t __stdcall WINRT_GetActivationFactory(void* classId, void** factory) noexcept; } #undef WINRT_IMPL_LINK diff --git a/strings/base_fast_forward.h b/strings/base_fast_forward.h index 3ca34dba7..dc89fe6ce 100644 --- a/strings/base_fast_forward.h +++ b/strings/base_fast_forward.h @@ -1,5 +1,7 @@ #include #include +#include +#include #define WINRT_IMPL_STRING_1(expression) #expression #define WINRT_IMPL_STRING(expression) WINRT_IMPL_STRING_1(expression) @@ -36,31 +38,31 @@ namespace winrt::impl { struct guid { - uint32_t Data1; - uint16_t Data2; - uint16_t Data3; - uint8_t Data4[8]; + std::uint32_t Data1; + std::uint16_t Data2; + std::uint16_t Data3; + std::uint8_t Data4[8]; inline bool operator!=(guid const& right) const noexcept { - return memcmp(this, &right, sizeof(guid)); + return std::memcmp(this, &right, sizeof(guid)); } }; struct WINRT_IMPL_FF_NOVTABLE WINRT_IMPL_FF_PUBLIC inspectable { - virtual int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept = 0; - virtual uint32_t __stdcall AddRef() noexcept = 0; - virtual uint32_t __stdcall Release() noexcept = 0; - virtual int32_t __stdcall GetIids(uint32_t* count, guid** ids) noexcept = 0; - virtual int32_t __stdcall GetRuntimeClassName(void** name) noexcept = 0; - virtual int32_t __stdcall GetTrustLevel(uint32_t* level) noexcept = 0; + virtual std::int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept = 0; + virtual std::uint32_t __stdcall AddRef() noexcept = 0; + virtual std::uint32_t __stdcall Release() noexcept = 0; + virtual std::int32_t __stdcall GetIids(std::uint32_t* count, guid** ids) noexcept = 0; + virtual std::int32_t __stdcall GetRuntimeClassName(void** name) noexcept = 0; + virtual std::int32_t __stdcall GetTrustLevel(std::uint32_t* level) noexcept = 0; }; void* const* m_vfptr; inspectable* m_owner; std::size_t m_offset; guid m_iid; - std::atomic m_references{ 1 }; + std::atomic m_references{ 1 }; fast_abi_forwarder(void* owner, guid const& iid, std::size_t offset) noexcept : m_vfptr(s_vtable), m_owner(static_cast(owner)), m_offset(offset), m_iid(iid) @@ -73,7 +75,7 @@ namespace winrt::impl m_owner->Release(); } - static int32_t __stdcall QueryInterface(fast_abi_forwarder* self, guid const& iid, void** object) noexcept + static std::int32_t __stdcall QueryInterface(fast_abi_forwarder* self, guid const& iid, void** object) noexcept { if (iid != self->m_iid) { @@ -85,14 +87,14 @@ namespace winrt::impl } // Note: COM interfaces use stdcall, not thiscall, ('this' gets no special treatment), permitting static implementations - static uint32_t __stdcall AddRef(fast_abi_forwarder* self) noexcept + static std::uint32_t __stdcall AddRef(fast_abi_forwarder* self) noexcept { return 1 + self->m_references.fetch_add(1, std::memory_order_relaxed); } - static uint32_t __stdcall Release(fast_abi_forwarder* self) noexcept + static std::uint32_t __stdcall Release(fast_abi_forwarder* self) noexcept { - uint32_t const remaining = self->m_references.fetch_sub(1, std::memory_order_release) - 1; + std::uint32_t const remaining = self->m_references.fetch_sub(1, std::memory_order_release) - 1; if (remaining == 0) { std::atomic_thread_fence(std::memory_order_acquire); @@ -101,17 +103,17 @@ namespace winrt::impl return remaining; } - static uint32_t __stdcall GetIids(fast_abi_forwarder* self, uint32_t* count, guid** iids) noexcept + static std::uint32_t __stdcall GetIids(fast_abi_forwarder* self, std::uint32_t* count, guid** iids) noexcept { return self->m_owner->GetIids(count, iids); } - static uint32_t __stdcall GetRuntimeClassName(fast_abi_forwarder* self, void** name) noexcept + static std::uint32_t __stdcall GetRuntimeClassName(fast_abi_forwarder* self, void** name) noexcept { return self->m_owner->GetRuntimeClassName(name); } - static uint32_t __stdcall GetTrustLevel(fast_abi_forwarder* self, uint32_t* level) noexcept + static std::uint32_t __stdcall GetTrustLevel(fast_abi_forwarder* self, std::uint32_t* level) noexcept { return self->m_owner->GetTrustLevel(level); } @@ -144,7 +146,7 @@ namespace winrt::impl namespace winrt { template - auto make_fast_abi_forwarder(void* owner, TGuid const& guid, size_t offset) + auto make_fast_abi_forwarder(void* owner, TGuid const& guid, std::size_t offset) { using ff_guid = impl::fast_abi_forwarder::guid; static_assert(sizeof(ff_guid) == sizeof(TGuid)); diff --git a/strings/base_identity.h b/strings/base_identity.h index 0f4a163b6..30830bc5a 100644 --- a/strings/base_identity.h +++ b/strings/base_identity.h @@ -19,31 +19,31 @@ WINRT_EXPORT namespace winrt namespace winrt::impl { - template + template constexpr std::array to_array(T const* value, std::index_sequence const) noexcept { return { value[Index]... }; } - template + template constexpr auto to_array(std::array const& value) noexcept { return value; } - template + template constexpr auto to_array(char const(&value)[Size]) noexcept { return to_array(value, std::make_index_sequence()); } - template + template constexpr auto to_array(wchar_t const(&value)[Size]) noexcept { return to_array(value, std::make_index_sequence()); } - template + template constexpr std::array concat( [[maybe_unused]] std::array const& left, [[maybe_unused]] std::array const& right, @@ -53,31 +53,31 @@ namespace winrt::impl return { left[LeftIndex]..., right[RightIndex]... }; } - template + template constexpr auto concat(std::array const& left, std::array const& right) noexcept { return concat(left, right, std::make_index_sequence(), std::make_index_sequence()); } - template + template constexpr auto concat(std::array const& left, T const(&right)[RightSize]) noexcept { return concat(left, to_array(right)); } - template + template constexpr auto concat(T const(&left)[LeftSize], std::array const& right) noexcept { return concat(to_array(left), right); } - template + template constexpr auto concat(std::array const& left, T const right) noexcept { return concat(left, std::array{right}); } - template + template constexpr auto concat(T const left, std::array const& right) noexcept { return concat(std::array{left}, right); @@ -96,31 +96,31 @@ namespace winrt::impl } } - template + template constexpr std::array zconcat_base(std::array const& left, std::array const& right, std::index_sequence const, std::index_sequence const) noexcept { return { left[LI]..., right[RI]..., T{} }; } - template + template constexpr auto zconcat(std::array const& left, std::array const& right) noexcept { return zconcat_base(left, right, std::make_index_sequence(), std::make_index_sequence()); } - template + template constexpr std::array to_zarray_base(T const(&value)[S], std::index_sequence const) noexcept { return { value[I]... }; } - template + template constexpr auto to_zarray(T const(&value)[S]) noexcept { return to_zarray_base(value, std::make_index_sequence()); } - template + template constexpr auto to_zarray(std::array const& value) noexcept { return value; @@ -139,43 +139,43 @@ namespace winrt::impl } } - constexpr std::array to_array(uint32_t value) noexcept + constexpr std::array to_array(std::uint32_t value) noexcept { - return { static_cast(value & 0x000000ff), static_cast((value & 0x0000ff00) >> 8), static_cast((value & 0x00ff0000) >> 16), static_cast((value & 0xff000000) >> 24) }; + return { static_cast(value & 0x000000ff), static_cast((value & 0x0000ff00) >> 8), static_cast((value & 0x00ff0000) >> 16), static_cast((value & 0xff000000) >> 24) }; } - constexpr std::array to_array(uint16_t value) noexcept + constexpr std::array to_array(std::uint16_t value) noexcept { - return { static_cast(value & 0x00ff), static_cast((value & 0xff00) >> 8) }; + return { static_cast(value & 0x00ff), static_cast((value & 0xff00) >> 8) }; } constexpr auto to_array(guid const& value) noexcept { return combine(to_array(value.Data1), to_array(value.Data2), to_array(value.Data3), - std::array{ value.Data4[0], value.Data4[1], value.Data4[2], value.Data4[3], value.Data4[4], value.Data4[5], value.Data4[6], value.Data4[7] }); + std::array{ value.Data4[0], value.Data4[1], value.Data4[2], value.Data4[3], value.Data4[4], value.Data4[5], value.Data4[6], value.Data4[7] }); } template - constexpr T to_hex_digit(uint8_t value) noexcept + constexpr T to_hex_digit(std::uint8_t value) noexcept { value &= 0xF; return value < 10 ? static_cast('0') + value : static_cast('a') + (value - 10); } template - constexpr std::array uint8_to_hex(uint8_t const value) noexcept + constexpr std::array uint8_to_hex(std::uint8_t const value) noexcept { return { to_hex_digit(value >> 4), to_hex_digit(value & 0xF) }; } template - constexpr auto uint16_to_hex(uint16_t value) noexcept + constexpr auto uint16_to_hex(std::uint16_t value) noexcept { - return combine(uint8_to_hex(static_cast(value >> 8)), uint8_to_hex(value & 0xFF)); + return combine(uint8_to_hex(static_cast(value >> 8)), uint8_to_hex(value & 0xFF)); } template - constexpr auto uint32_to_hex(uint32_t const value) noexcept + constexpr auto uint32_to_hex(std::uint32_t const value) noexcept { return combine(uint16_to_hex(value >> 16), uint16_to_hex(value & 0xFFFF)); } @@ -197,18 +197,18 @@ namespace winrt::impl ); } - constexpr uint32_t to_guid(uint8_t a, uint8_t b, uint8_t c, uint8_t d) noexcept + constexpr std::uint32_t to_guid(std::uint8_t a, std::uint8_t b, std::uint8_t c, std::uint8_t d) noexcept { - return (static_cast(d) << 24) | (static_cast(c) << 16) | (static_cast(b) << 8) | static_cast(a); + return (static_cast(d) << 24) | (static_cast(c) << 16) | (static_cast(b) << 8) | static_cast(a); } - constexpr uint16_t to_guid(uint8_t a, uint8_t b) noexcept + constexpr std::uint16_t to_guid(std::uint8_t a, std::uint8_t b) noexcept { - return (static_cast(b) << 8) | static_cast(a); + return (static_cast(b) << 8) | static_cast(a); } - template - constexpr guid to_guid(std::array const& arr) noexcept + template + constexpr guid to_guid(std::array const& arr) noexcept { return { @@ -219,12 +219,12 @@ namespace winrt::impl }; } - constexpr uint32_t endian_swap(uint32_t value) noexcept + constexpr std::uint32_t endian_swap(std::uint32_t value) noexcept { return (value & 0xFF000000) >> 24 | (value & 0x00FF0000) >> 8 | (value & 0x0000FF00) << 8 | (value & 0x000000FF) << 24; } - constexpr uint16_t endian_swap(uint16_t value) noexcept + constexpr std::uint16_t endian_swap(std::uint16_t value) noexcept { return (value & 0xFF00) >> 8 | (value & 0x00FF) << 8; } @@ -239,51 +239,51 @@ namespace winrt::impl constexpr guid set_named_guid_fields(guid value) noexcept { - value.Data3 = static_cast((value.Data3 & 0x0fff) | (5 << 12)); - value.Data4[0] = static_cast((value.Data4[0] & 0x3f) | 0x80); + value.Data3 = static_cast((value.Data3 & 0x0fff) | (5 << 12)); + value.Data4[0] = static_cast((value.Data4[0] & 0x3f) | 0x80); return value; } - template - constexpr std::array char_to_byte_array(std::array const& value, std::index_sequence const) noexcept + template + constexpr std::array char_to_byte_array(std::array const& value, std::index_sequence const) noexcept { - return { static_cast(value[Index])... }; + return { static_cast(value[Index])... }; } - constexpr auto sha1_rotl(uint8_t bits, uint32_t word) noexcept + constexpr auto sha1_rotl(std::uint8_t bits, std::uint32_t word) noexcept { return (word << bits) | (word >> (32 - bits)); } - constexpr auto sha_ch(uint32_t x, uint32_t y, uint32_t z) noexcept + constexpr auto sha_ch(std::uint32_t x, std::uint32_t y, std::uint32_t z) noexcept { return (x & y) ^ ((~x) & z); } - constexpr auto sha_parity(uint32_t x, uint32_t y, uint32_t z) noexcept + constexpr auto sha_parity(std::uint32_t x, std::uint32_t y, std::uint32_t z) noexcept { return x ^ y ^ z; } - constexpr auto sha_maj(uint32_t x, uint32_t y, uint32_t z) noexcept + constexpr auto sha_maj(std::uint32_t x, std::uint32_t y, std::uint32_t z) noexcept { return (x & y) ^ (x & z) ^ (y & z); } - constexpr std::array process_msg_block(uint8_t const* input, size_t start_pos, std::array const& intermediate_hash) noexcept + constexpr std::array process_msg_block(std::uint8_t const* input, std::size_t start_pos, std::array const& intermediate_hash) noexcept { - uint32_t const K[4] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 }; - std::array W = {}; + std::uint32_t const K[4] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 }; + std::array W = {}; - size_t t = 0; - uint32_t temp = 0; + std::size_t t = 0; + std::uint32_t temp = 0; for (t = 0; t < 16; t++) { - W[t] = static_cast(input[start_pos + t * 4]) << 24; - W[t] = W[t] | static_cast(input[start_pos + t * 4 + 1]) << 16; - W[t] = W[t] | static_cast(input[start_pos + t * 4 + 2]) << 8; - W[t] = W[t] | static_cast(input[start_pos + t * 4 + 3]); + W[t] = static_cast(input[start_pos + t * 4]) << 24; + W[t] = W[t] | static_cast(input[start_pos + t * 4 + 1]) << 16; + W[t] = W[t] | static_cast(input[start_pos + t * 4 + 2]) << 8; + W[t] = W[t] | static_cast(input[start_pos + t * 4 + 3]); } for (t = 16; t < 80; t++) @@ -291,11 +291,11 @@ namespace winrt::impl W[t] = sha1_rotl(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); } - uint32_t A = intermediate_hash[0]; - uint32_t B = intermediate_hash[1]; - uint32_t C = intermediate_hash[2]; - uint32_t D = intermediate_hash[3]; - uint32_t E = intermediate_hash[4]; + std::uint32_t A = intermediate_hash[0]; + std::uint32_t B = intermediate_hash[1]; + std::uint32_t C = intermediate_hash[2]; + std::uint32_t D = intermediate_hash[3]; + std::uint32_t E = intermediate_hash[4]; for (t = 0; t < 20; t++) { @@ -340,54 +340,54 @@ namespace winrt::impl return { intermediate_hash[0] + A, intermediate_hash[1] + B, intermediate_hash[2] + C, intermediate_hash[3] + D, intermediate_hash[4] + E }; } - template - constexpr std::array process_msg_block(std::array const& input, size_t start_pos, std::array const& intermediate_hash) noexcept + template + constexpr std::array process_msg_block(std::array const& input, std::size_t start_pos, std::array const& intermediate_hash) noexcept { return process_msg_block(input.data(), start_pos, intermediate_hash); } - constexpr std::array size_to_bytes(size_t size) noexcept + constexpr std::array size_to_bytes(std::size_t size) noexcept { return { - static_cast((size & 0xff00000000000000) >> 56), - static_cast((size & 0x00ff000000000000) >> 48), - static_cast((size & 0x0000ff0000000000) >> 40), - static_cast((size & 0x000000ff00000000) >> 32), - static_cast((size & 0x00000000ff000000) >> 24), - static_cast((size & 0x0000000000ff0000) >> 16), - static_cast((size & 0x000000000000ff00) >> 8), - static_cast((size & 0x00000000000000ff) >> 0) + static_cast((size & 0xff00000000000000) >> 56), + static_cast((size & 0x00ff000000000000) >> 48), + static_cast((size & 0x0000ff0000000000) >> 40), + static_cast((size & 0x000000ff00000000) >> 32), + static_cast((size & 0x00000000ff000000) >> 24), + static_cast((size & 0x0000000000ff0000) >> 16), + static_cast((size & 0x000000000000ff00) >> 8), + static_cast((size & 0x00000000000000ff) >> 0) }; } - template - constexpr std::array make_remaining([[maybe_unused]] std::array const& input, [[maybe_unused]] size_t start_pos, std::index_sequence) noexcept + template + constexpr std::array make_remaining([[maybe_unused]] std::array const& input, [[maybe_unused]] std::size_t start_pos, std::index_sequence) noexcept { return { input[Index + start_pos]..., 0x80 }; } - template - constexpr auto make_remaining(std::array const& input, size_t start_pos) noexcept + template + constexpr auto make_remaining(std::array const& input, std::size_t start_pos) noexcept { constexpr auto remaining_size = Size % 64; return make_remaining(input, start_pos, std::make_index_sequence()); } - template - constexpr auto make_buffer(std::array const& remaining_buffer) noexcept + template + constexpr auto make_buffer(std::array const& remaining_buffer) noexcept { constexpr auto message_length = (RemainderSize + 8 <= 64) ? 64 : 64 * 2; constexpr auto padding_length = message_length - RemainderSize - 8; - auto padding_buffer = std::array{}; + auto padding_buffer = std::array{}; auto length_buffer = size_to_bytes(InputSize * 8); return combine(remaining_buffer, padding_buffer, length_buffer); } - template - constexpr std::array finalize_remaining_buffer(std::array const& input, std::array const& intermediate_hash) noexcept + template + constexpr std::array finalize_remaining_buffer(std::array const& input, std::array const& intermediate_hash) noexcept { if constexpr (Size == 64) { @@ -399,22 +399,22 @@ namespace winrt::impl } } - template - constexpr std::array get_result(std::array const& intermediate_hash, std::index_sequence) noexcept + template + constexpr std::array get_result(std::array const& intermediate_hash, std::index_sequence) noexcept { - return { static_cast(intermediate_hash[Index >> 2] >> (8 * (3 - (Index & 0x03))))... }; + return { static_cast(intermediate_hash[Index >> 2] >> (8 * (3 - (Index & 0x03))))... }; } - constexpr auto get_result(std::array const& intermediate_hash) noexcept + constexpr auto get_result(std::array const& intermediate_hash) noexcept { return get_result(intermediate_hash, std::make_index_sequence<20>{}); } - template - constexpr auto calculate_sha1(std::array const& input) noexcept + template + constexpr auto calculate_sha1(std::array const& input) noexcept { - std::array intermediate_hash{ 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }; - size_t i = 0; + std::array intermediate_hash{ 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }; + std::size_t i = 0; while (i + 64 <= Size) { @@ -426,7 +426,7 @@ namespace winrt::impl return get_result(intermediate_hash); } - template + template constexpr guid generate_guid(std::array const& value) noexcept { guid namespace_guid = { 0xd57af411, 0x737b, 0xc042,{ 0xab, 0xae, 0x87, 0x8b, 0x1e, 0x16, 0xad, 0xee } }; @@ -472,7 +472,7 @@ namespace winrt::impl ) }; - constexpr size_t to_utf8_size(wchar_t const value) noexcept + constexpr std::size_t to_utf8_size(wchar_t const value) noexcept { if (value <= 0x7F) { @@ -487,7 +487,7 @@ namespace winrt::impl return 3; } - constexpr size_t to_utf8(wchar_t const value, char* buffer) noexcept + constexpr std::size_t to_utf8(wchar_t const value, char* buffer) noexcept { if (value <= 0x7F) { @@ -509,10 +509,10 @@ namespace winrt::impl } template - constexpr size_t to_utf8_size() noexcept + constexpr std::size_t to_utf8_size() noexcept { auto input = to_array(name_v); - size_t length = 0; + std::size_t length = 0; for (wchar_t const element : input) { @@ -527,7 +527,7 @@ namespace winrt::impl { auto input = to_array(name_v); std::array()> output{}; - size_t offset{}; + std::size_t offset{}; for (wchar_t const element : input) { @@ -544,14 +544,14 @@ namespace winrt::impl constexpr auto& basic_signature_v = ""; template <> inline constexpr auto& basic_signature_v = "b1"; - template <> inline constexpr auto& basic_signature_v = "i1"; - template <> inline constexpr auto& basic_signature_v = "i2"; - template <> inline constexpr auto& basic_signature_v = "i4"; - template <> inline constexpr auto& basic_signature_v = "i8"; - template <> inline constexpr auto& basic_signature_v = "u1"; - template <> inline constexpr auto& basic_signature_v = "u2"; - template <> inline constexpr auto& basic_signature_v = "u4"; - template <> inline constexpr auto& basic_signature_v = "u8"; + template <> inline constexpr auto& basic_signature_v = "i1"; + template <> inline constexpr auto& basic_signature_v = "i2"; + template <> inline constexpr auto& basic_signature_v = "i4"; + template <> inline constexpr auto& basic_signature_v = "i8"; + template <> inline constexpr auto& basic_signature_v = "u1"; + template <> inline constexpr auto& basic_signature_v = "u2"; + template <> inline constexpr auto& basic_signature_v = "u4"; + template <> inline constexpr auto& basic_signature_v = "u8"; template <> inline constexpr auto& basic_signature_v = "f4"; template <> inline constexpr auto& basic_signature_v = "f8"; template <> inline constexpr auto& basic_signature_v = "c2"; @@ -560,14 +560,14 @@ namespace winrt::impl template <> inline constexpr auto& basic_signature_v = "cinterface(IInspectable)"; template <> inline constexpr auto& name_v = L"Boolean"; - template <> inline constexpr auto& name_v = L"Int8"; - template <> inline constexpr auto& name_v = L"Int16"; - template <> inline constexpr auto& name_v = L"Int32"; - template <> inline constexpr auto& name_v = L"Int64"; - template <> inline constexpr auto& name_v = L"UInt8"; - template <> inline constexpr auto& name_v = L"UInt16"; - template <> inline constexpr auto& name_v = L"UInt32"; - template <> inline constexpr auto& name_v = L"UInt64"; + template <> inline constexpr auto& name_v = L"Int8"; + template <> inline constexpr auto& name_v = L"Int16"; + template <> inline constexpr auto& name_v = L"Int32"; + template <> inline constexpr auto& name_v = L"Int64"; + template <> inline constexpr auto& name_v = L"UInt8"; + template <> inline constexpr auto& name_v = L"UInt16"; + template <> inline constexpr auto& name_v = L"UInt32"; + template <> inline constexpr auto& name_v = L"UInt64"; template <> inline constexpr auto& name_v = L"Single"; template <> inline constexpr auto& name_v = L"Double"; template <> inline constexpr auto& name_v = L"Char16"; @@ -581,23 +581,23 @@ namespace winrt::impl template <> inline constexpr auto& name_v = L"IAgileObject"; template <> struct category { using type = basic_category; }; - template <> struct category { using type = basic_category; }; - template <> struct category { using type = basic_category; }; - template <> struct category { using type = basic_category; }; - template <> struct category { using type = basic_category; }; - template <> struct category { using type = basic_category; }; - template <> struct category { using type = basic_category; }; - template <> struct category { using type = basic_category; }; - template <> struct category { using type = basic_category; }; + template <> struct category { using type = basic_category; }; + template <> struct category { using type = basic_category; }; + template <> struct category { using type = basic_category; }; + template <> struct category { using type = basic_category; }; + template <> struct category { using type = basic_category; }; + template <> struct category { using type = basic_category; }; + template <> struct category { using type = basic_category; }; + template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; - template <> struct category { using type = struct_category; }; - template <> struct category { using type = struct_category; }; + template <> struct category { using type = struct_category; }; + template <> struct category { using type = struct_category; }; template <> struct category { using type = basic_category; }; - template <> struct category { using type = struct_category; }; - template <> struct category { using type = struct_category; }; + template <> struct category { using type = struct_category; }; + template <> struct category { using type = struct_category; }; template struct category_signature @@ -642,13 +642,13 @@ namespace winrt::impl constexpr static auto data{ combine("delegate(", to_array(guid_of()), ")") }; }; - template + template constexpr std::wstring_view to_wstring_view(std::array const& value) noexcept { return { value.data(), Size - 1 }; } - template + template constexpr std::wstring_view to_wstring_view(wchar_t const (&value)[Size]) noexcept { return { value, Size - 1 }; diff --git a/strings/base_implements.h b/strings/base_implements.h index b943c1d96..7edf32149 100644 --- a/strings/base_implements.h +++ b/strings/base_implements.h @@ -216,11 +216,11 @@ namespace winrt::impl } template - void zero_abi([[maybe_unused]] void* ptr, [[maybe_unused]] uint32_t const capacity) noexcept + void zero_abi([[maybe_unused]] void* ptr, [[maybe_unused]] std::uint32_t const capacity) noexcept { if constexpr (!std::is_trivially_destructible_v) { - memset(ptr, 0, sizeof(T) * capacity); + std::memset(ptr, 0, sizeof(T) * capacity); } } @@ -229,7 +229,7 @@ namespace winrt::impl { if constexpr (!std::is_trivially_destructible_v) { - memset(ptr, 0, sizeof(T)); + std::memset(ptr, 0, sizeof(T)); } } } @@ -522,32 +522,32 @@ namespace winrt::impl return*static_cast(reinterpret_cast*>(this)); } - int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept override + std::int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept override { return shim().QueryInterface(id, object); } - uint32_t __stdcall AddRef() noexcept override + std::uint32_t __stdcall AddRef() noexcept override { return shim().AddRef(); } - uint32_t __stdcall Release() noexcept override + std::uint32_t __stdcall Release() noexcept override { return shim().Release(); } - int32_t __stdcall GetIids(uint32_t* count, guid** array) noexcept override + std::int32_t __stdcall GetIids(std::uint32_t* count, guid** array) noexcept override { return shim().GetIids(reinterpret_cast(count), reinterpret_cast(array)); } - int32_t __stdcall GetRuntimeClassName(void** name) noexcept override + std::int32_t __stdcall GetRuntimeClassName(void** name) noexcept override { return shim().abi_GetRuntimeClassName(name); } - int32_t __stdcall GetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept final + std::int32_t __stdcall GetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept final { return shim().abi_GetTrustLevel(trustLevel); } @@ -579,27 +579,27 @@ namespace winrt::impl template struct produce : produce_base { - int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final + std::int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final { return this->shim().NonDelegatingQueryInterface(id, object); } - uint32_t __stdcall AddRef() noexcept final + std::uint32_t __stdcall AddRef() noexcept final { return this->shim().NonDelegatingAddRef(); } - uint32_t __stdcall Release() noexcept final + std::uint32_t __stdcall Release() noexcept final { return this->shim().NonDelegatingRelease(); } - int32_t __stdcall GetIids(uint32_t* count, guid** array) noexcept final + std::int32_t __stdcall GetIids(std::uint32_t* count, guid** array) noexcept final { return this->shim().NonDelegatingGetIids(count, array); } - int32_t __stdcall GetRuntimeClassName(void** name) noexcept final + std::int32_t __stdcall GetRuntimeClassName(void** name) noexcept final { return this->shim().NonDelegatingGetRuntimeClassName(name); } @@ -619,7 +619,7 @@ namespace winrt::impl return static_cast*>(reinterpret_cast*>(this)); } - int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final + std::int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final { if (is_guid_of(id)) { @@ -631,17 +631,17 @@ namespace winrt::impl return that()->m_object->QueryInterface(id, object); } - uint32_t __stdcall AddRef() noexcept final + std::uint32_t __stdcall AddRef() noexcept final { return that()->increment_strong(); } - uint32_t __stdcall Release() noexcept final + std::uint32_t __stdcall Release() noexcept final { return that()->m_object->Release(); } - int32_t __stdcall GetWeakReference(IWeakReference** weakReference) noexcept final + std::int32_t __stdcall GetWeakReference(IWeakReference** weakReference) noexcept final { *weakReference = that(); that()->AddRef(); @@ -659,14 +659,14 @@ namespace winrt::impl template struct weak_ref final : IWeakReference, weak_source_producer { - weak_ref(unknown_abi* object, uint32_t const strong) noexcept : + weak_ref(unknown_abi* object, std::uint32_t const strong) noexcept : m_object(object), m_strong(strong) { WINRT_ASSERT(object); } - int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final + std::int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final { if (is_guid_of(id) || is_guid_of(id)) { @@ -694,14 +694,14 @@ namespace winrt::impl return error_no_interface; } - uint32_t __stdcall AddRef() noexcept final + std::uint32_t __stdcall AddRef() noexcept final { return 1 + m_weak.fetch_add(1, std::memory_order_relaxed); } - uint32_t __stdcall Release() noexcept final + std::uint32_t __stdcall Release() noexcept final { - uint32_t const target = m_weak.fetch_sub(1, std::memory_order_relaxed) - 1; + std::uint32_t const target = m_weak.fetch_sub(1, std::memory_order_relaxed) - 1; if (target == 0) { @@ -711,9 +711,9 @@ namespace winrt::impl return target; } - int32_t __stdcall Resolve(guid const& id, void** objectReference) noexcept final + std::int32_t __stdcall Resolve(guid const& id, void** objectReference) noexcept final { - uint32_t target = m_strong.load(std::memory_order_relaxed); + std::uint32_t target = m_strong.load(std::memory_order_relaxed); while (true) { @@ -725,26 +725,26 @@ namespace winrt::impl if (m_strong.compare_exchange_weak(target, target + 1, std::memory_order_acquire, std::memory_order_relaxed)) { - int32_t hr = m_object->QueryInterface(id, objectReference); + std::int32_t hr = m_object->QueryInterface(id, objectReference); m_strong.fetch_sub(1, std::memory_order_relaxed); return hr; } } } - void set_strong(uint32_t const count) noexcept + void set_strong(std::uint32_t const count) noexcept { m_strong = count; } - uint32_t increment_strong() noexcept + std::uint32_t increment_strong() noexcept { return 1 + m_strong.fetch_add(1, std::memory_order_relaxed); } - uint32_t decrement_strong() noexcept + std::uint32_t decrement_strong() noexcept { - uint32_t const target = m_strong.fetch_sub(1, std::memory_order_release) - 1; + std::uint32_t const target = m_strong.fetch_sub(1, std::memory_order_release) - 1; if (target == 0) { @@ -767,8 +767,8 @@ namespace winrt::impl static_assert(sizeof(weak_source_producer) == sizeof(weak_source)); unknown_abi* m_object{}; - std::atomic m_strong{ 1 }; - std::atomic m_weak{ 1 }; + std::atomic m_strong{ 1 }; + std::atomic m_weak{ 1 }; }; template @@ -842,14 +842,14 @@ namespace winrt::impl using IInspectable = Windows::Foundation::IInspectable; using root_implements_type = root_implements; - int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept + std::int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept { if (this->outer()) { return this->outer()->QueryInterface(id, object); } - int32_t result = query_interface(id, object); + std::int32_t result = query_interface(id, object); if (result == error_no_interface && this->m_inner) { @@ -859,7 +859,7 @@ namespace winrt::impl return result; } - uint32_t __stdcall AddRef() noexcept + std::uint32_t __stdcall AddRef() noexcept { if (this->outer()) { @@ -869,7 +869,7 @@ namespace winrt::impl return NonDelegatingAddRef(); } - uint32_t __stdcall Release() noexcept + std::uint32_t __stdcall Release() noexcept { if (this->outer()) { @@ -907,7 +907,7 @@ namespace winrt::impl protected: - virtual int32_t query_interface_tearoff(guid const&, void**) const noexcept + virtual std::int32_t query_interface_tearoff(guid const&, void**) const noexcept { return error_no_interface; } @@ -922,7 +922,7 @@ namespace winrt::impl subtract_final_reference(); } - int32_t __stdcall GetIids(uint32_t* count, guid** array) noexcept + std::int32_t __stdcall GetIids(std::uint32_t* count, guid** array) noexcept { if (this->outer()) { @@ -932,7 +932,7 @@ namespace winrt::impl return NonDelegatingGetIids(count, array); } - int32_t __stdcall abi_GetRuntimeClassName(void** name) noexcept + std::int32_t __stdcall abi_GetRuntimeClassName(void** name) noexcept { if (this->outer()) { @@ -942,7 +942,7 @@ namespace winrt::impl return NonDelegatingGetRuntimeClassName(name); } - int32_t __stdcall abi_GetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept + std::int32_t __stdcall abi_GetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept { if (this->outer()) { @@ -952,11 +952,11 @@ namespace winrt::impl return NonDelegatingGetTrustLevel(trustLevel); } - uint32_t __stdcall NonDelegatingAddRef() noexcept + std::uint32_t __stdcall NonDelegatingAddRef() noexcept { if constexpr (is_weak_ref_source::value) { - uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed); + std::uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed); while (true) { @@ -965,11 +965,11 @@ namespace winrt::impl return decode_weak_ref(count_or_pointer)->increment_strong(); } - uintptr_t const target = count_or_pointer + 1; + std::uintptr_t const target = count_or_pointer + 1; if (m_references.compare_exchange_weak(count_or_pointer, target, std::memory_order_relaxed)) { - return static_cast(target); + return static_cast(target); } } } @@ -979,9 +979,9 @@ namespace winrt::impl } } - uint32_t __stdcall NonDelegatingRelease() noexcept + std::uint32_t __stdcall NonDelegatingRelease() noexcept { - uint32_t const target = subtract_reference(); + std::uint32_t const target = subtract_reference(); if (target == 0) { @@ -998,7 +998,7 @@ namespace winrt::impl return target; } - int32_t __stdcall NonDelegatingQueryInterface(guid const& id, void** object) noexcept + std::int32_t __stdcall NonDelegatingQueryInterface(guid const& id, void** object) noexcept { if (is_guid_of(id) || is_guid_of(id)) { @@ -1008,7 +1008,7 @@ namespace winrt::impl return 0; } - int32_t result = query_interface(id, object); + std::int32_t result = query_interface(id, object); if (result == error_no_interface && this->m_inner) { @@ -1018,10 +1018,10 @@ namespace winrt::impl return result; } - int32_t __stdcall NonDelegatingGetIids(uint32_t* count, guid** array) noexcept + std::int32_t __stdcall NonDelegatingGetIids(std::uint32_t* count, guid** array) noexcept { auto const& local_iids = static_cast(this)->get_local_iids(); - uint32_t const& local_count = local_iids.first; + std::uint32_t const& local_count = local_iids.first; if constexpr (root_implements_type::is_composing) { if (local_count > 0) @@ -1062,25 +1062,25 @@ namespace winrt::impl return 0; } - int32_t __stdcall NonDelegatingGetRuntimeClassName(void** name) noexcept try + std::int32_t __stdcall NonDelegatingGetRuntimeClassName(void** name) noexcept try { *name = detach_abi(static_cast(this)->GetRuntimeClassName()); return 0; } catch (...) { return to_hresult(); } - int32_t __stdcall NonDelegatingGetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept try + std::int32_t __stdcall NonDelegatingGetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept try { *trustLevel = static_cast(this)->GetTrustLevel(); return 0; } catch (...) { return to_hresult(); } - uint32_t subtract_final_reference() noexcept + std::uint32_t subtract_final_reference() noexcept { if constexpr (is_weak_ref_source::value) { - uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed); + std::uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed); while (true) { @@ -1089,11 +1089,11 @@ namespace winrt::impl return decode_weak_ref(count_or_pointer)->decrement_strong(); } - uintptr_t const target = count_or_pointer - 1; + std::uintptr_t const target = count_or_pointer - 1; if (m_references.compare_exchange_weak(count_or_pointer, target, std::memory_order_release, std::memory_order_relaxed)) { - return static_cast(target); + return static_cast(target); } } } @@ -1103,9 +1103,9 @@ namespace winrt::impl } } - uint32_t subtract_reference() noexcept + std::uint32_t subtract_reference() noexcept { - uint32_t result = subtract_final_reference(); + std::uint32_t result = subtract_final_reference(); if (result == 0) { @@ -1155,9 +1155,9 @@ namespace winrt::impl using use_module_lock = std::negation...>>; using weak_ref_t = impl::weak_ref; - std::atomic> m_references{ 1 }; + std::atomic> m_references{ 1 }; - int32_t query_interface(guid const& id, void** object) noexcept + std::int32_t query_interface(guid const& id, void** object) noexcept { *object = static_cast(this)->find_interface(id); @@ -1170,7 +1170,7 @@ namespace winrt::impl return query_interface_common(id, object); } - WINRT_IMPL_NOINLINE int32_t query_interface_common(guid const& id, void** object) noexcept + WINRT_IMPL_NOINLINE std::int32_t query_interface_common(guid const& id, void** object) noexcept { if (is_guid_of(id)) { @@ -1220,21 +1220,21 @@ namespace winrt::impl { if constexpr (is_weak_ref_source::value) { - uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed); + std::uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed); if (is_weak_ref(count_or_pointer)) { return decode_weak_ref(count_or_pointer)->get_source(); } - com_ptr weak_ref(new (std::nothrow) weak_ref_t(get_unknown(), static_cast(count_or_pointer)), take_ownership_from_abi); + com_ptr weak_ref(new (std::nothrow) weak_ref_t(get_unknown(), static_cast(count_or_pointer)), take_ownership_from_abi); if (!weak_ref) { return nullptr; } - uintptr_t const encoding = encode_weak_ref(weak_ref.get()); + std::uintptr_t const encoding = encode_weak_ref(weak_ref.get()); while (true) { @@ -1250,7 +1250,7 @@ namespace winrt::impl return decode_weak_ref(count_or_pointer)->get_source(); } - weak_ref->set_strong(static_cast(count_or_pointer)); + weak_ref->set_strong(static_cast(count_or_pointer)); } } else @@ -1260,28 +1260,28 @@ namespace winrt::impl } } - static bool is_weak_ref(intptr_t const value) noexcept + static bool is_weak_ref(std::intptr_t const value) noexcept { static_assert(is_weak_ref_source::value, "Weak references are not supported because no_weak_ref was specified."); return value < 0; } - static weak_ref_t* decode_weak_ref(uintptr_t const value) noexcept + static weak_ref_t* decode_weak_ref(std::uintptr_t const value) noexcept { static_assert(is_weak_ref_source::value, "Weak references are not supported because no_weak_ref was specified."); return reinterpret_cast(value << 1); } - static uintptr_t encode_weak_ref(weak_ref_t* value) noexcept + static std::uintptr_t encode_weak_ref(weak_ref_t* value) noexcept { static_assert(is_weak_ref_source::value, "Weak references are not supported because no_weak_ref was specified."); - constexpr uintptr_t pointer_flag = static_cast(1) << ((sizeof(uintptr_t) * 8) - 1); - WINRT_ASSERT((reinterpret_cast(value) & 1) == 0); - return (reinterpret_cast(value) >> 1) | pointer_flag; + constexpr std::uintptr_t pointer_flag = static_cast(1) << ((sizeof(std::uintptr_t) * 8) - 1); + WINRT_ASSERT((reinterpret_cast(value) & 1) == 0); + return (reinterpret_cast(value) >> 1) | pointer_flag; } virtual unknown_abi* get_unknown() const noexcept = 0; - virtual std::pair get_local_iids() const noexcept = 0; + virtual std::pair get_local_iids() const noexcept = 0; virtual hstring GetRuntimeClassName() const = 0; virtual void* find_interface(guid const&) const noexcept = 0; virtual inspectable_abi* find_inspectable() const noexcept = 0; @@ -1528,7 +1528,7 @@ WINRT_EXPORT namespace winrt impl::hresult_type __stdcall GetIids(impl::count_type* count, impl::guid_type** iids) noexcept { - return root_implements_type::GetIids(reinterpret_cast(count), reinterpret_cast(iids)); + return root_implements_type::GetIids(reinterpret_cast(count), reinterpret_cast(iids)); } impl::hresult_type __stdcall GetRuntimeClassName(impl::hstring_type* value) noexcept @@ -1556,11 +1556,11 @@ WINRT_EXPORT namespace winrt return impl::find_inspectable(static_cast(this)); } - std::pair get_local_iids() const noexcept override + std::pair get_local_iids() const noexcept override { using interfaces = impl::uncloaked_interfaces; using local_iids = impl::uncloaked_iids; - return { static_cast(local_iids::value.size()), local_iids::value.data() }; + return { static_cast(local_iids::value.size()), local_iids::value.data() }; } private: diff --git a/strings/base_includes.h b/strings/base_includes.h index a3bf308d1..d6808792b 100644 --- a/strings/base_includes.h +++ b/strings/base_includes.h @@ -6,9 +6,14 @@ #include #include #include +#include +#include #include +#include +#include #include #include +#include #include #include #include diff --git a/strings/base_iterator.h b/strings/base_iterator.h index b0ad7836d..acb0ebd42 100644 --- a/strings/base_iterator.h +++ b/strings/base_iterator.h @@ -7,13 +7,13 @@ namespace winrt::impl using iterator_concept = std::random_access_iterator_tag; using iterator_category = std::input_iterator_tag; using value_type = decltype(std::declval().GetAt(0)); - using difference_type = ptrdiff_t; + using difference_type = std::ptrdiff_t; using pointer = void; using reference = value_type; fast_iterator() noexcept = default; - fast_iterator(T const& collection, uint32_t const index) noexcept : + fast_iterator(T const& collection, std::uint32_t const index) noexcept : m_collection(&collection), m_index(index) {} @@ -46,7 +46,7 @@ namespace winrt::impl fast_iterator& operator+=(difference_type n) noexcept { - m_index += static_cast(n); + m_index += static_cast(n); return *this; } @@ -78,7 +78,7 @@ namespace winrt::impl reference operator[](difference_type n) const { - return m_collection->GetAt(m_index + static_cast(n)); + return m_collection->GetAt(m_index + static_cast(n)); } bool operator==(fast_iterator const& other) const noexcept @@ -127,7 +127,7 @@ namespace winrt::impl private: T const* m_collection = nullptr; - uint32_t m_index = 0; + std::uint32_t m_index = 0; }; template diff --git a/strings/base_lock.h b/strings/base_lock.h index cf70a001a..a0d6261e4 100644 --- a/strings/base_lock.h +++ b/strings/base_lock.h @@ -117,7 +117,7 @@ WINRT_EXPORT namespace winrt return false; } - if (!WINRT_IMPL_SleepConditionVariableSRW(&m_cv, x.get(), static_cast(milliseconds), 0)) + if (!WINRT_IMPL_SleepConditionVariableSRW(&m_cv, x.get(), static_cast(milliseconds), 0)) { return predicate(); } diff --git a/strings/base_marshaler.h b/strings/base_marshaler.h index 359cf3b47..526f4d4c3 100644 --- a/strings/base_marshaler.h +++ b/strings/base_marshaler.h @@ -1,7 +1,7 @@ namespace winrt::impl { - inline int32_t make_marshaler(unknown_abi* outer, void** result) noexcept + inline std::int32_t make_marshaler(unknown_abi* outer, void** result) noexcept { struct marshaler final : IMarshal { @@ -10,7 +10,7 @@ namespace winrt::impl m_object.copy_from(object); } - int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final + std::int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final { if (is_guid_of(id)) { @@ -22,12 +22,12 @@ namespace winrt::impl return m_object->QueryInterface(id, object); } - uint32_t __stdcall AddRef() noexcept final + std::uint32_t __stdcall AddRef() noexcept final { return ++m_references; } - uint32_t __stdcall Release() noexcept final + std::uint32_t __stdcall Release() noexcept final { auto const remaining = --m_references; @@ -39,7 +39,7 @@ namespace winrt::impl return remaining; } - int32_t __stdcall GetUnmarshalClass(guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags, guid* pCid) noexcept final + std::int32_t __stdcall GetUnmarshalClass(guid const& riid, void* pv, std::uint32_t dwDestContext, void* pvDestContext, std::uint32_t mshlflags, guid* pCid) noexcept final { if (m_marshaler) { @@ -49,7 +49,7 @@ namespace winrt::impl return error_bad_alloc; } - int32_t __stdcall GetMarshalSizeMax(guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags, uint32_t* pSize) noexcept final + std::int32_t __stdcall GetMarshalSizeMax(guid const& riid, void* pv, std::uint32_t dwDestContext, void* pvDestContext, std::uint32_t mshlflags, std::uint32_t* pSize) noexcept final { if (m_marshaler) { @@ -59,7 +59,7 @@ namespace winrt::impl return error_bad_alloc; } - int32_t __stdcall MarshalInterface(void* pStm, guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags) noexcept final + std::int32_t __stdcall MarshalInterface(void* pStm, guid const& riid, void* pv, std::uint32_t dwDestContext, void* pvDestContext, std::uint32_t mshlflags) noexcept final { if (m_marshaler) { @@ -69,7 +69,7 @@ namespace winrt::impl return error_bad_alloc; } - int32_t __stdcall UnmarshalInterface(void* pStm, guid const& riid, void** ppv) noexcept final + std::int32_t __stdcall UnmarshalInterface(void* pStm, guid const& riid, void** ppv) noexcept final { if (m_marshaler) { @@ -80,7 +80,7 @@ namespace winrt::impl return error_bad_alloc; } - int32_t __stdcall ReleaseMarshalData(void* pStm) noexcept final + std::int32_t __stdcall ReleaseMarshalData(void* pStm) noexcept final { if (m_marshaler) { @@ -90,7 +90,7 @@ namespace winrt::impl return error_bad_alloc; } - int32_t __stdcall DisconnectObject(uint32_t dwReserved) noexcept final + std::int32_t __stdcall DisconnectObject(std::uint32_t dwReserved) noexcept final { if (m_marshaler) { diff --git a/strings/base_natvis.h b/strings/base_natvis.h index 8ff4bd145..60c5f5548 100644 --- a/strings/base_natvis.h +++ b/strings/base_natvis.h @@ -15,19 +15,19 @@ namespace winrt::impl { bool b; wchar_t c; - int8_t i1; - int16_t i2; - int32_t i4; - int64_t i8; - uint8_t u1; - uint16_t u2; - uint32_t u4; - uint64_t u8; + std::int8_t i1; + std::int16_t i2; + std::int32_t i4; + std::int64_t i8; + std::uint8_t u1; + std::uint16_t u2; + std::uint32_t u4; + std::uint64_t u8; float r4; double r8; guid g; void* s; - uint8_t v[1024]; + std::uint8_t v[1024]; } value; value.s = 0; @@ -38,16 +38,16 @@ namespace winrt::impl { void* base_address; void* allocation_base; - uint32_t allocation_protect; + std::uint32_t allocation_protect; #ifdef _WIN64 - uint32_t __alignment1; + std::uint32_t __alignment1; #endif - uintptr_t region_size; - uint32_t state; - uint32_t protect; - uint32_t type; + std::uintptr_t region_size; + std::uint32_t state; + std::uint32_t protect; + std::uint32_t type; #ifdef _WIN64 - uint32_t __alignment2; + std::uint32_t __alignment2; #endif }; memory_basic_information info; @@ -66,7 +66,7 @@ namespace winrt::impl // validate method pointer is executable if ((WINRT_IMPL_VirtualQuery(vfunc, &info, sizeof(info)) != 0) && ((info.protect & 0xF0) != 0)) { - typedef int32_t(__stdcall inspectable_abi:: * PropertyAccessor)(void*); + typedef std::int32_t(__stdcall inspectable_abi:: * PropertyAccessor)(void*); (pinsp->**(PropertyAccessor*)&vfunc)(&value); pinsp->Release(); } diff --git a/strings/base_reference_produce.h b/strings/base_reference_produce.h index 8ea2de5b9..570ba42e0 100644 --- a/strings/base_reference_produce.h +++ b/strings/base_reference_produce.h @@ -23,39 +23,39 @@ namespace winrt::impl return std::is_arithmetic_v || std::is_enum_v; } - uint8_t GetUInt8() const + std::uint8_t GetUInt8() const { - return to_scalar(); + return to_scalar(); } - int16_t GetInt16() const + std::int16_t GetInt16() const { - return to_scalar(); + return to_scalar(); } - uint16_t GetUInt16() const + std::uint16_t GetUInt16() const { - return to_scalar(); + return to_scalar(); } - int32_t GetInt32() const + std::int32_t GetInt32() const { - return to_scalar(); + return to_scalar(); } - uint32_t GetUInt32() const + std::uint32_t GetUInt32() const { - return to_scalar(); + return to_scalar(); } - int64_t GetInt64() const + std::int64_t GetInt64() const { - return to_scalar(); + return to_scalar(); } - uint64_t GetUInt64() const + std::uint64_t GetUInt64() const { - return to_scalar(); + return to_scalar(); } float GetSingle() { throw hresult_not_implemented(); } @@ -69,13 +69,13 @@ namespace winrt::impl Windows::Foundation::Point GetPoint() { throw hresult_not_implemented(); } Windows::Foundation::Size GetSize() { throw hresult_not_implemented(); } Windows::Foundation::Rect GetRect() { throw hresult_not_implemented(); } - void GetUInt8Array(com_array &) { throw hresult_not_implemented(); } - void GetInt16Array(com_array &) { throw hresult_not_implemented(); } - void GetUInt16Array(com_array &) { throw hresult_not_implemented(); } - void GetInt32Array(com_array &) { throw hresult_not_implemented(); } - void GetUInt32Array(com_array &) { throw hresult_not_implemented(); } - void GetInt64Array(com_array &) { throw hresult_not_implemented(); } - void GetUInt64Array(com_array &) { throw hresult_not_implemented(); } + void GetUInt8Array(com_array &) { throw hresult_not_implemented(); } + void GetInt16Array(com_array &) { throw hresult_not_implemented(); } + void GetUInt16Array(com_array &) { throw hresult_not_implemented(); } + void GetInt32Array(com_array &) { throw hresult_not_implemented(); } + void GetUInt32Array(com_array &) { throw hresult_not_implemented(); } + void GetInt64Array(com_array &) { throw hresult_not_implemented(); } + void GetUInt64Array(com_array &) { throw hresult_not_implemented(); } void GetSingleArray(com_array &) { throw hresult_not_implemented(); } void GetDoubleArray(com_array &) { throw hresult_not_implemented(); } void GetChar16Array(com_array &) { throw hresult_not_implemented(); } @@ -115,52 +115,52 @@ namespace winrt::impl }; template <> - struct reference_traits + struct reference_traits { - static auto make(uint8_t value) { return Windows::Foundation::PropertyValue::CreateUInt8(value); } - using itf = Windows::Foundation::IReference; + static auto make(std::uint8_t value) { return Windows::Foundation::PropertyValue::CreateUInt8(value); } + using itf = Windows::Foundation::IReference; }; template <> - struct reference_traits + struct reference_traits { - static auto make(uint16_t value) { return Windows::Foundation::PropertyValue::CreateUInt16(value); } - using itf = Windows::Foundation::IReference; + static auto make(std::uint16_t value) { return Windows::Foundation::PropertyValue::CreateUInt16(value); } + using itf = Windows::Foundation::IReference; }; template <> - struct reference_traits + struct reference_traits { - static auto make(int16_t value) { return Windows::Foundation::PropertyValue::CreateInt16(value); } - using itf = Windows::Foundation::IReference; + static auto make(std::int16_t value) { return Windows::Foundation::PropertyValue::CreateInt16(value); } + using itf = Windows::Foundation::IReference; }; template <> - struct reference_traits + struct reference_traits { - static auto make(uint32_t value) { return Windows::Foundation::PropertyValue::CreateUInt32(value); } - using itf = Windows::Foundation::IReference; + static auto make(std::uint32_t value) { return Windows::Foundation::PropertyValue::CreateUInt32(value); } + using itf = Windows::Foundation::IReference; }; template <> - struct reference_traits + struct reference_traits { - static auto make(int32_t value) { return Windows::Foundation::PropertyValue::CreateInt32(value); } - using itf = Windows::Foundation::IReference; + static auto make(std::int32_t value) { return Windows::Foundation::PropertyValue::CreateInt32(value); } + using itf = Windows::Foundation::IReference; }; template <> - struct reference_traits + struct reference_traits { - static auto make(uint64_t value) { return Windows::Foundation::PropertyValue::CreateUInt64(value); } - using itf = Windows::Foundation::IReference; + static auto make(std::uint64_t value) { return Windows::Foundation::PropertyValue::CreateUInt64(value); } + using itf = Windows::Foundation::IReference; }; template <> - struct reference_traits + struct reference_traits { - static auto make(int64_t value) { return Windows::Foundation::PropertyValue::CreateInt64(value); } - using itf = Windows::Foundation::IReference; + static auto make(std::int64_t value) { return Windows::Foundation::PropertyValue::CreateInt64(value); } + using itf = Windows::Foundation::IReference; }; template <> @@ -255,52 +255,52 @@ namespace winrt::impl }; template <> - struct reference_traits> + struct reference_traits> { - static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateUInt8Array(value); } - using itf = Windows::Foundation::IReferenceArray; + static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateUInt8Array(value); } + using itf = Windows::Foundation::IReferenceArray; }; template <> - struct reference_traits> + struct reference_traits> { - static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateInt16Array(value); } - using itf = Windows::Foundation::IReferenceArray; + static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateInt16Array(value); } + using itf = Windows::Foundation::IReferenceArray; }; template <> - struct reference_traits> + struct reference_traits> { - static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateUInt16Array(value); } - using itf = Windows::Foundation::IReferenceArray; + static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateUInt16Array(value); } + using itf = Windows::Foundation::IReferenceArray; }; template <> - struct reference_traits> + struct reference_traits> { - static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateInt32Array(value); } - using itf = Windows::Foundation::IReferenceArray; + static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateInt32Array(value); } + using itf = Windows::Foundation::IReferenceArray; }; template <> - struct reference_traits> + struct reference_traits> { - static auto make(com_array const& value) { return Windows::Foundation::PropertyValue::CreateUInt32Array(value); } - using itf = Windows::Foundation::IReferenceArray; + static auto make(com_array const& value) { return Windows::Foundation::PropertyValue::CreateUInt32Array(value); } + using itf = Windows::Foundation::IReferenceArray; }; template <> - struct reference_traits> + struct reference_traits> { - static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateInt64Array(value); } - using itf = Windows::Foundation::IReferenceArray; + static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateInt64Array(value); } + using itf = Windows::Foundation::IReferenceArray; }; template <> - struct reference_traits> + struct reference_traits> { - static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateUInt64Array(value); } - using itf = Windows::Foundation::IReferenceArray; + static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateUInt64Array(value); } + using itf = Windows::Foundation::IReferenceArray; }; template <> diff --git a/strings/base_security.h b/strings/base_security.h index 8160f11ad..a912487e4 100644 --- a/strings/base_security.h +++ b/strings/base_security.h @@ -18,7 +18,7 @@ WINRT_EXPORT namespace winrt if (!WINRT_IMPL_OpenThreadToken(WINRT_IMPL_GetCurrentThread(), 0x0004 /*TOKEN_IMPERSONATE*/, 1, token.put())) { - uint32_t const error = WINRT_IMPL_GetLastError(); + std::uint32_t const error = WINRT_IMPL_GetLastError(); if (error != 1008 /*ERROR_NO_TOKEN*/) { diff --git a/strings/base_std_hash.h b/strings/base_std_hash.h index eb97db0e9..864c31b13 100644 --- a/strings/base_std_hash.h +++ b/strings/base_std_hash.h @@ -1,19 +1,19 @@ namespace winrt::impl { - inline size_t hash_data(void const* ptr, size_t const bytes) noexcept + inline std::size_t hash_data(void const* ptr, std::size_t const bytes) noexcept { #ifdef _WIN64 - constexpr size_t fnv_offset_basis = 14695981039346656037ULL; - constexpr size_t fnv_prime = 1099511628211ULL; + constexpr std::size_t fnv_offset_basis = 14695981039346656037ULL; + constexpr std::size_t fnv_prime = 1099511628211ULL; #else - constexpr size_t fnv_offset_basis = 2166136261U; - constexpr size_t fnv_prime = 16777619U; + constexpr std::size_t fnv_offset_basis = 2166136261U; + constexpr std::size_t fnv_prime = 16777619U; #endif - size_t result = fnv_offset_basis; - uint8_t const* const buffer = static_cast(ptr); + std::size_t result = fnv_offset_basis; + std::uint8_t const* const buffer = static_cast(ptr); - for (size_t next = 0; next < bytes; ++next) + for (std::size_t next = 0; next < bytes; ++next) { result ^= buffer[next]; result *= fnv_prime; @@ -24,7 +24,7 @@ namespace winrt::impl struct hash_base { - size_t operator()(Windows::Foundation::IUnknown const& value) const noexcept + std::size_t operator()(Windows::Foundation::IUnknown const& value) const noexcept { void* const abi_value = get_abi(value.try_as()); return std::hash{}(abi_value); @@ -36,7 +36,7 @@ namespace std { template<> struct hash { - size_t operator()(winrt::hstring const& value) const noexcept + std::size_t operator()(winrt::hstring const& value) const noexcept { return std::hash{}(value); } @@ -48,7 +48,7 @@ namespace std template<> struct hash { - size_t operator()(winrt::guid const& value) const noexcept + std::size_t operator()(winrt::guid const& value) const noexcept { return winrt::impl::hash_data(&value, sizeof(value)); } diff --git a/strings/base_string.h b/strings/base_string.h index 81229e3d5..c2ba6c742 100644 --- a/strings/base_string.h +++ b/strings/base_string.h @@ -5,21 +5,21 @@ namespace winrt::impl { atomic_ref_count() noexcept = default; - explicit atomic_ref_count(uint32_t count) noexcept : m_count(count) + explicit atomic_ref_count(std::uint32_t count) noexcept : m_count(count) { } - uint32_t operator=(uint32_t count) noexcept + std::uint32_t operator=(std::uint32_t count) noexcept { return m_count = count; } - uint32_t operator++() noexcept + std::uint32_t operator++() noexcept { - return static_cast(m_count.fetch_add(1, std::memory_order_relaxed) + 1); + return static_cast(m_count.fetch_add(1, std::memory_order_relaxed) + 1); } - uint32_t operator--() noexcept + std::uint32_t operator--() noexcept { auto const remaining = m_count.fetch_sub(1, std::memory_order_release) - 1; @@ -29,30 +29,30 @@ namespace winrt::impl } else if (remaining < 0) { - abort(); + std::abort(); } - return static_cast(remaining); + return static_cast(remaining); } - operator uint32_t() const noexcept + operator std::uint32_t() const noexcept { - return static_cast(m_count); + return static_cast(m_count); } private: - std::atomic m_count; + std::atomic m_count; }; - constexpr uint32_t hstring_reference_flag{ 1 }; + constexpr std::uint32_t hstring_reference_flag{ 1 }; struct hstring_header { - uint32_t flags; - uint32_t length; - uint32_t padding1; - uint32_t padding2; + std::uint32_t flags; + std::uint32_t length; + std::uint32_t padding1; + std::uint32_t padding2; wchar_t const* ptr; }; @@ -72,12 +72,12 @@ namespace winrt::impl } } - inline shared_hstring_header* precreate_hstring_on_heap(uint32_t length) + inline shared_hstring_header* precreate_hstring_on_heap(std::uint32_t length) { WINRT_ASSERT(length != 0); - uint64_t bytes_required = static_cast(sizeof(shared_hstring_header)) + static_cast(sizeof(wchar_t)) * static_cast(length); + std::uint64_t bytes_required = static_cast(sizeof(shared_hstring_header)) + static_cast(sizeof(wchar_t)) * static_cast(length); - if (bytes_required > UINT_MAX) + if (bytes_required > (std::numeric_limits::max)()) { throw std::invalid_argument("length"); } @@ -97,7 +97,7 @@ namespace winrt::impl return header; } - inline hstring_header* create_hstring_on_heap(wchar_t const* value, uint32_t length) + inline hstring_header* create_hstring_on_heap(wchar_t const* value, std::uint32_t length) { if (!length) { @@ -105,18 +105,18 @@ namespace winrt::impl } auto header = precreate_hstring_on_heap(length); - memcpy_s(header->buffer, sizeof(wchar_t) * length, value, sizeof(wchar_t) * length); + std::copy_n(value, length, header->buffer); return header; } - inline void create_hstring_on_stack(hstring_header& header, wchar_t const* value, uint32_t length) noexcept + inline void create_hstring_on_stack(hstring_header& header, wchar_t const* value, std::uint32_t length) noexcept { WINRT_ASSERT(value); WINRT_ASSERT(length != 0); if (value[length] != 0) { - abort(); + std::abort(); } header.flags = hstring_reference_flag; @@ -162,7 +162,7 @@ WINRT_EXPORT namespace winrt struct hstring { using value_type = wchar_t; - using size_type = uint32_t; + using size_type = std::uint32_t; using const_reference = value_type const&; using pointer = value_type*; using const_pointer = value_type const*; @@ -191,7 +191,7 @@ WINRT_EXPORT namespace winrt hstring& operator=(std::nullptr_t) = delete; hstring(std::initializer_list value) : - hstring(value.begin(), static_cast(value.size())) + hstring(value.begin(), static_cast(value.size())) {} hstring(wchar_t const* value) : @@ -428,12 +428,12 @@ WINRT_EXPORT namespace winrt inline void* detach_abi(std::wstring_view const& value) { - return impl::create_hstring_on_heap(value.data(), static_cast(value.size())); + return impl::create_hstring_on_heap(value.data(), static_cast(value.size())); } inline void* detach_abi(wchar_t const* const value) { - return impl::create_hstring_on_heap(value, static_cast(wcslen(value))); + return impl::create_hstring_on_heap(value, static_cast(std::wcslen(value))); } } @@ -459,7 +459,7 @@ namespace winrt::impl hstring_builder(hstring_builder const&) = delete; hstring_builder& operator=(hstring_builder const&) = delete; - explicit hstring_builder(uint32_t const size) : + explicit hstring_builder(std::uint32_t const size) : m_handle(impl::precreate_hstring_on_heap(size)) { } @@ -574,8 +574,8 @@ namespace winrt::impl // when non-const (e.g. ranges::filter_view) so taking a const reference // as parameter wouldn't work for all scenarios. auto const size = std::formatted_size(args...); - WINRT_ASSERT(size < INT_MAX); - auto const size32 = static_cast(size); + WINRT_ASSERT(size < static_cast((std::numeric_limits::max)())); + auto const size32 = static_cast(size); hstring_builder builder(size32); WINRT_VERIFY_(size32, std::format_to_n(builder.data(), size32, args...).size); @@ -608,42 +608,42 @@ WINRT_EXPORT namespace winrt }); } - inline hstring to_hstring(uint8_t value) + inline hstring to_hstring(std::uint8_t value) { return impl::hstring_convert(value); } - inline hstring to_hstring(int8_t value) + inline hstring to_hstring(std::int8_t value) { return impl::hstring_convert(value); } - inline hstring to_hstring(uint16_t value) + inline hstring to_hstring(std::uint16_t value) { return impl::hstring_convert(value); } - inline hstring to_hstring(int16_t value) + inline hstring to_hstring(std::int16_t value) { return impl::hstring_convert(value); } - inline hstring to_hstring(uint32_t value) + inline hstring to_hstring(std::uint32_t value) { return impl::hstring_convert(value); } - inline hstring to_hstring(int32_t value) + inline hstring to_hstring(std::int32_t value) { return impl::hstring_convert(value); } - inline hstring to_hstring(uint64_t value) + inline hstring to_hstring(std::uint64_t value) { return impl::hstring_convert(value); } - inline hstring to_hstring(int64_t value) + inline hstring to_hstring(std::int64_t value) { return impl::hstring_convert(value); } @@ -688,7 +688,7 @@ WINRT_EXPORT namespace winrt { wchar_t buffer[40]; //{00000000-0000-0000-0000-000000000000} - swprintf_s(buffer, L"{%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx}", + std::swprintf(buffer, std::size(buffer), L"{%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx}", value.Data1, value.Data2, value.Data3, value.Data4[0], value.Data4[1], value.Data4[2], value.Data4[3], value.Data4[4], value.Data4[5], value.Data4[6], value.Data4[7]); return hstring{ buffer }; @@ -698,7 +698,7 @@ WINRT_EXPORT namespace winrt hstring to_hstring(T const& value) { std::string_view const view(value); - int const size = WINRT_IMPL_MultiByteToWideChar(65001 /*CP_UTF8*/, 0, view.data(), static_cast(view.size()), nullptr, 0); + int const size = WINRT_IMPL_MultiByteToWideChar(65001 /*CP_UTF8*/, 0, view.data(), static_cast(view.size()), nullptr, 0); if (size == 0) { @@ -706,13 +706,13 @@ WINRT_EXPORT namespace winrt } impl::hstring_builder result(size); - WINRT_VERIFY_(size, WINRT_IMPL_MultiByteToWideChar(65001 /*CP_UTF8*/, 0, view.data(), static_cast(view.size()), result.data(), size)); + WINRT_VERIFY_(size, WINRT_IMPL_MultiByteToWideChar(65001 /*CP_UTF8*/, 0, view.data(), static_cast(view.size()), result.data(), size)); return result.to_hstring(); } inline std::string to_string(std::wstring_view value) { - int const size = WINRT_IMPL_WideCharToMultiByte(65001 /*CP_UTF8*/, 0, value.data(), static_cast(value.size()), nullptr, 0, nullptr, nullptr); + int const size = WINRT_IMPL_WideCharToMultiByte(65001 /*CP_UTF8*/, 0, value.data(), static_cast(value.size()), nullptr, 0, nullptr, nullptr); if (size == 0) { @@ -720,7 +720,7 @@ WINRT_EXPORT namespace winrt } std::string result(size, '?'); - WINRT_VERIFY_(size, WINRT_IMPL_WideCharToMultiByte(65001 /*CP_UTF8*/, 0, value.data(), static_cast(value.size()), result.data(), size, nullptr, nullptr)); + WINRT_VERIFY_(size, WINRT_IMPL_WideCharToMultiByte(65001 /*CP_UTF8*/, 0, value.data(), static_cast(value.size()), result.data(), size, nullptr, nullptr)); return result; } } diff --git a/strings/base_string_input.h b/strings/base_string_input.h index 8cfea212b..5ac0221f6 100644 --- a/strings/base_string_input.h +++ b/strings/base_string_input.h @@ -30,7 +30,7 @@ WINRT_EXPORT namespace winrt::param hstring(wchar_t const* const value) noexcept { - create_string_reference(value, wcslen(value)); + create_string_reference(value, std::wcslen(value)); } operator winrt::hstring const&() const noexcept @@ -39,10 +39,10 @@ WINRT_EXPORT namespace winrt::param } private: - void create_string_reference(wchar_t const* const data, size_t size) noexcept + void create_string_reference(wchar_t const* const data, std::size_t size) noexcept { - WINRT_ASSERT(size < UINT_MAX); - auto size32 = static_cast(size); + WINRT_ASSERT(size < (std::numeric_limits::max)()); + auto size32 = static_cast(size); if (size32 == 0) { diff --git a/strings/base_string_operators.h b/strings/base_string_operators.h index b00150f92..25e2eccce 100644 --- a/strings/base_string_operators.h +++ b/strings/base_string_operators.h @@ -98,14 +98,14 @@ namespace winrt::impl { inline hstring concat_hstring(std::wstring_view const& left, std::wstring_view const& right) { - auto size = static_cast(left.size() + right.size()); + auto size = static_cast(left.size() + right.size()); if (size == 0) { return{}; } hstring_builder text(size); - memcpy_s(text.data(), left.size() * sizeof(wchar_t), left.data(), left.size() * sizeof(wchar_t)); - memcpy_s(text.data() + left.size(), right.size() * sizeof(wchar_t), right.data(), right.size() * sizeof(wchar_t)); + std::copy_n(left.data(), left.size(), text.data()); + std::copy_n(right.data(), right.size(), text.data() + left.size()); return text.to_hstring(); } } diff --git a/strings/base_types.h b/strings/base_types.h index 84cf22f5d..18529e116 100644 --- a/strings/base_types.h +++ b/strings/base_types.h @@ -14,25 +14,25 @@ namespace winrt::impl struct com_callback_args { - uint32_t reserved1; - uint32_t reserved2; + std::uint32_t reserved1; + std::uint32_t reserved2; void* data; }; template - constexpr uint8_t hex_to_uint(T const c) + constexpr std::uint8_t hex_to_uint(T const c) { if (c >= '0' && c <= '9') { - return static_cast(c - '0'); + return static_cast(c - '0'); } else if (c >= 'A' && c <= 'F') { - return static_cast(10 + c - 'A'); + return static_cast(10 + c - 'A'); } else if (c >= 'a' && c <= 'f') { - return static_cast(10 + c - 'a'); + return static_cast(10 + c - 'a'); } else { @@ -41,20 +41,20 @@ namespace winrt::impl } template - constexpr uint8_t hex_to_uint8(T const a, T const b) + constexpr std::uint8_t hex_to_uint8(T const a, T const b) { return (hex_to_uint(a) << 4) | hex_to_uint(b); } - constexpr uint16_t uint8_to_uint16(uint8_t a, uint8_t b) + constexpr std::uint16_t uint8_to_uint16(std::uint8_t a, std::uint8_t b) { - return (static_cast(a) << 8) | static_cast(b); + return (static_cast(a) << 8) | static_cast(b); } - constexpr uint32_t uint8_to_uint32(uint8_t a, uint8_t b, uint8_t c, uint8_t d) + constexpr std::uint32_t uint8_to_uint32(std::uint8_t a, std::uint8_t b, std::uint8_t c, std::uint8_t d) { - return (static_cast(uint8_to_uint16(a, b)) << 16) | - static_cast(uint8_to_uint16(c, d)); + return (static_cast(uint8_to_uint16(a, b)) << 16) | + static_cast(uint8_to_uint16(c, d)); } } @@ -66,15 +66,15 @@ WINRT_EXPORT namespace winrt struct hresult { - int32_t value{}; + std::int32_t value{}; constexpr hresult() noexcept = default; - constexpr hresult(int32_t const value) noexcept : value(value) + constexpr hresult(std::int32_t const value) noexcept : value(value) { } - constexpr operator int32_t() const noexcept + constexpr operator std::int32_t() const noexcept { return value; } @@ -133,14 +133,14 @@ WINRT_EXPORT namespace winrt public: - uint32_t Data1; - uint16_t Data2; - uint16_t Data3; - uint8_t Data4[8]; + std::uint32_t Data1; + std::uint16_t Data2; + std::uint16_t Data3; + std::uint8_t Data4[8]; guid() noexcept = default; - constexpr guid(uint32_t const Data1, uint16_t const Data2, uint16_t const Data3, std::array const& Data4) noexcept : + constexpr guid(std::uint32_t const Data1, std::uint16_t const Data2, std::uint16_t const Data3, std::array const& Data4) noexcept : Data1(Data1), Data2(Data2), Data3(Data3), @@ -178,7 +178,7 @@ WINRT_EXPORT namespace winrt inline bool operator==(guid const& left, guid const& right) noexcept { - return !memcmp(&left, &right, sizeof(left)); + return !std::memcmp(&left, &right, sizeof(left)); } inline bool operator!=(guid const& left, guid const& right) noexcept @@ -188,13 +188,13 @@ WINRT_EXPORT namespace winrt inline bool operator<(guid const& left, guid const& right) noexcept { - return memcmp(&left, &right, sizeof(left)) < 0; + return std::memcmp(&left, &right, sizeof(left)) < 0; } } WINRT_EXPORT namespace winrt::Windows::Foundation { - enum class TrustLevel : int32_t + enum class TrustLevel : std::int32_t { BaseTrust, PartialTrust, @@ -204,7 +204,7 @@ WINRT_EXPORT namespace winrt::Windows::Foundation struct IUnknown; struct IInspectable; struct IActivationFactory; - using TimeSpan = std::chrono::duration; + using TimeSpan = std::chrono::duration; using DateTime = std::chrono::time_point; } @@ -215,8 +215,8 @@ namespace winrt::impl using count_type = unsigned long; using guid_type = GUID; #else - using hresult_type = int32_t; - using count_type = uint32_t; + using hresult_type = std::int32_t; + using count_type = std::uint32_t; using guid_type = guid; #endif diff --git a/strings/base_version.h b/strings/base_version.h index adb3608da..4a6b68e66 100644 --- a/strings/base_version.h +++ b/strings/base_version.h @@ -16,7 +16,7 @@ char const * const WINRT_version = "C++/WinRT version:" CPPWINRT_VERSION; WINRT_EXPORT namespace winrt { - template + template constexpr bool check_version(char const(&base)[BaseSize], char const(&component)[ComponentSize]) noexcept { if constexpr (BaseSize != ComponentSize) @@ -24,7 +24,7 @@ WINRT_EXPORT namespace winrt return false; } - for (size_t i = 0; i != BaseSize - 1; ++i) + for (std::size_t i = 0; i != BaseSize - 1; ++i) { if (base[i] != component[i]) { diff --git a/strings/base_windows.h b/strings/base_windows.h index 831e1b1fe..21c4163e5 100644 --- a/strings/base_windows.h +++ b/strings/base_windows.h @@ -6,12 +6,12 @@ namespace winrt::impl struct factory_diagnostics_info { bool is_agile{ true }; - uint32_t requests{ 0 }; + std::uint32_t requests{ 0 }; }; struct diagnostics_info { - std::map queries; + std::map queries; std::map factories; }; @@ -163,7 +163,7 @@ WINRT_EXPORT namespace winrt::Windows::Foundation { IUnknown() noexcept = default; IUnknown(std::nullptr_t) noexcept {} - void* operator new(size_t) = delete; + void* operator new(std::size_t) = delete; IUnknown(void* ptr, take_ownership_from_abi_t) noexcept : m_ptr(static_cast(ptr)) { diff --git a/strings/base_xaml_component_connector.h b/strings/base_xaml_component_connector.h index 366e18e22..092944613 100644 --- a/strings/base_xaml_component_connector.h +++ b/strings/base_xaml_component_connector.h @@ -17,7 +17,7 @@ WINRT_EXPORT namespace winrt::Windows::UI::Xaml::Markup D::InitializeComponent(); } - void Connect(int32_t connectionId, winrt::Windows::Foundation::IInspectable const& target) + void Connect(std::int32_t connectionId, winrt::Windows::Foundation::IInspectable const& target) { if constexpr (m_has_connectable_base) { @@ -30,7 +30,7 @@ WINRT_EXPORT namespace winrt::Windows::UI::Xaml::Markup D::Connect(connectionId, target); } - auto GetBindingConnector(int32_t connectionId, winrt::Windows::Foundation::IInspectable const& target) + auto GetBindingConnector(std::int32_t connectionId, winrt::Windows::Foundation::IInspectable const& target) { if constexpr (m_has_connectable_base) { diff --git a/strings/base_xaml_component_connector_winui.h b/strings/base_xaml_component_connector_winui.h index 4a1f0326a..312f5af29 100644 --- a/strings/base_xaml_component_connector_winui.h +++ b/strings/base_xaml_component_connector_winui.h @@ -17,7 +17,7 @@ WINRT_EXPORT namespace winrt::Microsoft::UI::Xaml::Markup D::InitializeComponent(); } - void Connect(int32_t connectionId, winrt::Windows::Foundation::IInspectable const& target) + void Connect(std::int32_t connectionId, winrt::Windows::Foundation::IInspectable const& target) { if constexpr (m_has_connectable_base) { @@ -30,7 +30,7 @@ WINRT_EXPORT namespace winrt::Microsoft::UI::Xaml::Markup D::Connect(connectionId, target); } - auto GetBindingConnector(int32_t connectionId, winrt::Windows::Foundation::IInspectable const& target) + auto GetBindingConnector(std::int32_t connectionId, winrt::Windows::Foundation::IInspectable const& target) { if constexpr (m_has_connectable_base) { diff --git a/strings/base_xaml_typename.h b/strings/base_xaml_typename.h index 4a782fc72..b7b3a954a 100644 --- a/strings/base_xaml_typename.h +++ b/strings/base_xaml_typename.h @@ -66,42 +66,42 @@ namespace winrt::impl static constexpr Windows::UI::Xaml::Interop::TypeKind value = Windows::UI::Xaml::Interop::TypeKind::Primitive; }; template<> - struct xaml_typename_kind + struct xaml_typename_kind { static constexpr Windows::UI::Xaml::Interop::TypeKind value = Windows::UI::Xaml::Interop::TypeKind::Primitive; }; template<> - struct xaml_typename_kind + struct xaml_typename_kind { static constexpr Windows::UI::Xaml::Interop::TypeKind value = Windows::UI::Xaml::Interop::TypeKind::Primitive; }; template<> - struct xaml_typename_kind + struct xaml_typename_kind { static constexpr Windows::UI::Xaml::Interop::TypeKind value = Windows::UI::Xaml::Interop::TypeKind::Primitive; }; template<> - struct xaml_typename_kind + struct xaml_typename_kind { static constexpr Windows::UI::Xaml::Interop::TypeKind value = Windows::UI::Xaml::Interop::TypeKind::Primitive; }; template<> - struct xaml_typename_kind + struct xaml_typename_kind { static constexpr Windows::UI::Xaml::Interop::TypeKind value = Windows::UI::Xaml::Interop::TypeKind::Primitive; }; template<> - struct xaml_typename_kind + struct xaml_typename_kind { static constexpr Windows::UI::Xaml::Interop::TypeKind value = Windows::UI::Xaml::Interop::TypeKind::Primitive; }; template<> - struct xaml_typename_kind + struct xaml_typename_kind { static constexpr Windows::UI::Xaml::Interop::TypeKind value = Windows::UI::Xaml::Interop::TypeKind::Primitive; }; template<> - struct xaml_typename_kind + struct xaml_typename_kind { static constexpr Windows::UI::Xaml::Interop::TypeKind value = Windows::UI::Xaml::Interop::TypeKind::Primitive; }; From b9553a9f0faf9a1395ac98aea65716c6f44e9fca Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Thu, 19 Mar 2026 11:27:29 -0700 Subject: [PATCH 25/42] Fix race condition in multi_threaded_observable_map test (#1550) * Fix race condition in multi_threaded_observable_map test * Hook the other iterator movement methods. --- test/test/multi_threaded_common.h | 15 +++++++++++++-- test/test/multi_threaded_map.cpp | 4 ++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/test/test/multi_threaded_common.h b/test/test/multi_threaded_common.h index 026cb3264..3ed687743 100644 --- a/test/test/multi_threaded_common.h +++ b/test/test/multi_threaded_common.h @@ -45,7 +45,7 @@ namespace concurrent_collections // for the first time on the background thread. enum class collection_action { - none, push_back, insert, erase, at, lookup + none, push_back, insert, erase, at, lookup, advance }; // All of our concurrency tests consists of starting an @@ -165,16 +165,23 @@ namespace concurrent_collections return owner->dereference_iterator(inner()); } - // inherited: pointer operator->() const; + pointer operator->() const + { + auto guard = owner->lock_const(); + owner->call_hook(collection_action::at); + return iterator::operator->(); + } concurrency_checked_random_access_iterator& operator++() { + owner->call_hook(collection_action::advance); ++inner(); return *this; } concurrency_checked_random_access_iterator& operator++(int) { + owner->call_hook(collection_action::advance); auto prev = *this; ++inner(); return prev; @@ -182,12 +189,14 @@ namespace concurrent_collections concurrency_checked_random_access_iterator& operator--() { + owner->call_hook(collection_action::advance); --inner(); return *this; } concurrency_checked_random_access_iterator& operator--(int) { + owner->call_hook(collection_action::advance); auto prev = *this; --inner(); return prev; @@ -195,6 +204,7 @@ namespace concurrent_collections concurrency_checked_random_access_iterator& operator+=(difference_type offset) { + owner->call_hook(collection_action::advance); inner() += offset; return *this; } @@ -206,6 +216,7 @@ namespace concurrent_collections concurrency_checked_random_access_iterator& operator-=(difference_type offset) { + owner->call_hook(collection_action::advance); inner() -= offset; return *this; } diff --git a/test/test/multi_threaded_map.cpp b/test/test/multi_threaded_map.cpp index d0f68c1e2..ffa9988ba 100644 --- a/test/test/multi_threaded_map.cpp +++ b/test/test/multi_threaded_map.cpp @@ -237,7 +237,7 @@ namespace { // MoveNext vs Remove bool moved = false; - race(collection_action::at, [&] + race(collection_action::advance, [&] { try { @@ -273,7 +273,7 @@ namespace { // MoveNext vs Insert bool moved = false; - race(collection_action::at, [&] + race(collection_action::advance, [&] { try { From 16a1c29b5351ca5212f4235d1db5776bdd13ae78 Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Mon, 23 Mar 2026 12:46:53 -0400 Subject: [PATCH 26/42] Fix integer fields causing impl promotion (#1551) --- cppwinrt/code_writers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index 0a4c4638e..fc5081bef 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -2916,7 +2916,7 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable for (auto&& field : type.fields) { - if (field.second.find(':') == std::string::npos) + if (field.second.find(':') == std::string::npos || starts_with(field.second, "std::")) { continue; } From 3893ce8c3d0af7676c36f5f933707d442c53050b Mon Sep 17 00:00:00 2001 From: justanotheranonymoususer Date: Thu, 2 Apr 2026 02:00:22 +0300 Subject: [PATCH 27/42] box_value constructor: Replace param::hstring with hstring (#1530) * box_value constructor: Replace param::hstring with hstring * Update base_reference_produce.h * Fix and add tests * Fix github.dev bug --- strings/base_reference_produce.h | 7 +++-- test/test/box_string.cpp | 53 ++++++++++++++++++++++++++++++++ test/test/test.vcxproj | 1 + 3 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 test/test/box_string.cpp diff --git a/strings/base_reference_produce.h b/strings/base_reference_produce.h index 570ba42e0..2820aff50 100644 --- a/strings/base_reference_produce.h +++ b/strings/base_reference_produce.h @@ -509,12 +509,13 @@ namespace winrt::impl WINRT_EXPORT namespace winrt { - inline Windows::Foundation::IInspectable box_value(param::hstring const& value) + template , int> = 0> + Windows::Foundation::IInspectable box_value(T&& value) { - return Windows::Foundation::IReference(*(hstring*)(&value)); + return Windows::Foundation::IReference(hstring(std::forward(value))); } - template , int> = 0> + template , int> = 0> Windows::Foundation::IInspectable box_value(T const& value) { if constexpr (std::is_base_of_v) diff --git a/test/test/box_string.cpp b/test/test/box_string.cpp new file mode 100644 index 000000000..efff92160 --- /dev/null +++ b/test/test/box_string.cpp @@ -0,0 +1,53 @@ +#include "pch.h" + +TEST_CASE("box_string") +{ + // hstring + { + winrt::hstring value = L"hstring"; + auto boxed = winrt::box_value(value); + REQUIRE(winrt::unbox_value(boxed) == L"hstring"); + } + + // wchar_t const* (string literal) + { + auto boxed = winrt::box_value(L"literal"); + REQUIRE(winrt::unbox_value(boxed) == L"literal"); + } + + // std::wstring + { + std::wstring value = L"wstring"; + auto boxed = winrt::box_value(value); + REQUIRE(winrt::unbox_value(boxed) == L"wstring"); + } + + // std::wstring_view (null-terminated) + { + std::wstring_view value = L"view"; + auto boxed = winrt::box_value(value); + REQUIRE(winrt::unbox_value(boxed) == L"view"); + } + + // std::wstring_view (not null-terminated) + // Regression test for https://github.com/microsoft/cppwinrt/issues/1527 + { + std::wstring source = L"ABCDE"; + std::wstring_view value(source.data(), 3); // "ABC" + auto boxed = winrt::box_value(value); + REQUIRE(winrt::unbox_value(boxed) == L"ABC"); + } + + // Empty string + { + auto boxed = winrt::box_value(winrt::hstring{}); + REQUIRE(winrt::unbox_value(boxed) == L""); + } + + // Empty wstring_view + { + std::wstring_view value; + auto boxed = winrt::box_value(value); + REQUIRE(winrt::unbox_value(boxed) == L""); + } +} diff --git a/test/test/test.vcxproj b/test/test/test.vcxproj index 7840f17eb..43928dab2 100644 --- a/test/test/test.vcxproj +++ b/test/test/test.vcxproj @@ -233,6 +233,7 @@ + NotUsing From d254f72ed6d4060f0028221e3e59ee1b2f5e6efc Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 16:23:17 -0700 Subject: [PATCH 28/42] fix: normalize CRLF to LF in test/test/box_string.cpp (#1557) * Initial plan * fix: convert CRLF to LF in test/test/box_string.cpp Agent-Logs-Url: https://github.com/microsoft/cppwinrt/sessions/9b31d4ec-f1c5-4859-89a1-3249eb553c5c Co-authored-by: DefaultRyan <26174284+DefaultRyan@users.noreply.github.com> * Add workflow to check line endings in pull requests --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: DefaultRyan <26174284+DefaultRyan@users.noreply.github.com> Co-authored-by: Ryan Shepherd --- .github/workflows/check-line-endings.yml | 32 +++++++ test/test/box_string.cpp | 106 +++++++++++------------ 2 files changed, 85 insertions(+), 53 deletions(-) create mode 100644 .github/workflows/check-line-endings.yml diff --git a/.github/workflows/check-line-endings.yml b/.github/workflows/check-line-endings.yml new file mode 100644 index 000000000..a0705cf58 --- /dev/null +++ b/.github/workflows/check-line-endings.yml @@ -0,0 +1,32 @@ +name: Check Line Endings + +on: + pull_request: + push: + branches: + - master + +jobs: + check-line-endings: + name: Enforce .gitattributes line endings + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Check for line ending violations + run: | + # Re-normalize all files according to .gitattributes + git add --renormalize . + + # Check if renormalization changed anything + if git diff --cached --name-only | grep -q .; then + echo "::error::The following files have line endings that don't match .gitattributes settings:" + git diff --cached --name-only + echo "" + echo "To fix, run:" + echo " git add --renormalize ." + echo " git commit -m 'Normalize line endings'" + exit 1 + fi + + echo "All files have correct line endings." diff --git a/test/test/box_string.cpp b/test/test/box_string.cpp index efff92160..7294eeb79 100644 --- a/test/test/box_string.cpp +++ b/test/test/box_string.cpp @@ -1,53 +1,53 @@ -#include "pch.h" - -TEST_CASE("box_string") -{ - // hstring - { - winrt::hstring value = L"hstring"; - auto boxed = winrt::box_value(value); - REQUIRE(winrt::unbox_value(boxed) == L"hstring"); - } - - // wchar_t const* (string literal) - { - auto boxed = winrt::box_value(L"literal"); - REQUIRE(winrt::unbox_value(boxed) == L"literal"); - } - - // std::wstring - { - std::wstring value = L"wstring"; - auto boxed = winrt::box_value(value); - REQUIRE(winrt::unbox_value(boxed) == L"wstring"); - } - - // std::wstring_view (null-terminated) - { - std::wstring_view value = L"view"; - auto boxed = winrt::box_value(value); - REQUIRE(winrt::unbox_value(boxed) == L"view"); - } - - // std::wstring_view (not null-terminated) - // Regression test for https://github.com/microsoft/cppwinrt/issues/1527 - { - std::wstring source = L"ABCDE"; - std::wstring_view value(source.data(), 3); // "ABC" - auto boxed = winrt::box_value(value); - REQUIRE(winrt::unbox_value(boxed) == L"ABC"); - } - - // Empty string - { - auto boxed = winrt::box_value(winrt::hstring{}); - REQUIRE(winrt::unbox_value(boxed) == L""); - } - - // Empty wstring_view - { - std::wstring_view value; - auto boxed = winrt::box_value(value); - REQUIRE(winrt::unbox_value(boxed) == L""); - } -} +#include "pch.h" + +TEST_CASE("box_string") +{ + // hstring + { + winrt::hstring value = L"hstring"; + auto boxed = winrt::box_value(value); + REQUIRE(winrt::unbox_value(boxed) == L"hstring"); + } + + // wchar_t const* (string literal) + { + auto boxed = winrt::box_value(L"literal"); + REQUIRE(winrt::unbox_value(boxed) == L"literal"); + } + + // std::wstring + { + std::wstring value = L"wstring"; + auto boxed = winrt::box_value(value); + REQUIRE(winrt::unbox_value(boxed) == L"wstring"); + } + + // std::wstring_view (null-terminated) + { + std::wstring_view value = L"view"; + auto boxed = winrt::box_value(value); + REQUIRE(winrt::unbox_value(boxed) == L"view"); + } + + // std::wstring_view (not null-terminated) + // Regression test for https://github.com/microsoft/cppwinrt/issues/1527 + { + std::wstring source = L"ABCDE"; + std::wstring_view value(source.data(), 3); // "ABC" + auto boxed = winrt::box_value(value); + REQUIRE(winrt::unbox_value(boxed) == L"ABC"); + } + + // Empty string + { + auto boxed = winrt::box_value(winrt::hstring{}); + REQUIRE(winrt::unbox_value(boxed) == L""); + } + + // Empty wstring_view + { + std::wstring_view value; + auto boxed = winrt::box_value(value); + REQUIRE(winrt::unbox_value(boxed) == L""); + } +} From f23b41e92176052bff519f00d44f6497e0845413 Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Thu, 2 Apr 2026 16:46:32 -0700 Subject: [PATCH 29/42] Breaking coroutines means v3.0 (#1547) * Start moving to v3.0 * Set more obvious placeholder version numbers --- .github/workflows/ci.yml | 8 ++++---- .pipelines/OneBranch.Official.yml | 2 +- .pipelines/OneBranch.PullRequest.yml | 2 +- .pipelines/variables/version.yml | 2 +- CMakeLists.txt | 4 ++-- Directory.Build.Props | 2 +- build_nuget.cmd | 2 +- build_test_all.cmd | 2 +- build_vsix.cmd | 2 +- prebuild/main.cpp | 18 ++++++++++++++---- 10 files changed, 27 insertions(+), 17 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a42f2c5b7..cb8cafd2b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,7 +41,7 @@ jobs: run: | $target_configuration = "${{ matrix.config }}" $target_platform = "${{ matrix.arch }}" - $target_version = "1.2.3.4" + $target_version = "999.999.999.999" $props = "Configuration=$target_configuration,Platform=$target_platform,CppWinRTBuildVersion=$target_version" if ("${{ matrix.compiler }}" -eq "clang-cl") { $props += ",Clang=1,PlatformToolset=ClangCl" @@ -134,7 +134,7 @@ jobs: run: | $target_configuration = "${{ matrix.config }}" $target_platform = "${{ matrix.arch }}" - $target_version = "1.2.3.4" + $target_version = "999.999.999.999" $props = "Configuration=$target_configuration,Platform=$target_platform,CppWinRTBuildVersion=$target_version" if ("${{ matrix.compiler }}" -eq "clang-cl") { $props += ",Clang=1,PlatformToolset=ClangCl" @@ -301,7 +301,7 @@ jobs: run: | $target_configuration = "${{ matrix.config }}" $target_platform = "${{ matrix.arch }}" - $target_version = "1.2.3.4" + $target_version = "999.999.999.999" Add-Content $env:GITHUB_ENV "msbuild_config_props=/p:Configuration=$target_configuration,Platform=$target_platform,CppWinRTBuildVersion=$target_version" - name: Restore nuget packages @@ -347,7 +347,7 @@ jobs: run: | $target_configuration = "${{ matrix.config }}" $target_platform = "${{ matrix.arch }}" - $target_version = "1.2.3.4" + $target_version = "999.999.999.999" Add-Content $env:GITHUB_ENV "msbuild_config_props=/p:Configuration=$target_configuration,Platform=$target_platform,CppWinRTBuildVersion=$target_version" - name: Restore nuget packages diff --git a/.pipelines/OneBranch.Official.yml b/.pipelines/OneBranch.Official.yml index 7a73b263b..158d3bf4e 100644 --- a/.pipelines/OneBranch.Official.yml +++ b/.pipelines/OneBranch.Official.yml @@ -12,7 +12,7 @@ variables: parameters: debug: ${{ parameters.debug }} -name: 2.0.$(date:yyMMdd)$(rev:.r) +name: 3.0.$(date:yyMMdd)$(rev:.r) trigger: none diff --git a/.pipelines/OneBranch.PullRequest.yml b/.pipelines/OneBranch.PullRequest.yml index 9e18821b4..d92dccaa2 100644 --- a/.pipelines/OneBranch.PullRequest.yml +++ b/.pipelines/OneBranch.PullRequest.yml @@ -10,7 +10,7 @@ variables: parameters: debug: ${{ parameters.debug }} -name: PullRequest_2.0.$(date:yyMMdd)$(rev:.r) +name: PullRequest_3.0.$(date:yyMMdd)$(rev:.r) trigger: none diff --git a/.pipelines/variables/version.yml b/.pipelines/variables/version.yml index 15382e7df..46a535ee0 100644 --- a/.pipelines/variables/version.yml +++ b/.pipelines/variables/version.yml @@ -4,7 +4,7 @@ parameters: default: false variables: - MajorVersion: "2" + MajorVersion: "3" MinorVersion: "0" VersionDate: $[format('{0:yyMMdd}', pipeline.startTime)] VersionCounter: $[counter(variables['VersionDate'], 1)] diff --git a/CMakeLists.txt b/CMakeLists.txt index 139da8379..b0089e7ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,8 +13,8 @@ project(cppwinrt LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED True) -set(CPPWINRT_BUILD_VERSION "2.3.4.5" CACHE STRING "The version string used for cppwinrt.") -if(CPPWINRT_BUILD_VERSION STREQUAL "2.3.4.5" OR CPPWINRT_BUILD_VERSION STREQUAL "0.0.0.0") +set(CPPWINRT_BUILD_VERSION "999.999.999.999" CACHE STRING "The version string used for cppwinrt.") +if(CPPWINRT_BUILD_VERSION STREQUAL "999.999.999.999" OR CPPWINRT_BUILD_VERSION STREQUAL "0.0.0.0") message(WARNING "CPPWINRT_BUILD_VERSION has been set to a dummy version string. Do not use in production!") endif() message(STATUS "Using version string: ${CPPWINRT_BUILD_VERSION}") diff --git a/Directory.Build.Props b/Directory.Build.Props index 5f530da91..c98cd5dd0 100644 --- a/Directory.Build.Props +++ b/Directory.Build.Props @@ -37,7 +37,7 @@ - 2.3.4.5 + 999.999.999.999 $(Platform) x86 $(SolutionDir)_build\$(CppWinRTPlatform)\$(Configuration)\ diff --git a/build_nuget.cmd b/build_nuget.cmd index 3926e4d0b..99e193311 100644 --- a/build_nuget.cmd +++ b/build_nuget.cmd @@ -1,7 +1,7 @@ rem @echo off set target_version=%1 -if "%target_version%"=="" set target_version=3.0.0.0 +if "%target_version%"=="" set target_version=999.999.999.999 call msbuild /m /p:Configuration=Release,Platform=x86,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:fast_fwd call msbuild /m /p:Configuration=Release,Platform=x64,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:fast_fwd diff --git a/build_test_all.cmd b/build_test_all.cmd index 649f4dc69..c9beb852c 100644 --- a/build_test_all.cmd +++ b/build_test_all.cmd @@ -7,7 +7,7 @@ set clean_intermediate_files=%4 if "%target_platform%"=="" set target_platform=x64 if "%target_configuration%"=="" set target_configuration=Release -if "%target_version%"=="" set target_version=1.2.3.4 +if "%target_version%"=="" set target_version=999.999.999.999 if not exist ".\.nuget" mkdir ".\.nuget" if not exist ".\.nuget\nuget.exe" powershell -Command "$ProgressPreference = 'SilentlyContinue' ; Invoke-WebRequest https://dist.nuget.org/win-x86-commandline/latest/nuget.exe -OutFile .\.nuget\nuget.exe" diff --git a/build_vsix.cmd b/build_vsix.cmd index aefc84df1..0a47f6bd6 100644 --- a/build_vsix.cmd +++ b/build_vsix.cmd @@ -6,7 +6,7 @@ set target_version=%2 set target_deployment=%3 if "%target_configuration%"=="" set target_configuration=Release -if "%target_version%"=="" set target_version=1.2.3.4 +if "%target_version%"=="" set target_version=999.999.999.999 if "%target_deployment%"=="" set target_deployment=Standalone if not exist ".\.nuget" mkdir ".\.nuget" diff --git a/prebuild/main.cpp b/prebuild/main.cpp index 3e427d32b..1295f8f69 100644 --- a/prebuild/main.cpp +++ b/prebuild/main.cpp @@ -77,12 +77,19 @@ namespace cppwinrt::strings { writer version_rc; + // Extract major.minor substrings from CPPWINRT_VERSION_STRING (e.g. "3.0.250316.1") + std::string_view const full_version{ CPPWINRT_VERSION_STRING }; + auto const first_dot = full_version.find('.'); + auto const second_dot = full_version.find('.', first_dot + 1); + auto const ver_major = full_version.substr(0, first_dot); + auto const ver_minor = full_version.substr(first_dot + 1, second_dot - first_dot - 1); + version_rc.write(R"( #include "winres.h" VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,0,0,0 - PRODUCTVERSION 2,0,0,0 + FILEVERSION %,%,0,0 + PRODUCTVERSION %,%,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -99,7 +106,7 @@ BEGIN BEGIN VALUE "CompanyName", "Microsoft Corporation" VALUE "FileDescription", "C++/WinRT" - VALUE "FileVersion", "2.0.0.0" + VALUE "FileVersion", "%.%.0.0" VALUE "LegalCopyright", "Microsoft Corporation. All rights reserved." VALUE "OriginalFilename", "cppwinrt.exe" VALUE "ProductName", "C++/WinRT" @@ -112,7 +119,10 @@ BEGIN END END )", - CPPWINRT_VERSION_STRING); + ver_major, ver_minor, // FILEVERSION + ver_major, ver_minor, // PRODUCTVERSION + ver_major, ver_minor, // FileVersion string + CPPWINRT_VERSION_STRING); // ProductVersion string std::filesystem::create_directories(argv[2]); auto const output = std::filesystem::canonical(argv[2]); From 748d1e0876cf64a512dccbedd6ca72ee3bcda813 Mon Sep 17 00:00:00 2001 From: Yexuan Xiao Date: Tue, 21 Apr 2026 03:55:48 +0800 Subject: [PATCH 30/42] Add inline for hstring_reference_flag (#1571) --- strings/base_string.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strings/base_string.h b/strings/base_string.h index c2ba6c742..92295e81c 100644 --- a/strings/base_string.h +++ b/strings/base_string.h @@ -45,7 +45,7 @@ namespace winrt::impl std::atomic m_count; }; - constexpr std::uint32_t hstring_reference_flag{ 1 }; + inline constexpr std::uint32_t hstring_reference_flag{ 1 }; struct hstring_header { From a5e9452e6858849496e61c166ab8510d3acaec2a Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 16:01:47 -0700 Subject: [PATCH 31/42] CI: test against VS2022 (v143) and VS2026 (v145) in parallel (#1573) * Run Windows CI matrix on 2025 and 2025-vs2026 toolsets Agent-Logs-Url: https://github.com/microsoft/cppwinrt/sessions/b78f8378-0fed-463c-97ac-e16f18e532a9 Co-authored-by: DefaultRyan <26174284+DefaultRyan@users.noreply.github.com> * Simplify CI: drop vswhere version/prerelease fields, keep platform_toolset Agent-Logs-Url: https://github.com/microsoft/cppwinrt/sessions/d084d7e4-1d03-4234-a219-7b58887d42d5 Co-authored-by: DefaultRyan <26174284+DefaultRyan@users.noreply.github.com> * Fix clang-cl v145 build: exclude clang from memset path in com_array::detach_abi Clang 19+ (VS2026/v145) treats memset on non-trivially-copyable types as a hard error. clang-cl defines _MSC_VER, so it was taking the memset workaround path meant only for MSVC. Guard with !defined(__clang__) so clang-cl uses the safe member-assignment branch instead. Agent-Logs-Url: https://github.com/microsoft/cppwinrt/sessions/d433cd66-3565-4257-9c9d-23ec477f8c4d Co-authored-by: DefaultRyan <26174284+DefaultRyan@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: DefaultRyan <26174284+DefaultRyan@users.noreply.github.com> --- .github/workflows/ci.yml | 43 +++++++++++++++++++++++++++++----------- strings/base_array.h | 2 +- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb8cafd2b..d660400a0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,12 +8,17 @@ on: jobs: test-msvc-cppwinrt-build: - name: '${{ matrix.compiler }}: Build (${{ matrix.arch }}, ${{ matrix.config }})' + name: '${{ matrix.compiler }}: Build (${{ matrix.arch }}, ${{ matrix.config }}, ${{ matrix.toolchain.platform_toolset }})' strategy: matrix: compiler: [MSVC, clang-cl] arch: [x86, x64, arm64] config: [Debug, Release] + toolchain: + - image: windows-2025 + platform_toolset: v143 + - image: windows-2025-vs2026 + platform_toolset: v145 exclude: - arch: arm64 config: Debug @@ -21,7 +26,7 @@ jobs: arch: arm64 - compiler: clang-cl config: Release - runs-on: windows-latest + runs-on: ${{ matrix.toolchain.image }} steps: - uses: actions/checkout@v6 @@ -45,6 +50,8 @@ jobs: $props = "Configuration=$target_configuration,Platform=$target_platform,CppWinRTBuildVersion=$target_version" if ("${{ matrix.compiler }}" -eq "clang-cl") { $props += ",Clang=1,PlatformToolset=ClangCl" + } else { + $props += ",PlatformToolset=${{ matrix.toolchain.platform_toolset }}" } Add-Content $env:GITHUB_ENV "msbuild_config_props=/p:$props" @@ -68,7 +75,7 @@ jobs: - name: Upload built executables uses: actions/upload-artifact@v7 with: - name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-bin + name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-${{ matrix.toolchain.platform_toolset }}-bin path: | _build/${{ matrix.arch }}/${{ matrix.config }}/*.exe _build/${{ matrix.arch }}/${{ matrix.config }}/*.dll @@ -84,7 +91,7 @@ jobs: & "_build\$target_platform\$target_configuration\cppwinrt.exe" -in local -out _build\$target_platform\$target_configuration -verbose test-msvc-cppwinrt-test: - name: '${{ matrix.compiler }}: Test [${{ matrix.test_exe }}] (${{ matrix.arch }}, ${{ matrix.config }})' + name: '${{ matrix.compiler }}: Test [${{ matrix.test_exe }}] (${{ matrix.arch }}, ${{ matrix.config }}, ${{ matrix.toolchain.platform_toolset }})' needs: test-msvc-cppwinrt-build strategy: fail-fast: false @@ -93,6 +100,11 @@ jobs: arch: [x86, x64, arm64] config: [Debug, Release] test_exe: [test, test_nocoro, test_cpp20, test_cpp20_no_sourcelocation, test_fast, test_slow, test_old, test_module_lock_custom, test_module_lock_none] + toolchain: + - image: windows-2025 + platform_toolset: v143 + - image: windows-2025-vs2026 + platform_toolset: v145 exclude: - arch: arm64 config: Debug @@ -100,7 +112,7 @@ jobs: arch: arm64 - compiler: clang-cl config: Release - runs-on: windows-latest + runs-on: ${{ matrix.toolchain.image }} steps: - uses: actions/checkout@v6 @@ -108,14 +120,14 @@ jobs: if: matrix.arch != 'arm64' uses: actions/download-artifact@v8 with: - name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-bin + name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-${{ matrix.toolchain.platform_toolset }}-bin path: _build/${{ matrix.arch }}/${{ matrix.config }}/ - name: Fetch x86 cppwinrt executables (arm64 only) if: matrix.arch == 'arm64' uses: actions/download-artifact@v8 with: - name: msvc-build-${{ matrix.compiler}}-x86-Release-bin + name: msvc-build-${{ matrix.compiler}}-x86-Release-${{ matrix.toolchain.platform_toolset }}-bin path: _build/x86/Release/ - name: Download nuget @@ -138,6 +150,8 @@ jobs: $props = "Configuration=$target_configuration,Platform=$target_platform,CppWinRTBuildVersion=$target_version" if ("${{ matrix.compiler }}" -eq "clang-cl") { $props += ",Clang=1,PlatformToolset=ClangCl" + } else { + $props += ",PlatformToolset=${{ matrix.toolchain.platform_toolset }}" } Add-Content $env:GITHUB_ENV "msbuild_config_props=/p:$props" @@ -232,7 +246,7 @@ jobs: if: matrix.arch == 'arm64' uses: actions/upload-artifact@v7 with: - name: msvc-tests-${{ matrix.test_exe }}-${{ matrix.compiler }}-${{ matrix.arch }}-${{ matrix.config }}-bin + name: msvc-tests-${{ matrix.test_exe }}-${{ matrix.compiler }}-${{ matrix.arch }}-${{ matrix.config }}-${{ matrix.toolchain.platform_toolset }}-bin path: | _build/${{ matrix.arch }}/${{ matrix.config }}/*.exe _build/${{ matrix.arch }}/${{ matrix.config }}/*.dll @@ -313,7 +327,7 @@ jobs: cmd /c "$env:VSDevCmd" "&" msbuild /m /clp:ForceConsoleColor "$env:msbuild_config_props" /p:Deployment=${{ matrix.Deployment }} natvis\cppwinrtvisualizer.sln build-msvc-nuget-test: - name: 'Build nuget test (${{ matrix.arch }})' + name: 'Build nuget test (${{ matrix.arch }}, ${{ matrix.toolchain.platform_toolset }})' needs: test-msvc-cppwinrt-build strategy: matrix: @@ -321,14 +335,19 @@ jobs: - MSVC arch: [x86, x64] config: [Release] - runs-on: windows-latest + toolchain: + - image: windows-2025 + platform_toolset: v143 + - image: windows-2025-vs2026 + platform_toolset: v145 + runs-on: ${{ matrix.toolchain.image }} steps: - uses: actions/checkout@v6 - name: Fetch cppwinrt executables uses: actions/download-artifact@v8 with: - name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-bin + name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-${{ matrix.toolchain.platform_toolset }}-bin path: _build/${{ matrix.arch }}/${{ matrix.config }}/ - name: Download nuget @@ -348,7 +367,7 @@ jobs: $target_configuration = "${{ matrix.config }}" $target_platform = "${{ matrix.arch }}" $target_version = "999.999.999.999" - Add-Content $env:GITHUB_ENV "msbuild_config_props=/p:Configuration=$target_configuration,Platform=$target_platform,CppWinRTBuildVersion=$target_version" + Add-Content $env:GITHUB_ENV "msbuild_config_props=/p:Configuration=$target_configuration,Platform=$target_platform,CppWinRTBuildVersion=$target_version,PlatformToolset=${{ matrix.toolchain.platform_toolset }}" - name: Restore nuget packages run: | diff --git a/strings/base_array.h b/strings/base_array.h index 9544dcf8c..48d10c6ce 100644 --- a/strings/base_array.h +++ b/strings/base_array.h @@ -376,7 +376,7 @@ WINRT_EXPORT namespace winrt std::pair> detach_abi() noexcept { -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) // https://github.com/microsoft/cppwinrt/pull/1165 std::pair> result; std::memset(&result, 0, sizeof(result)); From 58811e1efe1589b0d022137c3246fc5e703df3a4 Mon Sep 17 00:00:00 2001 From: Yexuan Xiao Date: Fri, 15 May 2026 00:27:24 +0800 Subject: [PATCH 32/42] Move operator<< to winrt::Windows::Foundation (#1576) --- strings/base_stringable_streams.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/strings/base_stringable_streams.h b/strings/base_stringable_streams.h index 52b481d6f..fa17b0f3e 100644 --- a/strings/base_stringable_streams.h +++ b/strings/base_stringable_streams.h @@ -1,8 +1,11 @@ #ifndef WINRT_LEAN_AND_MEAN -inline std::wostream& operator<<(std::wostream& stream, winrt::Windows::Foundation::IStringable const& stringable) +namespace winrt::Windows::Foundation { - stream << stringable.ToString(); - return stream; + inline std::wostream& operator<<(std::wostream& stream, winrt::Windows::Foundation::IStringable const& stringable) + { + stream << stringable.ToString(); + return stream; + } } #endif From 55f1b452aca069d6ac7eaad3e05cc1058fc39d27 Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Wed, 20 May 2026 13:17:10 -0700 Subject: [PATCH 33/42] C++20 module support v2 (#1575) * Initial implementation of vs modules based on cppwinrtplus fork * Rename WINRT_MODULE -> WINRT_IMPL_BUILD_MODULE; WINRT_CONSUME_MODULE -> WINRT_IMPORT_MODULE * Namespace modules are winrt.Namespace. Non-namespace modules are winrt_base/winrt_numerics Co-authored-by: Copilot * Bootstrap basic unit test Co-authored-by: Copilot * Fix coroutine export. A few more unit tests. Co-authored-by: Copilot * module_include, module_exclude Co-authored-by: Copilot * Rename test_module to test_cpp20_module * Nuget test project with module include/exclude Co-authored-by: Copilot * Refine generated files in component. Co-authored-by: Copilot * Added a type deriving from DependencyObject Co-authored-by: Copilot * Basic module build/consume support Co-authored-by: Copilot * Prefix namespace ixx files with "winrt." for consistency with module names and built ifc files. Co-authored-by: Copilot * IFC needs better per-project scoping. Now it fully works end to end. * Minor fix to TestModuleComponent2 * Documentation and polish. Co-authored-by: YexuanXiao Co-authored-by: Copilot * Fix CI failures Co-authored-by: Copilot * Try for better std hygiene * Address some PR feedback * Better automation of AdditionalBMIDirectories Co-authored-by: Copilot * Missed fallback definition of WINRT_IMPL_STD_EXPORT * Wrap base.h and extern the handler pointers * Uniform namespace filtering * Write trailing comments for #endif * Clarify language version requirement * Add source_location test Co-authored-by: Copilot * Refactor/cleanup some string writers Co-authored-by: Copilot * Add arm64 configs and replace bogus project guids with real guids. Co-authored-by: Copilot * More cleanup of strings. Collected common macros into base_macros.h, generates into winrt/macros.h Co-authored-by: Copilot * More strings cleanup. Emit a canonical winrt/base_macros.h Co-authored-by: Copilot * More clarifications about guidance when sharing pre-built modules Co-authored-by: Copilot * Ensure structured bindings are exported for IKeyValuePair Co-authored-by: Copilot * Fix up module namespace exclude logic so it still generates import statements. * intrin.h and only needed by base, not namespace modules * Tidy up a few codegen bits * Fix sln config on test_cpp20_module project * Namespace modules now check version against imported winrt_base Co-authored-by: Copilot * PR feedback: Test format, hash, natvis hook visibility, message on old compiler Co-authored-by: Copilot * Clean up some handling of numerics-related code and add some numerics smoke tests * De-duplicate windowsnumerics.impl.h logic * A little more WINRT_IMPORT_MODULE cleanup * Use write_depends in SCC writers --------- Co-authored-by: Copilot Co-authored-by: YexuanXiao --- .github/instructions/cppwinrt.instructions.md | 58 +++ .github/instructions/modules.instructions.md | 40 ++ .github/workflows/ci.yml | 9 + cppwinrt.sln | 18 + cppwinrt/code_writers.h | 57 ++- cppwinrt/component_writers.h | 5 +- cppwinrt/file_writers.h | 374 ++++++++++++++++-- cppwinrt/main.cpp | 203 +++++++++- cppwinrt/settings.h | 6 + docs/modules-design.md | 190 +++++++++ natvis/pch.h | 1 + nuget/Microsoft.Windows.CppWinRT.targets | 95 ++++- nuget/modules.md | 179 +++++++++ nuget/readme.md | 12 + strings/base_abi.h | 2 +- strings/base_activation.h | 6 +- strings/base_agile_ref.h | 2 +- strings/base_array.h | 2 +- strings/base_collections.h | 2 +- strings/base_collections_base.h | 2 +- strings/base_collections_input_iterable.h | 2 +- strings/base_collections_input_map.h | 2 +- strings/base_collections_input_map_view.h | 2 +- strings/base_collections_input_vector.h | 2 +- strings/base_collections_input_vector_view.h | 2 +- strings/base_collections_map.h | 6 +- strings/base_collections_vector.h | 2 +- strings/base_com_ptr.h | 4 +- strings/base_composable.h | 2 +- strings/base_coroutine_foundation.h | 6 +- strings/base_coroutine_threadpool.h | 6 +- strings/base_delegate.h | 2 +- strings/base_detect_numerics.h | 4 + strings/base_error.h | 4 +- strings/base_events.h | 2 +- strings/base_extern.h | 11 +- strings/base_fast_forward.h | 6 +- strings/base_foundation.h | 2 +- strings/base_identity.h | 2 +- strings/base_implements.h | 6 +- strings/base_include_numerics.h | 19 + strings/base_includes.h | 5 - strings/base_iterator.h | 2 +- strings/base_macros.h | 146 ++----- strings/base_marshaler.h | 2 +- strings/base_meta.h | 2 +- strings/base_module_base_ixx.h | 13 + strings/base_module_ixx_preamble.h | 11 + strings/base_module_numerics_ixx.h | 6 + strings/base_natvis.h | 2 +- strings/base_reference_produce.h | 4 +- strings/base_source_location.h | 97 +++++ strings/base_std_hash.h | 4 +- strings/base_string.h | 4 +- strings/base_string_input.h | 2 +- strings/base_string_operators.h | 2 +- strings/base_types.h | 4 +- strings/base_version.h | 2 + strings/base_windows.h | 2 +- strings/base_xaml_typename.h | 2 +- test/nuget/NuGetTest.sln | 69 +++- .../TestModuleApp/CustomDependencyObject.cpp | 8 + .../TestModuleApp/CustomDependencyObject.h | 23 ++ test/nuget/TestModuleApp/ModuleTestHelper.cpp | 7 + test/nuget/TestModuleApp/ModuleTestHelper.h | 27 ++ test/nuget/TestModuleApp/PropertySheet.props | 7 + test/nuget/TestModuleApp/TestModuleApp.def | 3 + test/nuget/TestModuleApp/TestModuleApp.idl | 20 + .../nuget/TestModuleApp/TestModuleApp.vcxproj | 127 ++++++ test/nuget/TestModuleApp/main.cpp | 42 ++ test/nuget/TestModuleApp/pch.cpp | 1 + test/nuget/TestModuleApp/pch.h | 1 + .../TestModuleBuilder/PropertySheet.props | 7 + .../TestModuleBuilder.vcxproj | 67 ++++ test/nuget/TestModuleBuilder/pch.cpp | 1 + test/nuget/TestModuleBuilder/pch.h | 1 + test/nuget/TestModuleComponent1/Greeter.cpp | 8 + test/nuget/TestModuleComponent1/Greeter.h | 25 ++ .../TestModuleComponent1/PropertySheet.props | 7 + .../TestModuleComponent1.def | 3 + .../TestModuleComponent1.idl | 12 + .../TestModuleComponent1.vcxproj | 92 +++++ test/nuget/TestModuleComponent1/pch.cpp | 1 + test/nuget/TestModuleComponent1/pch.h | 1 + .../TestModuleComponent2/GreeterGroup.cpp | 9 + .../nuget/TestModuleComponent2/GreeterGroup.h | 36 ++ .../TestModuleComponent2/PropertySheet.props | 7 + .../TestModuleComponent2.def | 3 + .../TestModuleComponent2.idl | 10 + .../TestModuleComponent2.vcxproj | 93 +++++ test/nuget/TestModuleComponent2/pch.cpp | 1 + test/nuget/TestModuleComponent2/pch.h | 1 + .../TestModuleConsumerApp/PropertySheet.props | 7 + .../TestModuleConsumerApp.vcxproj | 76 ++++ test/nuget/TestModuleConsumerApp/main.cpp | 32 ++ test/nuget/TestModuleConsumerApp/pch.cpp | 1 + test/nuget/TestModuleConsumerApp/pch.h | 1 + test/test_cpp20_module/collections.cpp | 57 +++ test/test_cpp20_module/com_interop.cpp | 84 ++++ test/test_cpp20_module/coroutines.cpp | 58 +++ test/test_cpp20_module/format.cpp | 49 +++ test/test_cpp20_module/foundation.cpp | 68 ++++ test/test_cpp20_module/hash.cpp | 73 ++++ test/test_cpp20_module/main.cpp | 24 ++ test/test_cpp20_module/natvis.cpp | 58 +++ test/test_cpp20_module/numerics.cpp | 129 ++++++ test/test_cpp20_module/pch.cpp | 1 + test/test_cpp20_module/pch.h | 3 + test/test_cpp20_module/range_for.cpp | 135 +++++++ test/test_cpp20_module/source_location.cpp | 13 + .../test_cpp20_module.vcxproj | 112 ++++++ 111 files changed, 3146 insertions(+), 224 deletions(-) create mode 100644 .github/instructions/cppwinrt.instructions.md create mode 100644 .github/instructions/modules.instructions.md create mode 100644 docs/modules-design.md create mode 100644 nuget/modules.md create mode 100644 strings/base_detect_numerics.h create mode 100644 strings/base_include_numerics.h create mode 100644 strings/base_module_base_ixx.h create mode 100644 strings/base_module_ixx_preamble.h create mode 100644 strings/base_module_numerics_ixx.h create mode 100644 strings/base_source_location.h create mode 100644 test/nuget/TestModuleApp/CustomDependencyObject.cpp create mode 100644 test/nuget/TestModuleApp/CustomDependencyObject.h create mode 100644 test/nuget/TestModuleApp/ModuleTestHelper.cpp create mode 100644 test/nuget/TestModuleApp/ModuleTestHelper.h create mode 100644 test/nuget/TestModuleApp/PropertySheet.props create mode 100644 test/nuget/TestModuleApp/TestModuleApp.def create mode 100644 test/nuget/TestModuleApp/TestModuleApp.idl create mode 100644 test/nuget/TestModuleApp/TestModuleApp.vcxproj create mode 100644 test/nuget/TestModuleApp/main.cpp create mode 100644 test/nuget/TestModuleApp/pch.cpp create mode 100644 test/nuget/TestModuleApp/pch.h create mode 100644 test/nuget/TestModuleBuilder/PropertySheet.props create mode 100644 test/nuget/TestModuleBuilder/TestModuleBuilder.vcxproj create mode 100644 test/nuget/TestModuleBuilder/pch.cpp create mode 100644 test/nuget/TestModuleBuilder/pch.h create mode 100644 test/nuget/TestModuleComponent1/Greeter.cpp create mode 100644 test/nuget/TestModuleComponent1/Greeter.h create mode 100644 test/nuget/TestModuleComponent1/PropertySheet.props create mode 100644 test/nuget/TestModuleComponent1/TestModuleComponent1.def create mode 100644 test/nuget/TestModuleComponent1/TestModuleComponent1.idl create mode 100644 test/nuget/TestModuleComponent1/TestModuleComponent1.vcxproj create mode 100644 test/nuget/TestModuleComponent1/pch.cpp create mode 100644 test/nuget/TestModuleComponent1/pch.h create mode 100644 test/nuget/TestModuleComponent2/GreeterGroup.cpp create mode 100644 test/nuget/TestModuleComponent2/GreeterGroup.h create mode 100644 test/nuget/TestModuleComponent2/PropertySheet.props create mode 100644 test/nuget/TestModuleComponent2/TestModuleComponent2.def create mode 100644 test/nuget/TestModuleComponent2/TestModuleComponent2.idl create mode 100644 test/nuget/TestModuleComponent2/TestModuleComponent2.vcxproj create mode 100644 test/nuget/TestModuleComponent2/pch.cpp create mode 100644 test/nuget/TestModuleComponent2/pch.h create mode 100644 test/nuget/TestModuleConsumerApp/PropertySheet.props create mode 100644 test/nuget/TestModuleConsumerApp/TestModuleConsumerApp.vcxproj create mode 100644 test/nuget/TestModuleConsumerApp/main.cpp create mode 100644 test/nuget/TestModuleConsumerApp/pch.cpp create mode 100644 test/nuget/TestModuleConsumerApp/pch.h create mode 100644 test/test_cpp20_module/collections.cpp create mode 100644 test/test_cpp20_module/com_interop.cpp create mode 100644 test/test_cpp20_module/coroutines.cpp create mode 100644 test/test_cpp20_module/format.cpp create mode 100644 test/test_cpp20_module/foundation.cpp create mode 100644 test/test_cpp20_module/hash.cpp create mode 100644 test/test_cpp20_module/main.cpp create mode 100644 test/test_cpp20_module/natvis.cpp create mode 100644 test/test_cpp20_module/numerics.cpp create mode 100644 test/test_cpp20_module/pch.cpp create mode 100644 test/test_cpp20_module/pch.h create mode 100644 test/test_cpp20_module/range_for.cpp create mode 100644 test/test_cpp20_module/source_location.cpp create mode 100644 test/test_cpp20_module/test_cpp20_module.vcxproj diff --git a/.github/instructions/cppwinrt.instructions.md b/.github/instructions/cppwinrt.instructions.md new file mode 100644 index 000000000..ba5d66212 --- /dev/null +++ b/.github/instructions/cppwinrt.instructions.md @@ -0,0 +1,58 @@ +# C++/WinRT Codebase — Agent Instructions + +## Repository Structure + +- `cppwinrt/` — The cppwinrt.exe code generator (C++ source) + - `main.cpp` — CLI parsing, namespace iteration, SCC detection, .ixx orchestration + - `file_writers.h` — All file generation functions (headers, .ixx modules, component stubs) + - `code_writers.h` — Code-level writing utilities (guards, namespace wrappers, type writers) + - `type_writers.h` — Type formatting (ABI signatures, names, GUIDs) + - `component_writers.h` — Component authoring code generation + - `helpers.h` — Metadata reading helpers + - `settings.h` — Global settings populated from CLI args + - `text_writer.h` — Core text writer infrastructure +- `strings/` — String literal `.h` files embedded by the prebuild step. Changes require: delete prebuild.exe → rebuild solution +- `nuget/` — MSBuild targets, props, and NuGet packaging + - `Microsoft.Windows.CppWinRT.targets` — Main MSBuild integration (projections, module support) +- `test/` — Test projects + - `test/test_cpp20_module/` — Standalone module test (in main solution) + - `test/nuget/` — NuGet integration tests (multi-project module chain) +- `docs/` — Documentation +- `natvis/` — Visual Studio debug visualizer (includes strings/*.h in its pch.h — add new files there too) + +## Build Process + +- Use VS Developer Shell for correct toolset environment +- `cmake --build build --config Release --target cppwinrt` for cppwinrt.exe (or MSBuild: `msbuild cppwinrt\cppwinrt.vcxproj /p:Configuration=Release /p:Platform=x64`) +- NuGet tests: `msbuild test\nuget\NuGetTest.sln /p:Configuration=Release /p:Platform=x64` +- Module test projects require v145 toolset (VS 2026). Directory.Build.Props sets v143 by default — override with `v145` in Configuration PropertyGroup + +## Key Patterns + +### Prebuild Embedding +The `strings/*.h` files are embedded as string literals by the prebuild step. If you modify any `strings/*.h` file, you must delete `prebuild.exe` and rebuild the entire solution for changes to take effect. + +### Module Guard Macros +- `WINRT_IMPL_BUILD_MODULE` — Defined in .ixx global fragment. Makes `WINRT_EXPORT` expand to `export extern "C++"` and suppresses `#include` of dependencies +- `WINRT_IMPORT_MODULE` — Defined by consumers who import modules. Makes namespace headers and base.h no-op (types come from module import) +- `WINRT_EXPORT` — Empty in header mode, `export extern "C++"` in module mode. Defined in `winrt/base_macros.h` +- `WINRT_IMPL_STD_EXPORT` — Empty in header mode, `extern "C++"` (without export) in module mode. Used for `namespace std` specializations + +### Generated Header Structure +Each namespace produces four header files: +- `impl/.0.h` — Forward declarations, ABIs, GUIDs, categories +- `impl/.1.h` — Interface definitions +- `impl/.2.h` — Delegates, structs, class implementations +- `.h` — Public API surface (consume definitions, class wrappers, operators) + +### Dependency Collection +When generating headers with `-modules`, writer.depends is inspected after each header to build a namespace dependency graph. This graph drives SCC detection and module import lists. + +## Common Gotchas + +- Module IFCs are NOT compatible across toolset versions — always clean rebuild when switching +- PCH and modules can coexist but PCH should NOT include winrt headers when using modules +- `/ifcSearchDir` works for the module dependency scanner to find IFCs, but cross-component modules may need explicit `/reference "name=path.ifc"` flags +- `import std;` requires `BuildStlModules=true` +- `strings/base_macros.h` is the single source of truth for shared macros (generated as `winrt/base_macros.h`). New macros go in `base_macros.h` only +- When adding, removing, or heavily refactoring `strings/*.h` files, always rebuild the natvis project (`natvis/cppwinrtvisualizer.sln`) to verify — it includes strings/*.h directly in its pch.h diff --git a/.github/instructions/modules.instructions.md b/.github/instructions/modules.instructions.md new file mode 100644 index 000000000..3deee2955 --- /dev/null +++ b/.github/instructions/modules.instructions.md @@ -0,0 +1,40 @@ +# C++/WinRT Modules — Agent Instructions + +## Module Architecture (v2 — Per-Namespace) + +Each WinRT namespace gets its own C++20 named module (`winrt.`). Base infrastructure is in `winrt_base` and `winrt_numerics`. + +### Code Generator Flow + +1. `-modules` flag enables .ixx generation in cppwinrt.exe +2. `-module_include`/`-module_exclude` filter which namespaces get modules +3. Headers are generated with dependency tracking (deps_ptr parameter) +4. Tarjan's SCC algorithm detects cyclic namespace groups +5. Standalone namespaces get individual .ixx; cyclic groups get consolidated SCC owner + re-export stubs + +### MSBuild Flow + +1. `CppWinRTBuildModule=true` adds `-modules` to cppwinrt.exe invocations +2. `CppWinRTAddModuleInterfaces` discovers `$(GeneratedFilesDir)winrt\*.ixx` and adds to ClCompile +3. `CppWinRTConsumeModule` metadata on ProjectReference controls per-reference IFC sharing +4. `CppWinRTResolveModuleReferences` calls `CppWinRTGetModuleOutputs` on tagged references +5. Platform projection suppresses `-modules` when consuming pre-built IFCs + +### Critical Invariants + +- Module guards are unconditional in codegen — `-modules` controls .ixx generation and component codegen (module.g.cpp, stub .cpp) +- SCC owner is alphabetically first namespace in the cycle +- All .ixx filenames use `winrt` prefix: `winrt.Windows.Foundation.ixx`, `winrt_base.ixx` +- Shared macros live in `strings/base_module.h` → generates `winrt/macros.h`. `base_macros.h` includes it via `#include "winrt/macros.h"` + +### Testing Changes + +After modifying cppwinrt.exe code: +1. Rebuild cppwinrt.exe: `msbuild cppwinrt\cppwinrt.vcxproj /p:Configuration=Release /p:Platform=x64` +2. Run standalone test: build `test_cpp20_module` in main solution +3. Run NuGet tests: `msbuild test\nuget\NuGetTest.sln /p:Configuration=Release /p:Platform=x64` + +After modifying targets: +1. Clean NuGet test obj dirs +2. Build with `/v:normal` and check "Module providers:" diagnostic messages +3. Inspect `.rsp` files in `obj/` to verify correct `-modules` flag placement diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d660400a0..6c2a04353 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -379,6 +379,15 @@ jobs: $target_platform = "${{ matrix.arch }}" & "_build\$target_platform\$target_configuration\cppwinrt.exe" -in local -out _build\$target_platform\$target_configuration -verbose + - name: Remove module test projects on v143 + if: matrix.toolchain.platform_toolset == 'v143' + run: | + # Module test projects require v145 toolset + mv test\nuget\NugetTest.sln test\nuget\NugetTest.sln.orig + Get-Content test\nuget\NugetTest.sln.orig | + Where-Object { -not ($_ -match 'TestModule') } | + Set-Content test\nuget\NugetTest.sln + - name: Run nuget test run: | cmd /c "$env:VSDevCmd" "&" msbuild /m /clp:ForceConsoleColor "$env:msbuild_config_props" test\nuget\NugetTest.sln diff --git a/cppwinrt.sln b/cppwinrt.sln index 3bcfb33bc..700e9f5ea 100644 --- a/cppwinrt.sln +++ b/cppwinrt.sln @@ -124,6 +124,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_nocoro", "test\test_no {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_cpp20_module", "test\test_cpp20_module\test_cpp20_module.vcxproj", "{B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}" + ProjectSection(ProjectDependencies) = postProject + {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} + EndProjectSection +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D15C8430-A7CD-4616-BD84-243B26A9F1C2}" ProjectSection(SolutionItems) = preProject build_nuget.cmd = build_nuget.cmd @@ -411,6 +416,18 @@ Global {9E392830-805A-4AAF-932D-C493143EFACA}.Release|x64.Build.0 = Release|x64 {9E392830-805A-4AAF-932D-C493143EFACA}.Release|x86.ActiveCfg = Release|Win32 {9E392830-805A-4AAF-932D-C493143EFACA}.Release|x86.Build.0 = Release|Win32 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Debug|ARM64.Build.0 = Debug|ARM64 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Debug|x64.ActiveCfg = Debug|x64 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Debug|x64.Build.0 = Debug|x64 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Debug|x86.ActiveCfg = Debug|Win32 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Debug|x86.Build.0 = Debug|Win32 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Release|ARM64.ActiveCfg = Release|ARM64 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Release|ARM64.Build.0 = Release|ARM64 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Release|x64.ActiveCfg = Release|x64 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Release|x64.Build.0 = Release|x64 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Release|x86.ActiveCfg = Release|Win32 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -435,6 +452,7 @@ Global {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} {D4C8F881-84D5-4A7B-8BDE-AB4E34A05374} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} {9E392830-805A-4AAF-932D-C493143EFACA} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {2783B8FD-EA3B-4D6B-9F81-662D289E02AA} diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index fc5081bef..ab119ae89 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -5,9 +5,9 @@ namespace cppwinrt struct finish_with { writer& w; - void (*finisher)(writer&); + std::function finisher; - finish_with(writer& w, void (*finisher)(writer&)) : w(w), finisher(finisher) {} + finish_with(writer& w, std::function finisher) : w(w), finisher(std::move(finisher)) {} finish_with(finish_with const&)= delete; void operator=(finish_with const&) = delete; @@ -35,6 +35,35 @@ namespace cppwinrt } } + static void write_endif(writer& w, std::string_view macro = {}) + { + if (macro.empty()) + { + w.write("#endif\n"); + } + else + { + w.write("#endif // %\n", macro); + } + } + + // When modules are enabled, wraps a block of #include directives in + // #ifndef WINRT_IMPL_BUILD_MODULE ... #endif so that in module builds (where + // WINRT_IMPL_BUILD_MODULE is defined in the global module fragment), textual + // includes are suppressed — dependencies come via import instead. + [[nodiscard]] static finish_with wrap_module_aware_includes_guard(writer& w, bool modules_enabled) + { + if (modules_enabled) + { + w.write("#ifndef WINRT_IMPL_BUILD_MODULE\n"); + return { w, [](writer& w) { write_endif(w, "WINRT_IMPL_BUILD_MODULE"); } }; + } + else + { + return { w, write_nothing }; + } + } + static void write_version_assert(writer& w) { w.write_root_include("base"); @@ -52,14 +81,6 @@ namespace cppwinrt w.write(format); } - static void write_endif(writer& w) - { - auto format = R"(#endif -)"; - - w.write(format); - } - static void write_close_file_guard(writer& w) { write_endif(w); @@ -105,7 +126,7 @@ namespace cppwinrt w.write(format); - return { w, write_endif }; + return { w, [](writer& w) { write_endif(w, "WINRT_LEAN_AND_MEAN"); } }; } else { @@ -120,7 +141,17 @@ namespace cppwinrt w.write(format, macro); - return { w, write_endif }; + return { w, [macro = std::string(macro)](writer& w) { write_endif(w, macro); } }; + } + + [[nodiscard]] static finish_with wrap_ifndef(writer& w, std::string_view macro) + { + auto format = R"(#ifndef % +)"; + + w.write(format, macro); + + return { w, [macro = std::string(macro)](writer& w) { write_endif(w, macro); } }; } static void write_parent_depends(writer& w, cache const& c, std::string_view const& type_namespace) @@ -166,7 +197,7 @@ namespace cppwinrt [[nodiscard]] static finish_with wrap_impl_namespace(writer& w) { - auto format = R"(namespace winrt::impl + auto format = R"(WINRT_EXPORT namespace winrt::impl { )"; diff --git a/cppwinrt/component_writers.h b/cppwinrt/component_writers.h index 3966cad6c..af5626d14 100644 --- a/cppwinrt/component_writers.h +++ b/cppwinrt/component_writers.h @@ -136,7 +136,10 @@ namespace cppwinrt static void write_module_g_cpp(writer& w, std::vector const& classes) { - w.write_root_include("base"); + if (!settings.modules) + { + w.write_root_include("base"); + } auto format = R"(% bool __stdcall %_can_unload_now() noexcept { diff --git a/cppwinrt/file_writers.h b/cppwinrt/file_writers.h index ed9386b4e..fd9833cb1 100644 --- a/cppwinrt/file_writers.h +++ b/cppwinrt/file_writers.h @@ -9,9 +9,16 @@ namespace cppwinrt w.write(strings::base_version_odr, CPPWINRT_VERSION_STRING); { auto wrap_file_guard = wrap_open_file_guard(w, "BASE"); + auto wrap_import = wrap_ifndef(w, "WINRT_IMPORT_MODULE"); - w.write(strings::base_includes); - w.write(strings::base_macros); + { + auto wrap_includes = wrap_module_aware_includes_guard(w, true); + w.write(strings::base_includes); + w.write(strings::base_detect_numerics); + w.write(strings::base_include_numerics); + } + w.write_root_include("base_macros"); + w.write(strings::base_source_location); w.write(strings::base_types); w.write(strings::base_extern); w.write(strings::base_meta); @@ -65,7 +72,15 @@ namespace cppwinrt w.flush_to_file(settings.output_folder + "winrt/fast_forward.h"); } - static void write_namespace_0_h(std::string_view const& ns, cache::namespace_members const& members) + static void collect_writer_deps(writer const& w, std::set& out) + { + for (auto&& [dep_ns, _] : w.depends) + { + out.insert(std::string(dep_ns)); + } + } + + static void write_namespace_0_h(std::string_view const& ns, cache::namespace_members const& members, std::set* out_deps = nullptr) { writer w; w.type_namespace = ns; @@ -118,10 +133,11 @@ namespace cppwinrt w.write_each(depends.second); } + if (out_deps) collect_writer_deps(w, *out_deps); w.save_header('0'); } - static void write_namespace_1_h(std::string_view const& ns, cache::namespace_members const& members) + static void write_namespace_1_h(std::string_view const& ns, cache::namespace_members const& members, std::set* out_deps = nullptr) { writer w; w.type_namespace = ns; @@ -137,16 +153,20 @@ namespace cppwinrt write_preamble(w); write_open_file_guard(w, ns, '1'); - for (auto&& depends : w.depends) { - w.write_depends(depends.first, '0'); - } + auto wrap_includes = wrap_module_aware_includes_guard(w, true); + for (auto&& depends : w.depends) + { + w.write_depends(depends.first, '0'); + } - w.write_depends(w.type_namespace, '0'); + w.write_depends(w.type_namespace, '0'); + } + if (out_deps) collect_writer_deps(w, *out_deps); w.save_header('1'); } - static void write_namespace_2_h(std::string_view const& ns, cache::namespace_members const& members) + static void write_namespace_2_h(std::string_view const& ns, cache::namespace_members const& members, std::set* out_deps = nullptr) { writer w; w.type_namespace = ns; @@ -167,16 +187,20 @@ namespace cppwinrt char const impl = promote ? '2' : '1'; - for (auto&& depends : w.depends) { - w.write_depends(depends.first, impl); - } + auto wrap_includes = wrap_module_aware_includes_guard(w, true); + for (auto&& depends : w.depends) + { + w.write_depends(depends.first, impl); + } - w.write_depends(w.type_namespace, '1'); + w.write_depends(w.type_namespace, '1'); + } + if (out_deps) collect_writer_deps(w, *out_deps); w.save_header('2'); } - static void write_namespace_h(cache const& c, std::string_view const& ns, cache::namespace_members const& members) + static void write_namespace_h(cache const& c, std::string_view const& ns, cache::namespace_members const& members, std::set* out_deps = nullptr) { writer w; w.type_namespace = ns; @@ -216,18 +240,28 @@ namespace cppwinrt write_namespace_special(w, ns); write_close_file_guard(w); + // The #ifndef WINRT_IMPORT_MODULE / #endif pair spans across w.swap(). + // The body is written first (above), then swap() prepends the header prefix (below). + // In the final output, #ifndef opens before the includes and #endif closes after + // the file guard, mirroring the write_open_file_guard / write_close_file_guard pair. + w.write("#endif // WINRT_IMPORT_MODULE\n"); w.swap(); write_preamble(w); write_open_file_guard(w, ns); - write_version_assert(w); - write_parent_depends(w, c, ns); - - for (auto&& depends : w.depends) + w.write("#ifndef WINRT_IMPORT_MODULE\n\n"); { - w.write_depends(depends.first, '2'); - } + auto wrap_includes = wrap_module_aware_includes_guard(w, true); + write_version_assert(w); + write_parent_depends(w, c, ns); - w.write_depends(w.type_namespace, '2'); + for (auto&& depends : w.depends) + { + w.write_depends(depends.first, '2'); + } + + w.write_depends(w.type_namespace, '2'); + } + if (out_deps) collect_writer_deps(w, *out_deps); w.save_header(); } @@ -236,6 +270,28 @@ namespace cppwinrt writer w; write_preamble(w); write_pch(w); + + if (settings.modules) + { + // In module builds, import std and winrt_base instead of #include "winrt/base.h". + // std is needed for std::wstring_view, std::equal, std::int32_t used in + // the activation factory lookup code. + w.write("\nimport std;\n"); + w.write("import winrt_base;\n"); + + // Collect all unique namespaces from the component classes + std::set namespaces; + for (auto&& type : classes) + { + namespaces.insert(std::string(type.TypeNamespace())); + } + for (auto&& ns : namespaces) + { + w.write("import winrt.%;\n", ns); + } + w.write("\n"); + } + write_module_g_cpp(w, classes); w.flush_to_file(settings.output_folder + "module.g.cpp"); } @@ -250,9 +306,19 @@ namespace cppwinrt write_preamble(w); write_include_guard(w); - for (auto&& depends : w.depends) { - w.write_depends(depends.first); + auto wrap = wrap_ifdef(w, "WINRT_IMPORT_MODULE"); + w.write_root_include("base_macros"); + for (auto&& depends : w.depends) + { + w.write("import winrt.%;\n", depends.first); + } + w.write("#else // WINRT_IMPORT_MODULE\n"); + + for (auto&& depends : w.depends) + { + w.write_depends(depends.first); + } } auto filename = settings.output_folder + get_generated_component_filename(type) + ".g.h"; @@ -316,7 +382,269 @@ namespace cppwinrt writer w; write_pch(w); + + if (settings.modules) + { + // The .g.h handles its own imports, but the implementation .h + // needs the types available in scope, so we import them here. + writer dep_scanner; + dep_scanner.add_depends(type); + write_component_g_h(dep_scanner, type); + + w.write("\n#define WINRT_IMPORT_MODULE\n"); + for (auto&& depends : dep_scanner.depends) + { + w.write("import winrt.%;\n", depends.first); + } + w.write("\n"); + } + write_component_cpp(w, type); w.flush_to_file(path); } + + // --- Per-namespace C++20 module interface unit (.ixx) writers --- + + // Emits the common global module fragment used by all generated .ixx files. + // Defines WINRT_IMPL_BUILD_MODULE so generated headers switch WINRT_EXPORT + // to 'export extern "C++"' and suppress textual #includes of dependencies + // (dependencies arrive via module imports instead). + // Includes minimal headers needed for macros, intrinsics, and debug assertions. + static void write_module_preamble(writer& w) + { + write_preamble(w); + w.write(strings::base_module_ixx_preamble); + w.write_root_include("base_macros"); + } + + // Emits $(out)/winrt/base_macros.h + // This header provides the core macros shared between header and module builds. + // In header builds, base.h includes base_macros.h inline (via the prebuild-embedded string). + // In module builds, each .ixx file includes this in its global module fragment. + static void write_macros_h() + { + writer w; + write_preamble(w); + w.write(strings::base_macros, CPPWINRT_VERSION_STRING); + w.flush_to_file(settings.output_folder + "winrt/base_macros.h"); + } + + static void write_base_ixx() + { + writer w; + write_module_preamble(w); + w.write(strings::base_module_base_ixx); + w.write(strings::base_detect_numerics); + w.write("\n"); + w.write_root_include("base"); + w.flush_to_file(settings.output_folder + "winrt/winrt_base.ixx"); + } + + static void write_numerics_ixx() + { + writer w; + write_module_preamble(w); + // GMF: detect numerics and pre-include directxmath so it's not pulled + // into the module purview by windowsnumerics.impl.h + w.write(strings::base_detect_numerics); + { + auto wrap = wrap_ifdef(w, "WINRT_IMPL_NUMERICS"); + w.write("#include \n"); + } + w.write(strings::base_module_numerics_ixx); + // Module declaration + w.write("\nexport module winrt_numerics;\n"); + // Include windowsnumerics.impl.h in the module purview (exports the types). + // directxmath.h is already included in the GMF above, so the #include inside + // base_include_numerics is a no-op (header guard). + { + auto wrap = wrap_ifdef(w, "_MSC_VER"); + w.write("#pragma warning(push)\n"); + w.write("#pragma warning(disable : 5244)\n"); + } + w.write(strings::base_include_numerics); + { + auto wrap = wrap_ifdef(w, "_MSC_VER"); + w.write("#pragma warning(pop)\n"); + } + w.flush_to_file(settings.output_folder + "winrt/winrt_numerics.ixx"); + } + + // Emits a per-namespace module interface unit for namespaces that are NOT + // part of a dependency cycle (standalone module). + // Output: $(out)/winrt/winrt..ixx (export module winrt.;) + // + // The generated .ixx: + // 1. Starts with the global module fragment (WINRT_IMPL_BUILD_MODULE, minimal includes) + // 2. Declares 'export module winrt.;' + // 3. Imports std and re-exports winrt_base + // 4. Imports each dependent namespace module (computed from type references in headers) + // 5. Includes the impl headers (*.0.h, *.1.h, *.2.h) and public header (.h) + // in the module purview, where WINRT_EXPORT causes declarations to be exported + static void write_namespace_ixx( + std::string_view const& ns, + std::set const& deps) + { + writer w; + write_module_preamble(w); + + // Module declaration + w.write("export module winrt.%;\n\n", ns); + + // Document dependencies + w.write("// Module dependencies:\n"); + w.write("// - std\n"); + w.write("// - winrt_base (re-exported)\n"); + if (deps.empty()) + { + w.write("// - (no additional namespace imports)\n"); + } + else + { + for (auto& dep : deps) + { + w.write("// - winrt.%\n", dep); + } + } + w.write("\n"); + + // Import std and base + w.write("import std;\n"); + w.write("export import winrt_base;\n"); + + // Import dependency namespace modules + for (auto& dep : deps) + { + w.write("import winrt.%;\n", dep); + } + + // Version mismatch check: ensure this namespace module was generated by the + // same version of cppwinrt.exe as the winrt_base module it imports. + // winrt::cppwinrt_version is exported from winrt_base; CPPWINRT_VERSION is + // the macro from this module's own base_macros.h in the global module fragment. + w.write("\nstatic_assert(winrt::check_version(winrt::cppwinrt_version, CPPWINRT_VERSION), \"Mismatched C++/WinRT headers.\");\n\n"); + + // Include namespace headers in module purview + w.write_depends(ns, '0'); + w.write_depends(ns, '1'); + w.write_depends(ns, '2'); + w.write_root_include(ns); + + w.flush_to_file(settings.output_folder + "winrt/winrt." + std::string(ns) + ".ixx"); + } + + // Emits the SCC (Strongly Connected Component) owner module interface unit. + // When multiple namespaces form a dependency cycle, they cannot each have their + // own independent module (circular imports are illegal in C++20 modules). + // Instead, one namespace is chosen as the "owner" (alphabetically first in the SCC), + // and ALL cyclic namespaces' declarations are consolidated into this single module. + // The other namespaces in the SCC get thin re-export stubs (see write_namespace_reexport_ixx). + // + // Output: $(out)/winrt/winrt..ixx (export module winrt.;) + // + // The owner module: + // 1. Imports external dependencies (deps outside the SCC) + // 2. Forward-declares all projected types for ALL SCC namespaces before any + // impl headers — this breaks the type reference cycles + // 3. Includes impl headers in stable phase order: all *.0.h, then all *.1.h, + // then all *.2.h, then all public headers — preserving the original header + // layering while keeping SCC compilation deterministic + static void write_namespace_scc_owner_ixx( + cache const& c, + std::string_view const& owner, + std::vector const& scc_members, + std::set const& external_deps) + { + writer w; + write_module_preamble(w); + + // Module declaration (owner namespace) + w.write("// This module is an SCC owner (cycle breaker). The following namespaces\n"); + w.write("// form a dependency cycle and are consolidated into this single module:\n"); + for (auto& ns : scc_members) + { + w.write("// - %\n", ns); + } + w.write("// Other SCC namespaces are emitted as re-export stubs.\n\n"); + w.write("export module winrt.%;\n\n", owner); + + // Import std and base + w.write("import std;\n"); + w.write("export import winrt_base;\n"); + + // Import external dependency modules (outside the SCC) + for (auto& dep : external_deps) + { + w.write("import winrt.%;\n", dep); + } + + // Version mismatch check: ensure this namespace module was generated by the + // same version of cppwinrt.exe as the winrt_base module it imports. + // winrt::cppwinrt_version is exported from winrt_base; CPPWINRT_VERSION is + // the macro from this module's own base_macros.h in the global module fragment. + w.write("\nstatic_assert(winrt::check_version(winrt::cppwinrt_version, CPPWINRT_VERSION), \"Mismatched C++/WinRT headers.\");\n"); + + // Forward declarations for all projected types in this SCC. + // This is required because SCC members have cyclic type references, + // and generated headers suppress dependent #includes when WINRT_IMPL_BUILD_MODULE + // is defined. Forward declarations provide the names needed before definitions. + for (auto& ns : scc_members) + { + auto found = c.namespaces().find(ns); + if (found == c.namespaces().end()) + { + continue; + } + auto& members = found->second; + + auto wrap_type = wrap_type_namespace(w, ns); + w.write_each(members.enums); + w.write_each(members.interfaces); + w.write_each(members.classes); + w.write_each(members.structs); + w.write_each(members.delegates); + w.write_each(members.contracts); + } + + // Include all SCC members' headers in stable phase order. + // All *.0.h (forward decls + ABIs), then all *.1.h (interfaces), + // then all *.2.h (delegates/structs/classes), then all public headers. + // This preserves the original header layering while keeping compilation deterministic. + for (auto& ns : scc_members) + { + w.write_depends(ns, '0'); + } + for (auto& ns : scc_members) + { + w.write_depends(ns, '1'); + } + for (auto& ns : scc_members) + { + w.write_depends(ns, '2'); + } + for (auto& ns : scc_members) + { + w.write_root_include(ns); + } + + w.flush_to_file(settings.output_folder + "winrt/winrt." + std::string(owner) + ".ixx"); + } + + // Emits a thin re-export stub module for SCC non-owner namespaces. + // This allows 'import winrt.;' to work even though the actual declarations + // live in the SCC owner module. The stub simply re-exports the owner. + // Output: $(out)/winrt/winrt..ixx (export module winrt.; export import winrt.;) + static void write_namespace_reexport_ixx( + std::string_view const& ns, + std::string_view const& owner) + { + writer w; + write_preamble(w); + w.write("\n// NOTE: This module does not define declarations of its own.\n"); + w.write("// It re-exports all declarations from the 'winrt.%' module. This is used to break cycles in the\n", owner); + w.write("// WinRT namespace module dependency graph (SCC owner consolidation).\n\n"); + w.write("export module winrt.%;\n", ns); + w.write("export import winrt.%;\n", owner); + w.flush_to_file(settings.output_folder + "winrt/winrt." + std::string(ns) + ".ixx"); + } } diff --git a/cppwinrt/main.cpp b/cppwinrt/main.cpp index 70a55b076..33bb9248e 100644 --- a/cppwinrt/main.cpp +++ b/cppwinrt/main.cpp @@ -1,5 +1,6 @@ #include "pch.h" #include +#include #include "strings.h" #include "settings.h" #include "type_writers.h" @@ -39,6 +40,9 @@ namespace cppwinrt { "fastabi", 0, 0 }, // Enable support for the Fast ABI { "ignore_velocity", 0, 0 }, // Ignore feature staging metadata and always include implementations { "synchronous", 0, 0 }, // Instructs cppwinrt to run on a single thread to avoid file system issues in batch builds + { "modules", 0, 0, {}, "Generate per-namespace C++20 module interface units (.ixx)" }, + { "module_include", 0, option::no_max, "", "Filter which namespaces are included in module .ixx generation" }, + { "module_exclude", 0, option::no_max, "", "Filter which namespaces are excluded from module .ixx generation" }, }; static void print_usage(writer& w) @@ -85,6 +89,7 @@ R"( local Local ^%WinDir^%\System32\WinMetadata folder { settings.verbose = args.exists("verbose"); settings.fastabi = args.exists("fastabi"); + settings.modules = args.exists("modules"); settings.input = args.files("input", database::is_database); settings.reference = args.files("reference", database::is_database); @@ -92,6 +97,15 @@ R"( local Local ^%WinDir^%\System32\WinMetadata folder settings.component = args.exists("component"); settings.base = args.exists("base"); + for (auto&& ns : args.values("module_include")) + { + settings.module_include.insert(ns); + } + for (auto&& ns : args.values("module_exclude")) + { + settings.module_exclude.insert(ns); + } + settings.license = args.exists("license"); settings.brackets = args.exists("brackets"); @@ -199,6 +213,13 @@ R"( local Local ^%WinDir^%\System32\WinMetadata folder static void build_filters(cache const& c) { + // Build module_filter from -module_include / -module_exclude args. + // This controls which namespaces get .ixx files without affecting header generation. + if (!settings.module_include.empty() || !settings.module_exclude.empty()) + { + settings.module_filter = { settings.module_include, settings.module_exclude }; + } + if (settings.reference.empty()) { return; @@ -281,6 +302,79 @@ R"( local Local ^%WinDir^%\System32\WinMetadata folder c.remove_type("Windows.Foundation.Numerics", "Vector4"); } + // Tarjan's algorithm for finding strongly connected components in the + // namespace dependency graph. Namespaces in an SCC have cyclic deps and + // must be combined into a single module. + static std::vector> find_sccs( + std::map, std::less<>> const& graph) + { + struct context + { + std::map index_of; + std::map lowlink; + std::map on_stack; + std::vector stack; + int next_index = 0; + std::vector> result; + + void strongconnect(std::string const& v, + std::map, std::less<>> const& g) + { + index_of[v] = next_index; + lowlink[v] = next_index; + next_index++; + stack.push_back(v); + on_stack[v] = true; + + auto it = g.find(v); + if (it != g.end()) + { + for (auto& w : it->second) + { + if (g.find(w) == g.end()) + { + continue; // dep not in graph (not a projected namespace) + } + + if (index_of.find(w) == index_of.end()) + { + strongconnect(w, g); + lowlink[v] = (std::min)(lowlink[v], lowlink[w]); + } + else if (on_stack[w]) + { + lowlink[v] = (std::min)(lowlink[v], index_of[w]); + } + } + } + + if (lowlink[v] == index_of[v]) + { + std::vector scc; + std::string w; + do + { + w = stack.back(); + stack.pop_back(); + on_stack[w] = false; + scc.push_back(std::move(w)); + } while (scc.back() != v); + result.push_back(std::move(scc)); + } + } + }; + + context ctx; + for (auto& [node, _] : graph) + { + if (ctx.index_of.find(node) == ctx.index_of.end()) + { + ctx.strongconnect(node, graph); + } + } + return std::move(ctx.result); + } + static int run(int const argc, char** argv) { int result{}; @@ -342,11 +436,30 @@ R"( local Local ^%WinDir^%\System32\WinMetadata folder w.flush_to_console(); task_group group; group.synchronous(args.exists("synchronous")); - writer ixx; - write_preamble(ixx); - ixx.write("module;\n"); - ixx.write(strings::base_includes); - ixx.write("\nexport module winrt;\n#define WINRT_EXPORT export\n\n"); + + // Dependency collection for per-namespace modules (v2) + std::map, std::less<>> ns_deps_map; + std::set projected_namespaces; + std::mutex ns_deps_mutex; + + // First pass: determine which namespaces will be in the module. + // This includes namespaces from this invocation AND those from other invocations + // (e.g., platform namespaces when building a component). The module_filter + // tells us which namespaces have modules across all invocations. + if (settings.modules) + { + for (auto&& [ns, members] : c.namespaces()) + { + if (!has_projected_types(members)) + { + continue; + } + if (settings.module_filter.empty() || settings.module_filter.includes(members)) + { + projected_namespaces.insert(std::string(ns)); + } + } + } for (auto&&[ns, members] : c.namespaces()) { @@ -355,21 +468,29 @@ R"( local Local ^%WinDir^%\System32\WinMetadata folder continue; } - ixx.write("#include \"winrt/%.h\"\n", ns); - group.add([&, &ns = ns, &members = members] { - write_namespace_0_h(ns, members); - write_namespace_1_h(ns, members); - write_namespace_2_h(ns, members); - write_namespace_h(c, ns, members); + bool in_module = projected_namespaces.count(std::string(ns)) > 0; + std::set ns_deps; + auto* deps_ptr = (settings.modules && in_module) ? &ns_deps : nullptr; + + write_namespace_0_h(ns, members, deps_ptr); + write_namespace_1_h(ns, members, deps_ptr); + write_namespace_2_h(ns, members, deps_ptr); + write_namespace_h(c, ns, members, deps_ptr); + + if (settings.modules && in_module) + { + std::lock_guard lock(ns_deps_mutex); + ns_deps_map[std::string(ns)] = std::move(ns_deps); + } }); } if (settings.base) { write_base_h(); - ixx.flush_to_file(settings.output_folder + "winrt/winrt.ixx"); + write_macros_h(); } if (settings.component) @@ -404,6 +525,64 @@ R"( local Local ^%WinDir^%\System32\WinMetadata folder group.get(); + // Generate per-namespace module interface files (.ixx) + // + // Each projected namespace gets its own C++20 named module (winrt.). + // Namespaces that form dependency cycles are detected using Tarjan's SCC algorithm + // and consolidated: one namespace "owns" the SCC module (containing all declarations), + // while others get thin re-export stubs so 'import winrt.;' always works. + // + // Base infrastructure modules (winrt_base, winrt_numerics) are only generated + // for platform projection builds (-base flag). + if (settings.modules) + { + if (settings.base) + { + write_numerics_ixx(); + write_base_ixx(); + } + + // Tarjan's SCC algorithm for cyclic namespace dependencies + auto sccs = find_sccs(ns_deps_map); + + for (auto& scc : sccs) + { + if (scc.size() == 1) + { + // Standalone namespace module + auto& ns = scc[0]; + write_namespace_ixx(ns, ns_deps_map[ns]); + } + else + { + // SCC: choose owner (alphabetically first), others re-export + std::sort(scc.begin(), scc.end()); + auto& owner = scc[0]; + + // External deps = union of all SCC members' deps, minus SCC members themselves + std::set external_deps; + std::set scc_set(scc.begin(), scc.end()); + for (auto& ns : scc) + { + for (auto& dep : ns_deps_map[ns]) + { + if (!scc_set.count(dep)) + { + external_deps.insert(dep); + } + } + } + + write_namespace_scc_owner_ixx(c, owner, scc, external_deps); + + for (size_t i = 1; i < scc.size(); ++i) + { + write_namespace_reexport_ixx(scc[i], owner); + } + } + } + } + if (settings.verbose) { w.write(" time: %ms\n", get_elapsed_time(start)); diff --git a/cppwinrt/settings.h b/cppwinrt/settings.h index e07df4ea2..110e64917 100644 --- a/cppwinrt/settings.h +++ b/cppwinrt/settings.h @@ -31,6 +31,12 @@ namespace cppwinrt bool fastabi{}; std::map fastabi_cache; + + bool modules{}; // Generate per-namespace C++20 module interface units (.ixx) + + std::set module_include; + std::set module_exclude; + winmd::reader::filter module_filter; }; extern settings_type settings; diff --git a/docs/modules-design.md b/docs/modules-design.md new file mode 100644 index 000000000..8327231a7 --- /dev/null +++ b/docs/modules-design.md @@ -0,0 +1,190 @@ +# C++/WinRT Per-Namespace Modules: Design & Internals + +This document describes the design and implementation of per-namespace C++20 module support in C++/WinRT. It is intended for cppwinrt maintainers and contributors. + +## Architecture Overview + +The module system generates one C++20 named module per WinRT namespace. Each module encapsulates the same content as the traditional header files but exports declarations via `WINRT_EXPORT` in module purview. + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ winrt_numerics.ixx ── export module winrt_numerics; │ +│ winrt_base.ixx ── export module winrt_base; │ +│ export import winrt_numerics; │ +│ winrt.Windows.Foundation.ixx │ +│ ── export module winrt.Windows.Foundation; │ +│ import std; export import winrt_base; │ +│ import winrt.Windows.Foundation.Collections; │ +│ #include "winrt/impl/Windows.Foundation.0.h" │ +│ ... │ +│ #include "winrt/Windows.Foundation.h" │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Key Design Decisions + +### Unconditional Guards + +Module guards (`WINRT_IMPL_BUILD_MODULE`, `WINRT_IMPORT_MODULE`) are emitted unconditionally in generated projection headers — they are always present regardless of whether `-modules` was passed to cppwinrt.exe. The `-modules` flag controls `.ixx` generation and whether generated component files (`module.g.cpp`, stub `.cpp`) use module imports. This means: + +- Projection headers generated without `-modules` still work correctly when later compiled inside a module interface unit +- No regeneration of projection headers needed when switching between header and module consumption + +### WINRT_EXPORT Macro + +`WINRT_EXPORT` is defined in `base_macros.h` (generated as `winrt/base_macros.h`): +- When `WINRT_IMPL_BUILD_MODULE` is defined (inside `.ixx` compilation): `export extern "C++"` +- Otherwise (header mode): empty + +All `namespace winrt::impl` and `namespace std` blocks use `WINRT_EXPORT` so they export correctly from modules. The `extern "C++"` wrapping enables include-before-import compatibility (same technique as MSVC STL). + +### Per-Namespace vs Monolithic + +Unlike the v1 approach (single `import winrt;`), v2 generates one module per namespace. This provides: + +- **Finer granularity**: Import only what you need +- **Better parallelism**: Independent modules compile in parallel +- **Component module support**: Component namespaces get their own modules + +The trade-off is handling dependency cycles between namespaces (see SCC below). + +This is enforced via the MSBuild `CppWinRTConsumeModule` metadata on ProjectReference — it only points at the platform module builder, not at component projects. + +## Code Generator Pipeline + +### Entry Point: `main.cpp` + +1. **Namespace enumeration**: First pass determines which namespaces are module-eligible using `module_filter` (from `-module_include`/`-module_exclude`) + +2. **Header generation**: Standard header generation with optional dependency collection. When `-modules` is active and a namespace is in the module, `write_namespace_*_h()` functions populate `ns_deps` sets via the `deps_ptr` parameter + +3. **Dependency graph construction**: After all headers are generated, `ns_deps_map` contains the full namespace dependency graph + +4. **SCC detection**: Tarjan's algorithm (`find_sccs()`) identifies strongly-connected components + +5. **Module generation**: For each SCC: + - Size 1: `write_namespace_ixx()` — standalone module + - Size > 1: `write_namespace_scc_owner_ixx()` for the owner (alphabetically first) + `write_namespace_reexport_ixx()` for others + +### CLI Options + +| Flag | Description | +|-|-| +| `-modules` | Enable `.ixx` generation | +| `-module_include ...` | Only generate modules for these namespace prefixes | +| `-module_exclude ...` | Skip these namespace prefixes | + +The `module_filter` is populated from these flags and checked against ALL cache namespaces (not just the projection filter). This is important for component builds where the platform namespaces are not being projected but their modules exist from a prior builder invocation. + +### Generated Files + +| File | When Generated | Purpose | +|-|-|-| +| `winrt/base_macros.h` | Always with `-base` | Macros for module builds (WINRT_EXPORT, etc.) | +| `winrt/winrt_base.ixx` | `-modules -base` | Core types module | +| `winrt/winrt_numerics.ixx` | `-modules -base` | Numerics module | +| `winrt/winrt..ixx` | `-modules` | Per-namespace module | + +## SCC (Strongly Connected Components) + +### The Problem + +WinRT namespaces have cyclic dependencies. For example: +- `Windows.Foundation` depends on `Windows.Foundation.Collections` (via `IVector`, `IMap`, etc.) +- `Windows.Foundation.Collections` depends on `Windows.Foundation` (via `IAsyncOperation`, `Uri`, etc.) + +C++20 modules cannot have circular imports. If module A imports module B, then module B cannot import module A. + +### The Solution: SCC Consolidation + +Tarjan's algorithm identifies groups of namespaces that form dependency cycles. These groups (SCCs) are consolidated: + +1. **Owner selection**: The alphabetically first namespace in the SCC becomes the "owner" +2. **Owner module**: Contains ALL declarations from ALL SCC namespaces. Forward-declares all types first, then includes headers in phase order (all `*.0.h`, then `*.1.h`, then `*.2.h`, then public headers) +3. **Re-export stubs**: Other SCC members get thin `.ixx` files that just re-export the owner module + +This means `import winrt.Windows.Foundation;` and `import winrt.Windows.Foundation.Collections;` both work — they resolve to the same underlying module. + +### Example Generated Files + +**Owner** (`winrt.Windows.Foundation.ixx`): +```cpp +module; +#define WINRT_IMPL_BUILD_MODULE +#include "winrt/base_macros.h" +// ... + +// This module is an SCC owner (cycle breaker). The following namespaces +// form a dependency cycle and are consolidated into this single module: +// - Windows.Foundation +// - Windows.Foundation.Collections +// Other SCC namespaces are emitted as re-export stubs. + +export module winrt.Windows.Foundation; + +import std; +export import winrt_base; + +// Forward declarations for all SCC namespaces... +// #include all impl headers in phase order... +``` + +**Re-export stub** (`winrt.Windows.Foundation.Collections.ixx`): +```cpp +// NOTE: This module does not define declarations of its own. +// It re-exports all declarations from the 'winrt.Windows.Foundation' module. +export module winrt.Windows.Foundation.Collections; +export import winrt.Windows.Foundation; +``` + +## MSBuild Integration + +### Targets Flow + +``` +CppWinRTResolveModuleReferences (resolves IFC paths from ProjectReference metadata) + ↓ +CppWinRTMakePlatformProjection (generates headers + .ixx for platform types) +CppWinRTMakeReferenceProjection (generates headers + .ixx for referenced WinMDs) +CppWinRTMakeComponentProjection (generates headers + .ixx for component types) + ↓ +CppWinRTAddModuleInterfaces (discovers .ixx files, adds to ClCompile items) + ↓ +FixupCLCompileOptions (MSVC module dependency scanner processes .ixx) + ↓ +ClCompile (compiles .ixx → .ifc + .obj) +``` + +### Key Properties + +- `CppWinRTBuildModule`: Enables `-modules` for all three projections (platform, reference, component), causing `.ixx` generation and compilation. +- `CppWinRTConsumeModule` (ProjectReference metadata): Per-reference opt-in for IFC consumption. When set, suppresses `-modules` on the platform projection so the consumer uses pre-built IFCs from the referenced project instead of generating its own. +- `_CppWinRTConsumesPlatformModules`: Internal property set by `CppWinRTResolveModuleReferences` when any ProjectReference has `CppWinRTConsumeModule=true`. Controls whether the platform projection receives `-modules`. + +### Cross-Project IFC Resolution + +MSVC's module dependency scanner uses `/ifcSearchDir` for within-project module resolution. For cross-project modules, the scanner generates explicit `/reference "module.name=path.ifc"` entries based on the dependency scan results. The `/ifcSearchDir` pointing to the builder's `$(IntDir)` allows the scanner to find the pre-built IFCs. + +## Dependency Collection + +During header generation, when `-modules` is active, each `write_namespace_*_h()` function receives a `deps_ptr` parameter. The writer's `w.depends` map is inspected to find referenced namespaces. Only namespaces that: +1. Exist in the cache +2. Have projected types +3. Are in the module namespace set (or set is empty) + +are added to the dependency set. Self-references are excluded. The union of dependencies from all four header files (`*.0.h`, `*.1.h`, `*.2.h`, `.h`) gives the complete dependency set for a namespace module. + +## Testing + +### test/test_cpp20_module/ (in-repo) + +Standalone test built by the main solution. Uses a PreBuildEvent to run cppwinrt.exe with `-modules -base -module_include "Windows.Foundation"`. Tests URI, events, collections, and coroutines. + +### test/nuget/ (NuGet integration) + +Multi-project solution: +- **TestModuleBuilder**: Static library that pre-builds platform modules +- **TestModuleComponent1**: Component DLL (Greeter class), consumes builder's modules +- **TestModuleComponent2**: Component DLL (GreeterGroup), depends on Component1 +- **TestModuleConsumerApp**: Console app, consumes builder + both components +- **TestModuleApp**: Single-project that builds and consumes its own modules diff --git a/natvis/pch.h b/natvis/pch.h index 95e561971..3de6807b3 100644 --- a/natvis/pch.h +++ b/natvis/pch.h @@ -12,6 +12,7 @@ #include #include "base_includes.h" #include "base_macros.h" +#include "base_source_location.h" #include "base_types.h" #include "base_extern.h" #include "base_meta.h" diff --git a/nuget/Microsoft.Windows.CppWinRT.targets b/nuget/Microsoft.Windows.CppWinRT.targets index 188e56835..a297258f3 100644 --- a/nuget/Microsoft.Windows.CppWinRT.targets +++ b/nuget/Microsoft.Windows.CppWinRT.targets @@ -26,6 +26,10 @@ Copyright (C) Microsoft Corporation. All rights reserved. $([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)))..\..\ $([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory))) $(CppWinRTParameters) -fastabi + + -modules + -module_include $(CppWinRTModuleInclude.Replace(';', ' ')) + $(CppWinRTCommandModuleFilter) -module_exclude $(CppWinRTModuleExclude.Replace(';', ' ')) "$(CppWinRTPackageDir)bin\" "$(CppWinRTPackageDir)" @@ -651,6 +655,9 @@ $(XamlMetaDataProviderPch) <_CppwinrtParameters>$(CppWinRTCommandVerbosity) $(CppWinRTParameters) + + <_CppwinrtParameters Condition="'$(_CppWinRTConsumesPlatformModules)'!='true'">$(_CppwinrtParameters) $(CppWinRTCommandModules) $(CppWinRTCommandModuleFilter) <_CppwinrtParameters>$(_CppwinrtParameters) @(_CppwinrtInputs->'-in "%(WinMDPath)"', ' ') <_CppwinrtParameters>$(_CppwinrtParameters) -out "$(GeneratedFilesDir)." @@ -729,7 +736,7 @@ $(XamlMetaDataProviderPch) <_CppwinrtRefRefs Include="@(CppWinRTPlatformWinMDReferences)"/> - <_CppwinrtParameters>$(CppWinRTCommandVerbosity) $(CppWinRTParameters) + <_CppwinrtParameters>$(CppWinRTCommandVerbosity) $(CppWinRTParameters) $(CppWinRTCommandModules) $(CppWinRTCommandModuleFilter) <_CppwinrtParameters>$(_CppwinrtParameters) @(_CppwinrtRefInputs->'-in "%(WinMDPath)"', ' ') <_CppwinrtParameters>$(_CppwinrtParameters) @(_CppwinrtRefRefs->'-ref "%(WinMDPath)"', ' ') <_CppwinrtParameters>$(_CppwinrtParameters) -out "$(GeneratedFilesDir)." @@ -835,7 +842,7 @@ $(XamlMetaDataProviderPch) <_CppwinrtCompRefs Include="@(CppWinRTPlatformWinMDReferences)"/> - <_CppwinrtParameters>$(CppWinRTCommandVerbosity) $(CppWinRTParameters) -overwrite -name $(RootNamespace) $(CppWinRTCommandPrecompiledHeader) $(CppWinRTCommandUsePrefixes) -comp "$(GeneratedFilesDir)sources" + <_CppwinrtParameters>$(CppWinRTCommandVerbosity) $(CppWinRTParameters) $(CppWinRTCommandModules) $(CppWinRTCommandModuleFilter) -overwrite -name $(RootNamespace) $(CppWinRTCommandPrecompiledHeader) $(CppWinRTCommandUsePrefixes) -comp "$(GeneratedFilesDir)sources" <_CppwinrtParameters Condition="'$(CppWinRTOptimized)'=='true'">$(_CppwinrtParameters) -opt <_CppwinrtParameters>$(_CppwinrtParameters) @(_CppwinrtCompInputs->'-in "%(WinMDPath)"', ' ') <_CppwinrtParameters>$(_CppwinrtParameters) @(_CppwinrtCompRefs->'-ref "%(WinMDPath)"', ' ') @@ -895,4 +902,88 @@ $(XamlMetaDataProviderPch) + + + + + CompileAsCppModule + true + NotUsing + + + + + + + + + $(GeneratedFilesDir) + $(IntDir) + $(OutDir) + + + + + + + + + <_CppWinRTModuleProviders Remove="@(_CppWinRTModuleProviders)" /> + <_CppWinRTModuleProviders Include="@(ProjectReference)" + Condition="'%(ProjectReference.CppWinRTConsumeModule)' == 'true'" /> + + + + + <_CppWinRTConsumesPlatformModules>true + + + + + + + + + + + + + <_CppWinRTModuleIfcSearchDirs>@(_CppWinRTResolvedModuleRefs->'%(CppWinRTModuleIfcDir)') + + + + $(_CppWinRTModuleIfcSearchDirs);%(ClCompile.AdditionalBMIDirectories) + + + + diff --git a/nuget/modules.md b/nuget/modules.md new file mode 100644 index 000000000..479781252 --- /dev/null +++ b/nuget/modules.md @@ -0,0 +1,179 @@ +# C++/WinRT C++20 Modules Guide + +## Overview + +C++/WinRT can generate per-namespace C++20 named modules (`.ixx` files) alongside the traditional projection headers. This allows you to write: + +```cpp +import winrt.Windows.Foundation; +``` + +instead of: + +```cpp +#include +``` + +Modules provide faster builds through pre-compiled module interfaces (IFCs) and better isolation of macro and declaration scopes. + +## Quick Start — Single Project + +For a project that builds and consumes its own modules: + +1. Set `CppWinRTBuildModule` to `true` in your project: + ```xml + + true + + ``` + +2. Optionally limit which namespaces get modules: + ```xml + + Windows.Foundation;Windows.Storage + + ``` + +3. Enable `BuildStlModules` for `import std;` support: + ```xml + + true + + ``` + +4. In your `.cpp` files: + ```cpp + import winrt.Windows.Foundation; + + int main() { + winrt::init_apartment(); + winrt::Windows::Foundation::Uri uri(L"https://example.com"); + } + ``` + +## Quick Start — Multi-Project (Recommended) + +For larger solutions, compile platform modules once in a dedicated "builder" static library, and share the pre-built IFCs with other projects. + +### Module Builder (static library) + +```xml + + StaticLibrary + true + Windows.Foundation + +``` + +### Consumer (exe or dll) + +```xml + + true + + + + true + + +``` + +The `CppWinRTConsumeModule` metadata on the ProjectReference tells the build system to: +- Use the builder's pre-built platform IFCs instead of compiling platform `.ixx` files again +- Skip generating platform `.ixx` files in the consumer's own projection + +### Component DLLs + +WinRT component projects can also use modules. Set `CppWinRTBuildModule=true` and all three projections (platform, reference, component) will generate `.ixx` files. + +```xml + + true + MyComponent + + + + true + + +``` + +### Consuming Components from Other Projects + +If project A references a component DLL from project B, project A builds its own reference projection modules from B's `.winmd`: + +```cpp +// These modules are built locally from the component's .winmd +import winrt.MyComponent; + +auto obj = winrt::MyComponent::MyClass(); +``` + +## MSBuild Properties + +| Property | Default | Description | +|-|-|-| +| `CppWinRTBuildModule` | false | Generate `.ixx` module interface units from projections | +| `CppWinRTModuleInclude` | (all) | Semicolon-delimited namespace prefixes to include in module generation | +| `CppWinRTModuleExclude` | (none) | Semicolon-delimited namespace prefixes to exclude from module generation | + +| ProjectReference Metadata | Default | Description | +|-|-|-| +| `CppWinRTConsumeModule` | false | Consume pre-built platform module IFCs from this project reference | + +## Module Filtering and Transitive Dependencies + +`CppWinRTModuleInclude` and `CppWinRTModuleExclude` control which namespace `.ixx` files are **generated**, but they do not suppress `import` statements for dependencies. If namespace A is included in the filter and depends on namespace B, the generated `winrt.A.ixx` will contain `import winrt.B;` even if B is excluded from the filter. This is by design — the module for B must exist *somewhere* (either from the same project or from a referenced project). + +This has important implications: + +- **Transitive closure must be satisfied.** If you filter to a subset of namespaces, any dependencies that fall outside the filter must be available from another source (e.g., a module builder project referenced via `CppWinRTConsumeModule`, or MSBuild's automatic `ReferencedModuleBMIs` from a static library reference). Otherwise, compilation will fail with "could not find module" errors. + +- **Use `CppWinRTModuleExclude` to avoid generating modules that have unsatisfied dependencies.** For example, `Windows.Foundation.Diagnostics` depends on `Windows.Storage`. If you filter to `CppWinRTModuleInclude=Windows.Foundation`, the Diagnostics `.ixx` will be generated (it matches the prefix) but will fail to compile because `winrt.Windows.Storage` doesn't exist. Add `CppWinRTModuleExclude=Windows.Foundation.Diagnostics` to prevent this. + +- **In multi-project scenarios with static libraries, use `CppWinRTModuleExclude` to avoid duplicate modules.** MSBuild automatically propagates all module IFCs from static library references to consuming projects (via the `AllProjectBMIsArePublic` property, which defaults to `true` for static libraries). If project A is a static library that builds modules for namespace X, and project B references A, then B already has A's IFCs available. If B also has `CppWinRTBuildModule=true`, its reference projection will generate a second `winrt.X.ixx`, causing an ambiguous module error. Set `CppWinRTModuleExclude=X` on project B to prevent this. B's own `.ixx` files will still emit `import winrt.X;`, which resolves to A's IFC via MSBuild's automatic propagation. Note: this issue does not affect DLL references — MSBuild does not propagate module IFCs from DLLs by default. + +## Module Names + +| Module | Contents | +|-|-| +| `winrt_base` | Core C++/WinRT types (`hstring`, `com_ptr`, `IUnknown`, etc.) — re-exported by all namespace modules | +| `winrt_numerics` | `Windows::Foundation::Numerics` types — re-exported by `winrt_base` | +| `winrt.` | Per-namespace projection (e.g., `winrt.Windows.Foundation`) | + +## Requirements + +- MSVC v145 toolset (Visual Studio 2026) or later recommended +- C++20 or later (`/std:c++20` or newer) +- `BuildStlModules=true` for `import std;` support + +## Limitations + +- Module IFCs are not compatible across toolset versions. All projects must use the same toolset. +- Cyclic namespace dependencies (e.g., `Windows.Foundation` ↔ `Windows.Foundation.Collections`) are handled automatically via SCC consolidation, but the resulting module name is chosen alphabetically. Adding new APIs could change SCC groupings. + +## Caution: Module Reuse Across Projects + +Pre-built IFCs (via `CppWinRTConsumeModule`) should only be shared when the builder and consumer use the same compilation context. In particular: + +- **Component modules are project-private.** A component projection built with `CppWinRTOptimized=true` generates modules that bypass activation factories for in-component type instantiation (`-opt`). If a consuming project accidentally imports these modules instead of building its own reference projection, the consumer will attempt direct instantiation across DLL boundaries, resulting in linker errors or incorrect behavior. Each project should build its own modules from the component's `.winmd` — do not tag component ProjectReferences with `CppWinRTConsumeModule`. + +- **`CppWinRTConsumeModule` is intended for platform module builders only.** The builder project is a dedicated static library whose sole purpose is compiling platform SDK modules. Its compilation flags (no `-opt`, no `-comp`) produce modules safe for any consumer. Only tag this builder's ProjectReference with `CppWinRTConsumeModule=true`. + +- **Module filter scope matters.** `CppWinRTModuleInclude` / `CppWinRTModuleExclude` applies to all three projections (platform, reference, component). If you set `CppWinRTModuleInclude=MyComponent`, only `MyComponent` namespaces will get `.ixx` files — platform and reference namespace modules will not be generated. Make sure your filter includes all namespaces you intend to import as modules, or use `CppWinRTConsumeModule` to get platform modules from a builder that was configured with the appropriate filter. + +- **Compilation settings must be compatible between builder and consumer.** Module IFCs encode assumptions about the compilation environment. While the compiler may not always diagnose mismatches, the following differences between the module builder and consumer may cause subtle or hard-to-diagnose issues: + - **Debug vs Release** — Mixing Debug and Release configurations can produce mismatched code generation, iterator debugging levels, and runtime library selections. + - **Preprocessor definitions** — Definitions that affect type layout, conditional compilation, or feature flags should match between builder and consumer. + - **Struct alignment / packing** — Different `/Zp` settings between projects can change struct layout, causing silent ABI mismatches. + - **Language standard** — While C++20 and later are generally compatible, mixing `/std:c++20` and `/std:c++23` and/or `/std:c++latest` if there are language features that affect type definitions. + + As a general rule, the module builder project try to use the same configuration, preprocessor definitions, and compiler options as its consumers. + +## Troubleshooting + +**"could not find module 'winrt.X'"** — Ensure the `.ixx` was generated (check `$(GeneratedFilesDir)winrt\`) and that `CppWinRTBuildModule=true` is set. For cross-project references, verify the consuming project's `ProjectReference` to the builder has `CppWinRTConsumeModule=true`, and that the builder's `IntDir` is accessible via `/ifcSearchDir`. + +**Linker errors for component constructors** — You may be importing a component's internal module instead of building your own reference projection. Remove explicit `/reference` flags for component IFCs and ensure your project has `CppWinRTBuildModule=true` so it builds reference projection modules from the component's `.winmd`. + +**Redefinition errors** — Don't mix `#include` and `import` for the same namespace in the same translation unit. Use `import` consistently. diff --git a/nuget/readme.md b/nuget/readme.md index 9379aa716..c8c0b9537 100644 --- a/nuget/readme.md +++ b/nuget/readme.md @@ -70,6 +70,9 @@ C++/WinRT behavior can be customized with these project properties: | CppWinRTOptimized | true \| *false | Enables component projection [optimization features](https://kennykerr.ca/2019/06/07/cppwinrt-optimizing-components/) | | CppWinRTGenerateWindowsMetadata | true \| *false | Indicates whether this project produces Windows Metadata | | CppWinRTEnableDefaultPrivateFalse | true \| *false | Indicates whether this project uses C++/WinRT optimized default for copying binaries to the output directory | +| CppWinRTBuildModule | true \| *false | Generates per-namespace C++20 module interface units (.ixx) alongside projection headers | +| CppWinRTModuleInclude | namespace list | Semicolon-delimited namespaces to include in module generation (default: all) | +| CppWinRTModuleExclude | namespace list | Semicolon-delimited namespaces to exclude from module generation | \*Default value To customize common C++/WinRT project properties: @@ -132,6 +135,15 @@ void DerivedPage::InitializeComponent() } ``` +## C++20 Modules + +C++/WinRT supports C++20 named modules as an alternative to `#include`-based consumption. Instead of `#include `, you can write `import winrt.Windows.Foundation;`. See [modules.md](modules.md) for the full guide. + +| ProjectReference metadata | Description | +|-|-| +| CppWinRTConsumeModule | true \| *false | When set on a ProjectReference, consumes pre-built platform module IFCs from the referenced project | +\*Default value + ## Troubleshooting The msbuild verbosity level maps to msbuild message importance as follows: diff --git a/strings/base_abi.h b/strings/base_abi.h index 72946a3fa..4b7b8f77f 100644 --- a/strings/base_abi.h +++ b/strings/base_abi.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template <> struct abi { diff --git a/strings/base_activation.h b/strings/base_activation.h index 1a195d865..c657c692d 100644 --- a/strings/base_activation.h +++ b/strings/base_activation.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { struct library_traits { @@ -125,7 +125,7 @@ WINRT_EXPORT namespace winrt #define WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER (__dmb(_ARM64_BARRIER_ISH)); #endif -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { inline std::int32_t interlocked_read_32(std::int32_t const volatile* target) noexcept { @@ -548,7 +548,7 @@ WINRT_EXPORT namespace winrt } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template T fast_activate(Windows::Foundation::IActivationFactory const& factory) diff --git a/strings/base_agile_ref.h b/strings/base_agile_ref.h index 88fbea065..14447706a 100644 --- a/strings/base_agile_ref.h +++ b/strings/base_agile_ref.h @@ -47,7 +47,7 @@ WINRT_EXPORT namespace winrt #endif } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct module_lock_updater; diff --git a/strings/base_array.h b/strings/base_array.h index 48d10c6ce..d29bee883 100644 --- a/strings/base_array.h +++ b/strings/base_array.h @@ -483,7 +483,7 @@ WINRT_EXPORT namespace winrt } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct array_size_proxy diff --git a/strings/base_collections.h b/strings/base_collections.h index 4e1af51eb..7d8dc2e77 100644 --- a/strings/base_collections.h +++ b/strings/base_collections.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { namespace wfc = Windows::Foundation::Collections; diff --git a/strings/base_collections_base.h b/strings/base_collections_base.h index 6fe10fa64..d299cc0c8 100644 --- a/strings/base_collections_base.h +++ b/strings/base_collections_base.h @@ -1,4 +1,4 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { struct nop_lock_guard {}; diff --git a/strings/base_collections_input_iterable.h b/strings/base_collections_input_iterable.h index e75211c30..e9d3af251 100644 --- a/strings/base_collections_input_iterable.h +++ b/strings/base_collections_input_iterable.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct input_iterable : diff --git a/strings/base_collections_input_map.h b/strings/base_collections_input_map.h index b33975fe6..3fe146bf6 100644 --- a/strings/base_collections_input_map.h +++ b/strings/base_collections_input_map.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct map_impl : diff --git a/strings/base_collections_input_map_view.h b/strings/base_collections_input_map_view.h index bfd8d82a9..d79eed61d 100644 --- a/strings/base_collections_input_map_view.h +++ b/strings/base_collections_input_map_view.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct input_map_view : diff --git a/strings/base_collections_input_vector.h b/strings/base_collections_input_vector.h index b5b76de38..a06e73b33 100644 --- a/strings/base_collections_input_vector.h +++ b/strings/base_collections_input_vector.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct vector_impl : diff --git a/strings/base_collections_input_vector_view.h b/strings/base_collections_input_vector_view.h index 3793e239a..30768c18e 100644 --- a/strings/base_collections_input_vector_view.h +++ b/strings/base_collections_input_vector_view.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct input_vector_view : diff --git a/strings/base_collections_map.h b/strings/base_collections_map.h index fa769fb88..6bf884236 100644 --- a/strings/base_collections_map.h +++ b/strings/base_collections_map.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template using multi_threaded_map = map_impl; @@ -116,7 +116,7 @@ WINRT_EXPORT namespace winrt } } -namespace std +WINRT_EXPORT namespace std { template struct tuple_size> @@ -132,7 +132,7 @@ namespace std }; } -namespace winrt::Windows::Foundation::Collections +WINRT_EXPORT namespace winrt::Windows::Foundation::Collections { template std::tuple_element_t> get(IKeyValuePair const& kvp) diff --git a/strings/base_collections_vector.h b/strings/base_collections_vector.h index 3e9c1b254..3388806af 100644 --- a/strings/base_collections_vector.h +++ b/strings/base_collections_vector.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template using multi_threaded_vector = vector_impl; diff --git a/strings/base_com_ptr.h b/strings/base_com_ptr.h index 27496789a..0f02fabeb 100644 --- a/strings/base_com_ptr.h +++ b/strings/base_com_ptr.h @@ -5,7 +5,7 @@ WINRT_EXPORT namespace winrt struct com_ptr; } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { struct capture_decay { @@ -349,7 +349,7 @@ WINRT_EXPORT namespace winrt } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template std::int32_t capture_to(void** result, com_ptr const& object, M method, Args&& ...args) diff --git a/strings/base_composable.h b/strings/base_composable.h index e606d1292..5a7712ef7 100644 --- a/strings/base_composable.h +++ b/strings/base_composable.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct composable_factory diff --git a/strings/base_coroutine_foundation.h b/strings/base_coroutine_foundation.h index 4f1c8d0b6..5cefad836 100644 --- a/strings/base_coroutine_foundation.h +++ b/strings/base_coroutine_foundation.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct async_completed_handler; @@ -312,7 +312,7 @@ WINRT_EXPORT namespace winrt } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct cancellation_token @@ -704,7 +704,7 @@ namespace winrt::impl }; } -namespace std +WINRT_IMPL_STD_EXPORT namespace std { template struct coroutine_traits diff --git a/strings/base_coroutine_threadpool.h b/strings/base_coroutine_threadpool.h index 6748906ca..057d5b548 100644 --- a/strings/base_coroutine_threadpool.h +++ b/strings/base_coroutine_threadpool.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { #ifdef WINRT_IMPL_COROUTINES inline auto submit_threadpool_callback(void(__stdcall* callback)(void*, void* context), void* context) @@ -321,7 +321,7 @@ WINRT_EXPORT namespace winrt }; } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { struct apartment_awaiter { @@ -671,7 +671,7 @@ WINRT_EXPORT namespace winrt struct fire_and_forget {}; } -namespace std +WINRT_IMPL_STD_EXPORT namespace std { template struct coroutine_traits diff --git a/strings/base_delegate.h b/strings/base_delegate.h index 1cfe58710..1fe00ecd1 100644 --- a/strings/base_delegate.h +++ b/strings/base_delegate.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { #if defined(_MSC_VER) #pragma warning(push) diff --git a/strings/base_detect_numerics.h b/strings/base_detect_numerics.h new file mode 100644 index 000000000..6a93a8ffa --- /dev/null +++ b/strings/base_detect_numerics.h @@ -0,0 +1,4 @@ + +#if __has_include() +#define WINRT_IMPL_NUMERICS +#endif diff --git a/strings/base_error.h b/strings/base_error.h index c58635e5d..d42ca516b 100644 --- a/strings/base_error.h +++ b/strings/base_error.h @@ -7,7 +7,7 @@ #define WINRT_IMPL_RETURNADDRESS() nullptr #endif -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { struct heap_traits { @@ -536,7 +536,7 @@ WINRT_EXPORT namespace winrt } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { inline hresult check_hresult_allow_bounds(hresult const result, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) { diff --git a/strings/base_events.h b/strings/base_events.h index f7e2e6976..c21124e9c 100644 --- a/strings/base_events.h +++ b/strings/base_events.h @@ -130,7 +130,7 @@ WINRT_EXPORT namespace winrt }; } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct event_revoker diff --git a/strings/base_extern.h b/strings/base_extern.h index 84e2943c4..a17908ac4 100644 --- a/strings/base_extern.h +++ b/strings/base_extern.h @@ -1,8 +1,11 @@ -__declspec(selectany) std::int32_t(__stdcall* winrt_to_hresult_handler)(void* address) noexcept {}; -__declspec(selectany) winrt::hstring(__stdcall* winrt_to_message_handler)(void* address) {}; -__declspec(selectany) void(__stdcall* winrt_throw_hresult_handler)(std::uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept {}; -__declspec(selectany) std::int32_t(__stdcall* winrt_activation_handler)(void* classId, winrt::guid const& iid, void** factory) noexcept {}; +// These global function pointers must use WINRT_EXPORT (which expands to +// 'export extern "C++"' in module builds) so that module and non-module TUs +// in the same binary share the same instances. +WINRT_EXPORT __declspec(selectany) std::int32_t(__stdcall* winrt_to_hresult_handler)(void* address) noexcept {}; +WINRT_EXPORT __declspec(selectany) winrt::hstring(__stdcall* winrt_to_message_handler)(void* address) {}; +WINRT_EXPORT __declspec(selectany) void(__stdcall* winrt_throw_hresult_handler)(std::uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept {}; +WINRT_EXPORT __declspec(selectany) std::int32_t(__stdcall* winrt_activation_handler)(void* classId, winrt::guid const& iid, void** factory) noexcept {}; #if defined(_MSC_VER) #ifdef _M_HYBRID diff --git a/strings/base_fast_forward.h b/strings/base_fast_forward.h index dc89fe6ce..a73e70a04 100644 --- a/strings/base_fast_forward.h +++ b/strings/base_fast_forward.h @@ -30,7 +30,11 @@ static_assert(WINRT_FAST_ABI_SIZE >= %); #pragma detect_mismatch("WINRT_FAST_ABI_SIZE", WINRT_IMPL_STRING(WINRT_FAST_ABI_SIZE)) -namespace winrt::impl +#ifndef WINRT_EXPORT +#define WINRT_EXPORT +#endif // WINRT_EXPORT + +WINRT_EXPORT namespace winrt::impl { // Thunk definitions are in arch-specific assembly sources % diff --git a/strings/base_foundation.h b/strings/base_foundation.h index ea8881edc..083252753 100644 --- a/strings/base_foundation.h +++ b/strings/base_foundation.h @@ -100,7 +100,7 @@ WINRT_EXPORT namespace winrt::Windows::Foundation } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template <> inline constexpr auto& name_v = L"Windows.Foundation.Point"; template <> inline constexpr auto& name_v = L"Windows.Foundation.Size"; diff --git a/strings/base_identity.h b/strings/base_identity.h index 30830bc5a..7c61c83e2 100644 --- a/strings/base_identity.h +++ b/strings/base_identity.h @@ -17,7 +17,7 @@ WINRT_EXPORT namespace winrt } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template constexpr std::array to_array(T const* value, std::index_sequence const) noexcept diff --git a/strings/base_implements.h b/strings/base_implements.h index 7edf32149..0eb8db0bd 100644 --- a/strings/base_implements.h +++ b/strings/base_implements.h @@ -6,7 +6,7 @@ #endif #endif -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { struct marker { @@ -30,7 +30,7 @@ WINRT_EXPORT namespace winrt struct implements; } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template using tuple_cat_t = decltype(std::tuple_cat(std::declval()...)); @@ -267,7 +267,7 @@ WINRT_EXPORT namespace winrt } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct interface_list; diff --git a/strings/base_include_numerics.h b/strings/base_include_numerics.h new file mode 100644 index 000000000..4b7658fff --- /dev/null +++ b/strings/base_include_numerics.h @@ -0,0 +1,19 @@ + +// Includes when WINRT_IMPL_NUMERICS is defined. +// Requires to already be included (via base_detect_numerics). +// The types are redirected into winrt::Windows::Foundation::Numerics via macro wrapping. +// Uses WINRT_EXPORT for the namespace declaration, which resolves to 'export extern "C++"' +// in module builds and nothing in header builds. +#ifdef WINRT_IMPL_NUMERICS +#ifndef WINRT_EXPORT +#define WINRT_EXPORT +#endif +#include +#define _WINDOWS_NUMERICS_NAMESPACE_ winrt::Windows::Foundation::Numerics +#define _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ WINRT_EXPORT namespace winrt::Windows::Foundation::Numerics +#define _WINDOWS_NUMERICS_END_NAMESPACE_ +#include +#undef _WINDOWS_NUMERICS_NAMESPACE_ +#undef _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ +#undef _WINDOWS_NUMERICS_END_NAMESPACE_ +#endif // WINRT_IMPL_NUMERICS diff --git a/strings/base_includes.h b/strings/base_includes.h index d6808792b..287a09709 100644 --- a/strings/base_includes.h +++ b/strings/base_includes.h @@ -31,11 +31,6 @@ #include #endif -#if __has_include() -#define WINRT_IMPL_NUMERICS -#include -#endif - #ifndef WINRT_LEAN_AND_MEAN #include #endif diff --git a/strings/base_iterator.h b/strings/base_iterator.h index acb0ebd42..46c0c6b63 100644 --- a/strings/base_iterator.h +++ b/strings/base_iterator.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct fast_iterator diff --git a/strings/base_macros.h b/strings/base_macros.h index 3dc01fa2d..91b0121d9 100644 --- a/strings/base_macros.h +++ b/strings/base_macros.h @@ -1,3 +1,6 @@ +#pragma once +#ifndef WINRT_BASE_MACROS_H +#define WINRT_BASE_MACROS_H #ifdef _DEBUG @@ -11,7 +14,11 @@ #define WINRT_VERIFY(expression) (void)(expression) #define WINRT_VERIFY_(result, expression) (void)(expression) -#endif +#endif // _DEBUG + +#if defined(__cpp_lib_coroutine) +#define WINRT_IMPL_COROUTINES +#endif // __cpp_lib_coroutine #define WINRT_IMPL_SHIM(...) (*(abi_t<__VA_ARGS__>**)&static_cast<__VA_ARGS__ const&>(static_cast(*this))) @@ -21,25 +28,30 @@ // Note: this is a workaround for a false-positive warning produced by the Visual C++ 16.3 compiler. #pragma warning(disable : 4268) -#endif -#if defined(__cpp_lib_coroutine) -#define WINRT_IMPL_COROUTINES -#endif +// C++ module warnings by /W4 +#pragma warning(disable : 4499) +#pragma warning(disable : 4630) +#endif // _MSC_VER #ifndef WINRT_EXPORT +#ifdef WINRT_IMPL_BUILD_MODULE +#define WINRT_EXPORT export extern "C++" +#else #define WINRT_EXPORT -#endif - -#ifdef WINRT_IMPL_NUMERICS -#define _WINDOWS_NUMERICS_NAMESPACE_ winrt::Windows::Foundation::Numerics -#define _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ WINRT_EXPORT namespace winrt::Windows::Foundation::Numerics -#define _WINDOWS_NUMERICS_END_NAMESPACE_ -#include -#undef _WINDOWS_NUMERICS_NAMESPACE_ -#undef _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ -#undef _WINDOWS_NUMERICS_END_NAMESPACE_ -#endif +#endif // WINRT_IMPL_BUILD_MODULE +#endif // WINRT_EXPORT + +// Template specializations in namespace std (hash, coroutine_traits) need extern "C++" +// linkage in module builds for proper merging with the std module, but must NOT be +// exported — exporting namespace std would make all of std transitively visible. +#ifndef WINRT_IMPL_STD_EXPORT +#ifdef WINRT_IMPL_BUILD_MODULE +#define WINRT_IMPL_STD_EXPORT extern "C++" +#else +#define WINRT_IMPL_STD_EXPORT +#endif // WINRT_IMPL_BUILD_MODULE +#endif // WINRT_IMPL_STD_EXPORT #if defined(_MSC_VER) #define WINRT_IMPL_NOINLINE __declspec(noinline) @@ -81,7 +93,7 @@ #define WINRT_IMPL_HAS_DECLSPEC_UUID 0 #endif -#ifdef __IUnknown_INTERFACE_DEFINED__ +#if defined(__IUnknown_INTERFACE_DEFINED__) || defined(WINRT_ENABLE_LEGACY_COM) #define WINRT_IMPL_IUNKNOWN_DEFINED #else // Forward declare so we can talk about it. @@ -95,99 +107,11 @@ typedef struct _GUID GUID; #define WINRT_IMPL_CONSTEVAL constexpr #endif -// The intrinsics (such as __builtin_FILE()) that power std::source_location are also used to power winrt:impl::slim_source_location. -// The source location needs to be for the calling code, not cppwinrt itself, so that it is useful to developers building on top of -// this library. As a result any public-facing method that can result in an error needs a default-constructed slim_source_location -// argument so that it will collect source information from the application code that is calling into cppwinrt. -// -// We do not directly use std::source_location for two reasons: -// 1) std::source_location::function_name() is unavoidable. These strings end up in the final binary, bloating their size. This -// is particularly impactful for code bases that use templates heavily. Cases of 50% binary size growth have been observed. -// 2) std::source_location is a cpp20 feature, which is above the cpp17 feature floor for cppwinrt. By defining our own version -// we can avoid ODR violations in mixed cpp17/cpp20 builds. cpp17 callers will have an ABI that matches cpp20 callers (they -// will just not have useful file/line/function information). -// -// Some projects may decide that the source information binary size impact is not worth the benefit. Defining WINRT_NO_SOURCE_LOCATION -// will prevent this feature from activating. The slim_source_location type will be forwarded around but it will not include any -// nonzero data. That eliminates the biggest source of binary size overhead. -// -// To help with debugging the __builtin_FUNCTION() intrinsic will be used in _DEBUG builds. This will provide a bit more diagnostic -// value at the cost of binary size. The assumption is that binary size is considered less important in debug builds so this tradeoff -// is acceptable. -// -// The different behavior of the default parameters to winrt::impl::slim_source_location::current() is technically an ODR violation, -// albeit a minor one. There should be no serious consequence to this violation. In practice it means that mixing cpp17/cpp20, -// or mixing WINRT_NO_SOURCE_LOCATION with undefining it, will lead to inconsistent source location information. It may be missing -// when it is expected to be included, or it may be present when it is not expected. The behavior will depend on the linker's choice -// when there are multiple translation units with different options. This violation is tracked by https://github.com/microsoft/cppwinrt/issues/1445. - -#if !defined(__cpp_lib_source_location) || defined(WINRT_NO_SOURCE_LOCATION) -// Case1: cpp17 mode. The source_location intrinsics are not available. -// Case2: The caller has disabled source_location support. Ensure that there is no binary size overhead for line/file/function. -#define WINRT_IMPL_BUILTIN_LINE 0 -#define WINRT_IMPL_BUILTIN_FILE nullptr -#define WINRT_IMPL_BUILTIN_FUNCTION nullptr -#elif _DEBUG -// cpp20 _DEBUG builds include function information, which has a heavy binary size impact, in addition to file/line. -#define WINRT_IMPL_BUILTIN_LINE __builtin_LINE() -#define WINRT_IMPL_BUILTIN_FILE __builtin_FILE() -#define WINRT_IMPL_BUILTIN_FUNCTION __builtin_FUNCTION() -#else -// Release builds in cpp20 mode get file and line information but NOT function information. Function strings -// quickly add up to a substantial binary size impact, especially when templates are heavily used. -#define WINRT_IMPL_BUILTIN_LINE __builtin_LINE() -#define WINRT_IMPL_BUILTIN_FILE __builtin_FILE() -#define WINRT_IMPL_BUILTIN_FUNCTION nullptr +// CPPWINRT_VERSION is defined here so it is available in module global fragments. +// In header builds, base_version_odr.h defines it first (before base_macros.h is included), +// so the #ifndef guard prevents redefinition. +#ifndef CPPWINRT_VERSION +#define CPPWINRT_VERSION "%" #endif -namespace winrt::impl -{ - // This struct is intended to be highly similar to std::source_location. The key difference is - // that function_name is NOT included. Function names do not fold to identical strings and can - // have heavy binary size overhead when templates cause many permutations to exist. - struct slim_source_location - { - [[nodiscard]] static WINRT_IMPL_CONSTEVAL slim_source_location current( - const std::uint_least32_t line = WINRT_IMPL_BUILTIN_LINE, - const char* const file = WINRT_IMPL_BUILTIN_FILE, - const char* const function = WINRT_IMPL_BUILTIN_FUNCTION) noexcept - { - return slim_source_location{ line, file, function }; - } - - [[nodiscard]] constexpr slim_source_location() noexcept = default; - - [[nodiscard]] constexpr slim_source_location( - const std::uint_least32_t line, - const char* const file, - const char* const function) noexcept : - m_line(line), - m_file(file), - m_function(function) - {} - - [[nodiscard]] constexpr std::uint_least32_t line() const noexcept - { - return m_line; - } - - [[nodiscard]] constexpr const char* file_name() const noexcept - { - return m_file; - } - - [[nodiscard]] constexpr const char* function_name() const noexcept - { - return m_function; - } - - private: - const std::uint_least32_t m_line{}; - const char* const m_file{}; - const char* const m_function{}; - }; -} - -#ifdef _MSC_VER -#pragma detect_mismatch("WINRT_SOURCE_LOCATION", "slim") -#endif // _MSC_VER +#endif // WINRT_BASE_MACROS_H diff --git a/strings/base_marshaler.h b/strings/base_marshaler.h index 526f4d4c3..9be6959c9 100644 --- a/strings/base_marshaler.h +++ b/strings/base_marshaler.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { inline std::int32_t make_marshaler(unknown_abi* outer, void** result) noexcept { diff --git a/strings/base_meta.h b/strings/base_meta.h index 7dbb4c386..6b28640ef 100644 --- a/strings/base_meta.h +++ b/strings/base_meta.h @@ -48,7 +48,7 @@ WINRT_EXPORT namespace winrt } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { using namespace std::literals; diff --git a/strings/base_module_base_ixx.h b/strings/base_module_base_ixx.h new file mode 100644 index 000000000..5930f54ea --- /dev/null +++ b/strings/base_module_base_ixx.h @@ -0,0 +1,13 @@ + +#include +#include + +#ifdef WINRT_ENABLE_LEGACY_COM +#include +#include +#endif + +export module winrt_base; + +import std; +export import winrt_numerics; diff --git a/strings/base_module_ixx_preamble.h b/strings/base_module_ixx_preamble.h new file mode 100644 index 000000000..114873dc7 --- /dev/null +++ b/strings/base_module_ixx_preamble.h @@ -0,0 +1,11 @@ +module; +#define WINRT_IMPL_BUILD_MODULE + +#if defined(_MSC_VER) && _MSC_VER < 1950 +#pragma message("warning: C++/WinRT modules require MSVC toolset v14.50 (v145) or later. Building with an older toolset is not supported and may produce unexpected errors.") +#endif + +#include +#ifdef _DEBUG +#include +#endif // _DEBUG diff --git a/strings/base_module_numerics_ixx.h b/strings/base_module_numerics_ixx.h new file mode 100644 index 000000000..f1ade01ff --- /dev/null +++ b/strings/base_module_numerics_ixx.h @@ -0,0 +1,6 @@ + +#include + +#if defined(_MSC_VER) +#pragma detect_mismatch("C++/WinRT version", CPPWINRT_VERSION) +#endif diff --git a/strings/base_natvis.h b/strings/base_natvis.h index 60c5f5548..9e78563cb 100644 --- a/strings/base_natvis.h +++ b/strings/base_natvis.h @@ -5,7 +5,7 @@ #ifdef WINRT_NATVIS -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { struct natvis { diff --git a/strings/base_reference_produce.h b/strings/base_reference_produce.h index 2820aff50..abffb3384 100644 --- a/strings/base_reference_produce.h +++ b/strings/base_reference_produce.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct reference : implements, Windows::Foundation::IReference, Windows::Foundation::IPropertyValue> @@ -420,7 +420,7 @@ WINRT_EXPORT namespace winrt::Windows::Foundation } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template T unbox_value_type(From&& value) diff --git a/strings/base_source_location.h b/strings/base_source_location.h new file mode 100644 index 000000000..c0fd81f9f --- /dev/null +++ b/strings/base_source_location.h @@ -0,0 +1,97 @@ + +// The intrinsics (such as __builtin_FILE()) that power std::source_location are also used to power winrt:impl::slim_source_location. +// The source location needs to be for the calling code, not cppwinrt itself, so that it is useful to developers building on top of +// this library. As a result any public-facing method that can result in an error needs a default-constructed slim_source_location +// argument so that it will collect source information from the application code that is calling into cppwinrt. +// +// We do not directly use std::source_location for two reasons: +// 1) std::source_location::function_name() is unavoidable. These strings end up in the final binary, bloating their size. This +// is particularly impactful for code bases that use templates heavily. Cases of 50% binary size growth have been observed. +// 2) std::source_location is a cpp20 feature, which is above the cpp17 feature floor for cppwinrt. By defining our own version +// we can avoid ODR violations in mixed cpp17/cpp20 builds. cpp17 callers will have an ABI that matches cpp20 callers (they +// will just not have useful file/line/function information). +// +// Some projects may decide that the source information binary size impact is not worth the benefit. Defining WINRT_NO_SOURCE_LOCATION +// will prevent this feature from activating. The slim_source_location type will be forwarded around but it will not include any +// nonzero data. That eliminates the biggest source of binary size overhead. +// +// To help with debugging the __builtin_FUNCTION() intrinsic will be used in _DEBUG builds. This will provide a bit more diagnostic +// value at the cost of binary size. The assumption is that binary size is considered less important in debug builds so this tradeoff +// is acceptable. +// +// The different behavior of the default parameters to winrt::impl::slim_source_location::current() is technically an ODR violation, +// albeit a minor one. There should be no serious consequence to this violation. In practice it means that mixing cpp17/cpp20, +// or mixing WINRT_NO_SOURCE_LOCATION with undefining it, will lead to inconsistent source location information. It may be missing +// when it is expected to be included, or it may be present when it is not expected. The behavior will depend on the linker's choice +// when there are multiple translation units with different options. This violation is tracked by https://github.com/microsoft/cppwinrt/issues/1445. + +#if !defined(__cpp_lib_source_location) || defined(WINRT_NO_SOURCE_LOCATION) +// Case1: cpp17 mode. The source_location intrinsics are not available. +// Case2: The caller has disabled source_location support. Ensure that there is no binary size overhead for line/file/function. +#define WINRT_IMPL_BUILTIN_LINE 0 +#define WINRT_IMPL_BUILTIN_FILE nullptr +#define WINRT_IMPL_BUILTIN_FUNCTION nullptr +#elif _DEBUG +// cpp20 _DEBUG builds include function information, which has a heavy binary size impact, in addition to file/line. +#define WINRT_IMPL_BUILTIN_LINE __builtin_LINE() +#define WINRT_IMPL_BUILTIN_FILE __builtin_FILE() +#define WINRT_IMPL_BUILTIN_FUNCTION __builtin_FUNCTION() +#else +// Release builds in cpp20 mode get file and line information but NOT function information. Function strings +// quickly add up to a substantial binary size impact, especially when templates are heavily used. +#define WINRT_IMPL_BUILTIN_LINE __builtin_LINE() +#define WINRT_IMPL_BUILTIN_FILE __builtin_FILE() +#define WINRT_IMPL_BUILTIN_FUNCTION nullptr +#endif + +WINRT_EXPORT namespace winrt::impl +{ + // This struct is intended to be highly similar to std::source_location. The key difference is + // that function_name is NOT included. Function names do not fold to identical strings and can + // have heavy binary size overhead when templates cause many permutations to exist. + struct slim_source_location + { + [[nodiscard]] static WINRT_IMPL_CONSTEVAL slim_source_location current( + const std::uint_least32_t line = WINRT_IMPL_BUILTIN_LINE, + const char* const file = WINRT_IMPL_BUILTIN_FILE, + const char* const function = WINRT_IMPL_BUILTIN_FUNCTION) noexcept + { + return slim_source_location{ line, file, function }; + } + + [[nodiscard]] constexpr slim_source_location() noexcept = default; + + [[nodiscard]] constexpr slim_source_location( + const std::uint_least32_t line, + const char* const file, + const char* const function) noexcept : + m_line(line), + m_file(file), + m_function(function) + {} + + [[nodiscard]] constexpr std::uint_least32_t line() const noexcept + { + return m_line; + } + + [[nodiscard]] constexpr const char* file_name() const noexcept + { + return m_file; + } + + [[nodiscard]] constexpr const char* function_name() const noexcept + { + return m_function; + } + + private: + const std::uint_least32_t m_line{}; + const char* const m_file{}; + const char* const m_function{}; + }; +} + +#ifdef _MSC_VER +#pragma detect_mismatch("WINRT_SOURCE_LOCATION", "slim") +#endif // _MSC_VER diff --git a/strings/base_std_hash.h b/strings/base_std_hash.h index 864c31b13..4777f8082 100644 --- a/strings/base_std_hash.h +++ b/strings/base_std_hash.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { inline std::size_t hash_data(void const* ptr, std::size_t const bytes) noexcept { @@ -32,7 +32,7 @@ namespace winrt::impl }; } -namespace std +WINRT_IMPL_STD_EXPORT namespace std { template<> struct hash { diff --git a/strings/base_string.h b/strings/base_string.h index 92295e81c..6b1fb37b5 100644 --- a/strings/base_string.h +++ b/strings/base_string.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { struct atomic_ref_count { @@ -442,7 +442,7 @@ template<> struct std::formatter : std::formatter {}; #endif -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template <> struct abi { diff --git a/strings/base_string_input.h b/strings/base_string_input.h index 5ac0221f6..71cd5f3c0 100644 --- a/strings/base_string_input.h +++ b/strings/base_string_input.h @@ -65,7 +65,7 @@ WINRT_EXPORT namespace winrt::param } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template using param_type = std::conditional_t, param::hstring, T>; diff --git a/strings/base_string_operators.h b/strings/base_string_operators.h index 25e2eccce..223769d01 100644 --- a/strings/base_string_operators.h +++ b/strings/base_string_operators.h @@ -94,7 +94,7 @@ WINRT_EXPORT namespace winrt bool operator>=(std::nullptr_t left, hstring const& right) = delete; } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { inline hstring concat_hstring(std::wstring_view const& left, std::wstring_view const& right) { diff --git a/strings/base_types.h b/strings/base_types.h index 18529e116..dc2b13632 100644 --- a/strings/base_types.h +++ b/strings/base_types.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { using ptp_io = struct tp_io*; using ptp_timer = struct tp_timer*; @@ -208,7 +208,7 @@ WINRT_EXPORT namespace winrt::Windows::Foundation using DateTime = std::chrono::time_point; } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { #ifdef WINRT_IMPL_IUNKNOWN_DEFINED using hresult_type = long; diff --git a/strings/base_version.h b/strings/base_version.h index 4a6b68e66..13d21fb2a 100644 --- a/strings/base_version.h +++ b/strings/base_version.h @@ -16,6 +16,8 @@ char const * const WINRT_version = "C++/WinRT version:" CPPWINRT_VERSION; WINRT_EXPORT namespace winrt { + inline constexpr char cppwinrt_version[] = CPPWINRT_VERSION; + template constexpr bool check_version(char const(&base)[BaseSize], char const(&component)[ComponentSize]) noexcept { diff --git a/strings/base_windows.h b/strings/base_windows.h index 21c4163e5..dcd164574 100644 --- a/strings/base_windows.h +++ b/strings/base_windows.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { #ifdef WINRT_DIAGNOSTICS diff --git a/strings/base_xaml_typename.h b/strings/base_xaml_typename.h index b7b3a954a..2cc45b0bb 100644 --- a/strings/base_xaml_typename.h +++ b/strings/base_xaml_typename.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct xaml_typename_name diff --git a/test/nuget/NuGetTest.sln b/test/nuget/NuGetTest.sln index 310b0f252..c836b2551 100644 --- a/test/nuget/NuGetTest.sln +++ b/test/nuget/NuGetTest.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.5.33516.290 @@ -47,6 +47,21 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConsoleApplication1", "Cons EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestProxyStub", "TestProxyStub\TestProxyStub.vcxproj", "{98E28FC8-2EB7-4544-9B6A-941462C6D3E2}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestModuleApp", "TestModuleApp\TestModuleApp.vcxproj", "{8679913F-D38D-468F-A8B7-75B187A7A8BC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestModuleBuilder", "TestModuleBuilder\TestModuleBuilder.vcxproj", "{AEE91B86-AA17-4C22-B0C2-08B2C287E375}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestModuleComponent1", "TestModuleComponent1\TestModuleComponent1.vcxproj", "{F54D9A50-84D7-4953-8350-BEFE73CC36F6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestModuleComponent2", "TestModuleComponent2\TestModuleComponent2.vcxproj", "{126E9412-E861-47C6-8684-C8F9BF32C0BD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestModuleConsumerApp", "TestModuleConsumerApp\TestModuleConsumerApp.vcxproj", "{FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}" + ProjectSection(ProjectDependencies) = postProject + {AEE91B86-AA17-4C22-B0C2-08B2C287E375} = {AEE91B86-AA17-4C22-B0C2-08B2C287E375} + {F54D9A50-84D7-4953-8350-BEFE73CC36F6} = {F54D9A50-84D7-4953-8350-BEFE73CC36F6} + {126E9412-E861-47C6-8684-C8F9BF32C0BD} = {126E9412-E861-47C6-8684-C8F9BF32C0BD} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 @@ -279,6 +294,58 @@ Global {98E28FC8-2EB7-4544-9B6A-941462C6D3E2}.Release|x64.Build.0 = Release|x64 {98E28FC8-2EB7-4544-9B6A-941462C6D3E2}.Release|x86.ActiveCfg = Release|Win32 {98E28FC8-2EB7-4544-9B6A-941462C6D3E2}.Release|x86.Build.0 = Release|Win32 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Debug|ARM64.Build.0 = Debug|ARM64 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Debug|x64.ActiveCfg = Debug|x64 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Debug|x64.Build.0 = Debug|x64 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Debug|x86.ActiveCfg = Debug|Win32 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Debug|x86.Build.0 = Debug|Win32 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Release|ARM64.ActiveCfg = Release|ARM64 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Release|ARM64.Build.0 = Release|ARM64 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Release|x64.ActiveCfg = Release|x64 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Release|x64.Build.0 = Release|x64 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Release|x86.ActiveCfg = Release|Win32 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Release|x86.Build.0 = Release|Win32 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Debug|ARM64.ActiveCfg = Release|ARM64 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Debug|x64.ActiveCfg = Release|x64 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Debug|x64.Build.0 = Release|x64 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Debug|x86.ActiveCfg = Release|Win32 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Release|ARM64.ActiveCfg = Release|ARM64 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Release|ARM64.Build.0 = Release|ARM64 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Release|x64.ActiveCfg = Release|x64 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Release|x64.Build.0 = Release|x64 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Release|x86.ActiveCfg = Release|Win32 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Release|x86.Build.0 = Release|Win32 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Debug|ARM64.ActiveCfg = Release|ARM64 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Debug|x64.ActiveCfg = Release|x64 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Debug|x64.Build.0 = Release|x64 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Debug|x86.ActiveCfg = Release|Win32 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Release|ARM64.ActiveCfg = Release|ARM64 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Release|ARM64.Build.0 = Release|ARM64 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Release|x64.ActiveCfg = Release|x64 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Release|x64.Build.0 = Release|x64 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Release|x86.ActiveCfg = Release|Win32 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Release|x86.Build.0 = Release|Win32 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Debug|ARM64.ActiveCfg = Release|ARM64 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Debug|x64.ActiveCfg = Release|x64 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Debug|x64.Build.0 = Release|x64 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Debug|x86.ActiveCfg = Release|Win32 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Release|ARM64.ActiveCfg = Release|ARM64 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Release|ARM64.Build.0 = Release|ARM64 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Release|x64.ActiveCfg = Release|x64 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Release|x64.Build.0 = Release|x64 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Release|x86.ActiveCfg = Release|Win32 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Release|x86.Build.0 = Release|Win32 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Debug|ARM64.ActiveCfg = Release|ARM64 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Debug|x64.ActiveCfg = Release|x64 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Debug|x64.Build.0 = Release|x64 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Debug|x86.ActiveCfg = Release|Win32 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Release|ARM64.ActiveCfg = Release|ARM64 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Release|ARM64.Build.0 = Release|ARM64 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Release|x64.ActiveCfg = Release|x64 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Release|x64.Build.0 = Release|x64 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Release|x86.ActiveCfg = Release|Win32 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/test/nuget/TestModuleApp/CustomDependencyObject.cpp b/test/nuget/TestModuleApp/CustomDependencyObject.cpp new file mode 100644 index 000000000..81631e387 --- /dev/null +++ b/test/nuget/TestModuleApp/CustomDependencyObject.cpp @@ -0,0 +1,8 @@ +#include "pch.h" + +#define WINRT_IMPORT_MODULE +import winrt.Windows.Foundation; +import winrt.Windows.UI.Xaml; + +#include "CustomDependencyObject.h" +#include "CustomDependencyObject.g.cpp" diff --git a/test/nuget/TestModuleApp/CustomDependencyObject.h b/test/nuget/TestModuleApp/CustomDependencyObject.h new file mode 100644 index 000000000..79fd6b1ff --- /dev/null +++ b/test/nuget/TestModuleApp/CustomDependencyObject.h @@ -0,0 +1,23 @@ +#pragma once +#include "CustomDependencyObject.g.h" + +namespace winrt::TestModuleApp::implementation +{ + struct CustomDependencyObject : CustomDependencyObjectT + { + CustomDependencyObject() = default; + + hstring Name() { return m_name; } + void Name(hstring const& value) { m_name = value; } + + private: + hstring m_name; + }; +} + +namespace winrt::TestModuleApp::factory_implementation +{ + struct CustomDependencyObject : CustomDependencyObjectT + { + }; +} diff --git a/test/nuget/TestModuleApp/ModuleTestHelper.cpp b/test/nuget/TestModuleApp/ModuleTestHelper.cpp new file mode 100644 index 000000000..1e3d7bc1a --- /dev/null +++ b/test/nuget/TestModuleApp/ModuleTestHelper.cpp @@ -0,0 +1,7 @@ +#include "pch.h" + +#define WINRT_IMPORT_MODULE +import winrt.Windows.Foundation; + +#include "ModuleTestHelper.h" +#include "ModuleTestHelper.g.cpp" diff --git a/test/nuget/TestModuleApp/ModuleTestHelper.h b/test/nuget/TestModuleApp/ModuleTestHelper.h new file mode 100644 index 000000000..c5a699c6b --- /dev/null +++ b/test/nuget/TestModuleApp/ModuleTestHelper.h @@ -0,0 +1,27 @@ +#pragma once +#include "ModuleTestHelper.g.h" + +namespace winrt::TestModuleApp::implementation +{ + struct ModuleTestHelper : ModuleTestHelperT + { + ModuleTestHelper() = default; + + Windows::Foundation::Uri CreateUri(hstring const& url) + { + return Windows::Foundation::Uri(url); + } + + Windows::Foundation::IAsyncOperation GetStringAsync() + { + co_return L"hello from module"; + } + }; +} + +namespace winrt::TestModuleApp::factory_implementation +{ + struct ModuleTestHelper : ModuleTestHelperT + { + }; +} diff --git a/test/nuget/TestModuleApp/PropertySheet.props b/test/nuget/TestModuleApp/PropertySheet.props new file mode 100644 index 000000000..379c2c3a2 --- /dev/null +++ b/test/nuget/TestModuleApp/PropertySheet.props @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/nuget/TestModuleApp/TestModuleApp.def b/test/nuget/TestModuleApp/TestModuleApp.def new file mode 100644 index 000000000..53d2e7cbf --- /dev/null +++ b/test/nuget/TestModuleApp/TestModuleApp.def @@ -0,0 +1,3 @@ +EXPORTS +DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE +DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE diff --git a/test/nuget/TestModuleApp/TestModuleApp.idl b/test/nuget/TestModuleApp/TestModuleApp.idl new file mode 100644 index 000000000..ab3c56707 --- /dev/null +++ b/test/nuget/TestModuleApp/TestModuleApp.idl @@ -0,0 +1,20 @@ +namespace TestModuleApp +{ + // A type that inherits from Windows.UI.Xaml.DependencyObject to exercise + // cross-namespace inheritance in module builds. + [default_interface] + unsealed runtimeclass CustomDependencyObject : Windows.UI.Xaml.DependencyObject + { + CustomDependencyObject(); + String Name{ get; set; }; + } + + // A simple runtime class using platform SDK types. + [default_interface] + runtimeclass ModuleTestHelper + { + ModuleTestHelper(); + Windows.Foundation.Uri CreateUri(String url); + Windows.Foundation.IAsyncOperation GetStringAsync(); + } +} diff --git a/test/nuget/TestModuleApp/TestModuleApp.vcxproj b/test/nuget/TestModuleApp/TestModuleApp.vcxproj new file mode 100644 index 000000000..522e0d911 --- /dev/null +++ b/test/nuget/TestModuleApp/TestModuleApp.vcxproj @@ -0,0 +1,127 @@ + + + + + true + true + true + Windows;TestModuleApp + true + {8679913F-D38D-468F-A8B7-75B187A7A8BC} + TestModuleApp + TestModuleApp + en-US + 14.0 + + + + + Debug + Win32 + + + Debug + x64 + + + Debug + ARM64 + + + Release + Win32 + + + Release + x64 + + + Release + ARM64 + + + + Application + v145 + Unicode + + + true + + + false + true + + + + + + + + + + + + + + + + + Use + pch.h + $(IntDir)pch.pch + stdcpplatest + Level4 + true + %(AdditionalOptions) /bigobj + 5311;28204 + NOMINMAX;%(PreprocessorDefinitions) + true + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + + + Console + + + + + _DEBUG;%(PreprocessorDefinitions) + + + + + NDEBUG;%(PreprocessorDefinitions) + + + + + + TestModuleApp.idl + + + TestModuleApp.idl + + + + + Create + + + + TestModuleApp.idl + + + TestModuleApp.idl + + + + + + + + + + + + + diff --git a/test/nuget/TestModuleApp/main.cpp b/test/nuget/TestModuleApp/main.cpp new file mode 100644 index 000000000..907e4afed --- /dev/null +++ b/test/nuget/TestModuleApp/main.cpp @@ -0,0 +1,42 @@ +#include "pch.h" + +#define WINRT_IMPORT_MODULE +import std; +import winrt.Windows.Foundation; +import winrt.Windows.UI.Xaml; + +#include "ModuleTestHelper.h" +#include "CustomDependencyObject.h" + +using namespace winrt; +using namespace Windows::Foundation; + +int main() +{ + init_apartment(); + + // Test ModuleTestHelper + auto helper = TestModuleApp::ModuleTestHelper(); + auto uri = helper.CreateUri(L"https://example.com"); + std::printf("URI: %ls\n", uri.AbsoluteUri().c_str()); + + auto str = helper.GetStringAsync().get(); + std::printf("Async: %ls\n", str.c_str()); + + // Test CustomDependencyObject (inherits from DependencyObject) + // Note: DependencyObject requires XAML runtime, which isn't available in a console app. + // We verify the type compiles and links correctly; runtime creation would need a XAML host. + try + { + auto obj = winrt::make(); + obj.Name(L"test"); + std::printf("Name: %ls\n", obj.Name().c_str()); + } + catch (winrt::hresult_error const& e) + { + std::printf("CustomDependencyObject: expected runtime error (no XAML host): %ls\n", e.message().c_str()); + } + + std::printf("All module tests passed.\n"); + return 0; +} diff --git a/test/nuget/TestModuleApp/pch.cpp b/test/nuget/TestModuleApp/pch.cpp new file mode 100644 index 000000000..1d9f38c57 --- /dev/null +++ b/test/nuget/TestModuleApp/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/test/nuget/TestModuleApp/pch.h b/test/nuget/TestModuleApp/pch.h new file mode 100644 index 000000000..6f70f09be --- /dev/null +++ b/test/nuget/TestModuleApp/pch.h @@ -0,0 +1 @@ +#pragma once diff --git a/test/nuget/TestModuleBuilder/PropertySheet.props b/test/nuget/TestModuleBuilder/PropertySheet.props new file mode 100644 index 000000000..379c2c3a2 --- /dev/null +++ b/test/nuget/TestModuleBuilder/PropertySheet.props @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/nuget/TestModuleBuilder/TestModuleBuilder.vcxproj b/test/nuget/TestModuleBuilder/TestModuleBuilder.vcxproj new file mode 100644 index 000000000..d2d852240 --- /dev/null +++ b/test/nuget/TestModuleBuilder/TestModuleBuilder.vcxproj @@ -0,0 +1,67 @@ + + + + + true + Windows.Foundation + Windows.Foundation.Diagnostics + true + {AEE91B86-AA17-4C22-B0C2-08B2C287E375} + TestModuleBuilder + TestModuleBuilder + en-US + 14.0 + + + + + Release + Win32 + + + Release + x64 + + + Release + ARM64 + + + + StaticLibrary + v145 + Unicode + + + false + true + + + + + + + + + + Use + pch.h + stdcpplatest + Level4 + true + %(AdditionalOptions) /bigobj + true + NOMINMAX;%(PreprocessorDefinitions) + + + + + + + + Create + + + + + diff --git a/test/nuget/TestModuleBuilder/pch.cpp b/test/nuget/TestModuleBuilder/pch.cpp new file mode 100644 index 000000000..1d9f38c57 --- /dev/null +++ b/test/nuget/TestModuleBuilder/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/test/nuget/TestModuleBuilder/pch.h b/test/nuget/TestModuleBuilder/pch.h new file mode 100644 index 000000000..6f70f09be --- /dev/null +++ b/test/nuget/TestModuleBuilder/pch.h @@ -0,0 +1 @@ +#pragma once diff --git a/test/nuget/TestModuleComponent1/Greeter.cpp b/test/nuget/TestModuleComponent1/Greeter.cpp new file mode 100644 index 000000000..04c668e10 --- /dev/null +++ b/test/nuget/TestModuleComponent1/Greeter.cpp @@ -0,0 +1,8 @@ +#include "pch.h" + +#define WINRT_IMPORT_MODULE +import winrt_base; +import winrt.Windows.Foundation; + +#include "Greeter.h" +#include "Greeter.g.cpp" diff --git a/test/nuget/TestModuleComponent1/Greeter.h b/test/nuget/TestModuleComponent1/Greeter.h new file mode 100644 index 000000000..726fb7d22 --- /dev/null +++ b/test/nuget/TestModuleComponent1/Greeter.h @@ -0,0 +1,25 @@ +#pragma once +#include "Greeter.g.h" + +namespace winrt::TestModuleComponent1::implementation +{ + struct Greeter : GreeterT + { + Greeter() : m_name(L"World") {} + Greeter(hstring const& name) : m_name(name) {} + + hstring Name() { return m_name; } + hstring Greet() { return L"Hello, " + m_name + L"!"; } + Windows::Foundation::Uri Homepage() { return Windows::Foundation::Uri(L"https://example.com/" + m_name); } + + private: + hstring m_name; + }; +} + +namespace winrt::TestModuleComponent1::factory_implementation +{ + struct Greeter : GreeterT + { + }; +} diff --git a/test/nuget/TestModuleComponent1/PropertySheet.props b/test/nuget/TestModuleComponent1/PropertySheet.props new file mode 100644 index 000000000..379c2c3a2 --- /dev/null +++ b/test/nuget/TestModuleComponent1/PropertySheet.props @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/nuget/TestModuleComponent1/TestModuleComponent1.def b/test/nuget/TestModuleComponent1/TestModuleComponent1.def new file mode 100644 index 000000000..53d2e7cbf --- /dev/null +++ b/test/nuget/TestModuleComponent1/TestModuleComponent1.def @@ -0,0 +1,3 @@ +EXPORTS +DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE +DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE diff --git a/test/nuget/TestModuleComponent1/TestModuleComponent1.idl b/test/nuget/TestModuleComponent1/TestModuleComponent1.idl new file mode 100644 index 000000000..73a983ee2 --- /dev/null +++ b/test/nuget/TestModuleComponent1/TestModuleComponent1.idl @@ -0,0 +1,12 @@ +namespace TestModuleComponent1 +{ + [default_interface] + runtimeclass Greeter + { + Greeter(); + Greeter(String name); + String Name{ get; }; + String Greet(); + Windows.Foundation.Uri Homepage{ get; }; + } +} diff --git a/test/nuget/TestModuleComponent1/TestModuleComponent1.vcxproj b/test/nuget/TestModuleComponent1/TestModuleComponent1.vcxproj new file mode 100644 index 000000000..669b25ff0 --- /dev/null +++ b/test/nuget/TestModuleComponent1/TestModuleComponent1.vcxproj @@ -0,0 +1,92 @@ + + + + + true + true + true + true + {F54D9A50-84D7-4953-8350-BEFE73CC36F6} + TestModuleComponent1 + TestModuleComponent1 + en-US + 14.0 + + + + + Release + Win32 + + + Release + x64 + + + Release + ARM64 + + + + DynamicLibrary + v145 + Unicode + + + false + true + + + + + + + + + + Use + pch.h + stdcpplatest + Level4 + true + %(AdditionalOptions) /bigobj + true + _WINRT_DLL;NOMINMAX;%(PreprocessorDefinitions) + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + + + Console + false + TestModuleComponent1.def + + + + + + TestModuleComponent1.idl + + + + + Create + + + TestModuleComponent1.idl + + + + + + + + + + + + + true + + + + + diff --git a/test/nuget/TestModuleComponent1/pch.cpp b/test/nuget/TestModuleComponent1/pch.cpp new file mode 100644 index 000000000..1d9f38c57 --- /dev/null +++ b/test/nuget/TestModuleComponent1/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/test/nuget/TestModuleComponent1/pch.h b/test/nuget/TestModuleComponent1/pch.h new file mode 100644 index 000000000..6f70f09be --- /dev/null +++ b/test/nuget/TestModuleComponent1/pch.h @@ -0,0 +1 @@ +#pragma once diff --git a/test/nuget/TestModuleComponent2/GreeterGroup.cpp b/test/nuget/TestModuleComponent2/GreeterGroup.cpp new file mode 100644 index 000000000..7c6410b44 --- /dev/null +++ b/test/nuget/TestModuleComponent2/GreeterGroup.cpp @@ -0,0 +1,9 @@ +#include "pch.h" + +#define WINRT_IMPORT_MODULE +import std; +import winrt.Windows.Foundation; +import winrt.TestModuleComponent1; + +#include "GreeterGroup.h" +#include "GreeterGroup.g.cpp" diff --git a/test/nuget/TestModuleComponent2/GreeterGroup.h b/test/nuget/TestModuleComponent2/GreeterGroup.h new file mode 100644 index 000000000..461570425 --- /dev/null +++ b/test/nuget/TestModuleComponent2/GreeterGroup.h @@ -0,0 +1,36 @@ +#pragma once +#include "GreeterGroup.g.h" + +namespace winrt::TestModuleComponent2::implementation +{ + struct GreeterGroup : GreeterGroupT + { + GreeterGroup() = default; + + void Add(winrt::TestModuleComponent1::Greeter const& greeter) + { + m_greeters.push_back(greeter); + } + + hstring GreetAll() + { + hstring result; + for (auto const& g : m_greeters) + { + if (!result.empty()) result = result + L", "; + result = result + g.Greet(); + } + return result; + } + + private: + std::vector m_greeters; + }; +} + +namespace winrt::TestModuleComponent2::factory_implementation +{ + struct GreeterGroup : GreeterGroupT + { + }; +} diff --git a/test/nuget/TestModuleComponent2/PropertySheet.props b/test/nuget/TestModuleComponent2/PropertySheet.props new file mode 100644 index 000000000..379c2c3a2 --- /dev/null +++ b/test/nuget/TestModuleComponent2/PropertySheet.props @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/nuget/TestModuleComponent2/TestModuleComponent2.def b/test/nuget/TestModuleComponent2/TestModuleComponent2.def new file mode 100644 index 000000000..53d2e7cbf --- /dev/null +++ b/test/nuget/TestModuleComponent2/TestModuleComponent2.def @@ -0,0 +1,3 @@ +EXPORTS +DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE +DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE diff --git a/test/nuget/TestModuleComponent2/TestModuleComponent2.idl b/test/nuget/TestModuleComponent2/TestModuleComponent2.idl new file mode 100644 index 000000000..e45eed438 --- /dev/null +++ b/test/nuget/TestModuleComponent2/TestModuleComponent2.idl @@ -0,0 +1,10 @@ +namespace TestModuleComponent2 +{ + [default_interface] + runtimeclass GreeterGroup + { + GreeterGroup(); + void Add(TestModuleComponent1.Greeter greeter); + String GreetAll(); + } +} diff --git a/test/nuget/TestModuleComponent2/TestModuleComponent2.vcxproj b/test/nuget/TestModuleComponent2/TestModuleComponent2.vcxproj new file mode 100644 index 000000000..ff4982965 --- /dev/null +++ b/test/nuget/TestModuleComponent2/TestModuleComponent2.vcxproj @@ -0,0 +1,93 @@ + + + + + true + true + true + true + {126E9412-E861-47C6-8684-C8F9BF32C0BD} + TestModuleComponent2 + TestModuleComponent2 + en-US + 14.0 + + + + + Release + Win32 + + + Release + x64 + + + Release + ARM64 + + + + DynamicLibrary + v145 + Unicode + + + false + true + + + + + + + + + + Use + pch.h + stdcpplatest + Level4 + true + %(AdditionalOptions) /bigobj + true + _WINRT_DLL;NOMINMAX;%(PreprocessorDefinitions) + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + + + Console + false + TestModuleComponent2.def + + + + + + TestModuleComponent2.idl + + + + + Create + + + TestModuleComponent2.idl + + + + + + + + + + + + + true + + + + + + diff --git a/test/nuget/TestModuleComponent2/pch.cpp b/test/nuget/TestModuleComponent2/pch.cpp new file mode 100644 index 000000000..1d9f38c57 --- /dev/null +++ b/test/nuget/TestModuleComponent2/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/test/nuget/TestModuleComponent2/pch.h b/test/nuget/TestModuleComponent2/pch.h new file mode 100644 index 000000000..6f70f09be --- /dev/null +++ b/test/nuget/TestModuleComponent2/pch.h @@ -0,0 +1 @@ +#pragma once diff --git a/test/nuget/TestModuleConsumerApp/PropertySheet.props b/test/nuget/TestModuleConsumerApp/PropertySheet.props new file mode 100644 index 000000000..379c2c3a2 --- /dev/null +++ b/test/nuget/TestModuleConsumerApp/PropertySheet.props @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/nuget/TestModuleConsumerApp/TestModuleConsumerApp.vcxproj b/test/nuget/TestModuleConsumerApp/TestModuleConsumerApp.vcxproj new file mode 100644 index 000000000..910586a0c --- /dev/null +++ b/test/nuget/TestModuleConsumerApp/TestModuleConsumerApp.vcxproj @@ -0,0 +1,76 @@ + + + + + true + true + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9} + TestModuleConsumerApp + TestModuleConsumerApp + en-US + 14.0 + + + + + Release + Win32 + + + Release + x64 + + + Release + ARM64 + + + + Application + v145 + Unicode + + + false + true + + + + + + + + + + Use + pch.h + stdcpplatest + Level4 + true + %(AdditionalOptions) /bigobj + true + NOMINMAX;%(PreprocessorDefinitions) + + + Console + + + + + + + + Create + + + + + + true + + + + + + + diff --git a/test/nuget/TestModuleConsumerApp/main.cpp b/test/nuget/TestModuleConsumerApp/main.cpp new file mode 100644 index 000000000..da930703b --- /dev/null +++ b/test/nuget/TestModuleConsumerApp/main.cpp @@ -0,0 +1,32 @@ +#include "pch.h" + +import std; +import winrt.Windows.Foundation; +import winrt.TestModuleComponent1; +import winrt.TestModuleComponent2; + +using namespace winrt; +using namespace Windows::Foundation; + +int main() +{ + init_apartment(); + + // Platform types from pre-built modules + Uri uri(L"https://example.com/consumer"); + std::printf("URI: %ls\n", uri.AbsoluteUri().c_str()); + + // Component1 + auto greeter = TestModuleComponent1::Greeter(L"Modules"); + std::printf("Greet: %ls\n", greeter.Greet().c_str()); + std::printf("Homepage: %ls\n", greeter.Homepage().AbsoluteUri().c_str()); + + // Component2 (depends on Component1) + auto group = TestModuleComponent2::GreeterGroup(); + group.Add(TestModuleComponent1::Greeter(L"Alice")); + group.Add(TestModuleComponent1::Greeter(L"Bob")); + std::printf("GreetAll: %ls\n", group.GreetAll().c_str()); + + std::printf("All consumer tests passed.\n"); + return 0; +} diff --git a/test/nuget/TestModuleConsumerApp/pch.cpp b/test/nuget/TestModuleConsumerApp/pch.cpp new file mode 100644 index 000000000..1d9f38c57 --- /dev/null +++ b/test/nuget/TestModuleConsumerApp/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/test/nuget/TestModuleConsumerApp/pch.h b/test/nuget/TestModuleConsumerApp/pch.h new file mode 100644 index 000000000..6f70f09be --- /dev/null +++ b/test/nuget/TestModuleConsumerApp/pch.h @@ -0,0 +1 @@ +#pragma once diff --git a/test/test_cpp20_module/collections.cpp b/test/test_cpp20_module/collections.cpp new file mode 100644 index 000000000..b80e123d2 --- /dev/null +++ b/test/test_cpp20_module/collections.cpp @@ -0,0 +1,57 @@ +#include "pch.h" + +import winrt.Windows.Foundation; + +using namespace winrt; +using namespace Windows::Foundation::Collections; + +TEST_CASE("module_vector") +{ + auto vec = single_threaded_vector(); + vec.Append(10); + vec.Append(20); + vec.Append(30); + REQUIRE(vec.Size() == 3); + REQUIRE(vec.GetAt(0) == 10); + REQUIRE(vec.GetAt(2) == 30); + + vec.RemoveAtEnd(); + REQUIRE(vec.Size() == 2); +} + +TEST_CASE("module_map") +{ + auto map = single_threaded_map(); + map.Insert(L"key1", L"value1"); + map.Insert(L"key2", L"value2"); + REQUIRE(map.Size() == 2); + REQUIRE(map.Lookup(L"key1") == L"value1"); + REQUIRE(map.HasKey(L"key2")); + REQUIRE(!map.HasKey(L"key3")); +} + +TEST_CASE("module_observable_vector") +{ + auto vec = single_threaded_observable_vector(); + int change_count = 0; + auto token = vec.VectorChanged([&](auto&&, auto&&) { ++change_count; }); + vec.Append(1); + vec.Append(2); + REQUIRE(change_count == 2); + vec.VectorChanged(token); +} + +TEST_CASE("module_iterable") +{ + auto vec = single_threaded_vector(); + vec.Append(1); + vec.Append(2); + vec.Append(3); + + int sum = 0; + for (auto v : vec) + { + sum += v; + } + REQUIRE(sum == 6); +} diff --git a/test/test_cpp20_module/com_interop.cpp b/test/test_cpp20_module/com_interop.cpp new file mode 100644 index 000000000..3035d2a05 --- /dev/null +++ b/test/test_cpp20_module/com_interop.cpp @@ -0,0 +1,84 @@ +#include "pch.h" +#include +#include + +import std; +import winrt.Windows.Foundation; + +// +// These tests confirm that COM interop — including legacy (non-WinRT) COM types +// from the Windows SDK — works correctly when consumed via modules. +// +// Note: We avoid 'using namespace Windows::Foundation' here because it brings +// IInspectable/IUnknown into scope and collides with the SDK types of the same name. +// + +using namespace winrt; + +TEST_CASE("module_com_ptr_round_trip") +{ + Windows::Foundation::Uri uri(L"https://example.com"); + + // Detach to raw ABI pointer and re-attach + void* abi = detach_abi(uri); + REQUIRE(abi != nullptr); + + Windows::Foundation::Uri uri2{ nullptr }; + attach_abi(uri2, abi); + REQUIRE(uri2.AbsoluteUri() == L"https://example.com/"); +} + +TEST_CASE("module_sdk_iunknown_interop") +{ + // Interop between winrt projected types and the Windows SDK ::IUnknown + Windows::Foundation::Uri uri(L"https://example.com"); + + // Get the SDK IUnknown pointer from a projected type + ::IUnknown* raw = nullptr; + copy_to_abi(uri, *reinterpret_cast(&raw)); + REQUIRE(raw != nullptr); + + // QI for IInspectable through the raw SDK pointer + ::IInspectable* inspectable = nullptr; + REQUIRE(raw->QueryInterface(IID_IInspectable, reinterpret_cast(&inspectable)) == S_OK); + REQUIRE(inspectable != nullptr); + inspectable->Release(); + + // Round-trip back to a projected type + Windows::Foundation::Uri uri2{ nullptr }; + copy_from_abi(uri2, raw); + REQUIRE(uri2.AbsoluteUri() == L"https://example.com/"); + + raw->Release(); +} + +TEST_CASE("module_com_ptr_sdk_type") +{ + // winrt::com_ptr wrapping a Windows SDK ::IUnknown + Windows::Foundation::Uri uri(L"https://example.com"); + + com_ptr<::IUnknown> unknown; + copy_to_abi(uri, *reinterpret_cast(unknown.put())); + REQUIRE(unknown.get() != nullptr); +} + +TEST_CASE("module_iunknown_identity") +{ + Windows::Foundation::Uri uri(L"https://example.com"); + + auto unknown1 = uri.as(); + auto unknown2 = uri.as(); + REQUIRE(unknown1 == unknown2); +} + +TEST_CASE("module_try_as") +{ + Windows::Foundation::Uri uri(L"https://example.com"); + + auto stringable = uri.try_as(); + REQUIRE(stringable != nullptr); + REQUIRE(!stringable.ToString().empty()); + + auto closable = uri.try_as(); + REQUIRE(closable == nullptr); +} diff --git a/test/test_cpp20_module/coroutines.cpp b/test/test_cpp20_module/coroutines.cpp new file mode 100644 index 000000000..1553b1c6d --- /dev/null +++ b/test/test_cpp20_module/coroutines.cpp @@ -0,0 +1,58 @@ +#include "pch.h" + +import std; +import winrt.Windows.Foundation; + +using namespace winrt; +using namespace Windows::Foundation; + +IAsyncAction do_nothing_async() +{ + co_return; +} + +IAsyncOperation return_42_async() +{ + co_return 42; +} + +IAsyncOperation return_string_async() +{ + co_return L"module coroutine"; +} + +IAsyncAction chain_async() +{ + auto result = co_await return_string_async(); + REQUIRE(!result.empty()); +} + +IAsyncOperation slow_operation() +{ + co_await resume_after(std::chrono::hours(1)); + co_return 0; +} + +TEST_CASE("module_async_action") +{ + auto action = do_nothing_async(); + action.get(); + REQUIRE(action.Status() == AsyncStatus::Completed); +} + +TEST_CASE("module_async_operation") +{ + REQUIRE(return_42_async().get() == 42); +} + +TEST_CASE("module_async_chain") +{ + chain_async().get(); +} + +TEST_CASE("module_async_cancel") +{ + auto op = slow_operation(); + op.Cancel(); + REQUIRE(op.Status() == AsyncStatus::Canceled); +} diff --git a/test/test_cpp20_module/format.cpp b/test/test_cpp20_module/format.cpp new file mode 100644 index 000000000..0c4570300 --- /dev/null +++ b/test/test_cpp20_module/format.cpp @@ -0,0 +1,49 @@ +#include "pch.h" + +#ifdef __cpp_lib_format + +import std; +import winrt.Windows.Foundation; + +// +// These tests confirm that std::format and std::formatter specializations work +// correctly when consumed via modules. Mirrors test/test_cpp20/format.cpp. +// + +using namespace winrt; +using namespace Windows::Foundation; + +TEST_CASE("module_format_hstring") +{ + hstring str = L"World"; + REQUIRE(std::format(L"Hello {}", str) == L"Hello World"); +} + +TEST_CASE("module_format_IStringable") +{ + // Uri implements IStringable — exercises the generated + // std::formatter specialization through modules. + Uri uri(L"https://example.com/path"); + IStringable stringable = uri; + REQUIRE(std::format(L"Visit: {}", stringable) == L"Visit: https://example.com/path"); +} + +TEST_CASE("module_format_projected_class") +{ + // Exercises the generated std::formatter specialization + // (inherits from formatter) through modules. + Uri uri(L"https://example.com"); + REQUIRE(std::format(L"URL: {}", uri) == L"URL: https://example.com/"); +} + +#if __cpp_lib_format >= 202207L +TEST_CASE("module_format_winrt_format") +{ + // winrt::format helper (C++23 formattable concept) + std::wstring str = L"World"; + REQUIRE(winrt::format(L"Hello {}", str) == L"Hello World"); + REQUIRE(winrt::format(L"C++/WinRT #{:d}", 1) == L"C++/WinRT #1"); +} +#endif + +#endif // __cpp_lib_format diff --git a/test/test_cpp20_module/foundation.cpp b/test/test_cpp20_module/foundation.cpp new file mode 100644 index 000000000..d26c55244 --- /dev/null +++ b/test/test_cpp20_module/foundation.cpp @@ -0,0 +1,68 @@ +#include "pch.h" + +import std; +import winrt.Windows.Foundation; + +using namespace winrt; +using namespace Windows::Foundation; + +TEST_CASE("module_uri") +{ + Uri uri(L"https://example.com/path?query=1"); + REQUIRE(!uri.AbsoluteUri().empty()); + REQUIRE(uri.Host() == L"example.com"); + REQUIRE(uri.Path() == L"/path"); +} + +TEST_CASE("module_property_value") +{ + auto pv = PropertyValue::CreateInt32(42); + REQUIRE(pv.as().GetInt32() == 42); + + auto pvs = PropertyValue::CreateString(L"hello"); + REQUIRE(pvs.as().GetString() == L"hello"); +} + +TEST_CASE("module_hstring") +{ + hstring text = L"C++/WinRT modules"; + REQUIRE(!text.empty()); + REQUIRE(text.size() == 17); + + hstring empty; + REQUIRE(empty.empty()); + REQUIRE(empty.size() == 0); +} + +TEST_CASE("module_events") +{ + winrt::event> my_event; + int received = 0; + auto token = my_event.add([&](auto&&, int value) { received = value; }); + my_event(nullptr, 42); + REQUIRE(received == 42); + my_event.remove(token); +} + +TEST_CASE("module_foundation_point") +{ + Point p{ 5.0f, 10.0f }; + REQUIRE(p.X == 5.0f); + REQUIRE(p.Y == 10.0f); +} + +TEST_CASE("module_foundation_size") +{ + Size s{ 800.0f, 600.0f }; + REQUIRE(s.Width == 800.0f); + REQUIRE(s.Height == 600.0f); +} + +TEST_CASE("module_foundation_rect") +{ + Point origin{ 0.0f, 0.0f }; + Size extent{ 100.0f, 200.0f }; + Rect r(origin, extent); + REQUIRE(r.X == 0.0f); + REQUIRE(r.Width == 100.0f); +} diff --git a/test/test_cpp20_module/hash.cpp b/test/test_cpp20_module/hash.cpp new file mode 100644 index 000000000..bb7594104 --- /dev/null +++ b/test/test_cpp20_module/hash.cpp @@ -0,0 +1,73 @@ +#include "pch.h" + +import std; +import winrt.Windows.Foundation; + +// +// These tests confirm that std::hash specializations work correctly +// when consumed via modules, enabling use in unordered containers. +// + +using namespace winrt; +using namespace Windows::Foundation; + +TEST_CASE("module_hash_hstring") +{ + std::unordered_set set; + set.insert(L"hello"); + set.insert(L"world"); + set.insert(L"hello"); // duplicate + REQUIRE(set.size() == 2); + REQUIRE(set.contains(L"hello")); + REQUIRE(set.contains(L"world")); +} + +TEST_CASE("module_hash_IUnknown") +{ + Uri uri(L"https://example.com"); + auto unknown = uri.as(); + + std::unordered_set set; + set.insert(unknown); + set.insert(unknown); // duplicate — same identity + REQUIRE(set.size() == 1); + + // A different object should hash differently (almost certainly) + Uri uri2(L"https://other.com"); + set.insert(uri2.as()); + REQUIRE(set.size() == 2); +} + +TEST_CASE("module_hash_projected_type") +{ + // Projected types like Uri should be hashable via the generated + // std::hash specialization (inherits from hash_base). + std::unordered_set set; + Uri u1(L"https://one.com"); + Uri u2(L"https://two.com"); + set.insert(u1); + set.insert(u2); + set.insert(u1); // duplicate + REQUIRE(set.size() == 2); +} + +TEST_CASE("module_hash_guid") +{ + std::unordered_set set; + guid g1{ 0x01020304, 0x0506, 0x0708, { 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 } }; + guid g2{ 0x11121314, 0x1516, 0x1718, { 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20 } }; + set.insert(g1); + set.insert(g2); + set.insert(g1); // duplicate + REQUIRE(set.size() == 2); +} + +TEST_CASE("module_hash_map_with_hstring_key") +{ + std::unordered_map map; + map[L"one"] = 1; + map[L"two"] = 2; + map[L"three"] = 3; + REQUIRE(map.size() == 3); + REQUIRE(map[L"two"] == 2); +} diff --git a/test/test_cpp20_module/main.cpp b/test/test_cpp20_module/main.cpp new file mode 100644 index 000000000..415e26f0f --- /dev/null +++ b/test/test_cpp20_module/main.cpp @@ -0,0 +1,24 @@ +#include +#define CATCH_CONFIG_RUNNER +#define CATCH_CONFIG_WINDOWS_SEH +#include "catch.hpp" + +import winrt_base; + +using namespace winrt; + +int main(int const argc, char** argv) +{ + init_apartment(); + std::set_terminate([] { reportFatal("Abnormal termination"); ExitProcess(1); }); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); + return Catch::Session().run(argc, argv); +} + +CATCH_TRANSLATE_EXCEPTION(hresult_error const& e) +{ + return to_string(e.message()); +} diff --git a/test/test_cpp20_module/natvis.cpp b/test/test_cpp20_module/natvis.cpp new file mode 100644 index 000000000..470654d07 --- /dev/null +++ b/test/test_cpp20_module/natvis.cpp @@ -0,0 +1,58 @@ +#include "pch.h" +#include + +import std; +import winrt.Windows.Foundation; + +// +// These tests confirm that the natvis infrastructure (winrt::impl::natvis) +// is reachable through modules, ensuring the debugger visualizer can function. +// natvis is only active in _DEBUG builds. +// + +using namespace winrt; +using namespace Windows::Foundation; + +#ifdef _DEBUG + +TEST_CASE("module_natvis_get_val") +{ + // Verify impl::natvis::get_val is callable through the module. + Uri uri(L"http://example.com/"); + IInspectable inspectable = uri; + + // IStringable IID: {96369F54-8EB6-48F0-ABCE-C1B211E627C3} + // Method index 0 = ToString + auto result = impl::natvis::get_val(&inspectable, L"{96369F54-8EB6-48F0-ABCE-C1B211E627C3}", 0); + + // Compare the natvis result with the direct call + hstring expected = uri.ToString(); + uint32_t expected_len = 0; + auto expected_buf = WindowsGetStringRawBuffer(static_cast(get_abi(expected)), &expected_len); + uint32_t actual_len = 0; + auto actual_buf = WindowsGetStringRawBuffer(static_cast(result.s), &actual_len); + REQUIRE(expected_len == actual_len); + REQUIRE(memcmp(expected_buf, actual_buf, expected_len * sizeof(wchar_t)) == 0); +} + +TEST_CASE("module_natvis_uri_properties") +{ + Uri uri(L"http://moderncpp.com/path"); + IInspectable inspectable = uri; + + // IUriRuntimeClass IID: {9E365E57-48B2-4160-956F-C7385120BBFC} + // Method 5 = Host, Method 7 = Path, Method 11 = SchemeName + auto host_val = impl::natvis::get_val(&inspectable, L"{9E365E57-48B2-4160-956F-C7385120BBFC}", 5); + hstring host_expected = uri.Host(); + REQUIRE(host_expected == hstring{ WindowsGetStringRawBuffer(static_cast(host_val.s), nullptr) }); + + auto path_val = impl::natvis::get_val(&inspectable, L"{9E365E57-48B2-4160-956F-C7385120BBFC}", 7); + hstring path_expected = uri.Path(); + REQUIRE(path_expected == hstring{ WindowsGetStringRawBuffer(static_cast(path_val.s), nullptr) }); + + auto scheme_val = impl::natvis::get_val(&inspectable, L"{9E365E57-48B2-4160-956F-C7385120BBFC}", 11); + hstring scheme_expected = uri.SchemeName(); + REQUIRE(scheme_expected == hstring{ WindowsGetStringRawBuffer(static_cast(scheme_val.s), nullptr) }); +} + +#endif // _DEBUG diff --git a/test/test_cpp20_module/numerics.cpp b/test/test_cpp20_module/numerics.cpp new file mode 100644 index 000000000..0f7dcc7fb --- /dev/null +++ b/test/test_cpp20_module/numerics.cpp @@ -0,0 +1,129 @@ +#include "pch.h" + +#if __has_include() + +import std; +import winrt.Windows.Foundation; +import winrt.Windows.Foundation.Numerics; + +// +// These tests exercise the SDK numerics types (float2, float3, etc.) from +// . These are exported by winrt_numerics and +// transitively available from winrt_base (and thus any namespace module). +// The Point/Size ↔ float2 conversions and name_v/category specializations +// are compiled in winrt_base. +// + +using namespace winrt; +using namespace winrt::Windows::Foundation; +using namespace winrt::Windows::Foundation::Numerics; + +// --- SDK math types (from winrt_numerics, re-exported via winrt_base) --- + +TEST_CASE("module_numerics_float2") +{ + float2 a{ 1.0f, 2.0f }; + float2 b{ 3.0f, 4.0f }; + + auto c = a + b; + REQUIRE(c.x == 4.0f); + REQUIRE(c.y == 6.0f); + + REQUIRE(length(a) > 0.0f); +} + +TEST_CASE("module_numerics_float3") +{ + float3 v{ 1.0f, 0.0f, 0.0f }; + float3 up{ 0.0f, 1.0f, 0.0f }; + + REQUIRE(dot(v, up) == 0.0f); + REQUIRE(cross(v, up).z != 0.0f); +} + +TEST_CASE("module_numerics_float4x4") +{ + auto identity = float4x4::identity(); + REQUIRE(identity.m11 == 1.0f); + REQUIRE(identity.m12 == 0.0f); + + auto t = make_float4x4_translation({ 10.0f, 20.0f, 30.0f }); + REQUIRE(t.m41 == 10.0f); +} + +TEST_CASE("module_numerics_quaternion") +{ + auto identity = quaternion::identity(); + REQUIRE(identity.w == 1.0f); + REQUIRE(length(identity) == 1.0f); +} + +// --- Point/Size ↔ float2 conversions (compiled in winrt_base) --- + +TEST_CASE("module_numerics_point_from_float2") +{ + Point p(float2{ 3.0f, 7.0f }); + REQUIRE(p.X == 3.0f); + REQUIRE(p.Y == 7.0f); +} + +TEST_CASE("module_numerics_point_to_float2") +{ + float2 v = Point{ 10.0f, 20.0f }; + REQUIRE(v.x == 10.0f); + REQUIRE(v.y == 20.0f); +} + +TEST_CASE("module_numerics_size_from_float2") +{ + Size s(float2{ 100.0f, 200.0f }); + REQUIRE(s.Width == 100.0f); + REQUIRE(s.Height == 200.0f); +} + +TEST_CASE("module_numerics_size_to_float2") +{ + float2 v = Size{ 640.0f, 480.0f }; + REQUIRE(v.x == 640.0f); + REQUIRE(v.y == 480.0f); +} + +// --- WinRT projection metadata (name_v/category, compiled in winrt_base) --- +// Verify that the projection machinery produces correct IReference GUIDs +// for numerics types. This exercises name_v, category, and the SHA-1 based +// GUID computation across module boundaries, at compile time. + +namespace +{ + constexpr bool equal(guid const& left, guid const& right) noexcept + { + return left.Data1 == right.Data1 && + left.Data2 == right.Data2 && + left.Data3 == right.Data3 && + left.Data4[0] == right.Data4[0] && + left.Data4[1] == right.Data4[1] && + left.Data4[2] == right.Data4[2] && + left.Data4[3] == right.Data4[3] && + left.Data4[4] == right.Data4[4] && + left.Data4[5] == right.Data4[5] && + left.Data4[6] == right.Data4[6] && + left.Data4[7] == right.Data4[7]; + } +} + +#define REQUIRE_EQUAL_GUID(left, ...) STATIC_REQUIRE(equal(guid(left), guid_of<__VA_ARGS__>())); + +TEST_CASE("module_numerics_ireference_guids") +{ + REQUIRE_EQUAL_GUID("48F6A69E-8465-57AE-9400-9764087F65AD", IReference); + REQUIRE_EQUAL_GUID("1EE770FF-C954-59CA-A754-6199A9BE282C", IReference); + REQUIRE_EQUAL_GUID("A5E843C9-ED20-5339-8F8D-9FE404CF3654", IReference); + REQUIRE_EQUAL_GUID("76358CFD-2CBD-525B-A49E-90EE18247B71", IReference); + REQUIRE_EQUAL_GUID("DACBFFDC-68EF-5FD0-B657-782D0AC9807E", IReference); + REQUIRE_EQUAL_GUID("B27004BB-C014-5DCE-9A21-799C5A3C1461", IReference); + REQUIRE_EQUAL_GUID("46D542A1-52F7-58E7-ACFC-9A6D364DA022", IReference); +} + +#undef REQUIRE_EQUAL_GUID + +#endif // __has_include() diff --git a/test/test_cpp20_module/pch.cpp b/test/test_cpp20_module/pch.cpp new file mode 100644 index 000000000..1d9f38c57 --- /dev/null +++ b/test/test_cpp20_module/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/test/test_cpp20_module/pch.h b/test/test_cpp20_module/pch.h new file mode 100644 index 000000000..d0eb301ac --- /dev/null +++ b/test/test_cpp20_module/pch.h @@ -0,0 +1,3 @@ +#pragma once + +#include "catch.hpp" diff --git a/test/test_cpp20_module/range_for.cpp b/test/test_cpp20_module/range_for.cpp new file mode 100644 index 000000000..962c97179 --- /dev/null +++ b/test/test_cpp20_module/range_for.cpp @@ -0,0 +1,135 @@ +#include "pch.h" + +import std; +import winrt.Windows.Foundation.Collections; + +// +// These tests confirm that C++/WinRT collections support range-based for loop iteration +// and structured bindings when consumed via modules. +// + +using namespace winrt; +using namespace Windows::Foundation::Collections; + +TEST_CASE("module_range_for_IIterable") +{ + IIterable c = single_threaded_vector({ 1, 2, 3 }); + std::vector result; + + for (int i : c) + { + result.push_back(i); + } + + REQUIRE(result.size() == 3); + REQUIRE(result[0] == 1); + REQUIRE(result[1] == 2); + REQUIRE(result[2] == 3); +} + +TEST_CASE("module_range_for_IVector") +{ + IVector c = single_threaded_vector({ 1, 2, 3 }); + std::vector result; + + for (int i : c) + { + result.push_back(i); + } + + REQUIRE(result.size() == 3); + REQUIRE(result[0] == 1); + REQUIRE(result[1] == 2); + REQUIRE(result[2] == 3); +} + +TEST_CASE("module_range_for_IVectorView") +{ + IVectorView c = single_threaded_vector({ 1, 2, 3 }).GetView(); + std::vector result; + + for (int i : c) + { + result.push_back(i); + } + + REQUIRE(result.size() == 3); + REQUIRE(result[0] == 1); + REQUIRE(result[1] == 2); + REQUIRE(result[2] == 3); +} + +TEST_CASE("module_structured_bindings_IKeyValuePair") +{ + std::map values + { + { 1, L"one"}, + { 2, L"two"}, + { 3, L"three"}, + }; + + IIterable> c = single_threaded_map(std::map(values)); + std::map result; + + for (IKeyValuePair i : c) + { + result[i.Key()] = i.Value(); + + // Structured binding on IKeyValuePair + auto const [key, value] = i; + REQUIRE(key == i.Key()); + REQUIRE(value == i.Value()); + } + + REQUIRE(result == values); + + // Range-for with structured bindings + result.clear(); + + for (auto&& [key, value] : c) + { + result[key] = value; + } + + REQUIRE(result == values); +} + +TEST_CASE("module_range_for_IMap") +{ + std::map values + { + { 1, L"one" }, + { 2, L"two" }, + { 3, L"three" }, + }; + + IMap c = single_threaded_map(std::map(values)); + std::map result; + + for (auto&& [key, value] : c) + { + result[key] = value; + } + + REQUIRE(result == values); +} + +TEST_CASE("module_range_for_IMapView") +{ + std::map values + { + { 1, L"one" }, + { 2, L"two" }, + { 3, L"three" }, + }; + + IMapView c = single_threaded_map(std::map(values)).GetView(); + std::map result; + + for (auto&& [key, value] : c) + { + result[key] = value; + } + + REQUIRE(result == values); +} diff --git a/test/test_cpp20_module/source_location.cpp b/test/test_cpp20_module/source_location.cpp new file mode 100644 index 000000000..ebf5139c3 --- /dev/null +++ b/test/test_cpp20_module/source_location.cpp @@ -0,0 +1,13 @@ +#include "pch.h" + +import std; +import winrt.Windows.Foundation; + +TEST_CASE("module_source_location") +{ + // Verify that slim_source_location works across the module boundary + auto loc = winrt::impl::slim_source_location::current(); + REQUIRE(loc.line() > 0); + std::string_view file(loc.file_name()); + REQUIRE(file.find("source_location.cpp") != std::string_view::npos); +} diff --git a/test/test_cpp20_module/test_cpp20_module.vcxproj b/test/test_cpp20_module/test_cpp20_module.vcxproj new file mode 100644 index 000000000..1e76c487b --- /dev/null +++ b/test/test_cpp20_module/test_cpp20_module.vcxproj @@ -0,0 +1,112 @@ + + + + + Debug + ARM64 + + + Debug + Win32 + + + Release + ARM64 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + 16.0 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72} + test_cpp20_module + test_cpp20_module + 10.0 + v145 + + + + Application + v145 + + + true + + + false + true + + + + + + + + + $(IntDir)Generated Files\ + + + + Use + pch.h + stdcpplatest + $(CppWinRTGenDir);..\;%(AdditionalIncludeDirectories) + NOMINMAX;%(PreprocessorDefinitions) + Level4 + true + 5311 + /bigobj + true + true + + + Console + ole32.lib;windowsapp.lib;%(AdditionalDependencies) + + + "$(CppWinRTDir)cppwinrt.exe" -in local -out "$(CppWinRTGenDir)." -modules -base -verbose -module_include "Windows.Foundation" -module_exclude "Windows.Foundation.Diagnostics" + + + + + + + CompileAsCppModule + true + NotUsing + + + + + + + + + Create + + + NotUsing + + + + + + + + + + + + + + \ No newline at end of file From c4cf531f6a8ec29c0e7eb19ed817043405ba9fa7 Mon Sep 17 00:00:00 2001 From: Mathias Berchtold Date: Mon, 1 Jun 2026 05:07:50 +0200 Subject: [PATCH 34/42] base_identity.h: added missing constexpr (#1589) Added missing constexpr to is_guid_of helper. guid_of is already constexpr: constexpr:https://github.com/microsoft/cppwinrt/blob/55f1b452aca069d6ac7eaad3e05cc1058fc39d27/strings/base_identity.h#L8 and find_iid_traits::test is constexpr and calls is_guid_of: https://github.com/microsoft/cppwinrt/blob/55f1b452aca069d6ac7eaad3e05cc1058fc39d27/strings/base_implements.h#L397 --- strings/base_identity.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strings/base_identity.h b/strings/base_identity.h index 7c61c83e2..4a5bedbb1 100644 --- a/strings/base_identity.h +++ b/strings/base_identity.h @@ -11,7 +11,7 @@ WINRT_EXPORT namespace winrt } template - bool is_guid_of(guid const& id) noexcept + constexpr bool is_guid_of(guid const& id) noexcept { return ((id == guid_of()) || ...); } From 478111fc4a4a74937508cf8915436ff2b97b3ca6 Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Tue, 23 Jun 2026 16:00:37 -0700 Subject: [PATCH 35/42] Stop exporting winrt::impl::get_marshaler to workaround MSVC modules bug (#1592) * Stop exporting winrt::impl::get_marshaler to workaround MSVC modules bug * Include base.h in marshal.cpp to verify that include-then-import still works --- strings/base_marshaler.h | 2 +- test/test_cpp20_module/marshal.cpp | 25 +++++++++++++++++++ .../test_cpp20_module.vcxproj | 4 ++- 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 test/test_cpp20_module/marshal.cpp diff --git a/strings/base_marshaler.h b/strings/base_marshaler.h index 9be6959c9..526f4d4c3 100644 --- a/strings/base_marshaler.h +++ b/strings/base_marshaler.h @@ -1,5 +1,5 @@ -WINRT_EXPORT namespace winrt::impl +namespace winrt::impl { inline std::int32_t make_marshaler(unknown_abi* outer, void** result) noexcept { diff --git a/test/test_cpp20_module/marshal.cpp b/test/test_cpp20_module/marshal.cpp new file mode 100644 index 000000000..d47f8c3cb --- /dev/null +++ b/test/test_cpp20_module/marshal.cpp @@ -0,0 +1,25 @@ +#include "pch.h" +#include +#include + +import std; +import winrt.Windows.Foundation.Collections; + +using namespace winrt; + +struct S : implements +{ + hstring ToString() + { + return L"S"; + } +}; + +// When winrt::impl::get_marshaler was being exported, an MSVC bug caused the marshaler +// object to have a null vtable, which caused a crash when calling any method on the marshaler. +// This test ensures that the marshaler vtable is properly initialized. +TEST_CASE("IMarshal") +{ + auto s = make(); + auto marshal = s.as(); +} diff --git a/test/test_cpp20_module/test_cpp20_module.vcxproj b/test/test_cpp20_module/test_cpp20_module.vcxproj index 1e76c487b..f5c20a35d 100644 --- a/test/test_cpp20_module/test_cpp20_module.vcxproj +++ b/test/test_cpp20_module/test_cpp20_module.vcxproj @@ -25,7 +25,8 @@ Release x64 - + + 16.0 {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72} test_cpp20_module @@ -91,6 +92,7 @@ + Create From b7eb2eacfd857c6334cd688306ab543ac4e96864 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Jun 2026 11:21:55 -0700 Subject: [PATCH 36/42] Migrate GitHub CI off VS 2022, add C++20 module test, dynamic v143/v145 toolset (#1601) * Migrate GitHub CI off VS 2022 (v143) to v145/VS 2026 * Add C++20 module test to CI; dynamic v143/v145 toolset selection --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- .github/instructions/cppwinrt.instructions.md | 2 +- .github/workflows/ci.yml | 26 +++++-------------- Directory.Build.Props | 3 +++ .../nuget/TestProxyStub/TestProxyStub.vcxproj | 1 - 4 files changed, 11 insertions(+), 21 deletions(-) diff --git a/.github/instructions/cppwinrt.instructions.md b/.github/instructions/cppwinrt.instructions.md index ba5d66212..eae2fc3c6 100644 --- a/.github/instructions/cppwinrt.instructions.md +++ b/.github/instructions/cppwinrt.instructions.md @@ -25,7 +25,7 @@ - Use VS Developer Shell for correct toolset environment - `cmake --build build --config Release --target cppwinrt` for cppwinrt.exe (or MSBuild: `msbuild cppwinrt\cppwinrt.vcxproj /p:Configuration=Release /p:Platform=x64`) - NuGet tests: `msbuild test\nuget\NuGetTest.sln /p:Configuration=Release /p:Platform=x64` -- Module test projects require v145 toolset (VS 2026). Directory.Build.Props sets v143 by default — override with `v145` in Configuration PropertyGroup +- Module test projects require v145 toolset (VS 2026). Directory.Build.Props selects v145 when VisualStudioVersion >= 18.0 (VS 2026) and falls back to v143 otherwise; override `` in the Configuration PropertyGroup to force a specific toolset ## Key Patterns diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c2a04353..37f42ab70 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,8 +15,6 @@ jobs: arch: [x86, x64, arm64] config: [Debug, Release] toolchain: - - image: windows-2025 - platform_toolset: v143 - image: windows-2025-vs2026 platform_toolset: v145 exclude: @@ -99,10 +97,8 @@ jobs: compiler: [MSVC, clang-cl] arch: [x86, x64, arm64] config: [Debug, Release] - test_exe: [test, test_nocoro, test_cpp20, test_cpp20_no_sourcelocation, test_fast, test_slow, test_old, test_module_lock_custom, test_module_lock_none] + test_exe: [test, test_nocoro, test_cpp20, test_cpp20_no_sourcelocation, test_cpp20_module, test_fast, test_slow, test_old, test_module_lock_custom, test_module_lock_none] toolchain: - - image: windows-2025 - platform_toolset: v143 - image: windows-2025-vs2026 platform_toolset: v145 exclude: @@ -112,6 +108,9 @@ jobs: arch: arm64 - compiler: clang-cl config: Release + # C++20 named modules require the MSVC v145 toolset; clang-cl is not supported. + - compiler: clang-cl + test_exe: test_cpp20_module runs-on: ${{ matrix.toolchain.image }} steps: - uses: actions/checkout@v6 @@ -295,7 +294,7 @@ jobs: arch: [x86, x64, arm64] config: [Release] Deployment: [Component, Standalone] - runs-on: windows-latest + runs-on: windows-2025-vs2026 steps: - uses: actions/checkout@v6 @@ -316,7 +315,7 @@ jobs: $target_configuration = "${{ matrix.config }}" $target_platform = "${{ matrix.arch }}" $target_version = "999.999.999.999" - Add-Content $env:GITHUB_ENV "msbuild_config_props=/p:Configuration=$target_configuration,Platform=$target_platform,CppWinRTBuildVersion=$target_version" + Add-Content $env:GITHUB_ENV "msbuild_config_props=/p:Configuration=$target_configuration,Platform=$target_platform,CppWinRTBuildVersion=$target_version,PlatformToolset=v145" - name: Restore nuget packages run: | @@ -336,8 +335,6 @@ jobs: arch: [x86, x64] config: [Release] toolchain: - - image: windows-2025 - platform_toolset: v143 - image: windows-2025-vs2026 platform_toolset: v145 runs-on: ${{ matrix.toolchain.image }} @@ -378,15 +375,6 @@ jobs: $target_configuration = "${{ matrix.config }}" $target_platform = "${{ matrix.arch }}" & "_build\$target_platform\$target_configuration\cppwinrt.exe" -in local -out _build\$target_platform\$target_configuration -verbose - - - name: Remove module test projects on v143 - if: matrix.toolchain.platform_toolset == 'v143' - run: | - # Module test projects require v145 toolset - mv test\nuget\NugetTest.sln test\nuget\NugetTest.sln.orig - Get-Content test\nuget\NugetTest.sln.orig | - Where-Object { -not ($_ -match 'TestModule') } | - Set-Content test\nuget\NugetTest.sln - name: Run nuget test run: | @@ -394,7 +382,7 @@ jobs: build-nuget: name: Build nuget package with MSVC - runs-on: windows-latest + runs-on: windows-2025-vs2026 steps: - uses: actions/checkout@v6 diff --git a/Directory.Build.Props b/Directory.Build.Props index c98cd5dd0..5972803c0 100644 --- a/Directory.Build.Props +++ b/Directory.Build.Props @@ -3,7 +3,10 @@ + v143 + v145 10.0 10.0.18362.0 diff --git a/test/nuget/TestProxyStub/TestProxyStub.vcxproj b/test/nuget/TestProxyStub/TestProxyStub.vcxproj index 69e41cfba..cd646da7f 100644 --- a/test/nuget/TestProxyStub/TestProxyStub.vcxproj +++ b/test/nuget/TestProxyStub/TestProxyStub.vcxproj @@ -40,7 +40,6 @@ DynamicLibrary - v143 Unicode From 5bf26503d49a7454442a8a569ae9e00d043c583e Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Wed, 24 Jun 2026 11:34:23 -0700 Subject: [PATCH 37/42] Massive speedup to file_equal and file_to_string (#1584) * Massive speedup to file_equal and file_to_string * Properly cast the result of tellg() and handle filesystem errors more gracefully. --- cppwinrt/text_writer.h | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/cppwinrt/text_writer.h b/cppwinrt/text_writer.h index a274d11ce..c6fc380b3 100644 --- a/cppwinrt/text_writer.h +++ b/cppwinrt/text_writer.h @@ -13,8 +13,26 @@ namespace cppwinrt { inline std::string file_to_string(std::string const& filename) { - std::ifstream file(filename, std::ios::binary); - return static_cast(std::stringstream() << file.rdbuf()).str(); + std::ifstream file(filename, std::ios::binary | std::ios::ate); + if (!file) { return{}; } + + const auto stream_size = file.tellg(); + if (stream_size == std::ifstream::pos_type(-1)) + { + return {}; + } + + file.seekg(0); + + auto size = static_cast(stream_size); + std::string result(size, '\0'); + file.read(result.data(), size); + if (!file) + { + result.resize(static_cast(file.gcount())); + } + + return result; } template @@ -218,18 +236,15 @@ namespace cppwinrt bool file_equal(std::string const& filename) const { - if (!std::filesystem::exists(filename)) + // Non-throwing file_size returns uintmax_t(-1) on errors, which shouldn't ever be the size of m_first or m_second + std::error_code ec; + if (std::filesystem::file_size(filename, ec) != m_first.size() + m_second.size()) { return false; } auto file = file_to_string(filename); - if (file.size() != m_first.size() + m_second.size()) - { - return false; - } - if (!std::equal(m_first.begin(), m_first.end(), file.begin(), file.begin() + m_first.size())) { return false; From 77b1e4e02057e4cfff1ce850e40024e9fbc0f7fb Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Wed, 24 Jun 2026 11:45:53 -0700 Subject: [PATCH 38/42] Improve module docs, ship them in the nuget, and add missing properties to Visual Studio proejct properties page (#1586) --- nuget/CppWinrtRules.Project.xml | 21 ++ nuget/Microsoft.Windows.CppWinRT.nuspec | 3 + nuget/modules.md | 415 ++++++++++++++++++++++-- nuget/readme.md | 4 +- nuget/readme.txt | 3 + 5 files changed, 410 insertions(+), 36 deletions(-) diff --git a/nuget/CppWinrtRules.Project.xml b/nuget/CppWinrtRules.Project.xml index 73f32c6d3..43a712d21 100644 --- a/nuget/CppWinrtRules.Project.xml +++ b/nuget/CppWinrtRules.Project.xml @@ -3,6 +3,7 @@ + @@ -86,4 +87,24 @@ Description="Enables the /await:strict compiler option" Category="General" /> + + + + + + + + diff --git a/nuget/Microsoft.Windows.CppWinRT.nuspec b/nuget/Microsoft.Windows.CppWinRT.nuspec index a63e08bf9..52151fc08 100644 --- a/nuget/Microsoft.Windows.CppWinRT.nuspec +++ b/nuget/Microsoft.Windows.CppWinRT.nuspec @@ -12,6 +12,7 @@ native C++ WinRT nativepackage © Microsoft Corporation. All rights reserved. LICENSE + readme.md https://github.com/Microsoft/cppwinrt https://aka.ms/cppwinrt.ico @@ -25,5 +26,7 @@ + + diff --git a/nuget/modules.md b/nuget/modules.md index 479781252..4f0eebb95 100644 --- a/nuget/modules.md +++ b/nuget/modules.md @@ -14,11 +14,41 @@ instead of: #include ``` -Modules provide faster builds through pre-compiled module interfaces (IFCs) and better isolation of macro and declaration scopes. +Benefits include: + +- **Smaller intermediate artifacts.** The IFC representation of a C++/WinRT projection is significantly smaller than the equivalent precompiled header (PCH). +- **Shared compilation across projects.** PCHs eliminate redundant parsing *within* a project, but each project rebuilds its own PCH. Module IFCs can be built once in a shared module builder project and consumed by all dependent projects, eliminating redundant work across the entire solution. +- **Better isolation.** Module imports don't leak macros into the importing translation unit. + +> **Real-world experience:** The guidance in this document was hardened against a prototype conversion of the Windows Terminal codebase (~250 files across 15+ projects) from textual `#include`s to module imports. + +## Prerequisites + +- **MSVC v145 toolset** (Visual Studio 2026) or later with C++20 module support +- **C++/WinRT 3.x** NuGet package with `CppWinRTBuildModule` support +- `/std:c++20` or later (`/std:c++latest` recommended for `import std;`) +- `BuildStlModules=true` for `import std;` support + +## Three Fundamental Constraints + +These three rules drive almost every pattern in this guide. Understanding them up front makes the rest of the document much easier to follow: + +1. **`import` in a PCH breaks the compiler.** MSVC cannot handle module `import` declarations inside a precompiled header — it produces internal compiler errors (ICE). All module imports must live outside the PCH. + +2. **Include-then-import is safe, but has a cost.** MSVC handles the case where you `#include` a header and then `import` the same content. For STL headers this is a reasonable workaround (the compilation cost is modest), but C++/WinRT projection headers can be extremely expensive to parse textually. Include-then-import with winrt headers defeats the build-cost improvements of adopting modules, so it should be avoided where possible. + +3. **Import-then-include is not supported.** When a module has already been imported, `#include`-ing a header that declares the same types causes errors — the compiler sees conflicting declarations. C++/WinRT provides a workaround: defining `WINRT_IMPORT_MODULE` before including a winrt header causes the header to be (mostly) a no-op, defining only its include-guard macro. This makes it safe to include winrt headers *after* importing modules, which is essential for lighting up header-guard-based features in libraries like WIL, and for interoperating with external code that includes winrt headers out of your control (e.g. the XAML compiler). STL headers do not have an equivalent workaround, but can fall back on the "generally safe" include-then-import pattern. + +The patterns throughout this guide are direct consequences of these constraints: + +- The PCH is stripped of all winrt content. +- A separate "module preamble" header centralizes imports. +- Wrapper headers define `WINRT_IMPORT_MODULE` before including winrt headers. +- STL headers are sometimes pre-included in the PCH, but only as a workaround. ## Quick Start — Single Project -For a project that builds and consumes its own modules: +For a small project that builds and consumes its own modules: 1. Set `CppWinRTBuildModule` to `true` in your project: ```xml @@ -34,6 +64,8 @@ For a project that builds and consumes its own modules: ``` + By default, C++/WinRT generates and builds `.ixx` files for **every** namespace reachable from your WinMD inputs — for a typical Windows SDK projection, that's hundreds of namespaces and can add upwards of a minute to your build. If build speed matters, prune the set with `CppWinRTModuleInclude` (or `CppWinRTModuleExclude`) so that only the namespaces you actually `import` are produced. See [Understanding the Include and Exclude Filters](#understanding-the-include-and-exclude-filters) for the full discussion. + 3. Enable `BuildStlModules` for `import std;` support: ```xml @@ -51,25 +83,40 @@ For a project that builds and consumes its own modules: } ``` -## Quick Start — Multi-Project (Recommended) +For a single vcxproj — or a handful of projects that don't share many namespaces — this is all you need. A dedicated module builder is only worth the overhead when multiple projects need the same platform and third-party WinRT modules. + +## Architecture — Module Builder (Recommended for Multi-Project Solutions) + +For solutions with multiple projects, the recommended approach is a dedicated **module builder** project that builds the shared IFC files once, consumed by all other projects. This avoids each project redundantly compiling the same module interfaces. -For larger solutions, compile platform modules once in a dedicated "builder" static library, and share the pre-built IFCs with other projects. +### The Module Builder Project -### Module Builder (static library) +Create a dedicated static library project whose sole purpose is to build the shared platform module IFC files. This project has no source files of its own — the C++/WinRT NuGet targets generate `.ixx` files automatically. ```xml StaticLibrary true - Windows.Foundation + true ``` -### Consumer (exe or dll) +Key configuration: + +- **`CppWinRTBuildModule=true`** generates per-namespace `.ixx` module interface files. +- **`BuildStlModules=true`** is required because the generated `.ixx` files use `import std;`. +- **`WINRT_ENABLE_LEGACY_COM`** — define this preprocessor macro if your project uses classic COM interfaces (`IUnknown`, `IInspectable`). It causes `` and `` to be included within the `winrt_base` module. +- **PCH**: don't bother. The module builder can use a PCH, but there is little benefit — its content is almost entirely C++/WinRT headers, and most non-C++/WinRT headers are only used once in `winrt_base`. + +### Consumer Project Configuration + +Each project that uses modules needs: ```xml true + MyCompany.MyComponent + Microsoft.UI;Microsoft.Web @@ -78,9 +125,25 @@ For larger solutions, compile platform modules once in a dedicated "builder" sta ``` -The `CppWinRTConsumeModule` metadata on the ProjectReference tells the build system to: -- Use the builder's pre-built platform IFCs instead of compiling platform `.ixx` files again -- Skip generating platform `.ixx` files in the consumer's own projection +- **`CppWinRTBuildModule=true`** is required on consumers too. It enables the C++/WinRT targets to generate `.ixx` module interface files for the project's own component namespaces (filtered by `CppWinRTModuleInclude` / `CppWinRTModuleExclude`) and wires up module consumption from referenced projects. +- **`CppWinRTConsumeModule=true`** on the `ProjectReference` tells the build system to use the builder's pre-built platform IFCs instead of compiling platform `.ixx` files again, and skip generating platform `.ixx` files in the consumer's own projection. + +### Adding Third-Party WinMDs to the Module Builder + +If your project uses third-party WinRT components (e.g., WinUI/MUX, WebView2), build their modules in the shared builder by adding their WinMDs as platform inputs: + +```xml + + + + + + +``` + +**Important:** Add these WinMDs as `CppWinRTPlatformWinMDReferences`, **not** as NuGet `` items. In practice, adding third-party WinMDs via NuGet `` items on the module builder has been observed to cause empty path errors in the reference projection step. Adding them directly as `CppWinRTPlatformWinMDReferences` feeds them into the platform projection, which is the correct pipeline for a module builder project. ### Component DLLs @@ -98,8 +161,6 @@ WinRT component projects can also use modules. Set `CppWinRTBuildModule=true` an ``` -### Consuming Components from Other Projects - If project A references a component DLL from project B, project A builds its own reference projection modules from B's `.winmd`: ```cpp @@ -113,19 +174,53 @@ auto obj = winrt::MyComponent::MyClass(); | Property | Default | Description | |-|-|-| -| `CppWinRTBuildModule` | false | Generate `.ixx` module interface units from projections | +| `CppWinRTBuildModule` | `false` | Generate `.ixx` module interface units from projections | | `CppWinRTModuleInclude` | (all) | Semicolon-delimited namespace prefixes to include in module generation | | `CppWinRTModuleExclude` | (none) | Semicolon-delimited namespace prefixes to exclude from module generation | -| ProjectReference Metadata | Default | Description | +| `ProjectReference` Metadata | Default | Description | |-|-|-| -| `CppWinRTConsumeModule` | false | Consume pre-built platform module IFCs from this project reference | +| `CppWinRTConsumeModule` | `false` | Consume pre-built platform module IFCs from this project reference | + +### Understanding the Include and Exclude Filters + +These filters control which C++/WinRT module `.ixx` files are generated from WinMD inputs. They only affect modules produced by the C++/WinRT NuGet targets from `.winmd` files — hand-authored modules or modules unrelated to WinRT are not affected. + +- **`CppWinRTModuleInclude`** — semicolon-separated namespace prefixes. Only matching namespaces will have `.ixx` files generated. Without this, *all* namespaces from the project's WinMD inputs are candidates. +- **`CppWinRTModuleExclude`** — semicolon-separated namespace prefixes to suppress `.ixx` generation for. **Import statements are still generated** in the modules that remain; only the `.ixx` file creation is suppressed. -## Module Filtering and Transitive Dependencies +#### Why Filter at All? + +There are three distinct reasons to set these filters. Most non-trivial projects will hit more than one: + +1. **Build performance.** By default, enabling `CppWinRTBuildModule=true` generates and compiles `.ixx` files for *every* namespace reachable from your WinMD inputs. For a typical Windows SDK projection that's hundreds of namespaces, and the IFC compilation step can easily add upwards of a minute to a clean build. Use `CppWinRTModuleInclude` to narrow generation to namespaces you (or your consumers) actually `import`, or `CppWinRTModuleExclude` to drop large subtrees you don't use (e.g., `Windows.Devices`, `Windows.Media`). For a dedicated module builder project that other projects consume, this is typically the dominant reason to filter. + +2. **Avoiding ambiguous IFC errors (C7684).** An IFC is ambiguous when the same module name resolves to two different `.ifc` files — typically one built locally and one from a referenced project. See [When to Set an Exclude for Ambiguity](#when-to-set-an-exclude-for-ambiguity) below. + +3. **Avoiding modules with unsatisfied dependencies.** Filtering to a subset of namespaces does *not* prune the `import` statements those modules emit for their dependencies — so a generated module whose dependencies fall outside your filter will fail to compile. See [Module Filtering and Transitive Dependencies](#module-filtering-and-transitive-dependencies) below. + +#### When to Set an Exclude for Ambiguity + +Exclude a namespace when its IFC is already provided by a project you reference: + +| Scenario | Action | +|----------|--------| +| You reference a **static library** with `CppWinRTBuildModule=true` | Exclude namespaces that static lib produces (its IFCs propagate via `AdditionalBMIDirectories`) | +| You reference a **DLL** with `CppWinRTBuildModule=true` | **No exclude needed** — DLL IFCs don't propagate by default | +| The **module builder** produces a namespace (e.g., `Microsoft.UI`) | Exclude it — the module builder's IFCs propagate via `CppWinRTConsumeModule` | + +Example — a project that references both the module builder (which provides `Microsoft.UI.*`) and a `TerminalCore` static library (which provides `Microsoft.Terminal.Core`): + +```xml +Microsoft.Terminal +Microsoft.Terminal.Core;Microsoft.UI;Microsoft.Web +``` + +### Module Filtering and Transitive Dependencies `CppWinRTModuleInclude` and `CppWinRTModuleExclude` control which namespace `.ixx` files are **generated**, but they do not suppress `import` statements for dependencies. If namespace A is included in the filter and depends on namespace B, the generated `winrt.A.ixx` will contain `import winrt.B;` even if B is excluded from the filter. This is by design — the module for B must exist *somewhere* (either from the same project or from a referenced project). -This has important implications: +Implications: - **Transitive closure must be satisfied.** If you filter to a subset of namespaces, any dependencies that fall outside the filter must be available from another source (e.g., a module builder project referenced via `CppWinRTConsumeModule`, or MSBuild's automatic `ReferencedModuleBMIs` from a static library reference). Otherwise, compilation will fail with "could not find module" errors. @@ -141,39 +236,289 @@ This has important implications: | `winrt_numerics` | `Windows::Foundation::Numerics` types — re-exported by `winrt_base` | | `winrt.` | Per-namespace projection (e.g., `winrt.Windows.Foundation`) | -## Requirements +## Converting an Existing Project: Step by Step -- MSVC v145 toolset (Visual Studio 2026) or later recommended -- C++20 or later (`/std:c++20` or newer) -- `BuildStlModules=true` for `import std;` support +### 1. Strip winrt from the PCH -## Limitations +Module `import` declarations inside a precompiled header cause compiler ICEs. All C++/WinRT content must be moved out of the PCH and into the module preamble header (see next step). -- Module IFCs are not compatible across toolset versions. All projects must use the same toolset. -- Cyclic namespace dependencies (e.g., `Windows.Foundation` ↔ `Windows.Foundation.Collections`) are handled automatically via SCC consolidation, but the resulting module name is chosen alphabetically. Adding new APIs could change SCC groupings. +Remove the following from your PCH: + +- `#include ` — all winrt projection headers +- `#include ` and `` +- Any header that depends on C++/WinRT types, **including headers that conditionally enable behavior based on C++/WinRT header guards.** For example, `wil/cppwinrt_helpers.h` checks for `WINRT_Windows_UI_Core_H` and uses types from `Windows.UI.Core` when defined — this header must move out of the PCH. + +**Keep** in the PCH: + +- Platform SDK headers (``, ``, etc.) +- Non-winrt third-party headers + +**STL headers and `import std;`** — STL headers are safe to include *before* `import std;` (include-then-import works). Problems arise when STL headers are included *after* `import std;`, which can cause redefinition warnings (C4348, C5028). In most cases it is preferable to use `import std;` instead of putting STL headers in the PCH. However, if you depend on libraries that internally `#include` STL headers *after* modules have been imported, you may need to pre-include the offending STL headers in the PCH to make the later inclusion inert: + +```cpp +// Pre-include STL headers that other libraries include after import std; +#include +#include +``` + +Ideally, the offending library code would also adopt `import std;`, but that's not always immediately practical. + +### 2. Create a Module Preamble Header + +A module preamble header centralizes the module imports and library setup that are shared across a project's source files. It is not strictly required — you could add imports directly to each `.cpp` file — but it speeds up migration significantly and becomes necessary if you need to deal with generated files outside your control (see [XAML Projects](#xaml-projects)). + +Create a preamble header in each project that contains the module imports commonly used across that project: + +```cpp +// ModulePreamble.h (or whatever name you prefer) +#pragma once + +#define WINRT_IMPORT_MODULE + +// Import the C++/WinRT namespaces used across this project +import winrt.Windows.Foundation; +import winrt.Windows.Foundation.Collections; +import winrt.Windows.System; +// ... other namespaces your project needs + +// Component modules +import winrt.MyCompany.MyComponent; +``` + +Importing modules is cheap, so don't hesitate to list every namespace the project uses. You can add library wrapper headers and other setup to this file as needed (see next section). + +Include the preamble in each `.cpp` file after the PCH: + +```cpp +#include "pch.h" +#include "ModulePreamble.h" +// ... rest of the file +``` + +### 3. Wrap Library Headers That Depend on C++/WinRT Types + +Libraries like WIL use `#ifdef WINRT_Windows_Foundation_H` guards to conditionally enable winrt-dependent features. With modules, those header guards are never defined because the winrt headers are never textually included. To light up this behavior, define the appropriate header guards before including the library header — or, equivalently, include the now-inert winrt headers under `WINRT_IMPORT_MODULE`, which defines the guards as a side effect. + +You can do this directly in the module preamble: + +```cpp +// In your module preamble header +import winrt.Windows.Foundation; +#define WINRT_IMPORT_MODULE +#define WINRT_Windows_Foundation_H // Lights up WIL's Foundation support +#include +``` + +If you include the library from many places, you can author a **wrapper header** that bundles the imports, guard definitions, and library include together: + +```cpp +// wil_cppwinrt_module.h +#pragma once + +import winrt_base; +import winrt.Windows.Foundation; +import winrt.Windows.Foundation.Collections; + +#define WINRT_IMPORT_MODULE +// Define header guards to light up WIL's conditional winrt features. +// You can either define the guards directly, or include the now-inert +// winrt headers (which define the guards as a side effect): +#include +#include + +#include +#include +``` + +Include this wrapper in your module preamble as needed. Re-importing modules and re-defining header guards is harmless, so there's no issue with including the wrapper from multiple places. + +This pattern applies to any library that conditionally uses winrt types based on header include guards. + +### 4. Update the vcxproj + +```xml + +true +MyCompany.MyComponent +Microsoft.UI;Microsoft.Web + + + + true + +``` + +### 5. Add Solution Build Dependency + +If using `.slnx` or `.sln`, add a build dependency to ensure the module builder, if using, compiles first: + +```xml + +``` + +## Special Cases + +### XAML Projects + +XAML projects have a two-pass compilation model that complicates module adoption. The XAML compiler generates source files (`XamlTypeInfo.g.cpp`, `XamlTypeInfo.Impl.g.cpp`, `XamlMetaDataProvider.cpp`) that use winrt types but don't know about modules. + +The solution is to inject `ModulePreamble.h` via the `/FI` (forced include) compiler flag on these generated files, using MSBuild targets: + +```xml + + + + + NotUsing + $(MSBuildProjectDirectory)\ModulePreamble.h + + + +``` + +For static library projects, the XAML build system has a second compilation pass (`CompileXamlGeneratedFiles`) that runs after `ClCompile` but before `Lib`. For DLLs and EXEs, the same targets run after the build compile phase. In either case, you need a second target to ensure the `/FI` metadata is applied before `CompileXamlGeneratedFiles`: + +```xml + + + + NotUsing + $(MSBuildProjectDirectory)\ModulePreamble.h + + + +``` + +**Critical MSBuild detail:** Use ``, not just ``. Without `Update`, MSBuild adds new items instead of modifying metadata on existing ones. + +**Why the preamble header needs `#include "pch.h"` for XAML:** When used as `/FI`, the preamble header is processed *before* the generated file's own `#include "pch.h"`. Adding `#include "pch.h"` at the top of the preamble ensures platform headers are available. For regular `.cpp` files that already include pch.h before the preamble, it's a `#pragma once` no-op. If your project doesn't use the `/FI` approach for XAML, you don't need pch.h in the preamble. + +#### Understanding the XAML Build Order + +The XAML build targets schedule `MarkupCompilePass2` and `CompileXamlGeneratedFiles` differently depending on project type: + +- **Static libraries** (`AfterClCompileTargets`): Pass2 runs after `ClCompile`, before `Lib` +- **DLLs/EXEs** (`AfterBuildCompileTargets`): Pass2 runs after the build compile phase, before `Link` + +In both cases, the order is: + +1. **MarkupCompilePass1** (before `ClCompile`): Generates `.xaml.g.h` declarations +2. **ClCompile**: Compiles your source files +3. **MarkupCompilePass2**: Generates `.xaml.g.hpp` implementations +4. **CompileXamlGeneratedFiles**: Compiles `XamlTypeInfo.g.cpp` (which `#include`s the `.xaml.g.hpp` files) + +The XAML-generated items (`XamlTypeInfo.g.cpp`, etc.) are added to `ClCompile` by the `ComputeXamlGeneratedCompileInputs` target, which is why the `/FI` target uses `AfterTargets="ComputeXamlGeneratedCompileInputs"`. + +### Headers with Conditional winrt Conversions + +If you have utility types (like a `color` struct) with conversion operators gated behind winrt header guards: + +```cpp +#ifdef WINRT_Windows_UI_H + operator winrt::Windows::UI::Color() const { ... } +#endif +``` + +These guards must be defined **before** the header is first included (`#pragma once` means it won't be processed again). Create a dedicated wrapper that imports the module, sets the guard, then re-includes the header: + +```cpp +// color_module.h +#pragma once +import winrt.Windows.UI; +#define WINRT_IMPORT_MODULE +#include // Sets WINRT_Windows_UI_H +#include // Now sees the guard, enables converters +``` + +Include this wrapper in your `ModulePreamble.h` **before** any other header that might include the guarded file. + +### Win32 Macro Conflicts + +Some Win32 macros (e.g., `GetObject` from `wingdi.h`) conflict with WinRT method names. With headers, the macro was applied to both the projection types and the call site. With modules, the WinRT types don't have the macro applied (they were compiled in the module without the macro), but your source file still has the macro defined. Use: + +```cpp +#pragma push_macro("GetObject") +#undef GetObject +// ... code using winrt types with GetObject method +#pragma pop_macro("GetObject") +``` ## Caution: Module Reuse Across Projects Pre-built IFCs (via `CppWinRTConsumeModule`) should only be shared when the builder and consumer use the same compilation context. In particular: -- **Component modules are project-private.** A component projection built with `CppWinRTOptimized=true` generates modules that bypass activation factories for in-component type instantiation (`-opt`). If a consuming project accidentally imports these modules instead of building its own reference projection, the consumer will attempt direct instantiation across DLL boundaries, resulting in linker errors or incorrect behavior. Each project should build its own modules from the component's `.winmd` — do not tag component ProjectReferences with `CppWinRTConsumeModule`. +- **Component modules are project-private.** A component projection built with `CppWinRTOptimized=true` generates modules that bypass activation factories for in-component type instantiation (`-opt`). If a consuming project accidentally imports these modules instead of building its own reference projection, the consumer will attempt direct instantiation across DLL boundaries, resulting in linker errors or incorrect behavior. Each project should build its own modules from the component's `.winmd` — do not tag component `ProjectReference`s with `CppWinRTConsumeModule`. -- **`CppWinRTConsumeModule` is intended for platform module builders only.** The builder project is a dedicated static library whose sole purpose is compiling platform SDK modules. Its compilation flags (no `-opt`, no `-comp`) produce modules safe for any consumer. Only tag this builder's ProjectReference with `CppWinRTConsumeModule=true`. +- **`CppWinRTConsumeModule` is intended for platform module builders only.** The builder project is a dedicated static library whose sole purpose is compiling platform SDK modules. Its compilation flags (no `-opt`, no `-comp`) produce modules safe for any consumer. Only tag this builder's `ProjectReference` with `CppWinRTConsumeModule=true`. - **Module filter scope matters.** `CppWinRTModuleInclude` / `CppWinRTModuleExclude` applies to all three projections (platform, reference, component). If you set `CppWinRTModuleInclude=MyComponent`, only `MyComponent` namespaces will get `.ixx` files — platform and reference namespace modules will not be generated. Make sure your filter includes all namespaces you intend to import as modules, or use `CppWinRTConsumeModule` to get platform modules from a builder that was configured with the appropriate filter. - **Compilation settings must be compatible between builder and consumer.** Module IFCs encode assumptions about the compilation environment. While the compiler may not always diagnose mismatches, the following differences between the module builder and consumer may cause subtle or hard-to-diagnose issues: - - **Debug vs Release** — Mixing Debug and Release configurations can produce mismatched code generation, iterator debugging levels, and runtime library selections. - - **Preprocessor definitions** — Definitions that affect type layout, conditional compilation, or feature flags should match between builder and consumer. - - **Struct alignment / packing** — Different `/Zp` settings between projects can change struct layout, causing silent ABI mismatches. - - **Language standard** — While C++20 and later are generally compatible, mixing `/std:c++20` and `/std:c++23` and/or `/std:c++latest` if there are language features that affect type definitions. + - **Debug vs Release** — mixing Debug and Release configurations can produce mismatched code generation, iterator debugging levels, and runtime library selections. + - **Preprocessor definitions** — definitions that affect type layout, conditional compilation, or feature flags should match between builder and consumer. + - **Struct alignment / packing** — different `/Zp` settings between projects can change struct layout, causing silent ABI mismatches. + - **Language standard** — while C++20 and later are generally compatible, mixing `/std:c++20` and `/std:c++23` and/or `/std:c++latest` can affect type definitions if language features differ. + + As a general rule, the module builder project should try to use the same configuration, preprocessor definitions, and compiler options as its consumers. + +## Limitations + +- Module IFCs are not compatible across toolset versions. All projects must use the same toolset. +- Cyclic namespace dependencies (e.g., `Windows.Foundation` ↔ `Windows.Foundation.Collections`) are handled automatically via SCC consolidation, but the resulting module name is chosen alphabetically. Adding new APIs could change SCC groupings. + +## Common Errors and Solutions + +| Error | Cause | Solution | +|-------|-------|----------| +| **C2230**: could not find module `winrt.X` | Missing import or the module IFC wasn't built | Add the import; verify the module builder or consumer produces it; check `CppWinRTModuleInclude` | +| **C7684**: ambiguous resolution to IFC | Same module built by multiple projects visible to the consumer | Add the namespace to `CppWinRTModuleExclude` | +| **C4348**: redefinition of default parameter | STL header included after `import std;` | Pre-include the STL header in the PCH (e.g., `#include `) | +| **C5028**: alignment specified in prior declaration | Same root cause as C4348 | Pre-include the STL header (e.g., `#include `) | +| **C4430 / C2039**: missing type / not a member | Type not visible because module not imported | Add the missing `import winrt.Namespace;` to ModulePreamble | +| **LNK2019**: unresolved external for `InitializeComponent` | XAML-generated code compiled without module imports | Ensure the `/FI` targets are present and use `Update="@(ClCompile)"` | +| **LNK2005**: symbol already defined | XAML-generated file compiled both directly and via a wrapper | Use the `/FI` injection approach instead of wrapper `.cpp` files | +| Redefinition errors when mixing `#include` and `import` | Same namespace included textually after being imported | Define `WINRT_IMPORT_MODULE` before the winrt header, or remove the `#include` | +| **"could not find module 'winrt.X'"** in cross-project consumer | Builder's `IntDir` not visible to consumer | Verify `ProjectReference` to the builder has `CppWinRTConsumeModule=true` | +| Linker errors for component constructors | Importing a component's internal module instead of building your own reference projection | Remove explicit `/reference` flags for component IFCs and ensure your project has `CppWinRTBuildModule=true` so it builds reference projection modules from the component's `.winmd` | + +## Tips + +- **Clean build after configuration changes.** Stale IFC files from previous builds cause confusing ambiguity errors. Clean the intermediate directory when changing module include/exclude filters. +- **Start from leaf projects.** Convert projects with no WinRT component dependencies first (e.g., utility libraries), then work up the dependency graph. +- **One project at a time.** Each conversion may surface new missing imports or exclude requirements. Building incrementally makes errors easier to diagnose. +- **Watch for transitive IFC propagation.** Static library IFCs become visible to all consumers in the reference chain. This is correct behavior but requires `CppWinRTModuleExclude` entries in consumers. +- **`CppWinRTModuleInclude` is usually needed.** Without it, projects with `CppWinRTModuleExclude` may not generate any `.ixx` files at all. Specify the namespace prefix for your component (e.g., `Microsoft.Terminal`). +- **DLL wrapper projects typically need no changes.** If you have a pattern of "static lib + thin DLL wrapper", the DLL wrapper usually just links the lib and doesn't need module conversion. + +## Approaches Tried and Abandoned + +For posterity, these patterns were attempted during the Terminal prototype but proved problematic. Avoid them. + +### Wrapper `.module.cpp` files for XAML-generated code + +The idea was to create wrapper `.cpp` files that would `#include` the XAML-generated files after setting up module imports, then remove the original generated items from `ClCompile` and replace them with the wrappers. + +**Why it failed:** The XAML build system generates files across two compilation passes. `XamlTypeInfo.g.cpp` `#include`s `.xaml.g.hpp` files that don't exist until Pass2, but the wrapper needed to compile during the first `ClCompile` pass. `__has_include` guards to make wrappers compile empty initially and recompile later proved unreliable — `CompileXamlGeneratedFiles` is a separate compilation step, and the wrapper items weren't correctly routed through it. + +**The `/FI` approach works** because it modifies the compiler flags on the *existing* generated items rather than replacing them, working with the XAML build system's two-pass compilation. + +### `AllProjectBMIsArePublic=false` on static libraries - As a general rule, the module builder project try to use the same configuration, preprocessor definitions, and compiler options as its consumers. +The idea was to prevent IFC propagation from static libraries by setting `AllProjectBMIsArePublic=false`, hiding the static lib's IFCs from consumers. -## Troubleshooting +**Why we moved away:** This fights against the intended VC++ build model. If a project consumes a static library, it should also consume that library's IFC files. Using different IFCs for the same types risks ODR violations. The `CppWinRTModuleExclude` approach is better — the consumer avoids building duplicate IFCs while still consuming the producer's IFCs. -**"could not find module 'winrt.X'"** — Ensure the `.ixx` was generated (check `$(GeneratedFilesDir)winrt\`) and that `CppWinRTBuildModule=true` is set. For cross-project references, verify the consuming project's `ProjectReference` to the builder has `CppWinRTConsumeModule=true`, and that the builder's `IntDir` is accessible via `/ifcSearchDir`. +### Moving wrapper items into MSBuild targets -**Linker errors for component constructors** — You may be importing a component's internal module instead of building your own reference projection. Remove explicit `/reference` flags for component IFCs and ensure your project has `CppWinRTBuildModule=true` so it builds reference projection modules from the component's `.winmd`. +The idea was to add wrapper `.cpp` `ClCompile` items inside a `` (dynamically) instead of a static ``, so they'd only enter `ClCompile` after generated files existed. -**Redefinition errors** — Don't mix `#include` and `import` for the same namespace in the same translation unit. Use `import` consistently. +**Why it failed:** Items added inside targets don't get the same metadata processing (module dependency scanning, IFC reference resolution) as items in static `ItemGroup`s. The compiler couldn't find any modules. diff --git a/nuget/readme.md b/nuget/readme.md index c8c0b9537..16eb5d2bb 100644 --- a/nuget/readme.md +++ b/nuget/readme.md @@ -137,7 +137,9 @@ void DerivedPage::InitializeComponent() ## C++20 Modules -C++/WinRT supports C++20 named modules as an alternative to `#include`-based consumption. Instead of `#include `, you can write `import winrt.Windows.Foundation;`. See [modules.md](modules.md) for the full guide. +C++/WinRT supports C++20 named modules as an alternative to `#include`-based consumption. Instead of `#include `, you can write `import winrt.Windows.Foundation;`. + +See the [C++/WinRT C++20 Modules Guide](https://github.com/microsoft/cppwinrt/blob/master/nuget/modules.md) for the full guide (also shipped alongside this file as `modules.md`). | ProjectReference metadata | Description | |-|-| diff --git a/nuget/readme.txt b/nuget/readme.txt index 049ab13b8..8d2681b6b 100644 --- a/nuget/readme.txt +++ b/nuget/readme.txt @@ -19,4 +19,7 @@ In addition, C++/WinRT generates templates and skeleton implementations for each ======================================================================== For more information, visit: https://github.com/Microsoft/cppwinrt/tree/master/nuget + +The full documentation is also included in this package as readme.md, and +the C++20 modules guide as modules.md. ======================================================================== From a31a05cedeee239995bbb09ea6867fbda9bb0fab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jun 2026 11:56:29 -0700 Subject: [PATCH 39/42] Bump actions/checkout from 6 to 7 (#1600) Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Ryan Shepherd --- .github/workflows/check-line-endings.yml | 2 +- .github/workflows/ci.yml | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/check-line-endings.yml b/.github/workflows/check-line-endings.yml index a0705cf58..dea958274 100644 --- a/.github/workflows/check-line-endings.yml +++ b/.github/workflows/check-line-endings.yml @@ -11,7 +11,7 @@ jobs: name: Enforce .gitattributes line endings runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Check for line ending violations run: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 37f42ab70..afdeed462 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: config: Release runs-on: ${{ matrix.toolchain.image }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Download nuget run: | @@ -113,7 +113,7 @@ jobs: test_exe: test_cpp20_module runs-on: ${{ matrix.toolchain.image }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Fetch cppwinrt executables if: matrix.arch != 'arm64' @@ -263,7 +263,7 @@ jobs: CMAKE_COLOR_DIAGNOSTICS: 1 CLICOLOR_FORCE: 1 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install cross compiler run: | @@ -296,7 +296,7 @@ jobs: Deployment: [Component, Standalone] runs-on: windows-2025-vs2026 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Download nuget run: | @@ -339,7 +339,7 @@ jobs: platform_toolset: v145 runs-on: ${{ matrix.toolchain.image }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Fetch cppwinrt executables uses: actions/download-artifact@v8 @@ -384,7 +384,7 @@ jobs: name: Build nuget package with MSVC runs-on: windows-2025-vs2026 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Package run: | From a535d38f083e6a428b64ac47e3144653c9739bc5 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 8 Jul 2026 12:38:40 -0700 Subject: [PATCH 40/42] Fix C4819 warning: replace non-ASCII em dash in base_macros.h comment (#1606) * Initial plan * Fix C4819 warning: replace non-ASCII em dash with ASCII hyphen in base_macros.h comment --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- strings/base_macros.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strings/base_macros.h b/strings/base_macros.h index 91b0121d9..850d0c627 100644 --- a/strings/base_macros.h +++ b/strings/base_macros.h @@ -44,7 +44,7 @@ // Template specializations in namespace std (hash, coroutine_traits) need extern "C++" // linkage in module builds for proper merging with the std module, but must NOT be -// exported — exporting namespace std would make all of std transitively visible. +// exported - exporting namespace std would make all of std transitively visible. #ifndef WINRT_IMPL_STD_EXPORT #ifdef WINRT_IMPL_BUILD_MODULE #define WINRT_IMPL_STD_EXPORT extern "C++" From d3d92d70e3e089307ab6d6deb5ed39c7a534fec2 Mon Sep 17 00:00:00 2001 From: Raymond Chen Date: Mon, 27 Jul 2026 09:39:55 -0700 Subject: [PATCH 41/42] Fix race condition in cancellation setup/teardown (#1609) The code failed to handle three cases. 1. A cancellation is in progress when a cancellable awaitable begins. 2. A cancellation is in progress when a cancellable awaitable ends. 3. A cancellation is in progress when a cancel() request is made. The m_canceller member has one of these three values: * nullptr, meaning that there is nothing to cancel. It has this value when the coroutine is not awaiting, or if it is awaiting something that cannot be cancelled. * cancelling_ptr, meaning that another thread (not the coroutine thread) is in the middle of cancellation request. * function pointer, representing the function to call to cancel the await. In case 1, we should not overwrite the canceling_ptr with the function pointer, because only the code doing the cancel() can transition into/out of cancelling_ptr. In case 2, we intended to spin until the m_canceller is no longer cancelling_ptr, but we used m_canceller.exchange(nullptr) in a loop, which means that if m_canceller was cancelling_ptr, we overwrite it with nullptr. As a result, the "while" loop always exits after one iteration. We need to spin on the m_canceller without modifying it if it is cancelling_ptr. In case 3, cancel() function resets m_cancelling back to nullptr, even if the value was cancelling_ptr on entry, prematurely declaring that the existing cancel() has completed. If the original value was cancelling_ptr, we should leave it that way. There are still other cases not handled: * Coroutine already cancelled when a co_await starts. In this case, we never call the canceller, so the coroutine fails to propagate cancellation. This will require a broader fix, so I'm not going to fix it in this PR. This PR is primarily about fixing the crash caused by case 2. Cases 1 and 3 were fixed opportunistically. --- strings/base_coroutine_threadpool.h | 34 +++++++++++++++++++---------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/strings/base_coroutine_threadpool.h b/strings/base_coroutine_threadpool.h index 057d5b548..c901b94ba 100644 --- a/strings/base_coroutine_threadpool.h +++ b/strings/base_coroutine_threadpool.h @@ -146,32 +146,42 @@ WINRT_EXPORT namespace winrt void set_canceller(canceller_t canceller, void* context) { m_context = context; - m_canceller.store(canceller, std::memory_order_release); + canceller_t expected = nullptr; + m_canceller.compare_exchange_strong(expected, canceller, std::memory_order_release, std::memory_order_relaxed); } void revoke_canceller() { - while (m_canceller.exchange(nullptr, std::memory_order_acquire) == cancelling_ptr) + auto existing = m_canceller.load(std::memory_order_relaxed); + do { - std::this_thread::yield(); + while (existing == cancelling_ptr) + { + std::this_thread::yield(); + existing = m_canceller.load(std::memory_order_relaxed); + } } + while (!m_canceller.compare_exchange_weak(existing, nullptr, std::memory_order_acquire, std::memory_order_relaxed)); } void cancel() { auto canceller = m_canceller.exchange(cancelling_ptr, std::memory_order_acquire); - struct unique_cancellation_lock + if (canceller != cancelling_ptr) { - cancellable_promise* promise; - ~unique_cancellation_lock() + struct unique_cancellation_lock + { + cancellable_promise* promise; + ~unique_cancellation_lock() + { + promise->m_canceller.store(nullptr, std::memory_order_release); + } + } lock{ this }; + + if (canceller != nullptr) { - promise->m_canceller.store(nullptr, std::memory_order_release); + canceller(m_context); } - } lock{ this }; - - if ((canceller != nullptr) && (canceller != cancelling_ptr)) - { - canceller(m_context); } } From d6cff316a991152071038668fb586a8b5ab1d51f Mon Sep 17 00:00:00 2001 From: Derek Morris Date: Mon, 27 Jul 2026 18:15:40 -0700 Subject: [PATCH 42/42] Add header to base_includes.h (#1612) base_types.h uses std::ratio_multiply, which is defined in . Under strict include-what-you-use rules not referencing this header can lead to weird build breaks. --- strings/base_includes.h | 1 + 1 file changed, 1 insertion(+) diff --git a/strings/base_includes.h b/strings/base_includes.h index 287a09709..bac7358bd 100644 --- a/strings/base_includes.h +++ b/strings/base_includes.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include