This commit is contained in:
Kenny Kerr 2019-10-08 08:19:10 -07:00
Родитель 76ab8890c1
Коммит f088d90071
702 изменённых файлов: 105202 добавлений и 0 удалений

2
.gitignore поставляемый
Просмотреть файл

@ -3,3 +3,5 @@
x86
x64
*.user
build
packages

52
CMakeLists.txt Normal file
Просмотреть файл

@ -0,0 +1,52 @@
file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/cppwinrt.exe" cppwinrt_exe)
file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}" CmakeOutDir)
set(build msbuild /nologo /m /p:Configuration=${CMAKE_BUILD_TYPE},Platform=$ENV{VSCMD_ARG_TGT_ARCH},XlangBuildVersion=${XLANG_BUILD_VERSION},CmakeOutDir=${CmakeOutDir} ${CMAKE_CURRENT_SOURCE_DIR}/cppwinrt.sln)
add_custom_command(OUTPUT ${cppwinrt_exe}
COMMAND ${build} /t:cppwinrt
)
add_custom_target(cppwinrt ALL DEPENDS ${cppwinrt_exe})
add_custom_target(cppwinrt_test ALL DEPENDS cppwinrt
COMMAND ${cppwinrt_exe} -in sdk -out ${CMAKE_CURRENT_BINARY_DIR} -verbose
COMMAND ${build} /t:fast_fwd
COMMAND ${build} /t:test
COMMAND ${build} /t:test_fast
COMMAND ${build} /t:test_fast_fwd
COMMAND ${build} /t:old_tests\\test_old
)
set_target_properties(cppwinrt PROPERTIES "cppwinrt_exe" ${cppwinrt_exe})
# For x86, build all arches of fast forwarder lib for NuGet dependency
if (WIN32 AND ("$ENV{VSCMD_ARG_TGT_ARCH}" STREQUAL "x86"))
set(ffbuild msbuild /nologo /m /p:Configuration=${CMAKE_BUILD_TYPE},XlangBuildVersion=${XLANG_BUILD_VERSION} ${CMAKE_CURRENT_SOURCE_DIR}/cppwinrt.sln /t:fast_fwd)
file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/cppwinrt_fast_forwarder.lib" cppwinrt_fast_fwd_x86)
set(CmakeOutDir_x86 ${CmakeOutDir})
string(REGEX REPLACE "x86" "x64" CmakeOutDir_x64 ${CmakeOutDir})
string(REGEX REPLACE "x86" "arm" CmakeOutDir_arm ${CmakeOutDir})
string(REGEX REPLACE "x86" "arm64" CmakeOutDir_arm64 ${CmakeOutDir})
add_custom_command(OUTPUT ${cppwinrt_fast_fwd_x86}
COMMAND ${ffbuild} /p:Platform=x86,CmakeOutDir=${CmakeOutDir_x86}
COMMAND ${CMAKE_COMMAND} -E make_directory ${CmakeOutDir_x64}
COMMAND cd /d ${CmakeOutDir_x64}
COMMAND ${ffbuild} /p:Platform=x64,CmakeOutDir=${CmakeOutDir_x64}
COMMAND ${CMAKE_COMMAND} -E make_directory ${CmakeOutDir_arm}
COMMAND cd /d ${CmakeOutDir_arm}
COMMAND ${ffbuild} /p:Platform=arm,CmakeOutDir=${CmakeOutDir_arm}
COMMAND ${CMAKE_COMMAND} -E make_directory ${CmakeOutDir_arm64}
COMMAND cd /d ${CmakeOutDir_arm64}
COMMAND ${ffbuild} /p:Platform=arm64,CmakeOutDir=${CmakeOutDir_arm64}
)
add_custom_target(cppwinrt_fast_fwd ALL DEPENDS ${cppwinrt_fast_fwd_x86})
set_target_properties(cppwinrt_fast_fwd PROPERTIES "cppwinrt_fast_fwd_x86" ${cppwinrt_fast_fwd_x86})
endif()

32
build_projection.cmd Normal file
Просмотреть файл

@ -0,0 +1,32 @@
@echo off
setlocal ENABLEDELAYEDEXPANSION
set target_platform=%1
set target_configuration=%2
if "%target_platform%"=="" set target_platform=x64
if /I "%target_platform%" equ "all" (
if "%target_configuration%"=="" (
set target_configuration=all
)
call %0 x86 !target_configuration!
call %0 x64 !target_configuration!
call %0 arm !target_configuration!
call %0 arm64 !target_configuration!
goto :eof
)
if /I "%target_configuration%" equ "all" (
call %0 %target_platform% Debug
call %0 %target_platform% Release
goto :eof
)
if "%target_configuration%"=="" (
set target_configuration=Debug
)
echo Building projection into %target_platform% %target_configuration%
%~p0\build\x64\Release\cppwinrt.exe -in local -out %~p0\build\%target_platform%\%target_configuration% -verbose
echo.

1
compile_tests.cmd Normal file
Просмотреть файл

@ -0,0 +1 @@
cl /EHsc /std:c++17 /MP /I ..\..\..\_build\Windows\x64\Debug\tool\cppwinrt ..\..\..\_build\Windows\x64\Debug\tool\cppwinrt\tests\*.cpp

69
cppwinrt.props Normal file
Просмотреть файл

@ -0,0 +1,69 @@
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Set common MSBuild properties and item metadata for CppWinRT tool and tests -->
<PropertyGroup Condition="'$(VisualStudioVersion)' == '15.0'">
<PlatformToolset>v141</PlatformToolset>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(VisualStudioVersion)' == '16.0'">
<PlatformToolset>v142</PlatformToolset>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<!--
Can be used as follows.
Compile with Visual C++:
msbuild /m /p:Configuration=Debug,Platform=x64 cppwinrt.sln
Compile with Clang:
msbuild /m /p:Configuration=Debug,Platform=x64,Clang=1 cppwinrt.sln
Optionally add /t:<project> to only build a given a solution project:
msbuild /m /p:Configuration=Debug,Platform=x64,Clang=1 cppwinrt.sln /t:cppwinrt
-->
<PropertyGroup Condition="'$(Clang)'=='1'">
<CLToolExe>clang-cl.exe</CLToolExe>
<CLToolPath>C:\Program Files\LLVM\bin</CLToolPath>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup>
<XlangBuildVersion Condition="'$(XlangBuildVersion)'==''">2.3.4.5</XlangBuildVersion>
<CmakePlatform>$(Platform)</CmakePlatform>
<CmakePlatform Condition="'$(Platform)'=='Win32'">x86</CmakePlatform>
<CmakeOutDir Condition="'$(CmakeOutDir)'==''">$(SolutionDir)build\$(CmakePlatform)\$(Configuration)</CmakeOutDir>
<CppWinRTDir>$(CmakeOutDir)\</CppWinRTDir>
<CppWinRTDir Condition="'$(Platform)'=='ARM' or '$(Platform)'=='ARM64'">$(SolutionDir)build\x86\$(Configuration)\</CppWinRTDir>
<OutDir>$(CmakeOutDir)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PreprocessorDefinitions>XLANG_VERSION_STRING="$(XlangBuildVersion)";NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<AdditionalOptions>/await /bigobj</AdditionalOptions>
<AdditionalOptions Condition="'$(Clang)'=='1'">-Wno-unused-command-line-argument -fno-delayed-template-parsing -Xclang -fcoroutines-ts -mcx16</AdditionalOptions>
</ClCompile>
<Link>
<AdditionalDependencies>onecore.lib</AdditionalDependencies>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>XLANG_VERSION_STRING="$(XlangBuildVersion)";%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
</ItemDefinitionGroup>
</Project>

375
cppwinrt.sln Normal file
Просмотреть файл

@ -0,0 +1,375 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28606.126
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cppwinrt", "cppwinrt\cppwinrt.vcxproj", "{D613FB39-5035-4043-91E2-BAB323908AF4}"
ProjectSection(ProjectDependencies) = postProject
{FB239623-7D19-4025-BCEA-B43298D4A315} = {FB239623-7D19-4025-BCEA-B43298D4A315}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "prebuild", "prebuild\prebuild.vcxproj", "{FB239623-7D19-4025-BCEA-B43298D4A315}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "old_tests", "old_tests", "{515B4F38-FD07-4C8B-94D0-BE3A813BB3EE}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_old", "test\old_tests\UnitTests\Tests.vcxproj", "{C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}"
ProjectSection(ProjectDependencies) = postProject
{559A7CF4-DC5F-4D62-BA6B-0C2B025593F8} = {559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Component", "test\old_tests\Component\Component.vcxproj", "{559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}"
ProjectSection(ProjectDependencies) = postProject
{152E4C6E-9A9D-4D5A-B38D-4905D173649A} = {152E4C6E-9A9D-4D5A-B38D-4905D173649A}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Composable", "test\old_tests\Composable\Composable.vcxproj", "{152E4C6E-9A9D-4D5A-B38D-4905D173649A}"
ProjectSection(ProjectDependencies) = postProject
{D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_component", "test\test_component\test_component.vcxproj", "{A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}"
ProjectSection(ProjectDependencies) = postProject
{D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test\test.vcxproj", "{D2961EA1-A8CA-4A62-B760-948403DC8494}"
ProjectSection(ProjectDependencies) = postProject
{F1C915B3-2C64-4992-AFB7-7F035B1A7607} = {F1C915B3-2C64-4992-AFB7-7F035B1A7607}
{A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} = {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_component_folders", "test\test_component_folders\test_component_folders.vcxproj", "{85695954-3800-4558-9857-966E69E9F9EC}"
ProjectSection(ProjectDependencies) = postProject
{D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_component_no_pch", "test\test_component_no_pch\test_component_no_pch.vcxproj", "{F1C915B3-2C64-4992-AFB7-7F035B1A7607}"
ProjectSection(ProjectDependencies) = postProject
{D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_component_base", "test\test_component_base\test_component_base.vcxproj", "{13333A6F-6A4A-48CD-865C-0F65135EB018}"
ProjectSection(ProjectDependencies) = postProject
{D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_component_derived", "test\test_component_derived\test_component_derived.vcxproj", "{0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}"
ProjectSection(ProjectDependencies) = postProject
{13333A6F-6A4A-48CD-865C-0F65135EB018} = {13333A6F-6A4A-48CD-865C-0F65135EB018}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_component_fast", "test\test_component_fast\test_component_fast.vcxproj", "{0E0ACA62-A92F-44CF-BD41-AEB541946DF8}"
ProjectSection(ProjectDependencies) = postProject
{D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_fast", "test\test_fast\test_fast.vcxproj", "{F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}"
ProjectSection(ProjectDependencies) = postProject
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8} = {0E0ACA62-A92F-44CF-BD41-AEB541946DF8}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_slow", "test\test_slow\test_slow.vcxproj", "{B68C61C6-4699-41E6-A158-EA1BE029E7A0}"
ProjectSection(ProjectDependencies) = postProject
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8} = {0E0ACA62-A92F-44CF-BD41-AEB541946DF8}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_fast_fwd", "test\test_fast_fwd\test_fast_fwd.vcxproj", "{303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}"
ProjectSection(ProjectDependencies) = postProject
{D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4}
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8} = {0E0ACA62-A92F-44CF-BD41-AEB541946DF8}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fast_fwd", "fast_fwd\fast_fwd.vcxproj", "{A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scratch", "scratch\scratch.vcxproj", "{E893622C-47DE-4F83-B422-0A26711590A4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_module_lock_none", "test\test_module_lock_none\test_module_lock_none.vcxproj", "{D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}"
ProjectSection(ProjectDependencies) = postProject
{D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_module_lock_custom", "test\test_module_lock_custom\test_module_lock_custom.vcxproj", "{08C40663-B6A3-481E-8755-AE32BAD99501}"
ProjectSection(ProjectDependencies) = postProject
{D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{3C7EA5F8-6E8C-4376-B499-2CAF596384B0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|ARM = Release|ARM
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D613FB39-5035-4043-91E2-BAB323908AF4}.Debug|ARM.ActiveCfg = Debug|Win32
{D613FB39-5035-4043-91E2-BAB323908AF4}.Debug|ARM64.ActiveCfg = Debug|Win32
{D613FB39-5035-4043-91E2-BAB323908AF4}.Debug|x64.ActiveCfg = Debug|x64
{D613FB39-5035-4043-91E2-BAB323908AF4}.Debug|x64.Build.0 = Debug|x64
{D613FB39-5035-4043-91E2-BAB323908AF4}.Debug|x86.ActiveCfg = Debug|Win32
{D613FB39-5035-4043-91E2-BAB323908AF4}.Debug|x86.Build.0 = Debug|Win32
{D613FB39-5035-4043-91E2-BAB323908AF4}.Release|ARM.ActiveCfg = Release|Win32
{D613FB39-5035-4043-91E2-BAB323908AF4}.Release|ARM64.ActiveCfg = Release|Win32
{D613FB39-5035-4043-91E2-BAB323908AF4}.Release|x64.ActiveCfg = Release|x64
{D613FB39-5035-4043-91E2-BAB323908AF4}.Release|x64.Build.0 = Release|x64
{D613FB39-5035-4043-91E2-BAB323908AF4}.Release|x86.ActiveCfg = Release|Win32
{D613FB39-5035-4043-91E2-BAB323908AF4}.Release|x86.Build.0 = Release|Win32
{FB239623-7D19-4025-BCEA-B43298D4A315}.Debug|ARM.ActiveCfg = Debug|Win32
{FB239623-7D19-4025-BCEA-B43298D4A315}.Debug|ARM64.ActiveCfg = Debug|Win32
{FB239623-7D19-4025-BCEA-B43298D4A315}.Debug|x64.ActiveCfg = Debug|x64
{FB239623-7D19-4025-BCEA-B43298D4A315}.Debug|x64.Build.0 = Debug|x64
{FB239623-7D19-4025-BCEA-B43298D4A315}.Debug|x86.ActiveCfg = Debug|Win32
{FB239623-7D19-4025-BCEA-B43298D4A315}.Debug|x86.Build.0 = Debug|Win32
{FB239623-7D19-4025-BCEA-B43298D4A315}.Release|ARM.ActiveCfg = Release|Win32
{FB239623-7D19-4025-BCEA-B43298D4A315}.Release|ARM64.ActiveCfg = Release|Win32
{FB239623-7D19-4025-BCEA-B43298D4A315}.Release|x64.ActiveCfg = Release|x64
{FB239623-7D19-4025-BCEA-B43298D4A315}.Release|x64.Build.0 = Release|x64
{FB239623-7D19-4025-BCEA-B43298D4A315}.Release|x86.ActiveCfg = Release|Win32
{FB239623-7D19-4025-BCEA-B43298D4A315}.Release|x86.Build.0 = Release|Win32
{C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Debug|ARM.ActiveCfg = Debug|Win32
{C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Debug|ARM64.ActiveCfg = Debug|Win32
{C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Debug|x64.ActiveCfg = Debug|x64
{C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Debug|x64.Build.0 = Debug|x64
{C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Debug|x86.ActiveCfg = Debug|Win32
{C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Debug|x86.Build.0 = Debug|Win32
{C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Release|ARM.ActiveCfg = Release|Win32
{C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Release|ARM64.ActiveCfg = Release|Win32
{C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Release|x64.ActiveCfg = Release|x64
{C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Release|x64.Build.0 = Release|x64
{C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Release|x86.ActiveCfg = Release|Win32
{C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Release|x86.Build.0 = Release|Win32
{559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Debug|ARM.ActiveCfg = Debug|Win32
{559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Debug|ARM64.ActiveCfg = Debug|Win32
{559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Debug|x64.ActiveCfg = Debug|x64
{559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Debug|x64.Build.0 = Debug|x64
{559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Debug|x86.ActiveCfg = Debug|Win32
{559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Debug|x86.Build.0 = Debug|Win32
{559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Release|ARM.ActiveCfg = Release|Win32
{559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Release|ARM64.ActiveCfg = Release|Win32
{559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Release|x64.ActiveCfg = Release|x64
{559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Release|x64.Build.0 = Release|x64
{559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Release|x86.ActiveCfg = Release|Win32
{559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Release|x86.Build.0 = Release|Win32
{152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Debug|ARM.ActiveCfg = Debug|Win32
{152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Debug|ARM64.ActiveCfg = Debug|Win32
{152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Debug|x64.ActiveCfg = Debug|x64
{152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Debug|x64.Build.0 = Debug|x64
{152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Debug|x86.ActiveCfg = Debug|Win32
{152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Debug|x86.Build.0 = Debug|Win32
{152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Release|ARM.ActiveCfg = Release|Win32
{152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Release|ARM64.ActiveCfg = Release|Win32
{152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Release|x64.ActiveCfg = Release|x64
{152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Release|x64.Build.0 = Release|x64
{152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Release|x86.ActiveCfg = Release|Win32
{152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Release|x86.Build.0 = Release|Win32
{A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Debug|ARM.ActiveCfg = Debug|Win32
{A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Debug|ARM64.ActiveCfg = Debug|Win32
{A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Debug|x64.ActiveCfg = Debug|x64
{A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Debug|x64.Build.0 = Debug|x64
{A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Debug|x86.ActiveCfg = Debug|Win32
{A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Debug|x86.Build.0 = Debug|Win32
{A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Release|ARM.ActiveCfg = Release|Win32
{A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Release|ARM64.ActiveCfg = Release|Win32
{A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Release|x64.ActiveCfg = Release|x64
{A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Release|x64.Build.0 = Release|x64
{A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Release|x86.ActiveCfg = Release|Win32
{A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Release|x86.Build.0 = Release|Win32
{D2961EA1-A8CA-4A62-B760-948403DC8494}.Debug|ARM.ActiveCfg = Debug|Win32
{D2961EA1-A8CA-4A62-B760-948403DC8494}.Debug|ARM64.ActiveCfg = Debug|Win32
{D2961EA1-A8CA-4A62-B760-948403DC8494}.Debug|x64.ActiveCfg = Debug|x64
{D2961EA1-A8CA-4A62-B760-948403DC8494}.Debug|x64.Build.0 = Debug|x64
{D2961EA1-A8CA-4A62-B760-948403DC8494}.Debug|x86.ActiveCfg = Debug|Win32
{D2961EA1-A8CA-4A62-B760-948403DC8494}.Debug|x86.Build.0 = Debug|Win32
{D2961EA1-A8CA-4A62-B760-948403DC8494}.Release|ARM.ActiveCfg = Release|Win32
{D2961EA1-A8CA-4A62-B760-948403DC8494}.Release|ARM64.ActiveCfg = Release|Win32
{D2961EA1-A8CA-4A62-B760-948403DC8494}.Release|x64.ActiveCfg = Release|x64
{D2961EA1-A8CA-4A62-B760-948403DC8494}.Release|x64.Build.0 = Release|x64
{D2961EA1-A8CA-4A62-B760-948403DC8494}.Release|x86.ActiveCfg = Release|Win32
{D2961EA1-A8CA-4A62-B760-948403DC8494}.Release|x86.Build.0 = Release|Win32
{85695954-3800-4558-9857-966E69E9F9EC}.Debug|ARM.ActiveCfg = Debug|Win32
{85695954-3800-4558-9857-966E69E9F9EC}.Debug|ARM64.ActiveCfg = Debug|Win32
{85695954-3800-4558-9857-966E69E9F9EC}.Debug|x64.ActiveCfg = Debug|x64
{85695954-3800-4558-9857-966E69E9F9EC}.Debug|x64.Build.0 = Debug|x64
{85695954-3800-4558-9857-966E69E9F9EC}.Debug|x86.ActiveCfg = Debug|Win32
{85695954-3800-4558-9857-966E69E9F9EC}.Debug|x86.Build.0 = Debug|Win32
{85695954-3800-4558-9857-966E69E9F9EC}.Release|ARM.ActiveCfg = Release|Win32
{85695954-3800-4558-9857-966E69E9F9EC}.Release|ARM64.ActiveCfg = Release|Win32
{85695954-3800-4558-9857-966E69E9F9EC}.Release|x64.ActiveCfg = Release|x64
{85695954-3800-4558-9857-966E69E9F9EC}.Release|x64.Build.0 = Release|x64
{85695954-3800-4558-9857-966E69E9F9EC}.Release|x86.ActiveCfg = Release|Win32
{85695954-3800-4558-9857-966E69E9F9EC}.Release|x86.Build.0 = Release|Win32
{F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Debug|ARM.ActiveCfg = Debug|Win32
{F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Debug|ARM64.ActiveCfg = Debug|Win32
{F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Debug|x64.ActiveCfg = Debug|x64
{F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Debug|x64.Build.0 = Debug|x64
{F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Debug|x86.ActiveCfg = Debug|Win32
{F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Debug|x86.Build.0 = Debug|Win32
{F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Release|ARM.ActiveCfg = Release|Win32
{F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Release|ARM64.ActiveCfg = Release|Win32
{F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Release|x64.ActiveCfg = Release|x64
{F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Release|x64.Build.0 = Release|x64
{F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Release|x86.ActiveCfg = Release|Win32
{F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Release|x86.Build.0 = Release|Win32
{13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|ARM.ActiveCfg = Debug|Win32
{13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|ARM64.ActiveCfg = Debug|Win32
{13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|x64.ActiveCfg = Debug|x64
{13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|x64.Build.0 = Debug|x64
{13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|x86.ActiveCfg = Debug|Win32
{13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|x86.Build.0 = Debug|Win32
{13333A6F-6A4A-48CD-865C-0F65135EB018}.Release|ARM.ActiveCfg = Release|Win32
{13333A6F-6A4A-48CD-865C-0F65135EB018}.Release|ARM64.ActiveCfg = Release|Win32
{13333A6F-6A4A-48CD-865C-0F65135EB018}.Release|x64.ActiveCfg = Release|x64
{13333A6F-6A4A-48CD-865C-0F65135EB018}.Release|x64.Build.0 = Release|x64
{13333A6F-6A4A-48CD-865C-0F65135EB018}.Release|x86.ActiveCfg = Release|Win32
{13333A6F-6A4A-48CD-865C-0F65135EB018}.Release|x86.Build.0 = Release|Win32
{0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Debug|ARM.ActiveCfg = Debug|Win32
{0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Debug|ARM64.ActiveCfg = Debug|Win32
{0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Debug|x64.ActiveCfg = Debug|x64
{0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Debug|x64.Build.0 = Debug|x64
{0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Debug|x86.ActiveCfg = Debug|Win32
{0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Debug|x86.Build.0 = Debug|Win32
{0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Release|ARM.ActiveCfg = Release|Win32
{0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Release|ARM64.ActiveCfg = Release|Win32
{0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Release|x64.ActiveCfg = Release|x64
{0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Release|x64.Build.0 = Release|x64
{0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Release|x86.ActiveCfg = Release|Win32
{0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Release|x86.Build.0 = Release|Win32
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Debug|ARM.ActiveCfg = Debug|Win32
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Debug|ARM.Build.0 = Debug|Win32
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Debug|ARM64.ActiveCfg = Debug|Win32
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Debug|ARM64.Build.0 = Debug|Win32
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Debug|x64.ActiveCfg = Debug|x64
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Debug|x64.Build.0 = Debug|x64
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Debug|x86.ActiveCfg = Debug|Win32
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Debug|x86.Build.0 = Debug|Win32
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Release|ARM.ActiveCfg = Release|Win32
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Release|ARM.Build.0 = Release|Win32
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Release|ARM64.ActiveCfg = Release|Win32
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Release|ARM64.Build.0 = Release|Win32
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Release|x64.ActiveCfg = Release|x64
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Release|x64.Build.0 = Release|x64
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Release|x86.ActiveCfg = Release|Win32
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Release|x86.Build.0 = Release|Win32
{F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Debug|ARM.ActiveCfg = Debug|Win32
{F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Debug|ARM64.ActiveCfg = Debug|Win32
{F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Debug|x64.ActiveCfg = Debug|x64
{F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Debug|x64.Build.0 = Debug|x64
{F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Debug|x86.ActiveCfg = Debug|Win32
{F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Debug|x86.Build.0 = Debug|Win32
{F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Release|ARM.ActiveCfg = Release|Win32
{F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Release|ARM64.ActiveCfg = Release|Win32
{F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Release|x64.ActiveCfg = Release|x64
{F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Release|x64.Build.0 = Release|x64
{F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Release|x86.ActiveCfg = Release|Win32
{F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Release|x86.Build.0 = Release|Win32
{B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Debug|ARM.ActiveCfg = Debug|Win32
{B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Debug|ARM64.ActiveCfg = Debug|Win32
{B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Debug|x64.ActiveCfg = Debug|x64
{B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Debug|x64.Build.0 = Debug|x64
{B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Debug|x86.ActiveCfg = Debug|Win32
{B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Debug|x86.Build.0 = Debug|Win32
{B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Release|ARM.ActiveCfg = Release|Win32
{B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Release|ARM64.ActiveCfg = Release|Win32
{B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Release|x64.ActiveCfg = Release|x64
{B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Release|x64.Build.0 = Release|x64
{B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Release|x86.ActiveCfg = Release|Win32
{B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Release|x86.Build.0 = Release|Win32
{303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Debug|ARM.ActiveCfg = Debug|ARM
{303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Debug|ARM.Build.0 = Debug|ARM
{303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Debug|ARM64.ActiveCfg = Debug|ARM64
{303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Debug|ARM64.Build.0 = Debug|ARM64
{303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Debug|x64.ActiveCfg = Debug|x64
{303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Debug|x64.Build.0 = Debug|x64
{303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Debug|x86.ActiveCfg = Debug|Win32
{303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Debug|x86.Build.0 = Debug|Win32
{303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Release|ARM.ActiveCfg = Release|ARM
{303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Release|ARM.Build.0 = Release|ARM
{303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Release|ARM64.ActiveCfg = Release|ARM64
{303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Release|ARM64.Build.0 = Release|ARM64
{303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Release|x64.ActiveCfg = Release|x64
{303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Release|x64.Build.0 = Release|x64
{303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Release|x86.ActiveCfg = Release|Win32
{303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Release|x86.Build.0 = Release|Win32
{A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Debug|ARM.ActiveCfg = Debug|ARM
{A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Debug|ARM.Build.0 = Debug|ARM
{A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Debug|ARM64.ActiveCfg = Debug|ARM64
{A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Debug|ARM64.Build.0 = Debug|ARM64
{A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Debug|x64.ActiveCfg = Debug|x64
{A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Debug|x64.Build.0 = Debug|x64
{A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Debug|x86.ActiveCfg = Debug|Win32
{A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Debug|x86.Build.0 = Debug|Win32
{A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Release|ARM.ActiveCfg = Release|ARM
{A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Release|ARM.Build.0 = Release|ARM
{A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Release|ARM64.ActiveCfg = Release|ARM64
{A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Release|ARM64.Build.0 = Release|ARM64
{A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Release|x64.ActiveCfg = Release|x64
{A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Release|x64.Build.0 = Release|x64
{A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Release|x86.ActiveCfg = Release|Win32
{A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Release|x86.Build.0 = Release|Win32
{E893622C-47DE-4F83-B422-0A26711590A4}.Debug|ARM.ActiveCfg = Debug|Win32
{E893622C-47DE-4F83-B422-0A26711590A4}.Debug|ARM64.ActiveCfg = Debug|Win32
{E893622C-47DE-4F83-B422-0A26711590A4}.Debug|x64.ActiveCfg = Debug|x64
{E893622C-47DE-4F83-B422-0A26711590A4}.Debug|x64.Build.0 = Debug|x64
{E893622C-47DE-4F83-B422-0A26711590A4}.Debug|x86.ActiveCfg = Debug|Win32
{E893622C-47DE-4F83-B422-0A26711590A4}.Debug|x86.Build.0 = Debug|Win32
{E893622C-47DE-4F83-B422-0A26711590A4}.Release|ARM.ActiveCfg = Release|Win32
{E893622C-47DE-4F83-B422-0A26711590A4}.Release|ARM64.ActiveCfg = Release|Win32
{E893622C-47DE-4F83-B422-0A26711590A4}.Release|x64.ActiveCfg = Release|x64
{E893622C-47DE-4F83-B422-0A26711590A4}.Release|x64.Build.0 = Release|x64
{E893622C-47DE-4F83-B422-0A26711590A4}.Release|x86.ActiveCfg = Release|Win32
{E893622C-47DE-4F83-B422-0A26711590A4}.Release|x86.Build.0 = Release|Win32
{D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Debug|ARM.ActiveCfg = Debug|Win32
{D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Debug|ARM64.ActiveCfg = Debug|Win32
{D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Debug|x64.ActiveCfg = Debug|x64
{D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Debug|x64.Build.0 = Debug|x64
{D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Debug|x86.ActiveCfg = Debug|Win32
{D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Debug|x86.Build.0 = Debug|Win32
{D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Release|ARM.ActiveCfg = Release|Win32
{D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Release|ARM64.ActiveCfg = Release|Win32
{D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Release|x64.ActiveCfg = Release|x64
{D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Release|x64.Build.0 = Release|x64
{D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Release|x86.ActiveCfg = Release|Win32
{D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Release|x86.Build.0 = Release|Win32
{08C40663-B6A3-481E-8755-AE32BAD99501}.Debug|ARM.ActiveCfg = Debug|Win32
{08C40663-B6A3-481E-8755-AE32BAD99501}.Debug|ARM64.ActiveCfg = Debug|Win32
{08C40663-B6A3-481E-8755-AE32BAD99501}.Debug|x64.ActiveCfg = Debug|x64
{08C40663-B6A3-481E-8755-AE32BAD99501}.Debug|x64.Build.0 = Debug|x64
{08C40663-B6A3-481E-8755-AE32BAD99501}.Debug|x86.ActiveCfg = Debug|Win32
{08C40663-B6A3-481E-8755-AE32BAD99501}.Debug|x86.Build.0 = Debug|Win32
{08C40663-B6A3-481E-8755-AE32BAD99501}.Release|ARM.ActiveCfg = Release|Win32
{08C40663-B6A3-481E-8755-AE32BAD99501}.Release|ARM64.ActiveCfg = Release|Win32
{08C40663-B6A3-481E-8755-AE32BAD99501}.Release|x64.ActiveCfg = Release|x64
{08C40663-B6A3-481E-8755-AE32BAD99501}.Release|x64.Build.0 = Release|x64
{08C40663-B6A3-481E-8755-AE32BAD99501}.Release|x86.ActiveCfg = Release|Win32
{08C40663-B6A3-481E-8755-AE32BAD99501}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{515B4F38-FD07-4C8B-94D0-BE3A813BB3EE} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0}
{C8B95FCB-9B0B-4E9F-B7D5-643883C192C9} = {515B4F38-FD07-4C8B-94D0-BE3A813BB3EE}
{559A7CF4-DC5F-4D62-BA6B-0C2B025593F8} = {515B4F38-FD07-4C8B-94D0-BE3A813BB3EE}
{152E4C6E-9A9D-4D5A-B38D-4905D173649A} = {515B4F38-FD07-4C8B-94D0-BE3A813BB3EE}
{A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0}
{D2961EA1-A8CA-4A62-B760-948403DC8494} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0}
{85695954-3800-4558-9857-966E69E9F9EC} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0}
{F1C915B3-2C64-4992-AFB7-7F035B1A7607} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0}
{13333A6F-6A4A-48CD-865C-0F65135EB018} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0}
{0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0}
{0E0ACA62-A92F-44CF-BD41-AEB541946DF8} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0}
{F8A1FE5A-DC8A-49DF-B882-DEF76E38E484} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0}
{B68C61C6-4699-41E6-A158-EA1BE029E7A0} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0}
{303CC0FE-7D66-4F9F-B7A1-0AF7F9359074} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0}
{D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0}
{08C40663-B6A3-481E-8755-AE32BAD99501} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2783B8FD-EA3B-4D6B-9F81-662D289E02AA}
EndGlobalSection
EndGlobal

3138
cppwinrt/code_writers.h Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

1211
cppwinrt/component_writers.h Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

231
cppwinrt/cppwinrt.vcxproj Normal file
Просмотреть файл

@ -0,0 +1,231 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Microsoft.Windows.WinMD.1.0.191006.1\build\native\Microsoft.Windows.WinMD.props" Condition="Exists('..\packages\Microsoft.Windows.WinMD.1.0.191006.1\build\native\Microsoft.Windows.WinMD.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\strings\base_abi.h" />
<ClInclude Include="..\strings\base_activation.h" />
<ClInclude Include="..\strings\base_agile_ref.h" />
<ClInclude Include="..\strings\base_array.h" />
<ClInclude Include="..\strings\base_chrono.h" />
<ClInclude Include="..\strings\base_collections.h" />
<ClInclude Include="..\strings\base_collections_base.h" />
<ClInclude Include="..\strings\base_collections_input_iterable.h" />
<ClInclude Include="..\strings\base_collections_input_map.h" />
<ClInclude Include="..\strings\base_collections_input_map_view.h" />
<ClInclude Include="..\strings\base_collections_input_vector.h" />
<ClInclude Include="..\strings\base_collections_input_vector_view.h" />
<ClInclude Include="..\strings\base_collections_map.h" />
<ClInclude Include="..\strings\base_collections_vector.h" />
<ClInclude Include="..\strings\base_composable.h" />
<ClInclude Include="..\strings\base_com_ptr.h" />
<ClInclude Include="..\strings\base_coroutine.h" />
<ClInclude Include="..\strings\base_coroutine_foundation.h" />
<ClInclude Include="..\strings\base_coroutine_system.h" />
<ClInclude Include="..\strings\base_coroutine_threadpool.h" />
<ClInclude Include="..\strings\base_coroutine_ui_core.h" />
<ClInclude Include="..\strings\base_deferral.h" />
<ClInclude Include="..\strings\base_delegate.h" />
<ClInclude Include="..\strings\base_dependencies.h" />
<ClInclude Include="..\strings\base_error.h" />
<ClInclude Include="..\strings\base_events.h" />
<ClInclude Include="..\strings\base_extern.h" />
<ClInclude Include="..\strings\base_fast_forward.h" />
<ClInclude Include="..\strings\base_foundation.h" />
<ClInclude Include="..\strings\base_handle.h" />
<ClInclude Include="..\strings\base_identity.h" />
<ClInclude Include="..\strings\base_implements.h" />
<ClInclude Include="..\strings\base_lock.h" />
<ClInclude Include="..\strings\base_macros.h" />
<ClInclude Include="..\strings\base_marshaler.h" />
<ClInclude Include="..\strings\base_meta.h" />
<ClInclude Include="..\strings\base_natvis.h" />
<ClInclude Include="..\strings\base_reference_produce.h" />
<ClInclude Include="..\strings\base_security.h" />
<ClInclude Include="..\strings\base_std_hash.h" />
<ClInclude Include="..\strings\base_string.h" />
<ClInclude Include="..\strings\base_string_input.h" />
<ClInclude Include="..\strings\base_string_operators.h" />
<ClInclude Include="..\strings\base_types.h" />
<ClInclude Include="..\strings\base_version.h" />
<ClInclude Include="..\strings\base_weak_ref.h" />
<ClInclude Include="..\strings\base_windows.h" />
<ClInclude Include="..\strings\base_xaml_typename.h" />
<ClInclude Include="code_writers.h" />
<ClInclude Include="component_writers.h" />
<ClInclude Include="file_writers.h" />
<ClInclude Include="helpers.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="settings.h" />
<ClInclude Include="type_writers.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(OutDir)strings.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="main.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="$(OutDir)version.rc" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{D613FB39-5035-4043-91E2-BAB323908AF4}</ProjectGuid>
<RootNamespace>cppwinrt</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(SolutionDir)\cppwinrt.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IntDir>$(OutDir)temp\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IntDir>$(OutDir)temp\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IntDir>$(OutDir)temp\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IntDir>$(OutDir)temp\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\inc;$(OutputPath);$(WinMDPackageDir);</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
</Link>
<PreBuildEvent>
<Command>$(OutputPath)prebuild.exe ..\strings $(OutputPath)</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\inc;$(OutputPath);$(WinMDPackageDir);</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
</Link>
<PreBuildEvent>
<Command>$(OutputPath)prebuild.exe ..\strings $(OutputPath)</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\inc;$(OutputPath);$(WinMDPackageDir);</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<PreBuildEvent>
<Command>$(OutputPath)prebuild.exe ..\strings $(OutputPath)</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\inc;$(OutputPath);$(WinMDPackageDir);</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<PreBuildEvent>
<Command>$(OutputPath)prebuild.exe ..\strings $(OutputPath)</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Microsoft.Windows.WinMD.1.0.191006.1\build\native\Microsoft.Windows.WinMD.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.WinMD.1.0.191006.1\build\native\Microsoft.Windows.WinMD.props'))" />
</Target>
</Project>

Просмотреть файл

@ -0,0 +1,172 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="main.cpp" />
<ClCompile Include="pch.cpp" />
<ClCompile Include="$(OutDir)strings.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="code_writers.h" />
<ClInclude Include="component_writers.h" />
<ClInclude Include="file_writers.h" />
<ClInclude Include="helpers.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="settings.h" />
<ClInclude Include="type_writers.h" />
<ClInclude Include="..\strings\base_abi.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_activation.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_agile_ref.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_array.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_chrono.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_collections.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_collections_base.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_collections_input_iterable.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_collections_input_map.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_collections_input_map_view.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_collections_input_vector.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_collections_input_vector_view.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_collections_map.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_collections_vector.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_com_ptr.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_composable.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_coroutine_foundation.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_coroutine_system.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_coroutine_threadpool.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_coroutine_ui_core.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_delegate.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_dependencies.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_error.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_events.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_extern.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_foundation.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_handle.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_identity.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_implements.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_lock.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_macros.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_marshaler.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_meta.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_natvis.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_reference_produce.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_security.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_std_hash.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_string.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_string_input.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_string_operators.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_types.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_version.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_weak_ref.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_windows.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_xaml_typename.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_fast_forward.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_coroutine.h">
<Filter>strings</Filter>
</ClInclude>
<ClInclude Include="..\strings\base_deferral.h">
<Filter>strings</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="$(OutDir)version.rc" />
</ItemGroup>
<ItemGroup>
<Filter Include="strings">
<UniqueIdentifier>{2eff9026-81b1-4243-9983-b055bd61534c}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

305
cppwinrt/file_writers.h Normal file
Просмотреть файл

@ -0,0 +1,305 @@
#pragma once
namespace xlang
{
static void write_base_h()
{
writer w;
write_preamble(w);
write_open_file_guard(w, "BASE");
w.write(strings::base_dependencies);
w.write(strings::base_coroutine);
w.write(strings::base_macros);
w.write(strings::base_types);
w.write(strings::base_extern);
w.write(strings::base_meta);
w.write(strings::base_identity);
w.write(strings::base_handle);
w.write(strings::base_lock);
w.write(strings::base_abi);
w.write(strings::base_windows);
w.write(strings::base_com_ptr);
w.write(strings::base_string);
w.write(strings::base_string_input);
w.write(strings::base_string_operators);
w.write(strings::base_array);
w.write(strings::base_weak_ref);
w.write(strings::base_agile_ref);
w.write(strings::base_error);
w.write(strings::base_marshaler);
w.write(strings::base_delegate);
w.write(strings::base_events);
w.write(strings::base_activation);
w.write(strings::base_implements);
w.write(strings::base_composable);
w.write(strings::base_foundation);
w.write(strings::base_chrono);
w.write(strings::base_security);
w.write(strings::base_std_hash);
w.write(strings::base_coroutine_threadpool);
w.write(strings::base_natvis);
w.write(strings::base_version, XLANG_VERSION_STRING);
write_endif(w);
w.flush_to_file(settings.output_folder + "winrt/base.h");
}
static void write_fast_forward_h(std::vector<TypeDef> const& classes)
{
writer w;
write_preamble(w);
write_open_file_guard(w, "FAST_FORWARD");
auto const fast_abi_size = get_fastabi_size(w, classes);
w.write(strings::base_fast_forward,
fast_abi_size,
fast_abi_size,
bind<write_component_fast_abi_thunk>(),
bind<write_component_fast_abi_vtable>());
write_endif(w);
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)
{
writer w;
w.type_namespace = ns;
write_type_namespace(w, ns);
w.write_each<write_enum>(members.enums);
w.write_each<write_forward>(members.interfaces);
w.write_each<write_forward>(members.classes);
w.write_each<write_forward>(members.structs);
w.write_each<write_forward>(members.delegates);
write_close_namespace(w);
write_impl_namespace(w);
w.write_each<write_category>(members.interfaces, "interface_category");
w.write_each<write_category>(members.classes, "class_category");
w.write_each<write_category>(members.enums, "enum_category");
w.write_each<write_struct_category>(members.structs);
w.write_each<write_category>(members.delegates, "delegate_category");
// Class names are always required for activation.
// Class, enum, and struct names are required for producing GUIDs for generic types.
// Interface and delegates names are not required by WinRT.
w.write_each<write_name>(members.classes);
w.write_each<write_name>(members.enums);
w.write_each<write_name>(members.structs);
write_lean_and_mean(w);
w.write_each<write_name>(members.interfaces);
w.write_each<write_name>(members.delegates);
write_endif(w);
w.write_each<write_guid>(members.interfaces);
w.write_each<write_guid>(members.delegates);
w.write_each<write_default_interface>(members.classes);
w.write_each<write_interface_abi>(members.interfaces);
w.write_each<write_delegate_abi>(members.delegates);
w.write_each<write_consume>(members.interfaces);
w.write_each<write_struct_abi>(members.structs);
write_close_namespace(w);
write_endif(w);
w.swap();
write_preamble(w);
write_open_file_guard(w, ns, '0');
for (auto&& depends : w.depends)
{
write_type_namespace(w, depends.first);
w.write_each<write_forward>(depends.second);
write_close_namespace(w);
}
w.save_header('0');
}
static void write_namespace_1_h(std::string_view const& ns, cache::namespace_members const& members)
{
writer w;
w.type_namespace = ns;
write_type_namespace(w, ns);
w.write_each<write_interface>(members.interfaces);
write_close_namespace(w);
write_endif(w);
w.swap();
write_preamble(w);
write_open_file_guard(w, ns, '1');
for (auto&& depends : w.depends)
{
w.write_depends(depends.first, '0');
}
w.write_depends(w.type_namespace, '0');
w.save_header('1');
}
static void write_namespace_2_h(std::string_view const& ns, cache::namespace_members const& members)
{
writer w;
w.type_namespace = ns;
write_type_namespace(w, ns);
w.write_each<write_delegate>(members.delegates);
bool const promote = write_structs(w, members.structs);
w.write_each<write_class>(members.classes);
w.write_each<write_interface_override>(members.classes);
write_close_namespace(w);
write_endif(w);
w.swap();
write_preamble(w);
write_open_file_guard(w, ns, '2');
char const impl = promote ? '2' : '1';
for (auto&& depends : w.depends)
{
w.write_depends(depends.first, impl);
}
w.write_depends(w.type_namespace, '1');
w.save_header('2');
}
static void write_namespace_h(cache const& c, std::string_view const& ns, cache::namespace_members const& members)
{
writer w;
w.type_namespace = ns;
write_impl_namespace(w);
w.write_each<write_consume_definitions>(members.interfaces);
w.write_each<write_delegate_implementation>(members.delegates);
w.write_each<write_produce>(members.interfaces);
w.write_each<write_dispatch_overridable>(members.classes);
write_close_namespace(w);
write_type_namespace(w, ns);
w.write_each<write_enum_operators>(members.enums);
w.write_each<write_class_definitions>(members.classes);
w.write_each<write_fast_class_base_definitions>(members.classes);
w.write_each<write_delegate_definition>(members.delegates);
w.write_each<write_interface_override_methods>(members.classes);
w.write_each<write_class_override>(members.classes);
write_close_namespace(w);
write_std_namespace(w);
write_lean_and_mean(w);
w.write_each<write_std_hash>(members.interfaces);
w.write_each<write_std_hash>(members.classes);
write_endif(w);
write_close_namespace(w);
write_namespace_special(w, ns, c);
write_endif(w);
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_depends(depends.first, '2');
}
w.write_depends(w.type_namespace, '2');
w.save_header();
}
static void write_module_g_cpp(std::vector<TypeDef> const& classes)
{
writer w;
write_preamble(w);
write_pch(w);
write_module_g_cpp(w, classes);
w.flush_to_file(settings.output_folder + "module.g.cpp");
}
static void write_component_g_h(TypeDef const& type)
{
writer w;
w.add_depends(type);
write_component_g_h(w, type);
w.swap();
write_preamble(w);
write_include_guard(w);
for (auto&& depends : w.depends)
{
w.write_depends(depends.first);
}
auto filename = settings.output_folder + get_generated_component_filename(type) + ".g.h";
path folder = filename;
folder.remove_filename();
create_directories(folder);
w.flush_to_file(filename);
}
static void write_component_g_cpp(TypeDef const& type)
{
if (!settings.component_opt)
{
return;
}
writer w;
write_preamble(w);
write_component_g_cpp(w, type);
auto filename = settings.output_folder + get_generated_component_filename(type) + ".g.cpp";
path folder = filename;
folder.remove_filename();
create_directories(folder);
w.flush_to_file(filename);
}
static void write_component_h(TypeDef const& type)
{
if (settings.component_folder.empty())
{
return;
}
auto path = settings.component_folder + get_component_filename(type) + ".h";
if (!settings.component_overwrite && exists(path))
{
return;
}
writer w;
write_include_guard(w);
write_component_h(w, type);
w.flush_to_file(path);
}
static void write_component_cpp(TypeDef const& type)
{
if (settings.component_folder.empty())
{
return;
}
auto path = settings.component_folder + get_component_filename(type) + ".cpp";
if (!settings.component_overwrite && exists(path))
{
return;
}
writer w;
write_pch(w);
write_component_cpp(w, type);
w.flush_to_file(path);
}
}

887
cppwinrt/helpers.h Normal file
Просмотреть файл

@ -0,0 +1,887 @@
#pragma once
namespace xlang
{
static auto get_start_time()
{
return std::chrono::high_resolution_clock::now();
}
static auto get_elapsed_time(decltype(get_start_time()) const& start)
{
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start).count();
}
[[noreturn]] inline void throw_invalid(std::string const& message)
{
throw std::invalid_argument(message);
}
template <typename...T>
[[noreturn]] inline void throw_invalid(std::string message, T const&... args)
{
(message.append(args), ...);
throw std::invalid_argument(message);
}
static bool is_put_overload(MethodDef const& method)
{
return method.SpecialName() && starts_with(method.Name(), "put_");
}
struct method_signature
{
explicit method_signature(MethodDef const& method) :
m_method(method),
m_signature(method.Signature())
{
auto params = method.ParamList();
if (m_signature.ReturnType() && params.first != params.second && params.first.Sequence() == 0)
{
m_return = params.first;
++params.first;
}
for (uint32_t i{}; i != size(m_signature.Params()); ++i)
{
m_params.emplace_back(params.first + i, &m_signature.Params().first[i]);
}
}
std::vector<std::pair<Param, ParamSig const*>>& params()
{
return m_params;
}
std::vector<std::pair<Param, ParamSig const*>> const& params() const
{
return m_params;
}
auto const& return_signature() const
{
return m_signature.ReturnType();
}
auto return_param_name() const
{
std::string_view name;
if (m_return)
{
name = m_return.Name();
}
else
{
name = "winrt_impl_result";
}
return name;
}
MethodDef const& method() const
{
return m_method;
}
bool is_async() const
{
// WinRT parameter passing conventions include the notion that input parameters of collection types may be read
// or copied but should not be stored directly since this would lead to instability as the collection is shared
// by the caller and callee. The exception to this rule is property setters where the callee may simply store a
// reference to the collection. The collection thus becomes async in the sense that it is expected to remain
// valid beyond the duration of the call.
if (is_put_overload(m_method))
{
return true;
}
if (!m_signature.ReturnType())
{
return false;
}
bool async{};
call(m_signature.ReturnType().Type().Type(),
[&](coded_index<TypeDefOrRef> const& type)
{
auto const& [type_namespace, type_name] = get_type_namespace_and_name(type);
async = type_namespace == "Windows.Foundation" && type_name == "IAsyncAction";
},
[&](GenericTypeInstSig const& type)
{
auto const& [type_namespace, type_name] = get_type_namespace_and_name(type.GenericType());
if (type_namespace == "Windows.Foundation")
{
async =
type_name == "IAsyncOperation`1" ||
type_name == "IAsyncActionWithProgress`1" ||
type_name == "IAsyncOperationWithProgress`2";
}
},
[](auto&&) {});
return async;
}
private:
MethodDef m_method;
MethodDefSig m_signature;
std::vector<std::pair<Param, ParamSig const*>> m_params;
Param m_return;
};
struct separator
{
writer& w;
bool first{ true };
void operator()()
{
if (first)
{
first = false;
}
else
{
w.write(", ");
}
}
};
template <typename T>
bool has_attribute(T const& row, std::string_view const& type_namespace, std::string_view const& type_name)
{
return static_cast<bool>(get_attribute(row, type_namespace, type_name));
}
template <typename T>
auto get_attribute_value(CustomAttribute const& attribute, uint32_t const arg)
{
return std::get<T>(std::get<ElemSig>(attribute.Value().FixedArgs()[arg].value).value);
}
static auto get_abi_name(MethodDef const& method)
{
if (auto overload = get_attribute(method, "Windows.Foundation.Metadata", "OverloadAttribute"))
{
return get_attribute_value<std::string_view>(overload, 0);
}
else
{
return method.Name();
}
}
static auto get_name(MethodDef const& method)
{
auto name = method.Name();
if (method.SpecialName())
{
return name.substr(name.find('_') + 1);
}
return name;
}
static bool is_remove_overload(MethodDef const& method)
{
return method.SpecialName() && starts_with(method.Name(), "remove_");
}
static bool is_add_overload(MethodDef const& method)
{
return method.SpecialName() && starts_with(method.Name(), "add_");
}
static bool is_get_overload(MethodDef const& method)
{
return method.SpecialName() && starts_with(method.Name(), "get_");
}
static bool is_noexcept(MethodDef const& method)
{
return is_remove_overload(method) || has_attribute(method, "Windows.Foundation.Metadata", "NoExceptionAttribute");
}
static bool has_fastabi(TypeDef const& type)
{
return settings.fastabi && has_attribute(type, "Windows.Foundation.Metadata", "FastAbiAttribute");
}
static bool is_always_disabled(TypeDef const& type)
{
if (settings.component_ignore_velocity)
{
return false;
}
auto feature = get_attribute(type, "Windows.Foundation.Metadata", "FeatureAttribute");
if (!feature)
{
return false;
}
auto stage = get_attribute_value<ElemSig::EnumValue>(feature, 0);
return stage.equals_enumerator("AlwaysDisabled");
}
static bool is_always_enabled(TypeDef const& type)
{
auto feature = get_attribute(type, "Windows.Foundation.Metadata", "FeatureAttribute");
if (!feature)
{
return true;
}
auto stage = get_attribute_value<ElemSig::EnumValue>(feature, 0);
return stage.equals_enumerator("AlwaysEnabled");
}
static coded_index<TypeDefOrRef> get_default_interface(TypeDef const& type)
{
auto impls = type.InterfaceImpl();
for (auto&& impl : impls)
{
if (has_attribute(impl, "Windows.Foundation.Metadata", "DefaultAttribute"))
{
return impl.Interface();
}
}
if (!empty(impls))
{
throw_invalid("Type '", type.TypeNamespace(), ".", type.TypeName(), "' does not have a default interface");
}
return {};
}
static TypeDef get_base_class(TypeDef const& derived)
{
auto extends = derived.Extends();
if (!extends)
{
return{};
}
auto const&[extends_namespace, extends_name] = get_type_namespace_and_name(extends);
if (extends_name == "Object" && extends_namespace == "System")
{
return {};
}
return find_required(extends);
};
static auto get_bases(TypeDef const& type)
{
std::vector<TypeDef> bases;
for (auto base = get_base_class(type); base; base = get_base_class(base))
{
bases.push_back(base);
}
return bases;
}
static std::pair<uint16_t, uint16_t> get_version(TypeDef const& type)
{
uint32_t version{};
for (auto&& attribute : type.CustomAttribute())
{
auto name = attribute.TypeNamespaceAndName();
if (name.first != "Windows.Foundation.Metadata")
{
continue;
}
if (name.second == "ContractVersionAttribute")
{
version = get_attribute_value<uint32_t>(attribute, 1);
break;
}
if (name.second == "VersionAttribute")
{
version = get_attribute_value<uint32_t>(attribute, 0);
break;
}
}
return { HIWORD(version), LOWORD(version) };
}
struct interface_info
{
TypeDef type;
bool is_default{};
bool defaulted{};
bool overridable{};
bool base{};
bool exclusive{};
bool fastabi{};
std::pair<uint16_t, uint16_t> version{};
std::vector<std::vector<std::string>> generic_param_stack{};
};
using get_interfaces_t = std::vector<std::pair<std::string, interface_info>>;
static interface_info* find(get_interfaces_t& interfaces, std::string_view const& name)
{
auto pair = std::find_if(interfaces.begin(), interfaces.end(), [&](auto&& pair)
{
return pair.first == name;
});
if (pair == interfaces.end())
{
return nullptr;
}
return &pair->second;
}
static void insert_or_assign(get_interfaces_t& interfaces, std::string_view const& name, interface_info&& info)
{
if (auto existing = find(interfaces, name))
{
*existing = std::move(info);
}
else
{
interfaces.emplace_back(name, std::move(info));
}
}
static void get_interfaces_impl(writer& w, get_interfaces_t& result, bool defaulted, bool overridable, bool base, std::vector<std::vector<std::string>> const& generic_param_stack, std::pair<InterfaceImpl, InterfaceImpl>&& children)
{
for (auto&& impl : children)
{
interface_info info;
auto type = impl.Interface();
auto name = w.write_temp("%", type);
info.is_default = has_attribute(impl, "Windows.Foundation.Metadata", "DefaultAttribute");
info.defaulted = !base && (defaulted || info.is_default);
{
// This is for correctness rather than an optimization (but helps performance as well).
// If the interface was not previously inserted, carry on and recursively insert it.
// If a previous insertion was defaulted we're done as it is correctly captured.
// If a newly discovered instance of a previous insertion is not defaulted, we're also done.
// If it was previously captured as non-defaulted but now found as defaulted, we carry on and
// rediscover it as we need it to be defaulted recursively.
if (auto found = find(result, name))
{
if (found->defaulted || !info.defaulted)
{
continue;
}
}
}
info.overridable = overridable || has_attribute(impl, "Windows.Foundation.Metadata", "OverridableAttribute");
info.base = base;
info.generic_param_stack = generic_param_stack;
writer::generic_param_guard guard;
switch (type.type())
{
case TypeDefOrRef::TypeDef:
{
info.type = type.TypeDef();
break;
}
case TypeDefOrRef::TypeRef:
{
info.type = find_required(type.TypeRef());
w.add_depends(info.type);
break;
}
case TypeDefOrRef::TypeSpec:
{
auto type_signature = type.TypeSpec().Signature();
std::vector<std::string> names;
for (auto&& arg : type_signature.GenericTypeInst().GenericArgs())
{
names.push_back(w.write_temp("%", arg));
}
info.generic_param_stack.push_back(std::move(names));
guard = w.push_generic_params(type_signature.GenericTypeInst());
auto signature = type_signature.GenericTypeInst();
info.type = find_required(signature.GenericType());
break;
}
}
info.exclusive = has_attribute(info.type, "Windows.Foundation.Metadata", "ExclusiveToAttribute");
info.version = get_version(info.type);
get_interfaces_impl(w, result, info.defaulted, info.overridable, base, info.generic_param_stack, info.type.InterfaceImpl());
insert_or_assign(result, name, std::move(info));
}
};
static auto get_interfaces(writer& w, TypeDef const& type)
{
w.abi_types = false;
get_interfaces_t result;
get_interfaces_impl(w, result, false, false, false, {}, type.InterfaceImpl());
for (auto&& base : get_bases(type))
{
get_interfaces_impl(w, result, false, false, true, {}, base.InterfaceImpl());
}
if (!has_fastabi(type))
{
return result;
}
auto count = std::count_if(result.begin(), result.end(), [](auto&& pair)
{
return pair.second.exclusive && !pair.second.base && !pair.second.overridable;
});
std::partial_sort(result.begin(), result.begin() + count, result.end(), [](auto&& left_pair, auto&& right_pair)
{
auto& left = left_pair.second;
auto& right = right_pair.second;
// Sort by base before is_default because each base will have a default.
if (left.base != right.base)
{
return !left.base;
}
if (left.is_default != right.is_default)
{
return left.is_default;
}
if (left.overridable != right.overridable)
{
return !left.overridable;
}
if (left.exclusive != right.exclusive)
{
return left.exclusive;
}
auto left_enabled = is_always_enabled(left.type);
auto right_enabled = is_always_enabled(right.type);
if (left_enabled != right_enabled)
{
return left_enabled;
}
if (left.version != right.version)
{
return left.version < right.version;
}
return left_pair.first < right_pair.first;
});
std::for_each_n(result.begin(), count, [](auto && pair)
{
pair.second.fastabi = true;
});
return result;
}
bool has_fastabi_tearoffs(writer& w, TypeDef const& type)
{
for (auto&& [name, info] : get_interfaces(w, type))
{
if (info.is_default)
{
continue;
}
return info.fastabi;
}
return false;
}
std::size_t get_fastabi_size(writer& w, TypeDef const& type)
{
if (!has_fastabi(type))
{
return 0;
}
auto result = 6 + get_bases(type).size();
for (auto&& [name, info] : get_interfaces(w, type))
{
if (!info.fastabi)
{
break;
}
result += size(info.type.MethodList());
}
return result;
}
auto get_fastabi_size(writer& w, std::vector<TypeDef> const& classes)
{
std::size_t result{};
for (auto&& type : classes)
{
result = std::max(result, get_fastabi_size(w, type));
}
return result;
}
struct factory_info
{
TypeDef type;
bool activatable{};
bool statics{};
bool composable{};
bool visible{};
};
static auto get_factories(writer& w, TypeDef const& type)
{
auto get_system_type = [&](auto&& signature) -> TypeDef
{
for (auto&& arg : signature.FixedArgs())
{
if (auto type_param = std::get_if<ElemSig::SystemType>(&std::get<ElemSig>(arg.value).value))
{
return type.get_cache().find_required(type_param->name);
}
}
return {};
};
std::map<std::string, factory_info> result;
for (auto&& attribute : type.CustomAttribute())
{
auto attribute_name = attribute.TypeNamespaceAndName();
if (attribute_name.first != "Windows.Foundation.Metadata")
{
continue;
}
auto signature = attribute.Value();
factory_info info;
if (attribute_name.second == "ActivatableAttribute")
{
info.type = get_system_type(signature);
info.activatable = true;
}
else if (attribute_name.second == "StaticAttribute")
{
info.type = get_system_type(signature);
info.statics = true;
}
else if (attribute_name.second == "ComposableAttribute")
{
info.type = get_system_type(signature);
info.composable = true;
for (auto&& arg : signature.FixedArgs())
{
if (auto visibility = std::get_if<ElemSig::EnumValue>(&std::get<ElemSig>(arg.value).value))
{
info.visible = std::get<int32_t>(visibility->value) == 2;
break;
}
}
}
else
{
continue;
}
std::string name;
if (info.type)
{
name = w.write_temp("%", info.type);
}
result[name] = std::move(info);
}
return result;
}
enum class param_category
{
generic_type,
object_type,
string_type,
enum_type,
struct_type,
array_type,
fundamental_type,
};
inline param_category get_category(TypeSig const& signature, TypeDef* signature_type = nullptr)
{
if (signature.is_szarray())
{
return param_category::array_type;
}
param_category result{};
call(signature.Type(),
[&](ElementType type)
{
if (type == ElementType::String)
{
result = param_category::string_type;
}
else if (type == ElementType::Object)
{
result = param_category::object_type;
}
else
{
result = param_category::fundamental_type;
}
},
[&](coded_index<TypeDefOrRef> const& type)
{
TypeDef type_def;
if (type.type() == TypeDefOrRef::TypeDef)
{
type_def = type.TypeDef();
}
else
{
auto type_ref = type.TypeRef();
if (type_name(type_ref) == "System.Guid")
{
result = param_category::struct_type;
return;
}
type_def = find_required(type_ref);
}
if (signature_type)
{
*signature_type = type_def;
}
switch (get_category(type_def))
{
case category::interface_type:
case category::class_type:
case category::delegate_type:
result = param_category::object_type;
return;
case category::struct_type:
result = param_category::struct_type;
return;
case category::enum_type:
result = param_category::enum_type;
return;
}
},
[&](GenericTypeInstSig const&)
{
result = param_category::object_type;
},
[&](auto&&)
{
result = param_category::generic_type;
});
return result;
}
static bool is_object(TypeSig const& signature)
{
bool object{};
call(signature.Type(),
[&](ElementType type)
{
if (type == ElementType::Object)
{
object = true;
}
},
[](auto&&) {});
return object;
}
static auto get_delegate_method(TypeDef const& type)
{
auto methods = type.MethodList();
auto method = std::find_if(begin(methods), end(methods), [](auto&& method)
{
return method.Name() == "Invoke";
});
if (method == end(methods))
{
throw_invalid("Delegate's Invoke method not found");
}
return method;
}
static std::string get_field_abi(writer& w, Field const& field)
{
auto signature = field.Signature();
auto const& type = signature.Type();
std::string name = w.write_temp("%", type);
if (starts_with(name, "struct "))
{
auto ref = std::get<coded_index<TypeDefOrRef>>(type.Type());
name = "struct{";
for (auto&& nested : find_required(ref).FieldList())
{
name += " " + get_field_abi(w, nested) + " ";
name += nested.Name();
name += ";";
}
name += " }";
}
return name;
}
static std::string get_component_filename(TypeDef const& type)
{
std::string result{ type.TypeNamespace() };
result += '.';
result += type.TypeName();
if (!settings.component_name.empty() && starts_with(result, settings.component_name))
{
result = result.substr(settings.component_name.size());
if (starts_with(result, "."))
{
result.erase(result.begin());
}
}
return result;
}
static std::string get_generated_component_filename(TypeDef const& type)
{
auto result = get_component_filename(type);
if (!settings.component_prefix)
{
std::replace(result.begin(), result.end(), '.', '/');
}
return result;
}
static bool has_factory_members(writer& w, TypeDef const& type)
{
for (auto&&[factory_name, factory] : get_factories(w, type))
{
if (!factory.type || !empty(factory.type.MethodList()))
{
return true;
}
}
return false;
}
static bool is_composable(writer& w, TypeDef const& type)
{
for (auto&&[factory_name, factory] : get_factories(w, type))
{
if (factory.composable)
{
return true;
}
}
return false;
}
static bool has_composable_constructors(writer& w, TypeDef const& type)
{
for (auto&&[interface_name, factory] : get_factories(w, type))
{
if (factory.composable && !empty(factory.type.MethodList()))
{
return true;
}
}
return false;
}
static bool has_projected_types(cache::namespace_members const& members)
{
return
!members.interfaces.empty() ||
!members.classes.empty() ||
!members.enums.empty() ||
!members.structs.empty() ||
!members.delegates.empty();
}
static bool can_produce(TypeDef const& type)
{
auto attribute = get_attribute(type, "Windows.Foundation.Metadata", "ExclusiveToAttribute");
if (!attribute)
{
return true;
}
if (!settings.component)
{
return false;
}
auto class_name = get_attribute_value<ElemSig::SystemType>(attribute, 0).name;
return settings.component_filter.includes(class_name);
}
}

369
cppwinrt/main.cpp Normal file
Просмотреть файл

@ -0,0 +1,369 @@
#include "pch.h"
#include <time.h>
#include "strings.h"
#include "settings.h"
#include "type_writers.h"
#include "helpers.h"
#include "code_writers.h"
#include "component_writers.h"
#include "file_writers.h"
#include "type_writers.h"
namespace xlang
{
settings_type settings;
struct usage_exception {};
static constexpr cmd::option options[]
{
{ "input", 0, cmd::option::no_max, "<spec>", "Windows metadata to include in projection" },
{ "reference", 0, cmd::option::no_max, "<spec>", "Windows metadata to reference from projection" },
{ "output", 0, 1, "<path>", "Location of generated projection and component templates" },
{ "component", 0, 1, "[<path>]", "Generate component templates, and optional implementation" },
{ "name", 0, 1, "<name>", "Specify explicit name for component files" },
{ "verbose", 0, 0, {}, "Show detailed progress information" },
{ "overwrite", 0, 0, {}, "Overwrite generated component files" },
{ "prefix", 0, 0, {}, "Use dotted namespace convention for component files (defaults to folders)" },
{ "pch", 0, 1, "<name>", "Specify name of precompiled header file (defaults to pch.h)" },
{ "include", 0, cmd::option::no_max, "<prefix>", "One or more prefixes to include in input" },
{ "exclude", 0, cmd::option::no_max, "<prefix>", "One or more prefixes to exclude from input" },
{ "base", 0, 0, {}, "Generate base.h unconditionally" },
{ "optimize", 0, 0, {}, "Generate component projection with unified construction support" },
{ "help", 0, cmd::option::no_max, {}, "Show detailed help with examples" },
{ "library", 0, 1, "<prefix>", "Specify library prefix (defaults to winrt)" },
{ "filter" }, // One or more prefixes to include in input (same as -include)
{ "license", 0, 0 }, // Generate license comment
{ "brackets", 0, 0 }, // Use angle brackets for #includes (defaults to quotes)
{ "fastabi", 0, 0 }, // Enable support for the Fast ABI
{ "ignore_velocity", 0, 0 }, // Ignore feature staging metadata and always include implementations
};
static void print_usage(writer& w)
{
static auto printColumns = [](writer& w, std::string_view const& col1, std::string_view const& col2)
{
w.write_printf(" %-20s%s\n", col1.data(), col2.data());
};
static auto printOption = [](writer& w, cmd::option const& opt)
{
if(opt.desc.empty())
{
return;
}
printColumns(w, w.write_temp("-% %", opt.name, opt.arg), opt.desc);
};
auto format = R"(
C++/WinRT v%
Copyright (c) Microsoft Corporation. All rights reserved.
cppwinrt.exe [options...]
Options:
% ^@<path> Response file containing command line options
Where <spec> is one or more of:
path Path to winmd file or recursively scanned folder
local Local ^%WinDir^%\System32\WinMetadata folder
sdk[+] Current version of Windows SDK [with extensions]
10.0.12345.0[+] Specific version of Windows SDK [with extensions]
)";
w.write(format, XLANG_VERSION_STRING, bind_each(printOption, options));
}
static void process_args(cmd::reader const& args)
{
settings.verbose = args.exists("verbose");
settings.fastabi = args.exists("fastabi");
settings.input = args.files("input", database::is_database);
settings.reference = args.files("reference", database::is_database);
settings.component = args.exists("component");
settings.base = args.exists("base");
settings.license = args.exists("license");
settings.brackets = args.exists("brackets");
path output_folder = args.value("output");
create_directories(output_folder / "winrt/impl");
settings.output_folder = canonical(output_folder).string();
settings.output_folder += '\\';
for (auto && include : args.values("include"))
{
settings.include.insert(include);
}
for (auto && include : args.values("filter"))
{
settings.include.insert(include);
}
for (auto && exclude : args.values("exclude"))
{
settings.exclude.insert(exclude);
}
if (settings.component)
{
settings.component_overwrite = args.exists("overwrite");
settings.component_name = args.value("name");
if (settings.component_name.empty())
{
// For compatibility with C++/WinRT 1.0, the component_name defaults to the *first*
// input, hence the use of values() here that will return the args in input order.
auto& values = args.values("input");
if (!values.empty())
{
settings.component_name = path(values[0]).filename().replace_extension().string();
}
}
settings.component_pch = args.value("pch", "pch.h");
settings.component_prefix = args.exists("prefix");
settings.component_lib = args.value("library", "winrt");
settings.component_opt = args.exists("optimize");
settings.component_ignore_velocity = args.exists("ignore_velocity");
if (settings.component_pch == ".")
{
settings.component_pch.clear();
}
auto component = args.value("component");
if (!component.empty())
{
create_directories(component);
settings.component_folder = canonical(component).string();
settings.component_folder += '\\';
}
}
}
static auto get_files_to_cache()
{
std::vector<std::string> files;
files.insert(files.end(), settings.input.begin(), settings.input.end());
files.insert(files.end(), settings.reference.begin(), settings.reference.end());
return files;
}
static void build_filters(cache const& c)
{
if (settings.reference.empty())
{
return;
}
std::set<std::string> include;
for (auto file : settings.input)
{
auto db = std::find_if(c.databases().begin(), c.databases().end(), [&](auto&& db)
{
return db.path() == file;
});
for (auto&& type : db->TypeDef)
{
if (!type.Flags().WindowsRuntime())
{
continue;
}
std::string full_name{ type.TypeNamespace() };
full_name += '.';
full_name += type.TypeName();
include.insert(full_name);
}
}
settings.projection_filter = { include, {} };
settings.component_filter = { settings.include.empty() ? include : settings.include, settings.exclude };
}
static void build_fastabi_cache(cache const& c)
{
if (!settings.fastabi)
{
return;
}
for (auto&& [ns, members] : c.namespaces())
{
for (auto&& type : members.classes)
{
if (!has_fastabi(type))
{
continue;
}
auto default_interface = get_default_interface(type);
if (default_interface.type() == TypeDefOrRef::TypeDef)
{
settings.fastabi_cache.try_emplace(default_interface.TypeDef(), type);
}
else
{
settings.fastabi_cache.try_emplace(find_required(default_interface.TypeRef()), type);
}
}
}
}
static void remove_foundation_types(cache& c)
{
c.remove_type("Windows.Foundation", "DateTime");
c.remove_type("Windows.Foundation", "EventRegistrationToken");
c.remove_type("Windows.Foundation", "HResult");
c.remove_type("Windows.Foundation", "Point");
c.remove_type("Windows.Foundation", "Rect");
c.remove_type("Windows.Foundation", "Size");
c.remove_type("Windows.Foundation", "TimeSpan");
c.remove_type("Windows.Foundation.Numerics", "Matrix3x2");
c.remove_type("Windows.Foundation.Numerics", "Matrix4x4");
c.remove_type("Windows.Foundation.Numerics", "Plane");
c.remove_type("Windows.Foundation.Numerics", "Quaternion");
c.remove_type("Windows.Foundation.Numerics", "Vector2");
c.remove_type("Windows.Foundation.Numerics", "Vector3");
c.remove_type("Windows.Foundation.Numerics", "Vector4");
}
static int run(int const argc, char** argv)
{
int result{};
writer w;
try
{
auto start = get_start_time();
cmd::reader args{ argc, argv, options };
if (!args || args.exists("help"))
{
throw usage_exception{};
}
process_args(args);
cache c{ get_files_to_cache() };
remove_foundation_types(c);
build_filters(c);
settings.base = settings.base || (!settings.component && settings.projection_filter.empty());
build_fastabi_cache(c);
if (settings.verbose)
{
w.write(" tool: %\n", canonical(path(argv[0]).replace_extension("exe")).string());
w.write(" ver: %\n", XLANG_VERSION_STRING);
for (auto&& file : settings.input)
{
w.write(" in: %\n", file);
}
for (auto&& file : settings.reference)
{
w.write(" ref: %\n", file);
}
w.write(" out: %\n", settings.output_folder);
if (!settings.component_folder.empty())
{
w.write(" cout: %\n", settings.component_folder);
}
}
w.flush_to_console();
task_group group;
for (auto&&[ns, members] : c.namespaces())
{
group.add([&, &ns = ns, &members = members]
{
if (!has_projected_types(members) || !settings.projection_filter.includes(members))
{
return;
}
write_namespace_0_h(ns, members);
write_namespace_1_h(ns, members);
write_namespace_2_h(ns, members);
write_namespace_h(c, ns, members);
});
}
if (settings.base)
{
write_base_h();
}
if (settings.component)
{
std::vector<TypeDef> classes;
for (auto&&[ns, members] : c.namespaces())
{
for (auto&& type : members.classes)
{
if (settings.component_filter.includes(type))
{
classes.push_back(type);
}
}
}
if (!classes.empty())
{
write_fast_forward_h(classes);
write_module_g_cpp(classes);
for (auto&& type : classes)
{
write_component_g_h(type);
write_component_g_cpp(type);
write_component_h(type);
write_component_cpp(type);
}
}
}
group.get();
if (settings.verbose)
{
w.write(" time: %ms\n", get_elapsed_time(start));
}
}
catch (usage_exception const&)
{
print_usage(w);
}
catch (std::exception const& e)
{
w.write(" error: %\n", e.what());
result = 1;
}
w.flush_to_console();
return result;
}
}
int main(int const argc, char** argv)
{
return xlang::run(argc, argv);
}

4
cppwinrt/packages.config Normal file
Просмотреть файл

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.WinMD" version="1.0.191006.1" targetFramework="native" />
</packages>

1
cppwinrt/pch.cpp Normal file
Просмотреть файл

@ -0,0 +1 @@
#include "pch.h"

6
cppwinrt/pch.h Normal file
Просмотреть файл

@ -0,0 +1,6 @@
#pragma once
#include "cmd_reader.h"
#include <winmd_reader.h>
#include "task_group.h"
#include "text_writer.h"

37
cppwinrt/settings.h Normal file
Просмотреть файл

@ -0,0 +1,37 @@
#pragma once
namespace xlang
{
struct settings_type
{
std::set<std::string> input;
std::set<std::string> reference;
std::string output_folder;
bool base{};
bool license{};
bool brackets{};
bool verbose{};
bool component{};
std::string component_folder;
std::string component_name;
std::string component_pch;
bool component_prefix{};
bool component_overwrite{};
std::string component_lib;
bool component_opt{};
bool component_ignore_velocity{};
std::set<std::string> include;
std::set<std::string> exclude;
winmd::reader::filter projection_filter;
winmd::reader::filter component_filter;
bool fastabi{};
std::map<winmd::reader::TypeDef, winmd::reader::TypeDef> fastabi_cache;
};
extern settings_type settings;
}

546
cppwinrt/type_writers.h Normal file
Просмотреть файл

@ -0,0 +1,546 @@
#pragma once
namespace xlang
{
using namespace std::filesystem;
using namespace text;
using namespace winmd::reader;
using namespace std::literals;
inline bool starts_with(std::string_view const& value, std::string_view const& match) noexcept
{
return 0 == value.compare(0, match.size(), match);
}
template <typename...T> struct visit_overload : T... { using T::operator()...; };
template <typename V, typename...C>
auto call(V&& variant, C&&...call)
{
return std::visit(visit_overload<C...>{ std::forward<C>(call)... }, std::forward<V>(variant));
}
struct type_name
{
std::string_view name;
std::string_view name_space;
explicit type_name(TypeDef const& type) :
name(type.TypeName()),
name_space(type.TypeNamespace())
{
}
explicit type_name(TypeRef const& type) :
name(type.TypeName()),
name_space(type.TypeNamespace())
{
}
};
bool operator==(type_name const& left, std::string_view const& right)
{
if (left.name.size() + 1 + left.name_space.size() != right.size())
{
return false;
}
if (right[left.name_space.size()] != '.')
{
return false;
}
if (0 != right.compare(left.name_space.size() + 1, left.name.size(), left.name))
{
return false;
}
return 0 == right.compare(0, left.name_space.size(), left.name_space);
}
static auto remove_tick(std::string_view const& name)
{
return name.substr(0, name.rfind('`'));
}
template <typename First, typename...Rest>
auto get_impl_name(First const& first, Rest const&... rest)
{
std::string result;
auto convert = [&](auto&& value)
{
for (auto&& c : value)
{
result += c == '.' ? '_' : c;
}
};
convert(first);
((result += '_', convert(rest)), ...);
return result;
}
struct writer : writer_base<writer>
{
using writer_base<writer>::write;
struct depends_compare
{
bool operator()(TypeDef const& left, TypeDef const& right) const
{
return left.TypeName() < right.TypeName();
}
};
std::string type_namespace;
bool abi_types{};
bool param_names{};
bool consume_types{};
bool async_types{};
std::map<std::string_view, std::set<TypeDef, depends_compare>> depends;
std::vector<std::vector<std::string>> generic_param_stack;
struct generic_param_guard
{
explicit generic_param_guard(writer* arg = nullptr)
: owner(arg)
{}
~generic_param_guard()
{
if (owner)
{
owner->generic_param_stack.pop_back();
}
}
generic_param_guard(generic_param_guard&& other)
: owner(other.owner)
{
owner = nullptr;
}
generic_param_guard& operator=(generic_param_guard&& other)
{
owner = std::exchange(other.owner, nullptr);
return *this;
}
generic_param_guard& operator=(generic_param_guard const&) = delete;
writer* owner;
};
void add_depends(TypeDef const& type)
{
auto ns = type.TypeNamespace();
if (ns != type_namespace)
{
depends[ns].insert(type);
}
}
[[nodiscard]] auto push_generic_params(std::pair<GenericParam, GenericParam> const& params)
{
if (empty(params))
{
return generic_param_guard{ nullptr };
}
std::vector<std::string> names;
for (auto&& param : params)
{
names.push_back(std::string{ param.Name() });
}
generic_param_stack.push_back(std::move(names));
return generic_param_guard{ this };
}
[[nodiscard]] auto push_generic_params(GenericTypeInstSig const& signature)
{
std::vector<std::string> names;
for (auto&& arg : signature.GenericArgs())
{
names.push_back(write_temp("%", arg));
}
generic_param_stack.push_back(std::move(names));
return generic_param_guard{ this };
}
void write_value(int32_t value)
{
write_printf("%d", value);
}
void write_value(uint32_t value)
{
write_printf("%#0x", value);
}
void write_code(std::string_view const& value)
{
for (auto&& c : value)
{
if (c == '.')
{
write("::");
}
else if (c == '`')
{
return;
}
else
{
write(c);
}
}
}
void write(Constant const& value)
{
switch (value.Type())
{
case ConstantType::Int32:
write_value(value.ValueInt32());
break;
case ConstantType::UInt32:
write_value(value.ValueUInt32());
break;
default:
throw std::invalid_argument("Unexpected constant type");
}
}
void write(TypeDef const& type)
{
add_depends(type);
auto ns = type.TypeNamespace();
auto name = type.TypeName();
auto generics = type.GenericParam();
if (!empty(generics))
{
write("@::%<%>", ns, remove_tick(name), bind_list(", ", generics));
return;
}
// TODO: get rid of all these renames once parity with cppwinrt.exe has been reached...
if (name == "EventRegistrationToken" && ns == "Windows.Foundation")
{
write("winrt::event_token");
}
else if (name == "HResult" && ns == "Windows.Foundation")
{
write("winrt::hresult");
}
else if (abi_types)
{
auto category = get_category(type);
if (ns == "Windows.Foundation.Numerics")
{
if (name == "Matrix3x2") { name = "float3x2"; }
else if (name == "Matrix4x4") { name = "float4x4"; }
else if (name == "Plane") { name = "plane"; }
else if (name == "Quaternion") { name = "quaternion"; }
else if (name == "Vector2") { name = "float2"; }
else if (name == "Vector3") { name = "float3"; }
else if (name == "Vector4") { name = "float4"; }
write("@::%", ns, name);
}
else if (category == category::struct_type)
{
if ((name == "DateTime" || name == "TimeSpan") && ns == "Windows.Foundation")
{
write("int64_t");
}
else if ((name == "Point" || name == "Size" || name == "Rect") && ns == "Windows.Foundation")
{
write("@::%", ns, name);
}
else
{
write("struct struct_%_%", get_impl_name(ns), name);
}
}
else if (category == category::enum_type)
{
write(type.FieldList().first.Signature().Type());
}
else
{
write("void*");
}
}
else
{
if (ns == "Windows.Foundation.Numerics")
{
if (name == "Matrix3x2") { name = "float3x2"; }
else if (name == "Matrix4x4") { name = "float4x4"; }
else if (name == "Plane") { name = "plane"; }
else if (name == "Quaternion") { name = "quaternion"; }
else if (name == "Vector2") { name = "float2"; }
else if (name == "Vector3") { name = "float3"; }
else if (name == "Vector4") { name = "float4"; }
write("@::%", ns, name);
}
else
{
write("@::%", ns, name);
}
}
}
void write(TypeRef const& type)
{
if (type_name(type) == "System.Guid")
{
write("winrt::guid");
}
else
{
write(find_required(type));
}
}
void write(GenericParam const& param)
{
write(param.Name());
}
void write(coded_index<TypeDefOrRef> const& type)
{
switch (type.type())
{
case TypeDefOrRef::TypeDef:
write(type.TypeDef());
break;
case TypeDefOrRef::TypeRef:
write(type.TypeRef());
break;
case TypeDefOrRef::TypeSpec:
write(type.TypeSpec().Signature().GenericTypeInst());
break;
}
}
void write(GenericTypeInstSig const& type)
{
if (abi_types)
{
write("void*");
}
else
{
auto generic_type = type.GenericType();
auto[ns, name] = get_type_namespace_and_name(generic_type);
name.remove_suffix(name.size() - name.rfind('`'));
add_depends(find_required(generic_type));
if (consume_types)
{
static constexpr std::string_view iterable("Windows::Foundation::Collections::IIterable<"sv);
static constexpr std::string_view vector_view("Windows::Foundation::Collections::IVectorView<"sv);
static constexpr std::string_view map_view("Windows::Foundation::Collections::IMapView<"sv);
static constexpr std::string_view vector("Windows::Foundation::Collections::IVector<"sv);
static constexpr std::string_view map("Windows::Foundation::Collections::IMap<"sv);
consume_types = false;
auto full_name = write_temp("@::%<%>", ns, name, bind_list(", ", type.GenericArgs()));
consume_types = true;
if (starts_with(full_name, iterable))
{
if (async_types)
{
write("param::async_iterable%", full_name.substr(iterable.size() - 1));
}
else
{
write("param::iterable%", full_name.substr(iterable.size() - 1));
}
}
else if (starts_with(full_name, vector_view))
{
if (async_types)
{
write("param::async_vector_view%", full_name.substr(vector_view.size() - 1));
}
else
{
write("param::vector_view%", full_name.substr(vector_view.size() - 1));
}
}
else if (starts_with(full_name, map_view))
{
if (async_types)
{
write("param::async_map_view%", full_name.substr(map_view.size() - 1));
}
else
{
write("param::map_view%", full_name.substr(map_view.size() - 1));
}
}
else if (starts_with(full_name, vector))
{
write("param::vector%", full_name.substr(vector.size() - 1));
}
else if (starts_with(full_name, map))
{
write("param::map%", full_name.substr(map.size() - 1));
}
else
{
write(full_name);
}
}
else
{
write("@::%<%>", ns, name, bind_list(", ", type.GenericArgs()));
}
}
}
void write(TypeSig::value_type const& type)
{
call(type,
[&](ElementType type)
{
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::R4) { write("float"); }
else if (type == ElementType::R8) { write("double"); }
else if (type == ElementType::String)
{
if (abi_types)
{
write("void*");
}
else if (consume_types)
{
write("param::hstring");
}
else
{
write("hstring");
}
}
else if (type == ElementType::Object)
{
if (abi_types)
{
write("void*");
}
else
{
write("Windows::Foundation::IInspectable");
}
}
else
{
XLANG_ASSERT(false);
}
},
[&](GenericTypeIndex var)
{
write(generic_param_stack.back()[var.index]);
},
[&](auto&& type)
{
write(type);
});
}
void write(TypeSig const& signature)
{
if (!abi_types && signature.is_szarray())
{
write("com_array<%>", signature.Type());
}
else
{
write(signature.Type());
}
}
void write(RetTypeSig const& value)
{
if (value)
{
write(value.Type());
}
else
{
write("void");
}
}
void write(Field const& value)
{
write(value.Signature().Type());
}
void write_root_include(std::string_view const& include)
{
auto format = R"(#include %winrt/%.h%
)";
write(format,
settings.brackets ? '<' : '\"',
include,
settings.brackets ? '>' : '\"');
}
void write_depends(std::string_view const& ns, char impl = 0)
{
if (impl)
{
write_root_include(write_temp("impl/%.%", ns, impl));
}
else
{
write_root_include(ns);
}
}
void save_header(char impl = 0)
{
auto filename{ settings.output_folder + "winrt/" };
if (impl)
{
filename += "impl/";
}
filename += type_namespace;
if (impl)
{
filename += '.';
filename += impl;
}
filename += ".h";
flush_to_file(filename);
}
};
}

58
fast_fwd/arm/thunks.asm Normal file
Просмотреть файл

@ -0,0 +1,58 @@
; ARM fast forwarder thunk implementations
; Calling convention: https://docs.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions
#include "ksarm.h"
IMPORT __guard_check_icall_fptr
TEXTAREA
CFG_ALIGN
NESTED_ENTRY InvokeForwarder
; Save enregistered args and return address
PROLOG_PUSH {r0-r4, lr}
; Replace forwarder abi with owner abi
ldr r1, [r0, #4]
str r1, [sp]
; Add offset and index (on stack)
ldr r2, [sp, #24]
ldr r3, [r0, #8]
add r2, r2, r3
; Get method address from owner abi vtable
ldr r0, [r1]
ldr r4, [r0, r2, lsl #2]
mov r0, r4
; Verify indirect call target
mov32 r12, __guard_check_icall_fptr
ldr r12, [r12]
blx r12
; Restore method address, return address, and args
mov r12, r4
EPILOG_POP {r0-r4, lr}
EPILOG_NOP add sp, #4
; Jump to method
EPILOG_NOP bx r12
NESTED_END InvokeForwarder
; Define thunks
MACRO
WINRT_FF_THUNK $i
LEAF_ENTRY winrt_ff_thunk$i
; Note: no scratch registers available (r12/IP is used by CFG), must use stack
mov r12, $i
push r12
ldr pc, =InvokeForwarder
LEAF_END winrt_ff_thunk$i
MEND
#include "thunks.inc"
END

60
fast_fwd/arm64/thunks.asm Normal file
Просмотреть файл

@ -0,0 +1,60 @@
; ARM64 fast forwarder thunk implementations
; Calling convention: https://docs.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions
#include "ksarm64.h"
IMPORT __guard_check_icall_fptr
TEXTAREA
CFG_ALIGN
NESTED_ENTRY InvokeForwarder
; Save enregistered args
PROLOG_SAVE_REG_PAIR fp, lr, #-64!
PROLOG_SAVE_REG_PAIR x19, x20, #16
PROLOG_NOP stp x0, x1, [sp, #32]
PROLOG_NOP stp x2, x3, [sp, #48]
; Replace forwarder abi with owner abi
ldr x1, [x0, #8]
str x1, [sp, #32]
; Add offset and index (on stack)
ldr x2, [x0, #16]
add x12, x12, x2
; Get method address from owner abi vtable
ldr x0, [x1]
ldr x19, [x0, x12, lsl #3]
mov x0, x19
; Verify indirect call target
adrp x12, __guard_check_icall_fptr
ldr x12, [x12, __guard_check_icall_fptr]
blr x12
; Restore method address, return address, and args
mov x12, x19
EPILOG_NOP ldp x2, x3, [sp, #48]
EPILOG_NOP ldp x0, x1, [sp, #32]
EPILOG_RESTORE_REG_PAIR x19, x20, #16
EPILOG_RESTORE_REG_PAIR fp, lr, #64!
; Jump to method
EPILOG_NOP br x12
NESTED_END InvokeForwarder
; Define thunks
MACRO
WINRT_FF_THUNK $i
LEAF_ENTRY winrt_ff_thunk$i
mov x12, #$i
b InvokeForwarder
LEAF_END winrt_ff_thunk$i
MEND
#include "thunks.inc"
END

140
fast_fwd/fast_fwd.vcxproj Normal file
Просмотреть файл

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>fastfwd</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(SolutionDir)\cppwinrt.props" />
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding Condition="'$(Configuration)'=='Release'">true</EnableCOMDATFolding>
<OptimizeReferences Condition="'$(Configuration)'=='Release'">true</OptimizeReferences>
</Link>
<Lib>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Lib>
</ItemDefinitionGroup>
<PropertyGroup>
<Platform_Arm Condition="'$(Platform)'=='ARM' or '$(Platform)'=='ARM64'">true</Platform_Arm>
<Platform_Arm Condition="'$(Platform_Arm)'!='true'">false</Platform_Arm>
<Platform_Intel>!$(Platform_Arm)</Platform_Intel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<TargetName>cppwinrt_fast_forwarder</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<TargetName>cppwinrt_fast_forwarder</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<TargetName>cppwinrt_fast_forwarder</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<TargetName>cppwinrt_fast_forwarder</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<TargetName>cppwinrt_fast_forwarder</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<TargetName>cppwinrt_fast_forwarder</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<TargetName>cppwinrt_fast_forwarder</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<TargetName>cppwinrt_fast_forwarder</TargetName>
</PropertyGroup>
<ImportGroup>
<Import Condition="$(Platform_Intel)" Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
<Import Condition="$(Platform_Arm)" Project="$(VCTargetsPath)\BuildCustomizations\marmasm.props" />
</ImportGroup>
<Target Name="CppWinRTPreprocessArmThunk" Condition="$(Platform_Arm)" BeforeTargets="_MARMASM" Outputs="$(IntDir)thunks.pp" Inputs="$(Platform)\thunks.asm">
<Exec Command="cl /I$(ProjectDir) /E /Tc $(Platform)\thunks.asm &gt; $(IntDir)thunks.pp" />
</Target>
<ItemGroup Condition="$(Platform_Intel)">
<MASM Include="$(Platform)\thunks.asm">
<FileType>Document</FileType>
<IncludePaths>src</IncludePaths>
<UseSafeExceptionHandlers Condition="'$(Platform)'=='Win32'">true</UseSafeExceptionHandlers>
<UseSafeExceptionHandlers Condition="'$(Platform)'=='ARM'">true</UseSafeExceptionHandlers>
<UseSafeExceptionHandlers Condition="'$(Platform)'=='ARM64'">true</UseSafeExceptionHandlers>
</MASM>
</ItemGroup>
<ItemGroup Condition="$(Platform_Arm)">
<MARMASM Include="$(IntDir)thunks.pp">
<FileType>Document</FileType>
<IncludePaths>src</IncludePaths>
</MARMASM>
</ItemGroup>
<ImportGroup>
<Import Condition="$(Platform_Intel)" Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
<Import Condition="$(Platform_Arm)" Project="$(VCTargetsPath)\BuildCustomizations\marmasm.targets" />
</ImportGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

1018
fast_fwd/thunks.inc Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

43
fast_fwd/win32/thunks.asm Normal file
Просмотреть файл

@ -0,0 +1,43 @@
; i386 fast forwarder thunk implementations
; Calling convention: https://docs.microsoft.com/en-us/cpp/cpp/stdcall
.MODEL FLAT
extrn ___guard_check_icall_fptr:DWORD
.CODE
InvokeForwarder PROC
; Replace forwarder abi with owner abi
mov ecx, dword ptr[esp + 4]
mov edx, dword ptr[ecx + 4]
mov [esp + 4], edx
; Add offset and index
add eax, dword ptr [ecx + 8]
; Get method address from owner abi vtable
mov ecx, dword ptr [edx]
mov eax, dword ptr [ecx + eax * 4]
; Verify indirect call target
call [___guard_check_icall_fptr]
; Jump to method
jmp eax
InvokeForwarder ENDP
; Define thunks
WINRT_FF_THUNK MACRO i
_winrt_ff_thunk&i&@0 PROC
mov eax, i
jmp InvokeForwarder
_winrt_ff_thunk&i&@0 ENDP
PUBLIC _winrt_ff_thunk&i&@0
ENDM
include thunks.inc
END

16865
inc/catch.hpp Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

405
inc/cmd_reader.h Normal file
Просмотреть файл

@ -0,0 +1,405 @@
#pragma once
#include <array>
#include <limits>
#include <stdint.h>
#include <string>
#include <string_view>
#include <map>
#include <vector>
#include <set>
#include <filesystem>
#include <fstream>
#include <regex>
#include <Windows.h>
#include <shlwapi.h>
#include <XmlLite.h>
#include "cmd_reader_windows.h"
namespace xlang::cmd
{
[[noreturn]] inline void throw_invalid(std::string const& message)
{
throw std::invalid_argument(message);
}
template <typename...T>
[[noreturn]] inline void throw_invalid(std::string message, T const&... args)
{
(message.append(args), ...);
throw std::invalid_argument(message);
}
struct option
{
static constexpr uint32_t no_min = 0;
static constexpr uint32_t no_max = std::numeric_limits<uint32_t>::max();
std::string_view name;
uint32_t min{ no_min };
uint32_t max{ no_max };
std::string_view arg{};
std::string_view desc{};
};
struct reader
{
template <typename C, typename V, size_t numOptions>
reader(C const argc, V const argv, const option(& options)[numOptions])
{
#ifdef XLANG_DEBUG
{
std::set<std::string_view> unique;
for (auto&& option : options)
{
// If this assertion fails it means there are duplicate options.
XLANG_ASSERT(unique.insert(option.name).second);
}
}
#endif
if (argc < 2)
{
return;
}
auto last{ std::end(options) };
for (C i = 1; i < argc; ++i)
{
extract_option(argv[i], options, last);
}
for (auto&& option : options)
{
auto args = m_options.find(option.name);
std::size_t const count = args == m_options.end() ? 0 : args->second.size();
if (option.min == 0 && option.max == 0 && count > 0)
{
throw_invalid("Option '", option.name, "' does not accept a value");
}
else if (option.max == option.min && count != option.max)
{
throw_invalid("Option '", option.name, "' requires exactly ", std::to_string(option.max), " value(s)");
}
else if (count < option.min)
{
throw_invalid("Option '", option.name, "' requires at least ", std::to_string(option.min), " value(s)");
}
else if (count > option.max)
{
throw_invalid("Option '", option.name, "' accepts at most ", std::to_string(option.max), " value(s)");
}
}
}
explicit operator bool() const noexcept
{
return !m_options.empty();
}
bool exists(std::string_view const& name) const noexcept
{
return m_options.count(name);
}
auto const& values(std::string_view const& name) const noexcept
{
auto result = m_options.find(name);
if (result == m_options.end())
{
static std::vector<std::string> empty{};
return empty;
}
return result->second;
}
auto value(std::string_view const& name, std::string_view const& default_value = {}) const
{
auto result = m_options.find(name);
if (result == m_options.end() || result->second.empty())
{
return std::string{ default_value };
}
return result->second.front();
}
template <typename F>
auto files(std::string_view const& name, F directory_filter) const
{
std::set<std::string> files;
auto add_directory = [&](auto&& path)
{
for (auto&& file : std::filesystem::directory_iterator(path))
{
if (std::filesystem::is_regular_file(file))
{
auto filename = file.path().string();
if (directory_filter(filename))
{
files.insert(filename);
}
}
}
};
for (auto&& path : values(name))
{
if (std::filesystem::is_directory(path))
{
add_directory(std::filesystem::canonical(path));
continue;
}
if (std::filesystem::is_regular_file(path))
{
files.insert(std::filesystem::canonical(path).string());
continue;
}
if (path == "local")
{
std::array<char, 260> local{};
#ifdef _WIN64
ExpandEnvironmentStringsA("%windir%\\System32\\WinMetadata", local.data(), static_cast<uint32_t>(local.size()));
#else
ExpandEnvironmentStringsA("%windir%\\SysNative\\WinMetadata", local.data(), static_cast<uint32_t>(local.size()));
#endif
add_directory(local.data());
continue;
}
std::string sdk_version;
if (path == "sdk" || path == "sdk+")
{
sdk_version = impl::get_sdk_version();
}
else
{
std::regex rx(R"(((\d+)\.(\d+)\.(\d+)\.(\d+))\+?)");
std::smatch match;
if (std::regex_match(path, match, rx))
{
sdk_version = match[1].str();
}
}
if (!sdk_version.empty())
{
auto sdk_path = impl::get_sdk_path();
auto xml_path = sdk_path;
xml_path /= L"Platforms\\UAP";
xml_path /= sdk_version;
xml_path /= L"Platform.xml";
impl::add_files_from_xml(files, sdk_version, xml_path, sdk_path);
if (path.back() != '+')
{
continue;
}
for (auto&& item : std::filesystem::directory_iterator(sdk_path / L"Extension SDKs"))
{
xml_path = item.path() / sdk_version;
xml_path /= L"SDKManifest.xml";
impl::add_files_from_xml(files, sdk_version, xml_path, sdk_path);
}
continue;
}
throw_invalid("Path '", path, "' is not a file or directory");
}
return files;
}
auto files(std::string_view const& name) const
{
return files(name, [](auto&&) {return true; });
}
private:
inline bool starts_with(std::string_view const& value, std::string_view const& match) noexcept
{
return 0 == value.compare(0, match.size(), match);
}
template<typename O>
auto find(O const& options, std::string_view const& arg)
{
for (auto current = std::begin(options); current != std::end(options); ++current)
{
if (starts_with(current->name, arg))
{
return current;
}
}
return std::end(options);
}
std::map<std::string_view, std::vector<std::string>> m_options;
template<typename O, typename L>
void extract_option(std::string_view arg, O const& options, L& last)
{
if (arg[0] == '-')
{
arg.remove_prefix(1);
last = find(options, arg);
if (last == std::end(options))
{
throw_invalid("Option '-", arg, "' is not supported");
}
m_options.try_emplace(last->name);
}
else if (arg[0] == '@')
{
arg.remove_prefix(1);
extract_response_file(arg, options, last);
}
else if (last == std::end(options))
{
throw_invalid("Value '", arg, "' is not supported");
}
else
{
m_options[last->name].push_back(std::string{ arg });
}
}
template<typename O, typename L>
void extract_response_file(std::string_view const& arg, O const& options, L& last)
{
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<unsigned char>(::tolower(c)); });
// Check if misuse of @ prefix, so if directory or metadata file instead of response file.
if (is_directory(response_path) || extension == ".winmd")
{
throw_invalid("'@' is reserved for response files");
}
std::string line_buf;
std::ifstream response_file(absolute(response_path));
while (getline(response_file, line_buf))
{
size_t argc = 0;
std::vector<std::string> argv;
parse_command_line(line_buf.data(), argv, &argc);
for (size_t i = 0; i < argc; i++)
{
extract_option(argv[i], options, last);
}
}
}
template <typename Character>
static void parse_command_line(Character* cmdstart, std::vector<std::string>& argv, size_t* argument_count)
{
std::string arg;
bool copy_character;
unsigned backslash_count;
bool in_quotes;
bool first_arg;
Character* p = cmdstart;
in_quotes = false;
first_arg = true;
*argument_count = 0;
for (;;)
{
if (*p)
{
while (*p == ' ' || *p == '\t')
++p;
}
if (!first_arg)
{
argv.emplace_back(arg);
arg.clear();
++*argument_count;
}
if (*p == '\0')
break;
for (;;)
{
copy_character = true;
// Rules:
// 2N backslashes + " ==> N backslashes and begin/end quote
// 2N + 1 backslashes + " ==> N backslashes + literal "
// N backslashes ==> N backslashes
backslash_count = 0;
while (*p == '\\')
{
++p;
++backslash_count;
}
if (*p == '"')
{
// if 2N backslashes before, start/end quote, otherwise
// copy literally:
if (backslash_count % 2 == 0)
{
if (in_quotes && p[1] == '"')
{
p++; // Double quote inside quoted string
}
else
{
// Skip first quote char and copy second:
copy_character = false;
in_quotes = !in_quotes;
}
}
backslash_count /= 2;
}
while (backslash_count--)
{
arg.push_back('\\');
}
if (*p == '\0' || (!in_quotes && (*p == ' ' || *p == '\t')))
break;
if (copy_character)
{
arg.push_back(*p);
}
++p;
}
first_arg = false;
}
}
};
}

257
inc/cmd_reader_windows.h Normal file
Просмотреть файл

@ -0,0 +1,257 @@
namespace xlang::impl
{
struct registry_key
{
HKEY handle{};
registry_key(registry_key const&) = delete;
registry_key& operator=(registry_key const&) = delete;
~registry_key() noexcept
{
if (handle)
{
RegCloseKey(handle);
}
}
};
template <typename T>
struct com_ptr
{
T* ptr{};
com_ptr(com_ptr const&) = delete;
com_ptr& operator=(com_ptr const&) = delete;
com_ptr() noexcept = default;
~com_ptr() noexcept
{
if (ptr)
{
ptr->Release();
}
}
auto operator->() const noexcept
{
return ptr;
}
};
static void check_xml(HRESULT result)
{
if (result < 0)
{
throw std::invalid_argument("Could not read the Windows SDK's Platform.xml");
}
}
inline void add_files_from_xml(
std::set<std::string>& files,
std::string const& sdk_version,
std::filesystem::path const& xml_path,
std::filesystem::path const& sdk_path)
{
com_ptr<IStream> stream;
check_xml(SHCreateStreamOnFileW(
xml_path.c_str(),
STGM_READ, &stream.ptr));
com_ptr<IXmlReader> reader;
check_xml(CreateXmlReader(
__uuidof(IXmlReader),
reinterpret_cast<void**>(&reader.ptr),
nullptr));
check_xml(reader->SetInput(stream.ptr));
XmlNodeType node_type = XmlNodeType_None;
while (S_OK == reader->Read(&node_type))
{
if (node_type != XmlNodeType_Element)
{
continue;
}
wchar_t const* value{ nullptr };
check_xml(reader->GetLocalName(&value, nullptr));
if (0 != wcscmp(value, L"ApiContract"))
{
continue;
}
auto path = sdk_path;
path /= L"References";
path /= sdk_version;
check_xml(reader->MoveToAttributeByName(L"name", nullptr));
check_xml(reader->GetValue(&value, nullptr));
path /= value;
check_xml(reader->MoveToAttributeByName(L"version", nullptr));
check_xml(reader->GetValue(&value, nullptr));
path /= value;
check_xml(reader->MoveToAttributeByName(L"name", nullptr));
check_xml(reader->GetValue(&value, nullptr));
path /= value;
path += L".winmd";
files.insert(path.string());
}
}
inline registry_key open_sdk()
{
HKEY key;
if (0 != RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots",
0,
KEY_READ,
&key))
{
throw std::invalid_argument("Could not find the Windows SDK in the registry");
}
return { key };
}
inline std::filesystem::path get_sdk_path()
{
auto key = open_sdk();
DWORD path_size = 0;
if (0 != RegQueryValueExW(
key.handle,
L"KitsRoot10",
nullptr,
nullptr,
nullptr,
&path_size))
{
throw std::invalid_argument("Could not find the Windows SDK path in the registry");
}
std::wstring root((path_size / sizeof(wchar_t)) - 1, L'?');
RegQueryValueExW(
key.handle,
L"KitsRoot10",
nullptr,
nullptr,
reinterpret_cast<BYTE*>(root.data()),
&path_size);
return root;
}
inline std::string get_module_path()
{
std::string path(100, '?');
DWORD actual_size{};
while (true)
{
actual_size = GetModuleFileNameA(nullptr, path.data(), 1 + static_cast<uint32_t>(path.size()));
if (actual_size < 1 + path.size())
{
path.resize(actual_size);
break;
}
else
{
path.resize(path.size() * 2, '?');
}
}
return path;
}
inline std::string get_sdk_version()
{
auto module_path = get_module_path();
std::regex rx(R"(((\d+)\.(\d+)\.(\d+)\.(\d+)))");
std::cmatch match;
auto sdk_path = get_sdk_path();
if (std::regex_search(module_path.c_str(), match, rx))
{
auto path = sdk_path / "Platforms\\UAP" / match[1].str() / "Platform.xml";
if (std::filesystem::exists(path))
{
return match[1].str();
}
}
auto key = open_sdk();
uint32_t index{};
std::array<char, 100> subkey;
std::array<unsigned long, 4> version_parts{};
std::string result;
while (0 == RegEnumKeyA(key.handle, index++, subkey.data(), static_cast<uint32_t>(subkey.size())))
{
if (!std::regex_match(subkey.data(), match, rx))
{
continue;
}
auto path = sdk_path / "Platforms\\UAP" / match[1].str() / "Platform.xml";
if (!std::filesystem::exists(path))
{
continue;
}
char* next_part = subkey.data();
bool force_newer = false;
for (size_t i = 0; ; ++i)
{
auto version_part = strtoul(next_part, &next_part, 10);
if ((version_part < version_parts[i]) && !force_newer)
{
break;
}
else if (version_part > version_parts[i])
{
// E.g. ensure something like '2.1' is considered newer than '1.2'
force_newer = true;
}
version_parts[i] = version_part;
if (i == std::size(version_parts) - 1)
{
result = subkey.data();
break;
}
if (!next_part)
{
break;
}
++next_part;
}
}
if (result.empty())
{
throw std::invalid_argument("Could not find the Windows SDK");
}
return result;
}
}

51
inc/task_group.h Normal file
Просмотреть файл

@ -0,0 +1,51 @@
#pragma once
#include "impl/base.h"
namespace xlang
{
struct task_group
{
task_group(task_group const&) = delete;
task_group& operator=(task_group const&) = delete;
task_group() noexcept = default;
~task_group() noexcept
{
for (auto&& task : m_tasks)
{
task.wait();
}
}
template <typename T>
void add(T&& callback)
{
#if defined(XLANG_DEBUG)
callback();
#else
m_tasks.push_back(std::async(std::forward<T>(callback)));
#endif
}
void get()
{
auto tasks = std::move(m_tasks);
for (auto&& task : tasks)
{
task.wait();
}
for (auto&& task : tasks)
{
task.get();
}
}
private:
std::vector<std::future<void>> m_tasks;
};
}

499
inc/text_writer.h Normal file
Просмотреть файл

@ -0,0 +1,499 @@
#pragma once
#include <assert.h>
#include <filesystem>
#include <fstream>
#include <sstream>
#include <string>
#include <string_view>
namespace xlang::text
{
inline std::string file_to_string(std::string const& filename)
{
std::ifstream file(filename, std::ios::binary);
return static_cast<std::stringstream const&>(std::stringstream() << file.rdbuf()).str();
}
template <typename T>
struct writer_base
{
writer_base(writer_base const&) = delete;
writer_base& operator=(writer_base const&) = delete;
writer_base()
{
m_first.reserve(16 * 1024);
}
template <typename... Args>
void write(std::string_view const& value, Args const&... args)
{
#if defined(XLANG_DEBUG)
auto expected = count_placeholders(value);
auto actual = sizeof...(Args);
XLANG_ASSERT(expected == actual);
#endif
write_segment(value, args...);
}
template <typename... Args>
std::string write_temp(std::string_view const& value, Args const&... args)
{
#if defined(XLANG_DEBUG)
bool restore_debug_trace = debug_trace;
debug_trace = false;
#endif
auto const size = m_first.size();
XLANG_ASSERT(count_placeholders(value) == sizeof...(Args));
write_segment(value, args...);
std::string result{ m_first.data() + size, m_first.size() - size };
m_first.resize(size);
#if defined(XLANG_DEBUG)
debug_trace = restore_debug_trace;
#endif
return result;
}
void write_impl(std::string_view const& value)
{
m_first.insert(m_first.end(), value.begin(), value.end());
#if defined(XLANG_DEBUG)
if (debug_trace)
{
::printf("%.*s", static_cast<int>(value.size()), value.data());
}
#endif
}
void write_impl(char const value)
{
m_first.push_back(value);
#if defined(XLANG_DEBUG)
if (debug_trace)
{
::printf("%c", value);
}
#endif
}
void write(std::string_view const& value)
{
static_cast<T*>(this)->write_impl(value);
}
void write(char const value)
{
static_cast<T*>(this)->write_impl(value);
}
void write_code(std::string_view const& value)
{
write(value);
}
template <typename F, typename = std::enable_if_t<std::is_invocable_v<F, T&>>>
void write(F const& f)
{
f(*static_cast<T*>(this));
}
void write(int32_t const value)
{
write(std::to_string(value));
}
void write(uint32_t const value)
{
write(std::to_string(value));
}
void write(int64_t const value)
{
write(std::to_string(value));
}
void write(uint64_t const value)
{
write(std::to_string(value));
}
template <typename... Args>
void write_printf(char const* format, Args const&... args)
{
char buffer[128];
#if XLANG_PLATFORM_WINDOWS
size_t const size = sprintf_s(buffer, format, args...);
#else
size_t const size = snprintf(buffer, sizeof(buffer), format, args...);
#endif
write(std::string_view{ buffer, size });
}
template <auto F, typename List, typename... Args>
void write_each(List const& list, Args const&... args)
{
for (auto&& item : list)
{
F(*static_cast<T*>(this), item, args...);
}
}
void swap() noexcept
{
std::swap(m_second, m_first);
}
void flush_to_console() noexcept
{
printf("%.*s", static_cast<int>(m_first.size()), m_first.data());
printf("%.*s", static_cast<int>(m_second.size()), m_second.data());
m_first.clear();
m_second.clear();
}
void flush_to_file(std::string const& filename)
{
if (!file_equal(filename))
{
std::ofstream file{ filename, std::ios::out | std::ios::binary };
file.write(m_first.data(), m_first.size());
file.write(m_second.data(), m_second.size());
}
m_first.clear();
m_second.clear();
}
void flush_to_file(std::filesystem::path const& filename)
{
flush_to_file(filename.string());
}
std::string flush_to_string()
{
std::string result;
result.reserve(m_first.size() + m_second.size());
result.assign(m_first.begin(), m_first.end());
result.append(m_second.begin(), m_second.end());
m_first.clear();
m_second.clear();
return result;
}
char back()
{
return m_first.empty() ? char{} : m_first.back();
}
bool file_equal(std::string const& filename) const
{
if (!std::filesystem::exists(filename))
{
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;
}
return std::equal(m_second.begin(), m_second.end(), file.begin() + m_first.size(), file.end());
}
#if defined(XLANG_DEBUG)
bool debug_trace{};
#endif
private:
static constexpr uint32_t count_placeholders(std::string_view const& format) noexcept
{
uint32_t count{};
bool escape{};
for (auto c : format)
{
if (!escape)
{
if (c == '^')
{
escape = true;
continue;
}
if (c == '%' || c == '@')
{
++count;
}
}
escape = false;
}
return count;
}
void write_segment(std::string_view const& value)
{
auto offset = value.find_first_of("^");
if (offset == std::string_view::npos)
{
write(value);
return;
}
write(value.substr(0, offset));
assert(offset != value.size() - 1);
write(value[offset + 1]);
write_segment(value.substr(offset + 2));
}
template <typename First, typename... Rest>
void write_segment(std::string_view const& value, First const& first, Rest const&... rest)
{
auto offset = value.find_first_of("^%@");
assert(offset != std::string_view::npos);
write(value.substr(0, offset));
if (value[offset] == '^')
{
assert(offset != value.size() - 1);
write(value[offset + 1]);
write_segment(value.substr(offset + 2), first, rest...);
}
else
{
if (value[offset] == '%')
{
static_cast<T*>(this)->write(first);
}
else
{
if constexpr (std::is_convertible_v<First, std::string_view>)
{
static_cast<T*>(this)->write_code(first);
}
else
{
assert(false); // '@' placeholders are only for text.
}
}
write_segment(value.substr(offset + 1), rest...);
}
}
std::vector<char> m_second;
std::vector<char> m_first;
};
template <typename T>
struct indented_writer_base : writer_base<T>
{
struct indent_guard
{
indent_guard(indented_writer_base<T>& w, int32_t offset = 1) noexcept : m_writer(w), m_offset(offset)
{
m_writer.m_indent += m_offset;
}
~indent_guard() noexcept
{
m_writer.m_indent -= m_offset;
}
private:
indented_writer_base<T>& m_writer;
int32_t m_offset{};
};
void write_indent()
{
for (int32_t i = 0; i < m_indent; i++)
{
writer_base<T>::write_impl(" ");
}
}
void write_impl(std::string_view const& value)
{
std::string_view::size_type current_pos{ 0 };
auto on_new_line = writer_base<T>::back() == '\n';
while (true)
{
const auto pos = value.find('\n', current_pos);
if (pos == std::string_view::npos)
{
if (current_pos < value.size())
{
if (on_new_line)
{
write_indent();
}
writer_base<T>::write_impl(value.substr(current_pos));
}
return;
}
auto current_line = value.substr(current_pos, pos - current_pos + 1);
auto empty_line = current_line[0] == '\n';
if (on_new_line && !empty_line)
{
write_indent();
}
writer_base<T>::write_impl(current_line);
on_new_line = true;
current_pos = pos + 1;
}
}
void write_impl(char const value)
{
if (writer_base<T>::back() == '\n' && value != '\n')
{
write_indent();
}
writer_base<T>::write_impl(value);
}
template <typename... Args>
std::string write_temp(std::string_view const& value, Args const& ... args)
{
auto restore_indent = m_indent;
m_indent = 0;
auto result = writer_base<T>::write_temp(value, args...);
m_indent = restore_indent;
return result;
}
int32_t m_indent{};
};
template <auto F, typename... Args>
auto bind(Args&&... args)
{
return [&](auto& writer)
{
F(writer, args...);
};
}
template <typename F, typename... Args>
auto bind(F fwrite, Args const&... args)
{
return [&, fwrite](auto& writer)
{
fwrite(writer, args...);
};
}
template <auto F, typename List, typename... Args>
auto bind_each(List const& list, Args const&... args)
{
return [&](auto& writer)
{
for (auto&& item : list)
{
F(writer, item, args...);
}
};
}
template <typename List, typename... Args>
auto bind_each(List const& list, Args const&... args)
{
return [&](auto& writer)
{
for (auto&& item : list)
{
writer.write(item, args...);
}
};
}
template <typename F, typename List, typename... Args>
auto bind_each(F fwrite, List const& list, Args const&... args)
{
return [&, fwrite](auto& writer)
{
for (auto&& item : list)
{
fwrite(writer, item, args...);
}
};
}
template <auto F, typename T, typename... Args>
auto bind_list(std::string_view const& delimiter, T const& list, Args const&... args)
{
return [&](auto& writer)
{
bool first{ true };
for (auto&& item : list)
{
if (first)
{
first = false;
}
else
{
writer.write(delimiter);
}
F(writer, item, args...);
}
};
}
template <typename T>
auto bind_list(std::string_view const& delimiter, T const& list)
{
return [&](auto& writer)
{
bool first{ true };
for (auto&& item : list)
{
if (first)
{
first = false;
}
else
{
writer.write(delimiter);
}
writer.write(item);
}
};
}
}

25
natvis/CMakeLists.txt Normal file
Просмотреть файл

@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.9)
# The natvis cppwinrtvisualizer.dll is only targeted at Visual Studio (on Windows)
if (WIN32 AND ("$ENV{VSCMD_ARG_TGT_ARCH}" STREQUAL "x86"))
file(TO_NATIVE_PATH "${CMAKE_BINARY_DIR}/build_tools/nuget.exe" nuget_exe)
file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/" cppwinrt_natvis_dir_x86)
file(TO_NATIVE_PATH ${cppwinrt_natvis_dir_x86}/cppwinrtvisualizer.dll cppwinrtvisualizer_dll)
string(REGEX REPLACE "x86" "x64" cppwinrt_natvis_dir_x64 ${cppwinrt_natvis_dir_x86})
set(build_visualizer msbuild ${CMAKE_CURRENT_SOURCE_DIR}/cppwinrtvisualizer.vcxproj /nologo /m /p:Configuration=${CMAKE_BUILD_TYPE})
file(DOWNLOAD https://dist.nuget.org/win-x86-commandline/latest/nuget.exe ${nuget_exe})
add_custom_command(OUTPUT ${cppwinrtvisualizer_dll}
COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} & ${nuget_exe} restore
COMMAND ${build_visualizer} /p:Platform=x86,OutDir=${cppwinrt_natvis_dir_x86}
COMMAND ${build_visualizer} /p:Platform=x64,OutDir=${cppwinrt_natvis_dir_x64}
)
add_custom_target(cppwinrtvisualizer ALL DEPENDS ${cppwinrtvisualizer_dll})
set_target_properties(cppwinrtvisualizer PROPERTIES "cppwinrt_natvis_dir_x86" ${cppwinrt_natvis_dir_x86})
endif()

8
natvis/SignConfig.xml Normal file
Просмотреть файл

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<SignConfigXML>
<job configuration="Release" dest="__OUTPATHROOT__" jobname="CppWinRT Tools" approvers="">
<file src="__INPATHROOT__\x86\cppwinrt\cppwinrt.exe" signType="400" dest="__OUTPATHROOT__\x86\cppwinrt.exe" />
<file src="__INPATHROOT__\x86\cppwinrtvisualizer.dll" signType="400" dest="__OUTPATHROOT__\x86\cppwinrtvisualizer.dll" />
<file src="__INPATHROOT__\x64\cppwinrtvisualizer.dll" signType="400" dest="__OUTPATHROOT__\x64\cppwinrtvisualizer.dll" />
</job>
</SignConfigXML>

58
natvis/cppwinrt.natvis Normal file
Просмотреть файл

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<!--Visualize top-level C++/WinRT objects containing ABI pointers-->
<Type Name="winrt::Windows::Foundation::IInspectable">
<CustomVisualizer Condition="m_ptr != 0" VisualizerId="2ec1a02f-997c-4693-840e-88ffa1e21b56"/>
<DisplayString Condition="m_ptr == 0">null</DisplayString>
</Type>
<!--Visualize nested object properties via raw ABI pointers-->
<Type Name="winrt::impl::IInspectable">
<CustomVisualizer Condition="this != 0" VisualizerId="2ec1a02f-997c-4693-840e-88ffa1e21b56"/>
<DisplayString Condition="this == 0">null</DisplayString>
</Type>
<Type Name="winrt::impl::inspectable_abi">
<CustomVisualizer Condition="this != 0" VisualizerId="2ec1a02f-997c-4693-840e-88ffa1e21b56"/>
<DisplayString Condition="this == 0">null</DisplayString>
</Type>
<!--Visualize all raw IInspectable pointers-->
<Type Name="IInspectable">
<CustomVisualizer Condition="this != 0" VisualizerId="2ec1a02f-997c-4693-840e-88ffa1e21b56"/>
<DisplayString Condition="this == 0">null</DisplayString>
</Type>
<!--Primitive type visualizers-->
<Type Name="winrt::com_ptr&lt;*&gt;">
<DisplayString>{m_ptr}</DisplayString>
<Expand>
<ExpandedItem>m_ptr</ExpandedItem>
</Expand>
</Type>
<Type Name="winrt::guid">
<DisplayString>{*((GUID*)this)}</DisplayString>
<StringView>*((GUID*)this)</StringView>
</Type>
<Type Name="winrt::hresult">
<DisplayString>{value,hr}</DisplayString>
</Type>
<Type Name="winrt::hstring">
<DisplayString>{m_handle.m_value,sh}</DisplayString>
<StringView>m_handle.m_value,sh</StringView>
<Expand>
<Item Name="size">WindowsGetStringLen(m_handle.m_value)</Item>
<Item Name="[ptr]">WindowsGetStringRawBuffer(m_handle.m_value, nullptr)</Item>
</Expand>
</Type>
<Type Name="winrt::param::hstring">
<DisplayString>{m_handle,sh}</DisplayString>
<StringView>m_handle,sh</StringView>
<Expand>
<Item Name="size">WindowsGetStringLen(m_handle)</Item>
<Item Name="[ptr]">WindowsGetStringRawBuffer(m_handle, nullptr)</Item>
</Expand>
</Type>
<Type Name="winrt::Windows::Foundation::IUnknown">
<DisplayString>{m_ptr}</DisplayString>
<Expand>
<ExpandedItem>m_ptr</ExpandedItem>
</Expand>
</Type>
</AutoVisualizer>

Просмотреть файл

@ -0,0 +1,365 @@
#include "pch.h"
#include "cppwinrt_visualizer.h"
#include "object_visualizer.h"
#include "property_visualizer.h"
using namespace Microsoft::VisualStudio::Debugger;
using namespace Microsoft::VisualStudio::Debugger::Evaluation;
using namespace Microsoft::VisualStudio::Debugger::Telemetry;
using namespace Microsoft::VisualStudio::Debugger::DefaultPort;
using namespace std::filesystem;
using namespace winrt;
using namespace xlang;
using namespace xlang::meta;
using namespace xlang::meta::reader;
std::vector<std::string> db_files;
std::unique_ptr<cache> db;
void MetadataDiagnostic(DkmProcess* process, std::wstring const& status, std::filesystem::path const& path)
{
auto path_str = path.string();
auto message = status + std::wstring(path_str.begin(), path_str.end());
NatvisDiagnostic(process, message, NatvisDiagnosticLevel::Verbose);
}
HRESULT DownloadMetadata(DkmProcess* process, std::filesystem::path const& remote_path, std::filesystem::path const& local_path)
{
auto conn = process->Connection();
if ((conn->Flags() & DkmTransportConnectionFlags_t::LocalComputer) != 0)
{
return E_FAIL;
}
com_ptr<DkmString> root_dir;
IF_FAIL_RET(DkmString::Create(remote_path.parent_path().c_str(), root_dir.put()));
com_ptr<DkmString> search_spec;
IF_FAIL_RET(DkmString::Create(remote_path.filename().c_str(), search_spec.put()));
DkmArray<DkmFileInfo*> results;
IF_FAIL_RET(conn->GetFileListing(root_dir.get(), search_spec.get(), false, &results));
if (results.Length != 1)
{
return E_FAIL;
}
auto& remote_listing = results.Members[0];
auto remote_file_size = remote_listing->FileSize();
file_time_type remote_file_time{ file_time_type::duration(remote_listing->LastWriteTime()) };
auto remote_file_path = remote_listing->FilePath();
auto remote_file_name = remote_listing->FileName(); remote_file_name;
if (exists(local_path))
{
auto local_file_time = last_write_time(local_path);
auto local_file_size = file_size(local_path);
if ((local_file_time >= remote_file_time) && (local_file_size == remote_file_size))
{
return S_OK;
}
}
MetadataDiagnostic(process, L"Downloading ", remote_path);
com_ptr<DkmString> local_file_path;
IF_FAIL_RET(DkmString::Create(local_path.c_str(), local_file_path.put()));
IF_FAIL_RET(conn->DownloadFile(remote_file_path, local_file_path.get(), true));
last_write_time(local_path, remote_file_time);
return S_OK;
}
// If local file found, use it
// If newer remote file found, download it to cache
// If cached file found (downloaded or not), use it
bool FindMetadata(DkmProcess* process, std::filesystem::path& winmd_path)
{
if (exists(winmd_path))
{
return true;
}
auto cached_path = winmd_path;
cached_path = std::filesystem::temp_directory_path();
cached_path.replace_filename(winmd_path.filename().c_str());
DownloadMetadata(process, winmd_path, cached_path);
if (exists(cached_path))
{
winmd_path = cached_path;
return true;
}
return false;
}
// If type not indexed, simulate RoGetMetaDataFile's strategy for finding app-local metadata
// and add to the database dynamically. RoGetMetaDataFile looks for types in the current process
// so cannot be called directly.
void LoadMetadata(DkmProcess* process, WCHAR const* processPath, std::string_view const& typeName)
{
auto winmd_path = path{ processPath };
auto probe_file = std::string{ typeName };
do
{
winmd_path.replace_filename(probe_file + ".winmd");
MetadataDiagnostic(process, L"Looking for ", winmd_path);
if (FindMetadata(process, winmd_path))
{
MetadataDiagnostic(process, L"Loaded ", winmd_path);
db_files.push_back(winmd_path.string());
}
auto pos = probe_file.rfind('.');
if (pos == std::string::npos)
{
break;
}
probe_file = probe_file.substr(0, pos);
} while (true);
db.reset(new cache(db_files));
}
TypeDef FindType(DkmProcess* process, std::string_view const& typeName)
{
auto type = db->find(typeName);
if (!type)
{
auto processPath = process->Path()->Value();
LoadMetadata(process, processPath, typeName);
type = db->find(typeName);
if (!type)
{
NatvisDiagnostic(process,
std::wstring(L"Could not find metadata for ") + std::wstring(typeName.begin(), typeName.end()), NatvisDiagnosticLevel::Error);
}
}
return type;
}
cppwinrt_visualizer::cppwinrt_visualizer()
{
try
{
std::array<char, MAX_PATH> local{};
#ifdef _WIN64
ExpandEnvironmentStringsA("%windir%\\System32\\WinMetadata", local.data(), static_cast<DWORD>(local.size()));
#else
ExpandEnvironmentStringsA("%windir%\\SysNative\\WinMetadata", local.data(), static_cast<DWORD>(local.size()));
#endif
for (auto&& file : std::filesystem::directory_iterator(local.data()))
{
if (std::filesystem::is_regular_file(file))
{
db_files.push_back(file.path().string());
}
}
db.reset(new cache(db_files));
}
catch (...)
{
// If unable to read metadata, don't take down VS
}
// Log an event for telemetry purposes when the visualizer is brought online
com_ptr<DkmString> eventName;
if SUCCEEDED(DkmString::Create(DkmSourceString(L"vs/vc/diagnostics/cppwinrtvisualizer/objectconstructed"), eventName.put()))
{
com_ptr<DkmTelemetryEvent> error;
if SUCCEEDED(DkmTelemetryEvent::Create(eventName.get(), nullptr, nullptr, error.put()))
{
error->Post();
}
}
}
cppwinrt_visualizer::~cppwinrt_visualizer()
{
db_files.clear();
db.reset();
}
HRESULT cppwinrt_visualizer::EvaluateVisualizedExpression(
_In_ DkmVisualizedExpression* pVisualizedExpression,
_Deref_out_ DkmEvaluationResult** ppResultObject
)
{
try
{
com_ptr<IUnknown> pUnkTypeSymbol;
IF_FAIL_RET(pVisualizedExpression->GetSymbolInterface(__uuidof(IDiaSymbol), pUnkTypeSymbol.put()));
com_ptr<IDiaSymbol> pTypeSymbol = pUnkTypeSymbol.as<IDiaSymbol>();
CComBSTR bstrTypeName;
IF_FAIL_RET(pTypeSymbol->get_name(&bstrTypeName));
// Visualize top-level C++/WinRT objects containing ABI pointers
bool isAbiObject;
if (wcscmp(bstrTypeName, L"winrt::Windows::Foundation::IInspectable") == 0)
{
isAbiObject = false;
}
// Visualize nested object properties via raw ABI pointers
else if ((wcscmp(bstrTypeName, L"winrt::impl::IInspectable") == 0) ||
(wcscmp(bstrTypeName, L"winrt::impl::inspectable_abi") == 0))
{
isAbiObject = true;
}
// Visualize all raw IInspectable pointers
else if (wcscmp(bstrTypeName, L"IInspectable") == 0)
{
isAbiObject = true;
}
else
{
// unrecognized type
NatvisDiagnostic(pVisualizedExpression,
std::wstring(L"Unrecognized type: ") + (LPWSTR)bstrTypeName, NatvisDiagnosticLevel::Error);
return S_OK;
}
IF_FAIL_RET(object_visualizer::CreateEvaluationResult(pVisualizedExpression, isAbiObject, ppResultObject));
return S_OK;
}
catch (...)
{
// If something goes wrong, just fail to display object/property. Don't take down VS.
NatvisDiagnostic(pVisualizedExpression,
L"Exception in cppwinrt_visualizer::EvaluateVisualizedExpression", NatvisDiagnosticLevel::Error, to_hresult());
return E_FAIL;
}
}
HRESULT cppwinrt_visualizer::UseDefaultEvaluationBehavior(
_In_ DkmVisualizedExpression* /*pVisualizedExpression*/,
_Out_ bool* pUseDefaultEvaluationBehavior,
_Deref_out_opt_ DkmEvaluationResult** ppDefaultEvaluationResult
)
{
*pUseDefaultEvaluationBehavior = false;
*ppDefaultEvaluationResult = nullptr;
return S_OK;
}
HRESULT cppwinrt_visualizer::GetChildren(
_In_ DkmVisualizedExpression* pVisualizedExpression,
_In_ UINT32 InitialRequestSize,
_In_ DkmInspectionContext* pInspectionContext,
_Out_ DkmArray<DkmChildVisualizedExpression*>* pInitialChildren,
_Deref_out_ DkmEvaluationResultEnumContext** ppEnumContext
)
{
try
{
com_ptr<object_visualizer> pObjectVisualizer;
HRESULT hr = pVisualizedExpression->GetDataItem(pObjectVisualizer.put());
if (SUCCEEDED(hr))
{
IF_FAIL_RET(pObjectVisualizer->GetChildren(InitialRequestSize, pInspectionContext, pInitialChildren, ppEnumContext));
}
else
{
com_ptr<property_visualizer> pPropertyVisualizer;
hr = pVisualizedExpression->GetDataItem(pPropertyVisualizer.put());
if (SUCCEEDED(hr))
{
IF_FAIL_RET(pPropertyVisualizer->GetChildren(InitialRequestSize, pInspectionContext, pInitialChildren, ppEnumContext));
}
}
return hr;
}
catch (...)
{
// If something goes wrong, just fail to display object/property. Don't take down VS.
NatvisDiagnostic(pVisualizedExpression,
L"Exception in cppwinrt_visualizer::GetChildren", NatvisDiagnosticLevel::Error, to_hresult());
return E_FAIL;
}
}
HRESULT cppwinrt_visualizer::GetItems(
_In_ DkmVisualizedExpression* pVisualizedExpression,
_In_ DkmEvaluationResultEnumContext* pEnumContext,
_In_ UINT32 StartIndex,
_In_ UINT32 Count,
_Out_ DkmArray<DkmChildVisualizedExpression*>* pItems
)
{
try
{
com_ptr<object_visualizer> pObjectVisualizer;
HRESULT hr = pVisualizedExpression->GetDataItem(pObjectVisualizer.put());
if (SUCCEEDED(hr))
{
IF_FAIL_RET(pObjectVisualizer->GetItems(pVisualizedExpression, pEnumContext, StartIndex, Count, pItems));
}
else
{
com_ptr<property_visualizer> pPropertyVisualizer;
hr = pVisualizedExpression->GetDataItem(pPropertyVisualizer.put());
if (SUCCEEDED(hr))
{
IF_FAIL_RET(pPropertyVisualizer->GetItems(pEnumContext, StartIndex, Count, pItems));
}
}
return hr;
}
catch (...)
{
// If something goes wrong, just fail to display object/property. Don't take down VS.
NatvisDiagnostic(pVisualizedExpression,
L"Exception in cppwinrt_visualizer::GetItems", NatvisDiagnosticLevel::Error, to_hresult());
return E_FAIL;
}
}
HRESULT cppwinrt_visualizer::SetValueAsString(
_In_ DkmVisualizedExpression* pVisualizedExpression,
_In_ DkmString* pValue,
_In_ UINT32 Timeout,
_Deref_out_opt_ DkmString** ppErrorText
)
{
try
{
com_ptr<property_visualizer> pPropertyVisualizer;
HRESULT hr = pVisualizedExpression->GetDataItem(pPropertyVisualizer.put());
if (SUCCEEDED(hr))
{
IF_FAIL_RET(pPropertyVisualizer->SetValueAsString(pValue, Timeout, ppErrorText));
}
return hr;
}
catch (...)
{
// If something goes wrong, just fail to update object/property. Don't take down VS.
NatvisDiagnostic(pVisualizedExpression,
L"Exception in cppwinrt_visualizer::SetValueAsString", NatvisDiagnosticLevel::Error, to_hresult());
return E_FAIL;
}
}
HRESULT cppwinrt_visualizer::GetUnderlyingString(
_In_ DkmVisualizedExpression* pVisualizedExpression,
_Deref_out_opt_ DkmString** ppStringValue
)
{
try
{
com_ptr<property_visualizer> pPropertyVisualizer;
HRESULT hr = pVisualizedExpression->GetDataItem(pPropertyVisualizer.put());
if (SUCCEEDED(hr))
{
IF_FAIL_RET(pPropertyVisualizer->GetUnderlyingString(ppStringValue));
}
return hr;
}
catch (...)
{
// If something goes wrong, just fail to display object/property. Don't take down VS.
NatvisDiagnostic(pVisualizedExpression->RuntimeInstance()->Process(),
L"Exception in cppwinrt_visualizer::GetUnderlyingString", NatvisDiagnosticLevel::Error, to_hresult());
return E_FAIL;
}
}

Просмотреть файл

@ -0,0 +1,42 @@
#pragma once
struct cppwinrt_visualizer : winrt::implements<cppwinrt_visualizer,
::Microsoft::VisualStudio::Debugger::ComponentInterfaces::IDkmCustomVisualizer>
{
cppwinrt_visualizer();
~cppwinrt_visualizer();
STDMETHOD(EvaluateVisualizedExpression)(
_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression,
_Deref_out_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResult** ppResultObject
);
STDMETHOD(UseDefaultEvaluationBehavior)(
_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression,
_Out_ bool* pUseDefaultEvaluationBehavior,
_Deref_out_opt_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResult** ppDefaultEvaluationResult
);
STDMETHOD(GetChildren)(
_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression,
_In_ UINT32 InitialRequestSize,
_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmInspectionContext* pInspectionContext,
_Out_ Microsoft::VisualStudio::Debugger::DkmArray<Microsoft::VisualStudio::Debugger::Evaluation::DkmChildVisualizedExpression*>* pInitialChildren,
_Deref_out_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResultEnumContext** ppEnumContext
);
STDMETHOD(GetItems)(
_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression,
_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResultEnumContext* pEnumContext,
_In_ UINT32 StartIndex,
_In_ UINT32 Count,
_Out_ Microsoft::VisualStudio::Debugger::DkmArray<Microsoft::VisualStudio::Debugger::Evaluation::DkmChildVisualizedExpression*>* pItems
);
STDMETHOD(SetValueAsString)(
_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression,
_In_ Microsoft::VisualStudio::Debugger::DkmString* pValue,
_In_ UINT32 Timeout,
_Deref_out_opt_ Microsoft::VisualStudio::Debugger::DkmString** ppErrorText
);
STDMETHOD(GetUnderlyingString)(
_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression,
_Deref_out_opt_ Microsoft::VisualStudio::Debugger::DkmString** ppStringValue
);
};

Просмотреть файл

@ -0,0 +1,8 @@
; Copyright (c) Microsoft. All rights reserved.
; Licensed under the MIT license. See LICENSE file in the project root for full license information.
LIBRARY "CppWinRTVisualizer.DLL"
EXPORTS
DllCanUnloadNow PRIVATE
DllGetClassObject PRIVATE

Просмотреть файл

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cppwinrtvisualizer", "cppwinrtvisualizer.vcxproj", "{3C692D34-10C1-4707-B469-5EDB0EEF8AFC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3C692D34-10C1-4707-B469-5EDB0EEF8AFC}.Debug|x64.ActiveCfg = Debug|x64
{3C692D34-10C1-4707-B469-5EDB0EEF8AFC}.Debug|x64.Build.0 = Debug|x64
{3C692D34-10C1-4707-B469-5EDB0EEF8AFC}.Debug|x86.ActiveCfg = Debug|Win32
{3C692D34-10C1-4707-B469-5EDB0EEF8AFC}.Debug|x86.Build.0 = Debug|Win32
{3C692D34-10C1-4707-B469-5EDB0EEF8AFC}.Release|x64.ActiveCfg = Release|x64
{3C692D34-10C1-4707-B469-5EDB0EEF8AFC}.Release|x64.Build.0 = Release|x64
{3C692D34-10C1-4707-B469-5EDB0EEF8AFC}.Release|x86.ActiveCfg = Release|Win32
{3C692D34-10C1-4707-B469-5EDB0EEF8AFC}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {046F64AF-7E60-4532-BCDE-C7F5B5D7C03A}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -0,0 +1,260 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{3C692D34-10C1-4707-B469-5EDB0EEF8AFC}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>cppwinrtvisualizer</RootNamespace>
<TargetName>cppwinrtvisualizer</TargetName>
<NugetPackagesDirectory>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)packages\))</NugetPackagesDirectory>
</PropertyGroup>
<PropertyGroup Condition="'$(VisualStudioVersion)' &gt;= '16.0'">
<PlatformToolset>v142</PlatformToolset>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(VisualStudioVersion)' &lt; '16.0'">
<PlatformToolset>v141</PlatformToolset>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
<DIASDKInc>$(VSInstallDir)DIA SDK\include</DIASDKInc>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>x86\$(Configuration)\</OutDir>
<IntDir>x86\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>x64\$(Configuration)\</OutDir>
<IntDir>x64\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>x86\$(Configuration)\</OutDir>
<IntDir>x86\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>x64\$(Configuration)\</OutDir>
<IntDir>x64\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;VISUALIZER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(IntDir);..\..\..\library;$(DIASDKInc);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalOptions>/await</AdditionalOptions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
<AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
<AdditionalDependencies>advapi32.lib;shell32.lib;windowsapp.lib;$(VsDebugEng_Lib);%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>.\cppwinrtvisualizer.def</ModuleDefinitionFile>
<FullProgramDatabaseFile>true</FullProgramDatabaseFile>
<DelayLoadDLLs>vsdebugeng.dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>_DEBUG;VISUALIZER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(IntDir);..\..\..\library;$(DIASDKInc);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalOptions>/await</AdditionalOptions>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
<AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
<AdditionalDependencies>advapi32.lib;shell32.lib;windowsapp.lib;$(VsDebugEng_Lib);%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>.\cppwinrtvisualizer.def</ModuleDefinitionFile>
<DelayLoadDLLs>vsdebugeng.dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;VISUALIZER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(IntDir);..\..\..\library;$(DIASDKInc);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalOptions>/await</AdditionalOptions>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
<AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
<AdditionalDependencies>advapi32.lib;shell32.lib;windowsapp.lib;$(VsDebugEng_Lib);%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>.\cppwinrtvisualizer.def</ModuleDefinitionFile>
<DelayLoadDLLs>vsdebugeng.dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>NDEBUG;VISUALIZER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(IntDir);..\..\..\library;$(DIASDKInc);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalOptions>/await</AdditionalOptions>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
<AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
<AdditionalDependencies>advapi32.lib;shell32.lib;windowsapp.lib;$(VsDebugEng_Lib);%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>.\cppwinrtvisualizer.def</ModuleDefinitionFile>
<DelayLoadDLLs>vsdebugeng.dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="$(NugetPackagesDirectory)Microsoft.VSSDK.Debugger.VSDebugEng.*\inc\VSDebugEng.h" />
<ClInclude Include="$(NugetPackagesDirectory)Microsoft.VSSDK.Debugger.VSDebugEng.*\inc\vsdebugeng.templates.h" />
<ClInclude Include="object_visualizer.h" />
<ClInclude Include="cppwinrt_visualizer.h" />
<ClInclude Include="property_visualizer.h" />
<ClInclude Include="pch.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="object_visualizer.cpp" />
<ClCompile Include="cppwinrt_visualizer.cpp" />
<ClCompile Include="property_visualizer.cpp" />
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<VsdConfigXmlFiles Condition="'$(VisualStudioVersion)' == '15.0'" Include="cppwinrtvisualizer15.vsdconfigxml" />
<VsdConfigXmlFiles Condition="'$(VisualStudioVersion)' != '15.0'" Include="cppwinrtvisualizer.vsdconfigxml" />
</ItemGroup>
<ItemGroup>
<Natvis Include="cppwinrt.natvis" />
</ItemGroup>
<ItemGroup>
<None Include="cppwinrtvisualizer.def" />
<None Include="cppwinrtvisualizer.vsdconfigxml" />
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="$(NugetPackagesDirectory)Microsoft.VSSDK.Debugger.VSDConfigTool.*\content\vsdconfig.xsd">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<ItemGroup>
<Xsd Remove="vsdconfig.xsd" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="packages\Microsoft.VSSDK.Debugger.VSDConfigTool.16.0.2012201-preview\build\Microsoft.VSSDK.Debugger.VSDConfigTool.targets" Condition="Exists('packages\Microsoft.VSSDK.Debugger.VSDConfigTool.16.0.2012201-preview\build\Microsoft.VSSDK.Debugger.VSDConfigTool.targets')" />
<Import Project="packages\Microsoft.VSSDK.Debugger.VSDebugEng.16.0.2012201-preview\Microsoft.VSSDK.Debugger.VSDebugEng.targets" Condition="Exists('packages\Microsoft.VSSDK.Debugger.VSDebugEng.16.0.2012201-preview\Microsoft.VSSDK.Debugger.VSDebugEng.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('packages\Microsoft.VSSDK.Debugger.VSDConfigTool.16.0.2012201-preview\build\Microsoft.VSSDK.Debugger.VSDConfigTool.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.VSSDK.Debugger.VSDConfigTool.16.0.2012201-preview\build\Microsoft.VSSDK.Debugger.VSDConfigTool.targets'))" />
<Error Condition="!Exists('packages\Microsoft.VSSDK.Debugger.VSDebugEng.16.0.2012201-preview\Microsoft.VSSDK.Debugger.VSDebugEng.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.VSSDK.Debugger.VSDebugEng.16.0.2012201-preview\Microsoft.VSSDK.Debugger.VSDebugEng.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Configuration xmlns="http://schemas.microsoft.com/vstudio/vsdconfig/2008">
<DefineGuid Name="guidCppWinRTVisualizer" Value="2ec1a02f-997c-4693-840e-88ffa1e21b56"/>
<DefineGuid Name="guidCppWinRTVisualizerSourceId" Value="7168763a-71e1-4447-b5d1-a44a52986527" />
<NativeComponent ComponentId="1498d919-25ee-4913-910d-6f68b224b6e7" ComponentLevel="9991500" ModuleName="CppWinRTVisualizer.DLL">
<Class Name="CppWinrtVisualizer" ClassId="2ea3526b-93a1-4854-ae18-9028288f6f64" WorkerProcessSupported="true">
<Implements>
<InterfaceGroup>
<Filter>
<VisualizerId RequiredValue="guidCppWinRTVisualizer"/>
</Filter>
<Interface Name="IDkmCustomVisualizer"/>
</InterfaceGroup>
</Implements>
</Class>
</NativeComponent>
</Configuration>

Просмотреть файл

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Configuration xmlns="http://schemas.microsoft.com/vstudio/vsdconfig/2008">
<DefineGuid Name="guidCppWinRTVisualizer" Value="2ec1a02f-997c-4693-840e-88ffa1e21b56"/>
<DefineGuid Name="guidCppWinRTVisualizerSourceId" Value="7168763a-71e1-4447-b5d1-a44a52986527" />
<NativeComponent ComponentId="1498d919-25ee-4913-910d-6f68b224b6e7" ComponentLevel="9991500" ModuleName="CppWinRTVisualizer.DLL">
<Class Name="CppWinrtVisualizer" ClassId="2ea3526b-93a1-4854-ae18-9028288f6f64">
<Implements>
<InterfaceGroup>
<Filter>
<VisualizerId RequiredValue="guidCppWinRTVisualizer"/>
</Filter>
<Interface Name="IDkmCustomVisualizer"/>
</InterfaceGroup>
</Implements>
</Class>
</NativeComponent>
</Configuration>

54
natvis/dllmain.cpp Normal file
Просмотреть файл

@ -0,0 +1,54 @@
#include "pch.h"
#include "cppwinrt_visualizer.h"
using namespace winrt;
struct cppwinrt_visualizer_factory : implements<cppwinrt_visualizer_factory, IClassFactory>
{
HRESULT __stdcall CreateInstance(IUnknown* outer, GUID const& id, void** object) noexcept final
{
if (outer != nullptr)
{
return E_INVALIDARG;
}
com_ptr<IUnknown> temp = make<cppwinrt_visualizer>();
return temp->QueryInterface(id, object);
}
HRESULT __stdcall LockServer(BOOL) noexcept final
{
return S_OK;
}
};
extern "C" HRESULT STDAPICALLTYPE DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
{
*ppv = nullptr;
static constexpr GUID winrtVisualizerIID{ 0x2ea3526b, 0x93a1, 0x4854,{ 0xae, 0x18, 0x90, 0x28, 0x28, 0x8f, 0x6f, 0x64 } };
if (rclsid == winrtVisualizerIID)
{
try
{
com_ptr<IClassFactory> factory = make<cppwinrt_visualizer_factory>();
return factory->QueryInterface(riid, ppv);
}
catch (...)
{
return to_hresult();
}
}
return CLASS_E_CLASSNOTAVAILABLE;
}
STDAPI DllCanUnloadNow(void)
{
if (get_module_lock())
{
return S_FALSE;
}
return S_OK;
}

Просмотреть файл

@ -0,0 +1,719 @@
#include "pch.h"
#include <variant>
#include "object_visualizer.h"
#include "property_visualizer.h"
using namespace Microsoft::VisualStudio::Debugger;
using namespace Microsoft::VisualStudio::Debugger::Evaluation;
using namespace winrt;
using namespace xlang;
using namespace xlang::meta;
using namespace xlang::meta::reader;
template <typename...T> struct overloaded : T... { using T::operator()...; };
template <typename...T> overloaded(T...)->overloaded<T...>;
#define IID_IInspectable L"AF86E2E0-B12D-4C6A-9C5A-D7AA65101E90"
#define IID_IStringable L"96369F54-8EB6-48F0-ABCE-C1B211E627C3"
constexpr struct
{
PCWSTR propField;
PCWSTR displayType;
}
g_categoryData[] =
{
{ L"b", L"bool" },
{ L"c", L"wchar_t" },
{ L"i1", L"int8_t" },
{ L"u1", L"uint8_t" },
{ L"i2", L"int16_t" },
{ L"u2", L"uint16_t" },
{ L"i4", L"int32_t" },
{ L"u4", L"uint32_t" },
{ L"i8", L"int64_t" },
{ L"u8", L"uint64_t" },
{ L"r4", L"float" },
{ L"r8", L"double" },
{ L"s,sh", L"winrt::hstring" },
{ L"g", L"winrt::guid" },
};
NatvisDiagnosticLevel GetNatvisDiagnosticLevel()
{
static NatvisDiagnosticLevel level = NatvisDiagnosticLevel::Unknown;
if (level != NatvisDiagnosticLevel::Unknown)
{
return level;
}
level = NatvisDiagnosticLevel::Error;
// If < VS16, just output errors
if (!DkmComponentManager::IsApiVersionSupported(DkmApiVersion::VS16RTM))
{
return level;
}
// Else, use VS natvis diagnostics level directly
HKEY userSettingsKey;
if (FAILED(DkmGlobalSettings::OpenVSUserSettingsKey(L"Debugger\\NatvisDiagnostics", &userSettingsKey)))
{
return level;
}
char data[MAX_PATH];
DWORD dataSize = _countof(data);
if (RegGetValue(userSettingsKey, "", "Level", RRF_RT_REG_SZ, nullptr, data, &dataSize) == ERROR_SUCCESS)
{
switch (data[0])
{
case 'O':
level = NatvisDiagnosticLevel::Off;
break;
case 'E':
level = NatvisDiagnosticLevel::Error;
break;
case 'W':
level = NatvisDiagnosticLevel::Warning;
break;
case 'V':
level = NatvisDiagnosticLevel::Verbose;
break;
}
}
RegCloseKey(userSettingsKey);
return level;
}
HRESULT NatvisDiagnostic(DkmProcess* process, std::wstring_view const& messageText, NatvisDiagnosticLevel level, HRESULT errorCode)
{
if (GetNatvisDiagnosticLevel() < level)
{
return S_OK;
}
auto userMessage = std::wstring(L"Natvis C++/WinRT: ") + std::wstring(messageText) + L"\n";
com_ptr<DkmString> pUserMessageText;
IF_FAIL_RET(DkmString::Create(DkmSourceString(userMessage.c_str()), pUserMessageText.put()));
com_ptr<DkmUserMessage> pUserMessage;
IF_FAIL_RET(DkmUserMessage::Create(process->Connection(), process, DkmUserMessageOutputKind::UnfilteredOutputWindowMessage, pUserMessageText.get(), 0, errorCode, pUserMessage.put()));
return pUserMessage->Post();
}
static HRESULT EvaluatePropertyExpression(
_In_ PropertyData const& prop,
_In_ DkmVisualizedExpression* pExpression,
_In_ DkmPointerValueHome* pObject,
bool isAbiObject,
_Out_ com_ptr<DkmEvaluationResult>& pEvaluationResult
)
{
wchar_t abiAddress[40];
auto process = pExpression->RuntimeInstance()->Process();
bool is64Bit = ((process->SystemInformation()->Flags() & DefaultPort::DkmSystemInformationFlags::Is64Bit) != 0);
swprintf_s(abiAddress, is64Bit ? L"%s0x%I64x" : L"%s0x%08x", isAbiObject ? L"(::IUnknown*)" : L"*(::IUnknown**)", pObject->Address());
wchar_t wszEvalText[500];
std::wstring propCast;
PCWSTR propField;
if (prop.category < PropertyCategory::Value)
{
propField = g_categoryData[(int)prop.category].propField;
}
else
{
propField = L"v";
propCast = L"*(" + prop.abiType + L"*)";
}
swprintf_s(wszEvalText, L"%sWINRT_abi_val(%s, L\"{%s}\", %i).%s", propCast.c_str(), abiAddress, prop.iid.c_str(), prop.index, propField);
com_ptr<DkmString> pEvalText;
IF_FAIL_RET(DkmString::Create(DkmSourceString(wszEvalText), pEvalText.put()));
NatvisDiagnostic(process, wszEvalText, NatvisDiagnosticLevel::Verbose);
auto evalFlags = DkmEvaluationFlags::TreatAsExpression | DkmEvaluationFlags::ForceEvaluationNow | DkmEvaluationFlags::ForceRealFuncEval;
auto inspectionContext = pExpression->InspectionContext();
com_ptr<DkmLanguageExpression> pLanguageExpression;
IF_FAIL_RET(DkmLanguageExpression::Create(
inspectionContext->Language(),
evalFlags,
pEvalText.get(),
DkmDataItem::Null(),
pLanguageExpression.put()
));
com_ptr<DkmInspectionContext> pInspectionContext;
if ( (pExpression->InspectionContext()->EvaluationFlags() & evalFlags) != evalFlags)
{
DkmInspectionContext::Create(
inspectionContext->InspectionSession(),
inspectionContext->RuntimeInstance(),
inspectionContext->Thread(),
inspectionContext->Timeout(),
evalFlags,
inspectionContext->FuncEvalFlags(),
inspectionContext->Radix(),
inspectionContext->Language(),
inspectionContext->ReturnValue(),
pInspectionContext.put()
);
}
else
{
pInspectionContext.copy_from(inspectionContext);
}
auto hr = pExpression->EvaluateExpressionCallback(
pInspectionContext.get(),
pLanguageExpression.get(),
pExpression->StackFrame(),
pEvaluationResult.put()
);
if (hr != S_OK)
{
NatvisDiagnostic(process, L"EvaluateExpressionCallback failed", NatvisDiagnosticLevel::Warning, hr);
}
return hr;
}
static HRESULT EvaluatePropertyString(
_In_ PropertyData const& prop,
_In_ DkmVisualizedExpression* pExpression,
_In_ DkmPointerValueHome* pObject,
bool isAbiObject,
_Out_ com_ptr<DkmString>& pValue
)
{
com_ptr<DkmEvaluationResult> pEvaluationResult;
IF_FAIL_RET(EvaluatePropertyExpression(prop, pExpression, pObject, isAbiObject, pEvaluationResult));
if (pEvaluationResult->TagValue() != DkmEvaluationResult::Tag::SuccessResult)
{
return E_FAIL;
}
com_ptr<DkmSuccessEvaluationResult> pSuccessEvaluationResult = pEvaluationResult.as<DkmSuccessEvaluationResult>();
if (pSuccessEvaluationResult->Address()->Value() != 0)
{
pValue.copy_from(pSuccessEvaluationResult->Value());
}
return S_OK;
}
static std::string GetRuntimeClass(
_In_ DkmVisualizedExpression* pExpression,
_In_ DkmPointerValueHome* pObject,
bool isAbiObject
)
{
com_ptr<DkmString> pValue;
EvaluatePropertyString({ IID_IInspectable, -2, PropertyCategory::String }, pExpression, pObject, isAbiObject, pValue);
if (!pValue || pValue->Length() == 0)
{
return "";
}
return to_string(pValue->Value());
}
static HRESULT ObjectToString(
_In_ DkmVisualizedExpression* pExpression,
_In_ DkmPointerValueHome* pObject,
bool isAbiObject,
_Out_ com_ptr<DkmString>& pValue
)
{
if (SUCCEEDED(EvaluatePropertyString({ IID_IStringable, 0, PropertyCategory::String }, pExpression, pObject, isAbiObject, pValue)))
{
if (pValue && pValue->Length() > 0)
{
return S_OK;
}
pValue = nullptr;
// WINRT_abi_val returned 0, which may be success or failure (due to VirtualQuery validation)
// Call back for the runtime class name to determine which it was
if (!GetRuntimeClass(pExpression, pObject, isAbiObject).empty())
{
return DkmString::Create(L"<Expand object to view properties>", pValue.put());
}
}
// VirtualQuery validation failed (as determined by no runtime class name) or an
// exception escaped WINRT_abi_val (e.g, bad pointer, which we try to avoid via VirtualQuery)
return DkmString::Create(L"<Object uninitialized or information unavailable>", pValue.put());
}
static HRESULT CreateChildVisualizedExpression(
_In_ PropertyData const& prop,
_In_ DkmVisualizedExpression* pParent,
bool isAbiObject,
_Deref_out_ DkmChildVisualizedExpression** ppResult
)
{
*ppResult = nullptr;
com_ptr<DkmEvaluationResult> pEvaluationResult;
auto valueHome = make_com_ptr(pParent->ValueHome());
com_ptr<DkmPointerValueHome> pParentPointer = valueHome.as<DkmPointerValueHome>();
IF_FAIL_RET(EvaluatePropertyExpression(prop, pParent, pParentPointer.get(), isAbiObject, pEvaluationResult));
if (pEvaluationResult->TagValue() != DkmEvaluationResult::Tag::SuccessResult)
{
return E_FAIL;
}
com_ptr<DkmSuccessEvaluationResult> pSuccessEvaluationResult = pEvaluationResult.as<DkmSuccessEvaluationResult>();
com_ptr<DkmString> pValue;
com_ptr<DkmPointerValueHome> pChildPointer;
bool isNonNullObject = false;
if (prop.category == PropertyCategory::Class)
{
auto childObjectAddress = pSuccessEvaluationResult->Address()->Value();
if (childObjectAddress)
{
isNonNullObject = true;
IF_FAIL_RET(DkmPointerValueHome::Create(childObjectAddress, pChildPointer.put()));
IF_FAIL_RET(ObjectToString(pParent, pChildPointer.get(), true, pValue));
}
}
if(!isNonNullObject)
{
com_ptr<DkmExpressionValueHome> expressionValueHome = make_com_ptr(pParent->ValueHome());
pChildPointer = expressionValueHome.as<DkmPointerValueHome>();
pValue.copy_from(pSuccessEvaluationResult->Value());
}
com_ptr<DkmString> pDisplayName;
IF_FAIL_RET(DkmString::Create(prop.displayName.c_str(), pDisplayName.put()));
PCWSTR displayType;
if (prop.category < PropertyCategory::Value)
{
displayType = g_categoryData[(int)prop.category].displayType;
}
else
{
displayType = prop.displayType.c_str();
}
com_ptr<DkmString> pDisplayType;
IF_FAIL_RET(DkmString::Create(displayType, pDisplayType.put()));
com_ptr<DkmSuccessEvaluationResult> pVisualizedResult;
IF_FAIL_RET(DkmSuccessEvaluationResult::Create(
pParent->InspectionContext(),
pParent->StackFrame(),
pDisplayName.get(),
pSuccessEvaluationResult->FullName(),
pSuccessEvaluationResult->Flags(),
pValue.get(),
pSuccessEvaluationResult->EditableValue(),
pDisplayType.get(),
pSuccessEvaluationResult->Category(),
pSuccessEvaluationResult->Access(),
pSuccessEvaluationResult->StorageType(),
pSuccessEvaluationResult->TypeModifierFlags(),
pSuccessEvaluationResult->Address(),
pSuccessEvaluationResult->CustomUIVisualizers(),
pSuccessEvaluationResult->ExternalModules(),
DkmDataItem::Null(),
pVisualizedResult.put()
));
com_ptr<DkmChildVisualizedExpression> pChildVisualizedExpression;
IF_FAIL_RET(DkmChildVisualizedExpression::Create(
pParent->InspectionContext(),
pParent->VisualizerId(),
pParent->SourceId(),
pParent->StackFrame(),
pChildPointer.get(),
pVisualizedResult.get(),
pParent,
2,
DkmDataItem::Null(),
pChildVisualizedExpression.put()
));
if (isNonNullObject)
{
com_ptr<object_visualizer> pObjectVisualizer = make_self<object_visualizer>(pChildVisualizedExpression.get(), true);
IF_FAIL_RET(pChildVisualizedExpression->SetDataItem(DkmDataCreationDisposition::CreateNew, pObjectVisualizer.get()));
}
else
{
com_ptr<property_visualizer> pPropertyVisualizer = make_self<property_visualizer>(pChildVisualizedExpression.get(), pSuccessEvaluationResult.get());
IF_FAIL_RET(pChildVisualizedExpression->SetDataItem(DkmDataCreationDisposition::CreateNew, pPropertyVisualizer.get()));
}
*ppResult = pChildVisualizedExpression.detach();
return S_OK;
}
struct property_type
{
MethodDef get;
MethodDef set;
};
void GetInterfaceData(
DkmProcess* process,
coded_index<TypeDefOrRef> index,
_Inout_ std::vector<PropertyData>& propertyData,
_Out_ bool& isStringable
){
auto resolve_type_index = [](coded_index<TypeDefOrRef> index) -> TypeDef
{
switch (index.type())
{
case TypeDefOrRef::TypeDef:
{
return index.TypeDef();
}
case TypeDefOrRef::TypeRef:
{
return find_required(index.TypeRef());
}
case TypeDefOrRef::TypeSpec:
{
auto type_signature = index.TypeSpec().Signature();
auto signature = type_signature.GenericTypeInst();
return find_required(signature.GenericType().TypeRef());
}
}
return {};
};
auto type = resolve_type_index(index);
auto attribute = get_attribute(type, "Windows.Foundation.Metadata", "GuidAttribute");
if (!attribute)
{
throw_invalid("'Windows.Foundation.Metadata.GuidAttribute' attribute for type '", type.TypeNamespace(), ".", type.TypeName(), "' not found");
}
auto args = attribute.Value().FixedArgs();
std::string guid(68, '?');
int count = sprintf_s(guid.data(), guid.size() + 1,
"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X"
, std::get<uint32_t>(std::get<ElemSig>(args[0].value).value)
, std::get<uint16_t>(std::get<ElemSig>(args[1].value).value)
, std::get<uint16_t>(std::get<ElemSig>(args[2].value).value)
, std::get<uint8_t>(std::get<ElemSig>(args[3].value).value)
, std::get<uint8_t>(std::get<ElemSig>(args[4].value).value)
, std::get<uint8_t>(std::get<ElemSig>(args[5].value).value)
, std::get<uint8_t>(std::get<ElemSig>(args[6].value).value)
, std::get<uint8_t>(std::get<ElemSig>(args[7].value).value)
, std::get<uint8_t>(std::get<ElemSig>(args[8].value).value)
, std::get<uint8_t>(std::get<ElemSig>(args[9].value).value)
, std::get<uint8_t>(std::get<ElemSig>(args[10].value).value));
guid.resize(count);
std::wstring propIid(guid.cbegin(), guid.cend());
if (propIid == IID_IStringable)
{
isStringable = true;
return;
}
int32_t propIndex = -1;
for (auto&& method : type.MethodList())
{
propIndex++;
auto isGetter = method.Flags().SpecialName() && starts_with(method.Name(), "get_");
if (!isGetter)
{
continue;
}
PropertyCategory propCategory;
std::wstring propAbiType;
std::wstring propDisplayType;
auto retType = method.Signature().ReturnType();
std::visit(overloaded
{
[&](ElementType type)
{
if ((type < ElementType::Boolean) || (type > ElementType::String))
{
return;
}
propCategory = (PropertyCategory)(static_cast<std::underlying_type<ElementType>::type>(type) -
static_cast<std::underlying_type<ElementType>::type>(ElementType::Boolean));
},
[&](coded_index<TypeDefOrRef> const& index)
{
auto type = resolve_type_index(index);
auto typeName = type.TypeName();
if (typeName == "GUID"sv)
{
propCategory = PropertyCategory::Guid;
}
else
{
auto ns = std::string(type.TypeNamespace());
auto name = std::string(type.TypeName());
// Map numeric type names
if (ns == "Windows.Foundation.Numerics")
{
if (name == "Matrix3x2") { name = "float3x2"; }
else if (name == "Matrix4x4") { name = "float4x4"; }
else if (name == "Plane") { name = "plane"; }
else if (name == "Quaternion") { name = "quaternion"; }
else if (name == "Vector2") { name = "float2"; }
else if (name == "Vector3") { name = "float3"; }
else if (name == "Vector4") { name = "float4"; }
}
// Types come back from winmd files with '.', need to be '::'
// Ex. Windows.Foundation.Uri needs to be Windows::Foundation::Uri
auto fullTypeName = ns + "::" + name;
wchar_t cppTypename[500];
size_t i, j;
for (i = 0, j = 0; i < (fullTypeName.length() + 1); i++, j++)
{
if (fullTypeName[i] == L'.')
{
cppTypename[j++] = L':';
cppTypename[j] = L':';
}
else
{
cppTypename[j] = fullTypeName[i];
}
}
propDisplayType = std::wstring(L"winrt::") + cppTypename;
if(get_category(type) == category::class_type)
{
propCategory = PropertyCategory::Class;
propAbiType = L"winrt::impl::inspectable_abi*";
}
else
{
propCategory = PropertyCategory::Value;
propAbiType = propDisplayType;
}
}
},
[&](GenericTypeIndex /*var*/)
{
// TODO: generic properties
NatvisDiagnostic(process, L"Generics are not yet supported", NatvisDiagnosticLevel::Verbose);
},
[&](GenericMethodTypeIndex /*var*/)
{
throw_invalid("Generic methods not supported.");
},
[&](GenericTypeInstSig const& /*type*/)
{
// TODO: generic properties
NatvisDiagnostic(process, L"Generics are not yet supported", NatvisDiagnosticLevel::Verbose);
}
},
retType.Type().Type());
auto propName = method.Name().substr(4);
std::wstring propDisplayName(propName.cbegin(), propName.cend());
propertyData.push_back({ propIid, propIndex, propCategory, propAbiType, propDisplayType, propDisplayName });
}
}
void object_visualizer::GetPropertyData()
{
auto valueHome = make_com_ptr(m_pVisualizedExpression->ValueHome());
com_ptr<DkmPointerValueHome> pObject = valueHome.as<DkmPointerValueHome>();
auto rc = GetRuntimeClass(m_pVisualizedExpression.get(), pObject.get(), m_isAbiObject);
if (rc.empty())
{
return;
}
auto process = m_pVisualizedExpression->RuntimeInstance()->Process();
// runtime class name is delimited by L"..."
GetTypeProperties(process, std::string_view{ rc.data() + 2, rc.length() - 3 });
}
void object_visualizer::GetTypeProperties(Microsoft::VisualStudio::Debugger::DkmProcess* process, std::string_view const& type_name)
{
auto type = FindType(process, type_name);
if (!type)
{
return;
}
if (get_category(type) == category::class_type)
{
auto const& [extends_namespace, extends_name] = get_base_class_namespace_and_name(type);
if(!extends_namespace.empty() && !extends_name.empty())
{
auto base_type = std::string(extends_namespace) + "." + std::string(extends_name);
if (base_type != "System.Object")
{
GetTypeProperties(process, base_type);
}
}
auto impls = type.InterfaceImpl();
for (auto&& impl : impls)
{
GetInterfaceData(process, impl.Interface(), m_propertyData, m_isStringable);
}
}
else if (get_category(type) == category::interface_type)
{
auto impls = type.InterfaceImpl();
for (auto&& impl : impls)
{
GetInterfaceData(process, impl.Interface(), m_propertyData, m_isStringable);
}
GetInterfaceData(process, type.coded_index<TypeDefOrRef>(), m_propertyData, m_isStringable);
}
}
HRESULT object_visualizer::CreateEvaluationResult(_In_ DkmVisualizedExpression* pVisualizedExpression, _In_ bool isAbiObject, _Deref_out_ DkmEvaluationResult** ppResultObject)
{
com_ptr<object_visualizer> pObjectVisualizer = make_self<object_visualizer>(pVisualizedExpression, isAbiObject);
IF_FAIL_RET(pVisualizedExpression->SetDataItem(DkmDataCreationDisposition::CreateNew, pObjectVisualizer.get()));
IF_FAIL_RET(pObjectVisualizer->CreateEvaluationResult(ppResultObject));
IF_FAIL_RET(pVisualizedExpression->SetDataItem(DkmDataCreationDisposition::CreateNew, *ppResultObject));
return S_OK;
}
HRESULT object_visualizer::CreateEvaluationResult(_Deref_out_ DkmEvaluationResult** ppResultObject)
{
com_ptr<DkmRootVisualizedExpression> pRootVisualizedExpression = m_pVisualizedExpression.as<DkmRootVisualizedExpression>();
auto valueHome = make_com_ptr(m_pVisualizedExpression->ValueHome());
com_ptr<DkmPointerValueHome> pPointerValueHome = valueHome.as<DkmPointerValueHome>();
com_ptr<DkmString> pValue;
IF_FAIL_RET(ObjectToString(m_pVisualizedExpression.get(), pPointerValueHome.get(), m_isAbiObject, pValue));
com_ptr<DkmDataAddress> pAddress;
IF_FAIL_RET(DkmDataAddress::Create(m_pVisualizedExpression->StackFrame()->RuntimeInstance(), pPointerValueHome->Address(), nullptr, pAddress.put()));
com_ptr<DkmSuccessEvaluationResult> pSuccessEvaluationResult;
IF_FAIL_RET(DkmSuccessEvaluationResult::Create(
m_pVisualizedExpression->InspectionContext(),
m_pVisualizedExpression->StackFrame(),
pRootVisualizedExpression->Name(),
pRootVisualizedExpression->FullName(),
DkmEvaluationResultFlags::Expandable | DkmEvaluationResultFlags::ReadOnly,
pValue.get(),
pValue.get(),
pRootVisualizedExpression->Type(),
DkmEvaluationResultCategory::Class,
DkmEvaluationResultAccessType::None,
DkmEvaluationResultStorageType::None,
DkmEvaluationResultTypeModifierFlags::None,
pAddress.get(),
(DkmReadOnlyCollection<DkmCustomUIVisualizerInfo*>*)nullptr,
(DkmReadOnlyCollection<DkmModuleInstance*>*)nullptr,
DkmDataItem::Null(),
pSuccessEvaluationResult.put()
));
pSuccessEvaluationResult->SetDataItem(DkmDataCreationDisposition::CreateNew, this);
*ppResultObject = (DkmEvaluationResult*)pSuccessEvaluationResult.detach();
return S_OK;
}
HRESULT object_visualizer::GetChildren(
_In_ UINT32 /*InitialRequestSize*/,
_In_ DkmInspectionContext* pInspectionContext,
_Out_ DkmArray<DkmChildVisualizedExpression*>* pInitialChildren,
_Deref_out_ DkmEvaluationResultEnumContext** ppEnumContext
)
{
// Ignore metadata errors to ensure that Raw Data is always available
try
{
GetPropertyData();
}
catch (...)
{
NatvisDiagnostic(m_pVisualizedExpression.get(),
L"Exception in object_visualizer::GetPropertyData", NatvisDiagnosticLevel::Error, to_hresult());
}
com_ptr<DkmEvaluationResultEnumContext> pEnumContext;
IF_FAIL_RET(DkmEvaluationResultEnumContext::Create(
static_cast<uint32_t>(m_propertyData.size()),
m_pVisualizedExpression->StackFrame(),
pInspectionContext,
this,
pEnumContext.put()));
DkmAllocArray(0, pInitialChildren);
*ppEnumContext = pEnumContext.detach();
return S_OK;
}
HRESULT object_visualizer::GetItems(
_In_ DkmVisualizedExpression* /*pVisualizedExpression*/,
_In_ DkmEvaluationResultEnumContext* /*pEnumContext*/,
_In_ UINT32 StartIndex,
_In_ UINT32 Count,
_Out_ DkmArray<DkmChildVisualizedExpression*>* pItems
)
{
std::list<com_ptr<DkmChildVisualizedExpression>> childItems;
auto pParent = m_pVisualizedExpression.get();
for( auto childIndex = StartIndex; childIndex < StartIndex + Count; ++childIndex)
{
auto& prop = m_propertyData[childIndex];
com_ptr<DkmChildVisualizedExpression> pPropertyVisualized;
if(FAILED(CreateChildVisualizedExpression(prop, pParent, m_isAbiObject, pPropertyVisualized.put())))
{
com_ptr<DkmString> pErrorMessage;
IF_FAIL_RET(DkmString::Create(L"<Property evaluation failed>", pErrorMessage.put()));
com_ptr<DkmString> pDisplayName;
IF_FAIL_RET(DkmString::Create(prop.displayName.c_str(), pDisplayName.put()));
com_ptr<DkmFailedEvaluationResult> pVisualizedResult;
IF_FAIL_RET(DkmFailedEvaluationResult::Create(
pParent->InspectionContext(),
pParent->StackFrame(),
pDisplayName.get(),
nullptr,
pErrorMessage.get(),
DkmEvaluationResultFlags::ExceptionThrown,
DkmDataItem::Null(),
pVisualizedResult.put()
));
IF_FAIL_RET(DkmChildVisualizedExpression::Create(
pParent->InspectionContext(),
pParent->VisualizerId(),
pParent->SourceId(),
pParent->StackFrame(),
nullptr,
pVisualizedResult.get(),
pParent,
2,
DkmDataItem::Null(),
pPropertyVisualized.put()
));
}
childItems.push_back(pPropertyVisualized);
}
CAutoDkmArray<DkmChildVisualizedExpression*> resultValues;
IF_FAIL_RET(DkmAllocArray(childItems.size(), &resultValues));
UINT32 j = 0;
auto pos = childItems.begin();
while (pos != childItems.end())
{
com_ptr<DkmChildVisualizedExpression> pCurr = *pos;
resultValues.Members[j++] = pCurr.detach();
pos++;
}
*pItems = resultValues.Detach();
return S_OK;
}

Просмотреть файл

@ -0,0 +1,75 @@
#pragma once
enum class PropertyCategory
{
Bool,
Char,
Int1,
Uint1,
Int2,
Uint2,
Int4,
Uint4,
Int8,
Uint8,
Real4,
Real8,
String,
Guid,
Value,
Class,
};
// Metatdata for resolving a runtime class property value
struct PropertyData
{
std::wstring iid;
int32_t index;
PropertyCategory category;
std::wstring abiType;
std::wstring displayType;
std::wstring displayName;
};
// object_visualizer provides the visualization data model for WinRT objects,
// both for root-level RAII IInspectables, and for nested ABI IInspectable properties.
struct __declspec(uuid("c7da92da-3bc9-4312-8a93-46f480663980"))
object_visualizer : winrt::implements<object_visualizer, ::IUnknown>
{
object_visualizer(Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression, bool isAbiObject)
{
m_pVisualizedExpression = make_com_ptr(pVisualizedExpression);
m_isAbiObject = isAbiObject;
}
~object_visualizer()
{
}
static HRESULT CreateEvaluationResult(_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression, _In_ bool isAbiObject, _Deref_out_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResult** ppResultObject);
HRESULT CreateEvaluationResult(_Deref_out_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResult** ppResultObject);
HRESULT GetChildren(
_In_ UINT32 InitialRequestSize,
_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmInspectionContext* pInspectionContext,
_Out_ Microsoft::VisualStudio::Debugger::DkmArray<Microsoft::VisualStudio::Debugger::Evaluation::DkmChildVisualizedExpression*>* pInitialChildren,
_Deref_out_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResultEnumContext** ppEnumContext
);
HRESULT GetItems(
_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression,
_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResultEnumContext* pEnumContext,
_In_ UINT32 StartIndex,
_In_ UINT32 Count,
_Out_ Microsoft::VisualStudio::Debugger::DkmArray<Microsoft::VisualStudio::Debugger::Evaluation::DkmChildVisualizedExpression*>* pItems
);
private:
void GetPropertyData();
void GetTypeProperties(Microsoft::VisualStudio::Debugger::DkmProcess* process, std::string_view const& type_name);
winrt::com_ptr<Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression> m_pVisualizedExpression;
bool m_isAbiObject;
std::vector<PropertyData> m_propertyData;
bool m_isStringable{ false };
};

5
natvis/packages.config Normal file
Просмотреть файл

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.VSSDK.Debugger.VSDebugEng" version="16.0.2012201-preview" developmentDependency="true" />
<package id="Microsoft.VSSDK.Debugger.VSDConfigTool" version="16.0.2012201-preview" developmentDependency="true" />
</packages>

1
natvis/pch.cpp Normal file
Просмотреть файл

@ -0,0 +1 @@
#include "pch.h"

49
natvis/pch.h Normal file
Просмотреть файл

@ -0,0 +1,49 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#define NOMINMAX
#include <windows.h>
#include <vsdebugeng.h>
#include <vsdebugeng.templates.h>
#include <Dia2.h>
#include "winrt\base.h"
#include <rometadataapi.h>
#include <rometadata.h>
#include <filesystem>
#include <functional>
#include <optional>
#include <set>
#include <memory>
#include <variant>
#include <cmd_reader.h>
#include <meta_reader.h>
#ifndef IF_FAIL_RET
#define IF_FAIL_RET(expr) { HRESULT _hr = (expr); if(FAILED(_hr)) { return(_hr); } }
#endif
template<typename T>
winrt::com_ptr<T> make_com_ptr(T* ptr)
{
winrt::com_ptr<T> result;
result.copy_from(ptr);
return result;
}
xlang::meta::reader::TypeDef FindType(Microsoft::VisualStudio::Debugger::DkmProcess* process, std::string_view const& typeName);
enum class NatvisDiagnosticLevel
{
Unknown = -1,
Off,
Error,
Warning,
Verbose
};
NatvisDiagnosticLevel GetNatvisDiagnosticLevel();
HRESULT NatvisDiagnostic(Microsoft::VisualStudio::Debugger::DkmProcess* process, std::wstring_view const& messageText, NatvisDiagnosticLevel level, HRESULT errorCode = S_OK);
inline HRESULT NatvisDiagnostic(Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* expression, std::wstring_view const& messageText, NatvisDiagnosticLevel level, HRESULT errorCode = S_OK)
{
return NatvisDiagnostic(expression->RuntimeInstance()->Process(), messageText, level, errorCode);
}

Просмотреть файл

@ -0,0 +1,129 @@
#include "pch.h"
#include "object_visualizer.h"
#include "property_visualizer.h"
using namespace Microsoft::VisualStudio::Debugger;
using namespace Microsoft::VisualStudio::Debugger::Evaluation;
using namespace xlang;
using namespace xlang::meta;
using namespace xlang::meta::reader;
HRESULT property_visualizer::GetChildren(
_In_ UINT32 InitialRequestSize,
_In_ DkmInspectionContext* pInspectionContext,
_Out_ DkmArray<DkmChildVisualizedExpression*>* pVisualizedInitialChildren,
_Deref_out_ DkmEvaluationResultEnumContext** ppEnumContext
)
{
// Forward this on to the EE.
CAutoDkmArray<DkmEvaluationResult*> initialChildren;
IF_FAIL_RET(m_pVisualizedExpression->GetChildrenCallback(m_pEEEvaluationResult.get(), InitialRequestSize, pInspectionContext, &initialChildren, ppEnumContext));
// Need to create a DkmArray of DkmChildVisualizedExpression that contain the evaluation results and return that.
DkmAllocArray(initialChildren.Length, pVisualizedInitialChildren);
for (DWORD i = 0; i < initialChildren.Length; i++)
{
auto pCurrEvaluationResult = make_com_ptr(initialChildren.Members[i]);
if (pCurrEvaluationResult->TagValue() != DkmEvaluationResult::Tag::SuccessResult)
{
return E_FAIL;
}
DkmSuccessEvaluationResult* pCurrSuccessEvaluationResult = (DkmSuccessEvaluationResult*)(pCurrEvaluationResult.get());
winrt::com_ptr<DkmPointerValueHome> pPointerValueHome;
IF_FAIL_RET(DkmPointerValueHome::Create(pCurrSuccessEvaluationResult->Address()->Value(), pPointerValueHome.put()));
winrt::com_ptr<DkmChildVisualizedExpression> pChildVisualizedExpression;
IF_FAIL_RET(DkmChildVisualizedExpression::Create(
pInspectionContext,
pChildVisualizedExpression->Parent()->VisualizerId(),
pChildVisualizedExpression->Parent()->SourceId(),
pChildVisualizedExpression->Parent()->StackFrame(),
pPointerValueHome.get(),
pCurrEvaluationResult.get(),
m_pVisualizedExpression.get(), // (parent)
i,
this,
pChildVisualizedExpression.put()
));
pVisualizedInitialChildren->Members[i] = pChildVisualizedExpression.detach();
}
return S_OK;
}
HRESULT property_visualizer::GetItems(
_In_ DkmEvaluationResultEnumContext* pEnumContext,
_In_ UINT32 StartIndex,
_In_ UINT32 Count,
_Out_ DkmArray<DkmChildVisualizedExpression*>* pItems
)
{
// Forward this on to the EE.
CAutoDkmArray<DkmEvaluationResult*> evaluationResults;
IF_FAIL_RET(m_pVisualizedExpression->GetItemsCallback(pEnumContext, StartIndex, Count, &evaluationResults));
DkmAllocArray(evaluationResults.Length, pItems);
for (DWORD i = 0; i < evaluationResults.Length; i++)
{
auto pCurrEvaluationResult = make_com_ptr(evaluationResults.Members[i]);
if (pCurrEvaluationResult->TagValue() != DkmEvaluationResult::Tag::SuccessResult)
{
return E_FAIL;
}
DkmSuccessEvaluationResult* pCurrSuccessEvaluationResult = (DkmSuccessEvaluationResult*)(pCurrEvaluationResult.get());
winrt::com_ptr<DkmPointerValueHome> pPointerValueHome;
auto address = pCurrSuccessEvaluationResult->Address();
IF_FAIL_RET(DkmPointerValueHome::Create(address ? address->Value() : 0, pPointerValueHome.put()));
winrt::com_ptr<DkmChildVisualizedExpression> pChildVisualizedExpression;
IF_FAIL_RET(DkmChildVisualizedExpression::Create(
m_pVisualizedExpression->InspectionContext(),
m_pVisualizedExpression->Parent()->VisualizerId(),
m_pVisualizedExpression->Parent()->SourceId(),
m_pVisualizedExpression->Parent()->StackFrame(),
pPointerValueHome.get(),
pCurrEvaluationResult.get(),
m_pVisualizedExpression.get(), // (parent)
i,
this,
pChildVisualizedExpression.put()
));
pItems->Members[i] = pChildVisualizedExpression.detach();
}
return S_OK;
}
HRESULT property_visualizer::SetValueAsString(
_In_ DkmString* pValue,
_In_ UINT32 Timeout,
_Deref_out_opt_ DkmString** ppErrorText
)
{
// Forward this on to the EE.
IF_FAIL_RET(m_pVisualizedExpression->SetValueAsStringCallback(m_pEEEvaluationResult.get(), pValue, Timeout, ppErrorText));
return S_OK;
}
HRESULT property_visualizer::GetUnderlyingString(
_Deref_out_opt_ DkmString** ppStringValue
)
{
// Forward this on to the EE.
IF_FAIL_RET(m_pVisualizedExpression->GetUnderlyingStringCallback(m_pEEEvaluationResult.get(), ppStringValue));
return S_OK;
}

Просмотреть файл

@ -0,0 +1,51 @@
#pragma once
// property_visualizer provides the visualization data model for leaf (non-WinRT object)
// nodes in the WinRT object graph, forwarding its implementation back to the expression
// evaluator for external types.
struct __declspec(uuid("87feab93-47a3-4f55-b48b-a29317fa52da"))
property_visualizer : winrt::implements<property_visualizer, ::IUnknown>
{
property_visualizer(
_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmChildVisualizedExpression* pVisualizedExpression,
_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmSuccessEvaluationResult* pEEEvaluationResult)
{
m_pVisualizedExpression = make_com_ptr(pVisualizedExpression);
m_pEEEvaluationResult = make_com_ptr(pEEEvaluationResult);
}
~property_visualizer()
{
}
HRESULT GetChildren(
_In_ UINT32 InitialRequestSize,
_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmInspectionContext* pInspectionContext,
_Out_ Microsoft::VisualStudio::Debugger::DkmArray<Microsoft::VisualStudio::Debugger::Evaluation::DkmChildVisualizedExpression*>* pInitialChildren,
_Deref_out_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResultEnumContext** ppEnumContext
);
HRESULT GetItems(
_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResultEnumContext* pEnumContext,
_In_ UINT32 StartIndex,
_In_ UINT32 Count,
_Out_ Microsoft::VisualStudio::Debugger::DkmArray<Microsoft::VisualStudio::Debugger::Evaluation::DkmChildVisualizedExpression*>* pItems
);
HRESULT SetValueAsString(
_In_ Microsoft::VisualStudio::Debugger::DkmString* pValue,
_In_ UINT32 Timeout,
_Deref_out_opt_ Microsoft::VisualStudio::Debugger::DkmString** ppErrorText
);
HRESULT GetUnderlyingString(
_Deref_out_opt_ Microsoft::VisualStudio::Debugger::DkmString** ppStringValue
);
private:
// The DkmVisualizedExpression created for this object.
winrt::com_ptr<Microsoft::VisualStudio::Debugger::Evaluation::DkmChildVisualizedExpression> m_pVisualizedExpression;
// The original evaluation result returned from the expression evaluator.
winrt::com_ptr<Microsoft::VisualStudio::Debugger::Evaluation::DkmSuccessEvaluationResult> m_pEEEvaluationResult;
};

30
nuget/CMakeLists.txt Normal file
Просмотреть файл

@ -0,0 +1,30 @@
cmake_minimum_required(VERSION 3.9)
# The Microsoft.Windows.CppWinRT NuGet package is only targeted at Visual Studio (on Windows)
if (WIN32 AND ("$ENV{VSCMD_ARG_TGT_ARCH}" STREQUAL "x86"))
file(TO_NATIVE_PATH "${CMAKE_BINARY_DIR}/build_tools/nuget.exe" nuget_exe)
file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}" cppwinrt_nupkg_dir)
file(TO_NATIVE_PATH "${cppwinrt_nupkg_dir}/Microsoft.Windows.CppWinRT.${XLANG_BUILD_VERSION}.nupkg" cppwinrt_nupkg)
get_target_property(cppwinrt_exe cppwinrt "cppwinrt_exe")
get_target_property(cppwinrt_fast_fwd_x86 cppwinrt_fast_fwd "cppwinrt_fast_fwd_x86")
string(REGEX REPLACE "x86" "x64" cppwinrt_fast_fwd_x64 ${cppwinrt_fast_fwd_x86})
string(REGEX REPLACE "x86" "arm" cppwinrt_fast_fwd_arm ${cppwinrt_fast_fwd_x86})
string(REGEX REPLACE "x86" "arm64" cppwinrt_fast_fwd_arm64 ${cppwinrt_fast_fwd_x86})
file(DOWNLOAD https://dist.nuget.org/win-x86-commandline/latest/nuget.exe ${nuget_exe})
add_custom_command(OUTPUT ${cppwinrt_nupkg}
COMMAND ${nuget_exe} pack ${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.Windows.CppWinRT.nuspec -Properties cppwinrt_exe=${cppwinrt_exe} -Properties cppwinrt_fast_fwd_x86=${cppwinrt_fast_fwd_x86} -Properties cppwinrt_fast_fwd_x64=${cppwinrt_fast_fwd_x64} -Properties cppwinrt_fast_fwd_arm=${cppwinrt_fast_fwd_arm} -Properties cppwinrt_fast_fwd_arm64=${cppwinrt_fast_fwd_arm64}; -Version ${XLANG_BUILD_VERSION} -OutputDirectory ${CMAKE_CURRENT_BINARY_DIR} -NonInteractive -Verbosity Detailed
DEPENDS ${cppwinrt_exe} ${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.Windows.CppWinRT.nuspec
)
add_custom_target(make_cppwinrt_nupkg ALL DEPENDS cppwinrt ${cppwinrt_nupkg} cppwinrt_fast_fwd)
set_target_properties(make_cppwinrt_nupkg PROPERTIES "cppwinrt_nupkg_dir" ${cppwinrt_nupkg_dir})
set_target_properties(make_cppwinrt_nupkg PROPERTIES "cppwinrt_nupkg" ${cppwinrt_nupkg})
endif()

Просмотреть файл

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<Rule Name="CppWinRT" DisplayName="C++/WinRT" Order="75" PageTemplate="generic" xmlns="http://schemas.microsoft.com/build/2009/properties">
<Rule.Categories>
<Category Name="General" DisplayName="General"/>
</Rule.Categories>
<Rule.DataSource>
<DataSource Persistence="ProjectFile" HasConfigurationCondition="false" Label="Globals" />
</Rule.DataSource>
<StringProperty Name="RootNamespace"
DisplayName="Root Namespace"
Description="Specifies the default namespace to be used with new files created in this project."
Category="General" />
<EnumProperty Name="CppWinRTVerbosity"
DisplayName="Verbosity"
Description="Sets the importance of C++/WinRT build messages"
Category="General">
<EnumValue Name="low" DisplayName="low" Description="Enables messages when MSBuild verbosity is set to at least 'detailed'" />
<EnumValue Name="normal" DisplayName="normal" Description="Enables messages when MSBuild verbosity is set to at least 'normal'" />
<EnumValue Name="high" DisplayName="high" Description="Enables messages when MSBuild verbosity is set to at least 'minimal'" />
</EnumProperty>
<EnumProperty Name="CppWinRTProjectLanguage"
DisplayName="Project Language"
Description="Sets the C++ dialect for the project. C++/WinRT provides full projection support, C++/CX permits consuming projection headers."
Category="General">
<EnumValue Name="C++/WinRT" DisplayName="C++/WinRT" Description="Enables full consuming and producing projection support and Xaml integration" />
<EnumValue Name="C++/CX" DisplayName="C++/CX" Description="Enables C++/CX code to generate and use consuming projections" />
</EnumProperty>
<BoolProperty Name="CppWinRTLibs"
DisplayName="Umbrella Library"
Description="Adds the WindowsApp.lib umbrella library for Windows Runtime imports"
Category="General" />
<BoolProperty Name="CppWinRTModernIDL"
DisplayName="Modern IDL"
Description="Enables midlrt.exe modern IDL support (disable for custom behavior such as proxy/stub generation)"
Category="General" />
<IntProperty Name="CppWinRTNamespaceMergeDepth"
DisplayName="Namespace Merge Depth"
Description="Overrides the depth of mdmerge.exe namespace merging (Xaml apps require 1)"
Category="General" />
<BoolProperty Name="CppWinRTRootNamespaceAutoMerge"
DisplayName="Use Root Namespace Merge Depth"
Description="Use the Root Namespace as the default merge depth"
Category="General" />
<BoolProperty Name="CppWinRTUsePrefixes"
DisplayName="Use Prefixes"
Description="Uses a dotted prefix namespace convention (versus a nested folder convention)"
Category="General" />
<StringProperty Name="CppWinRTParameters"
DisplayName="Additional Parameters"
Description="Additional cppwinrt.exe command-line parameters"
Category="General" />
<BoolProperty Name="CppWinRTFastAbi"
DisplayName="Fast ABI"
Description="Enables Fast ABI feature for both consuming and producing projections"
Category="General" />
<BoolProperty Name="CppWinRTOptimized"
DisplayName="Optimized"
Description="Enables component projection optimization features (e.g., unified construction)"
Category="General" />
</Rule>

Просмотреть файл

@ -0,0 +1,30 @@
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata minClientVersion="2.5">
<id>Microsoft.Windows.CppWinRT</id>
<version>1.0.0.0</version>
<title>C++/WinRT Build Support</title>
<authors>Microsoft</authors>
<owners>Microsoft</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>C++/WinRT is a standard C++ language projection for the Windows Runtime implemented solely in header files. It allows you to both author and consume Windows Runtime APIs using any standards-compliant C++ compiler. C++/WinRT is designed to provide C++ developers with first-class access to the modern Windows API.</description>
<releaseNotes></releaseNotes>
<tags>native C++ WinRT nativepackage</tags>
<copyright>© Microsoft Corporation. All rights reserved.</copyright>
<license type="file">LICENSE</license>
<projectUrl>https://github.com/Microsoft/xlang/tree/master/src/package/cppwinrt/nuget</projectUrl>
<iconUrl>https://aka.ms/cppwinrt.ico</iconUrl>
</metadata>
<files>
<file src="..\LICENSE"/>
<file src="$cppwinrt_exe$" target="bin"/>
<file src="$cppwinrt_fast_fwd_x86$" target="build\native\lib\win32"/>
<file src="$cppwinrt_fast_fwd_x64$" target="build\native\lib\x64"/>
<file src="$cppwinrt_fast_fwd_arm$" target="build\native\lib\arm"/>
<file src="$cppwinrt_fast_fwd_arm64$" target="build\native\lib\arm64"/>
<file src="Microsoft.Windows.CppWinRT.props" target="build\native"/>
<file src="Microsoft.Windows.CppWinRT.targets" target="build\native"/>
<file src="CppWinrtRules.Project.xml" target="build\native"/>
<file src="readme.txt"/>
</files>
</package>

Просмотреть файл

@ -0,0 +1,57 @@
<!--
***********************************************************************************************
Copyright (C) Microsoft Corporation. All rights reserved.
***********************************************************************************************
-->
<!--Set compiler and linker options for projects requiring C++/WinRT. -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
<CanReferenceWinRT>true</CanReferenceWinRT>
<CppWinRTPackage Condition="'$(CppWinRTEnabled)' != 'true'">true</CppWinRTPackage>
<CppWinRTPackage Condition="'$(CppWinRTPackage)' != 'true'">false</CppWinRTPackage>
<XamlLanguage>CppWinRT</XamlLanguage>
<IsNativeLanguage>true</IsNativeLanguage>
<!-- This causes VS to add the platform WinMD references for the target SDK -->
<WinMDAssembly>true</WinMDAssembly>
</PropertyGroup>
<!-- For a static library we don't want the winmd/lib/pdb to be packaged -->
<PropertyGroup Condition="'$(ConfigurationType)' == 'StaticLibrary'">
<IncludeCopyWinMDArtifactsOutputGroup>false</IncludeCopyWinMDArtifactsOutputGroup>
<IncludeBuiltProjectOutputGroup>false</IncludeBuiltProjectOutputGroup>
<IncludeDebugSymbolsProjectOutputGroup>false</IncludeDebugSymbolsProjectOutputGroup>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<CompileAsWinRT Condition="'$(CppWinRTProjectLanguage)' != 'C++/CX' And '%(ClCompile.CompileAsWinRT)' == ''">false</CompileAsWinRT>
<LanguageStandard Condition="'%(ClCompile.LanguageStandard)' == ''">stdcpp17</LanguageStandard>
<AdditionalOptions>/bigobj /await %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(GeneratedFilesDir)</AdditionalIncludeDirectories>
</ClCompile>
<Midl Condition="'$(CppWinRTModernIDL)' != 'false'">
<AdditionalOptions>%(AdditionalOptions) /nomidl</AdditionalOptions>
<EnableWindowsRuntime>true</EnableWindowsRuntime>
<MetadataFileName>$(IntDir)Unmerged\%(Filename).winmd</MetadataFileName>
<GenerateClientFiles Condition="'%(Midl.GenerateClientFiles)'==''">None</GenerateClientFiles>
<GenerateServerFiles Condition="'%(Midl.GenerateServerFiles)'==''">None</GenerateServerFiles>
<GenerateStublessProxies Condition="'%(Midl.GenerateStublessProxies)'==''">false</GenerateStublessProxies>
<GenerateTypeLibrary Condition="'%(Midl.GenerateTypeLibrary)'==''">false</GenerateTypeLibrary>
<HeaderFileName Condition="'%(Midl.HeaderFileName)'==''">nul</HeaderFileName>
<DllDataFileName Condition="'%(Midl.DllDataFileName)'==''">nul</DllDataFileName>
<InterfaceIdentifierFileName Condition="'%(Midl.InterfaceIdentifierFileName)'==''">nul</InterfaceIdentifierFileName>
<ProxyFileName Condition="'%(Midl.ProxyFileName)'==''">nul</ProxyFileName>
<TypeLibraryName Condition="'%(Midl.TypeLibraryName)'==''"></TypeLibraryName>
</Midl>
<Link>
<AdditionalDependencies Condition="'$(CppWinRTLibs)' != 'false'">WindowsApp.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<PropertyPageSchema Include="$(MSBuildThisFileDirectory)\CppWinrtRules.Project.xml"/>
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,563 @@
<!--
***********************************************************************************************
Copyright (C) Microsoft Corporation. All rights reserved.
***********************************************************************************************
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CppWinRTVerbosity Condition="'$(CppWinRTVerbosity)' == ''">normal</CppWinRTVerbosity>
<CppWinRTCommandVerbosity Condition="'$(CppWinRTVerbosity)' == 'high'">-verbose</CppWinRTCommandVerbosity>
<CppWinRTProjectWinMD>$(OutDir)$(RootNamespace).winmd</CppWinRTProjectWinMD>
<CppWinRTMergedDir>$(IntDir)Merged\</CppWinRTMergedDir>
<CppWinRTUnmergedDir>$(IntDir)Unmerged\</CppWinRTUnmergedDir>
<CppWinRTSkipUnchangedFiles Condition="'$(CppWinRTSkipUnchangedFiles)' == ''">true</CppWinRTSkipUnchangedFiles>
<CppWinRTUseHardlinksIfPossible Condition="'$(CppWinRTUseHardlinksIfPossible)' == ''">false</CppWinRTUseHardlinksIfPossible>
<CppWinRTWriteOnlyWhenDifferent Condition="('$(CppWinRTWriteOnlyWhenDifferent)' == '') And (('$(MSBuildToolsVersion)' == 'Current') Or ('$(MSBuildToolsVersion)' &gt;= '15'))">true</CppWinRTWriteOnlyWhenDifferent>
<CppWinRTWriteOnlyWhenDifferent Condition="'$(CppWinRTWriteOnlyWhenDifferent)' != 'true'">false</CppWinRTWriteOnlyWhenDifferent>
<CppWinRTPackageDir Condition="'$(CppWinRTPackage)' == 'true' and '$(CppWinRTPackageDir)'==''">$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)))..\..\</CppWinRTPackageDir>
<CppWinRTPackageDir Condition="'$(CppWinRTPackage)' != 'true' and '$(CppWinRTPackageDir)'==''">$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)))</CppWinRTPackageDir>
<CppWinRTPath Condition="'$(CppWinRTPackage)' == 'true' and '$(CppWinRTPath)'==''">"$(CppWinRTPackageDir)bin\"</CppWinRTPath>
<CppWinRTPath Condition="'$(CppWinRTPackage)' != 'true' and '$(CppWinRTPath)'==''">"$(CppWinRTPackageDir)"</CppWinRTPath>
<XamlLanguage Condition="'$(CppWinRTProjectLanguage)' == 'C++/CX'">C++</XamlLanguage>
<XamlNamespace Condition="'$(XamlNamespace)' == ''">Windows.UI.Xaml</XamlNamespace>
<XamlMetaDataProviderIdl Condition="'$(XamlMetaDataProviderIdl)'== ''">$(GeneratedFilesDir)XamlMetaDataProvider.idl</XamlMetaDataProviderIdl>
<XamlMetaDataProviderCpp Condition="'$(XamlMetaDataProviderCpp)'== ''">$(GeneratedFilesDir)XamlMetaDataProvider.cpp</XamlMetaDataProviderCpp>
<GeneratedFilesDir Condition="'$(GeneratedFilesDir)' == ''">$(IntDir)Generated Files\</GeneratedFilesDir>
<!--Override SDK's uap.props setting to ensure version-matched headers-->
<CppWinRT_IncludePath>$(GeneratedFilesDir)</CppWinRT_IncludePath>
<!--TEMP: Override NuGet SDK's erroneous setting in uap.props -->
<WindowsSDK_MetadataFoundationPath Condition="('$(WindowsSDK_MetadataFoundationPath)'!='') And !Exists($(WindowsSDK_MetadataFoundationPath))">$(WindowsSDK_MetadataPathVersioned)</WindowsSDK_MetadataFoundationPath>
<GetTargetPathDependsOn>
$(GetTargetPathDependsOn);CppWinRTCalculateEnabledProjections;CppWinRTGetTargetPath
</GetTargetPathDependsOn>
<PrepareForBuildDependsOn>
$(PrepareForBuildDependsOn);CppWinRTVerifyKitVersion
</PrepareForBuildDependsOn>
<!-- Note: Before* targets run before Compute* targets. -->
<BeforeMidlCompileTargets>
$(BeforeMidlCompileTargets);CppWinRTAddXamlMetaDataProviderIdl;
</BeforeMidlCompileTargets>
<ComputeMidlInputsTargets>
$(ComputeMidlInputsTargets);CppWinRTComputeXamlGeneratedMidlInputs;CppWinRTSetMidlReferences;
</ComputeMidlInputsTargets>
<AfterMidlTargets>
$(AfterMidlTargets);CppWinRTMergeProjectWinMDInputs
</AfterMidlTargets>
<ResolveAssemblyReferencesDependsOn>
$(ResolveAssemblyReferencesDependsOn);GetCppWinRTProjectWinMDReferences;CppWinRTRemoveStaticLibraries
</ResolveAssemblyReferencesDependsOn>
<!-- Note: Before* targets run before Compute* targets. -->
<BeforeClCompileTargets>
$(BeforeClCompileTargets);CppWinRTAddXamlMetaDataProviderCpp;CppWinRTMakeProjections;
</BeforeClCompileTargets>
<ComputeCompileInputsTargets>
$(ComputeCompileInputsTargets);CppWinRTComputeXamlGeneratedCompileInputs;CppWinRTHeapEnforcementOptOut;
</ComputeCompileInputsTargets>
<MarkupCompilePass1DependsOn>
$(MarkupCompilePass1DependsOn);CppWinRTAddXamlReferences
</MarkupCompilePass1DependsOn>
<MarkupCompilePass2DependsOn>
$(MarkupCompilePass2DependsOn);CppWinRTSetXamlLocalAssembly
</MarkupCompilePass2DependsOn>
<CleanDependsOn>
$(CleanDependsOn);CppWinRTClean
</CleanDependsOn>
<CAExcludePath>
$(CAExcludePath);$(GeneratedFilesDir);
</CAExcludePath>
</PropertyGroup>
<Target Name="CppWinRTVerifyKitVersion" Condition="'$(CppWinRTOverrideSDKReferences)' != 'true'">
<PropertyGroup>
<_CppWinRT_RS4OrGreater>false</_CppWinRT_RS4OrGreater>
<_CppWinRT_RS4OrGreater Condition="'$(TargetPlatformVersion)' &gt;= '10.0.17134.0'">true</_CppWinRT_RS4OrGreater>
</PropertyGroup>
<VCMessage Code="MSB8036" Type="Error" Arguments="10.0.17134.0 (or later)" Condition="$(_CppWinRT_RS4OrGreater) != 'true'" />
</Target>
<Target Name="CppWinRTClean">
<ItemGroup>
<_FilesToDelete Remove="@(_FilesToDelete)"/>
<_FilesToDelete Include="$(GeneratedFilesDir)**"/>
<_FilesToDelete Include="$(OutDir)*.winmd"/>
<_FilesToDelete Include="$(IntDir)*.winmd"/>
<_FilesToDelete Include="$(IntDir)*.idl"/>
<_FilesToDelete Include="$(IntDir)*.rsp"/>
<_FilesToDelete Include="$(CppWinRTMergedDir)**"/>
<_FilesToDelete Include="$(CppWinRTUnmergedDir)**"/>
</ItemGroup>
<Delete Files="@(_FilesToDelete)"/>
</Target>
<Target Name="CppWinRTHeapEnforcementOptOut" Condition="'@(ClCompile)' != ''">
<ItemGroup Condition="'$(CppWinRTHeapEnforcement)'=='' and ('@(Page)' != '' Or '@(ApplicationDefinition)' != '')">
<ClCompile>
<AdditionalOptions>%(ClCompile.AdditionalOptions) /DWINRT_NO_MAKE_DETECTION</AdditionalOptions>
</ClCompile>
</ItemGroup>
</Target>
<Target Name="CppWinRTCalculateEnabledProjections"
DependsOnTargets="GetCppWinRTProjectWinMDReferences;GetCppWinRTMdMergeInputs;$(CppWinRTCalculateEnabledProjectionsDependsOn)"
BeforeTargets="CppWinRTGetTargetPath;CppWinRTMakePlatformProjection;CppWinRTMakeComponentProjection;CppWinRTMakeReferenceProjection"
Returns="$(CppWinRTEnableComponentProjection);$(CppWinRTEnablePlatformProjection);$(CppWinRTEnableReferenceProjection)">
<PropertyGroup>
<!-- For CX projects, turn off the component projection generation-->
<CppWinRTEnableComponentProjection Condition="'$(CppWinRTEnableComponentProjection)' == '' AND '$(CppWinRTProjectLanguage)' == 'C++/CX' ">false</CppWinRTEnableComponentProjection>
<CppWinRTEnableComponentProjection Condition="'$(CppWinRTEnableComponentProjection)' == '' AND '$(XamlLanguage)' == 'C++' ">false</CppWinRTEnableComponentProjection>
<!-- Turn on component projection if not turned off and:
1. @(Midl) is not empty or
2. project has static library references
-->
<CppWinRTEnableComponentProjection Condition="'$(CppWinRTEnableComponentProjection)' == '' AND '@(Midl)' != ''">true</CppWinRTEnableComponentProjection>
<CppWinRTEnableComponentProjection Condition="'$(CppWinRTEnableComponentProjection)' == '' AND '@(CppWinRTMdMergeInputs)' != ''">true</CppWinRTEnableComponentProjection>
<CppWinRTEnablePlatformProjection Condition="'$(CppWinRTEnablePlatformProjection)' == ''">true</CppWinRTEnablePlatformProjection>
<CppWinRTEnableReferenceProjection Condition="'$(CppWinRTEnableReferenceProjection)' == ''">true</CppWinRTEnableReferenceProjection>
</PropertyGroup>
<Message Text="CppWinRTEnableComponentProjection: $(CppWinRTEnableComponentProjection)" Importance="$(CppWinRTVerbosity)"/>
<Message Text="CppWinRTEnablePlatformProjection: $(CppWinRTEnablePlatformProjection)" Importance="$(CppWinRTVerbosity)"/>
<Message Text="CppWinRTEnableReferenceProjection: $(CppWinRTEnableReferenceProjection)" Importance="$(CppWinRTVerbosity)"/>
</Target>
<Target Name="CppWinRTGetTargetPath"
Condition="'$(CppWinRTEnableComponentProjection)' == 'true'"
Returns="@(TargetPathWithTargetPlatformMoniker)">
<ItemGroup>
<TargetPathWithTargetPlatformMoniker Remove="$(TargetPathWithTargetPlatformMoniker)"/>
<TargetPathWithTargetPlatformMoniker Include="$(CppWinRTProjectWinMD)">
<TargetPath>$([System.IO.Path]::GetFileName('$(CppWinRTProjectWinMD)'))</TargetPath>
<Primary>true</Primary>
<Implementation Condition="'$(TargetExt)' == '.dll'">$(WinMDImplementationPath)$(RootNamespace)$(TargetExt)</Implementation>
<FileType>winmd</FileType>
<WinMDFile>true</WinMDFile>
<ProjectName>$(MSBuildProjectName)</ProjectName>
<ProjectType>$(ConfigurationType)</ProjectType>
</TargetPathWithTargetPlatformMoniker>
</ItemGroup>
<Message Text="CppWinRTGetTargetPath: @(TargetPathWithTargetPlatformMoniker->'%(FullPath)')" Importance="$(CppWinRTVerbosity)"/>
</Target>
<!-- Static library reference files are merged into the project that
references it. They shouldn't be included as actual project references.
Make sure that we've ran the GetCppWinRTProjectWinMDReferences target
and then remove them. -->
<Target Name="CppWinRTRemoveStaticLibraries"
DependsOnTargets="GetCppWinRTProjectWinMDReferences"
Returns="@(_ResolvedProjectReferencePaths)">
<ItemGroup>
<_ResolvedProjectReferencePaths Remove="@(_ResolvedProjectReferencePaths)" Condition="'%(_ResolvedProjectReferencePaths.ProjectType)' == 'StaticLibrary'" />
</ItemGroup>
</Target>
<!--Define platform projection WinMD inputs-->
<Target Name="GetCppWinRTPlatformWinMDInputs"
DependsOnTargets="ResolveAssemblyReferences"
Returns="@(CppWinRTPlatformWinMDInputs)">
<ItemGroup>
<_CppWinRTPlatformWinMDInputs Remove="@(_CppWinRTPlatformWinMDInputs)" />
<_CppWinRTPlatformWinMDInputs Include="$(WindowsSDK_MetadataPathVersioned)\**\*.winmd" />
<CppWinRTPlatformWinMDInputs Include="@(_CppWinRTPlatformWinMDInputs)">
<WinMDPath>%(FullPath)</WinMDPath>
</CppWinRTPlatformWinMDInputs>
</ItemGroup>
<Message Text="CppWinRTPlatformWinMDInputs: @(CppWinRTPlatformWinMDInputs->'%(WinMDPath)')" Importance="$(CppWinRTVerbosity)"/>
</Target>
<!--Define platform WinMD references for modern IDL compilation-->
<Target Name="GetCppWinRTPlatformWinMDReferences"
DependsOnTargets="ResolveAssemblyReferences;$(GetCppWinRTPlatformWinMDReferencesDependsOn)"
Returns="@(CppWinRTPlatformWinMDReferences)">
<ItemGroup>
<_CppWinRTPlatformWinMDReferences Remove="@(_CppWinRTPlatformWinMDReferences)" />
<_CppWinRTPlatformWinMDReferences Include="@(ReferencePath)" Condition="'%(ReferencePath.IsSystemReference)' == 'true' and '%(ReferencePath.WinMDFile)' == 'true' and '%(ReferencePath.ReferenceSourceTarget)' == 'ResolveAssemblyReference'" />
<_CppWinRTPlatformWinMDReferences Condition="'$(CppWinRTOverrideSDKReferences)' != 'true'" Include="$(WindowsSDK_MetadataPathVersioned)\**\Windows.Foundation.FoundationContract.winmd" />
<_CppWinRTPlatformWinMDReferences Condition="'$(CppWinRTOverrideSDKReferences)' != 'true'" Include="$(WindowsSDK_MetadataPathVersioned)\**\Windows.Foundation.UniversalApiContract.winmd" />
<_CppWinRTPlatformWinMDReferences Condition="'$(CppWinRTOverrideSDKReferences)' != 'true'" Include="$(WindowsSDK_MetadataPathVersioned)\**\Windows.Networking.Connectivity.WwanContract.winmd" />
<_CppWinRTPlatformWinMDReferences Include="$(CppWinRTSDKReferences)" />
<CppWinRTPlatformWinMDReferences Remove="@(CppWinRTPlatformWinMDReferences)"/>
<CppWinRTPlatformWinMDReferences Include="@(_CppWinRTPlatformWinMDReferences->'%(FullPath)'->Distinct())">
<WinMDPath>%(FullPath)</WinMDPath>
</CppWinRTPlatformWinMDReferences>
</ItemGroup>
<Message Text="CppWinRTPlatformWinMDReferences: @(CppWinRTPlatformWinMDReferences->'%(WinMDPath)')" Importance="$(CppWinRTVerbosity)"/>
</Target>
<!--Get direct WinMD references (including Nuget packages) for projections, IDL processing, and AppX packaging-->
<Target Name="GetCppWinRTDirectWinMDReferences"
DependsOnTargets="ResolveAssemblyReferences;$(GetCppWinRTDirectWinMDReferencesDependsOn)"
Returns="@(CppWinRTDirectWinMDReferences)">
<ItemGroup>
<_CppWinRTDirectWinMDReferences Remove="@(_CppWinRTDirectWinMDReferences)" />
<_CppWinRTDirectWinMDReferences Include="@(ReferencePath)" Condition="'%(ReferencePath.IsSystemReference)' != 'true' and '%(ReferencePath.WinMDFile)' == 'true' and '%(ReferencePath.ReferenceSourceTarget)' == 'ResolveAssemblyReference'" />
<CppWinRTDirectWinMDReferences Remove="@(CppWinRTDirectWinMDReferences)"/>
<CppWinRTDirectWinMDReferences Include="@(_CppWinRTDirectWinMDReferences)">
<WinMDPath>%(FullPath)</WinMDPath>
</CppWinRTDirectWinMDReferences>
</ItemGroup>
<Message Text="CppWinRTDirectWinMDReferences: @(CppWinRTDirectWinMDReferences->'%(WinMDPath)')" Importance="$(CppWinRTVerbosity)"/>
</Target>
<!--Get direct WinMD project references for projections, IDL processing, and AppX packaging-->
<Target Name="GetCppWinRTProjectWinMDReferences"
DependsOnTargets="ResolveProjectReferences;$(GetCppWinRTProjectWinMDReferencesDependsOn)"
Returns="@(CppWinRTStaticProjectWinMDReferences);@(CppWinRTDynamicProjectWinMDReferences)">
<ItemGroup>
<!-- Get static library project references -->
<_CppWinRTStaticProjectReferences Remove="@(_CppWinRTStaticProjectReferences)"/>
<_CppWinRTStaticProjectReferences Include="@(_ResolvedProjectReferencePaths)"
Condition= "'%(_ResolvedProjectReferencePaths.ProjectType)'=='StaticLibrary' AND
'%(_ResolvedProjectReferencePaths.WinMDFile)' == 'true'"/>
<!--Get dynamic library project references-->
<_CppWinRTDynamicProjectReferences Remove="@(_CppWinRTDynamicProjectReferences)"/>
<_CppWinRTDynamicProjectReferences Include="@(_ResolvedProjectReferencePaths)"
Condition= "'%(_ResolvedProjectReferencePaths.ProjectType)'!='StaticLibrary' AND '%(_ResolvedProjectReferencePaths.WinMDFile)' == 'true'"/>
</ItemGroup>
<ItemGroup>
<CppWinRTStaticProjectWinMDReferences Remove="@(CppWinRTStaticProjectWinMDReferences)" />
<CppWinRTStaticProjectWinMDReferences Include="@(_CppWinRTStaticProjectReferences)">
<WinMDPath>%(FullPath)</WinMDPath>
</CppWinRTStaticProjectWinMDReferences>
<CppWinRTDynamicProjectWinMDReferences Remove="@(CppWinRTDynamicProjectWinMDReferences)" />
<CppWinRTDynamicProjectWinMDReferences Include="@(_CppWinRTDynamicProjectReferences)">
<WinMDPath>%(FullPath)</WinMDPath>
</CppWinRTDynamicProjectWinMDReferences>
</ItemGroup>
<Message Text="CppWinRTStaticProjectWinMDReferences: @(CppWinRTStaticProjectWinMDReferences->'%(WinMDPath)')" Importance="$(CppWinRTVerbosity)"/>
<Message Text="CppWinRTDynamicProjectWinMDReferences: @(CppWinRTDynamicProjectWinMDReferences->'%(WinMDPath)')" Importance="$(CppWinRTVerbosity)"/>
</Target>
<!-- Calculates the input files and metadata directories to be passed to MdMerge -->
<Target Name="GetCppWinRTMdMergeInputs"
DependsOnTargets="GetCppWinRTPlatformWinMDReferences;GetCppWinRTDirectWinMDReferences;GetCppWinRTProjectWinMDReferences;"
Returns="@(CppWinRTMdMergeMetadataDirectories);@(CppWinRTMdMergeInputs)">
<ItemGroup>
<_MdMergeInputs Remove="@(_MdMergeInputs)"/>
<_MdMergeInputs Include="@(Midl)">
<WinMDPath>%(Midl.OutputDirectory)%(Midl.MetadataFileName)</WinMDPath>
<MdMergeOutputFile>$(CppWinRTProjectWinMD)</MdMergeOutputFile>
</_MdMergeInputs>
<!-- Static libraries don't mdmerge other static libraries.
Instead they are passed independent inputs for the compoenent projection. -->
<_MdMergeInputs Include="@(CppWinRTStaticProjectWinMDReferences)" Condition="'$(ConfigurationType)' != 'StaticLibrary'">
<MdMergeOutputFile>$(CppWinRTProjectWinMD)</MdMergeOutputFile>
</_MdMergeInputs>
<_MdMergeReferences Remove="@(_MdMergeReferences)" />
<_MdMergeReferences Include="@(CppWinRTDirectWinMDReferences)" />
<_MdMergeReferences Include="@(CppWinRTDynamicProjectWinMDReferences)" />
<_MdMergeReferences Include="@(CppWinRTPlatformWinMDReferences)" />
<CppWinRTMdMergeMetadataDirectories Remove="@(CppWinRTMdMergeMetadataDirectories)" />
<CppWinRTMdMergeMetadataDirectories Include="@(_MdMergeReferences->'%(RelativeDir)'->Distinct())" />
<CppWinRTMdMergeInputs Remove="@(CppWinRTMdMergeInputs)" />
<CppWinRTMdMergeInputs Include="@(_MdMergeInputs->'%(WinMDPath)'->Distinct())" />
</ItemGroup>
<Message Text="CppWinRTMdMergeInputs: @(CppWinRTMdMergeInputs)" Importance="$(CppWinRTVerbosity)"/>
<Message Text="CppWinRTMdMergeMetadataDirectories: @(CppWinRTMdMergeMetadataDirectories)" Importance="$(CppWinRTVerbosity)"/>
</Target>
<!-- Adds the XamlMetadataProvider idl to the Midl itemgroup, if building any xaml content -->
<Target Name="CppWinRTComputeXamlGeneratedMidlInputs"
DependsOnTargets="$(CppWinRTComputeXamlGeneratedMidlInputsDependsOn)"
Condition="'@(Page)@(ApplicationDefinition)' != '' and '$(XamlLanguage)' == 'CppWinRT' and '$(CppWinRTAddXamlMetaDataProviderIdl)' == 'true'">
<PropertyGroup>
<_DisableReferences>false</_DisableReferences>
<_DisableReferences Condition="('$(CppWinRTOverrideSDKReferences)' != 'true') and ('$(TargetPlatformVersion)' &lt; '10.0.18310.0')">true</_DisableReferences>
</PropertyGroup>
<ItemGroup>
<Midl Remove="$(XamlMetaDataProviderIdl)" />
<Midl Include="$(XamlMetaDataProviderIdl)">
<DisableReferences Condition="$(_DisableReferences)">>true</DisableReferences>
</Midl>
</ItemGroup>
</Target>
<!-- Adds the XamlMetadataProvider cpp to the ClCompile itemgroup, if building any xaml content -->
<Target Name="CppWinRTComputeXamlGeneratedCompileInputs"
DependsOnTargets="$(CppWinRTComputeXamlGeneratedCompileInputsDependsOn)"
Condition="'@(Page)@(ApplicationDefinition)' != '' and '$(XamlLanguage)' == 'CppWinRT' and '$(CppWinRTAddXamlMetaDataProviderIdl)' == 'true'">
<ItemGroup>
<ClCompile Remove="$(XamlMetaDataProviderCpp)" />
<ClCompile Include="$(XamlMetaDataProviderCpp)" Condition="'$(CppWinRTOptimized)'=='true'">
<CompilerIteration>XamlGenerated</CompilerIteration>
</ClCompile>
</ItemGroup>
</Target>
<!--If building any Xaml content, write XamlMetaDataProvider idl file -->
<Target Name="CppWinRTAddXamlMetaDataProviderIdl"
Condition="'@(Page)@(ApplicationDefinition)' != '' and '$(XamlLanguage)' == 'CppWinRT' and '$(CppWinRTAddXamlMetaDataProviderIdl)' == 'true'">
<PropertyGroup>
<_DisableReferences>false</_DisableReferences>
<_DisableReferences Condition="('$(CppWinRTOverrideSDKReferences)' != 'true') and ('$(TargetPlatformVersion)' &lt; '10.0.18310.0')">true</_DisableReferences>
<FullXamlMetadataProviderAttribute Condition="$(XamlCodeGenerationControlFlags.Contains('FullXamlMetadataProvider'))">[$(XamlNamespace).Markup.FullXamlMetadataProvider] </FullXamlMetadataProviderAttribute>
<XamlMarkupIdlImport Condition="$(_DisableReferences)">import "$(XamlNamespace).Markup.idl"%3b</XamlMarkupIdlImport>
<XamlMetaDataProviderIdlLines>
// This file is generated by the build to support Xaml apps
$(XamlMarkupIdlImport)
namespace $(RootNamespace)
{
$(FullXamlMetadataProviderAttribute)runtimeclass XamlMetaDataProvider : [default] $(XamlNamespace).Markup.IXamlMetadataProvider
{
XamlMetaDataProvider()%3b
}
}
</XamlMetaDataProviderIdlLines>
</PropertyGroup>
<WriteLinesToFile Condition="!$(CppWinRTWriteOnlyWhenDifferent)"
File="$(XamlMetaDataProviderIdl)" Lines="$(XamlMetaDataProviderIdlLines)"
ContinueOnError="true" Overwrite="true" />
<WriteLinesToFile Condition="$(CppWinRTWriteOnlyWhenDifferent)"
File="$(XamlMetaDataProviderIdl)" Lines="$(XamlMetaDataProviderIdlLines)"
ContinueOnError="true" Overwrite="true"
WriteOnlyWhenDifferent="true" />
</Target>
<!--If building any Xaml content, write XamlMetaDataProvider cpp file -->
<Target Name="CppWinRTAddXamlMetaDataProviderCpp"
Condition="'@(Page)@(ApplicationDefinition)' != '' and '$(XamlLanguage)' == 'CppWinRT' and '$(CppWinRTAddXamlMetaDataProviderIdl)' == 'true'">
<PropertyGroup>
<_PCH>@(ClCompile->Metadata('PrecompiledHeaderFile')->Distinct())</_PCH>
<XamlMetaDataProviderPch Condition="'$(_PCH)'!=''">#include "$(_PCH)"</XamlMetaDataProviderPch>
<XamlMetaDataProviderCppLines>
// This file is generated by the build to support Xaml apps
$(XamlMetaDataProviderPch)
#include "XamlMetaDataProvider.h"
#include "XamlMetaDataProvider.g.cpp"
</XamlMetaDataProviderCppLines>
</PropertyGroup>
<WriteLinesToFile Condition="!$(CppWinRTWriteOnlyWhenDifferent)"
File="$(XamlMetaDataProviderCpp)" Lines="$(XamlMetaDataProviderCppLines)"
ContinueOnError="true" Overwrite="true" />
<WriteLinesToFile Condition="$(CppWinRTWriteOnlyWhenDifferent)"
File="$(XamlMetaDataProviderCpp)" Lines="$(XamlMetaDataProviderCppLines)"
ContinueOnError="true" Overwrite="true"
WriteOnlyWhenDifferent="true" />
</Target>
<!--Insert Midl /references to Platform WinMDs, library reference WinMDs, and direct reference WinMDs-->
<Target Name="CppWinRTSetMidlReferences"
DependsOnTargets="GetCppWinRTPlatformWinMDReferences;GetCppWinRTDirectWinMDReferences;GetCppWinRTProjectWinMDReferences;$(CppWinRTSetMidlReferencesDependsOn)">
<ItemGroup Condition="'$(CppWinRTModernIDL)' != 'false'">
<_MidlReferences Remove="@(_MidlReferences)"/>
<_MidlReferences Include="@(CppWinRTDirectWinMDReferences)"/>
<_MidlReferences Include="@(CppWinRTStaticProjectWinMDReferences)"/>
<_MidlReferences Include="@(CppWinRTDynamicProjectWinMDReferences)"/>
<_MidlReferences Include="@(CppWinRTPlatformWinMDReferences)"/>
<_MidlReferencesDistinct Remove="@(_MidlReferencesDistinct)" />
<_MidlReferencesDistinct Include="@(_MidlReferences->'%(WinMDPath)'->Distinct())" />
<Midl Condition="'%(Midl.DisableReferences)'==''">
<AdditionalOptions>%(Midl.AdditionalOptions) %40"$(IntDir)midlrt.rsp"</AdditionalOptions>
</Midl>
</ItemGroup>
<ItemGroup>
<Midl Condition="'%(Midl.AdditionalMetadataDirectories)'==''">
<AdditionalMetadataDirectories Condition="'$(WindowsSDK_MetadataFoundationPath)' != ''">%(Midl.AdditionalMetadataDirectories);$(WindowsSDK_MetadataFoundationPath);</AdditionalMetadataDirectories>
<AdditionalMetadataDirectories Condition="'$(WindowsSDK_MetadataFoundationPath)' == ''">%(Midl.AdditionalMetadataDirectories);$(WindowsSDK_MetadataPath);</AdditionalMetadataDirectories>
</Midl>
</ItemGroup>
<PropertyGroup>
<_MidlrtParameters>@(_MidlReferencesDistinct->'/reference &quot;%(WinMDPath)&quot;','&#x0d;&#x0a;')</_MidlrtParameters>
</PropertyGroup>
<WriteLinesToFile Condition="!$(CppWinRTWriteOnlyWhenDifferent)"
File="$(IntDir)midlrt.rsp" Lines="$(_MidlrtParameters)"
ContinueOnError="true" Overwrite="true" />
<WriteLinesToFile Condition="$(CppWinRTWriteOnlyWhenDifferent)"
File="$(IntDir)midlrt.rsp" Lines="$(_MidlrtParameters)"
ContinueOnError="true" Overwrite="true"
WriteOnlyWhenDifferent="true" />
<Message Text="CppWinRTMidlReferences: @(_MidlReferences->'%(WinMDPath)')" Importance="$(CppWinRTVerbosity)"/>
</Target>
<!--Merge project-generated WinMDs and project-referenced static library WinMDs into project WinMD-->
<Target Name="CppWinRTMergeProjectWinMDInputs"
DependsOnTargets="Midl;GetCppWinRTMdMergeInputs;$(CppWinRTMergeProjectWinMDInputsDependsOn)"
Inputs="@(CppWinRTMdMergeInputs)"
Outputs="$(CppWinRTProjectWinMD)">
<PropertyGroup>
<!--Note: CppWinRTNamespaceMergeDepth supersedes CppWinRTMergeDepth-->
<_MdMergeDepth Condition="'$(CppWinRTNamespaceMergeDepth)' != ''">-n:$(CppWinRTNamespaceMergeDepth)</_MdMergeDepth>
<_MdMergeDepth Condition="'$(_MdMergeDepth)' == ''">$(CppWinRTMergeDepth)</_MdMergeDepth>
<_MdMergeDepth Condition="'$(_MdMergeDepth)' == '' And '$(CppWinRTRootNamespaceAutoMerge)' == 'true'">-n:$(RootNamespace.Split('.').length)</_MdMergeDepth>
<_MdMergeDepth Condition="'$(_MdMergeDepth)' == '' And ('@(Page)' != '' Or '@(ApplicationDefinition)' != '')">-n:1</_MdMergeDepth>
<_MdMergeCommand>$(MdMergePath)mdmerge %40"$(IntDir)mdmerge.rsp"</_MdMergeCommand>
</PropertyGroup>
<PropertyGroup>
<!-- mdmerge.exe wants the folders to not have a trailing \ -->
<_MdMergeParameters>-v @(CppWinRTMdMergeMetadataDirectories->'-metadata_dir &quot;%(RelativeDir).&quot;', '&#x0d;&#x0a;')</_MdMergeParameters>
<_MdMergeParameters>$(_MdMergeParameters) @(CppWinRTMdMergeInputs->'-i &quot;%(Identity)&quot;', '&#x0d;&#x0a;')</_MdMergeParameters>
<_MdMergeParameters>$(_MdMergeParameters) -o &quot;$(CppWinRTMergedDir.TrimEnd('\'))&quot; -partial $(_MdMergeDepth)</_MdMergeParameters>
</PropertyGroup>
<WriteLinesToFile Condition="!$(CppWinRTWriteOnlyWhenDifferent)"
File="$(IntDir)mdmerge.rsp" Lines="$(_MdMergeParameters)"
ContinueOnError="true" Overwrite="true" />
<WriteLinesToFile Condition="$(CppWinRTWriteOnlyWhenDifferent)"
File="$(IntDir)mdmerge.rsp" Lines="$(_MdMergeParameters)"
ContinueOnError="true" Overwrite="true"
WriteOnlyWhenDifferent="true" />
<MakeDir Directories="$(CppWinRTUnmergedDir);$(CppWinRTMergedDir)" />
<Message Text="$(_MdMergeCommand)" Importance="$(CppWinRTVerbosity)"/>
<Exec Command="$(_MdMergeCommand)" />
<ItemGroup>
<_MdMergedOutput Remove="@(_MdMergedOutput)"/>
<_MdMergedOutput Include="$(CppWinRTMergedDir)*.winmd"/>
</ItemGroup>
<Copy UseHardlinksIfPossible="$(CppWinRTUseHardlinksIfPossible)"
SkipUnchangedFiles="$(CppWinRTSkipUnchangedFiles)"
SourceFiles="@(_MdMergedOutput)"
DestinationFiles="@(_MdMergedOutput->'$(OutDir)%(Filename)%(Extension)')" />
<Message Text="CppWinRTMdMerge output: @(MdMergeOutput)" Importance="$(CppWinRTVerbosity)"/>
</Target>
<!-- Build the platform projection from the winmds that sip with the platform in the Windows SDK -->
<Target Name="CppWinRTMakePlatformProjection"
Condition="'$(CppWinRTEnablePlatformProjection)' == 'true' AND '$(CppWinRTOverrideSDKReferences)' != 'true'"
DependsOnTargets="GetCppWinRTPlatformWinMDInputs;$(CppWinRTMakePlatformProjectionDependsOn)"
Inputs="@(CppWinRTPlatformWinMDInputs)"
Outputs="$(GeneratedFilesDir)winrt\base.h">
<PropertyGroup>
<CppWinRTCommand>$(CppWinRTPath)cppwinrt %40"$(IntDir)cppwinrt_plat.rsp"</CppWinRTCommand>
</PropertyGroup>
<ItemGroup>
<_CppwinrtInputs Remove="@(_CppwinrtInputs)"/>
<_CppwinrtInputs Include="@(CppWinRTPlatformWinMDInputs)"/>
</ItemGroup>
<PropertyGroup>
<_CppwinrtParameters>$(CppWinRTCommandVerbosity) $(CppWinRTParameters)</_CppwinrtParameters>
<_CppwinrtParameters>$(_CppwinrtParameters) @(_CppwinrtInputs->'-in &quot;%(WinMDPath)&quot;', '&#x0d;&#x0a;')</_CppwinrtParameters>
<_CppwinrtParameters>$(_CppwinrtParameters) -out &quot;$(GeneratedFilesDir).&quot;</_CppwinrtParameters>
</PropertyGroup>
<WriteLinesToFile Condition="!$(CppWinRTWriteOnlyWhenDifferent)"
File="$(IntDir)cppwinrt_plat.rsp" Lines="$(_CppwinrtParameters)"
ContinueOnError="true" Overwrite="true" />
<WriteLinesToFile Condition="$(CppWinRTWriteOnlyWhenDifferent)"
File="$(IntDir)cppwinrt_plat.rsp" Lines="$(_CppwinrtParameters)"
ContinueOnError="true" Overwrite="true"
WriteOnlyWhenDifferent="true" />
<Message Text="$(CppWinRTCommand)" Importance="$(CppWinRTVerbosity)"/>
<Exec Command="$(CppWinRTCommand)" />
</Target>
<!--Build reference projection from WinMD project references and dynamic library project references-->
<Target Name="CppWinRTMakeReferenceProjection"
Condition="'$(CppWinRTEnableReferenceProjection)' == 'true'"
DependsOnTargets="GetCppWinRTProjectWinMDReferences;GetCppWinRTPlatformWinMDReferences;GetCppWinRTDirectWinMDReferences;$(CppWinRTMakeReferenceProjectionDependsOn)"
Inputs="@(CppWinRTDirectWinMDReferences);@(CppWinRTDynamicProjectWinMDReferences);@(CppWinRTPlatformWinMDReferences)"
Outputs="@(CppWinRTDirectWinMDReferences->'$(GeneratedFilesDir)winrt\%(Filename).h');@(CppWinRTDynamicProjectWinMDReferences->'$(GeneratedFilesDir)winrt\%(Filename).h')">
<PropertyGroup>
<CppWinRTCommand>$(CppWinRTPath)cppwinrt %40"$(IntDir)cppwinrt_ref.rsp"</CppWinRTCommand>
</PropertyGroup>
<ItemGroup>
<_CppwinrtRefInputs Remove="@(_CppwinrtRefInputs)"/>
<_CppwinrtRefInputs Include="@(CppWinRTDirectWinMDReferences)"/>
<_CppwinrtRefInputs Include="@(CppWinRTDynamicProjectWinMDReferences)"/>
<_CppwinrtRefRefs Remove="@(_CppwinrtRefRefs)"/>
<_CppwinrtRefRefs Include="@(CppWinRTPlatformWinMDReferences)"/>
</ItemGroup>
<PropertyGroup>
<_CppwinrtParameters>$(CppWinRTCommandVerbosity) $(CppWinRTParameters)</_CppwinrtParameters>
<_CppwinrtParameters>$(_CppwinrtParameters) @(_CppwinrtRefInputs->'-in &quot;%(WinMDPath)&quot;', '&#x0d;&#x0a;')</_CppwinrtParameters>
<_CppwinrtParameters>$(_CppwinrtParameters) @(_CppwinrtRefRefs->'-ref &quot;%(WinMDPath)&quot;', '&#x0d;&#x0a;')</_CppwinrtParameters>
<_CppwinrtParameters>$(_CppwinrtParameters) -out &quot;$(GeneratedFilesDir).&quot;</_CppwinrtParameters>
</PropertyGroup>
<WriteLinesToFile Condition="!$(CppWinRTWriteOnlyWhenDifferent)"
File="$(IntDir)cppwinrt_ref.rsp" Lines="$(_CppwinrtParameters)"
ContinueOnError="true" Overwrite="true" />
<WriteLinesToFile Condition="$(CppWinRTWriteOnlyWhenDifferent)"
File="$(IntDir)cppwinrt_ref.rsp" Lines="$(_CppwinrtParameters)"
ContinueOnError="true" Overwrite="true"
WriteOnlyWhenDifferent="true" />
<Message Text="$(CppWinRTCommand)" Importance="$(CppWinRTVerbosity)"/>
<Exec Command="$(CppWinRTCommand)" />
</Target>
<!--Build component projection from project WinMD file and static library project references-->
<Target Name="CppWinRTMakeComponentProjection"
Condition="'$(CppWinRTEnableComponentProjection)' == 'true'"
DependsOnTargets="GetCppWinRTProjectWinMDReferences;GetCppWinRTPlatformWinMDReferences;GetCppWinRTDirectWinMDReferences;$(CppWinRTMakeComponentProjectionDependsOn)"
Inputs="@(Midl->'%(MetadataFileName)');@(CppWinRTStaticProjectWinMDReferences)"
Outputs="$(GeneratedFilesDir)winrt\$(RootNamespace).h">
<PropertyGroup>
<_PCH>@(ClCompile->Metadata('PrecompiledHeaderFile')->Distinct())</_PCH>
</PropertyGroup>
<Error Condition="('$(CppWinRTOverrideSDKReferences)' != 'true') and ('$(TargetPlatformVersion)' &lt; '10.0.17709.0') and ('$(_PCH)' != 'pch.h')"
Text="Please retarget to 10.0.17709.0 or later, or rename your PCH to 'pch.h'."/>
<PropertyGroup Condition="('$(CppWinRTOverrideSDKReferences)' == 'true') or ('$(TargetPlatformVersion)' &gt; '10.0.17708.0')">
<CppWinRTUsePrefixes Condition="'$(CppWinRTUsePrefixes)' == ''">true</CppWinRTUsePrefixes>
<CppWinRTPrecompiledHeader Condition="'$(CppWinRTPrecompiledHeader)' == ''">$(_PCH)</CppWinRTPrecompiledHeader>
</PropertyGroup>
<PropertyGroup>
<CppWinRTCommandUsePrefixes Condition="'$(CppWinRTUsePrefixes)' == 'true'">-prefix</CppWinRTCommandUsePrefixes>
<CppWinRTCommandPrecompiledHeader Condition="'$(CppWinRTPrecompiledHeader)' != ''">-pch $(CppWinRTPrecompiledHeader)</CppWinRTCommandPrecompiledHeader>
<CppWinRTCommand>$(CppWinRTPath)cppwinrt %40"$(IntDir)cppwinrt_comp.rsp"</CppWinRTCommand>
</PropertyGroup>
<ItemGroup>
<!-- use the output from MdMerge directly to generate the component projection. -->
<_MdMergedOutput Remove="@(_MdMergedOutput)"/>
<_MdMergedOutput Include="$(CppWinRTMergedDir)*.winmd"/>
<_CppwinrtCompInputs Remove="@(_CppwinrtCompInputs)"/>
<_CppwinrtCompInputs Include="@(_MdMergedOutput)">
<WinMDPath>%(_MdMergedOutput.FullPath)</WinMDPath>
</_CppwinrtCompInputs>
<!-- If this is a static library with static library references,
pass the individual static library references to cppwinrt.exe
for the component projection as they are not merged.-->
<_CppwinrtCompInputs Include="@(CppWinRTStaticProjectWinMDReferences)" Condition="'$(ConfigurationType)' == 'StaticLibrary'">
<WinMDPath>%(CppWinRTStaticProjectWinMDReferences.FullPath)</WinMDPath>
</_CppwinrtCompInputs>
<_CppwinrtCompRefs Remove="@(_CppwinrtCompRefs)"/>
<_CppwinrtCompRefs Include="@(CppWinRTDirectWinMDReferences)"/>
<_CppwinrtCompRefs Include="@(CppWinRTDynamicProjectWinMDReferences)"/>
<_CppwinrtCompRefs Include="@(CppWinRTPlatformWinMDReferences)"/>
</ItemGroup>
<PropertyGroup>
<_CppwinrtParameters>$(CppWinRTCommandVerbosity) $(CppWinRTParameters) -overwrite -name $(RootNamespace) $(CppWinRTCommandPrecompiledHeader) $(CppWinRTCommandUsePrefixes) -comp &quot;$(GeneratedFilesDir)sources&quot;</_CppwinrtParameters>
<_CppwinrtParameters Condition="'$(CppWinRTOptimized)'=='true'">$(_CppwinrtParameters) -opt</_CppwinrtParameters>
<_CppwinrtParameters>$(_CppwinrtParameters) @(_CppwinrtCompInputs->'-in &quot;%(WinMDPath)&quot;', '&#x0d;&#x0a;')</_CppwinrtParameters>
<_CppwinrtParameters>$(_CppwinrtParameters) @(_CppwinrtCompRefs->'-ref &quot;%(WinMDPath)&quot;', '&#x0d;&#x0a;')</_CppwinrtParameters>
<_CppwinrtParameters>$(_CppwinrtParameters) -out &quot;$(GeneratedFilesDir).&quot;</_CppwinrtParameters>
</PropertyGroup>
<WriteLinesToFile Condition="!$(CppWinRTWriteOnlyWhenDifferent)"
File="$(IntDir)cppwinrt_comp.rsp" Lines="$(_CppwinrtParameters)"
ContinueOnError="true" Overwrite="true" />
<WriteLinesToFile Condition="$(CppWinRTWriteOnlyWhenDifferent)"
File="$(IntDir)cppwinrt_comp.rsp" Lines="$(_CppwinrtParameters)"
ContinueOnError="true" Overwrite="true"
WriteOnlyWhenDifferent="true" />
<Message Text="$(CppWinRTCommand)" Importance="$(CppWinRTVerbosity)" Condition="'@(_CppwinrtCompInputs)' != ''"/>
<Exec Command="$(CppWinRTCommand)" Condition="'@(_CppwinrtCompInputs)' != ''"/>
</Target>
<!-- Main target that generates all the CppWinRT projections. -->
<Target Name="CppWinRTMakeProjections" DependsOnTargets="CppWinRTCalculateEnabledProjections;CppWinRTMakePlatformProjection;CppWinRTMakeReferenceProjection;CppWinRTMakeComponentProjection;$(CppWinRTMakeProjectionsDependsOn)" />
<!--Add references to all merged project WinMD files for Xaml Compiler-->
<Target Name="CppWinRTAddXamlReferences" DependsOnTargets="$(CppWinRTAddXamlReferencesDependsOn)">
<ItemGroup>
<XamlReferencesToCompile Include="$(OutDir)*.winmd" />
</ItemGroup>
</Target>
<!--Clear merged assembly and set local assembly for Xaml Compiler.
(Note: this can be removed when CppWinRT references are removed from the Xaml targets file.)-->
<Target Name="CppWinRTSetXamlLocalAssembly" DependsOnTargets="$(CppWinRTSetXamlLocalAssemblyDependsOn)">
<PropertyGroup>
<CppWinRTMetadataAssembly></CppWinRTMetadataAssembly>
<XamlLocalAssembly>$(CppWinRTProjectWinMD)</XamlLocalAssembly>
</PropertyGroup>
</Target>
<!-- Fast ABI component support -->
<PropertyGroup Condition="'$(CppWinRTFastAbi)'=='true'">
<CppWinRTParameters>$(CppWinRTParameters) -fastabi</CppWinRTParameters>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(CppWinRTFastAbi)'=='true'">
<Link>
<AdditionalDependencies>%(AdditionalDependencies);$(CppWinRTPackageDir)build\native\lib\$(Platform)\cppwinrt_fast_forwarder.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
</Project>

6
nuget/SignConfig.xml Normal file
Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<SignConfigXML>
<job configuration="Release" dest="__OUTPATHROOT__" jobname="CppWinRT NuGet" approvers="">
<file src="__INPATHROOT__\Microsoft.Windows.CppWinRT.*.nupkg" signType="CP-401405" dest="__OUTPATHROOT__\Microsoft.Windows.CppWinRT.*.nupkg" />
</job>
</SignConfigXML>

95
nuget/readme.md Normal file
Просмотреть файл

@ -0,0 +1,95 @@
# Microsoft.Windows.CppWinRT NuGet Package
## Overview
Please visit [Microsoft.Windows.CppWinRT](https://www.nuget.org/packages/Microsoft.Windows.CppWinRT/) for official Microsoft-signed builds of the NuGet package. See also the [C++/WinRT](https://aka.ms/cppwinrt/vsix/) VSIX, which provides C++/WinRT project templates and debug visualization.
To add build support for C++/WinRT vcxproj projects, add a reference to the Microsoft.Windows.CppWinRT NuGet package. This customizes your project's build rules to automatically generate C++/WinRT projection headers, enabling you to both consume and produce Windows Runtime classes.
C++/WinRT detects Windows metadata referenced by the project, from:
* Platform winmd files in the SDK (both MSI and NuGet)
* NuGet packages containing winmd files
* Other projects producing winmd files
* Raw winmd files
* Interface definition language (IDL) files in the project
For any winmd file referenced by the project, C++/WinRT creates reference (consuming) projection headers. Client code can simply #include these headers, which are created in the generated files directory (see below).
For any IDL file contained in the project, C++/WinRT creates component (producing) projection headers. In addition, C++/WinRT generates templates and skeleton implementations for each runtime class, under the generated files directory.
## Details
C++/WinRT configures build rules for the following tools:
* C++ compiler
* C++/WinRT compiler
* MdMerge utility
* Midlrt utility
* Xaml compiler
It sets the following project properties and item metadata:
| Property | Value | Description |
|-|-|-|
| [PreferredToolArchitecture](https://docs.microsoft.com/en-us/cpp/build/msbuild-visual-cpp-overview?view=vs-2017) | x64 | Enables the compiler to use more memory |
| CanReferenceWinRT | true | Enables native project references (e.g., to WinMD files) |
| GeneratedFilesDir | *$(IntDir)Generated Files\ | Sets the folder for C++/WinRT generated source files |
| XamlLanguage | CppWinRT | Directs the Xaml compiler to generate C++/WinRT code |
| ClCompile.CompileAsWinRT | *false | Enables ISO C++ compilation (disables C++/CX) |
| ClCompile.LanguageStandard | *stdcpp17 | Enables C++17 language features |
| ClCompile.AdditionalOptions | /bigobj /await | Enables support for large object files and coroutines |
| ClCompile.AdditionalIncludeDirectories | GeneratedFilesDir | Adds $(GeneratedFilesDir) to the C++ include dirs |
| Link.AdditionalDependencies | WindowsApp.lib | Umbrella library for Windows Runtime imports |
| Midl.AdditionalOptions | /reference ... | Enables faster compilation with winmd references (versus idl imports) |
| Midl.EnableWindowsRuntime | true | Enables Windows Runtime semantics |
| Midl.MetadataFileName | Unmerged\%(Filename).winmd | Generates unmerged metadata in a tempoary location |
| Midl.GenerateClientFiles, GenerateServerFiles, GenerateStublessProxies, GenerateTypeLibrary, HeaderFileName, DllDataFileName, InterfaceIdentifierFileName, ProxyFileName, TypeLibraryName | *nul, *None, *false | Disable unnecessary output |
\*If not already set
## Generated Files
The generated files directory created by C++/WinRT contains two subfolders:
* sources: runtime class skeleton implementations
* winrt: reference projection headers
## Customizing
C++/WinRT behavior can be customized with these project properties:
| Property | Value | Description |
|-|-|-|
| CppWinRTLibs | *true \| false | Enables the Link item metadata settings above |
| CppWinRTModernIDL | *true \| false | Enables the Midl item metadata settings above |
| CppWinRTVerbosity | low \| *normal \| high | Sets the [importance](https://docs.microsoft.com/en-us/visualstudio/msbuild/message-task?view=vs-2017) of C++/WinRT build messages (see below) |
| CppWinRTNamespaceMergeDepth | *1 | Sets the depth of namespace merging (Xaml apps require 1) |
| CppWinRTRootNamespaceAutoMerge | true \| *false | Sets the namespace merge depth to be the length of the root namespace |
| CppWinRTUsePrefixes | *true \| false | Uses a dotted prefix namespace convention (versus a nested folder convention) |
| CppWinRTPath | ...\cppwinrt.exe | NuGet package-relative path to cppwinrt.exe, for custom build rule invocation |
| CppWinRTParameters | "" | Custom cppwinrt.exe command-line parameters (be sure to append to existing) |
| CppWinRTFastAbi | true \| *false | Enables Fast ABI feature for both consuming and producing projections |
| CppWinRTProjectLanguage | C++/CX \| *C++/WinRT | Selects the C++ dialect for the project. C++/WinRT provides full projection support, C++/CX permits consuming projection headers. |
| CppWinRTOptimized | true \| *false | Enables component projection [optimization features](https://kennykerr.ca/2019/06/07/cppwinrt-optimizing-components/) |
\*Default value
To customize common C++/WinRT project properties:
* right-click the project node
* expand the Common Properties item
* select the C++/WinRT property page
## Troubleshooting
The msbuild verbosity level maps to msbuild message importance as follows:
| Verbosity | Importance |
|-|-|
| q[uiet] | n/a |
| m[inimal] | high |
| n[ormal] | normal+ |
| d[etailed], diag[nostic] | low+ |
For example, if the verbosity is set to minimal, then only messages with high importance are generated. However, if the verbosity is set to diagnostic, then all messages are generated.
The default importance of C++/WinRT build messages is 'normal', but this can be overridden with the CppWinRTVerbosity property to enable throttling of C++/WinRT messages independent of the overall verbosity level.
Example:
> msbuild project.vcxproj /vebosity:minimal /property:CppWinRTVerbosity=high ...
For more complex analysis of build errors, the [MSBuild Binary and Structured Log Viewer](http://msbuildlog.com/) is highly recommended.

22
nuget/readme.txt Normal file
Просмотреть файл

@ -0,0 +1,22 @@
========================================================================
The Microsoft.Windows.CppWinRT NuGet package automatically generates C++/WinRT projection headers,
enabling you to both consume and produce Windows Runtime classes.
========================================================================
C++/WinRT detects Windows metadata referenced by the project, from:
* Platform winmd files in the SDK (both MSI and NuGet)
* NuGet packages containing winmd files
* Other projects producing winmd files
* Raw winmd files
* Interface definition language (IDL) files in the project
For any winmd file referenced by the project, C++/WinRT creates reference (consuming) projection headers.
Client code can simply #include these headers, which are created in the Generated Files directory.
For any IDL file contained in the project, C++/WinRT creates component (producing) projection headers.
In addition, C++/WinRT generates templates and skeleton implementations for each runtime class, under the Generated Files directory.
========================================================================
For more information, visit:
https://github.com/Microsoft/xlang/tree/master/src/package/cppwinrt/nuget
========================================================================

119
prebuild/main.cpp Normal file
Просмотреть файл

@ -0,0 +1,119 @@
#include "pch.h"
struct writer : xlang::text::writer_base<writer>
{
};
int main(int const argc, char** argv)
{
if (argc < 3)
{
puts("Usage: prebuild.exe input output");
return 0;
}
writer strings_h;
writer strings_cpp;
strings_h.write(R"(
#pragma once
namespace xlang::strings {
)");
strings_cpp.write(R"(
namespace xlang::strings {
)");
for (auto&& file : std::filesystem::directory_iterator(argv[1]))
{
if (!std::filesystem::is_regular_file(file))
{
continue;
}
auto path = file.path();
auto name = path.filename();
name.replace_extension();
auto view = xlang::text::file_to_string(path.string());
strings_h.write(R"(extern char const %[%];
)",
name.string(),
static_cast<uint64_t>(view.size()));
strings_cpp.write(R"(extern char const %[] = R"xyz()xyz"
)",
name.string());
std::string_view remainder = view;
while (remainder.size())
{
auto const size = std::min(size_t{ 16'000 }, remainder.size());
auto const chunk = remainder.substr(0, size);
strings_cpp.write(R"(R"xyz(%)xyz"
)",
chunk);
remainder = remainder.substr(size);
}
strings_cpp.write(";\n");
}
strings_h.write(R"(
}
)");
strings_cpp.write(R"(
}
)");
writer version_rc;
version_rc.write(R"(
#include "winres.h"
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,0,0,0
PRODUCTVERSION 2,0,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x0L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Microsoft Corporation"
VALUE "FileDescription", "C++/WinRT"
VALUE "FileVersion", "2.0.0.0"
VALUE "LegalCopyright", "Microsoft Corporation. All rights reserved."
VALUE "OriginalFilename", "cppwinrt.exe"
VALUE "ProductName", "C++/WinRT"
VALUE "ProductVersion", "%"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
)",
XLANG_VERSION_STRING);
std::filesystem::create_directories(argv[2]);
auto const output = std::filesystem::canonical(argv[2]);
strings_h.flush_to_file(output / "strings.h");
strings_cpp.flush_to_file(output / "strings.cpp");
version_rc.flush_to_file(output / "version.rc");
}

1
prebuild/pch.cpp Normal file
Просмотреть файл

@ -0,0 +1 @@
#include "pch.h"

3
prebuild/pch.h Normal file
Просмотреть файл

@ -0,0 +1,3 @@
#pragma once
#include "text_writer.h"

132
prebuild/prebuild.vcxproj Normal file
Просмотреть файл

@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{FB239623-7D19-4025-BCEA-B43298D4A315}</ProjectGuid>
<RootNamespace>cppwinrt</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(SolutionDir)\cppwinrt.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IntDir>$(OutDir)temp\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IntDir>$(OutDir)temp\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IntDir>$(OutDir)temp\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IntDir>$(OutDir)temp\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\inc</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\inc</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\inc</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\inc</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

6
run_tests.cmd Normal file
Просмотреть файл

@ -0,0 +1,6 @@
..\..\..\_build\Windows\x64\Debug\tool\cppwinrt\test.exe
..\..\..\_build\Windows\x64\Debug\tool\cppwinrt\test_fast.exe
..\..\..\_build\Windows\x64\Debug\tool\cppwinrt\test_slow.exe
..\..\..\_build\Windows\x64\Debug\tool\cppwinrt\test_old.exe
..\..\..\_build\Windows\x64\Debug\tool\cppwinrt\test_module_lock_custom.exe
..\..\..\_build\Windows\x64\Debug\tool\cppwinrt\test_module_lock_none.exe

7
scratch/main.cpp Normal file
Просмотреть файл

@ -0,0 +1,7 @@
#include "pch.h"
using namespace winrt;
int main()
{
}

1
scratch/pch.cpp Normal file
Просмотреть файл

@ -0,0 +1 @@
#include "pch.h"

3
scratch/pch.h Normal file
Просмотреть файл

@ -0,0 +1,3 @@
#pragma once
#include "winrt/Windows.Foundation.Collections.h"

182
scratch/scratch.vcxproj Normal file
Просмотреть файл

@ -0,0 +1,182 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{E893622C-47DE-4F83-B422-0A26711590A4}</ProjectGuid>
<RootNamespace>scratch</RootNamespace>
<ProjectName>scratch</ProjectName>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(SolutionDir)\cppwinrt.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IntDir>$(OutDir)temp\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IntDir>$(OutDir)temp\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IntDir>$(OutDir)temp\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IntDir>$(OutDir)temp\$(ProjectName)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(OutputPath);Generated Files;..\..\..\library</AdditionalIncludeDirectories>
<PreprocessorDefinitions>NOMINMAX;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalOptions>/await %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<PreBuildEvent>
<Command>
</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(OutputPath);Generated Files;..\..\..\library</AdditionalIncludeDirectories>
<PreprocessorDefinitions>NOMINMAX;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalOptions>/await %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
</Link>
<PreBuildEvent>
<Command>
</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(OutputPath);Generated Files;..\..\..\library</AdditionalIncludeDirectories>
<PreprocessorDefinitions>NOMINMAX;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalOptions>/await %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
</Link>
<PreBuildEvent>
<Command>
</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(OutputPath);Generated Files;..\..\..\library</AdditionalIncludeDirectories>
<PreprocessorDefinitions>NOMINMAX;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalOptions>/await %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<PreBuildEvent>
<Command>
</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Use</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Use</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Use</PrecompiledHeader>
</ClCompile>
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

149
strings/base_abi.h Normal file
Просмотреть файл

@ -0,0 +1,149 @@
namespace winrt::impl
{
template <> struct abi<Windows::Foundation::IUnknown>
{
struct __declspec(novtable) 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;
};
};
using unknown_abi = abi_t<Windows::Foundation::IUnknown>;
template <> struct abi<Windows::Foundation::IInspectable>
{
struct __declspec(novtable) 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;
};
};
using inspectable_abi = abi_t<Windows::Foundation::IInspectable>;
template <> struct abi<Windows::Foundation::IActivationFactory>
{
struct __declspec(novtable) type : inspectable_abi
{
virtual int32_t __stdcall ActivateInstance(void** instance) noexcept = 0;
};
};
struct __declspec(novtable) IAgileObject : unknown_abi {};
struct __declspec(novtable) IAgileReference : unknown_abi
{
virtual int32_t __stdcall Resolve(guid const& id, void** object) noexcept = 0;
};
struct __declspec(novtable) 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;
};
struct __declspec(novtable) IStaticLifetime : inspectable_abi
{
virtual int32_t __stdcall unused() noexcept = 0;
virtual int32_t __stdcall GetCollection(void** value) noexcept = 0;
};
struct __declspec(novtable) 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 unused4() noexcept = 0;
virtual int32_t __stdcall unused5() noexcept = 0;
};
struct __declspec(novtable) IWeakReference : unknown_abi
{
virtual int32_t __stdcall Resolve(guid const& iid, void** objectReference) noexcept = 0;
};
struct __declspec(novtable) IWeakReferenceSource : unknown_abi
{
virtual int32_t __stdcall GetWeakReference(IWeakReference** weakReference) noexcept = 0;
};
struct __declspec(novtable) 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;
};
struct __declspec(novtable) 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;
};
struct __declspec(novtable) 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;
};
struct ICallbackWithNoReentrancyToApplicationSTA;
struct __declspec(novtable) 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;
};
struct __declspec(novtable) 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;
};
struct __declspec(novtable) IBufferByteAccess : unknown_abi
{
virtual int32_t __stdcall Buffer(uint8_t** value) noexcept = 0;
};
template <> struct abi<Windows::Foundation::TimeSpan>
{
using type = int64_t;
};
template <> struct abi<Windows::Foundation::DateTime>
{
using type = int64_t;
};
template <> inline constexpr guid guid_v<Windows::Foundation::IUnknown>{ 0x00000000, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
template <> inline constexpr guid guid_v<Windows::Foundation::IInspectable>{ 0xAF86E2E0, 0xB12D, 0x4C6A, { 0x9C,0x5A,0xD7,0xAA,0x65,0x10,0x1E,0x90 } };
template <> inline constexpr guid guid_v<Windows::Foundation::IActivationFactory>{ 0x00000035, 0x0000, 0x0000, { 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
template <> inline constexpr guid guid_v<IAgileObject>{ 0x94EA2B94, 0xE9CC, 0x49E0, { 0xC0,0xFF,0xEE,0x64,0xCA,0x8F,0x5B,0x90 } };
template <> inline constexpr guid guid_v<IMarshal>{ 0x00000003, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
template <> inline constexpr guid guid_v<IStaticLifetime>{ 0x17b0e613, 0x942a, 0x422d, { 0x90,0x4c,0xf9,0x0d,0xc7,0x1a,0x7d,0xae } };
template <> inline constexpr guid guid_v<IStaticLifetimeCollection>{ 0x1b0d3570, 0x0877, 0x5ec2, { 0x8a,0x2c,0x3b,0x95,0x39,0x50,0x6a,0xca } };
template <> inline constexpr guid guid_v<IWeakReference>{ 0x00000037, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
template <> inline constexpr guid guid_v<IWeakReferenceSource>{ 0x00000038, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
template <> inline constexpr guid guid_v<IRestrictedErrorInfo>{ 0x82BA7092, 0x4C88, 0x427D, { 0xA7,0xBC,0x16,0xDD,0x93,0xFE,0xB6,0x7E } };
template <> inline constexpr guid guid_v<IErrorInfo>{ 0x1CF2B120, 0x547D, 0x101B, { 0x8E,0x65,0x08,0x00,0x2B,0x2B,0xD1,0x19 } };
template <> inline constexpr guid guid_v<ILanguageExceptionErrorInfo2>{ 0x5746E5C4, 0x5B97, 0x424C, { 0xB6,0x20,0x28,0x22,0x91,0x57,0x34,0xDD } };
template <> inline constexpr guid guid_v<ICallbackWithNoReentrancyToApplicationSTA>{ 0x0A299774, 0x3E4E, 0xFC42, { 0x1D,0x9D,0x72,0xCE,0xE1,0x05,0xCA,0x57 } };
template <> inline constexpr guid guid_v<IContextCallback>{ 0x000001da, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
template <> inline constexpr guid guid_v<IServerSecurity>{ 0x0000013E, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
template <> inline constexpr guid guid_v<IBufferByteAccess>{ 0x905a0fef, 0xbc53, 0x11df, { 0x8c,0x49,0x00,0x1e,0x4f,0xc6,0x86,0xda } };
}

426
strings/base_activation.h Normal file
Просмотреть файл

@ -0,0 +1,426 @@
WINRT_EXPORT namespace winrt
{
template <typename Interface = Windows::Foundation::IActivationFactory>
impl::com_ref<Interface> get_activation_factory(param::hstring const& name)
{
void* result{};
hresult hr = WINRT_RoGetActivationFactory(*(void**)(&name), guid_of<Interface>(), &result);
if (hr == impl::error_not_initialized)
{
void* cookie;
WINRT_CoIncrementMTAUsage(&cookie);
hr = WINRT_RoGetActivationFactory(*(void**)(&name), guid_of<Interface>(), &result);
}
check_hresult(hr);
return { result, take_ownership_from_abi };
}
}
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
#if defined _M_ARM
#define WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER (__dmb(_ARM_BARRIER_ISH));
#elif defined _M_ARM64
#define WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER (__dmb(_ARM64_BARRIER_ISH));
#endif
namespace winrt::impl
{
inline int32_t interlocked_read_32(int32_t const volatile* target) noexcept
{
#if defined _M_IX86 || defined _M_X64
int32_t const result = *target;
_ReadWriteBarrier();
return result;
#elif defined _M_ARM || defined _M_ARM64
int32_t const result = __iso_volatile_load32(reinterpret_cast<int32_t const volatile*>(target));
WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER
return result;
#else
#error Unsupported architecture
#endif
}
#if defined _WIN64
inline int64_t interlocked_read_64(int64_t const volatile* target) noexcept
{
#if defined _M_X64
int64_t const result = *target;
_ReadWriteBarrier();
return result;
#elif defined _M_ARM64
int64_t const result = __iso_volatile_load64(target);
WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER
return result;
#else
#error Unsupported architecture
#endif
}
#endif
#undef WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER
#ifdef __clang__
#pragma clang diagnostic pop
#endif
template <typename T>
T* interlocked_read_pointer(T* const volatile* target) noexcept
{
#ifdef _WIN64
return (T*)interlocked_read_64((int64_t*)target);
#else
return (T*)interlocked_read_32((int32_t*)target);
#endif
}
#ifdef _WIN64
inline constexpr uint32_t memory_allocation_alignment{ 16 };
#pragma warning(push)
#pragma warning(disable:4324) // structure was padded due to alignment specifier
struct alignas(16) slist_entry
{
slist_entry* next;
};
union alignas(16) slist_header
{
struct
{
uint64_t reserved1;
uint64_t reserved2;
} reserved1;
struct
{
uint64_t reserved1 : 16;
uint64_t reserved2 : 48;
uint64_t reserved3 : 4;
uint64_t reserved4 : 60;
} reserved2;
};
#pragma warning(pop)
#else
inline constexpr uint32_t memory_allocation_alignment{ 8 };
struct slist_entry
{
slist_entry* next;
};
union slist_header
{
uint64_t reserved1;
struct
{
slist_entry reserved1;
uint16_t reserved2;
uint16_t reserved3;
} reserved2;
};
#endif
struct factory_count_guard
{
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)
{
#ifdef _WIN64
_InterlockedIncrement64((int64_t*)&m_count);
#else
_InterlockedIncrement((long*)&m_count);
#endif
}
~factory_count_guard() noexcept
{
#ifdef _WIN64
_InterlockedDecrement64((int64_t*)&m_count);
#else
_InterlockedDecrement((long*)&m_count);
#endif
}
private:
size_t& m_count;
};
struct factory_cache_entry_base
{
struct alignas(sizeof(void*) * 2) object_and_count
{
unknown_abi* object;
size_t count;
};
object_and_count m_value;
alignas(memory_allocation_alignment) slist_entry m_next;
void clear() noexcept
{
unknown_abi* pointer_value = interlocked_read_pointer(&m_value.object);
if (pointer_value == nullptr)
{
return;
}
object_and_count current_value{ pointer_value, 0 };
#if defined _WIN64
if (1 == _InterlockedCompareExchange128((int64_t*)this, 0, 0, (int64_t*)&current_value))
{
pointer_value->Release();
}
#else
int64_t const result = _InterlockedCompareExchange64((int64_t*)this, 0, *(int64_t*)&current_value);
if (result == *(int64_t*)&current_value)
{
pointer_value->Release();
}
#endif
}
};
static_assert(std::is_standard_layout_v<factory_cache_entry_base>);
#if !defined _M_IX86 && !defined _M_X64 && !defined _M_ARM && !defined _M_ARM64
#error Unsupported architecture: verify that zero-initialization of SLIST_HEADER is still safe
#endif
struct factory_cache
{
factory_cache(factory_cache const&) = delete;
factory_cache& operator=(factory_cache const&) = delete;
factory_cache() noexcept = default;
void add(factory_cache_entry_base* const entry) noexcept
{
WINRT_ASSERT(entry);
WINRT_InterlockedPushEntrySList(&m_list, &entry->m_next);
}
void clear() noexcept
{
slist_entry* entry = static_cast<slist_entry*>(WINRT_InterlockedFlushSList(&m_list));
while (entry != nullptr)
{
// 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<factory_cache_entry_base*>(reinterpret_cast<uint8_t*>(entry) - offsetof(factory_cache_entry_base, m_next))->clear();
entry = next;
}
}
private:
alignas(memory_allocation_alignment) slist_header m_list;
};
inline factory_cache& get_factory_cache() noexcept
{
static factory_cache cache;
return cache;
}
template <typename Class, typename Interface>
struct factory_cache_entry : factory_cache_entry_base
{
template <typename F>
__declspec(noinline) auto call(F&& callback)
{
#ifdef WINRT_DIAGNOSTICS
get_diagnostics_info().add_factory<Class>();
#endif
auto object = get_activation_factory<Interface>(name_of<Class>());
if (!object.template try_as<IAgileObject>())
{
#ifdef WINRT_DIAGNOSTICS
get_diagnostics_info().non_agile_factory<Class>();
#endif
return callback(object);
}
{
factory_count_guard const guard(m_value.count);
if (nullptr == _InterlockedCompareExchangePointer(reinterpret_cast<void**>(&m_value.object), *reinterpret_cast<void**>(&object), nullptr))
{
*reinterpret_cast<void**>(&object) = nullptr;
get_factory_cache().add(this);
}
return callback(*reinterpret_cast<com_ref<Interface> const*>(&m_value.object));
}
}
};
template <typename Class, typename Interface>
factory_cache_entry<Class, Interface> factory_cache_entry_v{};
template <typename Class, typename Interface = Windows::Foundation::IActivationFactory, typename F>
auto call_factory(F&& callback)
{
auto& factory = factory_cache_entry_v<Class, Interface>;
{
factory_count_guard const guard(factory.m_value.count);
if (factory.m_value.object)
{
return callback(*reinterpret_cast<com_ref<Interface> const*>(&factory.m_value.object));
}
}
return factory.call(callback);
}
template <typename CastType, typename Class, typename Interface = Windows::Foundation::IActivationFactory, typename F>
auto call_factory_cast(F&& callback)
{
auto& factory = factory_cache_entry_v<Class, Interface>;
{
factory_count_guard const guard(factory.m_value.count);
if (factory.m_value.object)
{
return callback(*reinterpret_cast<com_ref<Interface> const*>(&factory.m_value.object));
}
}
return factory.call(static_cast<CastType>(callback));
}
template <typename Class, typename Interface = Windows::Foundation::IActivationFactory>
impl::com_ref<Interface> try_get_activation_factory(hresult_error* exception = nullptr) noexcept
{
param::hstring const name{ name_of<Class>() };
void* result{};
hresult const hr = WINRT_RoGetActivationFactory(get_abi(name), guid_of<Interface>(), &result);
if (hr < 0)
{
// Ensure that the IRestrictedErrorInfo is not left on the thread.
hresult_error local_exception{ hr, take_ownership_from_abi };
if (exception)
{
// Optionally transfer ownership to the caller.
*exception = std::move(local_exception);
}
}
return { result, take_ownership_from_abi };
}
template <typename D> struct produce<D, Windows::Foundation::IActivationFactory> : produce_base<D, Windows::Foundation::IActivationFactory>
{
int32_t __stdcall ActivateInstance(void** instance) noexcept final try
{
*instance = nullptr;
typename D::abi_guard guard(this->shim());
*instance = detach_abi(this->shim().ActivateInstance());
return 0;
}
catch (...) { return to_hresult(); }
};
}
WINRT_EXPORT namespace winrt
{
enum class apartment_type : int32_t
{
single_threaded,
multi_threaded
};
inline void init_apartment(apartment_type const type = apartment_type::multi_threaded)
{
hresult const result = WINRT_RoInitialize(static_cast<uint32_t>(type));
if (result < 0)
{
throw_hresult(result);
}
}
inline void uninit_apartment() noexcept
{
WINRT_RoUninitialize();
}
template <typename Class, typename Interface = Windows::Foundation::IActivationFactory>
auto get_activation_factory()
{
// Normally, the callback avoids having to return a ref-counted object and the resulting AddRef/Release bump.
// In this case we do want a unique reference, so we use the lambda to return one and thus produce an
// AddRef'd object that is returned to the caller.
return impl::call_factory<Class, Interface>([](auto&& factory)
{
return factory;
});
}
template <typename Class, typename Interface = Windows::Foundation::IActivationFactory>
auto try_get_activation_factory() noexcept
{
return impl::try_get_activation_factory<Class, Interface>();
}
template <typename Class, typename Interface = Windows::Foundation::IActivationFactory>
auto try_get_activation_factory(hresult_error& exception) noexcept
{
return impl::try_get_activation_factory<Class, Interface>(&exception);
}
inline void clear_factory_cache() noexcept
{
impl::get_factory_cache().clear();
}
template <typename Interface>
auto create_instance(guid const& clsid, uint32_t context = 0x1 /*CLSCTX_INPROC_SERVER*/, void* outer = nullptr)
{
return capture<Interface>(WINRT_CoCreateInstance, clsid, outer, context);
}
namespace Windows::Foundation
{
struct IActivationFactory : IInspectable
{
IActivationFactory(std::nullptr_t = nullptr) noexcept {}
IActivationFactory(void* ptr, take_ownership_from_abi_t) noexcept : IInspectable(ptr, take_ownership_from_abi) {}
template <typename T>
T ActivateInstance() const
{
IInspectable instance;
check_hresult((*(impl::abi_t<IActivationFactory>**)this)->ActivateInstance(put_abi(instance)));
return instance.try_as<T>();
}
};
}
}
namespace winrt::impl
{
template <typename T>
T fast_activate(Windows::Foundation::IActivationFactory const& factory)
{
void* result{};
check_hresult((*(impl::abi_t<Windows::Foundation::IActivationFactory>**)&factory)->ActivateInstance(&result));
return{ result, take_ownership_from_abi };
}
}

44
strings/base_agile_ref.h Normal file
Просмотреть файл

@ -0,0 +1,44 @@
WINRT_EXPORT namespace winrt
{
template <typename T>
struct agile_ref
{
agile_ref(std::nullptr_t = nullptr) noexcept {}
agile_ref(impl::com_ref<T> const& object)
{
if (object)
{
check_hresult(WINRT_RoGetAgileReference(0, guid_of<T>(), winrt::get_abi(object), m_ref.put_void()));
}
}
impl::com_ref<T> get() const noexcept
{
if (!m_ref)
{
return nullptr;
}
void* result{};
m_ref->Resolve(guid_of<T>(), &result);
return { result, take_ownership_from_abi };
}
explicit operator bool() const noexcept
{
return static_cast<bool>(m_ref);
}
private:
com_ptr<impl::IAgileReference> m_ref;
};
template <typename T>
agile_ref<T> make_agile(T const& object)
{
return object;
}
}

489
strings/base_array.h Normal file
Просмотреть файл

@ -0,0 +1,489 @@
WINRT_EXPORT namespace winrt
{
template <typename T>
struct array_view
{
using value_type = T;
using size_type = uint32_t;
using reference = value_type&;
using const_reference = value_type const&;
using pointer = value_type*;
using const_pointer = value_type const*;
using iterator = value_type*;
using const_iterator = value_type const*;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
array_view() noexcept = default;
array_view(pointer first, pointer last) noexcept :
m_data(first),
m_size(static_cast<size_type>(last - first))
{}
array_view(std::initializer_list<value_type> value) noexcept :
array_view(value.begin(), static_cast<size_type>(value.size()))
{}
template <typename C, size_type N>
array_view(C(&value)[N]) noexcept :
array_view(value, N)
{}
template <typename = std::enable_if_t<std::is_same_v<T, bool>>>
array_view(std::vector<bool>& value) noexcept
{
static_assert(false, "Cannot use std::vector<bool> as an array_view. Consider std::array or std::unique_ptr<bool[]>.");
}
template <typename = std::enable_if_t<std::is_same_v<T, bool>>>
array_view(std::vector<bool> const& value) noexcept
{
static_assert(false, "Cannot use std::vector<bool> as an array_view. Consider std::array or std::unique_ptr<bool[]>.");
}
template <typename C>
array_view(std::vector<C>& value) noexcept :
array_view(value.data(), static_cast<size_type>(value.size()))
{}
template <typename C>
array_view(std::vector<C> const& value) noexcept :
array_view(value.data(), static_cast<size_type>(value.size()))
{}
template <typename C, size_t N>
array_view(std::array<C, N>& value) noexcept :
array_view(value.data(), static_cast<size_type>(value.size()))
{}
template <typename C, size_t N>
array_view(std::array<C, N> const& value) noexcept :
array_view(value.data(), static_cast<size_type>(value.size()))
{}
reference operator[](size_type const pos) noexcept
{
WINRT_ASSERT(pos < size());
return m_data[pos];
}
const_reference operator[](size_type const pos) const noexcept
{
WINRT_ASSERT(pos < size());
return m_data[pos];
}
reference at(size_type const pos)
{
if (size() <= pos)
{
throw std::out_of_range("Invalid array subscript");
}
return m_data[pos];
}
const_reference at(size_type const pos) const
{
if (size() <= pos)
{
throw std::out_of_range("Invalid array subscript");
}
return m_data[pos];
}
reference front() noexcept
{
WINRT_ASSERT(m_size > 0);
return*m_data;
}
const_reference front() const noexcept
{
WINRT_ASSERT(m_size > 0);
return*m_data;
}
reference back() noexcept
{
WINRT_ASSERT(m_size > 0);
return m_data[m_size - 1];
}
const_reference back() const noexcept
{
WINRT_ASSERT(m_size > 0);
return m_data[m_size - 1];
}
pointer data() noexcept
{
return m_data;
}
const_pointer data() const noexcept
{
return m_data;
}
iterator begin() noexcept
{
return m_data;
}
const_iterator begin() const noexcept
{
return m_data;
}
const_iterator cbegin() const noexcept
{
return m_data;
}
iterator end() noexcept
{
return m_data + m_size;
}
const_iterator end() const noexcept
{
return m_data + m_size;
}
const_iterator cend() const noexcept
{
return m_data + m_size;
}
reverse_iterator rbegin() noexcept
{
return reverse_iterator(end());
}
const_reverse_iterator rbegin() const noexcept
{
return const_reverse_iterator(end());
}
const_reverse_iterator crbegin() const noexcept
{
return rbegin();
}
reverse_iterator rend() noexcept
{
return reverse_iterator(begin());
}
const_reverse_iterator rend() const noexcept
{
return const_reverse_iterator(begin());
}
const_reverse_iterator crend() const noexcept
{
return rend();
}
bool empty() const noexcept
{
return m_size == 0;
}
size_type size() const noexcept
{
return m_size;
}
protected:
array_view(pointer data, size_type size) noexcept :
m_data(data),
m_size(size)
{}
pointer m_data{ nullptr };
size_type m_size{ 0 };
};
template <typename T>
struct com_array : array_view<T>
{
using typename array_view<T>::value_type;
using typename array_view<T>::size_type;
using typename array_view<T>::reference;
using typename array_view<T>::const_reference;
using typename array_view<T>::pointer;
using typename array_view<T>::const_pointer;
using typename array_view<T>::iterator;
using typename array_view<T>::const_iterator;
using typename array_view<T>::reverse_iterator;
using typename array_view<T>::const_reverse_iterator;
com_array(com_array const&) = delete;
com_array& operator=(com_array const&) = delete;
com_array() noexcept = default;
explicit com_array(size_type const count) :
com_array(count, value_type())
{}
com_array(void* ptr, uint32_t const count, take_ownership_from_abi_t) noexcept :
array_view<T>(static_cast<value_type*>(ptr), static_cast<value_type*>(ptr) + count)
{
}
com_array(size_type const count, value_type const& value)
{
alloc(count);
std::uninitialized_fill_n(this->m_data, count, value);
}
template <typename InIt> com_array(InIt first, InIt last)
{
alloc(static_cast<size_type>(std::distance(first, last)));
std::uninitialized_copy(first, last, this->begin());
}
explicit com_array(std::vector<value_type> const& value) :
com_array(value.begin(), value.end())
{}
template <size_t N>
explicit com_array(std::array<value_type, N> const& value) :
com_array(value.begin(), value.end())
{}
template <size_type N>
explicit com_array(value_type const(&value)[N]) :
com_array(value, value + N)
{}
com_array(std::initializer_list<value_type> value) :
com_array(value.begin(), value.end())
{}
com_array(com_array&& other) noexcept :
array_view<T>(other.m_data, other.m_size)
{
other.m_data = nullptr;
other.m_size = 0;
}
com_array& operator=(com_array&& other) noexcept
{
clear();
this->m_data = other.m_data;
this->m_size = other.m_size;
other.m_data = nullptr;
other.m_size = 0;
return*this;
}
~com_array() noexcept
{
clear();
}
void clear() noexcept
{
if (this->m_data == nullptr) { return; }
std::destroy(this->begin(), this->end());
WINRT_CoTaskMemFree(this->m_data);
this->m_data = nullptr;
this->m_size = 0;
}
friend void swap(com_array& left, com_array& right) noexcept
{
std::swap(left.m_data, right.m_data);
std::swap(left.m_size, right.m_size);
}
private:
void alloc(size_type const size)
{
WINRT_ASSERT(this->empty());
if (0 != size)
{
this->m_data = static_cast<value_type*>(WINRT_CoTaskMemAlloc(size * sizeof(value_type)));
if (this->m_data == nullptr)
{
throw std::bad_alloc();
}
this->m_size = size;
}
}
};
template <typename T>
bool operator==(array_view<T> const& left, array_view<T> const& right) noexcept
{
return std::equal(left.begin(), left.end(), right.begin(), right.end());
}
template <typename T>
bool operator<(array_view<T> const& left, array_view<T> const& right) noexcept
{
return std::lexicographical_compare(left.begin(), left.end(), right.begin(), right.end());
}
template <typename T> bool operator!=(array_view<T> const& left, array_view<T> const& right) noexcept { return !(left == right); }
template <typename T> bool operator>(array_view<T> const& left, array_view<T> const& right) noexcept { return right < left; }
template <typename T> bool operator<=(array_view<T> const& left, array_view<T> const& right) noexcept { return !(right < left); }
template <typename T> bool operator>=(array_view<T> const& left, array_view<T> const& right) noexcept { return !(left < right); }
template <typename T>
auto get_abi(array_view<T> object) noexcept
{
if constexpr (std::is_base_of_v<Windows::Foundation::IUnknown, T>)
{
return (void**)object.data();
}
else
{
return reinterpret_cast<impl::arg_out<std::remove_const_t<T>>>(const_cast<std::remove_const_t<T>*>(object.data()));
}
}
template <typename T>
auto put_abi(array_view<T> object) noexcept
{
if constexpr (!std::is_trivially_destructible_v<T>)
{
std::fill(object.begin(), object.end(), impl::empty_value<T>());
}
return get_abi(object);
}
template<typename T>
auto put_abi(com_array<T>& object) noexcept
{
object.clear();
return reinterpret_cast<impl::arg_out<T>*>(&object);
}
template <typename T>
auto detach_abi(com_array<T>& object) noexcept
{
std::pair<uint32_t, impl::arg_out<T>> result(object.size(), *reinterpret_cast<impl::arg_out<T>*>(&object));
memset(&object, 0, sizeof(com_array<T>));
return result;
}
template <typename T>
auto detach_abi(com_array<T>&& object) noexcept
{
return detach_abi(object);
}
}
namespace winrt::impl
{
template <typename T>
struct array_size_proxy
{
array_size_proxy& operator=(array_size_proxy const&) = delete;
array_size_proxy(com_array<T>& value) noexcept : m_value(value)
{}
~array_size_proxy() noexcept
{
WINRT_ASSERT(m_value.data() || (!m_value.data() && m_size == 0));
*reinterpret_cast<uint32_t*>(reinterpret_cast<uintptr_t*>(&m_value) + 1) = m_size;
}
operator uint32_t*() noexcept
{
return &m_size;
}
operator unsigned long*() noexcept
{
return reinterpret_cast<unsigned long*>(&m_size);
}
private:
com_array<T>& m_value;
uint32_t m_size{ 0 };
};
template<typename T>
array_size_proxy<T> put_size_abi(com_array<T>& object) noexcept
{
return array_size_proxy<T>(object);
}
template <typename T>
struct com_array_proxy
{
com_array_proxy(uint32_t* size, winrt::impl::arg_out<T>* value) noexcept : m_size(size), m_value(value)
{}
~com_array_proxy() noexcept
{
std::tie(*m_size, *m_value) = detach_abi(m_temp);
}
operator com_array<T>&() noexcept
{
return m_temp;
}
com_array_proxy(com_array_proxy const&) noexcept
{
// A Visual C++ compiler bug (550631) requires the copy constructor even though it is never called.
WINRT_ASSERT(false);
}
private:
uint32_t* m_size;
arg_out<T>* m_value;
com_array<T> m_temp;
};
}
WINRT_EXPORT namespace winrt
{
template <typename T>
auto detach_abi(uint32_t* __valueSize, impl::arg_out<T>* value) noexcept
{
return impl::com_array_proxy<T>(__valueSize, value);
}
inline hstring get_class_name(Windows::Foundation::IInspectable const& object)
{
void* value{};
check_hresult((*(impl::inspectable_abi**)&object)->GetRuntimeClassName(&value));
return { value, take_ownership_from_abi };
}
inline com_array<guid> get_interfaces(Windows::Foundation::IInspectable const& object)
{
com_array<guid> value;
check_hresult((*(impl::inspectable_abi**)&object)->GetIids(impl::put_size_abi(value), put_abi(value)));
return value;
}
inline Windows::Foundation::TrustLevel get_trust_level(Windows::Foundation::IInspectable const& object)
{
Windows::Foundation::TrustLevel value{};
check_hresult((*(impl::inspectable_abi**)&object)->GetTrustLevel(&value));
return value;
}
}

79
strings/base_chrono.h Normal file
Просмотреть файл

@ -0,0 +1,79 @@
WINRT_EXPORT namespace winrt
{
struct file_time
{
uint64_t value{};
file_time() noexcept = default;
constexpr explicit file_time(uint64_t const value) noexcept : value(value)
{
}
#ifdef _FILETIME_
constexpr file_time(FILETIME const& value) noexcept
: value(value.dwLowDateTime | (static_cast<uint64_t>(value.dwHighDateTime) << 32))
{
}
operator FILETIME() const noexcept
{
return { static_cast<DWORD>(value & 0xFFFFFFFF), static_cast<DWORD>(value >> 32) };
}
#endif
};
struct clock
{
using rep = int64_t;
using period = impl::filetime_period;
using duration = Windows::Foundation::TimeSpan;
using time_point = Windows::Foundation::DateTime;
static constexpr bool is_steady = false;
static time_point now() noexcept
{
file_time ft;
WINRT_GetSystemTimePreciseAsFileTime(&ft);
return from_file_time(ft);
}
static time_t to_time_t(time_point const& time) noexcept
{
return std::chrono::duration_cast<time_t_duration>(time - time_t_epoch).count();
}
static time_point from_time_t(time_t time) noexcept
{
return time_t_epoch + time_t_duration{ time };
}
static file_time to_file_time(time_point const& time) noexcept
{
return file_time{ static_cast<uint64_t>(time.time_since_epoch().count()) };
}
static time_point from_file_time(file_time const& time) noexcept
{
return time_point{ duration{ time.value } };
}
static auto to_FILETIME(time_point const& time) noexcept
{
return to_file_time(time);
}
static time_point from_FILETIME(file_time const& time) noexcept
{
return from_file_time(time);
}
private:
// Define 00:00:00, Jan 1 1970 UTC in FILETIME units.
static constexpr time_point time_t_epoch{ duration{ 0x019DB1DED53E8000 } };
using time_t_duration = std::chrono::duration<time_t>;
};
}

265
strings/base_collections.h Normal file
Просмотреть файл

@ -0,0 +1,265 @@
namespace winrt::impl
{
namespace wfc = Windows::Foundation::Collections;
template <typename T>
struct fast_iterator
{
using iterator_category = std::input_iterator_tag;
using value_type = T;
using difference_type = ptrdiff_t;
using pointer = T * ;
using reference = T & ;
fast_iterator(T const& collection, uint32_t const index) noexcept :
m_collection(&collection),
m_index(index)
{}
fast_iterator& operator++() noexcept
{
++m_index;
return*this;
}
auto operator*() const
{
return m_collection->GetAt(m_index);
}
bool operator==(fast_iterator const& other) const noexcept
{
WINRT_ASSERT(m_collection == other.m_collection);
return m_index == other.m_index;
}
bool operator!=(fast_iterator const& other) const noexcept
{
return !(*this == other);
}
private:
T const* m_collection{};
uint32_t m_index{};
};
template <typename T>
struct rfast_iterator
{
using iterator_category = std::input_iterator_tag;
using value_type = T;
using difference_type = ptrdiff_t;
using pointer = T *;
using reference = T &;
rfast_iterator(T const& collection, int64_t const index) noexcept :
m_collection(&collection),
m_index(index)
{}
rfast_iterator& operator++() noexcept
{
--m_index;
return*this;
}
auto operator*() const
{
return m_collection->GetAt(static_cast<uint32_t>(m_index));
}
bool operator==(rfast_iterator const& other) const noexcept
{
WINRT_ASSERT(m_collection == other.m_collection);
return m_index == other.m_index;
}
bool operator!=(rfast_iterator const& other) const noexcept
{
return !(*this == other);
}
private:
T const* m_collection{};
int64_t m_index{};
};
template <typename T>
class has_GetAt
{
template <typename U, typename = decltype(std::declval<U>().GetAt(0))> static constexpr bool get_value(int) { return true; }
template <typename> static constexpr bool get_value(...) { return false; }
public:
static constexpr bool value = get_value<T>(0);
};
template <typename T, std::enable_if_t<!has_GetAt<T>::value, int> = 0>
auto begin(T const& collection) -> decltype(collection.First())
{
auto result = collection.First();
if (!result.HasCurrent())
{
return {};
}
return result;
}
template <typename T, std::enable_if_t<!has_GetAt<T>::value, int> = 0>
auto end([[maybe_unused]] T const& collection) noexcept -> decltype(collection.First())
{
return {};
}
template <typename T, std::enable_if_t<has_GetAt<T>::value, int> = 0>
fast_iterator<T> begin(T const& collection) noexcept
{
return { collection, 0 };
}
template <typename T, std::enable_if_t<has_GetAt<T>::value, int> = 0>
fast_iterator<T> end(T const& collection)
{
return { collection, collection.Size() };
}
template <typename T, std::enable_if_t<has_GetAt<T>::value, int> = 0>
rfast_iterator<T> rbegin(T const& collection) noexcept
{
return { collection, collection.Size() - 1 };
}
template <typename T, std::enable_if_t<has_GetAt<T>::value, int> = 0>
rfast_iterator<T> rend(T const& collection)
{
return { collection, -1 };
}
template <typename T>
struct key_value_pair;
template <typename K, typename V>
struct key_value_pair<wfc::IKeyValuePair<K, V>> : implements<key_value_pair<wfc::IKeyValuePair<K, V>>, wfc::IKeyValuePair<K, V>>
{
key_value_pair(K key, V value) :
m_key(std::move(key)),
m_value(std::move(value))
{
}
K Key() const
{
return m_key;
}
V Value() const
{
return m_value;
}
private:
K const m_key;
V const m_value;
};
template <typename T>
struct is_key_value_pair : std::false_type {};
template <typename K, typename V>
struct is_key_value_pair<wfc::IKeyValuePair<K, V>> : std::true_type {};
struct input_scope
{
void invalidate_scope() noexcept
{
m_invalid = true;
}
void check_scope() const
{
if (m_invalid)
{
throw hresult_illegal_method_call();
}
}
private:
bool m_invalid{};
};
struct no_collection_version
{
struct iterator_type
{
iterator_type(no_collection_version const&) noexcept
{
}
void check_version(no_collection_version const&) const noexcept
{
}
};
};
struct collection_version
{
struct iterator_type
{
iterator_type(collection_version const& version) noexcept :
m_snapshot(version.get_version())
{
}
void check_version(collection_version const& version) const
{
if (version.get_version() != m_snapshot)
{
throw hresult_changed_state();
}
}
private:
uint32_t const m_snapshot;
};
uint32_t get_version() const noexcept
{
return m_version;
}
void increment_version() noexcept
{
++m_version;
}
private:
std::atomic<uint32_t> m_version{};
};
template <typename T>
struct range_container
{
T const first;
T const last;
auto begin() const noexcept
{
return first;
}
auto end() const noexcept
{
return last;
}
};
}

Просмотреть файл

@ -0,0 +1,494 @@
WINRT_EXPORT namespace winrt
{
template <typename D, typename T, typename Version = impl::no_collection_version>
struct iterable_base : Version
{
template <typename U>
static constexpr auto const& wrap_value(U const& value) noexcept
{
return value;
}
template <typename U>
static constexpr auto const& unwrap_value(U const& value) noexcept
{
return value;
}
auto First()
{
return make<iterator>(static_cast<D*>(this));
}
protected:
template<typename InputIt, typename Size, typename OutputIt>
auto copy_n(InputIt first, Size count, OutputIt result) const
{
if constexpr (std::is_same_v<T, std::decay_t<decltype(*std::declval<D const>().get_container().begin())>> && !impl::is_key_value_pair<T>::value)
{
std::copy_n(first, count, result);
}
else
{
return std::transform(first, std::next(first, count), result, [&](auto&& value)
{
if constexpr (!impl::is_key_value_pair<T>::value)
{
return static_cast<D const&>(*this).unwrap_value(value);
}
else
{
return make<impl::key_value_pair<T>>(static_cast<D const&>(*this).unwrap_value(value.first), static_cast<D const&>(*this).unwrap_value(value.second));
}
});
}
}
private:
struct iterator : Version::iterator_type, implements<iterator, Windows::Foundation::Collections::IIterator<T>>
{
void abi_enter()
{
m_owner->abi_enter();
this->check_version(*m_owner);
}
void abi_exit()
{
m_owner->abi_exit();
}
explicit iterator(D* const owner) noexcept :
Version::iterator_type(*owner),
m_current(owner->get_container().begin()),
m_end(owner->get_container().end())
{
m_owner.copy_from(owner);
}
T Current() const
{
if (m_current == m_end)
{
throw hresult_out_of_bounds();
}
if constexpr (!impl::is_key_value_pair<T>::value)
{
return m_owner->unwrap_value(*m_current);
}
else
{
return make<impl::key_value_pair<T>>(m_owner->unwrap_value(m_current->first), m_owner->unwrap_value(m_current->second));
}
}
bool HasCurrent() const noexcept
{
return m_current != m_end;
}
bool MoveNext() noexcept
{
if (m_current != m_end)
{
++m_current;
}
return HasCurrent();
}
uint32_t GetMany(array_view<T> values)
{
return GetMany(values, typename std::iterator_traits<iterator_type>::iterator_category());
}
private:
uint32_t GetMany(array_view<T> values, std::random_access_iterator_tag)
{
uint32_t const actual = (std::min)(static_cast<uint32_t>(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<T> values, std::input_iterator_tag)
{
auto output = values.begin();
while (output < values.end() && m_current != m_end)
{
*output = Current();
++output;
++m_current;
}
return static_cast<uint32_t>(output - values.begin());
}
using iterator_type = decltype(std::declval<D>().get_container().begin());
com_ptr<D> m_owner;
iterator_type m_current;
iterator_type const m_end;
};
};
template <typename D, typename T, typename Version = impl::no_collection_version>
struct vector_view_base : iterable_base<D, T, Version>
{
T GetAt(uint32_t const index) const
{
if (index >= Size())
{
throw hresult_out_of_bounds();
}
return static_cast<D const&>(*this).unwrap_value(*std::next(static_cast<D const&>(*this).get_container().begin(), index));
}
uint32_t Size() const noexcept
{
return static_cast<uint32_t>(std::distance(static_cast<D const&>(*this).get_container().begin(), static_cast<D const&>(*this).get_container().end()));
}
bool IndexOf(T const& value, uint32_t& index) const noexcept
{
auto first = std::find_if(static_cast<D const&>(*this).get_container().begin(), static_cast<D const&>(*this).get_container().end(), [&](auto&& match)
{
return value == static_cast<D const&>(*this).unwrap_value(match);
});
index = static_cast<uint32_t>(first - static_cast<D const&>(*this).get_container().begin());
return index < Size();
}
uint32_t GetMany(uint32_t const startIndex, array_view<T> values) const
{
if (startIndex >= Size())
{
return 0;
}
uint32_t const actual = (std::min)(Size() - startIndex, values.size());
this->copy_n(static_cast<D const&>(*this).get_container().begin() + startIndex, actual, values.begin());
return actual;
}
};
template <typename D, typename T>
struct vector_base : vector_view_base<D, T, impl::collection_version>
{
Windows::Foundation::Collections::IVectorView<T> GetView() const noexcept
{
return static_cast<D const&>(*this);
}
void SetAt(uint32_t const index, T const& value)
{
if (index >= static_cast<D const&>(*this).get_container().size())
{
throw hresult_out_of_bounds();
}
this->increment_version();
static_cast<D&>(*this).get_container()[index] = static_cast<D const&>(*this).wrap_value(value);
}
void InsertAt(uint32_t const index, T const& value)
{
if (index > static_cast<D const&>(*this).get_container().size())
{
throw hresult_out_of_bounds();
}
this->increment_version();
static_cast<D&>(*this).get_container().insert(static_cast<D const&>(*this).get_container().begin() + index, static_cast<D const&>(*this).wrap_value(value));
}
void RemoveAt(uint32_t const index)
{
if (index >= static_cast<D const&>(*this).get_container().size())
{
throw hresult_out_of_bounds();
}
this->increment_version();
static_cast<D&>(*this).get_container().erase(static_cast<D const&>(*this).get_container().begin() + index);
}
void Append(T const& value)
{
this->increment_version();
static_cast<D&>(*this).get_container().push_back(static_cast<D const&>(*this).wrap_value(value));
}
void RemoveAtEnd()
{
if (static_cast<D const&>(*this).get_container().empty())
{
throw hresult_out_of_bounds();
}
this->increment_version();
static_cast<D&>(*this).get_container().pop_back();
}
void Clear() noexcept
{
this->increment_version();
static_cast<D&>(*this).get_container().clear();
}
void ReplaceAll(array_view<T const> value)
{
this->increment_version();
assign(value.begin(), value.end());
}
private:
template <typename InputIt>
void assign(InputIt first, InputIt last)
{
using container_type = std::remove_reference_t<decltype(static_cast<D&>(*this).get_container())>;
if constexpr (std::is_same_v<T, typename container_type::value_type>)
{
static_cast<D&>(*this).get_container().assign(first, last);
}
else
{
auto& container = static_cast<D&>(*this).get_container();
container.clear();
container.reserve(std::distance(first, last));
std::transform(first, last, std::back_inserter(container), [&](auto&& value)
{
return static_cast<D const&>(*this).wrap_value(value);
});
}
}
};
template <typename D, typename T>
struct observable_vector_base : vector_base<D, T>
{
event_token VectorChanged(Windows::Foundation::Collections::VectorChangedEventHandler<T> const& handler)
{
return m_changed.add(handler);
}
void VectorChanged(event_token const cookie)
{
m_changed.remove(cookie);
}
void SetAt(uint32_t const index, T const& value)
{
vector_base<D, T>::SetAt(index, value);
call_changed(Windows::Foundation::Collections::CollectionChange::ItemChanged, index);
}
void InsertAt(uint32_t const index, T const& value)
{
vector_base<D, T>::InsertAt(index, value);
call_changed(Windows::Foundation::Collections::CollectionChange::ItemInserted, index);
}
void RemoveAt(uint32_t const index)
{
vector_base<D, T>::RemoveAt(index);
call_changed(Windows::Foundation::Collections::CollectionChange::ItemRemoved, index);
}
void Append(T const& value)
{
vector_base<D, T>::Append(value);
call_changed(Windows::Foundation::Collections::CollectionChange::ItemInserted, this->Size() - 1);
}
void RemoveAtEnd()
{
vector_base<D, T>::RemoveAtEnd();
call_changed(Windows::Foundation::Collections::CollectionChange::ItemRemoved, this->Size());
}
void Clear()
{
vector_base<D, T>::Clear();
call_changed(Windows::Foundation::Collections::CollectionChange::Reset, 0);
}
void ReplaceAll(array_view<T const> value)
{
vector_base<D, T>::ReplaceAll(value);
call_changed(Windows::Foundation::Collections::CollectionChange::Reset, 0);
}
protected:
void call_changed(Windows::Foundation::Collections::CollectionChange const change, uint32_t const index)
{
m_changed(static_cast<D const&>(*this), make<args>(change, index));
}
private:
event<Windows::Foundation::Collections::VectorChangedEventHandler<T>> m_changed;
struct args : implements<args, Windows::Foundation::Collections::IVectorChangedEventArgs>
{
args(Windows::Foundation::Collections::CollectionChange const change, uint32_t const index) noexcept :
m_change(change),
m_index(index)
{
}
Windows::Foundation::Collections::CollectionChange CollectionChange() const noexcept
{
return m_change;
}
uint32_t Index() const noexcept
{
return m_index;
}
private:
Windows::Foundation::Collections::CollectionChange const m_change;
uint32_t const m_index;
};
};
template <typename D, typename K, typename V, typename Version = impl::no_collection_version>
struct map_view_base : iterable_base<D, Windows::Foundation::Collections::IKeyValuePair<K, V>, Version>
{
V Lookup(K const& key) const
{
auto pair = static_cast<D const&>(*this).get_container().find(static_cast<D const&>(*this).wrap_value(key));
if (pair == static_cast<D const&>(*this).get_container().end())
{
throw hresult_out_of_bounds();
}
return static_cast<D const&>(*this).unwrap_value(pair->second);
}
uint32_t Size() const noexcept
{
return static_cast<uint32_t>(static_cast<D const&>(*this).get_container().size());
}
bool HasKey(K const& key) const noexcept
{
return static_cast<D const&>(*this).get_container().find(static_cast<D const&>(*this).wrap_value(key)) != static_cast<D const&>(*this).get_container().end();
}
void Split(Windows::Foundation::Collections::IMapView<K, V>& first, Windows::Foundation::Collections::IMapView<K, V>& second) const noexcept
{
first = nullptr;
second = nullptr;
}
};
template <typename D, typename K, typename V>
struct map_base : map_view_base<D, K, V, impl::collection_version>
{
Windows::Foundation::Collections::IMapView<K, V> GetView() const
{
return static_cast<D const&>(*this);
}
bool Insert(K const& key, V const& value)
{
this->increment_version();
auto pair = static_cast<D&>(*this).get_container().insert_or_assign(static_cast<D const&>(*this).wrap_value(key), static_cast<D const&>(*this).wrap_value(value));
return !pair.second;
}
void Remove(K const& key)
{
this->increment_version();
static_cast<D&>(*this).get_container().erase(static_cast<D const&>(*this).wrap_value(key));
}
void Clear() noexcept
{
this->increment_version();
static_cast<D&>(*this).get_container().clear();
}
};
template <typename D, typename K, typename V>
struct observable_map_base : map_base<D, K, V>
{
event_token MapChanged(Windows::Foundation::Collections::MapChangedEventHandler<K, V> const& handler)
{
return m_changed.add(handler);
}
void MapChanged(event_token const cookie)
{
m_changed.remove(cookie);
}
bool Insert(K const& key, V const& value)
{
bool const result = map_base<D, K, V>::Insert(key, value);
call_changed(Windows::Foundation::Collections::CollectionChange::ItemInserted, key);
return result;
}
void Remove(K const& key)
{
map_base<D, K, V>::Remove(key);
call_changed(Windows::Foundation::Collections::CollectionChange::ItemRemoved, key);
}
void Clear() noexcept
{
map_base<D, K, V>::Clear();
call_changed(Windows::Foundation::Collections::CollectionChange::Reset, impl::empty_value<K>());
}
private:
event<Windows::Foundation::Collections::MapChangedEventHandler<K, V>> m_changed;
void call_changed(Windows::Foundation::Collections::CollectionChange const change, K const& key)
{
m_changed(static_cast<D const&>(*this), make<args>(change, key));
}
struct args : implements<args, Windows::Foundation::Collections::IMapChangedEventArgs<K>>
{
args(Windows::Foundation::Collections::CollectionChange const change, K const& key) noexcept :
m_change(change),
m_key(key)
{
}
Windows::Foundation::Collections::CollectionChange CollectionChange() const noexcept
{
return m_change;
}
K Key() const noexcept
{
return m_key;
}
private:
Windows::Foundation::Collections::CollectionChange const m_change;
K const m_key;
};
};
}

Просмотреть файл

@ -0,0 +1,351 @@
namespace winrt::impl
{
template <typename T, typename Container>
struct input_iterable :
implements<input_iterable<T, Container>, non_agile, no_weak_ref, wfc::IIterable<T>>,
iterable_base<input_iterable<T, Container>, T>
{
static_assert(std::is_same_v<Container, std::remove_reference_t<Container>>, "Must be constructed with rvalue.");
explicit input_iterable(Container&& values) : m_values(std::forward<Container>(values))
{
}
auto& get_container() const noexcept
{
return m_values;
}
private:
Container const m_values;
};
template <typename T, typename InputIt>
struct scoped_input_iterable :
input_scope,
implements<scoped_input_iterable<T, InputIt>, non_agile, no_weak_ref, wfc::IIterable<T>>,
iterable_base<scoped_input_iterable<T, InputIt>, T>
{
void abi_enter() const
{
check_scope();
}
scoped_input_iterable(InputIt first, InputIt last) : m_begin(first), m_end(last)
{
}
auto get_container() const noexcept
{
return range_container<InputIt>{ m_begin, m_end };
}
#if defined(_DEBUG) && !defined(WINRT_NO_MAKE_DETECTION)
void use_make_function_to_create_this_object() final
{
}
#endif
private:
InputIt const m_begin;
InputIt const m_end;
};
template <typename T, typename Container>
auto make_input_iterable(Container&& values)
{
return make<input_iterable<T, Container>>(std::forward<Container>(values));
}
template <typename T, typename InputIt>
auto make_scoped_input_iterable(InputIt first, InputIt last)
{
using interface_type = wfc::IIterable<T>;
std::pair<interface_type, input_scope*> result;
auto ptr = new scoped_input_iterable<T, InputIt>(first, last);
*put_abi(result.first) = to_abi<interface_type>(ptr);
result.second = ptr;
return result;
}
}
WINRT_EXPORT namespace winrt::param
{
template <typename T>
struct iterable
{
using value_type = T;
using interface_type = Windows::Foundation::Collections::IIterable<value_type>;
iterable(std::nullptr_t) noexcept
{
}
iterable(iterable const& values) = delete;
iterable& operator=(iterable const& values) = delete;
iterable(interface_type const& values) noexcept : m_owned(false)
{
attach_abi(m_pair.first, winrt::get_abi(values));
}
template <typename Collection, std::enable_if_t<std::is_convertible_v<Collection, interface_type>, int> = 0>
iterable(Collection const& values) noexcept
{
m_pair.first = values;
}
template <typename Allocator>
iterable(std::vector<value_type, Allocator>&& values) : m_pair(impl::make_input_iterable<value_type>(std::move(values)), nullptr)
{
}
template <typename Allocator>
iterable(std::vector<value_type, Allocator> const& values) : m_pair(impl::make_scoped_input_iterable<value_type>(values.begin(), values.end()))
{
}
iterable(std::initializer_list<value_type> values) : m_pair(impl::make_scoped_input_iterable<value_type>(values.begin(), values.end()))
{
}
template <typename U, std::enable_if_t<std::is_convertible_v<U, value_type>, int> = 0>
iterable(std::initializer_list<U> values) : m_pair(impl::make_scoped_input_iterable<value_type>(values.begin(), values.end()))
{
}
template<class InputIt>
iterable(InputIt first, InputIt last) : m_pair(impl::make_scoped_input_iterable<value_type>(first, last))
{
}
~iterable() noexcept
{
if (m_pair.second)
{
m_pair.second->invalidate_scope();
}
if (!m_owned)
{
detach_abi(m_pair.first);
}
}
operator interface_type const& () const noexcept
{
return m_pair.first;
}
private:
std::pair<interface_type, impl::input_scope*> m_pair;
bool m_owned{ true };
};
template <typename K, typename V>
struct iterable<Windows::Foundation::Collections::IKeyValuePair<K, V>>
{
using value_type = Windows::Foundation::Collections::IKeyValuePair<K, V>;
using interface_type = Windows::Foundation::Collections::IIterable<value_type>;
iterable(std::nullptr_t) noexcept
{
}
iterable(iterable const& values) = delete;
iterable& operator=(iterable const& values) = delete;
iterable(interface_type const& values) noexcept : m_owned(false)
{
attach_abi(m_pair.first, winrt::get_abi(values));
}
template <typename Collection, std::enable_if_t<std::is_convertible_v<Collection, interface_type>, int> = 0>
iterable(Collection const& values) noexcept
{
m_pair.first = values;
}
template <typename Compare, typename Allocator>
iterable(std::map<K, V, Compare, Allocator>&& values) : m_pair(impl::make_input_iterable<value_type>(std::move(values)), nullptr)
{
}
template <typename Compare, typename Allocator>
iterable(std::map<K, V, Compare, Allocator> const& values) : m_pair(impl::make_scoped_input_iterable<value_type>(values.begin(), values.end()))
{
}
template <typename Hash, typename KeyEqual, typename Allocator>
iterable(std::unordered_map<K, V, Hash, KeyEqual, Allocator>&& values) : m_pair(impl::make_input_iterable<value_type>(std::move(values)), nullptr)
{
}
template <typename Hash, typename KeyEqual, typename Allocator>
iterable(std::unordered_map<K, V, Hash, KeyEqual, Allocator> const& values) : m_pair(impl::make_scoped_input_iterable<value_type>(values.begin(), values.end()))
{
}
iterable(std::initializer_list<std::pair<K const, V>> values) : m_pair(impl::make_scoped_input_iterable<value_type>(values.begin(), values.end()))
{
}
template<class InputIt>
iterable(InputIt first, InputIt last) : m_pair(impl::make_scoped_input_iterable<value_type>(first, last))
{
}
~iterable() noexcept
{
if (m_pair.second)
{
m_pair.second->invalidate_scope();
}
if (!m_owned)
{
detach_abi(m_pair.first);
}
}
operator interface_type const& () const noexcept
{
return m_pair.first;
}
private:
std::pair<interface_type, impl::input_scope*> m_pair;
bool m_owned{ true };
};
template <typename T>
auto get_abi(iterable<T> const& object) noexcept
{
return *(void**)(&object);
}
template <typename T>
struct async_iterable
{
using value_type = T;
using interface_type = Windows::Foundation::Collections::IIterable<value_type>;
async_iterable(std::nullptr_t) noexcept
{
}
async_iterable(async_iterable const& values) = delete;
async_iterable& operator=(async_iterable const& values) = delete;
async_iterable(interface_type const& values) noexcept : m_owned(false)
{
attach_abi(m_interface, winrt::get_abi(values));
}
template <typename Collection, std::enable_if_t<std::is_convertible_v<Collection, interface_type>, int> = 0>
async_iterable(Collection const& values) noexcept
{
m_interface = values;
}
template <typename Allocator>
async_iterable(std::vector<value_type, Allocator>&& values) :
m_interface(impl::make_input_iterable<value_type>(std::move(values)))
{
}
async_iterable(std::initializer_list<value_type> values) :
m_interface(impl::make_input_iterable<value_type>(std::vector<value_type>(values)))
{
}
~async_iterable() noexcept
{
if (!m_owned)
{
detach_abi(m_interface);
}
}
operator interface_type const& () const noexcept
{
return m_interface;
}
private:
interface_type m_interface;
bool m_owned{ true };
};
template <typename K, typename V>
struct async_iterable<Windows::Foundation::Collections::IKeyValuePair<K, V>>
{
using value_type = Windows::Foundation::Collections::IKeyValuePair<K, V>;
using interface_type = Windows::Foundation::Collections::IIterable<value_type>;
async_iterable(std::nullptr_t) noexcept
{
}
async_iterable(async_iterable const& values) = delete;
async_iterable& operator=(async_iterable const& values) = delete;
async_iterable(interface_type const& values) noexcept : m_owned(false)
{
attach_abi(m_interface, winrt::get_abi(values));
}
template <typename Collection, std::enable_if_t<std::is_convertible_v<Collection, interface_type>, int> = 0>
async_iterable(Collection const& values) noexcept
{
m_interface = values;
}
template <typename Compare, typename Allocator>
async_iterable(std::map<K, V, Compare, Allocator>&& values) :
m_interface(impl::make_input_iterable<value_type>(std::move(values)))
{
}
template <typename Hash, typename KeyEqual, typename Allocator>
async_iterable(std::unordered_map<K, V, Hash, KeyEqual, Allocator>&& values) :
m_interface(impl::make_input_iterable<value_type>(std::move(values)))
{
}
async_iterable(std::initializer_list<std::pair<K const, V>> values) :
m_interface(impl::make_input_iterable<value_type>(std::map<K, V>(values)))
{
}
~async_iterable() noexcept
{
if (!m_owned)
{
detach_abi(m_interface);
}
}
operator interface_type const& () const noexcept
{
return m_interface;
}
private:
interface_type m_interface;
bool m_owned{ true };
};
template <typename T>
auto get_abi(async_iterable<T> const& object) noexcept
{
return *(void**)(&object);
}
}

Просмотреть файл

@ -0,0 +1,104 @@
namespace winrt::impl
{
template <typename K, typename V, typename Container>
struct input_map :
implements<input_map<K, V, Container>, wfc::IMap<K, V>, wfc::IMapView<K, V>, wfc::IIterable<wfc::IKeyValuePair<K, V>>>,
map_base<input_map<K, V, Container>, K, V>
{
static_assert(std::is_same_v<Container, std::remove_reference_t<Container>>, "Must be constructed with rvalue.");
explicit input_map(Container&& values) : m_values(std::forward<Container>(values))
{
}
auto& get_container() noexcept
{
return m_values;
}
auto& get_container() const noexcept
{
return m_values;
}
private:
Container m_values;
};
template <typename K, typename V, typename Container>
auto make_input_map(Container&& values)
{
return make<input_map<K, V, Container>>(std::forward<Container>(values));
}
}
WINRT_EXPORT namespace winrt::param
{
template <typename K, typename V>
struct map
{
using value_type = Windows::Foundation::Collections::IKeyValuePair<K, V>;
using interface_type = Windows::Foundation::Collections::IMap<K, V>;
map(std::nullptr_t) noexcept
{
}
map(map const& values) = delete;
map& operator=(map const& values) = delete;
map(interface_type const& values) noexcept : m_owned(false)
{
attach_abi(m_interface, winrt::get_abi(values));
}
template <typename Collection, std::enable_if_t<std::is_convertible_v<Collection, interface_type>, int> = 0>
map(Collection const& values) noexcept
{
m_interface = values;
}
template <typename Compare, typename Allocator>
map(std::map<K, V, Compare, Allocator>&& values) :
m_interface(impl::make_input_map<K, V>(std::move(values)))
{
}
template <typename Hash, typename KeyEqual, typename Allocator>
map(std::unordered_map<K, V, Hash, KeyEqual, Allocator>&& values) :
m_interface(impl::make_input_map<K, V>(std::move(values)))
{
}
map(std::initializer_list<std::pair<K const, V>> values) :
m_interface(impl::make_input_map<K, V>(std::map<K, V>(values)))
{
}
~map() noexcept
{
if (!m_owned)
{
detach_abi(m_interface);
}
}
operator interface_type const& () const noexcept
{
return m_interface;
}
private:
interface_type m_interface;
bool m_owned{ true };
};
template <typename K, typename V>
auto get_abi(map<K, V> const& object) noexcept
{
return *(void**)(&object);
}
}

Просмотреть файл

@ -0,0 +1,219 @@
namespace winrt::impl
{
template <typename K, typename V, typename Container>
struct input_map_view :
implements<input_map_view<K, V, Container>, non_agile, no_weak_ref, wfc::IMapView<K, V>, wfc::IIterable<wfc::IKeyValuePair<K, V>>>,
map_view_base<input_map_view<K, V, Container>, K, V>
{
static_assert(std::is_same_v<Container, std::remove_reference_t<Container>>, "Must be constructed with rvalue.");
explicit input_map_view(Container&& values) : m_values(std::forward<Container>(values))
{
}
auto& get_container() const noexcept
{
return m_values;
}
private:
Container const m_values;
};
template <typename K, typename V, typename Container>
struct scoped_input_map_view :
input_scope,
implements<scoped_input_map_view<K, V, Container>, non_agile, no_weak_ref, wfc::IMapView<K, V>, wfc::IIterable<wfc::IKeyValuePair<K, V>>>,
map_view_base<scoped_input_map_view<K, V, Container>, K, V>
{
void abi_enter() const
{
check_scope();
}
explicit scoped_input_map_view(Container const& values) : m_values(values)
{
}
auto& get_container() const noexcept
{
return m_values;
}
#if defined(_DEBUG) && !defined(WINRT_NO_MAKE_DETECTION)
void use_make_function_to_create_this_object() final
{
}
#endif
private:
Container const& m_values;
};
template <typename K, typename V, typename Container>
auto make_input_map_view(Container&& values)
{
return make<input_map_view<K, V, Container>>(std::forward<Container>(values));
}
template <typename K, typename V, typename Container>
auto make_scoped_input_map_view(Container const& values)
{
using interface_type = wfc::IMapView<K, V>;
std::pair<interface_type, input_scope*> result;
auto ptr = new scoped_input_map_view<K, V, Container>(values);
*put_abi(result.first) = to_abi<interface_type>(ptr);
result.second = ptr;
return result;
}
}
WINRT_EXPORT namespace winrt::param
{
template <typename K, typename V>
struct map_view
{
using value_type = Windows::Foundation::Collections::IKeyValuePair<K, V>;
using interface_type = Windows::Foundation::Collections::IMapView<K, V>;
map_view(std::nullptr_t) noexcept
{
}
map_view(map_view const& values) = delete;
map_view& operator=(map_view const& values) = delete;
map_view(interface_type const& values) noexcept : m_owned(false)
{
attach_abi(m_pair.first, winrt::get_abi(values));
}
template <typename Collection, std::enable_if_t<std::is_convertible_v<Collection, interface_type>, int> = 0>
map_view(Collection const& values) noexcept
{
m_pair.first = values;
}
template <typename Compare, typename Allocator>
map_view(std::map<K, V, Compare, Allocator>&& values) : m_pair(impl::make_input_map_view<K, V>(std::move(values)), nullptr)
{
}
template <typename Compare, typename Allocator>
map_view(std::map<K, V, Compare, Allocator> const& values) : m_pair(impl::make_scoped_input_map_view<K, V>(values))
{
}
template <typename Hash, typename KeyEqual, typename Allocator>
map_view(std::unordered_map<K, V, Hash, KeyEqual, Allocator>&& values) : m_pair(impl::make_input_map_view<K, V>(std::move(values)), nullptr)
{
}
template <typename Hash, typename KeyEqual, typename Allocator>
map_view(std::unordered_map<K, V, Hash, KeyEqual, Allocator> const& values) : m_pair(impl::make_scoped_input_map_view<K, V>(values))
{
}
map_view(std::initializer_list<std::pair<K const, V>> values) : m_pair(impl::make_input_map_view<K, V>(std::map<K, V>(values)), nullptr)
{
}
~map_view() noexcept
{
if (m_pair.second)
{
m_pair.second->invalidate_scope();
}
if (!m_owned)
{
detach_abi(m_pair.first);
}
}
operator interface_type const& () const noexcept
{
return m_pair.first;
}
private:
std::pair<interface_type, impl::input_scope*> m_pair;
bool m_owned{ true };
};
template <typename K, typename V>
auto get_abi(map_view<K, V> const& object) noexcept
{
return *(void**)(&object);
}
template <typename K, typename V>
struct async_map_view
{
using value_type = Windows::Foundation::Collections::IKeyValuePair<K, V>;
using interface_type = Windows::Foundation::Collections::IMapView<K, V>;
async_map_view(std::nullptr_t) noexcept
{
}
async_map_view(async_map_view const& values) = delete;
async_map_view& operator=(async_map_view const& values) = delete;
async_map_view(interface_type const& values) noexcept : m_owned(false)
{
attach_abi(m_interface, winrt::get_abi(values));
}
template <typename Collection, std::enable_if_t<std::is_convertible_v<Collection, interface_type>, int> = 0>
async_map_view(Collection const& values) noexcept
{
m_interface = values;
}
template <typename Compare, typename Allocator>
async_map_view(std::map<K, V, Compare, Allocator>&& values) :
m_interface(impl::make_input_map_view<K, V>(std::move(values)))
{
}
template <typename Hash, typename KeyEqual, typename Allocator>
async_map_view(std::unordered_map<K, V, Hash, KeyEqual, Allocator>&& values) :
m_interface(impl::make_input_map_view<K, V>(std::move(values)))
{
}
async_map_view(std::initializer_list<std::pair<K const, V>> values) :
m_interface(impl::make_input_map_view<K, V>(std::map<K, V>(values)))
{
}
~async_map_view() noexcept
{
if (!m_owned)
{
detach_abi(m_interface);
}
}
operator interface_type const& () const noexcept
{
return m_interface;
}
private:
interface_type m_interface;
bool m_owned{ true };
};
template <typename K, typename V>
auto get_abi(async_map_view<K, V> const& object) noexcept
{
return *(void**)(&object);
}
}

Просмотреть файл

@ -0,0 +1,92 @@
namespace winrt::impl
{
template <typename T, typename Container>
struct input_vector :
implements<input_vector<T, Container>, wfc::IVector<T>, wfc::IVectorView<T>, wfc::IIterable<T>>,
vector_base<input_vector<T, Container>, T>
{
static_assert(std::is_same_v<Container, std::remove_reference_t<Container>>, "Must be constructed with rvalue.");
explicit input_vector(Container&& values) : m_values(std::forward<Container>(values))
{
}
auto& get_container() noexcept
{
return m_values;
}
auto& get_container() const noexcept
{
return m_values;
}
private:
Container m_values;
};
}
WINRT_EXPORT namespace winrt::param
{
template <typename T>
struct vector
{
using value_type = T;
using interface_type = Windows::Foundation::Collections::IVector<value_type>;
vector(std::nullptr_t) noexcept
{
}
vector(vector const& values) = delete;
vector& operator=(vector const& values) = delete;
vector(interface_type const& values) noexcept : m_owned(false)
{
attach_abi(m_interface, winrt::get_abi(values));
}
template <typename Collection, std::enable_if_t<std::is_convertible_v<Collection, interface_type>, int> = 0>
vector(Collection const& values) noexcept
{
m_interface = values;
}
template <typename Allocator>
vector(std::vector<value_type, Allocator>&& values) :
m_interface(make<impl::input_vector<value_type, std::vector<value_type, Allocator>>>(std::move(values)))
{
}
vector(std::initializer_list<value_type> values) :
m_interface(make<impl::input_vector<value_type, std::vector<value_type>>>(values))
{
}
~vector() noexcept
{
if (!m_owned)
{
detach_abi(m_interface);
}
}
operator interface_type const& () const noexcept
{
return m_interface;
}
private:
interface_type m_interface;
bool m_owned{ true };
};
template <typename T>
auto get_abi(vector<T> const& object) noexcept
{
return *(void**)(&object);
}
}

Просмотреть файл

@ -0,0 +1,208 @@
namespace winrt::impl
{
template <typename T, typename Container>
struct input_vector_view :
implements<input_vector_view<T, Container>, non_agile, no_weak_ref, wfc::IVectorView<T>, wfc::IIterable<T>>,
vector_view_base<input_vector_view<T, Container>, T>
{
static_assert(std::is_same_v<Container, std::remove_reference_t<Container>>, "Must be constructed with rvalue.");
explicit input_vector_view(Container&& values) : m_values(std::forward<Container>(values))
{
}
auto& get_container() const noexcept
{
return m_values;
}
private:
Container const m_values;
};
template <typename T, typename InputIt>
struct scoped_input_vector_view :
input_scope,
implements<scoped_input_vector_view<T, InputIt>, non_agile, no_weak_ref, wfc::IVectorView<T>, wfc::IIterable<T>>,
vector_view_base<scoped_input_vector_view<T, InputIt>, T>
{
void abi_enter() const
{
check_scope();
}
scoped_input_vector_view(InputIt first, InputIt last) : m_begin(first), m_end(last)
{
}
auto get_container() const noexcept
{
return range_container<InputIt>{ m_begin, m_end };
}
#if defined(_DEBUG) && !defined(WINRT_NO_MAKE_DETECTION)
void use_make_function_to_create_this_object() final
{
}
#endif
private:
InputIt const m_begin;
InputIt const m_end;
};
template <typename T, typename InputIt>
auto make_scoped_input_vector_view(InputIt first, InputIt last)
{
using interface_type = wfc::IVectorView<T>;
std::pair<interface_type, input_scope*> result;
auto ptr = new scoped_input_vector_view<T, InputIt>(first, last);
*put_abi(result.first) = to_abi<interface_type>(ptr);
result.second = ptr;
return result;
}
}
WINRT_EXPORT namespace winrt::param
{
template <typename T>
struct vector_view
{
using value_type = T;
using interface_type = Windows::Foundation::Collections::IVectorView<value_type>;
vector_view(std::nullptr_t) noexcept
{
}
vector_view(vector_view const& values) = delete;
vector_view& operator=(vector_view const& values) = delete;
vector_view(interface_type const& values) noexcept : m_owned(false)
{
attach_abi(m_pair.first, winrt::get_abi(values));
}
template <typename Collection, std::enable_if_t<std::is_convertible_v<Collection, interface_type>, int> = 0>
vector_view(Collection const& values) noexcept
{
m_pair.first = values;
}
template <typename Allocator>
vector_view(std::vector<value_type, Allocator>&& values) : m_pair(make<impl::input_vector_view<value_type, std::vector<value_type, Allocator>>>(std::move(values)), nullptr)
{
}
template <typename Allocator>
vector_view(std::vector<value_type, Allocator> const& values) : m_pair(impl::make_scoped_input_vector_view<value_type>(values.begin(), values.end()))
{
}
vector_view(std::initializer_list<value_type> values) : m_pair(impl::make_scoped_input_vector_view<value_type>(values.begin(), values.end()))
{
}
template <typename U, std::enable_if_t<std::is_convertible_v<U, value_type>, int> = 0>
vector_view(std::initializer_list<U> values) : m_pair(impl::make_scoped_input_vector_view<value_type>(values.begin(), values.end()))
{
}
template<class InputIt>
vector_view(InputIt first, InputIt last) : m_pair(impl::make_scoped_input_vector_view<value_type>(first, last))
{
}
~vector_view() noexcept
{
if (m_pair.second)
{
m_pair.second->invalidate_scope();
}
if (!m_owned)
{
detach_abi(m_pair.first);
}
}
operator interface_type const& () const noexcept
{
return m_pair.first;
}
private:
std::pair<interface_type, impl::input_scope*> m_pair;
bool m_owned{ true };
};
template <typename T>
auto get_abi(vector_view<T> const& object) noexcept
{
return *(void**)(&object);
}
template <typename T>
struct async_vector_view
{
using value_type = T;
using interface_type = Windows::Foundation::Collections::IVectorView<value_type>;
async_vector_view(std::nullptr_t) noexcept
{
}
async_vector_view(async_vector_view const& values) = delete;
async_vector_view& operator=(async_vector_view const& values) = delete;
async_vector_view(interface_type const& values) noexcept : m_owned(false)
{
attach_abi(m_interface, winrt::get_abi(values));
}
template <typename Collection, std::enable_if_t<std::is_convertible_v<Collection, interface_type>, int> = 0>
async_vector_view(Collection const& values) noexcept
{
m_interface = values;
}
template <typename Allocator>
async_vector_view(std::vector<value_type, Allocator>&& values) :
m_interface(make<impl::input_vector_view<value_type, std::vector<value_type, Allocator>>>(std::move(values)))
{
}
async_vector_view(std::initializer_list<value_type> values) :
m_interface(make<impl::input_vector_view<value_type, std::vector<value_type>>>(values))
{
}
~async_vector_view() noexcept
{
if (!m_owned)
{
detach_abi(m_interface);
}
}
operator interface_type const& () const noexcept
{
return m_interface;
}
private:
interface_type m_interface;
bool m_owned{ true };
};
template <typename T>
auto get_abi(async_vector_view<T> const& object) noexcept
{
return *(void**)(&object);
}
}

Просмотреть файл

@ -0,0 +1,68 @@
namespace winrt::impl
{
template <typename K, typename V, typename Container>
struct observable_map :
implements<observable_map<K, V, Container>, wfc::IObservableMap<K, V>, wfc::IMap<K, V>, wfc::IMapView<K, V>, wfc::IIterable<wfc::IKeyValuePair<K, V>>>,
observable_map_base<observable_map<K, V, Container>, K, V>
{
static_assert(std::is_same_v<Container, std::remove_reference_t<Container>>, "Must be constructed with rvalue.");
explicit observable_map(Container&& values) : m_values(std::forward<Container>(values))
{
}
auto& get_container() noexcept
{
return m_values;
}
auto& get_container() const noexcept
{
return m_values;
}
private:
Container m_values;
};
}
WINRT_EXPORT namespace winrt
{
template <typename K, typename V, typename Compare = std::less<K>, typename Allocator = std::allocator<std::pair<K const, V>>>
Windows::Foundation::Collections::IMap<K, V> single_threaded_map()
{
return make<impl::input_map<K, V, std::map<K, V, Compare, Allocator>>>(std::map<K, V, Compare, Allocator>{});
}
template <typename K, typename V, typename Compare = std::less<K>, typename Allocator = std::allocator<std::pair<K const, V>>>
Windows::Foundation::Collections::IMap<K, V> single_threaded_map(std::map<K, V, Compare, Allocator>&& values)
{
return make<impl::input_map<K, V, std::map<K, V, Compare, Allocator>>>(std::move(values));
}
template <typename K, typename V, typename Hash = std::hash<K>, typename KeyEqual = std::equal_to<K>, typename Allocator = std::allocator<std::pair<K const, V>>>
Windows::Foundation::Collections::IMap<K, V> single_threaded_map(std::unordered_map<K, V, Hash, KeyEqual, Allocator>&& values)
{
return make<impl::input_map<K, V, std::unordered_map<K, V, Hash, KeyEqual, Allocator>>>(std::move(values));
}
template <typename K, typename V, typename Compare = std::less<K>, typename Allocator = std::allocator<std::pair<K const, V>>>
Windows::Foundation::Collections::IObservableMap<K, V> single_threaded_observable_map()
{
return make<impl::observable_map<K, V, std::map<K, V, Compare, Allocator>>>(std::map<K, V, Compare, Allocator>{});
}
template <typename K, typename V, typename Compare = std::less<K>, typename Allocator = std::allocator<std::pair<K const, V>>>
Windows::Foundation::Collections::IObservableMap<K, V> single_threaded_observable_map(std::map<K, V, Compare, Allocator>&& values)
{
return make<impl::observable_map<K, V, std::map<K, V, Compare, Allocator>>>(std::move(values));
}
template <typename K, typename V, typename Hash = std::hash<K>, typename KeyEqual = std::equal_to<K>, typename Allocator = std::allocator<std::pair<K const, V>>>
Windows::Foundation::Collections::IObservableMap<K, V> single_threaded_observable_map(std::unordered_map<K, V, Hash, KeyEqual, Allocator>&& values)
{
return make<impl::observable_map<K, V, std::unordered_map<K, V, Hash, KeyEqual, Allocator>>>(std::move(values));
}
}

Просмотреть файл

@ -0,0 +1,280 @@
namespace winrt::impl
{
template <typename Container>
struct inspectable_observable_vector :
observable_vector_base<inspectable_observable_vector<Container>, Windows::Foundation::IInspectable>,
implements<inspectable_observable_vector<Container>,
wfc::IObservableVector<Windows::Foundation::IInspectable>, wfc::IVector<Windows::Foundation::IInspectable>, wfc::IVectorView<Windows::Foundation::IInspectable>, wfc::IIterable<Windows::Foundation::IInspectable>>
{
static_assert(std::is_same_v<Container, std::remove_reference_t<Container>>, "Must be constructed with rvalue.");
explicit inspectable_observable_vector(Container&& values) : m_values(std::forward<Container>(values))
{
}
auto& get_container() noexcept
{
return m_values;
}
auto& get_container() const noexcept
{
return m_values;
}
private:
Container m_values;
};
template <typename T, typename Container>
struct convertible_observable_vector :
observable_vector_base<convertible_observable_vector<T, Container>, T>,
implements<convertible_observable_vector<T, Container>,
wfc::IObservableVector<T>, wfc::IVector<T>, wfc::IVectorView<T>, wfc::IIterable<T>,
wfc::IObservableVector<Windows::Foundation::IInspectable>, wfc::IVector<Windows::Foundation::IInspectable>, wfc::IVectorView<Windows::Foundation::IInspectable>, wfc::IIterable<Windows::Foundation::IInspectable>>
{
static_assert(!std::is_same_v<T, Windows::Foundation::IInspectable>);
static_assert(std::is_same_v<Container, std::remove_reference_t<Container>>, "Must be constructed with rvalue.");
using container_type = convertible_observable_vector<T, Container>;
using base_type = observable_vector_base<convertible_observable_vector<T, Container>, T>;
explicit convertible_observable_vector(Container&& values) : m_values(std::forward<Container>(values))
{
}
auto& get_container() noexcept
{
return m_values;
}
auto& get_container() const noexcept
{
return m_values;
}
auto First()
{
struct result
{
container_type* container;
operator wfc::IIterator<T>()
{
return static_cast<base_type*>(container)->First();
}
operator wfc::IIterator<Windows::Foundation::IInspectable>()
{
return make<iterator>(container);
}
};
return result{ this };
}
auto GetAt(uint32_t const index) const
{
struct result
{
base_type const* container;
uint32_t const index;
operator T() const
{
return container->GetAt(index);
}
operator Windows::Foundation::IInspectable() const
{
return box_value(container->GetAt(index));
}
};
return result{ this, index };
}
using base_type::IndexOf;
bool IndexOf(Windows::Foundation::IInspectable const& value, uint32_t& index) const
{
return IndexOf(unbox_value<T>(value), index);
}
using base_type::GetMany;
uint32_t GetMany(uint32_t const startIndex, array_view<Windows::Foundation::IInspectable> values) const
{
if (startIndex >= m_values.size())
{
return 0;
}
uint32_t const actual = (std::min)(static_cast<uint32_t>(m_values.size() - startIndex), values.size());
std::transform(m_values.begin() + startIndex, m_values.begin() + startIndex + actual, values.begin(), [&](auto && value)
{
return box_value(value);
});
return actual;
}
auto GetView() const noexcept
{
struct result
{
container_type const* container;
operator wfc::IVectorView<T>() const
{
return *container;
}
operator wfc::IVectorView<Windows::Foundation::IInspectable>() const
{
return *container;
}
};
return result{ this };
}
using base_type::SetAt;
void SetAt(uint32_t const index, Windows::Foundation::IInspectable const& value)
{
SetAt(index, unbox_value<T>(value));
}
using base_type::InsertAt;
void InsertAt(uint32_t const index, Windows::Foundation::IInspectable const& value)
{
InsertAt(index, unbox_value<T>(value));
}
using base_type::Append;
void Append(Windows::Foundation::IInspectable const& value)
{
Append(unbox_value<T>(value));
}
using base_type::ReplaceAll;
void ReplaceAll(array_view<Windows::Foundation::IInspectable const> values)
{
this->increment_version();
m_values.clear();
m_values.reserve(values.size());
std::transform(values.begin(), values.end(), std::back_inserter(m_values), [&](auto && value)
{
return unbox_value<T>(value);
});
this->call_changed(Windows::Foundation::Collections::CollectionChange::Reset, 0);
}
using base_type::VectorChanged;
event_token VectorChanged(wfc::VectorChangedEventHandler<Windows::Foundation::IInspectable> const& handler)
{
return base_type::VectorChanged([handler](auto && sender, auto && args)
{
handler(sender.template try_as<wfc::IObservableVector<Windows::Foundation::IInspectable>>(), args);
});
}
private:
struct iterator :
impl::collection_version::iterator_type,
implements<iterator, Windows::Foundation::Collections::IIterator<Windows::Foundation::IInspectable>>
{
void abi_enter()
{
check_version(*m_owner);
}
explicit iterator(container_type* const container) noexcept :
impl::collection_version::iterator_type(*container),
m_current(container->get_container().begin()),
m_end(container->get_container().end())
{
m_owner.copy_from(container);
}
Windows::Foundation::IInspectable Current() const
{
if (m_current == m_end)
{
throw hresult_out_of_bounds();
}
return box_value(*m_current);
}
bool HasCurrent() const noexcept
{
return m_current != m_end;
}
bool MoveNext() noexcept
{
if (m_current != m_end)
{
++m_current;
}
return HasCurrent();
}
uint32_t GetMany(array_view<Windows::Foundation::IInspectable> values)
{
uint32_t const actual = (std::min)(static_cast<uint32_t>(std::distance(m_current, m_end)), values.size());
std::transform(m_current, m_current + actual, values.begin(), [&](auto && value)
{
return box_value(value);
});
std::advance(m_current, actual);
return actual;
}
private:
com_ptr<container_type> m_owner;
decltype(m_owner->get_container().begin()) m_current;
decltype(m_owner->get_container().end()) const m_end;
};
Container m_values;
};
}
WINRT_EXPORT namespace winrt
{
template <typename T, typename Allocator = std::allocator<T>>
Windows::Foundation::Collections::IVector<T> single_threaded_vector(std::vector<T, Allocator>&& values = {})
{
return make<impl::input_vector<T, std::vector<T, Allocator>>>(std::move(values));
}
template <typename T, typename Allocator = std::allocator<T>>
Windows::Foundation::Collections::IObservableVector<T> single_threaded_observable_vector(std::vector<T, Allocator>&& values = {})
{
if constexpr (std::is_same_v<T, Windows::Foundation::IInspectable>)
{
return make<impl::inspectable_observable_vector<std::vector<T, Allocator>>>(std::move(values));
}
else
{
return make<impl::convertible_observable_vector<T, std::vector<T, Allocator>>>(std::move(values));
}
}
}

311
strings/base_com_ptr.h Normal file
Просмотреть файл

@ -0,0 +1,311 @@
WINRT_EXPORT namespace winrt
{
template <typename T>
struct com_ptr
{
using type = impl::abi_t<T>;
com_ptr(std::nullptr_t = nullptr) noexcept {}
com_ptr(void* ptr, take_ownership_from_abi_t) noexcept : m_ptr(static_cast<type*>(ptr))
{
}
com_ptr(com_ptr const& other) noexcept : m_ptr(other.m_ptr)
{
add_ref();
}
template <typename U>
com_ptr(com_ptr<U> const& other) noexcept : m_ptr(other.m_ptr)
{
add_ref();
}
template <typename U>
com_ptr(com_ptr<U>&& other) noexcept : m_ptr(std::exchange(other.m_ptr, {}))
{
}
~com_ptr() noexcept
{
release_ref();
}
com_ptr& operator=(com_ptr const& other) noexcept
{
copy_ref(other.m_ptr);
return*this;
}
com_ptr& operator=(com_ptr&& other) noexcept
{
if (this != &other)
{
release_ref();
m_ptr = std::exchange(other.m_ptr, {});
}
return*this;
}
template <typename U>
com_ptr& operator=(com_ptr<U> const& other) noexcept
{
copy_ref(other.m_ptr);
return*this;
}
template <typename U>
com_ptr& operator=(com_ptr<U>&& other) noexcept
{
release_ref();
m_ptr = std::exchange(other.m_ptr, {});
return*this;
}
explicit operator bool() const noexcept
{
return m_ptr != nullptr;
}
auto operator->() const noexcept
{
return m_ptr;
}
T& operator*() const noexcept
{
return *m_ptr;
}
type* get() const noexcept
{
return m_ptr;
}
type** put() noexcept
{
WINRT_ASSERT(m_ptr == nullptr);
return &m_ptr;
}
void** put_void() noexcept
{
return reinterpret_cast<void**>(put());
}
void attach(type* value) noexcept
{
release_ref();
*put() = value;
}
type* detach() noexcept
{
return std::exchange(m_ptr, {});
}
friend void swap(com_ptr& left, com_ptr& right) noexcept
{
std::swap(left.m_ptr, right.m_ptr);
}
template <typename To>
auto as() const
{
return impl::as<To>(m_ptr);
}
template <typename To>
auto try_as() const noexcept
{
return impl::try_as<To>(m_ptr);
}
template <typename To>
void as(To& to) const
{
to = as<impl::wrapped_type_t<To>>();
}
template <typename To>
bool try_as(To& to) const noexcept
{
to = try_as<impl::wrapped_type_t<To>>();
return static_cast<bool>(to);
}
hresult as(guid const& id, void** result) const noexcept
{
return m_ptr->QueryInterface(id, result);
}
void copy_from(type* other) noexcept
{
copy_ref(other);
}
void copy_to(type** other) const noexcept
{
add_ref();
*other = m_ptr;
}
template <typename F, typename...Args>
void capture(F function, Args&&...args)
{
check_hresult(function(args..., guid_of<T>(), put_void()));
}
template <typename O, typename M, typename...Args>
void capture(com_ptr<O> const& object, M method, Args&&...args)
{
check_hresult((object.get()->*(method))(args..., guid_of<T>(), put_void()));
}
private:
void copy_ref(type* other) noexcept
{
if (m_ptr != other)
{
release_ref();
m_ptr = other;
add_ref();
}
}
void add_ref() const noexcept
{
if (m_ptr)
{
const_cast<std::remove_const_t<type>*>(m_ptr)->AddRef();
}
}
void release_ref() noexcept
{
if (m_ptr)
{
unconditional_release_ref();
}
}
__declspec(noinline) void unconditional_release_ref() noexcept
{
std::exchange(m_ptr, {})->Release();
}
template <typename U>
friend struct com_ptr;
type* m_ptr{};
};
template <typename T, typename F, typename...Args>
impl::com_ref<T> capture(F function, Args&& ...args)
{
void* result{};
check_hresult(function(args..., guid_of<T>(), &result));
return { result, take_ownership_from_abi };
}
template <typename T, typename O, typename M, typename...Args>
impl::com_ref<T> capture(com_ptr<O> const& object, M method, Args && ...args)
{
void* result{};
check_hresult((object.get()->*(method))(args..., guid_of<T>(), &result));
return { result, take_ownership_from_abi };
}
template <typename T>
auto get_abi(com_ptr<T> const& object) noexcept
{
return object.get();
}
template <typename T>
auto put_abi(com_ptr<T>& object) noexcept
{
return object.put_void();
}
template <typename T>
void attach_abi(com_ptr<T>& object, impl::abi_t<T>* value) noexcept
{
object.attach(value);
}
template <typename T>
auto detach_abi(com_ptr<T>& object) noexcept
{
return object.detach();
}
template <typename T>
bool operator==(com_ptr<T> const& left, com_ptr<T> const& right) noexcept
{
return get_abi(left) == get_abi(right);
}
template <typename T>
bool operator==(com_ptr<T> const& left, std::nullptr_t) noexcept
{
return get_abi(left) == nullptr;
}
template <typename T>
bool operator==(std::nullptr_t, com_ptr<T> const& right) noexcept
{
return nullptr == get_abi(right);
}
template <typename T>
bool operator!=(com_ptr<T> const& left, com_ptr<T> const& right) noexcept
{
return !(left == right);
}
template <typename T>
bool operator!=(com_ptr<T> const& left, std::nullptr_t) noexcept
{
return !(left == nullptr);
}
template <typename T>
bool operator!=(std::nullptr_t, com_ptr<T> const& right) noexcept
{
return !(nullptr == right);
}
template <typename T>
bool operator<(com_ptr<T> const& left, com_ptr<T> const& right) noexcept
{
return get_abi(left) < get_abi(right);
}
template <typename T>
bool operator>(com_ptr<T> const& left, com_ptr<T> const& right) noexcept
{
return right < left;
}
template <typename T>
bool operator<=(com_ptr<T> const& left, com_ptr<T> const& right) noexcept
{
return !(right < left);
}
template <typename T>
bool operator>=(com_ptr<T> const& left, com_ptr<T> const& right) noexcept
{
return !(left < right);
}
}
template <typename T>
void** IID_PPV_ARGS_Helper(winrt::com_ptr<T>* ptr) noexcept
{
return winrt::put_abi(*ptr);
}

80
strings/base_composable.h Normal file
Просмотреть файл

@ -0,0 +1,80 @@
namespace winrt::impl
{
template <typename D>
struct composable_factory
{
template <typename I, typename... Args>
static I CreateInstance(const Windows::Foundation::IInspectable& outer, Windows::Foundation::IInspectable& inner, Args&&... args)
{
static_assert(std::is_base_of_v<Windows::Foundation::IInspectable, I>, "Requested interface must derive from winrt::Windows::Foundation::IInspectable");
inner = CreateInstanceImpl(outer, std::forward<Args>(args)...);
return inner.as<I>();
}
private:
template <typename... Args>
static Windows::Foundation::IInspectable CreateInstanceImpl(const Windows::Foundation::IInspectable& outer, Args&&... args)
{
// Very specific dance here. The return value must have a ref on the outer, while inner must have a ref count of 1.
// Be sure not to make a delegating QueryInterface call because the controlling outer is not fully constructed yet.
com_ptr<D> instance = make_self<D>(std::forward<Args>(args)...);
instance->m_outer = static_cast<inspectable_abi*>(get_abi(outer));
Windows::Foundation::IInspectable inner;
attach_abi(inner, to_abi<INonDelegatingInspectable>(detach_abi(instance)));
return inner;
}
};
template <typename T, typename D, typename I>
class __declspec(empty_bases) produce_dispatch_to_overridable_base
{
protected:
D& shim() noexcept
{
return static_cast<T&>(*this).instance;
}
I shim_overridable()
{
void* result{};
if (shim().outer())
{
check_hresult(shim().QueryInterface(guid_of<I>(), &result));
}
return { result, take_ownership_from_abi };
}
};
template <typename T, typename D, typename I>
struct produce_dispatch_to_overridable;
template <typename D, typename... I>
class dispatch_to_overridable
{
class wrapper : public produce_dispatch_to_overridable<wrapper, D, I>...
{
D& instance;
template <typename, typename, typename>
friend class produce_dispatch_to_overridable_base;
template <typename, typename...>
friend class dispatch_to_overridable;
explicit wrapper(D& d) : instance(d) {}
public:
wrapper(const wrapper&) = delete;
wrapper(wrapper&&) = default;
};
public:
static wrapper overridable(D& instance) noexcept
{
return wrapper{ instance };
}
};
}

125
strings/base_coroutine.h Normal file
Просмотреть файл

@ -0,0 +1,125 @@
#ifndef __clang__
#include <experimental/coroutine>
#else
namespace std::experimental
{
template <typename R, typename...> struct coroutine_traits
{
using promise_type = typename R::promise_type;
};
template <typename Promise = void> struct coroutine_handle;
template <> struct coroutine_handle<void>
{
coroutine_handle(decltype(nullptr)) noexcept
{
}
coroutine_handle() noexcept
{
}
static coroutine_handle from_address(void* address) noexcept
{
coroutine_handle result;
result.ptr = address;
return result;
}
coroutine_handle& operator=(decltype(nullptr)) noexcept
{
ptr = nullptr;
return *this;
}
explicit operator bool() const noexcept
{
return ptr;
}
void* address() const noexcept
{
return ptr;
}
void operator()() const
{
resume();
}
void resume() const
{
__builtin_coro_resume(ptr);
}
void destroy() const
{
__builtin_coro_destroy(ptr);
}
bool done() const
{
return __builtin_coro_done(ptr);
}
protected:
void* ptr{};
};
template <typename Promise> struct coroutine_handle : coroutine_handle<>
{
using coroutine_handle<>::operator=;
static coroutine_handle from_address(void* address) noexcept
{
coroutine_handle result;
result.ptr = address;
return result;
}
Promise& promise() const
{
return *reinterpret_cast<Promise*>(__builtin_coro_promise(ptr, alignof(Promise), false));
}
static coroutine_handle from_promise(Promise& promise)
{
coroutine_handle result;
result.ptr = __builtin_coro_promise(&promise, alignof(Promise), true);
return result;
}
};
template <typename Promise>
bool operator==(coroutine_handle<Promise> const& left, coroutine_handle<Promise> const& right) noexcept
{
return left.address() == right.address();
}
template <typename Promise>
bool operator!=(coroutine_handle<Promise> const& left, coroutine_handle<Promise> const& right) noexcept
{
return !(left == right);
}
struct suspend_always
{
bool await_ready() noexcept { return false; }
void await_suspend(coroutine_handle<>) noexcept {}
void await_resume() noexcept {}
};
struct suspend_never
{
bool await_ready() noexcept { return true; }
void await_suspend(coroutine_handle<>) noexcept {}
void await_resume() noexcept {}
};
}
#endif

Просмотреть файл

@ -0,0 +1,692 @@
namespace winrt::impl
{
template <typename Async>
struct async_completed_handler;
template <typename Async>
using async_completed_handler_t = typename async_completed_handler<Async>::type;
template <>
struct async_completed_handler<Windows::Foundation::IAsyncAction>
{
using type = Windows::Foundation::AsyncActionCompletedHandler;
};
template <typename TProgress>
struct async_completed_handler<Windows::Foundation::IAsyncActionWithProgress<TProgress>>
{
using type = Windows::Foundation::AsyncActionWithProgressCompletedHandler<TProgress>;
};
template <typename TResult>
struct async_completed_handler<Windows::Foundation::IAsyncOperation<TResult>>
{
using type = Windows::Foundation::AsyncOperationCompletedHandler<TResult>;
};
template <typename TResult, typename TProgress>
struct async_completed_handler<Windows::Foundation::IAsyncOperationWithProgress<TResult, TProgress>>
{
using type = Windows::Foundation::AsyncOperationWithProgressCompletedHandler<TResult, TProgress>;
};
inline void check_sta_blocking_wait() noexcept
{
// Note: A blocking wait on the UI thread for an asynchronous operation can cause a deadlock.
// See https://docs.microsoft.com/windows/uwp/cpp-and-winrt-apis/concurrency#block-the-calling-thread
WINRT_ASSERT(!is_sta());
}
template <typename Async>
void wait_for_completed(Async const& async, uint32_t const timeout)
{
void* event = check_pointer(WINRT_CreateEventW(nullptr, true, false, nullptr));
// The delegate is a local to ensure that the event outlives the call to WaitForSingleObject.
async_completed_handler_t<Async> delegate = [event = handle(event)](auto && ...)
{
WINRT_VERIFY(WINRT_SetEvent(event.get()));
};
async.Completed(delegate);
WINRT_WaitForSingleObject(event, timeout);
}
template <typename Async>
auto wait_for(Async const& async, Windows::Foundation::TimeSpan const& timeout)
{
check_sta_blocking_wait();
auto const milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count();
WINRT_ASSERT((milliseconds >= 0) && (static_cast<uint64_t>(milliseconds) < 0xFFFFFFFFull)); // Within uint32_t range and not INFINITE
wait_for_completed(async, static_cast<uint32_t>(milliseconds));
return async.Status();
}
template <typename Async>
auto wait_get(Async const& async)
{
check_sta_blocking_wait();
if (async.Status() == Windows::Foundation::AsyncStatus::Started)
{
wait_for_completed(async, 0xFFFFFFFF); // INFINITE
}
return async.GetResults();
}
template <typename Async>
struct await_adapter
{
Async const& async;
bool await_ready() const noexcept
{
return false;
}
void await_suspend(std::experimental::coroutine_handle<> handle) const
{
async.Completed([handle, context = impl::sta_apartment_context()](auto&& ...)
{
impl::resume_apartment(context, handle);
});
}
auto await_resume() const
{
return async.GetResults();
}
};
template <typename D>
auto consume_Windows_Foundation_IAsyncAction<D>::get() const
{
impl::wait_get(static_cast<Windows::Foundation::IAsyncAction const&>(static_cast<D const&>(*this)));
}
template <typename D>
auto consume_Windows_Foundation_IAsyncAction<D>::wait_for(Windows::Foundation::TimeSpan const& timeout) const
{
return impl::wait_for(static_cast<Windows::Foundation::IAsyncAction const&>(static_cast<D const&>(*this)), timeout);
}
template <typename D, typename TResult>
auto consume_Windows_Foundation_IAsyncOperation<D, TResult>::get() const
{
return impl::wait_get(static_cast<Windows::Foundation::IAsyncOperation<TResult> const&>(static_cast<D const&>(*this)));
}
template <typename D, typename TResult>
auto consume_Windows_Foundation_IAsyncOperation<D, TResult>::wait_for(Windows::Foundation::TimeSpan const& timeout) const
{
return impl::wait_for(static_cast<Windows::Foundation::IAsyncOperation<TResult> const&>(static_cast<D const&>(*this)), timeout);
}
template <typename D, typename TProgress>
auto consume_Windows_Foundation_IAsyncActionWithProgress<D, TProgress>::get() const
{
impl::wait_get(static_cast<Windows::Foundation::IAsyncActionWithProgress<TProgress> const&>(static_cast<D const&>(*this)));
}
template <typename D, typename TProgress>
auto consume_Windows_Foundation_IAsyncActionWithProgress<D, TProgress>::wait_for(Windows::Foundation::TimeSpan const& timeout) const
{
return impl::wait_for(static_cast<Windows::Foundation::IAsyncActionWithProgress<TProgress> const&>(static_cast<D const&>(*this)), timeout);
}
template <typename D, typename TResult, typename TProgress>
auto consume_Windows_Foundation_IAsyncOperationWithProgress<D, TResult, TProgress>::get() const
{
return impl::wait_get(static_cast<Windows::Foundation::IAsyncOperationWithProgress<TResult, TProgress> const&>(static_cast<D const&>(*this)));
}
template <typename D, typename TResult, typename TProgress>
auto consume_Windows_Foundation_IAsyncOperationWithProgress<D, TResult, TProgress>::wait_for(Windows::Foundation::TimeSpan const& timeout) const
{
return impl::wait_for(static_cast<Windows::Foundation::IAsyncOperationWithProgress<TResult, TProgress> const&>(static_cast<D const&>(*this)), timeout);
}
}
#ifdef __cpp_coroutines
WINRT_EXPORT namespace winrt::Windows::Foundation
{
inline impl::await_adapter<IAsyncAction> operator co_await(IAsyncAction const& async)
{
return{ async };
}
template <typename TProgress>
impl::await_adapter<IAsyncActionWithProgress<TProgress>> operator co_await(IAsyncActionWithProgress<TProgress> const& async)
{
return{ async };
}
template <typename TResult>
impl::await_adapter<IAsyncOperation<TResult>> operator co_await(IAsyncOperation<TResult> const& async)
{
return{ async };
}
template <typename TResult, typename TProgress>
impl::await_adapter<IAsyncOperationWithProgress<TResult, TProgress>> operator co_await(IAsyncOperationWithProgress<TResult, TProgress> const& async)
{
return{ async };
}
}
#endif
WINRT_EXPORT namespace winrt
{
struct get_progress_token_t {};
inline get_progress_token_t get_progress_token() noexcept
{
return{};
}
struct get_cancellation_token_t {};
inline get_cancellation_token_t get_cancellation_token() noexcept
{
return{};
}
}
namespace winrt::impl
{
template <typename Promise>
struct cancellation_token
{
cancellation_token(Promise* promise) noexcept : m_promise(promise)
{
}
bool await_ready() const noexcept
{
return true;
}
void await_suspend(std::experimental::coroutine_handle<>) const noexcept
{
}
cancellation_token<Promise> await_resume() const noexcept
{
return *this;
}
bool operator()() const noexcept
{
return m_promise->Status() == Windows::Foundation::AsyncStatus::Canceled;
}
void callback(winrt::delegate<>&& cancel) noexcept
{
m_promise->cancellation_callback(std::move(cancel));
}
private:
Promise* m_promise;
};
template <typename Promise, typename Progress>
struct progress_token
{
progress_token(Promise* promise) noexcept :
m_promise(promise)
{
}
bool await_ready() const noexcept
{
return true;
}
void await_suspend(std::experimental::coroutine_handle<>) const noexcept
{
}
progress_token<Promise, Progress> await_resume() const noexcept
{
return *this;
}
void operator()(Progress const& result)
{
m_promise->set_progress(result);
}
private:
Promise* m_promise;
};
template <typename Derived, typename AsyncInterface, typename TProgress = void>
struct promise_base : implements<Derived, AsyncInterface, Windows::Foundation::IAsyncInfo>
{
using AsyncStatus = Windows::Foundation::AsyncStatus;
unsigned long __stdcall Release() noexcept
{
uint32_t const remaining = this->subtract_reference();
if (remaining == 0)
{
std::atomic_thread_fence(std::memory_order_acquire);
std::experimental::coroutine_handle<Derived>::from_promise(*static_cast<Derived*>(this)).destroy();
}
return remaining;
}
void Completed(async_completed_handler_t<AsyncInterface> const& handler)
{
AsyncStatus status;
{
slim_lock_guard const guard(m_lock);
if (m_completed_assigned)
{
throw hresult_illegal_delegate_assignment();
}
m_completed_assigned = true;
if (m_status == AsyncStatus::Started)
{
m_completed = make_agile_delegate(handler);
return;
}
status = m_status;
}
if (handler)
{
invoke(handler, *this, status);
}
}
auto Completed() noexcept
{
slim_lock_guard const guard(m_lock);
return m_completed;
}
uint32_t Id() const noexcept
{
return 1;
}
AsyncStatus Status() noexcept
{
slim_lock_guard const guard(m_lock);
return m_status;
}
hresult ErrorCode() noexcept
{
try
{
slim_lock_guard const guard(m_lock);
rethrow_if_failed();
return 0;
}
catch (...)
{
return to_hresult();
}
}
void Cancel() noexcept
{
winrt::delegate<> cancel;
{
slim_lock_guard const guard(m_lock);
if (m_status == AsyncStatus::Started)
{
m_status = AsyncStatus::Canceled;
m_exception = std::make_exception_ptr(hresult_canceled());
cancel = std::move(m_cancel);
}
}
if (cancel)
{
cancel();
}
}
void Close() const noexcept
{
}
auto GetResults()
{
slim_lock_guard const guard(m_lock);
if (m_status == AsyncStatus::Completed)
{
return static_cast<Derived*>(this)->get_return_value();
}
rethrow_if_failed();
WINRT_ASSERT(m_status == AsyncStatus::Started);
throw hresult_illegal_method_call();
}
AsyncInterface get_return_object() const noexcept
{
return *this;
}
void get_return_value() const noexcept
{
}
void set_completed() noexcept
{
async_completed_handler_t<AsyncInterface> handler;
AsyncStatus status;
{
slim_lock_guard const guard(m_lock);
if (m_status == AsyncStatus::Started)
{
m_status = AsyncStatus::Completed;
}
handler = std::move(this->m_completed);
status = this->m_status;
}
if (handler)
{
invoke(handler, *this, status);
}
}
std::experimental::suspend_never initial_suspend() const noexcept
{
return{};
}
struct final_suspend_awaiter
{
promise_base* promise;
bool await_ready() const noexcept
{
return false;
}
void await_resume() const noexcept
{
}
bool await_suspend(std::experimental::coroutine_handle<>) const noexcept
{
promise->set_completed();
uint32_t const remaining = promise->subtract_reference();
if (remaining == 0)
{
std::atomic_thread_fence(std::memory_order_acquire);
}
return remaining > 0;
}
};
auto final_suspend() noexcept
{
return final_suspend_awaiter{ this };
}
void unhandled_exception() noexcept
{
slim_lock_guard const guard(m_lock);
WINRT_ASSERT(m_status == AsyncStatus::Started || m_status == AsyncStatus::Canceled);
m_exception = std::current_exception();
try
{
std::rethrow_exception(m_exception);
}
catch (hresult_canceled const&)
{
m_status = AsyncStatus::Canceled;
}
catch (...)
{
m_status = AsyncStatus::Error;
}
}
template <typename Expression>
Expression&& await_transform(Expression&& expression)
{
if (Status() == AsyncStatus::Canceled)
{
throw winrt::hresult_canceled();
}
return std::forward<Expression>(expression);
}
cancellation_token<Derived> await_transform(get_cancellation_token_t) noexcept
{
return{ static_cast<Derived*>(this) };
}
progress_token<Derived, TProgress> await_transform(get_progress_token_t) noexcept
{
return{ static_cast<Derived*>(this) };
}
void cancellation_callback(winrt::delegate<>&& cancel) noexcept
{
{
slim_lock_guard const guard(m_lock);
if (m_status != AsyncStatus::Canceled)
{
m_cancel = std::move(cancel);
return;
}
}
cancel();
}
#if defined(_DEBUG) && !defined(WINRT_NO_MAKE_DETECTION)
void use_make_function_to_create_this_object() final
{
}
#endif
protected:
void rethrow_if_failed() const
{
if (m_status == AsyncStatus::Error || m_status == AsyncStatus::Canceled)
{
std::rethrow_exception(m_exception);
}
}
std::exception_ptr m_exception{};
slim_mutex m_lock;
async_completed_handler_t<AsyncInterface> m_completed;
winrt::delegate<> m_cancel;
AsyncStatus m_status{ AsyncStatus::Started };
bool m_completed_assigned{ false };
};
}
namespace std::experimental
{
template <typename... Args>
struct coroutine_traits<winrt::Windows::Foundation::IAsyncAction, Args...>
{
struct promise_type final : winrt::impl::promise_base<promise_type, winrt::Windows::Foundation::IAsyncAction>
{
void return_void() const noexcept
{
}
};
};
template <typename TProgress, typename... Args>
struct coroutine_traits<winrt::Windows::Foundation::IAsyncActionWithProgress<TProgress>, Args...>
{
struct promise_type final : winrt::impl::promise_base<promise_type, winrt::Windows::Foundation::IAsyncActionWithProgress<TProgress>, TProgress>
{
using ProgressHandler = winrt::Windows::Foundation::AsyncActionProgressHandler<TProgress>;
void Progress(ProgressHandler const& handler) noexcept
{
winrt::slim_lock_guard const guard(this->m_lock);
m_progress = winrt::impl::make_agile_delegate(handler);
}
ProgressHandler Progress() noexcept
{
winrt::slim_lock_guard const guard(this->m_lock);
return m_progress;
}
void return_void() const noexcept
{
}
void set_progress(TProgress const& result)
{
if (auto handler = Progress())
{
winrt::impl::invoke(handler, *this, result);
}
}
ProgressHandler m_progress;
};
};
template <typename TResult, typename... Args>
struct coroutine_traits<winrt::Windows::Foundation::IAsyncOperation<TResult>, Args...>
{
struct promise_type final : winrt::impl::promise_base<promise_type, winrt::Windows::Foundation::IAsyncOperation<TResult>>
{
TResult get_return_value() noexcept
{
return std::move(m_result);
}
void return_value(TResult&& value) noexcept
{
m_result = std::move(value);
}
void return_value(TResult const& value) noexcept
{
m_result = value;
}
TResult m_result{ winrt::impl::empty_value<TResult>() };
};
};
template <typename TResult, typename TProgress, typename... Args>
struct coroutine_traits<winrt::Windows::Foundation::IAsyncOperationWithProgress<TResult, TProgress>, Args...>
{
struct promise_type final : winrt::impl::promise_base<promise_type,
winrt::Windows::Foundation::IAsyncOperationWithProgress<TResult, TProgress>, TProgress>
{
using ProgressHandler = winrt::Windows::Foundation::AsyncOperationProgressHandler<TResult, TProgress>;
void Progress(ProgressHandler const& handler) noexcept
{
winrt::slim_lock_guard const guard(this->m_lock);
m_progress = winrt::impl::make_agile_delegate(handler);
}
ProgressHandler Progress() noexcept
{
winrt::slim_lock_guard const guard(this->m_lock);
return m_progress;
}
TResult get_return_value() noexcept
{
return std::move(m_result);
}
void return_value(TResult&& value) noexcept
{
m_result = std::move(value);
}
void return_value(TResult const& value) noexcept
{
m_result = value;
}
void set_progress(TProgress const& result)
{
if (auto handler = Progress())
{
winrt::impl::invoke(handler, *this, result);
}
}
TResult m_result{ winrt::impl::empty_value<TResult>() };
ProgressHandler m_progress;
};
};
}
WINRT_EXPORT namespace winrt
{
template <typename... T>
Windows::Foundation::IAsyncAction when_all(T... async)
{
(co_await async, ...);
}
template <typename T, typename... Rest>
T when_any(T const& first, Rest const& ... rest)
{
static_assert(impl::has_category_v<T>, "T must be WinRT async type such as IAsyncAction or IAsyncOperation.");
static_assert((std::is_same_v<T, Rest> && ...), "All when_any parameters must be the same type.");
struct shared_type
{
handle event{ check_pointer(WINRT_CreateEventW(nullptr, true, false, nullptr)) };
T result;
};
auto shared = std::make_shared<shared_type>();
auto completed = [&](T const& async)
{
async.Completed([shared](T const& sender, Windows::Foundation::AsyncStatus) noexcept
{
auto sender_abi = *(impl::unknown_abi**)&sender;
if (nullptr == _InterlockedCompareExchangePointer(reinterpret_cast<void**>(&shared->result), sender_abi, nullptr))
{
sender_abi->AddRef();
WINRT_VERIFY(WINRT_SetEvent(shared->event.get()));
}
});
};
completed(first);
(completed(rest), ...);
co_await resume_on_signal(shared->event.get());
co_return shared->result.GetResults();
}
}

Просмотреть файл

@ -0,0 +1,52 @@
WINRT_EXPORT namespace winrt
{
[[nodiscard]] inline auto resume_foreground(
Windows::System::DispatcherQueue const& dispatcher,
Windows::System::DispatcherQueuePriority const priority = Windows::System::DispatcherQueuePriority::Normal) noexcept
{
struct awaitable
{
awaitable(Windows::System::DispatcherQueue const& dispatcher, Windows::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(std::experimental::coroutine_handle<> handle)
{
m_queued = m_dispatcher.TryEnqueue(m_priority, [handle]
{
handle();
});
return m_queued;
}
private:
Windows::System::DispatcherQueue const& m_dispatcher;
Windows::System::DispatcherQueuePriority const m_priority;
bool m_queued{};
};
return awaitable{ dispatcher, priority };
};
#ifdef __cpp_coroutines
inline auto operator co_await(Windows::System::DispatcherQueue const& dispatcher)
{
return resume_foreground(dispatcher);
}
#endif
}

Просмотреть файл

@ -0,0 +1,383 @@
namespace winrt::impl
{
inline auto resume_background(std::experimental::coroutine_handle<> handle)
{
auto callback = [](void*, void* context) noexcept
{
std::experimental::coroutine_handle<>::from_address(context)();
};
if (!WINRT_TrySubmitThreadpoolCallback(callback, handle.address(), nullptr))
{
throw_last_error();
}
}
inline bool is_sta() noexcept
{
int32_t aptType;
int32_t aptTypeQualifier;
return (0 == WINRT_CoGetApartmentType(&aptType, &aptTypeQualifier)) && ((aptType == 0 /*APTTYPE_STA*/) || (aptType == 3 /*APTTYPE_MAINSTA*/));
}
inline auto sta_apartment_context()
{
return is_sta() ? capture<IContextCallback>(WINRT_CoGetObjectContext) : nullptr;
}
inline auto resume_apartment(com_ptr<IContextCallback> const& sta_context, std::experimental::coroutine_handle<> handle)
{
if (sta_context)
{
com_callback_args args{};
args.data = handle.address();
auto callback = [](com_callback_args* args) noexcept -> int32_t
{
std::experimental::coroutine_handle<>::from_address(args->data)();
return 0;
};
check_hresult(sta_context->ContextCallback(callback, &args, guid_of<ICallbackWithNoReentrancyToApplicationSTA>(), 5, nullptr));
}
else
{
if (is_sta())
{
resume_background(handle);
}
else
{
handle();
}
}
}
}
WINRT_EXPORT namespace winrt
{
[[nodiscard]] inline auto resume_background() noexcept
{
struct awaitable
{
bool await_ready() const noexcept
{
return false;
}
void await_resume() const noexcept
{
}
void await_suspend(std::experimental::coroutine_handle<> handle) const
{
impl::resume_background(handle);
}
};
return awaitable{};
}
template <typename T>
[[nodiscard]] auto resume_background(T const& context) noexcept
{
struct awaitable
{
awaitable(T const& context) : m_context(context)
{
}
bool await_ready() const noexcept
{
return false;
}
void await_resume() const noexcept
{
}
void await_suspend(std::experimental::coroutine_handle<> resume)
{
m_resume = resume;
if (!WINRT_TrySubmitThreadpoolCallback(callback, this, nullptr))
{
throw_last_error();
}
}
private:
static void __stdcall callback(void*, void* context) noexcept
{
auto that = static_cast<awaitable*>(context);
auto guard = that->m_context();
that->m_resume();
}
T const& m_context;
std::experimental::coroutine_handle<> m_resume{ nullptr };
};
return awaitable{ context };
}
struct apartment_context
{
bool await_ready() const noexcept
{
return false;
}
void await_resume() const noexcept
{
}
void await_suspend(std::experimental::coroutine_handle<> handle) const
{
impl::resume_apartment(sta_context, handle);
}
com_ptr<impl::IContextCallback> sta_context = impl::sta_apartment_context();
};
[[nodiscard]] inline auto resume_after(Windows::Foundation::TimeSpan duration) noexcept
{
struct awaitable
{
explicit awaitable(Windows::Foundation::TimeSpan duration) noexcept :
m_duration(duration)
{
}
bool await_ready() const noexcept
{
return m_duration.count() <= 0;
}
void await_suspend(std::experimental::coroutine_handle<> handle)
{
m_timer.attach(check_pointer(WINRT_CreateThreadpoolTimer(callback, handle.address(), nullptr)));
int64_t relative_count = -m_duration.count();
WINRT_SetThreadpoolTimer(m_timer.get(), &relative_count, 0, 0);
}
void await_resume() const noexcept
{
}
private:
static void __stdcall callback(void*, void* context, void*) noexcept
{
std::experimental::coroutine_handle<>::from_address(context)();
}
struct timer_traits
{
using type = impl::ptp_timer;
static void close(type value) noexcept
{
WINRT_CloseThreadpoolTimer(value);
}
static constexpr type invalid() noexcept
{
return nullptr;
}
};
handle_type<timer_traits> m_timer;
Windows::Foundation::TimeSpan m_duration;
};
return awaitable{ duration };
}
#ifdef __cpp_coroutines
inline auto operator co_await(Windows::Foundation::TimeSpan duration)
{
return resume_after(duration);
}
#endif
[[nodiscard]] inline auto resume_on_signal(void* handle, Windows::Foundation::TimeSpan timeout = {}) noexcept
{
struct awaitable
{
awaitable(void* handle, Windows::Foundation::TimeSpan timeout) noexcept :
m_timeout(timeout),
m_handle(handle)
{}
bool await_ready() const noexcept
{
return WINRT_WaitForSingleObject(m_handle, 0) == 0;
}
void await_suspend(std::experimental::coroutine_handle<> resume)
{
m_resume = resume;
m_wait.attach(check_pointer(WINRT_CreateThreadpoolWait(callback, this, nullptr)));
int64_t relative_count = -m_timeout.count();
int64_t* file_time = relative_count != 0 ? &relative_count : nullptr;
WINRT_SetThreadpoolWait(m_wait.get(), m_handle, file_time);
}
bool await_resume() const noexcept
{
return m_result == 0;
}
private:
static void __stdcall callback(void*, void* context, void*, uint32_t result) noexcept
{
auto that = static_cast<awaitable*>(context);
that->m_result = result;
that->m_resume();
}
struct wait_traits
{
using type = impl::ptp_wait;
static void close(type value) noexcept
{
WINRT_CloseThreadpoolWait(value);
}
static constexpr type invalid() noexcept
{
return nullptr;
}
};
handle_type<wait_traits> m_wait;
Windows::Foundation::TimeSpan m_timeout;
void* m_handle;
uint32_t m_result{};
std::experimental::coroutine_handle<> m_resume{ nullptr };
};
return awaitable{ handle, timeout };
}
struct thread_pool
{
thread_pool() :
m_pool(check_pointer(WINRT_CreateThreadpool(nullptr)))
{
m_environment.Pool = m_pool.get();
}
void thread_limits(uint32_t const high, uint32_t const low)
{
WINRT_SetThreadpoolThreadMaximum(m_pool.get(), high);
check_bool(WINRT_SetThreadpoolThreadMinimum(m_pool.get(), low));
}
bool await_ready() const noexcept
{
return false;
}
void await_resume() const noexcept
{
}
void await_suspend(std::experimental::coroutine_handle<> handle)
{
if (!WINRT_TrySubmitThreadpoolCallback(callback, handle.address(), &m_environment))
{
throw_last_error();
}
}
private:
static void __stdcall callback(void*, void* context) noexcept
{
std::experimental::coroutine_handle<>::from_address(context)();
}
struct pool_traits
{
using type = impl::ptp_pool;
static void close(type value) noexcept
{
WINRT_CloseThreadpool(value);
}
static constexpr type invalid() noexcept
{
return nullptr;
}
};
struct environment // TP_CALLBACK_ENVIRON
{
uint32_t Version{ 3 };
void* Pool{};
void* CleanupGroup{};
void* CleanupGroupCancelCallback{};
void* RaceDll{};
void* ActivationContext{};
void* FinalizationCallback{};
union
{
uint32_t Flags{};
struct
{
uint32_t LongFunction : 1;
uint32_t Persistent : 1;
uint32_t Private : 30;
} s;
} u;
int32_t CallbackPriority{ 1 };
uint32_t Size{ sizeof(environment) };
};
handle_type<pool_traits> m_pool;
environment m_environment;
};
struct fire_and_forget {};
}
namespace std::experimental
{
template <typename... Args>
struct coroutine_traits<winrt::fire_and_forget, Args...>
{
struct promise_type
{
winrt::fire_and_forget get_return_object() const noexcept
{
return{};
}
void return_void() const noexcept
{
}
suspend_never initial_suspend() const noexcept
{
return{};
}
suspend_never final_suspend() const noexcept
{
return{};
}
void unhandled_exception() const noexcept
{
winrt::terminate();
}
};
};
}

Просмотреть файл

@ -0,0 +1,48 @@
WINRT_EXPORT namespace winrt
{
[[nodiscard]] inline auto resume_foreground(
Windows::UI::Core::CoreDispatcher const& dispatcher,
Windows::UI::Core::CoreDispatcherPriority const priority = Windows::UI::Core::CoreDispatcherPriority::Normal) noexcept
{
struct awaitable
{
awaitable(Windows::UI::Core::CoreDispatcher const& dispatcher, Windows::UI::Core::CoreDispatcherPriority const priority) noexcept :
m_dispatcher(dispatcher),
m_priority(priority)
{
}
bool await_ready() const noexcept
{
return false;
}
void await_resume() const noexcept
{
}
void await_suspend(std::experimental::coroutine_handle<> handle) const
{
m_dispatcher.RunAsync(m_priority, [handle]
{
handle();
});
}
private:
Windows::UI::Core::CoreDispatcher const& m_dispatcher;
Windows::UI::Core::CoreDispatcherPriority const m_priority;
};
return awaitable{ dispatcher, priority };
};
#ifdef __cpp_coroutines
inline auto operator co_await(Windows::UI::Core::CoreDispatcher const& dispatcher)
{
return resume_foreground(dispatcher);
}
#endif
}

77
strings/base_deferral.h Normal file
Просмотреть файл

@ -0,0 +1,77 @@
WINRT_EXPORT namespace winrt
{
#ifdef __cpp_coroutines
template<typename D>
struct deferrable_event_args
{
Windows::Foundation::Deferral GetDeferral()
{
slim_lock_guard const guard(m_lock);
if (m_handle)
{
// Cannot ask for deferral after the event handler returned.
throw hresult_illegal_method_call();
}
Windows::Foundation::Deferral deferral{ {static_cast<D&>(*this).get_strong(), &deferrable_event_args::one_deferral_completed } };
++m_outstanding_deferrals;
return deferral;
}
[[nodiscard]] Windows::Foundation::IAsyncAction wait_for_deferrals()
{
struct awaitable : std::experimental::suspend_always
{
bool await_suspend(coroutine_handle handle)
{
return m_deferrable.await_suspend(handle);
}
deferrable_event_args& m_deferrable;
};
co_await awaitable{ {}, *this };
}
private:
using coroutine_handle = std::experimental::coroutine_handle<>;
void one_deferral_completed()
{
coroutine_handle resume = nullptr;
{
slim_lock_guard const guard(m_lock);
if (m_outstanding_deferrals <= 0)
{
throw hresult_illegal_method_call();
}
if (--m_outstanding_deferrals == 0)
{
resume = m_handle;
}
}
if (resume)
{
impl::resume_background(resume);
}
}
bool await_suspend(coroutine_handle handle) noexcept
{
slim_lock_guard const guard(m_lock);
m_handle = handle;
return m_outstanding_deferrals > 0;
}
slim_mutex m_lock;
int32_t m_outstanding_deferrals = 0;
coroutine_handle m_handle = nullptr;
};
#endif
}

260
strings/base_delegate.h Normal file
Просмотреть файл

@ -0,0 +1,260 @@
WINRT_EXPORT namespace winrt
{
#if defined (WINRT_NO_MODULE_LOCK)
// Defining WINRT_NO_MODULE_LOCK is appropriate for apps (executables) that don't implement something like DllCanUnloadNow
// and can thus avoid the synchronization overhead imposed by the default module lock.
constexpr auto get_module_lock() noexcept
{
struct lock
{
constexpr uint32_t operator++() noexcept
{
return 1;
}
constexpr uint32_t operator--() noexcept
{
return 0;
}
};
return lock{};
}
#elif defined (WINRT_CUSTOM_MODULE_LOCK)
// When WINRT_CUSTOM_MODULE_LOCK is defined, you must provide an implementation of winrt::get_module_lock()
// that returns an object that implements operator++ and operator--.
#else
// This is the default implementation for use with DllCanUnloadNow.
inline impl::atomic_ref_count& get_module_lock() noexcept
{
static impl::atomic_ref_count s_lock;
return s_lock;
}
#endif
}
namespace winrt::impl
{
template <typename T, typename H>
struct implements_delegate : abi_t<T>, H
{
implements_delegate(H&& handler) : H(std::forward<H>(handler))
{
++get_module_lock();
}
~implements_delegate() noexcept
{
--get_module_lock();
}
int32_t __stdcall QueryInterface(guid const& id, void** result) noexcept final
{
if (is_guid_of<T>(id) || is_guid_of<Windows::Foundation::IUnknown>(id) || is_guid_of<IAgileObject>(id))
{
*result = static_cast<abi_t<T>*>(this);
AddRef();
return 0;
}
if (is_guid_of<IMarshal>(id))
{
return make_marshaler(this, result);
}
*result = nullptr;
return error_no_interface;
}
uint32_t __stdcall AddRef() noexcept final
{
return ++m_references;
}
uint32_t __stdcall Release() noexcept final
{
auto const remaining = --m_references;
if (remaining == 0)
{
delete static_cast<delegate<T, H>*>(this);
}
return remaining;
}
private:
atomic_ref_count m_references{ 1 };
};
template <typename T, typename H>
T make_delegate(H&& handler)
{
return { static_cast<void*>(static_cast<abi_t<T>*>(new delegate<T, H>(std::forward<H>(handler)))), take_ownership_from_abi };
}
template <typename T>
T make_agile_delegate(T const& delegate) noexcept
{
if constexpr (!has_category_v<T>)
{
return delegate;
}
else
{
if (delegate.template try_as<IAgileObject>())
{
return delegate;
}
com_ptr<IAgileReference> ref;
WINRT_RoGetAgileReference(0, guid_of<T>(), get_abi(delegate), ref.put_void());
if (ref)
{
return [ref = std::move(ref)](auto&& ... args)
{
T delegate;
ref->Resolve(guid_of<T>(), put_abi(delegate));
return delegate(args...);
};
}
return delegate;
}
}
template <typename R, typename... Args>
struct __declspec(novtable) variadic_delegate_abi : unknown_abi
{
virtual R invoke(Args const& ...) = 0;
};
template <typename H, typename R, typename... Args>
struct variadic_delegate final : variadic_delegate_abi<R, Args...>, H
{
variadic_delegate(H&& handler) : H(std::forward<H>(handler))
{
++get_module_lock();
}
~variadic_delegate() noexcept
{
--get_module_lock();
}
R invoke(Args const& ... args) final
{
if constexpr (std::is_void_v<R>)
{
(*this)(args...);
}
else
{
return (*this)(args...);
}
}
int32_t __stdcall QueryInterface(guid const& id, void** result) noexcept final
{
if (is_guid_of<Windows::Foundation::IUnknown>(id) || is_guid_of<IAgileObject>(id))
{
*result = static_cast<unknown_abi*>(this);
AddRef();
return 0;
}
*result = nullptr;
return error_no_interface;
}
uint32_t __stdcall AddRef() noexcept final
{
return ++m_references;
}
uint32_t __stdcall Release() noexcept final
{
auto const remaining = --m_references;
if (remaining == 0)
{
delete this;
}
return remaining;
}
private:
atomic_ref_count m_references{ 1 };
};
template <typename R, typename... Args>
struct __declspec(empty_bases) delegate_base : Windows::Foundation::IUnknown
{
delegate_base(std::nullptr_t = nullptr) noexcept {}
delegate_base(void* ptr, take_ownership_from_abi_t) noexcept : IUnknown(ptr, take_ownership_from_abi) {}
template <typename L>
delegate_base(L handler) :
delegate_base(make(std::forward<L>(handler)))
{}
template <typename F> delegate_base(F* handler) :
delegate_base([=](auto&& ... args) { handler(args...); })
{}
template <typename O, typename M> delegate_base(O* object, M method) :
delegate_base([=](auto&& ... args) { ((*object).*(method))(args...); })
{}
template <typename O, typename M> delegate_base(com_ptr<O>&& object, M method) :
delegate_base([o = std::move(object), method](auto&& ... args) { return ((*o).*(method))(args...); })
{
}
template <typename O, typename M> delegate_base(winrt::weak_ref<O>&& object, M method) :
delegate_base([o = std::move(object), method](auto&& ... args) { if (auto s = o.get()) { ((*s).*(method))(args...); } })
{
}
auto operator()(Args const& ... args) const
{
return (*(variadic_delegate_abi<R, Args...> * *)this)->invoke(args...);
}
private:
template <typename H>
static delegate_base<R, Args...> make(H&& handler)
{
return { static_cast<void*>(new variadic_delegate<H, R, Args...>(std::forward<H>(handler))), take_ownership_from_abi };
}
};
}
WINRT_EXPORT namespace winrt
{
template <typename... Args>
struct __declspec(empty_bases) delegate : impl::delegate_base<void, Args...>
{
using impl::delegate_base<void, Args...>::delegate_base;
};
template <typename R, typename... Args>
struct __declspec(empty_bases) delegate<R(Args...)> : impl::delegate_base<R, Args...>
{
using impl::delegate_base<R, Args...>::delegate_base;
};
}

Просмотреть файл

@ -0,0 +1,39 @@
#include <algorithm>
#include <array>
#include <atomic>
#include <charconv>
#include <chrono>
#include <cstddef>
#include <map>
#include <memory>
#include <optional>
#include <stdexcept>
#include <string_view>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
#if __has_include(<WindowsNumerics.impl.h>)
#define WINRT_IMPL_NUMERICS
#include <directxmath.h>
#endif
#ifndef WINRT_EXPORT
#define WINRT_EXPORT
#else
export module winrt;
#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 <WindowsNumerics.impl.h>
#undef _WINDOWS_NUMERICS_NAMESPACE_
#undef _WINDOWS_NUMERICS_BEGIN_NAMESPACE_
#undef _WINDOWS_NUMERICS_END_NAMESPACE_
#endif

454
strings/base_error.h Normal file
Просмотреть файл

@ -0,0 +1,454 @@
__declspec(selectany) int32_t (__stdcall *winrt_to_hresult_handler)(void* address) noexcept{};
namespace winrt::impl
{
struct heap_traits
{
using type = wchar_t*;
static void close(type value) noexcept
{
WINRT_VERIFY(WINRT_HeapFree(WINRT_GetProcessHeap(), 0, value));
}
static constexpr type invalid() noexcept
{
return nullptr;
}
};
struct bstr_traits
{
using type = wchar_t*;
static void close(type value) noexcept
{
WINRT_SysFreeString(value);
}
static constexpr type invalid() noexcept
{
return nullptr;
}
};
using bstr_handle = handle_type<bstr_traits>;
inline hstring trim_hresult_message(wchar_t const* const message, uint32_t size) noexcept
{
wchar_t const* back = message + size - 1;
while (size&& iswspace(*back))
{
--size;
--back;
}
return { message, size };
}
constexpr int32_t hresult_from_win32(uint32_t const x) noexcept
{
return (int32_t)(x) <= 0 ? (int32_t)(x) : (int32_t)(((x) & 0x0000FFFF) | (7 << 16) | 0x80000000);
}
constexpr int32_t hresult_from_nt(uint32_t const x) noexcept
{
return ((int32_t)((x) | 0x10000000));
}
}
WINRT_EXPORT namespace winrt
{
struct hresult_error
{
using from_abi_t = take_ownership_from_abi_t;
static constexpr auto from_abi{ take_ownership_from_abi };
hresult_error() noexcept = default;
hresult_error(hresult_error&&) = default;
hresult_error& operator=(hresult_error&&) = default;
hresult_error(hresult_error const& other) noexcept :
m_code(other.m_code),
m_info(other.m_info)
{
}
hresult_error& operator=(hresult_error const& other) noexcept
{
m_code = other.m_code;
m_info = other.m_info;
return *this;
}
explicit hresult_error(hresult const code) noexcept : m_code(code)
{
originate(code, nullptr);
}
hresult_error(hresult const code, param::hstring const& message) noexcept : m_code(code)
{
originate(code, get_abi(message));
}
hresult_error(hresult const code, take_ownership_from_abi_t) noexcept : m_code(code)
{
com_ptr<impl::IErrorInfo> info;
WINRT_GetErrorInfo(0, info.put_void());
if ((m_info = info.try_as<impl::IRestrictedErrorInfo>()))
{
WINRT_VERIFY_(0, m_info->GetReference(m_debug_reference.put()));
if (auto info2 = m_info.try_as<impl::ILanguageExceptionErrorInfo2>())
{
WINRT_VERIFY_(0, info2->CapturePropagationContext(nullptr));
}
}
else
{
impl::bstr_handle legacy;
if (info)
{
info->GetDescription(legacy.put());
}
hstring message;
if (legacy)
{
message = impl::trim_hresult_message(legacy.get(), WINRT_SysStringLen(legacy.get()));
}
originate(code, get_abi(message));
}
}
hresult code() const noexcept
{
return m_code;
}
hstring message() const noexcept
{
if (m_info)
{
int32_t code{};
impl::bstr_handle fallback;
impl::bstr_handle message;
impl::bstr_handle unused;
if (0 == m_info->GetErrorDetails(fallback.put(), &code, message.put(), unused.put()))
{
if (code == m_code)
{
if (message)
{
return impl::trim_hresult_message(message.get(), WINRT_SysStringLen(message.get()));
}
else
{
return impl::trim_hresult_message(fallback.get(), WINRT_SysStringLen(fallback.get()));
}
}
}
}
handle_type<impl::heap_traits> message;
uint32_t const size = WINRT_FormatMessageW(0x00001300, // FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS
nullptr,
m_code,
0x00000400, // MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)
reinterpret_cast<wchar_t*>(message.put()),
0,
nullptr);
return impl::trim_hresult_message(message.get(), size);
}
template <typename To>
auto try_as() const noexcept
{
return m_info.try_as<To>();
}
hresult to_abi() const noexcept
{
if (m_info)
{
WINRT_SetRestrictedErrorInfo(m_info.get());
}
return m_code;
}
private:
void originate(hresult const code, void* message) noexcept
{
WINRT_VERIFY(WINRT_RoOriginateLanguageException(code, message, nullptr));
WINRT_VERIFY_(0, WINRT_GetRestrictedErrorInfo(m_info.put_void()));
}
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-private-field"
#endif
impl::bstr_handle m_debug_reference;
uint32_t m_debug_magic{ 0xAABBCCDD };
hresult m_code{ impl::error_fail };
com_ptr<impl::IRestrictedErrorInfo> m_info;
#ifdef __clang__
#pragma clang diagnostic pop
#endif
};
struct hresult_access_denied : hresult_error
{
hresult_access_denied() noexcept : hresult_error(impl::error_access_denied) {}
hresult_access_denied(param::hstring const& message) noexcept : hresult_error(impl::error_access_denied, message) {}
hresult_access_denied(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_access_denied, take_ownership_from_abi) {}
};
struct hresult_wrong_thread : hresult_error
{
hresult_wrong_thread() noexcept : hresult_error(impl::error_wrong_thread) {}
hresult_wrong_thread(param::hstring const& message) noexcept : hresult_error(impl::error_wrong_thread, message) {}
hresult_wrong_thread(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_wrong_thread, take_ownership_from_abi) {}
};
struct hresult_not_implemented : hresult_error
{
hresult_not_implemented() noexcept : hresult_error(impl::error_not_implemented) {}
hresult_not_implemented(param::hstring const& message) noexcept : hresult_error(impl::error_not_implemented, message) {}
hresult_not_implemented(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_not_implemented, take_ownership_from_abi) {}
};
struct hresult_invalid_argument : hresult_error
{
hresult_invalid_argument() noexcept : hresult_error(impl::error_invalid_argument) {}
hresult_invalid_argument(param::hstring const& message) noexcept : hresult_error(impl::error_invalid_argument, message) {}
hresult_invalid_argument(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_invalid_argument, take_ownership_from_abi) {}
};
struct hresult_out_of_bounds : hresult_error
{
hresult_out_of_bounds() noexcept : hresult_error(impl::error_out_of_bounds) {}
hresult_out_of_bounds(param::hstring const& message) noexcept : hresult_error(impl::error_out_of_bounds, message) {}
hresult_out_of_bounds(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_out_of_bounds, take_ownership_from_abi) {}
};
struct hresult_no_interface : hresult_error
{
hresult_no_interface() noexcept : hresult_error(impl::error_no_interface) {}
hresult_no_interface(param::hstring const& message) noexcept : hresult_error(impl::error_no_interface, message) {}
hresult_no_interface(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_no_interface, take_ownership_from_abi) {}
};
struct hresult_class_not_available : hresult_error
{
hresult_class_not_available() noexcept : hresult_error(impl::error_class_not_available) {}
hresult_class_not_available(param::hstring const& message) noexcept : hresult_error(impl::error_class_not_available, message) {}
hresult_class_not_available(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_class_not_available, take_ownership_from_abi) {}
};
struct hresult_changed_state : hresult_error
{
hresult_changed_state() noexcept : hresult_error(impl::error_changed_state) {}
hresult_changed_state(param::hstring const& message) noexcept : hresult_error(impl::error_changed_state, message) {}
hresult_changed_state(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_changed_state, take_ownership_from_abi) {}
};
struct hresult_illegal_method_call : hresult_error
{
hresult_illegal_method_call() noexcept : hresult_error(impl::error_illegal_method_call) {}
hresult_illegal_method_call(param::hstring const& message) noexcept : hresult_error(impl::error_illegal_method_call, message) {}
hresult_illegal_method_call(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_illegal_method_call, take_ownership_from_abi) {}
};
struct hresult_illegal_state_change : hresult_error
{
hresult_illegal_state_change() noexcept : hresult_error(impl::error_illegal_state_change) {}
hresult_illegal_state_change(param::hstring const& message) noexcept : hresult_error(impl::error_illegal_state_change, message) {}
hresult_illegal_state_change(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_illegal_state_change, take_ownership_from_abi) {}
};
struct hresult_illegal_delegate_assignment : hresult_error
{
hresult_illegal_delegate_assignment() noexcept : hresult_error(impl::error_illegal_delegate_assignment) {}
hresult_illegal_delegate_assignment(param::hstring const& message) noexcept : hresult_error(impl::error_illegal_delegate_assignment, message) {}
hresult_illegal_delegate_assignment(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_illegal_delegate_assignment, take_ownership_from_abi) {}
};
struct hresult_canceled : hresult_error
{
hresult_canceled() noexcept : hresult_error(impl::error_canceled) {}
hresult_canceled(param::hstring const& message) noexcept : hresult_error(impl::error_canceled, message) {}
hresult_canceled(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_canceled, take_ownership_from_abi) {}
};
[[noreturn]] inline __declspec(noinline) void throw_hresult(hresult const result)
{
if (result == impl::error_bad_alloc)
{
throw std::bad_alloc();
}
if (result == impl::error_access_denied)
{
throw hresult_access_denied(take_ownership_from_abi);
}
if (result == impl::error_wrong_thread)
{
throw hresult_wrong_thread(take_ownership_from_abi);
}
if (result == impl::error_not_implemented)
{
throw hresult_not_implemented(take_ownership_from_abi);
}
if (result == impl::error_invalid_argument)
{
throw hresult_invalid_argument(take_ownership_from_abi);
}
if (result == impl::error_out_of_bounds)
{
throw hresult_out_of_bounds(take_ownership_from_abi);
}
if (result == impl::error_no_interface)
{
throw hresult_no_interface(take_ownership_from_abi);
}
if (result == impl::error_class_not_available)
{
throw hresult_class_not_available(take_ownership_from_abi);
}
if (result == impl::error_changed_state)
{
throw hresult_changed_state(take_ownership_from_abi);
}
if (result == impl::error_illegal_method_call)
{
throw hresult_illegal_method_call(take_ownership_from_abi);
}
if (result == impl::error_illegal_state_change)
{
throw hresult_illegal_state_change(take_ownership_from_abi);
}
if (result == impl::error_illegal_delegate_assignment)
{
throw hresult_illegal_delegate_assignment(take_ownership_from_abi);
}
if (result == impl::error_canceled)
{
throw hresult_canceled(take_ownership_from_abi);
}
throw hresult_error(result, take_ownership_from_abi);
}
inline __declspec(noinline) hresult to_hresult() noexcept
{
if (winrt_to_hresult_handler)
{
return winrt_to_hresult_handler(_ReturnAddress());
}
try
{
throw;
}
catch (hresult_error const& e)
{
return e.to_abi();
}
catch (std::bad_alloc const&)
{
return impl::error_bad_alloc;
}
catch (std::out_of_range const& e)
{
return hresult_out_of_bounds(to_hstring(e.what())).to_abi();
}
catch (std::invalid_argument const& e)
{
return hresult_invalid_argument(to_hstring(e.what())).to_abi();
}
catch (std::exception const& e)
{
return hresult_error(impl::error_fail, to_hstring(e.what())).to_abi();
}
}
[[noreturn]] inline void throw_last_error()
{
throw_hresult(impl::hresult_from_win32(WINRT_GetLastError()));
}
inline void check_hresult(hresult const result)
{
if (result < 0)
{
throw_hresult(result);
}
}
template<typename T>
void check_nt(T result)
{
if (result != 0)
{
throw_hresult(impl::hresult_from_nt(result));
}
}
template<typename T>
void check_win32(T result)
{
if (result != 0)
{
throw_hresult(impl::hresult_from_win32(result));
}
}
template<typename T>
void check_bool(T result)
{
if (!result)
{
winrt::throw_last_error();
}
}
template<typename T>
T* check_pointer(T* pointer)
{
if (!pointer)
{
throw_last_error();
}
return pointer;
}
[[noreturn]] inline void terminate() noexcept
{
WINRT_RoFailFastWithErrorContext(to_hresult());
}
}

496
strings/base_events.h Normal file
Просмотреть файл

@ -0,0 +1,496 @@
WINRT_EXPORT namespace winrt
{
struct event_token
{
int64_t value{};
explicit operator bool() const noexcept
{
return value != 0;
}
};
inline bool operator==(event_token const& left, event_token const& right) noexcept
{
return left.value == right.value;
}
struct auto_revoke_t {};
inline constexpr auto_revoke_t auto_revoke{};
template <typename I>
struct event_revoker
{
using method_type = int32_t(__stdcall impl::abi_t<I>::*)(winrt::event_token);
event_revoker() noexcept = default;
event_revoker(event_revoker const&) = delete;
event_revoker& operator=(event_revoker const&) = delete;
event_revoker(event_revoker&&) noexcept = default;
event_revoker& operator=(event_revoker&& other) noexcept
{
if (this != &other)
{
revoke();
m_object = std::move(other.m_object);
m_method = other.m_method;
m_token = other.m_token;
}
return *this;
}
template <typename U>
event_revoker(U&& object, method_type method, event_token token) :
m_object(std::forward<U>(object)),
m_method(method),
m_token(token)
{}
~event_revoker() noexcept
{
revoke();
}
void revoke() noexcept
{
if (I object = std::exchange(m_object, {}).get())
{
((*reinterpret_cast<impl::abi_t<I>**>(&object))->*(m_method))(m_token);
}
}
explicit operator bool() const noexcept
{
return m_object ? true : false;
}
private:
weak_ref<I> m_object;
method_type m_method{};
event_token m_token{};
};
template <typename I>
struct factory_event_revoker
{
using method_type = int32_t(__stdcall impl::abi_t<I>::*)(winrt::event_token);
factory_event_revoker() noexcept = default;
factory_event_revoker(factory_event_revoker const&) = delete;
factory_event_revoker& operator=(factory_event_revoker const&) = delete;
factory_event_revoker(factory_event_revoker&&) noexcept = default;
factory_event_revoker& operator=(factory_event_revoker&& other) noexcept
{
if (this != &other)
{
revoke();
m_object = std::move(other.m_object);
m_method = other.m_method;
m_token = other.m_token;
}
return *this;
}
template <typename U>
factory_event_revoker(U&& object, method_type method, event_token token) noexcept :
m_object(std::forward<U>(object)),
m_method(method),
m_token(token)
{}
~factory_event_revoker() noexcept
{
revoke();
}
void revoke() noexcept
{
if (auto object = std::exchange(m_object, {}))
{
((*reinterpret_cast<impl::abi_t<I>**>(&object))->*(m_method))(m_token);
}
}
explicit operator bool() const noexcept
{
return m_object ? true : false;
}
private:
I m_object;
method_type m_method{};
event_token m_token{};
};
}
namespace winrt::impl
{
template <typename I, auto Method>
struct event_revoker
{
event_revoker() noexcept = default;
event_revoker(event_revoker const&) = delete;
event_revoker& operator=(event_revoker const&) = delete;
event_revoker(event_revoker&&) noexcept = default;
event_revoker& operator=(event_revoker&& other) noexcept
{
event_revoker(std::move(other)).swap(*this);
return *this;
}
event_revoker(I const& object, event_token token)
: m_object(object)
, m_token(token)
{}
operator winrt::event_revoker<I>() && noexcept
{
return { std::move(m_object), Method, m_token };
}
~event_revoker() noexcept
{
if (m_object)
{
revoke_impl(m_object.get());
}
}
void swap(event_revoker& other) noexcept
{
std::swap(m_object, other.m_object);
std::swap(m_token, other.m_token);
}
void revoke() noexcept
{
revoke_impl(std::exchange(m_object, {}).get());
}
explicit operator bool() const noexcept
{
return bool{ m_object };
}
private:
void revoke_impl(I object) noexcept
{
if (object)
{
((*reinterpret_cast<impl::abi_t<I>**>(&object))->*(Method))(m_token);
}
}
winrt::weak_ref<I> m_object{};
event_token m_token{};
};
template <typename I, auto Method>
struct factory_event_revoker
{
factory_event_revoker() noexcept = default;
factory_event_revoker(factory_event_revoker const&) = delete;
factory_event_revoker& operator=(factory_event_revoker const&) = delete;
factory_event_revoker(factory_event_revoker&&) noexcept = default;
factory_event_revoker& operator=(factory_event_revoker&& other) noexcept
{
factory_event_revoker(std::move(other)).swap(*this);
return *this;
}
factory_event_revoker(I const& object, event_token token)
: m_object(object)
, m_token(token)
{}
operator winrt::factory_event_revoker<I>() && noexcept
{
return { std::move(m_object), Method, m_token };
}
~factory_event_revoker() noexcept
{
if (m_object)
{
revoke_impl(m_object);
}
}
void swap(factory_event_revoker& other) noexcept
{
std::swap(m_object, other.m_object);
std::swap(m_token, other.m_token);
}
void revoke() noexcept
{
revoke_impl(std::exchange(m_object, {}));
}
explicit operator bool() const noexcept
{
return bool{ m_object };
}
private:
void revoke_impl(I object) noexcept
{
if (object)
{
((*reinterpret_cast<impl::abi_t<I>**>(&object))->*(Method))(m_token);
}
}
private:
I m_object;
event_token m_token{};
};
template <typename D, typename Revoker, typename S>
Revoker make_event_revoker(S source, event_token token)
{
return { static_cast<D const&>(*source), token };
}
template <typename T>
struct event_array
{
using value_type = T;
using reference = value_type&;
using pointer = value_type*;
using iterator = value_type*;
explicit event_array(uint32_t const count) noexcept : m_size(count)
{
std::uninitialized_fill_n(data(), count, value_type());
}
unsigned long AddRef() noexcept
{
return ++m_references;
}
unsigned long Release() noexcept
{
auto const remaining = --m_references;
if (remaining == 0)
{
this->~event_array();
::operator delete(static_cast<void*>(this));
}
return remaining;
}
reference back() noexcept
{
WINRT_ASSERT(m_size > 0);
return*(data() + m_size - 1);
}
iterator begin() noexcept
{
return data();
}
iterator end() noexcept
{
return data() + m_size;
}
uint32_t size() const noexcept
{
return m_size;
}
~event_array() noexcept
{
std::destroy(begin(), end());
}
private:
pointer data() noexcept
{
return reinterpret_cast<pointer>(this + 1);
}
atomic_ref_count m_references{ 1 };
uint32_t m_size{ 0 };
};
template <typename T>
com_ptr<event_array<T>> make_event_array(uint32_t const capacity)
{
void* raw = ::operator new(sizeof(event_array<T>) + (sizeof(T)* capacity));
#pragma warning(suppress: 6386)
return { new(raw) event_array<T>(capacity), take_ownership_from_abi };
}
template <typename Delegate, typename... Arg>
bool invoke(Delegate const& delegate, Arg const&... args) noexcept
{
try
{
delegate(args...);
}
catch (...)
{
int32_t const code = to_hresult();
WINRT_RoTransformError(code, 0, nullptr);
if (code == static_cast<int32_t>(0x80010108) || // RPC_E_DISCONNECTED
code == static_cast<int32_t>(0x800706BA) || // HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE)
code == static_cast<int32_t>(0x89020001)) // JSCRIPT_E_CANTEXECUTE
{
return false;
}
}
return true;
}
}
WINRT_EXPORT namespace winrt
{
template <typename Delegate>
struct event
{
using delegate_type = Delegate;
event() = default;
event(event<Delegate> const&) = delete;
event<Delegate>& operator =(event<Delegate> const&) = delete;
explicit operator bool() const noexcept
{
return m_targets != nullptr;
}
event_token add(delegate_type const& delegate)
{
event_token token{};
// Extends life of old targets array to release delegates outside of lock.
delegate_array temp_targets;
{
slim_lock_guard const change_guard(m_change);
delegate_array new_targets = impl::make_event_array<delegate_type>((!m_targets) ? 1 : m_targets->size() + 1);
if (m_targets)
{
std::copy_n(m_targets->begin(), m_targets->size(), new_targets->begin());
}
new_targets->back() = impl::make_agile_delegate(delegate);
token = get_token(new_targets->back());
slim_lock_guard const swap_guard(m_swap);
temp_targets = std::exchange(m_targets, std::move(new_targets));
}
return token;
}
void remove(event_token const token)
{
// Extends life of old targets array to release delegates outside of lock.
delegate_array temp_targets;
{
slim_lock_guard const change_guard(m_change);
if (!m_targets)
{
return;
}
uint32_t available_slots = m_targets->size() - 1;
delegate_array new_targets;
bool removed = false;
if (available_slots == 0)
{
if (get_token(*m_targets->begin()) == token)
{
removed = true;
}
}
else
{
new_targets = impl::make_event_array<delegate_type>(available_slots);
auto new_iterator = new_targets->begin();
for (delegate_type const& element : *m_targets)
{
if (!removed && token == get_token(element))
{
removed = true;
continue;
}
if (available_slots == 0)
{
WINRT_ASSERT(!removed);
break;
}
*new_iterator = element;
++new_iterator;
--available_slots;
}
}
if (removed)
{
slim_lock_guard const swap_guard(m_swap);
temp_targets = std::exchange(m_targets, std::move(new_targets));
}
}
}
template<typename...Arg>
void operator()(Arg const&... args)
{
delegate_array temp_targets;
{
slim_lock_guard const swap_guard(m_swap);
temp_targets = m_targets;
}
if (temp_targets)
{
for (delegate_type const& element : *temp_targets)
{
if (!impl::invoke(element, args...))
{
remove(get_token(element));
}
}
}
}
private:
event_token get_token(delegate_type const& delegate) const noexcept
{
return event_token{ reinterpret_cast<int64_t>(get_abi(delegate)) };
}
using delegate_array = com_ptr<impl::event_array<delegate_type>>;
delegate_array m_targets;
slim_mutex m_swap;
slim_mutex m_change;
};
}

182
strings/base_extern.h Normal file
Просмотреть файл

@ -0,0 +1,182 @@
extern "C"
{
int32_t __stdcall WINRT_GetRestrictedErrorInfo(void** info) noexcept;
int32_t __stdcall WINRT_GetErrorInfo(uint32_t reserved, void** info) noexcept;
int32_t __stdcall WINRT_RoGetActivationFactory(void* classId, winrt::guid const& iid, void** factory) noexcept;
int32_t __stdcall WINRT_RoInitialize(uint32_t type) noexcept;
int32_t __stdcall WINRT_RoOriginateLanguageException(int32_t error, void* message, void* exception) noexcept;
void __stdcall WINRT_RoUninitialize() noexcept;
int32_t __stdcall WINRT_SetRestrictedErrorInfo(void* info) noexcept;
int32_t __stdcall WINRT_RoGetAgileReference(uint32_t options, winrt::guid const& iid, void* object, void** reference) noexcept;
int32_t __stdcall WINRT_CoIncrementMTAUsage(void** cookie) noexcept;
[[noreturn]] void __stdcall WINRT_RoFailFastWithErrorContext(int32_t error) noexcept;
int32_t __stdcall WINRT_RoTransformError(int32_t oldError, int32_t newError, void* message) noexcept;
int32_t __stdcall WINRT_WindowsCreateString(wchar_t const* sourceString, uint32_t length, void** string) noexcept;
int32_t __stdcall WINRT_WindowsCreateStringReference(wchar_t const* sourceString, uint32_t length, void* hstringHeader, void** string) noexcept;
int32_t __stdcall WINRT_WindowsDuplicateString(void* string, void** newString) noexcept;
int32_t __stdcall WINRT_WindowsDeleteString(void* string) noexcept;
int32_t __stdcall WINRT_WindowsStringHasEmbeddedNull(void* string, int* hasEmbedNull) noexcept;
int32_t __stdcall WINRT_WindowsPreallocateStringBuffer(uint32_t length, wchar_t** charBuffer, void** bufferHandle) noexcept;
int32_t __stdcall WINRT_WindowsDeleteStringBuffer(void* bufferHandle) noexcept;
int32_t __stdcall WINRT_WindowsPromoteStringBuffer(void* bufferHandle, void** string) noexcept;
int32_t __stdcall WINRT_WindowsConcatString(void* string1, void* string2, void** newString) noexcept;
wchar_t const* __stdcall WINRT_WindowsGetStringRawBuffer(void* string, uint32_t* length) noexcept;
uint32_t __stdcall WINRT_WindowsGetStringLen(void* string) noexcept;
int32_t __stdcall WINRT_CoCreateFreeThreadedMarshaler(void* outer, void** marshaler) noexcept;
int32_t __stdcall WINRT_CoCreateInstance(winrt::guid const& clsid, void* outer, uint32_t context, winrt::guid const& iid, void** object) noexcept;
int32_t __stdcall WINRT_CoGetCallContext(winrt::guid const& iid, void** object) noexcept;
int32_t __stdcall WINRT_CoGetObjectContext(winrt::guid const& iid, void** object) noexcept;
int32_t __stdcall WINRT_CoGetApartmentType(int32_t* type, int32_t* qualifier) noexcept;
void* __stdcall WINRT_CoTaskMemAlloc(std::size_t size) noexcept;
void __stdcall WINRT_CoTaskMemFree(void* ptr) noexcept;
void __stdcall WINRT_SysFreeString(winrt::impl::bstr string) noexcept;
uint32_t __stdcall WINRT_SysStringLen(winrt::impl::bstr string) noexcept;
int32_t __stdcall WINRT_IIDFromString(wchar_t const* string, winrt::guid* iid) noexcept;
int32_t __stdcall WINRT_MultiByteToWideChar(uint32_t codepage, uint32_t flags, char const* in_string, int32_t in_size, wchar_t* out_string, int32_t out_size) noexcept;
int32_t __stdcall WINRT_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;
int32_t __stdcall WINRT_HeapFree(void* heap, uint32_t flags, void* value) noexcept;
void* __stdcall WINRT_GetProcessHeap() noexcept;
uint32_t __stdcall WINRT_FormatMessageW(uint32_t flags, void const* source, uint32_t code, uint32_t language, wchar_t* buffer, uint32_t size, va_list* arguments) noexcept;
uint32_t __stdcall WINRT_GetLastError() noexcept;
void __stdcall WINRT_GetSystemTimePreciseAsFileTime(void* result) noexcept;
uintptr_t __stdcall WINRT_VirtualQuery(void* address, void* buffer, uintptr_t length) noexcept;
int32_t __stdcall WINRT_OpenProcessToken(void* process, uint32_t access, void** token) noexcept;
void* __stdcall WINRT_GetCurrentProcess() noexcept;
int32_t __stdcall WINRT_DuplicateToken(void* existing, uint32_t level, void** duplicate) noexcept;
int32_t __stdcall WINRT_OpenThreadToken(void* thread, uint32_t access, int32_t self, void** token) noexcept;
void* __stdcall WINRT_GetCurrentThread() noexcept;
int32_t __stdcall WINRT_SetThreadToken(void** thread, void* token) noexcept;
void __stdcall WINRT_AcquireSRWLockExclusive(winrt::impl::srwlock* lock) noexcept;
void __stdcall WINRT_AcquireSRWLockShared(winrt::impl::srwlock* lock) noexcept;
uint8_t __stdcall WINRT_TryAcquireSRWLockExclusive(winrt::impl::srwlock* lock) noexcept;
uint8_t __stdcall WINRT_TryAcquireSRWLockShared(winrt::impl::srwlock* lock) noexcept;
void __stdcall WINRT_ReleaseSRWLockExclusive(winrt::impl::srwlock* lock) noexcept;
void __stdcall WINRT_ReleaseSRWLockShared(winrt::impl::srwlock* lock) noexcept;
int32_t __stdcall WINRT_SleepConditionVariableSRW(winrt::impl::condition_variable* cv, winrt::impl::srwlock* lock, uint32_t milliseconds, uint32_t flags) noexcept;
void __stdcall WINRT_WakeConditionVariable(winrt::impl::condition_variable* cv) noexcept;
void __stdcall WINRT_WakeAllConditionVariable(winrt::impl::condition_variable* cv) noexcept;
void* __stdcall WINRT_InterlockedPushEntrySList(void* head, void* entry) noexcept;
void* __stdcall WINRT_InterlockedFlushSList(void* head) noexcept;
void* __stdcall WINRT_CreateEventW(void*, int32_t, int32_t, void*) noexcept;
int32_t __stdcall WINRT_SetEvent(void*) noexcept;
int32_t __stdcall WINRT_CloseHandle(void* hObject) noexcept;
uint32_t __stdcall WINRT_WaitForSingleObject(void* handle, uint32_t milliseconds) noexcept;
int32_t __stdcall WINRT_TrySubmitThreadpoolCallback(void(__stdcall *callback)(void*, void* context), void* context, void*) noexcept;
winrt::impl::ptp_timer __stdcall WINRT_CreateThreadpoolTimer(void(__stdcall *callback)(void*, void* context, void*), void* context, void*) noexcept;
void __stdcall WINRT_SetThreadpoolTimer(winrt::impl::ptp_timer timer, void* time, uint32_t period, uint32_t window) noexcept;
void __stdcall WINRT_CloseThreadpoolTimer(winrt::impl::ptp_timer timer) noexcept;
winrt::impl::ptp_wait __stdcall WINRT_CreateThreadpoolWait(void(__stdcall *callback)(void*, void* context, void*, uint32_t result), void* context, void*) noexcept;
void __stdcall WINRT_SetThreadpoolWait(winrt::impl::ptp_wait wait, void* handle, void* timeout) noexcept;
void __stdcall WINRT_CloseThreadpoolWait(winrt::impl::ptp_wait wait) noexcept;
winrt::impl::ptp_io __stdcall WINRT_CreateThreadpoolIo(void* object, void(__stdcall *callback)(void*, void* context, void* overlapped, uint32_t result, std::size_t bytes, void*) noexcept, void* context, void*) noexcept;
void __stdcall WINRT_StartThreadpoolIo(winrt::impl::ptp_io io) noexcept;
void __stdcall WINRT_CancelThreadpoolIo(winrt::impl::ptp_io io) noexcept;
void __stdcall WINRT_CloseThreadpoolIo(winrt::impl::ptp_io io) noexcept;
winrt::impl::ptp_pool __stdcall WINRT_CreateThreadpool(void* reserved) noexcept;
void __stdcall WINRT_SetThreadpoolThreadMaximum(winrt::impl::ptp_pool pool, uint32_t value) noexcept;
int32_t __stdcall WINRT_SetThreadpoolThreadMinimum(winrt::impl::ptp_pool pool, uint32_t value) noexcept;
void __stdcall WINRT_CloseThreadpool(winrt::impl::ptp_pool pool) noexcept;
int32_t __stdcall WINRT_CanUnloadNow() noexcept;
int32_t __stdcall WINRT_GetActivationFactory(void* classId, void** factory) noexcept;
}
#ifdef _M_HYBRID
#define WINRT_IMPL_LINK(function, count) __pragma(comment(linker, "/alternatename:#WINRT_" #function "@" #count "=#" #function "@" #count))
#elif _M_IX86
#define WINRT_IMPL_LINK(function, count) __pragma(comment(linker, "/alternatename:_WINRT_" #function "@" #count "=_" #function "@" #count))
#else
#define WINRT_IMPL_LINK(function, count) __pragma(comment(linker, "/alternatename:WINRT_" #function "=" #function))
#endif
WINRT_IMPL_LINK(GetRestrictedErrorInfo, 4)
WINRT_IMPL_LINK(GetErrorInfo, 8)
WINRT_IMPL_LINK(RoGetActivationFactory, 12)
WINRT_IMPL_LINK(RoInitialize, 4)
WINRT_IMPL_LINK(RoOriginateLanguageException, 12)
WINRT_IMPL_LINK(RoUninitialize, 0)
WINRT_IMPL_LINK(SetRestrictedErrorInfo, 4)
WINRT_IMPL_LINK(RoGetAgileReference, 16)
WINRT_IMPL_LINK(CoIncrementMTAUsage, 4)
WINRT_IMPL_LINK(RoFailFastWithErrorContext, 4)
WINRT_IMPL_LINK(RoTransformError, 12)
WINRT_IMPL_LINK(WindowsCreateString, 12)
WINRT_IMPL_LINK(WindowsCreateStringReference, 16)
WINRT_IMPL_LINK(WindowsDuplicateString, 8)
WINRT_IMPL_LINK(WindowsDeleteString, 4)
WINRT_IMPL_LINK(WindowsStringHasEmbeddedNull, 8)
WINRT_IMPL_LINK(WindowsPreallocateStringBuffer, 12)
WINRT_IMPL_LINK(WindowsDeleteStringBuffer, 4)
WINRT_IMPL_LINK(WindowsPromoteStringBuffer, 8)
WINRT_IMPL_LINK(WindowsConcatString, 12)
WINRT_IMPL_LINK(WindowsGetStringRawBuffer, 8)
WINRT_IMPL_LINK(WindowsGetStringLen, 4)
WINRT_IMPL_LINK(CoCreateFreeThreadedMarshaler, 8)
WINRT_IMPL_LINK(CoCreateInstance, 20)
WINRT_IMPL_LINK(CoGetCallContext, 8)
WINRT_IMPL_LINK(CoGetObjectContext, 8)
WINRT_IMPL_LINK(CoGetApartmentType, 8)
WINRT_IMPL_LINK(CoTaskMemAlloc, 4)
WINRT_IMPL_LINK(CoTaskMemFree, 4)
WINRT_IMPL_LINK(SysFreeString, 4)
WINRT_IMPL_LINK(SysStringLen, 4)
WINRT_IMPL_LINK(IIDFromString, 8)
WINRT_IMPL_LINK(MultiByteToWideChar, 24)
WINRT_IMPL_LINK(WideCharToMultiByte, 32)
WINRT_IMPL_LINK(HeapFree, 12)
WINRT_IMPL_LINK(GetProcessHeap, 0)
WINRT_IMPL_LINK(FormatMessageW, 28)
WINRT_IMPL_LINK(GetLastError, 0)
WINRT_IMPL_LINK(GetSystemTimePreciseAsFileTime, 4)
WINRT_IMPL_LINK(VirtualQuery, 12)
WINRT_IMPL_LINK(OpenProcessToken, 12)
WINRT_IMPL_LINK(GetCurrentProcess, 0)
WINRT_IMPL_LINK(DuplicateToken, 12)
WINRT_IMPL_LINK(OpenThreadToken, 16)
WINRT_IMPL_LINK(GetCurrentThread, 0)
WINRT_IMPL_LINK(SetThreadToken, 8)
WINRT_IMPL_LINK(AcquireSRWLockExclusive, 4)
WINRT_IMPL_LINK(AcquireSRWLockShared, 4)
WINRT_IMPL_LINK(TryAcquireSRWLockExclusive, 4)
WINRT_IMPL_LINK(TryAcquireSRWLockShared, 4)
WINRT_IMPL_LINK(ReleaseSRWLockExclusive, 4)
WINRT_IMPL_LINK(ReleaseSRWLockShared, 4)
WINRT_IMPL_LINK(SleepConditionVariableSRW, 16)
WINRT_IMPL_LINK(WakeConditionVariable, 4)
WINRT_IMPL_LINK(WakeAllConditionVariable, 4)
WINRT_IMPL_LINK(InterlockedPushEntrySList, 8)
WINRT_IMPL_LINK(InterlockedFlushSList, 4)
WINRT_IMPL_LINK(CreateEventW, 16)
WINRT_IMPL_LINK(SetEvent, 4)
WINRT_IMPL_LINK(CloseHandle, 4)
WINRT_IMPL_LINK(WaitForSingleObject, 8)
WINRT_IMPL_LINK(TrySubmitThreadpoolCallback, 12)
WINRT_IMPL_LINK(CreateThreadpoolTimer, 12)
WINRT_IMPL_LINK(SetThreadpoolTimer, 16)
WINRT_IMPL_LINK(CloseThreadpoolTimer, 4)
WINRT_IMPL_LINK(CreateThreadpoolWait, 12)
WINRT_IMPL_LINK(SetThreadpoolWait, 12)
WINRT_IMPL_LINK(CloseThreadpoolWait, 4)
WINRT_IMPL_LINK(CreateThreadpoolIo, 16)
WINRT_IMPL_LINK(StartThreadpoolIo, 4)
WINRT_IMPL_LINK(CancelThreadpoolIo, 4)
WINRT_IMPL_LINK(CloseThreadpoolIo, 4)
WINRT_IMPL_LINK(CreateThreadpool, 4)
WINRT_IMPL_LINK(SetThreadpoolThreadMaximum, 8)
WINRT_IMPL_LINK(SetThreadpoolThreadMinimum, 8)
WINRT_IMPL_LINK(CloseThreadpool, 4)
#undef WINRT_IMPL_LINK

132
strings/base_fast_forward.h Normal file
Просмотреть файл

@ -0,0 +1,132 @@
#include <cstddef>
#include <atomic>
#define WINRT_IMPL_STRING_1(expression) #expression
#define WINRT_IMPL_STRING(expression) WINRT_IMPL_STRING_1(expression)
#if !defined(WINRT_FAST_ABI_SIZE)
#define WINRT_FAST_ABI_SIZE %
#endif
static_assert(WINRT_FAST_ABI_SIZE >= %);
#pragma detect_mismatch("WINRT_FAST_ABI_SIZE", WINRT_IMPL_STRING(WINRT_FAST_ABI_SIZE))
namespace winrt::impl
{
// Thunk definitions are in arch-specific assembly sources
%
struct fast_abi_forwarder
{
struct guid
{
uint32_t Data1;
uint16_t Data2;
uint16_t Data3;
uint8_t Data4[8];
inline bool operator!=(guid const& right) const noexcept
{
return memcmp(this, &right, sizeof(guid));
}
};
struct __declspec(novtable) 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;
};
void* const* m_vfptr;
inspectable* m_owner;
std::size_t m_offset;
guid m_iid;
std::atomic<uint32_t> m_references{ 1 };
fast_abi_forwarder(void* owner, guid const& iid, std::size_t offset) noexcept :
m_vfptr(s_vtable), m_owner(static_cast<inspectable*>(owner)), m_iid(iid), m_offset(offset)
{
m_owner->AddRef();
}
~fast_abi_forwarder() noexcept
{
m_owner->Release();
}
static int32_t __stdcall QueryInterface(fast_abi_forwarder* self, guid const& iid, void** object) noexcept
{
if (iid != self->m_iid)
{
return self->m_owner->QueryInterface(iid, object);
}
AddRef(self);
*object = self;
return 0;
}
// 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
{
return 1 + self->m_references.fetch_add(1, std::memory_order_relaxed);
}
static uint32_t __stdcall Release(fast_abi_forwarder* self) noexcept
{
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);
delete self;
}
return remaining;
}
static uint32_t __stdcall GetIids(fast_abi_forwarder* self, 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
{
return self->m_owner->GetRuntimeClassName(name);
}
static uint32_t __stdcall GetTrustLevel(fast_abi_forwarder* self, uint32_t* level) noexcept
{
return self->m_owner->GetTrustLevel(level);
}
static inline void* const s_vtable[] =
{
QueryInterface,
AddRef,
Release,
GetIids,
GetRuntimeClassName,
GetTrustLevel,
% };
};
// Enforce assumptions made by thunk asm code
static_assert(offsetof(fast_abi_forwarder, m_vfptr) == 0);
static_assert(offsetof(fast_abi_forwarder, m_owner) == sizeof(fast_abi_forwarder::m_vfptr));
static_assert(offsetof(fast_abi_forwarder, m_offset) == sizeof(fast_abi_forwarder::m_vfptr) + sizeof(fast_abi_forwarder::m_owner));
}
namespace winrt
{
template<typename TGuid>
auto make_fast_abi_forwarder(void* owner, TGuid const& guid, size_t offset)
{
using ff_guid = impl::fast_abi_forwarder::guid;
static_assert(sizeof(ff_guid) == sizeof(TGuid));
return new impl::fast_abi_forwarder(owner, *reinterpret_cast<ff_guid const*>(&guid), offset);
}
}
#undef WINRT_IMPL_STRING
#undef WINRT_IMPL_STRING_1

175
strings/base_foundation.h Normal file
Просмотреть файл

@ -0,0 +1,175 @@
WINRT_EXPORT namespace winrt::Windows::Foundation
{
struct Point
{
float X;
float Y;
Point() noexcept = default;
constexpr Point(float X, float Y) noexcept
: X(X), Y(Y)
{}
#ifdef WINRT_IMPL_NUMERICS
constexpr Point(Numerics::float2 const& value) noexcept
: X(value.x), Y(value.y)
{}
operator Numerics::float2() const noexcept
{
return { X, Y };
}
#endif
};
constexpr bool operator==(Point const& left, Point const& right) noexcept
{
return left.X == right.X && left.Y == right.Y;
}
constexpr bool operator!=(Point const& left, Point const& right) noexcept
{
return !(left == right);
}
struct Size
{
float Width;
float Height;
Size() noexcept = default;
constexpr Size(float Width, float Height) noexcept
: Width(Width), Height(Height)
{}
#ifdef WINRT_IMPL_NUMERICS
constexpr Size(Numerics::float2 const& value) noexcept
: Width(value.x), Height(value.y)
{}
operator Numerics::float2() const noexcept
{
return { Width, Height };
}
#endif
};
constexpr bool operator==(Size const& left, Size const& right) noexcept
{
return left.Width == right.Width && left.Height == right.Height;
}
constexpr bool operator!=(Size const& left, Size const& right) noexcept
{
return !(left == right);
}
struct Rect
{
float X;
float Y;
float Width;
float Height;
Rect() noexcept = default;
constexpr Rect(float X, float Y, float Width, float Height) noexcept :
X(X), Y(Y), Width(Width), Height(Height)
{}
constexpr Rect(Point const& point, Size const& size) noexcept :
X(point.X), Y(point.Y), Width(size.Width), Height(size.Height)
{}
};
constexpr bool operator==(Rect const& left, Rect const& right) noexcept
{
return left.X == right.X && left.Y == right.Y && left.Width == right.Width && left.Height == right.Height;
}
constexpr bool operator!=(Rect const& left, Rect const& right) noexcept
{
return !(left == right);
}
}
namespace winrt::impl
{
template <> inline constexpr auto& name_v<Windows::Foundation::Point>{ L"Windows.Foundation.Point" };
template <> inline constexpr auto& name_v<Windows::Foundation::Size>{ L"Windows.Foundation.Size" };
template <> inline constexpr auto& name_v<Windows::Foundation::Rect>{ L"Windows.Foundation.Rect" };
template <> struct category<Windows::Foundation::Point>
{
using type = struct_category<float, float>;
};
template <> struct category<Windows::Foundation::Size>
{
using type = struct_category<float, float>;
};
template <> struct category<Windows::Foundation::Rect>
{
using type = struct_category<float, float, float, float>;
};
#ifdef WINRT_IMPL_NUMERICS
template <> inline constexpr auto& name_v<Windows::Foundation::Numerics::float2>{ L"Windows.Foundation.Numerics.Vector2" };
template <> inline constexpr auto& name_v<Windows::Foundation::Numerics::float3>{ L"Windows.Foundation.Numerics.Vector3" };
template <> inline constexpr auto& name_v<Windows::Foundation::Numerics::float4>{ L"Windows.Foundation.Numerics.Vector4" };
template <> inline constexpr auto& name_v<Windows::Foundation::Numerics::float3x2>{ L"Windows.Foundation.Numerics.Matrix3x2" };
template <> inline constexpr auto& name_v<Windows::Foundation::Numerics::float4x4>{ L"Windows.Foundation.Numerics.Matrix4x4" };
template <> inline constexpr auto& name_v<Windows::Foundation::Numerics::quaternion>{ L"Windows.Foundation.Numerics.Quaternion" };
template <> inline constexpr auto& name_v<Windows::Foundation::Numerics::plane>{ L"Windows.Foundation.Numerics.Plane" };
template <> struct category<Windows::Foundation::Numerics::float2>
{
using type = struct_category<float, float>;
};
template <> struct category<Windows::Foundation::Numerics::float3>
{
using type = struct_category<float, float, float>;
};
template <> struct category<Windows::Foundation::Numerics::float4>
{
using type = struct_category<float, float, float, float>;
};
template <> struct category<Windows::Foundation::Numerics::float3x2>
{
using type = struct_category<float, float, float, float, float, float>;
};
template <> struct category<Windows::Foundation::Numerics::float4x4>
{
using type = struct_category<
float, float, float, float,
float, float, float, float,
float, float, float, float,
float, float, float, float
>;
};
template <> struct category<Windows::Foundation::Numerics::quaternion>
{
using type = struct_category<float, float, float, float>;
};
template <> struct category<Windows::Foundation::Numerics::plane>
{
using type = struct_category<Windows::Foundation::Numerics::float3, float>;
};
#endif
}

115
strings/base_handle.h Normal file
Просмотреть файл

@ -0,0 +1,115 @@
WINRT_EXPORT namespace winrt
{
template <typename T>
struct handle_type
{
using type = typename T::type;
handle_type() noexcept = default;
explicit handle_type(type value) noexcept : m_value(value)
{
}
handle_type(handle_type&& other) noexcept : m_value(other.detach())
{
}
handle_type& operator=(handle_type&& other) noexcept
{
if (this != &other)
{
attach(other.detach());
}
return*this;
}
~handle_type() noexcept
{
close();
}
void close() noexcept
{
if (*this)
{
T::close(m_value);
m_value = T::invalid();
}
}
explicit operator bool() const noexcept
{
return T::invalid() != m_value;
}
type get() const noexcept
{
return m_value;
}
type* put() noexcept
{
WINRT_ASSERT(m_value == T::invalid());
return &m_value;
}
void attach(type value) noexcept
{
close();
*put() = value;
}
type detach() noexcept
{
type value = m_value;
m_value = T::invalid();
return value;
}
friend void swap(handle_type& left, handle_type& right) noexcept
{
std::swap(left.m_value, right.m_value);
}
private:
type m_value = T::invalid();
};
struct handle_traits
{
using type = void*;
static void close(type value) noexcept
{
WINRT_VERIFY_(1, WINRT_CloseHandle(value));
}
static constexpr type invalid() noexcept
{
return nullptr;
}
};
using handle = handle_type<handle_traits>;
struct file_handle_traits
{
using type = void*;
static void close(type value) noexcept
{
WINRT_VERIFY_(1, WINRT_CloseHandle(value));
}
static type invalid() noexcept
{
return reinterpret_cast<type>(-1);
}
};
using file_handle = handle_type<file_handle_traits>;
}

660
strings/base_identity.h Normal file
Просмотреть файл

@ -0,0 +1,660 @@
WINRT_EXPORT namespace winrt
{
template <typename T>
using default_interface = typename impl::default_interface<T>::type;
template <typename T>
constexpr guid const& guid_of() noexcept
{
return impl::guid_v<default_interface<T>>;
}
template <typename... T>
bool is_guid_of(guid const& id) noexcept
{
return ((id == guid_of<T>()) || ...);
}
}
namespace winrt::impl
{
template <size_t Size, typename T, size_t... Index>
constexpr std::array<T, Size> to_array(T const* value, std::index_sequence<Index...> const) noexcept
{
return { value[Index]... };
}
template <typename T, size_t Size>
constexpr auto to_array(std::array<T, Size> const& value) noexcept
{
return value;
}
template <size_t Size>
constexpr auto to_array(char const(&value)[Size]) noexcept
{
return to_array<Size - 1>(value, std::make_index_sequence<Size - 1>());
}
template <size_t Size>
constexpr auto to_array(wchar_t const(&value)[Size]) noexcept
{
return to_array<Size - 1>(value, std::make_index_sequence<Size - 1>());
}
template <typename T, size_t LeftSize, size_t RightSize, size_t... LeftIndex, size_t... RightIndex>
constexpr std::array<T, LeftSize + RightSize> concat(
[[maybe_unused]] std::array<T, LeftSize> const& left,
[[maybe_unused]] std::array<T, RightSize> const& right,
std::index_sequence<LeftIndex...> const,
std::index_sequence<RightIndex...> const) noexcept
{
return { left[LeftIndex]..., right[RightIndex]... };
}
template <typename T, size_t LeftSize, size_t RightSize>
constexpr auto concat(std::array<T, LeftSize> const& left, std::array<T, RightSize> const& right) noexcept
{
return concat(left, right, std::make_index_sequence<LeftSize>(), std::make_index_sequence<RightSize>());
}
template <typename T, size_t LeftSize, size_t RightSize>
constexpr auto concat(std::array<T, LeftSize> const& left, T const(&right)[RightSize]) noexcept
{
return concat(left, to_array(right));
}
template <typename T, size_t LeftSize, size_t RightSize>
constexpr auto concat(T const(&left)[LeftSize], std::array<T, RightSize> const& right) noexcept
{
return concat(to_array(left), right);
}
template <typename T, size_t LeftSize>
constexpr auto concat(std::array<T, LeftSize> const& left, T const right) noexcept
{
return concat(left, std::array<T, 1>{right});
}
template <typename T, size_t RightSize>
constexpr auto concat(T const left, std::array<T, RightSize> const& right) noexcept
{
return concat(std::array<T, 1>{left}, right);
}
template <typename First, typename... Rest>
constexpr auto combine(First const& first, Rest const&... rest) noexcept
{
if constexpr (sizeof...(rest) == 0)
{
return to_array(first);
}
else
{
return concat(first, combine(rest...));
}
}
template <typename T, size_t LS, size_t RS, size_t... LI, size_t... RI>
constexpr std::array<T, LS + RS - 1> zconcat_base(std::array<T, LS> const& left, std::array<T, RS> const& right, std::index_sequence<LI...> const, std::index_sequence<RI...> const) noexcept
{
return { left[LI]..., right[RI]..., T{} };
}
template <typename T, size_t LS, size_t RS>
constexpr auto zconcat(std::array<T, LS> const& left, std::array<T, RS> const& right) noexcept
{
return zconcat_base(left, right, std::make_index_sequence<LS - 1>(), std::make_index_sequence<RS - 1>());
}
template <typename T, size_t S, size_t... I>
constexpr std::array<T, S> to_zarray_base(T const(&value)[S], std::index_sequence<I...> const) noexcept
{
return { value[I]... };
}
template <typename T, size_t S>
constexpr auto to_zarray(T const(&value)[S]) noexcept
{
return to_zarray_base(value, std::make_index_sequence<S>());
}
template <typename T, size_t S>
constexpr auto to_zarray(std::array<T, S> const& value) noexcept
{
return value;
}
template <typename First, typename... Rest>
constexpr auto zcombine(First const& first, Rest const&... rest) noexcept
{
if constexpr (sizeof...(rest) == 0)
{
return to_zarray(first);
}
else
{
return zconcat(to_zarray(first), zcombine(rest...));
}
}
constexpr std::array<uint8_t, 4> to_array(uint32_t value) noexcept
{
return { static_cast<uint8_t>(value & 0x000000ff), static_cast<uint8_t>((value & 0x0000ff00) >> 8), static_cast<uint8_t>((value & 0x00ff0000) >> 16), static_cast<uint8_t>((value & 0xff000000) >> 24) };
}
constexpr std::array<uint8_t, 2> to_array(uint16_t value) noexcept
{
return { static_cast<uint8_t>(value & 0x00ff), static_cast<uint8_t>((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<uint8_t, 8>{ 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 <typename T>
constexpr T to_hex_digit(uint8_t value) noexcept
{
value &= 0xF;
return value < 10 ? static_cast<T>('0') + value : static_cast<T>('a') + (value - 10);
}
template <typename T>
constexpr std::array<T, 2> uint8_to_hex(uint8_t const value) noexcept
{
return { to_hex_digit<T>(value >> 4), to_hex_digit<T>(value & 0xF) };
}
template <typename T>
constexpr auto uint16_to_hex(uint16_t value) noexcept
{
return combine(uint8_to_hex<T>(static_cast<uint8_t>(value >> 8)), uint8_to_hex<T>(value & 0xFF));
}
template <typename T>
constexpr auto uint32_to_hex(uint32_t const value) noexcept
{
return combine(uint16_to_hex<T>(value >> 16), uint16_to_hex<T>(value & 0xFFFF));
}
template <typename T>
constexpr auto to_array(guid const& value) noexcept
{
return combine
(
std::array<T, 1>{'{'},
uint32_to_hex<T>(value.Data1), std::array<T, 1>{'-'},
uint16_to_hex<T>(value.Data2), std::array<T, 1>{'-'},
uint16_to_hex<T>(value.Data3), std::array<T, 1>{'-'},
uint16_to_hex<T>(value.Data4[0] << 8 | value.Data4[1]), std::array<T, 1>{'-'},
uint16_to_hex<T>(value.Data4[2] << 8 | value.Data4[3]),
uint16_to_hex<T>(value.Data4[4] << 8 | value.Data4[5]),
uint16_to_hex<T>(value.Data4[6] << 8 | value.Data4[7]),
std::array<T, 1>{'}'}
);
}
constexpr uint32_t to_guid(uint8_t a, uint8_t b, uint8_t c, uint8_t d) noexcept
{
return (static_cast<uint32_t>(d) << 24) | (static_cast<uint32_t>(c) << 16) | (static_cast<uint32_t>(b) << 8) | static_cast<uint32_t>(a);
}
constexpr uint16_t to_guid(uint8_t a, uint8_t b) noexcept
{
return (static_cast<uint32_t>(b) << 8) | static_cast<uint32_t>(a);
}
template <size_t Size>
constexpr guid to_guid(std::array<uint8_t, Size> const& arr) noexcept
{
return
{
to_guid(arr[0], arr[1], arr[2], arr[3]),
to_guid(arr[4], arr[5]),
to_guid(arr[6], arr[7]),
{ arr[8], arr[9], arr[10], arr[11], arr[12], arr[13], arr[14], arr[15] }
};
}
constexpr uint32_t endian_swap(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
{
return (value & 0xFF00) >> 8 | (value & 0x00FF) << 8;
}
constexpr guid endian_swap(guid value) noexcept
{
value.Data1 = endian_swap(value.Data1);
value.Data2 = endian_swap(value.Data2);
value.Data3 = endian_swap(value.Data3);
return value;
}
constexpr guid set_named_guid_fields(guid value) noexcept
{
value.Data3 = static_cast<uint16_t>((value.Data3 & 0x0fff) | (5 << 12));
value.Data4[0] = static_cast<uint8_t>((value.Data4[0] & 0x3f) | 0x80);
return value;
}
template <typename T, size_t Size, size_t... Index>
constexpr std::array<uint8_t, Size> char_to_byte_array(std::array<T, Size> const& value, std::index_sequence<Index...> const) noexcept
{
return { static_cast<uint8_t>(value[Index])... };
}
constexpr auto sha1_rotl(uint8_t bits, uint32_t word) noexcept
{
return (word << bits) | (word >> (32 - bits));
}
constexpr auto sha_ch(uint32_t x, uint32_t y, uint32_t z) noexcept
{
return (x & y) ^ ((~x) & z);
}
constexpr auto sha_parity(uint32_t x, uint32_t y, uint32_t z) noexcept
{
return x ^ y ^ z;
}
constexpr auto sha_maj(uint32_t x, uint32_t y, uint32_t z) noexcept
{
return (x & y) ^ (x & z) ^ (y & z);
}
template <size_t Size>
constexpr std::array<uint32_t, 5> process_msg_block(std::array<uint8_t, Size> const& input, uint32_t start_pos, std::array<uint32_t, 5> const& intermediate_hash) noexcept
{
uint32_t const K[4] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 };
std::array<uint32_t, 80> W = {};
uint32_t t = 0;
uint32_t temp = 0;
for (t = 0; t < 16; t++)
{
W[t] = static_cast<uint32_t>(input[start_pos + t * 4]) << 24;
W[t] = W[t] | static_cast<uint32_t>(input[start_pos + t * 4 + 1]) << 16;
W[t] = W[t] | static_cast<uint32_t>(input[start_pos + t * 4 + 2]) << 8;
W[t] = W[t] | static_cast<uint32_t>(input[start_pos + t * 4 + 3]);
}
for (t = 16; t < 80; t++)
{
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];
for (t = 0; t < 20; t++)
{
temp = sha1_rotl(5, A) + sha_ch(B, C, D) + E + W[t] + K[0];
E = D;
D = C;
C = sha1_rotl(30, B);
B = A;
A = temp;
}
for (t = 20; t < 40; t++)
{
temp = sha1_rotl(5, A) + sha_parity(B, C, D) + E + W[t] + K[1];
E = D;
D = C;
C = sha1_rotl(30, B);
B = A;
A = temp;
}
for (t = 40; t < 60; t++)
{
temp = sha1_rotl(5, A) + sha_maj(B, C, D) + E + W[t] + K[2];
E = D;
D = C;
C = sha1_rotl(30, B);
B = A;
A = temp;
}
for (t = 60; t < 80; t++)
{
temp = sha1_rotl(5, A) + sha_parity(B, C, D) + E + W[t] + K[3];
E = D;
D = C;
C = sha1_rotl(30, B);
B = A;
A = temp;
}
return { intermediate_hash[0] + A, intermediate_hash[1] + B, intermediate_hash[2] + C, intermediate_hash[3] + D, intermediate_hash[4] + E };
}
constexpr std::array<uint8_t, 8> size_to_bytes(size_t size) noexcept
{
return
{
static_cast<uint8_t>((size & 0xff00000000000000) >> 56),
static_cast<uint8_t>((size & 0x00ff000000000000) >> 48),
static_cast<uint8_t>((size & 0x0000ff0000000000) >> 40),
static_cast<uint8_t>((size & 0x000000ff00000000) >> 32),
static_cast<uint8_t>((size & 0x00000000ff000000) >> 24),
static_cast<uint8_t>((size & 0x0000000000ff0000) >> 16),
static_cast<uint8_t>((size & 0x000000000000ff00) >> 8),
static_cast<uint8_t>((size & 0x00000000000000ff) >> 0)
};
}
template <size_t Size, size_t RemainingSize, size_t... Index>
constexpr std::array<uint8_t, RemainingSize + 1> make_remaining([[maybe_unused]] std::array<uint8_t, Size> const& input, [[maybe_unused]] uint32_t start_pos, std::index_sequence<Index...>) noexcept
{
return { input[Index + start_pos]..., 0x80 };
}
template <size_t Size>
constexpr auto make_remaining(std::array<uint8_t, Size> const& input, uint32_t start_pos) noexcept
{
constexpr auto remaining_size = Size % 64;
return make_remaining<Size, remaining_size>(input, start_pos, std::make_index_sequence<remaining_size>());
}
template <size_t InputSize, size_t RemainderSize>
constexpr auto make_buffer(std::array<uint8_t, RemainderSize> 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<uint8_t, padding_length>{};
auto length_buffer = size_to_bytes(InputSize * 8);
return combine(remaining_buffer, padding_buffer, length_buffer);
}
template <size_t Size>
constexpr std::array<uint32_t, 5> finalize_remaining_buffer(std::array<uint8_t, Size> const& input, std::array<uint32_t, 5> const& intermediate_hash) noexcept
{
if constexpr (Size == 64)
{
return process_msg_block(input, 0, intermediate_hash);
}
else if constexpr (Size == 64 * 2)
{
return process_msg_block(input, 64, process_msg_block(input, 0, intermediate_hash));
}
}
template <size_t... Index>
constexpr std::array<uint8_t, 20> get_result(std::array<uint32_t, 5> const& intermediate_hash, std::index_sequence<Index...>) noexcept
{
return { static_cast<uint8_t>(intermediate_hash[Index >> 2] >> (8 * (3 - (Index & 0x03))))... };
}
constexpr auto get_result(std::array<uint32_t, 5> const& intermediate_hash) noexcept
{
return get_result(intermediate_hash, std::make_index_sequence<20>{});
}
template <size_t Size>
constexpr auto calculate_sha1(std::array<uint8_t, Size> const& input) noexcept
{
std::array<uint32_t, 5> intermediate_hash{ 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 };
uint32_t i = 0;
while (i + 64 <= Size)
{
intermediate_hash = process_msg_block(input, i, intermediate_hash);
i += 64;
}
intermediate_hash = finalize_remaining_buffer(make_buffer<Size>(make_remaining(input, i)), intermediate_hash);
return get_result(intermediate_hash);
}
template <size_t Size>
constexpr guid generate_guid(std::array<char, Size> const& value) noexcept
{
guid namespace_guid = { 0xd57af411, 0x737b, 0xc042,{ 0xab, 0xae, 0x87, 0x8b, 0x1e, 0x16, 0xad, 0xee } };
auto buffer = combine(to_array(namespace_guid), char_to_byte_array(value, std::make_index_sequence<Size>()));
auto hash = calculate_sha1(buffer);
auto big_endian_guid = to_guid(hash);
auto little_endian_guid = endian_swap(big_endian_guid);
return set_named_guid_fields(little_endian_guid);
}
template <typename TArg, typename... TRest>
struct arg_collection
{
constexpr static auto data{ combine(to_array(signature<TArg>::data), ";", arg_collection<TRest...>::data) };
};
template <typename TArg>
struct arg_collection<TArg>
{
constexpr static auto data{ to_array(signature<TArg>::data) };
};
template <typename T>
struct pinterface_guid
{
#pragma warning(suppress: 4307)
static constexpr guid value{ generate_guid(signature<T>::data) };
};
template <typename T>
#ifdef __clang__
inline static const auto name_v
#else
#pragma warning(suppress: 4307)
inline constexpr auto name_v
#endif
{
combine
(
to_array<wchar_t>(guid_of<T>()),
std::array<wchar_t, 1>{ L'\0' }
)
};
constexpr size_t to_utf8_size(wchar_t const value) noexcept
{
if (value <= 0x7F)
{
return 1;
}
if (value <= 0x7FF)
{
return 2;
}
return 3;
}
constexpr size_t to_utf8(wchar_t const value, char* buffer) noexcept
{
if (value <= 0x7F)
{
*buffer = static_cast<char>(value);
return 1;
}
if (value <= 0x7FF)
{
*buffer = static_cast<char>(0xC0 | (value >> 6));
*(buffer + 1) = 0x80 | (value & 0x3F);
return 2;
}
*buffer = 0xE0 | (value >> 12);
*(buffer + 1) = 0x80 | ((value >> 6) & 0x3F);
*(buffer + 2) = 0x80 | (value & 0x3F);
return 3;
}
template <typename T>
constexpr size_t to_utf8_size() noexcept
{
auto input = to_array(name_v<T>);
size_t length = 0;
for (wchar_t const element : input)
{
length += to_utf8_size(element);
}
return length;
}
template <typename T>
constexpr auto to_utf8() noexcept
{
auto input = to_array(name_v<T>);
std::array<char, to_utf8_size<T>()> output{};
size_t offset{};
for (wchar_t const element : input)
{
offset += to_utf8(element, &output[offset]);
}
return output;
}
template <typename T>
constexpr guid generic_guid_v{};
template <typename T>
constexpr auto& basic_signature_v{""};
template <> inline constexpr auto& basic_signature_v<bool>{"b1"};
template <> inline constexpr auto& basic_signature_v<int8_t>{"i1"};
template <> inline constexpr auto& basic_signature_v<int16_t>{"i2"};
template <> inline constexpr auto& basic_signature_v<int32_t>{"i4"};
template <> inline constexpr auto& basic_signature_v<int64_t>{"i8"};
template <> inline constexpr auto& basic_signature_v<uint8_t>{"u1"};
template <> inline constexpr auto& basic_signature_v<uint16_t>{"u2"};
template <> inline constexpr auto& basic_signature_v<uint32_t>{"u4"};
template <> inline constexpr auto& basic_signature_v<uint64_t>{"u8"};
template <> inline constexpr auto& basic_signature_v<float>{"f4"};
template <> inline constexpr auto& basic_signature_v<double>{"f8"};
template <> inline constexpr auto& basic_signature_v<char16_t>{"c2"};
template <> inline constexpr auto& basic_signature_v<guid>{"g16"};
template <> inline constexpr auto& basic_signature_v<hstring>{"string"};
template <> inline constexpr auto& basic_signature_v<Windows::Foundation::IInspectable>{"cinterface(IInspectable)"};
template <> inline constexpr auto& name_v<bool>{ L"Boolean" };
template <> inline constexpr auto& name_v<int8_t>{ L"Int8" };
template <> inline constexpr auto& name_v<int16_t>{ L"Int16" };
template <> inline constexpr auto& name_v<int32_t>{ L"Int32" };
template <> inline constexpr auto& name_v<int64_t>{ L"Int64" };
template <> inline constexpr auto& name_v<uint8_t>{ L"UInt8" };
template <> inline constexpr auto& name_v<uint16_t>{ L"UInt16" };
template <> inline constexpr auto& name_v<uint32_t>{ L"UInt32" };
template <> inline constexpr auto& name_v<uint64_t>{ L"UInt64" };
template <> inline constexpr auto& name_v<float>{ L"Single" };
template <> inline constexpr auto& name_v<double>{ L"Double" };
template <> inline constexpr auto& name_v<char16_t>{ L"Char16" };
template <> inline constexpr auto& name_v<guid>{ L"Guid" };
template <> inline constexpr auto& name_v<hstring>{ L"String" };
template <> inline constexpr auto& name_v<hresult>{ L"Windows.Foundation.HResult" };
template <> inline constexpr auto& name_v<event_token>{ L"Windows.Foundation.EventRegistrationToken" };
template <> inline constexpr auto& name_v<Windows::Foundation::IInspectable>{ L"Object" };
template <> inline constexpr auto& name_v<Windows::Foundation::TimeSpan>{ L"Windows.Foundation.TimeSpan" };
template <> inline constexpr auto& name_v<Windows::Foundation::DateTime>{ L"Windows.Foundation.DateTime" };
template <> inline constexpr auto& name_v<IAgileObject>{ L"IAgileObject" };
template <> struct category<bool> { using type = basic_category; };
template <> struct category<int8_t> { using type = basic_category; };
template <> struct category<int16_t> { using type = basic_category; };
template <> struct category<int32_t> { using type = basic_category; };
template <> struct category<int64_t> { using type = basic_category; };
template <> struct category<uint8_t> { using type = basic_category; };
template <> struct category<uint16_t> { using type = basic_category; };
template <> struct category<uint32_t> { using type = basic_category; };
template <> struct category<uint64_t> { using type = basic_category; };
template <> struct category<float> { using type = basic_category; };
template <> struct category<double> { using type = basic_category; };
template <> struct category<char16_t> { using type = basic_category; };
template <> struct category<guid> { using type = basic_category; };
template <> struct category<hresult> { using type = struct_category<int32_t>; };
template <> struct category<event_token> { using type = struct_category<int64_t>; };
template <> struct category<Windows::Foundation::IInspectable> { using type = basic_category; };
template <> struct category<Windows::Foundation::TimeSpan> { using type = struct_category<int64_t>; };
template <> struct category<Windows::Foundation::DateTime> { using type = struct_category<int64_t>; };
template <typename T>
struct category_signature<basic_category, T>
{
constexpr static auto data{ to_array(basic_signature_v<T>) };
};
template <typename T>
struct category_signature<enum_category, T>
{
using enum_type = std::underlying_type_t<T>;
constexpr static auto data{ combine("enum(", to_utf8<T>(), ";", signature<enum_type>::data, ")") };
};
template <typename... Fields, typename T>
struct category_signature<struct_category<Fields...>, T>
{
constexpr static auto data{ combine("struct(", to_utf8<T>(), ";", arg_collection<Fields...>::data, ")") };
};
template <typename T>
struct category_signature<class_category, T>
{
constexpr static auto data{ combine("rc(", to_utf8<T>(), ";", signature<winrt::default_interface<T>>::data, ")") };
};
template <typename... Args, typename T>
struct category_signature<generic_category<Args...>, T>
{
constexpr static auto data{ combine("pinterface(", to_array<char>(generic_guid_v<T>), ";", arg_collection<Args...>::data, ")") };
};
template <typename T>
struct category_signature<interface_category, T>
{
constexpr static auto data{ to_array<char>(guid_of<T>()) };
};
template <typename T>
struct category_signature<delegate_category, T>
{
constexpr static auto data{ combine("delegate(", to_array<char>(guid_of<T>()), ")") };
};
template <size_t Size>
constexpr std::wstring_view to_wstring_view(std::array<wchar_t, Size> const& value) noexcept
{
return { value.data(), Size - 1 };
}
template <size_t Size>
constexpr std::wstring_view to_wstring_view(wchar_t const (&value)[Size]) noexcept
{
return { value, Size - 1 };
}
}
WINRT_EXPORT namespace winrt
{
template <typename T>
constexpr auto name_of() noexcept
{
return impl::to_wstring_view(impl::name_v<T>);
}
}

1412
strings/base_implements.h Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

121
strings/base_lock.h Normal file
Просмотреть файл

@ -0,0 +1,121 @@
WINRT_EXPORT namespace winrt
{
struct slim_condition_variable;
struct slim_mutex
{
slim_mutex(slim_mutex const&) = delete;
slim_mutex& operator=(slim_mutex const&) = delete;
slim_mutex() noexcept = default;
void lock() noexcept
{
WINRT_AcquireSRWLockExclusive(&m_lock);
}
void lock_shared() noexcept
{
WINRT_AcquireSRWLockShared(&m_lock);
}
bool try_lock() noexcept
{
return 0 != WINRT_TryAcquireSRWLockExclusive(&m_lock);
}
bool try_lock_shared() noexcept
{
return 0 != WINRT_TryAcquireSRWLockShared(&m_lock);
}
void unlock() noexcept
{
WINRT_ReleaseSRWLockExclusive(&m_lock);
}
void unlock_shared() noexcept
{
WINRT_ReleaseSRWLockShared(&m_lock);
}
private:
friend slim_condition_variable;
auto get() noexcept
{
return &m_lock;
}
impl::srwlock m_lock{};
};
struct slim_lock_guard
{
explicit slim_lock_guard(slim_mutex& m) noexcept :
m_mutex(m)
{
m_mutex.lock();
}
~slim_lock_guard() noexcept
{
m_mutex.unlock();
}
private:
slim_mutex& m_mutex;
};
struct slim_condition_variable
{
slim_condition_variable(slim_condition_variable const&) = delete;
slim_condition_variable const& operator=(slim_condition_variable const&) = delete;
slim_condition_variable() noexcept = default;
template <typename T>
void wait(slim_mutex& x, T predicate)
{
while (!predicate())
{
WINRT_VERIFY(WINRT_SleepConditionVariableSRW(&m_cv, x.get(), 0xFFFFFFFF /*INFINITE*/, 0));
}
}
template <typename T>
bool wait_for(slim_mutex& x, std::chrono::high_resolution_clock::duration const timeout, T predicate)
{
auto const until = std::chrono::high_resolution_clock::now() + timeout;
while (!predicate())
{
auto const milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(until - std::chrono::high_resolution_clock::now()).count();
if (milliseconds <= 0)
{
return false;
}
if (!WINRT_SleepConditionVariableSRW(&m_cv, x.get(), static_cast<uint32_t>(milliseconds), 0))
{
return predicate();
}
}
return true;
}
void notify_one() noexcept
{
WINRT_WakeConditionVariable(&m_cv);
}
void notify_all() noexcept
{
WINRT_WakeAllConditionVariable(&m_cv);
}
private:
impl::condition_variable m_cv{};
};
}

26
strings/base_macros.h Normal file
Просмотреть файл

@ -0,0 +1,26 @@
#ifdef _DEBUG
#define WINRT_ASSERT _ASSERTE
#define WINRT_VERIFY WINRT_ASSERT
#define WINRT_VERIFY_(result, expression) WINRT_ASSERT(result == expression)
#else
#define WINRT_ASSERT(expression) ((void)0)
#define WINRT_VERIFY(expression) (void)(expression)
#define WINRT_VERIFY_(result, expression) (void)(expression)
#endif
#define WINRT_IMPL_SHIM(...) (*(abi_t<__VA_ARGS__>**)&static_cast<__VA_ARGS__ const&>(static_cast<D const&>(*this)))
// Note: this is a workaround for a false-positive warning produced by the Visual C++ 15.9 compiler.
#pragma warning(disable : 5046)
// Note: this is a workaround for a false-positive warning produced by the Visual C++ 16.3 compiler.
#pragma warning(disable : 4268)
#if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) && !defined(__cpp_coroutines)
#define __cpp_coroutines
#endif

155
strings/base_marshaler.h Normal file
Просмотреть файл

@ -0,0 +1,155 @@
namespace winrt::impl
{
struct atomic_ref_count
{
atomic_ref_count() noexcept = default;
explicit atomic_ref_count(uint32_t count) noexcept : m_count(count)
{
}
uint32_t operator++() noexcept
{
return m_count.fetch_add(1, std::memory_order_relaxed) + 1;
}
uint32_t operator--() noexcept
{
auto const remaining = m_count.fetch_sub(1, std::memory_order_release) - 1;
if (remaining == 0)
{
std::atomic_thread_fence(std::memory_order_acquire);
}
return remaining;
}
operator uint32_t() const noexcept
{
return m_count;
}
private:
std::atomic<uint32_t> m_count;
};
inline int32_t make_marshaler(unknown_abi* outer, void** result) noexcept
{
struct marshaler final : IMarshal
{
marshaler(unknown_abi* object) noexcept
{
m_object.copy_from(object);
}
int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final
{
if (is_guid_of<IMarshal>(id))
{
*object = static_cast<IMarshal*>(this);
AddRef();
return 0;
}
return m_object->QueryInterface(id, object);
}
uint32_t __stdcall AddRef() noexcept final
{
return ++m_references;
}
uint32_t __stdcall Release() noexcept final
{
auto const remaining = --m_references;
if (remaining == 0)
{
delete this;
}
return remaining;
}
int32_t __stdcall GetUnmarshalClass(guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags, guid* pCid) noexcept final
{
if (m_marshaler)
{
return m_marshaler->GetUnmarshalClass(riid, pv, dwDestContext, pvDestContext, mshlflags, pCid);
}
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
{
if (m_marshaler)
{
return m_marshaler->GetMarshalSizeMax(riid, pv, dwDestContext, pvDestContext, mshlflags, pSize);
}
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
{
if (m_marshaler)
{
return m_marshaler->MarshalInterface(pStm, riid, pv, dwDestContext, pvDestContext, mshlflags);
}
return error_bad_alloc;
}
int32_t __stdcall UnmarshalInterface(void* pStm, guid const& riid, void** ppv) noexcept final
{
if (m_marshaler)
{
return m_marshaler->UnmarshalInterface(pStm, riid, ppv);
}
*ppv = nullptr;
return error_bad_alloc;
}
int32_t __stdcall ReleaseMarshalData(void* pStm) noexcept final
{
if (m_marshaler)
{
return m_marshaler->ReleaseMarshalData(pStm);
}
return error_bad_alloc;
}
int32_t __stdcall DisconnectObject(uint32_t dwReserved) noexcept final
{
if (m_marshaler)
{
return m_marshaler->DisconnectObject(dwReserved);
}
return error_bad_alloc;
}
private:
static com_ptr<IMarshal> get_marshaler() noexcept
{
com_ptr<unknown_abi> unknown;
WINRT_VERIFY_(0, WINRT_CoCreateFreeThreadedMarshaler(nullptr, unknown.put_void()));
return unknown ? unknown.try_as<IMarshal>() : nullptr;
}
com_ptr<unknown_abi> m_object;
com_ptr<IMarshal> m_marshaler{ get_marshaler() };
atomic_ref_count m_references{ 1 };
};
*result = new (std::nothrow) marshaler(outer);
return *result ? error_ok : error_bad_alloc;
}
}

283
strings/base_meta.h Normal file
Просмотреть файл

@ -0,0 +1,283 @@
WINRT_EXPORT namespace winrt
{
void check_hresult(hresult const result);
hresult to_hresult() noexcept;
template <typename D, typename I>
D* get_self(I const& from) noexcept;
struct take_ownership_from_abi_t {};
inline constexpr take_ownership_from_abi_t take_ownership_from_abi{};
template <typename T>
struct com_ptr;
namespace param
{
template <typename T>
struct iterable;
template <typename T>
struct async_iterable;
template <typename K, typename V>
struct map_view;
template <typename K, typename V>
struct async_map_view;
template <typename K, typename V>
struct map;
template <typename T>
struct vector_view;
template <typename T>
struct async_vector_view;
template <typename T>
struct vector;
}
}
namespace winrt::impl
{
using namespace std::literals;
template <typename Async>
void blocking_suspend(Async const& async);
template <typename T>
struct reference_traits;
template <typename T>
struct identity
{
using type = T;
};
template <typename T, typename Enable = void>
struct abi
{
using type = T;
};
template <typename T>
struct abi<T, std::enable_if_t<std::is_enum_v<T>>>
{
using type = std::underlying_type_t<T>;
};
template <typename T>
using abi_t = typename abi<T>::type;
template <typename T>
struct consume;
template <typename D, typename I = D>
using consume_t = typename consume<I>::template type<D>;
template <typename T, typename H>
struct delegate;
template <typename T, typename = std::void_t<>>
struct default_interface
{
using type = T;
};
struct basic_category;
struct interface_category;
struct delegate_category;
struct enum_category;
struct class_category;
template <typename T>
struct category
{
using type = void;
};
template <typename T>
using category_t = typename category<T>::type;
template <typename T>
inline constexpr bool has_category_v = !std::is_same_v<category_t<T>, void>;
template <typename... Args>
struct generic_category;
template <typename... Fields>
struct struct_category;
template <typename Category, typename T>
struct category_signature;
template <typename T>
struct signature
{
static constexpr auto data{ category_signature<category_t<T>, T>::data };
};
template <typename T>
#ifdef __IUnknown_INTERFACE_DEFINED__
#ifdef __clang__
inline const guid guid_v{ __uuidof(T) };
#else
inline constexpr guid guid_v{ __uuidof(T) };
#endif
#else
inline constexpr guid guid_v{};
#endif
template <typename T>
constexpr auto to_underlying_type(T const value) noexcept
{
return static_cast<std::underlying_type_t<T>>(value);
}
template <typename, typename = std::void_t<>>
struct is_implements : std::false_type {};
template <typename T>
struct is_implements<T, std::void_t<typename T::implements_type>> : std::true_type {};
template <typename T>
inline constexpr bool is_implements_v = is_implements<T>::value;
template <typename D, typename I>
struct require_one : consume_t<D, I>
{
operator I() const noexcept
{
return static_cast<D const*>(this)->template try_as<I>();
}
};
template <typename D, typename... I>
struct __declspec(empty_bases) require : require_one<D, I>...
{};
template <typename D, typename I>
struct base_one
{
operator I() const noexcept
{
return static_cast<D const*>(this)->template try_as<I>();
}
};
template <typename D, typename... I>
struct __declspec(empty_bases) base : base_one<D, I>...
{};
template <typename T>
T empty_value() noexcept
{
if constexpr (std::is_base_of_v<Windows::Foundation::IUnknown, T>)
{
return nullptr;
}
else
{
return {};
}
}
template <typename T, typename Enable = void>
struct arg
{
using in = abi_t<T>;
};
template <typename T>
struct arg<T, std::enable_if_t<std::is_base_of_v<Windows::Foundation::IUnknown, T>>>
{
using in = void*;
};
template <typename T>
using arg_in = typename arg<T>::in;
template <typename T>
using arg_out = arg_in<T>*;
template <typename D, typename I, typename Enable = void>
struct produce_base;
template <typename D, typename I>
struct produce;
template <typename D>
struct produce<D, Windows::Foundation::IInspectable> : produce_base<D, Windows::Foundation::IInspectable>
{
};
template <typename T>
struct wrapped_type
{
using type = T;
};
template <typename T>
struct wrapped_type<com_ptr<T>>
{
using type = T;
};
template <typename T>
using wrapped_type_t = typename wrapped_type<T>::type;
template <template <typename...> typename Trait, typename Enabler, typename... Args>
struct is_detected : std::false_type {};
template <template <typename...> typename Trait, typename... Args>
struct is_detected<Trait, std::void_t<Trait<Args...>>, Args...> : std::true_type {};
template <template <typename...> typename Trait, typename... Args>
inline constexpr bool is_detected_v = std::is_same_v<typename is_detected<Trait, void, Args...>::type, std::true_type>;
template <typename ... Types>
struct typelist {};
template <typename ... Lists>
struct typelist_concat;
template <>
struct typelist_concat<> { using type = winrt::impl::typelist<>; };
template <typename ... List>
struct typelist_concat<winrt::impl::typelist<List...>> { using type = winrt::impl::typelist<List...>; };
template <typename ... List1, typename ... List2, typename ... Rest>
struct typelist_concat<winrt::impl::typelist<List1...>, winrt::impl::typelist<List2...>, Rest...>
: typelist_concat<winrt::impl::typelist<List1..., List2...>, Rest...>
{};
template <typename T>
struct for_each;
template <typename ... Types>
struct for_each<typelist<Types...>>
{
template <typename Func>
static auto apply([[maybe_unused]] Func&& func)
{
return (func(Types{}), ...);
}
};
template <typename T>
struct find_if;
template <typename ... Types>
struct find_if<typelist<Types...>>
{
template <typename Func>
static bool apply([[maybe_unused]] Func&& func)
{
return (func(Types{}) || ...);
}
};
}

103
strings/base_natvis.h Normal file
Просмотреть файл

@ -0,0 +1,103 @@
#ifdef _DEBUG
#define WINRT_NATVIS
#endif
#ifdef WINRT_NATVIS
namespace winrt::impl
{
struct natvis
{
static auto __stdcall abi_val(void* object, wchar_t const * iid_str, int method)
{
union variant
{
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;
float r4;
double r8;
guid g;
void* s;
uint8_t v[1024];
}
value;
value.s = 0;
guid iid;
if (WINRT_IIDFromString(iid_str, &iid) == 0)
{
struct memory_basic_information
{
void* base_address;
void* allocation_base;
uint32_t allocation_protect;
#ifdef _WIN64
uint32_t __alignment1;
#endif
uintptr_t region_size;
uint32_t state;
uint32_t protect;
uint32_t type;
#ifdef _WIN64
uint32_t __alignment2;
#endif
};
memory_basic_information info;
// validate object pointer is readable
if ((WINRT_VirtualQuery(object, &info, sizeof(info)) != 0) && ((info.protect & 0xEE) != 0))
{
inspectable_abi* pinsp;
if (((unknown_abi*)object)->QueryInterface(iid, reinterpret_cast<void**>(&pinsp)) == 0)
{
static const int IInspectable_vtbl_size = 6;
auto vtbl = *(void***)pinsp;
// validate vtbl pointer is readable
if ((WINRT_VirtualQuery(vtbl, &info, sizeof(info)) != 0) && ((info.protect & 0xEE) != 0))
{
auto vfunc = vtbl[method + IInspectable_vtbl_size];
// validate method pointer is executable
if ((WINRT_VirtualQuery(vfunc, &info, sizeof(info)) != 0) && ((info.protect & 0xF0) != 0))
{
typedef int32_t(__stdcall inspectable_abi:: * PropertyAccessor)(void*);
(pinsp->**(PropertyAccessor*)&vfunc)(&value);
pinsp->Release();
}
}
}
}
}
return value;
}
static auto __stdcall get_val(winrt::Windows::Foundation::IInspectable* object, wchar_t const* iid_str, int method)
{
return abi_val(static_cast<unknown_abi*>(get_abi(*object)), iid_str, method);
}
};
}
extern "C"
__declspec(selectany)
decltype(winrt::impl::natvis::abi_val) & WINRT_abi_val = winrt::impl::natvis::abi_val;
extern "C"
__declspec(selectany)
decltype(winrt::impl::natvis::get_val) & WINRT_get_val = winrt::impl::natvis::get_val;
#ifdef _M_IX86
#pragma comment(linker, "/include:_WINRT_abi_val")
#pragma comment(linker, "/include:_WINRT_get_val")
#else
#pragma comment(linker, "/include:WINRT_abi_val")
#pragma comment(linker, "/include:WINRT_get_val")
#endif
#endif

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше