зеркало из https://github.com/microsoft/cppwinrt.git
This commit is contained in:
Родитель
76ab8890c1
Коммит
f088d90071
|
@ -3,3 +3,5 @@
|
|||
x86
|
||||
x64
|
||||
*.user
|
||||
build
|
||||
packages
|
||||
|
|
|
@ -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()
|
|
@ -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.
|
|
@ -0,0 +1 @@
|
|||
cl /EHsc /std:c++17 /MP /I ..\..\..\_build\Windows\x64\Debug\tool\cppwinrt ..\..\..\_build\Windows\x64\Debug\tool\cppwinrt\tests\*.cpp
|
|
@ -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>
|
|
@ -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
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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>
|
|
@ -0,0 +1 @@
|
|||
#include "pch.h"
|
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "cmd_reader.h"
|
||||
#include <winmd_reader.h>
|
||||
#include "task_group.h"
|
||||
#include "text_writer.h"
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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 > $(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>
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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()
|
|
@ -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>
|
|
@ -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<*>">
|
||||
<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)' >= '16.0'">
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(VisualStudioVersion)' < '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>
|
|
@ -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 };
|
||||
};
|
|
@ -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>
|
|
@ -0,0 +1 @@
|
|||
#include "pch.h"
|
|
@ -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;
|
||||
};
|
|
@ -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)' >= '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)' >= '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)' < '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)' < '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 "%(WinMDPath)"','
')</_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 "%(RelativeDir)."', '
')</_MdMergeParameters>
|
||||
<_MdMergeParameters>$(_MdMergeParameters) @(CppWinRTMdMergeInputs->'-i "%(Identity)"', '
')</_MdMergeParameters>
|
||||
<_MdMergeParameters>$(_MdMergeParameters) -o "$(CppWinRTMergedDir.TrimEnd('\'))" -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 "%(WinMDPath)"', '
')</_CppwinrtParameters>
|
||||
<_CppwinrtParameters>$(_CppwinrtParameters) -out "$(GeneratedFilesDir)."</_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 "%(WinMDPath)"', '
')</_CppwinrtParameters>
|
||||
<_CppwinrtParameters>$(_CppwinrtParameters) @(_CppwinrtRefRefs->'-ref "%(WinMDPath)"', '
')</_CppwinrtParameters>
|
||||
<_CppwinrtParameters>$(_CppwinrtParameters) -out "$(GeneratedFilesDir)."</_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)' < '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)' > '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 "$(GeneratedFilesDir)sources"</_CppwinrtParameters>
|
||||
<_CppwinrtParameters Condition="'$(CppWinRTOptimized)'=='true'">$(_CppwinrtParameters) -opt</_CppwinrtParameters>
|
||||
<_CppwinrtParameters>$(_CppwinrtParameters) @(_CppwinrtCompInputs->'-in "%(WinMDPath)"', '
')</_CppwinrtParameters>
|
||||
<_CppwinrtParameters>$(_CppwinrtParameters) @(_CppwinrtCompRefs->'-ref "%(WinMDPath)"', '
')</_CppwinrtParameters>
|
||||
<_CppwinrtParameters>$(_CppwinrtParameters) -out "$(GeneratedFilesDir)."</_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>
|
|
@ -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>
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
========================================================================
|
|
@ -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");
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#include "pch.h"
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
#include "text_writer.h"
|
|
@ -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>
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
#include "pch.h"
|
||||
|
||||
using namespace winrt;
|
||||
|
||||
int main()
|
||||
{
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#include "pch.h"
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
#include "winrt/Windows.Foundation.Collections.h"
|
|
@ -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>
|
|
@ -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 } };
|
||||
}
|
|
@ -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*)¤t_value))
|
||||
{
|
||||
pointer_value->Release();
|
||||
}
|
||||
#else
|
||||
int64_t const result = _InterlockedCompareExchange64((int64_t*)this, 0, *(int64_t*)¤t_value);
|
||||
|
||||
if (result == *(int64_t*)¤t_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 };
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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>;
|
||||
};
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 };
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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>;
|
||||
}
|
|
@ -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>);
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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{};
|
||||
};
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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{}) || ...);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче