Compare commits

...

7 Commits

Author SHA1 Message Date
Clint Rutkas
8564f9d864 Update code.txt 2026-05-25 08:11:54 -07:00
Clint Rutkas
d8a7fe5913 Merge branch 'crutkas/dev/fixcoroutine' of https://github.com/microsoft/powertoys into crutkas/dev/fixcoroutine 2026-05-24 21:36:34 -07:00
Clint Rutkas
e627f1755b Eliminate VS 2026 build warnings: IIDOptimizer, AutoInitializer dupe, CsWinRT projection race fallback
- Common.Dotnet.CsWinRT.props: opt out of CsWinRT 2.2 IIDOptimizer which exits with code -1 on .NET 10 (MSB3073). Add DeleteStaleCsWinRTRspAfterPrepare second-pass target so projects that override CsWinRTGeneratedFilesDir to OutDir (e.g. PowerToys.Settings, PowerAccent.Common.UnitTests) also have stale cswinrt.rsp deleted after the value is resolved.

- PowerRenameUI.vcxproj: add Microsoft.WindowsAppSDK.Foundation PackageReference and FixWinAppSDKAutoInitializer target (same pattern as runner.vcxproj) so WindowsAppRuntimeAutoInitializer.cpp is only added once, eliminating MSB8027 and LNK4042.
2026-05-24 20:51:48 -07:00
copilot-swe-agent[bot]
e503ccfd89 Allow cswinrt and rsp in spell check 2026-05-25 01:04:37 +00:00
Clint Rutkas
2084992f42 getting most stood up and functional again 2026-05-24 09:37:31 -07:00
Clint Rutkas
6ecb06c8cb WIP: spdlog 1.17 / fmt 12 compile fixes
- Add FMT_UNICODE=0 to logging.vcxproj, spdlog.props, UnitTests-CommonUtils (Microsoft codebase isn't /utf-8 by default)
- Rename spdlog's fmt.cpp -> bundled_fmtlib_format.cpp in logging.vcxproj (renamed upstream)
- Add SPDLOG_WCHAR_TO_UTF8_SUPPORT to logging.vcxproj so wstr_to_utf8buf is compiled
- Wrap Logger:: format strings with fmt::runtime() (fmt 11+ requires consteval format strings)
- Bump CalculatorEngineCommon to C++20 to drop dependency on <experimental/coroutine>
2026-05-23 22:08:58 -07:00
Clint Rutkas
a3cad81295 Bump spdlog submodule to v1.17.0 (bundled fmt 12.1); remove MSVC 14.51 checked_array_iterator shim 2026-05-23 21:37:50 -07:00
14 changed files with 122 additions and 124 deletions

View File

@@ -308,8 +308,11 @@ pwa
AOT
Aot
cswinrt
ify
rsp
TFM
RTIID
# YML
onefuzz

2
deps/spdlog vendored

View File

@@ -1,94 +0,0 @@
// spdlog-msvc-fix.h
//
// Workaround for MSVC 14.51 (compiler version 19.51, _MSC_VER >= 1951) removing
// stdext::checked_array_iterator. Force-included for all spdlog consumers via
// deps/spdlog.props, because spdlog v1.8.5's bundled fmt format.h(357) still
// references this type inside #if defined(_SECURE_SCL) && _SECURE_SCL -- a
// branch entered in Debug builds where _ITERATOR_DEBUG_LEVEL > 0.
//
// On MSVC 14.50 and earlier, the type still exists in <iterator>, so this shim
// is a no-op via the _MSC_VER guard. On MSVC 14.51+, it provides a minimal
// pointer-backed substitute that satisfies the bundled fmt's usage:
//
// template <typename T> using checked_ptr = stdext::checked_array_iterator<T*>;
// template <typename T> checked_ptr<T> make_checked(T* p, size_t size) {
// return {p, size};
// }
// ... return make_checked(get_data(c) + size, n);
//
// When deps/spdlog is bumped past v1.14 (which ships fmt 10.2 and drops this
// dependency), this shim and its <ForcedIncludeFiles> entry in deps/spdlog.props
// can be deleted.
#pragma once
#if defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER >= 1951
#include <cstddef>
#include <iterator>
#include <type_traits>
namespace stdext
{
template <typename _Ptr>
class checked_array_iterator
{
_Ptr _Myarray = nullptr;
std::size_t _Mysize = 0;
std::size_t _Myindex = 0;
public:
using iterator_category = std::random_access_iterator_tag;
using value_type = std::remove_cv_t<std::remove_pointer_t<_Ptr>>;
using difference_type = std::ptrdiff_t;
using pointer = _Ptr;
using reference = std::remove_pointer_t<_Ptr>&;
constexpr checked_array_iterator() = default;
constexpr checked_array_iterator(_Ptr arr, std::size_t size, std::size_t idx = 0) noexcept
: _Myarray(arr), _Mysize(size), _Myindex(idx)
{
}
constexpr reference operator*() const noexcept { return _Myarray[_Myindex]; }
constexpr pointer operator->() const noexcept { return _Myarray + _Myindex; }
constexpr reference operator[](difference_type n) const noexcept
{
return _Myarray[_Myindex + static_cast<std::size_t>(n)];
}
constexpr checked_array_iterator& operator++() noexcept { ++_Myindex; return *this; }
constexpr checked_array_iterator operator++(int) noexcept { auto t = *this; ++_Myindex; return t; }
constexpr checked_array_iterator& operator--() noexcept { --_Myindex; return *this; }
constexpr checked_array_iterator operator--(int) noexcept { auto t = *this; --_Myindex; return t; }
constexpr checked_array_iterator& operator+=(difference_type n) noexcept
{
_Myindex = static_cast<std::size_t>(static_cast<difference_type>(_Myindex) + n);
return *this;
}
constexpr checked_array_iterator& operator-=(difference_type n) noexcept
{
_Myindex = static_cast<std::size_t>(static_cast<difference_type>(_Myindex) - n);
return *this;
}
friend constexpr checked_array_iterator operator+(checked_array_iterator it, difference_type n) noexcept { it += n; return it; }
friend constexpr checked_array_iterator operator+(difference_type n, checked_array_iterator it) noexcept { return it + n; }
friend constexpr checked_array_iterator operator-(checked_array_iterator it, difference_type n) noexcept { it -= n; return it; }
friend constexpr difference_type operator-(checked_array_iterator a, checked_array_iterator b) noexcept
{
return static_cast<difference_type>(a._Myindex) - static_cast<difference_type>(b._Myindex);
}
friend constexpr bool operator==(checked_array_iterator a, checked_array_iterator b) noexcept { return a._Myindex == b._Myindex; }
friend constexpr bool operator!=(checked_array_iterator a, checked_array_iterator b) noexcept { return !(a == b); }
friend constexpr bool operator<(checked_array_iterator a, checked_array_iterator b) noexcept { return a._Myindex < b._Myindex; }
friend constexpr bool operator>(checked_array_iterator a, checked_array_iterator b) noexcept { return b < a; }
friend constexpr bool operator<=(checked_array_iterator a, checked_array_iterator b) noexcept { return !(b < a); }
friend constexpr bool operator>=(checked_array_iterator a, checked_array_iterator b) noexcept { return !(a < b); }
};
} // namespace stdext
#endif // __cplusplus && _MSC_VER >= 1951

3
deps/spdlog.props vendored
View File

@@ -2,8 +2,7 @@
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)spdlog\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>SPDLOG_WCHAR_TO_UTF8_SUPPORT;SPDLOG_COMPILED_LIB;SPDLOG_WCHAR_FILENAMES;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ForcedIncludeFiles>$(MSBuildThisFileDirectory)spdlog-msvc-fix\include\spdlog-msvc-fix.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
<PreprocessorDefinitions>SPDLOG_WCHAR_TO_UTF8_SUPPORT;SPDLOG_COMPILED_LIB;SPDLOG_WCHAR_FILENAMES;FMT_UNICODE=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
</Project>

View File

@@ -12,6 +12,17 @@
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
</PropertyGroup>
<!--
Opt out of CsWinRT 2.2 IIDOptimizer. On .NET 10 / CsWinRT 2.2 the tool exits with code -1
after producing "0 IID calculations/fetches patched", which generates a noisy MSB3073
warning for every CsWinRT-consuming project. The IIDOptimizer is a runtime-perf optimization
that interns GUID lookups; disabling it just means a small first-call cost. This switch
causes Microsoft.Windows.CsWinRT.IIDOptimizer.targets to not be imported at all.
-->
<PropertyGroup>
<CsWinRTIIDOptimizerOptOut>true</CsWinRTIIDOptimizerOptOut>
</PropertyGroup>
<!-- Common from the debug / release items -->
<PropertyGroup>
<WarningLevel>4</WarningLevel>
@@ -41,7 +52,54 @@
<!-- this may need to be removed on future CsWinRT upgrades-->
<Target Name="RemoveCsWinRTPackageAnalyzer" BeforeTargets="CoreCompile">
<ItemGroup>
<Analyzer Remove="@(Analyzer)" Condition="%(Analyzer.NuGetPackageId) == 'Microsoft.Windows.CsWinRT'" />
<Analyzer Remove="@(Analyzer)" Condition="%(Analyzer.NuGetPackageId) == 'Microsoft.Windows.CsWinRT'" />
</ItemGroup>
</Target>
<!--
Ensure any referenced C++/WinRT (.vcxproj) projects are fully built BEFORE the CsWinRT
source generator runs in this csproj. On a clean machine the SDK-style ProjectReference
graph does not guarantee that the producing vcxproj has emitted its .winmd before the
consuming C# Compile / source-generator stage starts in a parallel solution build,
which manifests as CS0246 on the projected namespace (e.g. 'PowerToys.Interop').
Forcing a serialized Build of the .vcxproj references here closes that race.
We hook BEFORE ResolveProjectReferences so the produced .winmd is visible to
CsWinRTRemoveWinMDReferences (which moves it into @(CsWinRTInputs)) and we also
delete a possibly stale cswinrt.rsp so CsWinRTGenerateProjection re-invokes
cswinrt.exe instead of incrementally skipping.
-->
<Target Name="EnsureNativeWinMDProjectionInputsBuilt"
BeforeTargets="ResolveProjectReferences;ResolveAssemblyReferences;CsWinRTPrepareProjection;CsWinRTGenerateProjection"
Condition="'@(ProjectReference)' != '' and '$(DesignTimeBuild)' != 'true' and '$(BuildingProject)' != 'false'">
<ItemGroup>
<_NativeWinMDProjectionRef Include="@(ProjectReference)" Condition="'%(Extension)' == '.vcxproj'" />
</ItemGroup>
<MSBuild Projects="@(_NativeWinMDProjectionRef)"
Properties="Configuration=$(Configuration);Platform=$(Platform)"
Targets="Build"
BuildInParallel="false"
Condition="'@(_NativeWinMDProjectionRef)' != ''" />
<!-- Force CsWinRTGenerateProjection to re-run so stale-rsp incremental skip cannot
leave us without generated .cs files when the .winmd has just been (re)produced. -->
<Delete Files="$(CsWinRTGeneratedFilesDir)cswinrt.rsp;$(CsWinRTGeneratedFilesDir)cswinrt_internal.rsp"
Condition="'@(_NativeWinMDProjectionRef)' != '' and '$(CsWinRTGeneratedFilesDir)' != ''" />
<!-- Mark that we need to delete the rsp again once CsWinRTGeneratedFilesDir is fully resolved
(some projects set it to $(OutDir) which is not evaluated this early). -->
<PropertyGroup>
<_DeleteStaleCsWinRTRspPending>true</_DeleteStaleCsWinRTRspPending>
</PropertyGroup>
</Target>
<!--
Second pass: after CsWinRTPrepareProjection has resolved $(CsWinRTGeneratedFilesDir) to its
final value (which may depend on $(OutDir)), delete any stale cswinrt.rsp so the
CsWinRTGenerateProjection target's incremental-skip cannot leave us without generated .cs files.
-->
<Target Name="DeleteStaleCsWinRTRspAfterPrepare"
AfterTargets="CsWinRTPrepareProjection"
BeforeTargets="CsWinRTGenerateProjection"
Condition="'$(_DeleteStaleCsWinRTRspPending)' == 'true' and '$(CsWinRTGeneratedFilesDir)' != ''">
<Delete Files="$(CsWinRTGeneratedFilesDir)cswinrt.rsp;$(CsWinRTGeneratedFilesDir)cswinrt_internal.rsp" />
</Target>
</Project>

View File

@@ -161,7 +161,7 @@
<ClCompile>
<!-- We use MultiThreadedDebug, rather than MultiThreadedDebugDLL, to avoid DLL dependencies on VCRUNTIME140d.dll and MSVCP140d.dll. -->
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">stdcpp17</LanguageStandard>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<!-- Link statically against the runtime and STL, but link dynamically against the CRT by ignoring the static CRT

View File

@@ -29,7 +29,7 @@
<ClCompile>
<AdditionalIncludeDirectories>..\;..\utils;..\Telemetry;..\..\;..\..\..\deps\;..\..\..\deps\spdlog\include;..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.260126.7\include;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp23</LanguageStandard>
<PreprocessorDefinitions>SPDLOG_WCHAR_TO_UTF8_SUPPORT;SPDLOG_HEADER_ONLY;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>SPDLOG_WCHAR_TO_UTF8_SUPPORT;SPDLOG_HEADER_ONLY;FMT_UNICODE=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>

View File

@@ -1,7 +1,27 @@
#pragma once
#include <spdlog/spdlog.h>
#include <type_traits>
#include "logger_settings.h"
// fmt 9+ no longer auto-formats enums. Provide a generic formatter that
// converts any scoped or unscoped enum to its underlying integer type so
// existing Logger::xxx(L"... {} ...", someEnum) call sites keep working
// after the spdlog 1.17 / fmt 12 upgrade.
namespace fmt
{
template <typename E, typename Char>
struct formatter<E, Char, std::enable_if_t<std::is_enum_v<E>>>
: formatter<std::underlying_type_t<E>, Char>
{
template <typename FormatContext>
auto format(E value, FormatContext& ctx) const
{
return formatter<std::underlying_type_t<E>, Char>::format(
static_cast<std::underlying_type_t<E>>(value), ctx);
}
};
}
class Logger
{
private:
@@ -17,44 +37,44 @@ public:
// log message should not be localized
template<typename FormatString, typename... Args>
static void trace(const FormatString& fmt, const Args&... args)
static void trace(const FormatString& formatString, const Args&... args)
{
logger->trace(fmt, args...);
logger->trace(fmt::runtime(formatString), args...);
}
// log message should not be localized
template<typename FormatString, typename... Args>
static void debug(const FormatString& fmt, const Args&... args)
static void debug(const FormatString& formatString, const Args&... args)
{
logger->debug(fmt, args...);
logger->debug(fmt::runtime(formatString), args...);
}
// log message should not be localized
template<typename FormatString, typename... Args>
static void info(const FormatString& fmt, const Args&... args)
static void info(const FormatString& formatString, const Args&... args)
{
logger->info(fmt, args...);
logger->info(fmt::runtime(formatString), args...);
}
// log message should not be localized
template<typename FormatString, typename... Args>
static void warn(const FormatString& fmt, const Args&... args)
static void warn(const FormatString& formatString, const Args&... args)
{
logger->warn(fmt, args...);
logger->warn(fmt::runtime(formatString), args...);
}
// log message should not be localized
template<typename FormatString, typename... Args>
static void error(const FormatString& fmt, const Args&... args)
static void error(const FormatString& formatString, const Args&... args)
{
logger->error(fmt, args...);
logger->error(fmt::runtime(formatString), args...);
}
// log message should not be localized
template<typename FormatString, typename... Args>
static void critical(const FormatString& fmt, const Args&... args)
static void critical(const FormatString& formatString, const Args&... args)
{
logger->critical(fmt, args...);
logger->critical(fmt::runtime(formatString), args...);
}
static void flush()

View File

@@ -55,7 +55,7 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<WarningLevel>Level4</WarningLevel>
<PreprocessorDefinitions>WIN32;_WINDOWS;SPDLOG_COMPILED_LIB;SPDLOG_WCHAR_FILENAMES;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;_WINDOWS;SPDLOG_COMPILED_LIB;SPDLOG_WCHAR_FILENAMES;SPDLOG_WCHAR_TO_UTF8_SUPPORT;FMT_UNICODE=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ObjectFileName>$(IntDir)</ObjectFileName>
<FunctionLevelLinking>true</FunctionLevelLinking>
<EnableParallelCodeGeneration>true</EnableParallelCodeGeneration>
@@ -71,7 +71,7 @@
<ClCompile Include="$(RepoRoot)deps\spdlog\src\file_sinks.cpp" />
<ClCompile Include="$(RepoRoot)deps\spdlog\src\async.cpp" />
<ClCompile Include="$(RepoRoot)deps\spdlog\src\cfg.cpp" />
<ClCompile Include="$(RepoRoot)deps\spdlog\src\fmt.cpp" />
<ClCompile Include="$(RepoRoot)deps\spdlog\src\bundled_fmtlib_format.cpp" />
<ClInclude Include="$(RepoRoot)deps\spdlog\include\spdlog\async.h" />
<ClInclude Include="$(RepoRoot)deps\spdlog\include\spdlog\async_logger-inl.h" />
<ClInclude Include="$(RepoRoot)deps\spdlog\include\spdlog\async_logger.h" />

View File

@@ -698,7 +698,7 @@ void LightSwitchInterface::init_settings()
}
catch (const winrt::hresult_error& e)
{
Logger::error(L"[Light Switch] init_settings: hresult_error 0x{:08X} - {}", e.code(), e.message().c_str());
Logger::error(L"[Light Switch] init_settings: hresult_error 0x{:08X} - {}", static_cast<int32_t>(e.code()), e.message().c_str());
}
catch (const std::exception& e)
{

View File

@@ -111,10 +111,10 @@ int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR cmdline, int cm
switch (res.error())
{
case JsonUtils::WorkspacesFileError::FileReadingError:
formattedMessage = fmt::format(GET_RESOURCE_STRING(IDS_FILE_READING_ERROR), file);
formattedMessage = fmt::format(fmt::runtime(GET_RESOURCE_STRING(IDS_FILE_READING_ERROR)), file);
break;
case JsonUtils::WorkspacesFileError::IncorrectFileError:
formattedMessage = fmt::format(GET_RESOURCE_STRING(IDS_INCORRECT_FILE_ERROR), file);
formattedMessage = fmt::format(fmt::runtime(GET_RESOURCE_STRING(IDS_INCORRECT_FILE_ERROR)), file);
break;
}
@@ -137,10 +137,10 @@ int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR cmdline, int cm
switch (res.error())
{
case JsonUtils::WorkspacesFileError::FileReadingError:
formattedMessage = fmt::format(GET_RESOURCE_STRING(IDS_FILE_READING_ERROR), file);
formattedMessage = fmt::format(fmt::runtime(GET_RESOURCE_STRING(IDS_FILE_READING_ERROR)), file);
break;
case JsonUtils::WorkspacesFileError::IncorrectFileError:
formattedMessage = fmt::format(GET_RESOURCE_STRING(IDS_INCORRECT_FILE_ERROR), file);
formattedMessage = fmt::format(fmt::runtime(GET_RESOURCE_STRING(IDS_INCORRECT_FILE_ERROR)), file);
break;
}
@@ -151,7 +151,7 @@ int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR cmdline, int cm
if (workspaces.empty())
{
Logger::warn("Workspaces file is empty");
std::wstring formattedMessage = fmt::format(GET_RESOURCE_STRING(IDS_EMPTY_FILE), file);
std::wstring formattedMessage = fmt::format(fmt::runtime(GET_RESOURCE_STRING(IDS_EMPTY_FILE)), file);
MessageBox(NULL, formattedMessage.c_str(), GET_RESOURCE_STRING(IDS_WORKSPACES).c_str(), MB_ICONERROR | MB_OK);
return 1;
}
@@ -169,7 +169,7 @@ int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR cmdline, int cm
if (projectToLaunch.id.empty())
{
Logger::critical(L"Workspace {} not found", cmdArgs.workspaceId);
std::wstring formattedMessage = fmt::format(GET_RESOURCE_STRING(IDS_PROJECT_NOT_FOUND), cmdArgs.workspaceId);
std::wstring formattedMessage = fmt::format(fmt::runtime(GET_RESOURCE_STRING(IDS_PROJECT_NOT_FOUND)), cmdArgs.workspaceId);
MessageBox(NULL, formattedMessage.c_str(), GET_RESOURCE_STRING(IDS_WORKSPACES).c_str(), MB_ICONERROR | MB_OK);
return 1;
}

View File

@@ -1,7 +1,9 @@
#pragma once
#pragma once
#include "KeyboardListener.g.h"
#include <windows.h>
#include <mutex>
#include <functional>
#include <spdlog/stopwatch.h>
#include <set>

View File

@@ -1,7 +1,8 @@
#pragma once
#pragma once
#include "KeyboardListener.g.h"
#include <mutex>
#include <functional>
#include <spdlog/stopwatch.h>
namespace winrt::PowerToys::PowerAccentKeyboardService::implementation

View File

@@ -40,6 +40,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.WindowsAppSDK" GeneratePathProperty="true" />
<PackageReference Include="Microsoft.WindowsAppSDK.Foundation" GeneratePathProperty="true" />
<PackageReference Include="Microsoft.Windows.CppWinRT" GeneratePathProperty="true" />
<PackageReference Include="Microsoft.Windows.ImplementationLibrary" GeneratePathProperty="true" />
<PackageReference Include="boost" GeneratePathProperty="true" />
@@ -224,4 +225,12 @@
<PRIResource Include="@(_WildCardPRIResource)" />
</ItemGroup>
</Target>
</Project>
<!-- Deduplicate WindowsAppRuntimeAutoInitializer.cpp (added twice via transitive imports causing MSB8027/LNK4042). Same fix as runner.vcxproj. -->
<Target Name="FixWinAppSDKAutoInitializer" BeforeTargets="ClCompile" AfterTargets="WindowsAppRuntimeAutoInitializer">
<ItemGroup>
<ClCompile Remove="@(ClCompile)" Condition="'%(Filename)' == 'WindowsAppRuntimeAutoInitializer'" />
<ClCompile Include="$(PkgMicrosoft_WindowsAppSDK_Foundation)\include\WindowsAppRuntimeAutoInitializer.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
</ItemGroup>
</Target></Project>