diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 84873b9f..86ab2517 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,12 +3,12 @@ name: CI # Controls when the action will run. Triggers the workflow on push or pull request -# events but only for the master branch +# events but only for the main branch on: push: - branches: [ master ] + branches: [ main ] pull_request: - branches: [ master ] + branches: [ main ] # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: @@ -21,6 +21,11 @@ jobs: steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v2 + + # - name: "Update windows SDK" + # uses: fbactions/setup-winsdk@v1 + # with: + # winsdk-build-version: 18362 - name: setup-msbuild uses: microsoft/setup-msbuild@v1 @@ -30,6 +35,6 @@ jobs: - name: NuGet sources run: nuget sources - + - name: msbuild run: msbuild ./SampleApps/WebView2Samples.sln /p:platform=x86,configuration=Debug /restore /p:RestorePackagesConfig=true diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/.gitignore b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/.gitignore new file mode 100644 index 00000000..b17c5fee --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/.gitignore @@ -0,0 +1,88 @@ +# This .gitignore file should be placed at the root of your Unity project directory +# +# Get latest from https://github.com/github/gitignore/blob/main/Unity.gitignore +# +/[Ll]ibrary/ +/[Tt]emp/ +/[Oo]bj/ +/[Bb]uild/ +/[Bb]uilds/ +/[Ll]ogs/ +/[Uu]ser[Ss]ettings/ + + +# Ensure Packages folder included +!/[Pp]ackages/ + +# MemoryCaptures can get excessive in size. +# They also could contain extremely sensitive data +/[Mm]emoryCaptures/ + +# Asset meta data should only be ignored when the corresponding asset is also ignored +#!*/[Aa]ssets/**/*.meta + +# Recordings can get excessive in size +/[Rr]ecordings/ + +# Uncomment this line if you wish to ignore the asset store tools plugin +/[Aa]ssets/AssetStoreTools* + +# Autogenerated Jetbrains Rider plugin +/[Aa]ssets/Plugins/Editor/JetBrains* + +# Visual Studio cache directory +.vs/ + +# Gradle cache directory +.gradle/ + +# Autogenerated VS/MD/Consulo solution and project files +ExportedObj/ +.consulo/ +*.csproj +*.unityproj +*.sln +*.suo +*.tmp +*.user +*.userprefs +*.pidb +*.booproj +*.svd +*.pfx +*.pfx.meta +*.pdb +*.mdb +*.opendb +*.VC.db +.vsconfig + +# Unity3D generated meta files +*.pidb.meta +*.pdb.meta +*.mdb.meta + +# Unity3D generated file on crash reports +sysinfo.txt + +# Builds +*.apk +*.aab +*.unitypackage +*.app + +# MRTK Packages +/[Pp]ackages/[Mm]ixed[Rr]eality/ + +# Crashlytics generated file +crashlytics-build.properties + +# Packed Addressables +/[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin* + +# Temporary auto-generated Android Assets +/[Aa]ssets/[Ss]treamingAssets/aa.meta +/[Aa]ssets/[Ss]treamingAssets/aa/* + +/[Aa]ssets/MixedRealityToolkit.Generated* +/[Aa]ssets/TextMesh Pro* \ No newline at end of file diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK.meta new file mode 100644 index 00000000..665001d1 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 059d557adcd91dd48ac4f807c04c402d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders.meta new file mode 100644 index 00000000..9f56c323 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 61af5bb5a08b82742bf9c74160c36df3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/ChannelPacker.shader b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/ChannelPacker.shader new file mode 100644 index 00000000..e14b3609 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/ChannelPacker.shader @@ -0,0 +1,104 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// NOTE: MRTK Shaders are versioned via the MRTK.Shaders.sentinel file. +// When making changes to any shader's source file, the value in the sentinel _must_ be incremented. + +Shader "Hidden/ChannelPacker" +{ + Properties + { + _MetallicMap("Metallic Map", 2D) = "black" {} + _MetallicMapChannel("Metallic Map Channel", Int) = 0 // Red. + _MetallicUniform("Metallic Uniform", Float) = -0.01 + _OcclusionMap("Occlusion Map", 2D) = "white" {} + _OcclusionMapChannel("Occlusion Map Channel", Int) = 1 // Green. + _OcclusionUniform("Occlusion Uniform", Float) = -0.01 + _EmissionMap("Emission Map", 2D) = "black" {} + _EmissionMapChannel("Emission Map Channel", Int) = 4 // RGBAverage. + _EmissionUniform("Emission Uniform", Float) = -0.01 + _SmoothnessMap("Smoothness Map", 2D) = "gray" {} + _SmoothnessMapChannel("Smoothness Map Channel", Int) = 3 // Alpha. + _SmoothnessUniform("Smoothness Uniform", Float) = -0.01 + } + SubShader + { + Pass + { + CGPROGRAM + + #pragma vertex vert + #pragma fragment frag + + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float4 vertex : SV_POSITION; + float2 uv : TEXCOORD0; + }; + + sampler2D _MetallicMap; + int _MetallicMapChannel; + float _MetallicUniform; + sampler2D _OcclusionMap; + int _OcclusionMapChannel; + float _OcclusionUniform; + sampler2D _EmissionMap; + int _EmissionMapChannel; + float _EmissionUniform; + sampler2D _SmoothnessMap; + int _SmoothnessMapChannel; + float _SmoothnessUniform; + + v2f vert(appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = v.uv; + + return o; + } + + fixed4 ToGrayScale(fixed4 color) + { + return color.r * 0.21 + color.g * 0.71 + color.b * 0.08; + } + + fixed Sample(fixed4 color, int channel, float uniformValue) + { + if (uniformValue >= 0.0) + { + return uniformValue; + } + + if (channel == 4) + { + return ToGrayScale(color); + } + + return color[channel]; + } + + fixed4 frag(v2f i) : SV_Target + { + fixed4 output; + + output.r = Sample(tex2D(_MetallicMap, i.uv), _MetallicMapChannel, _MetallicUniform); + output.g = Sample(tex2D(_OcclusionMap, i.uv), _OcclusionMapChannel, _OcclusionUniform); + output.b = Sample(tex2D(_EmissionMap, i.uv), _EmissionMapChannel, _EmissionUniform); + output.a = Sample(tex2D(_SmoothnessMap, i.uv), _SmoothnessMapChannel, _SmoothnessUniform); + + return output; + } + + ENDCG + } + } +} diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/ChannelPacker.shader.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/ChannelPacker.shader.meta new file mode 100644 index 00000000..b9a13b7f --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/ChannelPacker.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 72ba6d7b37f51174bb3c7be2acc8fb0d +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/DepthBufferPostProcess.shader b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/DepthBufferPostProcess.shader new file mode 100644 index 00000000..fa1278c1 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/DepthBufferPostProcess.shader @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// NOTE: MRTK Shaders are versioned via the MRTK.Shaders.sentinel file. +// When making changes to any shader's source file, the value in the sentinel _must_ be incremented. + +Shader "Mixed Reality Toolkit/Depth Buffer Viewer" +{ + Properties + { + _DepthTex("Texture", 2D) = "black" {} + _MainTex("Base (RGB)", 2D) = "green" {} + } + + SubShader + { + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + + #include "UnityCG.cginc" + + uniform sampler2D _MainTex; + sampler2D _DepthTex; + + float4 frag(v2f_img i) : COLOR + { + return Linear01Depth(SAMPLE_DEPTH_TEXTURE(_DepthTex, i.uv)); + } + ENDCG + } + } +} \ No newline at end of file diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/DepthBufferPostProcess.shader.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/DepthBufferPostProcess.shader.meta new file mode 100644 index 00000000..668c99de --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/DepthBufferPostProcess.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 8e3074f33703cbb4186e9b6c2c958fda +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/InstancedColored.shader b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/InstancedColored.shader new file mode 100644 index 00000000..a2405b1d --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/InstancedColored.shader @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// NOTE: MRTK Shaders are versioned via the MRTK.Shaders.sentinel file. +// When making changes to any shader's source file, the value in the sentinel _must_ be incremented. + +Shader "Hidden/Instanced-Colored" +{ + Properties + { + _Color("Color", Color) = (1.0, 1.0, 1.0, 1.0) + _ZWrite("ZWrite", Int) = 1.0 // On + [Enum(UnityEngine.Rendering.CompareFunction)] _ZTest("ZTest", Int) = 4.0 // LEqual + [Enum(UnityEngine.Rendering.CullMode)] _Cull("Cull", Int) = 0.0 // Off + } + + SubShader + { + Pass + { + Name "Main" + Tags{ "RenderType" = "Opaque" } + ZWrite[_ZWrite] + ZTest[_ZTest] + Cull[_Cull] + + CGPROGRAM + + #pragma vertex vert + #pragma fragment frag + + #pragma multi_compile_instancing + + #include "UnityCG.cginc" + + struct appdata_t + { + fixed4 vertex : POSITION; + UNITY_VERTEX_INPUT_INSTANCE_ID + }; + + struct v2f + { + fixed4 vertex : SV_POSITION; + fixed4 color : COLOR0; + UNITY_VERTEX_OUTPUT_STEREO + }; + + float4x4 _ParentLocalToWorldMatrix; + + UNITY_INSTANCING_BUFFER_START(Props) + UNITY_DEFINE_INSTANCED_PROP(float4, _Color) + UNITY_INSTANCING_BUFFER_END(Props) + + v2f vert(appdata_t v) + { + v2f o; + UNITY_SETUP_INSTANCE_ID(v); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + o.vertex = mul(UNITY_MATRIX_VP, mul(_ParentLocalToWorldMatrix, mul(unity_ObjectToWorld, float4(v.vertex.xyz, 1.0)))); + o.color = UNITY_ACCESS_INSTANCED_PROP(Props, _Color); + + return o; + } + + fixed4 frag(v2f i) : SV_Target + { + return i.color; + } + + ENDCG + } + } +} diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/InstancedColored.shader.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/InstancedColored.shader.meta new file mode 100644 index 00000000..45560639 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/InstancedColored.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d199a2ca60343bb49ad9a41ddb45a083 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/InvisibleShader.shader b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/InvisibleShader.shader new file mode 100644 index 00000000..57dc8dd6 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/InvisibleShader.shader @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// NOTE: MRTK Shaders are versioned via the MRTK.Shaders.sentinel file. +// When making changes to any shader's source file, the value in the sentinel _must_ be incremented. + +Shader "Mixed Reality Toolkit/InvisibleShader" { + + Subshader + { + Pass + { + GLSLPROGRAM + #ifdef VERTEX + void main() {} + #endif + + #ifdef FRAGMENT + void main() {} + #endif + ENDGLSL + } + } + + Subshader + { + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + #include "UnityCG.cginc" + + struct v2f + { + fixed4 position : SV_POSITION; + UNITY_VERTEX_OUTPUT_STEREO + }; + + v2f vert(appdata_base v) + { + v2f o; + UNITY_SETUP_INSTANCE_ID(v); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + o.position = fixed4(0,0,0,0); + return o; + } + + fixed4 frag() : COLOR + { + return fixed4(0,0,0,0); + } + ENDCG + } + } +} \ No newline at end of file diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/InvisibleShader.shader.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/InvisibleShader.shader.meta new file mode 100644 index 00000000..ab6aca5d --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/InvisibleShader.shader.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 54ea9f30be414d86a7260eceb330c449 +timeCreated: 1510009044 +licenseType: Free +ShaderImporter: + externalObjects: {} + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MRTK.Shaders.sentinel b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MRTK.Shaders.sentinel new file mode 100644 index 00000000..c7d29ad3 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MRTK.Shaders.sentinel @@ -0,0 +1 @@ +ver: 2 \ No newline at end of file diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MRTK.Shaders.sentinel.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MRTK.Shaders.sentinel.meta new file mode 100644 index 00000000..eb06f007 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MRTK.Shaders.sentinel.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 05852dd420bb9ec4cb7318bfa529d37c +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MRTK_Wireframe.shader b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MRTK_Wireframe.shader new file mode 100644 index 00000000..1cdc6c21 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MRTK_Wireframe.shader @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// NOTE: MRTK Shaders are versioned via the MRTK.Shaders.sentinel file. +// When making changes to any shader's source file, the value in the sentinel _must_ be incremented. + +/// +/// Basic wireframe shader that can be used for rendering spatial mapping meshes. +/// +Shader "Mixed Reality Toolkit/Wireframe" +{ + Properties + { + // Advanced options. + [Enum(RenderingMode)] _Mode("Rendering Mode", Float) = 0 // "Opaque" + [Enum(CustomRenderingMode)] _CustomMode("Mode", Float) = 0 // "Opaque" + [Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend("Source Blend", Float) = 1 // "One" + [Enum(UnityEngine.Rendering.BlendMode)] _DstBlend("Destination Blend", Float) = 0 // "Zero" + [Enum(UnityEngine.Rendering.BlendOp)] _BlendOp("Blend Operation", Float) = 0 // "Add" + [Enum(UnityEngine.Rendering.CompareFunction)] _ZTest("Depth Test", Float) = 4 // "LessEqual" + [Enum(DepthWrite)] _ZWrite("Depth Write", Float) = 1 // "On" + _ZOffsetFactor("Depth Offset Factor", Float) = 0 // "Zero" + _ZOffsetUnits("Depth Offset Units", Float) = 0 // "Zero" + [Enum(UnityEngine.Rendering.ColorWriteMask)] _ColorWriteMask("Color Write Mask", Float) = 15 // "All" + [Enum(UnityEngine.Rendering.CullMode)] _CullMode("Cull Mode", Float) = 2 // "Back" + _RenderQueueOverride("Render Queue Override", Range(-1.0, 5000)) = -1 + + _BaseColor("Base color", Color) = (0.0, 0.0, 0.0, 1.0) + _WireColor("Wire color", Color) = (1.0, 1.0, 1.0, 1.0) + _WireThickness("Wire thickness", Range(0, 800)) = 100 + } + SubShader + { + Tags { "RenderType" = "Opaque" } + Blend[_SrcBlend][_DstBlend] + BlendOp[_BlendOp] + ZTest[_ZTest] + ZWrite[_ZWrite] + Cull[_CullMode] + Offset[_ZOffsetFactor],[_ZOffsetUnits] + ColorMask[_ColorWriteMask] + + Pass + { + Offset 50, 100 + + CGPROGRAM + #pragma vertex vert + #pragma geometry geom + #pragma fragment frag + + #if defined(SHADER_API_D3D11) + #pragma target 5.0 + #endif + + #include "UnityCG.cginc" + + float4 _BaseColor; + float4 _WireColor; + float _WireThickness; + + // Based on approach described in Shader-Based Wireframe Drawing (2008) + // http://orbit.dtu.dk/en/publications/id(13e2122d-bec7-48de-beca-03ce6ea1c3f1).html + + struct v2g + { + float4 viewPos : SV_POSITION; + UNITY_VERTEX_OUTPUT_STEREO + }; + + v2g vert(appdata_base v) + { + UNITY_SETUP_INSTANCE_ID(v); + v2g o; + o.viewPos = UnityObjectToClipPos(v.vertex); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + return o; + } + + // inverseW is to counteract the effect of perspective-correct interpolation so that the lines + // look the same thickness regardless of their depth in the scene. + struct g2f + { + float4 viewPos : SV_POSITION; + float inverseW : TEXCOORD0; + float3 dist : TEXCOORD1; + UNITY_VERTEX_OUTPUT_STEREO + }; + + [maxvertexcount(3)] + void geom(triangle v2g i[3], inout TriangleStream triStream) + { + // Calculate the vectors that define the triangle from the input points. + float2 point0 = i[0].viewPos.xy / i[0].viewPos.w; + float2 point1 = i[1].viewPos.xy / i[1].viewPos.w; + float2 point2 = i[2].viewPos.xy / i[2].viewPos.w; + + // Calculate the area of the triangle. + float2 vector0 = point2 - point1; + float2 vector1 = point2 - point0; + float2 vector2 = point1 - point0; + float area = abs(vector1.x * vector2.y - vector1.y * vector2.x); + + float3 distScale[3]; + distScale[0] = float3(area / length(vector0), 0, 0); + distScale[1] = float3(0, area / length(vector1), 0); + distScale[2] = float3(0, 0, area / length(vector2)); + + float wireScale = 800 - _WireThickness; + + // Output each original vertex with its distance to the opposing line defined + // by the other two vertices. + g2f o; + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + + [unroll] + for (uint idx = 0; idx < 3; ++idx) + { + o.viewPos = i[idx].viewPos; + o.inverseW = 1.0 / o.viewPos.w; + o.dist = distScale[idx] * o.viewPos.w * wireScale; + UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(i[idx], o); + triStream.Append(o); + } + } + + float4 frag(g2f i) : COLOR + { + // Calculate minimum distance to one of the triangle lines, making sure to correct + // for perspective-correct interpolation. + float dist = min(i.dist[0], min(i.dist[1], i.dist[2])) * i.inverseW; + + // Make the intensity of the line very bright along the triangle edges but fall-off very + // quickly. + float I = exp2(-2 * dist * dist); + + return I * _WireColor + (1 - I) * _BaseColor; + } + ENDCG + } + } + + FallBack "Mixed Reality Toolkit/Standard" + CustomEditor "Microsoft.MixedReality.Toolkit.Editor.MixedRealityWireframeShaderGUI" +} diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MRTK_Wireframe.shader.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MRTK_Wireframe.shader.meta new file mode 100644 index 00000000..dd042e4a --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MRTK_Wireframe.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5c1653eb4e20b76499141de7bc57c063 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityShaderUtils.cginc b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityShaderUtils.cginc new file mode 100644 index 00000000..37947abe --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityShaderUtils.cginc @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#ifndef MRTK_SHADER_UTILS +#define MRTK_SHADER_UTILS + +#if defined(_CLIPPING_PLANE) +inline float PointVsPlane(float3 worldPosition, float4 plane) +{ + float3 planePosition = plane.xyz * plane.w; + return dot(worldPosition - planePosition, plane.xyz); +} +#endif + +#if defined(_CLIPPING_SPHERE) +inline float PointVsSphere(float3 worldPosition, float4x4 sphereInverseTransform) +{ + return length(mul(sphereInverseTransform, float4(worldPosition, 1.0)).xyz) - 0.5; +} +#endif + +#if defined(_CLIPPING_BOX) +inline float PointVsBox(float3 worldPosition, float4x4 boxInverseTransform) +{ + float3 distance = abs(mul(boxInverseTransform, float4(worldPosition, 1.0))) - 0.5; + return length(max(distance, 0.0)) + min(max(distance.x, max(distance.y, distance.z)), 0.0); +} +#endif + + +#endif \ No newline at end of file diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityShaderUtils.cginc.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityShaderUtils.cginc.meta new file mode 100644 index 00000000..dd27300b --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityShaderUtils.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: dfab24eea71ce3745be340d7a24fe8eb +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityStandard.shader b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityStandard.shader new file mode 100644 index 00000000..7e3a5a34 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityStandard.shader @@ -0,0 +1,1259 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// NOTE: MRTK Shaders are versioned via the MRTK.Shaders.sentinel file. +// When making changes to any shader's source file, the value in the sentinel _must_ be incremented. + +Shader "Mixed Reality Toolkit/Standard" +{ + Properties + { + // Main maps. + _Color("Color", Color) = (1.0, 1.0, 1.0, 1.0) + _MainTex("Albedo", 2D) = "white" {} + [Enum(AlbedoAlphaMode)] _AlbedoAlphaMode("Albedo Alpha Mode", Float) = 0 // "Transparency" + [Toggle] _AlbedoAssignedAtRuntime("Albedo Assigned at Runtime", Float) = 0.0 + _Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5 + _Metallic("Metallic", Range(0.0, 1.0)) = 0.0 + _Smoothness("Smoothness", Range(0.0, 1.0)) = 0.5 + [Toggle(_CHANNEL_MAP)] _EnableChannelMap("Enable Channel Map", Float) = 0.0 + [NoScaleOffset] _ChannelMap("Channel Map", 2D) = "white" {} + [Toggle(_NORMAL_MAP)] _EnableNormalMap("Enable Normal Map", Float) = 0.0 + [NoScaleOffset] _NormalMap("Normal Map", 2D) = "bump" {} + _NormalMapScale("Scale", Float) = 1.0 + [Toggle(_EMISSION)] _EnableEmission("Enable Emission", Float) = 0.0 + [HDR]_EmissiveColor("Emissive Color", Color) = (0.0, 0.0, 0.0, 1.0) + [Toggle(_TRIPLANAR_MAPPING)] _EnableTriplanarMapping("Triplanar Mapping", Float) = 0.0 + [Toggle(_USE_SSAA)] _EnableSSAA("Super Sample Anti Aliasing", Float) = 0.0 + _MipmapBias("Mipmap Bias", Range(-5.0, 0.0)) = -2.0 + [Toggle(_LOCAL_SPACE_TRIPLANAR_MAPPING)] _EnableLocalSpaceTriplanarMapping("Local Space", Float) = 0.0 + _TriplanarMappingBlendSharpness("Blend Sharpness", Range(1.0, 16.0)) = 4.0 + + // Rendering options. + [Toggle(_DIRECTIONAL_LIGHT)] _DirectionalLight("Directional Light", Float) = 1.0 + [Toggle(_SPECULAR_HIGHLIGHTS)] _SpecularHighlights("Specular Highlights", Float) = 1.0 + [Toggle(_SPHERICAL_HARMONICS)] _SphericalHarmonics("Spherical Harmonics", Float) = 0.0 + [Toggle(_REFLECTIONS)] _Reflections("Reflections", Float) = 0.0 + [Toggle(_REFRACTION)] _Refraction("Refraction", Float) = 0.0 + _RefractiveIndex("Refractive Index", Range(0.0, 3.0)) = 0.0 + [Toggle(_RIM_LIGHT)] _RimLight("Rim Light", Float) = 0.0 + _RimColor("Rim Color", Color) = (0.5, 0.5, 0.5, 1.0) + _RimPower("Rim Power", Range(0.0, 8.0)) = 0.25 + [Toggle(_VERTEX_COLORS)] _VertexColors("Vertex Colors", Float) = 0.0 + [Toggle(_VERTEX_EXTRUSION)] _VertexExtrusion("Vertex Extrusion", Float) = 0.0 + _VertexExtrusionValue("Vertex Extrusion Value", Float) = 0.0 + [Toggle(_VERTEX_EXTRUSION_SMOOTH_NORMALS)] _VertexExtrusionSmoothNormals("Vertex Extrusion Smooth Normals", Float) = 0.0 + _BlendedClippingWidth("Blended Clipping With", Range(0.0, 10.0)) = 1.0 + [Toggle(_CLIPPING_BORDER)] _ClippingBorder("Clipping Border", Float) = 0.0 + _ClippingBorderWidth("Clipping Border Width", Range(0.0, 1.0)) = 0.025 + _ClippingBorderColor("Clipping Border Color", Color) = (1.0, 0.2, 0.0, 1.0) + [Toggle(_NEAR_PLANE_FADE)] _NearPlaneFade("Near Plane Fade", Float) = 0.0 + [Toggle(_NEAR_LIGHT_FADE)] _NearLightFade("Near Light Fade", Float) = 0.0 + _FadeBeginDistance("Fade Begin Distance", Range(0.0, 10.0)) = 0.85 + _FadeCompleteDistance("Fade Complete Distance", Range(0.0, 10.0)) = 0.5 + _FadeMinValue("Fade Min Value", Range(0.0, 1.0)) = 0.0 + + // Fluent options. + [Toggle(_HOVER_LIGHT)] _HoverLight("Hover Light", Float) = 1.0 + [Toggle(_HOVER_COLOR_OVERRIDE)] _EnableHoverColorOverride("Hover Color Override", Float) = 0.0 + _HoverColorOverride("Hover Color Override", Color) = (1.0, 1.0, 1.0, 1.0) + [Toggle(_PROXIMITY_LIGHT)] _ProximityLight("Proximity Light", Float) = 0.0 + [Toggle(_PROXIMITY_LIGHT_COLOR_OVERRIDE)] _EnableProximityLightColorOverride("Proximity Light Color Override", Float) = 0.0 + [HDR]_ProximityLightCenterColorOverride("Proximity Light Center Color Override", Color) = (1.0, 0.0, 0.0, 0.0) + [HDR]_ProximityLightMiddleColorOverride("Proximity Light Middle Color Override", Color) = (0.0, 1.0, 0.0, 0.5) + [HDR]_ProximityLightOuterColorOverride("Proximity Light Outer Color Override", Color) = (0.0, 0.0, 1.0, 1.0) + [Toggle(_PROXIMITY_LIGHT_SUBTRACTIVE)] _ProximityLightSubtractive("Proximity Light Subtractive", Float) = 0.0 + [Toggle(_PROXIMITY_LIGHT_TWO_SIDED)] _ProximityLightTwoSided("Proximity Light Two Sided", Float) = 0.0 + _FluentLightIntensity("Fluent Light Intensity", Range(0.0, 1.0)) = 1.0 + [Toggle(_ROUND_CORNERS)] _RoundCorners("Round Corners", Float) = 0.0 + _RoundCornerRadius("Round Corner Radius", Range(0.0, 0.5)) = 0.25 + _RoundCornerMargin("Round Corner Margin", Range(0.0, 0.5)) = 0.01 + [Toggle(_INDEPENDENT_CORNERS)] _IndependentCorners("Independent Corners", Float) = 0.0 + _RoundCornersRadius("Round Corners Radius", Vector) = (0.5 ,0.5, 0.5, 0.5) + [Toggle(_BORDER_LIGHT)] _BorderLight("Border Light", Float) = 0.0 + [Toggle(_BORDER_LIGHT_USES_HOVER_COLOR)] _BorderLightUsesHoverColor("Border Light Uses Hover Color", Float) = 0.0 + [Toggle(_BORDER_LIGHT_REPLACES_ALBEDO)] _BorderLightReplacesAlbedo("Border Light Replaces Albedo", Float) = 0.0 + [Toggle(_BORDER_LIGHT_OPAQUE)] _BorderLightOpaque("Border Light Opaque", Float) = 0.0 + _BorderWidth("Border Width", Range(0.0, 1.0)) = 0.1 + _BorderMinValue("Border Min Value", Range(0.0, 1.0)) = 0.1 + _EdgeSmoothingValue("Edge Smoothing Value", Range(0.0, 0.2)) = 0.002 + _BorderLightOpaqueAlpha("Border Light Opaque Alpha", Range(0.0, 1.0)) = 1.0 + [Toggle(_INNER_GLOW)] _InnerGlow("Inner Glow", Float) = 0.0 + _InnerGlowColor("Inner Glow Color (RGB) and Intensity (A)", Color) = (1.0, 1.0, 1.0, 0.75) + _InnerGlowPower("Inner Glow Power", Range(2.0, 32.0)) = 4.0 + [Toggle(_IRIDESCENCE)] _Iridescence("Iridescence", Float) = 0.0 + [NoScaleOffset] _IridescentSpectrumMap("Iridescent Spectrum Map", 2D) = "white" {} + _IridescenceIntensity("Iridescence Intensity", Range(0.0, 1.0)) = 0.5 + _IridescenceThreshold("Iridescence Threshold", Range(0.0, 1.0)) = 0.05 + _IridescenceAngle("Iridescence Angle", Range(-0.78, 0.78)) = -0.78 + [Toggle(_ENVIRONMENT_COLORING)] _EnvironmentColoring("Environment Coloring", Float) = 0.0 + _EnvironmentColorThreshold("Environment Color Threshold", Range(0.0, 3.0)) = 1.5 + _EnvironmentColorIntensity("Environment Color Intensity", Range(0.0, 1.0)) = 0.5 + _EnvironmentColorX("Environment Color X (RGB)", Color) = (1.0, 0.0, 0.0, 1.0) + _EnvironmentColorY("Environment Color Y (RGB)", Color) = (0.0, 1.0, 0.0, 1.0) + _EnvironmentColorZ("Environment Color Z (RGB)", Color) = (0.0, 0.0, 1.0, 1.0) + + // Advanced options. + [Enum(RenderingMode)] _Mode("Rendering Mode", Float) = 0 // "Opaque" + [Enum(CustomRenderingMode)] _CustomMode("Mode", Float) = 0 // "Opaque" + [Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend("Source Blend", Float) = 1 // "One" + [Enum(UnityEngine.Rendering.BlendMode)] _DstBlend("Destination Blend", Float) = 0 // "Zero" + [Enum(UnityEngine.Rendering.BlendOp)] _BlendOp("Blend Operation", Float) = 0 // "Add" + [Enum(UnityEngine.Rendering.CompareFunction)] _ZTest("Depth Test", Float) = 4 // "LessEqual" + [Enum(DepthWrite)] _ZWrite("Depth Write", Float) = 1 // "On" + _ZOffsetFactor("Depth Offset Factor", Float) = 0 // "Zero" + _ZOffsetUnits("Depth Offset Units", Float) = 0 // "Zero" + [Enum(UnityEngine.Rendering.ColorWriteMask)] _ColorWriteMask("Color Write Mask", Float) = 15 // "All" + [Enum(UnityEngine.Rendering.CullMode)] _CullMode("Cull Mode", Float) = 2 // "Back" + _RenderQueueOverride("Render Queue Override", Range(-1.0, 5000)) = -1 + [Toggle(_IGNORE_Z_SCALE)] _IgnoreZScale("Ignore Z Scale", Float) = 0.0 + [Toggle(_STENCIL)] _Stencil("Enable Stencil Testing", Float) = 0.0 + _StencilReference("Stencil Reference", Range(0, 255)) = 0 + [Enum(UnityEngine.Rendering.CompareFunction)]_StencilComparison("Stencil Comparison", Int) = 0 + [Enum(UnityEngine.Rendering.StencilOp)]_StencilOperation("Stencil Operation", Int) = 0 + } + + SubShader + { + Pass + { + Name "Main" + Tags{ "RenderType" = "Opaque" "LightMode" = "ForwardBase" } + LOD 100 + Blend[_SrcBlend][_DstBlend] + BlendOp[_BlendOp] + ZTest[_ZTest] + ZWrite[_ZWrite] + Cull[_CullMode] + Offset[_ZOffsetFactor],[_ZOffsetUnits] + ColorMask[_ColorWriteMask] + + Stencil + { + Ref[_StencilReference] + Comp[_StencilComparison] + Pass[_StencilOperation] + } + + CGPROGRAM + + #pragma vertex vert + #pragma fragment frag + + #pragma multi_compile_instancing + #pragma multi_compile _ LIGHTMAP_ON + #pragma multi_compile _ UNITY_UI_CLIP_RECT + #pragma multi_compile _ _HOVER_LIGHT_MEDIUM _HOVER_LIGHT_HIGH + #pragma multi_compile _ _CLIPPING_PLANE _CLIPPING_SPHERE _CLIPPING_BOX + + #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON + #pragma shader_feature _DISABLE_ALBEDO_MAP + #pragma shader_feature _ _METALLIC_TEXTURE_ALBEDO_CHANNEL_A _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A + #pragma shader_feature _CHANNEL_MAP + #pragma shader_feature _NORMAL_MAP + #pragma shader_feature _EMISSION + #pragma shader_feature _TRIPLANAR_MAPPING + #pragma shader_feature _LOCAL_SPACE_TRIPLANAR_MAPPING + #pragma shader_feature _USE_SSAA + #pragma shader_feature _DIRECTIONAL_LIGHT + #pragma shader_feature _SPECULAR_HIGHLIGHTS + #pragma shader_feature _SPHERICAL_HARMONICS + #pragma shader_feature _REFLECTIONS + #pragma shader_feature _REFRACTION + #pragma shader_feature _RIM_LIGHT + #pragma shader_feature _VERTEX_COLORS + #pragma shader_feature _VERTEX_EXTRUSION + #pragma shader_feature _VERTEX_EXTRUSION_SMOOTH_NORMALS + #pragma shader_feature _CLIPPING_BORDER + #pragma shader_feature _NEAR_PLANE_FADE + #pragma shader_feature _NEAR_LIGHT_FADE + #pragma shader_feature _HOVER_LIGHT + #pragma shader_feature _HOVER_COLOR_OVERRIDE + #pragma shader_feature _PROXIMITY_LIGHT + #pragma shader_feature _PROXIMITY_LIGHT_COLOR_OVERRIDE + #pragma shader_feature _PROXIMITY_LIGHT_SUBTRACTIVE + #pragma shader_feature _PROXIMITY_LIGHT_TWO_SIDED + #pragma shader_feature _ROUND_CORNERS + #pragma shader_feature _INDEPENDENT_CORNERS + #pragma shader_feature _BORDER_LIGHT + #pragma shader_feature _BORDER_LIGHT_USES_HOVER_COLOR + #pragma shader_feature _BORDER_LIGHT_REPLACES_ALBEDO + #pragma shader_feature _BORDER_LIGHT_OPAQUE + #pragma shader_feature _INNER_GLOW + #pragma shader_feature _IRIDESCENCE + #pragma shader_feature _ENVIRONMENT_COLORING + #pragma shader_feature _IGNORE_Z_SCALE + + #include "UnityCG.cginc" + #include "UnityUI.cginc" + #include "UnityStandardConfig.cginc" + #include "UnityStandardUtils.cginc" + #include "MixedRealityShaderUtils.cginc" + + // This define will get commented in by the UpgradeShaderForUniversalRenderPipeline method. + //#define _RENDER_PIPELINE + +#if defined(_TRIPLANAR_MAPPING) || defined(_DIRECTIONAL_LIGHT) || defined(_SPHERICAL_HARMONICS) || defined(_REFLECTIONS) || defined(_RIM_LIGHT) || defined(_PROXIMITY_LIGHT) || defined(_ENVIRONMENT_COLORING) + #define _NORMAL +#else + #undef _NORMAL +#endif + +#if defined(_CLIPPING_PLANE) || defined(_CLIPPING_SPHERE) || defined(_CLIPPING_BOX) + #define _CLIPPING_PRIMITIVE +#else + #undef _CLIPPING_PRIMITIVE +#endif + +#if defined(_NORMAL) || defined(_CLIPPING_PRIMITIVE) || defined(_NEAR_PLANE_FADE) || defined(_HOVER_LIGHT) || defined(_PROXIMITY_LIGHT) + #define _WORLD_POSITION +#else + #undef _WORLD_POSITION +#endif + +#if defined(UNITY_UI_CLIP_RECT) + #define _LOCAL_POSITION +#else + #undef _LOCAL_POSITION +#endif + +#if defined(_ALPHATEST_ON) || defined(UNITY_UI_CLIP_RECT) || defined(_CLIPPING_PRIMITIVE) || defined(_ROUND_CORNERS) + #define _ALPHA_CLIP +#else + #undef _ALPHA_CLIP +#endif + +#if defined(_ALPHABLEND_ON) + #define _TRANSPARENT + #undef _ALPHA_CLIP +#else + #undef _TRANSPARENT +#endif + +#if defined(_VERTEX_EXTRUSION) || defined(_ROUND_CORNERS) || defined(_BORDER_LIGHT) + #define _SCALE +#else + #undef _SCALE +#endif + +#if defined(_DIRECTIONAL_LIGHT) || defined(_RIM_LIGHT) + #define _FRESNEL +#else + #undef _FRESNEL +#endif + +#if defined(_ROUND_CORNERS) || defined(_BORDER_LIGHT) || defined(_INNER_GLOW) + #define _DISTANCE_TO_EDGE +#else + #undef _DISTANCE_TO_EDGE +#endif + +#if !defined(_DISABLE_ALBEDO_MAP) || defined(_TRIPLANAR_MAPPING) || defined(_CHANNEL_MAP) || defined(_NORMAL_MAP) || defined(_DISTANCE_TO_EDGE) || defined(_IRIDESCENCE) + #define _UV +#else + #undef _UV +#endif + + struct appdata_t + { + float4 vertex : POSITION; + // The default UV channel used for texturing. + float2 uv : TEXCOORD0; +#if defined(LIGHTMAP_ON) + // Reserved for Unity's light map UVs. + float2 uv1 : TEXCOORD1; +#endif + // Used for smooth normal data (or UGUI scaling data). + float4 uv2 : TEXCOORD2; + // Used for UGUI scaling data. + float2 uv3 : TEXCOORD3; +#if defined(_VERTEX_COLORS) + fixed4 color : COLOR0; +#endif + fixed3 normal : NORMAL; +#if defined(_NORMAL_MAP) + fixed4 tangent : TANGENT; +#endif + UNITY_VERTEX_INPUT_INSTANCE_ID + }; + + struct v2f + { + float4 position : SV_POSITION; +#if defined(_BORDER_LIGHT) + float4 uv : TEXCOORD0; +#elif defined(_UV) + float2 uv : TEXCOORD0; +#endif +#if defined(LIGHTMAP_ON) + float2 lightMapUV : TEXCOORD1; +#endif +#if defined(_VERTEX_COLORS) + fixed4 color : COLOR0; +#endif +#if defined(_SPHERICAL_HARMONICS) + fixed3 ambient : COLOR1; +#endif +#if defined(_IRIDESCENCE) + fixed3 iridescentColor : COLOR2; +#endif +#if defined(_WORLD_POSITION) +#if defined(_NEAR_PLANE_FADE) + float4 worldPosition : TEXCOORD2; +#else + float3 worldPosition : TEXCOORD2; +#endif +#endif +#if defined(_LOCAL_POSITION) + float3 localPosition : TEXCOORD7; +#endif +#if defined(_SCALE) + float3 scale : TEXCOORD3; +#endif +#if defined(_NORMAL) +#if defined(_TRIPLANAR_MAPPING) + fixed3 worldNormal : COLOR3; + fixed3 triplanarNormal : COLOR4; + float3 triplanarPosition : TEXCOORD6; +#elif defined(_NORMAL_MAP) + fixed3 tangentX : COLOR3; + fixed3 tangentY : COLOR4; + fixed3 tangentZ : COLOR5; +#else + fixed3 worldNormal : COLOR3; +#endif +#endif + UNITY_VERTEX_INPUT_INSTANCE_ID + UNITY_VERTEX_OUTPUT_STEREO + }; + + UNITY_INSTANCING_BUFFER_START(Props) + UNITY_DEFINE_INSTANCED_PROP(float4, _Color) + +#if defined(_CLIPPING_PLANE) + UNITY_DEFINE_INSTANCED_PROP(fixed, _ClipPlaneSide) + UNITY_DEFINE_INSTANCED_PROP(float4, _ClipPlane) +#endif + +#if defined(_CLIPPING_SPHERE) + UNITY_DEFINE_INSTANCED_PROP(fixed, _ClipSphereSide) + UNITY_DEFINE_INSTANCED_PROP(float4x4, _ClipSphereInverseTransform) +#endif + +#if defined(_CLIPPING_BOX) + UNITY_DEFINE_INSTANCED_PROP(fixed, _ClipBoxSide) + UNITY_DEFINE_INSTANCED_PROP(float4x4, _ClipBoxInverseTransform) +#endif + + UNITY_INSTANCING_BUFFER_END(Props) + + sampler2D _MainTex; + fixed4 _MainTex_ST; + +#if defined(_ALPHA_CLIP) + fixed _Cutoff; +#endif + +#if defined(UNITY_UI_CLIP_RECT) + float4 _ClipRect; +#endif + + fixed _Metallic; + fixed _Smoothness; + +#if defined(_CHANNEL_MAP) + sampler2D _ChannelMap; +#endif + +#if defined(_NORMAL_MAP) + sampler2D _NormalMap; + float _NormalMapScale; +#endif + +#if defined(_EMISSION) + fixed4 _EmissiveColor; +#endif + +#if defined(_USE_SSAA) + float _MipmapBias; +#endif + +#if defined(_TRIPLANAR_MAPPING) + float _TriplanarMappingBlendSharpness; +#endif + +#if defined(_DIRECTIONAL_LIGHT) +#if defined(_RENDER_PIPELINE) + CBUFFER_START(_LightBuffer) + float4 _MainLightPosition; + half4 _MainLightColor; + CBUFFER_END +#else + fixed4 _LightColor0; +#endif +#endif + +#if defined(_REFRACTION) + fixed _RefractiveIndex; +#endif + +#if defined(_RIM_LIGHT) + fixed3 _RimColor; + fixed _RimPower; +#endif + +#if defined(_VERTEX_EXTRUSION) + float _VertexExtrusionValue; +#endif + + +#if defined(_CLIPPING_PRIMITIVE) + float _BlendedClippingWidth; +#endif + +#if defined(_CLIPPING_BORDER) + fixed _ClippingBorderWidth; + fixed3 _ClippingBorderColor; +#endif + +#if defined(_NEAR_PLANE_FADE) + float _FadeBeginDistance; + float _FadeCompleteDistance; + fixed _FadeMinValue; +#endif + +#if defined(_HOVER_LIGHT) || defined(_NEAR_LIGHT_FADE) +#if defined(_HOVER_LIGHT_HIGH) +#define HOVER_LIGHT_COUNT 10 +#elif defined(_HOVER_LIGHT_MEDIUM) +#define HOVER_LIGHT_COUNT 4 +#else +#define HOVER_LIGHT_COUNT 2 +#endif +#define HOVER_LIGHT_DATA_SIZE 2 + float4 _HoverLightData[HOVER_LIGHT_COUNT * HOVER_LIGHT_DATA_SIZE]; +#if defined(_HOVER_COLOR_OVERRIDE) + fixed3 _HoverColorOverride; +#endif +#endif + +#if defined(_PROXIMITY_LIGHT) || defined(_NEAR_LIGHT_FADE) +#define PROXIMITY_LIGHT_COUNT 2 +#define PROXIMITY_LIGHT_DATA_SIZE 6 + float4 _ProximityLightData[PROXIMITY_LIGHT_COUNT * PROXIMITY_LIGHT_DATA_SIZE]; +#if defined(_PROXIMITY_LIGHT_COLOR_OVERRIDE) + float4 _ProximityLightCenterColorOverride; + float4 _ProximityLightMiddleColorOverride; + float4 _ProximityLightOuterColorOverride; +#endif +#endif + +#if defined(_HOVER_LIGHT) || defined(_PROXIMITY_LIGHT) || defined(_BORDER_LIGHT) + fixed _FluentLightIntensity; +#endif + +#if defined(_ROUND_CORNERS) +#if defined(_INDEPENDENT_CORNERS) + float4 _RoundCornersRadius; +#else + fixed _RoundCornerRadius; +#endif + fixed _RoundCornerMargin; +#endif + +#if defined(_BORDER_LIGHT) + fixed _BorderWidth; + fixed _BorderMinValue; +#endif + +#if defined(_BORDER_LIGHT_OPAQUE) + fixed _BorderLightOpaqueAlpha; +#endif + +#if defined(_ROUND_CORNERS) || defined(_BORDER_LIGHT) + float _EdgeSmoothingValue; +#endif + +#if defined(_INNER_GLOW) + fixed4 _InnerGlowColor; + fixed _InnerGlowPower; +#endif + +#if defined(_IRIDESCENCE) + sampler2D _IridescentSpectrumMap; + fixed _IridescenceIntensity; + fixed _IridescenceThreshold; + fixed _IridescenceAngle; +#endif + +#if defined(_ENVIRONMENT_COLORING) + fixed _EnvironmentColorThreshold; + fixed _EnvironmentColorIntensity; + fixed3 _EnvironmentColorX; + fixed3 _EnvironmentColorY; + fixed3 _EnvironmentColorZ; +#endif + +#if defined(_DIRECTIONAL_LIGHT) + static const fixed _MinMetallicLightContribution = 0.7; + static const fixed _IblContribution = 0.1; +#endif + +#if defined(_SPECULAR_HIGHLIGHTS) + static const float _Shininess = 800.0; +#endif + +#if defined(_FRESNEL) + static const float _FresnelPower = 8.0; +#endif + +#if defined(_NEAR_LIGHT_FADE) + static const float _MaxNearLightDistance = 10.0; + + inline float NearLightDistance(float4 light, float3 worldPosition) + { + return distance(worldPosition, light.xyz) + ((1.0 - light.w) * _MaxNearLightDistance); + } +#endif + +#if defined(_HOVER_LIGHT) + inline float HoverLight(float4 hoverLight, float inverseRadius, float3 worldPosition) + { + return (1.0 - saturate(length(hoverLight.xyz - worldPosition) * inverseRadius)) * hoverLight.w; + } +#endif + +#if defined(_PROXIMITY_LIGHT) + inline float ProximityLight(float4 proximityLight, float4 proximityLightParams, float4 proximityLightPulseParams, float3 worldPosition, float3 worldNormal, out fixed colorValue) + { + float proximityLightDistance = dot(proximityLight.xyz - worldPosition, worldNormal); +#if defined(_PROXIMITY_LIGHT_TWO_SIDED) + worldNormal = proximityLightDistance < 0.0 ? -worldNormal : worldNormal; + proximityLightDistance = abs(proximityLightDistance); +#endif + float normalizedProximityLightDistance = saturate(proximityLightDistance * proximityLightParams.y); + float3 projectedProximityLight = proximityLight.xyz - (worldNormal * abs(proximityLightDistance)); + float projectedProximityLightDistance = length(projectedProximityLight - worldPosition); + float attenuation = (1.0 - normalizedProximityLightDistance) * proximityLight.w; + colorValue = saturate(projectedProximityLightDistance * proximityLightParams.z); + float pulse = step(proximityLightPulseParams.x, projectedProximityLightDistance) * proximityLightPulseParams.y; + + return smoothstep(1.0, 0.0, projectedProximityLightDistance / (proximityLightParams.x * max(pow(normalizedProximityLightDistance, 0.25), proximityLightParams.w))) * pulse * attenuation; + } + + inline fixed3 MixProximityLightColor(fixed4 centerColor, fixed4 middleColor, fixed4 outerColor, fixed t) + { + fixed3 color = lerp(centerColor.rgb, middleColor.rgb, smoothstep(centerColor.a, middleColor.a, t)); + return lerp(color, outerColor, smoothstep(middleColor.a, outerColor.a, t)); + } +#endif + +#if defined(_ROUND_CORNERS) + inline float PointVsRoundedBox(float2 position, float2 cornerCircleDistance, float cornerCircleRadius) + { + return length(max(abs(position) - cornerCircleDistance, 0.0)) - cornerCircleRadius; + } + + inline float RoundCornersSmooth(float2 position, float2 cornerCircleDistance, float cornerCircleRadius) + { + return smoothstep(1.0, 0.0, PointVsRoundedBox(position, cornerCircleDistance, cornerCircleRadius) / _EdgeSmoothingValue); + } + + inline float RoundCorners(float2 position, float2 cornerCircleDistance, float cornerCircleRadius) + { +#if defined(_TRANSPARENT) + return RoundCornersSmooth(position, cornerCircleDistance, cornerCircleRadius); +#else + return (PointVsRoundedBox(position, cornerCircleDistance, cornerCircleRadius) < 0.0); +#endif + } +#endif + +#if defined(_IRIDESCENCE) + fixed3 Iridescence(float tangentDotIncident, sampler2D spectrumMap, float threshold, float2 uv, float angle, float intensity) + { + float k = tangentDotIncident * 0.5 + 0.5; + float4 left = tex2D(spectrumMap, float2(lerp(0.0, 1.0 - threshold, k), 0.5), float2(0.0, 0.0), float2(0.0, 0.0)); + float4 right = tex2D(spectrumMap, float2(lerp(threshold, 1.0, k), 0.5), float2(0.0, 0.0), float2(0.0, 0.0)); + + float2 XY = uv - float2(0.5, 0.5); + float s = (cos(angle) * XY.x - sin(angle) * XY.y) / cos(angle); + return (left.rgb + s * (right.rgb - left.rgb)) * intensity; + } +#endif + + v2f vert(appdata_t v) + { + v2f o; + UNITY_SETUP_INSTANCE_ID(v); + UNITY_INITIALIZE_OUTPUT(v2f, o); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + UNITY_TRANSFER_INSTANCE_ID(v, o); + + float4 vertexPosition = v.vertex; + +#if defined(_WORLD_POSITION) || defined(_VERTEX_EXTRUSION) + float3 worldVertexPosition = mul(unity_ObjectToWorld, vertexPosition).xyz; +#endif + +#if defined(_SCALE) + o.scale.x = length(mul(unity_ObjectToWorld, float4(1.0, 0.0, 0.0, 0.0))); + o.scale.y = length(mul(unity_ObjectToWorld, float4(0.0, 1.0, 0.0, 0.0))); +#if defined(_IGNORE_Z_SCALE) + o.scale.z = o.scale.x; +#else + o.scale.z = length(mul(unity_ObjectToWorld, float4(0.0, 0.0, 1.0, 0.0))); +#endif +#if !defined(_VERTEX_EXTRUSION_SMOOTH_NORMALS) + // uv3.y will contain a negative value when rendered by a UGUI and ScaleMeshEffect. + if (v.uv3.y < 0.0) + { + o.scale.x *= v.uv2.x; + o.scale.y *= v.uv2.y; + o.scale.z *= v.uv3.x; + } +#endif +#endif + + fixed3 localNormal = v.normal; + +#if defined(_NORMAL) || defined(_VERTEX_EXTRUSION) + fixed3 worldNormal = UnityObjectToWorldNormal(localNormal); +#endif + +#if defined(_VERTEX_EXTRUSION) +#if defined(_VERTEX_EXTRUSION_SMOOTH_NORMALS) + worldVertexPosition += UnityObjectToWorldNormal(v.uv2 * o.scale) * _VertexExtrusionValue; +#else + worldVertexPosition += worldNormal * _VertexExtrusionValue; +#endif + vertexPosition = mul(unity_WorldToObject, float4(worldVertexPosition, 1.0)); +#endif + + o.position = UnityObjectToClipPos(vertexPosition); + +#if defined(_WORLD_POSITION) + o.worldPosition.xyz = worldVertexPosition; +#endif + +#if defined(_LOCAL_POSITION) + o.localPosition.xyz = vertexPosition; +#endif + +#if defined(_NEAR_PLANE_FADE) + float rangeInverse = 1.0 / (_FadeBeginDistance - _FadeCompleteDistance); +#if defined(_NEAR_LIGHT_FADE) + float fadeDistance = _MaxNearLightDistance; + + [unroll] + for (int hoverLightIndex = 0; hoverLightIndex < HOVER_LIGHT_COUNT; ++hoverLightIndex) + { + int dataIndex = hoverLightIndex * HOVER_LIGHT_DATA_SIZE; + fadeDistance = min(fadeDistance, NearLightDistance(_HoverLightData[dataIndex], o.worldPosition)); + } + + [unroll] + for (int proximityLightIndex = 0; proximityLightIndex < PROXIMITY_LIGHT_COUNT; ++proximityLightIndex) + { + int dataIndex = proximityLightIndex * PROXIMITY_LIGHT_DATA_SIZE; + fadeDistance = min(fadeDistance, NearLightDistance(_ProximityLightData[dataIndex], o.worldPosition)); + } +#else + float fadeDistance = -UnityObjectToViewPos(vertexPosition).z; +#endif + o.worldPosition.w = max(saturate(mad(fadeDistance, rangeInverse, -_FadeCompleteDistance * rangeInverse)), _FadeMinValue); +#endif + +#if defined(_BORDER_LIGHT) || defined(_ROUND_CORNERS) + o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex); + + float minScale = min(min(o.scale.x, o.scale.y), o.scale.z); + +#if defined(_BORDER_LIGHT) + float maxScale = max(max(o.scale.x, o.scale.y), o.scale.z); + float minOverMiddleScale = minScale / (o.scale.x + o.scale.y + o.scale.z - minScale - maxScale); + + float areaYZ = o.scale.y * o.scale.z; + float areaXZ = o.scale.z * o.scale.x; + float areaXY = o.scale.x * o.scale.y; + + float borderWidth = _BorderWidth; +#endif + + if (abs(localNormal.x) == 1.0) // Y,Z plane. + { + o.scale.x = o.scale.z; + o.scale.y = o.scale.y; + +#if defined(_BORDER_LIGHT) + if (areaYZ > areaXZ && areaYZ > areaXY) + { + borderWidth *= minOverMiddleScale; + } +#endif + } + else if (abs(localNormal.y) == 1.0) // X,Z plane. + { + o.scale.x = o.scale.x; + o.scale.y = o.scale.z; + +#if defined(_BORDER_LIGHT) + if (areaXZ > areaXY && areaXZ > areaYZ) + { + borderWidth *= minOverMiddleScale; + } +#endif + } + else // X,Y plane. + { + o.scale.x = o.scale.x; + o.scale.y = o.scale.y; + +#if defined(_BORDER_LIGHT) + if (areaXY > areaYZ && areaXY > areaXZ) + { + borderWidth *= minOverMiddleScale; + } +#endif + } + + o.scale.z = minScale; + +#if defined(_BORDER_LIGHT) + float scaleRatio = min(o.scale.x, o.scale.y) / max(o.scale.x, o.scale.y); + o.uv.z = o.scale.x > o.scale.y ? 1.0 - (borderWidth * scaleRatio) : 1.0 - borderWidth; + o.uv.w = o.scale.x > o.scale.y ? 1.0 - borderWidth : 1.0 - (borderWidth * scaleRatio); +#endif +#elif defined(_UV) + o.uv = TRANSFORM_TEX(v.uv, _MainTex); +#endif + +#if defined(LIGHTMAP_ON) + o.lightMapUV.xy = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw; +#endif + +#if defined(_VERTEX_COLORS) + o.color = v.color; +#endif + +#if defined(_SPHERICAL_HARMONICS) + o.ambient = ShadeSH9(float4(worldNormal, 1.0)); +#endif + +#if defined(_IRIDESCENCE) + float3 rightTangent = normalize(mul((float3x3)unity_ObjectToWorld, float3(1.0, 0.0, 0.0))); + float3 incidentWithCenter = normalize(mul(unity_ObjectToWorld, float4(0.0, 0.0, 0.0, 1.0)) - _WorldSpaceCameraPos); + float tangentDotIncident = dot(rightTangent, incidentWithCenter); + o.iridescentColor = Iridescence(tangentDotIncident, _IridescentSpectrumMap, _IridescenceThreshold, v.uv, _IridescenceAngle, _IridescenceIntensity); +#endif + +#if defined(_NORMAL) +#if defined(_TRIPLANAR_MAPPING) + o.worldNormal = worldNormal; +#if defined(_LOCAL_SPACE_TRIPLANAR_MAPPING) + o.triplanarNormal = localNormal; + o.triplanarPosition = vertexPosition; +#else + o.triplanarNormal = worldNormal; + o.triplanarPosition = o.worldPosition; +#endif +#elif defined(_NORMAL_MAP) + fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz); + fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w; + fixed3 worldBitangent = cross(worldNormal, worldTangent) * tangentSign; + o.tangentX = fixed3(worldTangent.x, worldBitangent.x, worldNormal.x); + o.tangentY = fixed3(worldTangent.y, worldBitangent.y, worldNormal.y); + o.tangentZ = fixed3(worldTangent.z, worldBitangent.z, worldNormal.z); +#else + o.worldNormal = worldNormal; +#endif +#endif + + return o; + } + + fixed4 frag(v2f i, fixed facing : VFACE) : SV_Target + { + UNITY_SETUP_INSTANCE_ID(i); + +#if defined(_TRIPLANAR_MAPPING) + // Calculate triplanar uvs and apply texture scale and offset values like TRANSFORM_TEX. + fixed3 triplanarBlend = pow(abs(i.triplanarNormal), _TriplanarMappingBlendSharpness); + triplanarBlend /= dot(triplanarBlend, fixed3(1.0, 1.0, 1.0)); + float2 uvX = i.triplanarPosition.zy * _MainTex_ST.xy + _MainTex_ST.zw; + float2 uvY = i.triplanarPosition.xz * _MainTex_ST.xy + _MainTex_ST.zw; + float2 uvZ = i.triplanarPosition.xy * _MainTex_ST.xy + _MainTex_ST.zw; + + // Ternary operator is 2 instructions faster than sign() when we don't care about zero returning a zero sign. + float3 axisSign = i.triplanarNormal < 0 ? -1 : 1; + uvX.x *= axisSign.x; + uvY.x *= axisSign.y; + uvZ.x *= -axisSign.z; +#endif + + // Texturing. +#if defined(_DISABLE_ALBEDO_MAP) + fixed4 albedo = fixed4(1.0, 1.0, 1.0, 1.0); +#else +#if defined(_TRIPLANAR_MAPPING) + fixed4 albedo = tex2D(_MainTex, uvX) * triplanarBlend.x + + tex2D(_MainTex, uvY) * triplanarBlend.y + + tex2D(_MainTex, uvZ) * triplanarBlend.z; +#else +#if defined(_USE_SSAA) + // Does SSAA on the texture, implementation based off this article: https://medium.com/@bgolus/sharper-mipmapping-using-shader-based-supersampling-ed7aadb47bec + // per pixel screen space partial derivatives + float2 dx = ddx(i.uv.xy) * 0.25; // horizontal offset + float2 dy = ddy(i.uv.xy) * 0.25; // vertical offset + // supersampled 2x2 ordered grid + fixed4 albedo = 0; + albedo += tex2Dbias(_MainTex, float4(i.uv.xy + dx + dy, 0.0, _MipmapBias)); + albedo += tex2Dbias(_MainTex, float4(i.uv.xy - dx + dy, 0.0, _MipmapBias)); + albedo += tex2Dbias(_MainTex, float4(i.uv.xy + dx - dy, 0.0, _MipmapBias)); + albedo += tex2Dbias(_MainTex, float4(i.uv.xy - dx - dy, 0.0, _MipmapBias)); + albedo *= 0.25; +#else + fixed4 albedo = tex2D(_MainTex, i.uv); +#endif +#endif +#endif + + +#ifdef LIGHTMAP_ON + albedo.rgb *= DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, i.lightMapUV)); +#endif + +#if defined(_CHANNEL_MAP) + fixed4 channel = tex2D(_ChannelMap, i.uv); + _Metallic = channel.r; + albedo.rgb *= channel.g; + _Smoothness = channel.a; +#else +#if defined(_METALLIC_TEXTURE_ALBEDO_CHANNEL_A) + _Metallic = albedo.a; + albedo.a = 1.0; +#elif defined(_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A) + _Smoothness = albedo.a; + albedo.a = 1.0; +#endif +#endif + + // Primitive clipping. +#if defined(_CLIPPING_PRIMITIVE) + float primitiveDistance = 1.0; +#if defined(_CLIPPING_PLANE) + fixed clipPlaneSide = UNITY_ACCESS_INSTANCED_PROP(Props, _ClipPlaneSide); + float4 clipPlane = UNITY_ACCESS_INSTANCED_PROP(Props, _ClipPlane); + primitiveDistance = min(primitiveDistance, PointVsPlane(i.worldPosition.xyz, clipPlane) * clipPlaneSide); +#endif +#if defined(_CLIPPING_SPHERE) + fixed clipSphereSide = UNITY_ACCESS_INSTANCED_PROP(Props, _ClipSphereSide); + float4x4 clipSphereInverseTransform = UNITY_ACCESS_INSTANCED_PROP(Props, _ClipSphereInverseTransform); + primitiveDistance = min(primitiveDistance, PointVsSphere(i.worldPosition.xyz, clipSphereInverseTransform) * clipSphereSide); +#endif +#if defined(_CLIPPING_BOX) + fixed clipBoxSide = UNITY_ACCESS_INSTANCED_PROP(Props, _ClipBoxSide); + float4x4 clipBoxInverseTransform = UNITY_ACCESS_INSTANCED_PROP(Props, _ClipBoxInverseTransform); + primitiveDistance = min(primitiveDistance, PointVsBox(i.worldPosition.xyz, clipBoxInverseTransform) * clipBoxSide); +#endif +#if defined(_CLIPPING_BORDER) + fixed3 primitiveBorderColor = lerp(_ClippingBorderColor, fixed3(0.0, 0.0, 0.0), primitiveDistance / _ClippingBorderWidth); + albedo.rgb += primitiveBorderColor * (primitiveDistance < _ClippingBorderWidth ? 1.0 : 0.0); +#endif +#endif + +#if defined(_DISTANCE_TO_EDGE) + fixed2 distanceToEdge; + distanceToEdge.x = abs(i.uv.x - 0.5) * 2.0; + distanceToEdge.y = abs(i.uv.y - 0.5) * 2.0; +#endif + + // Rounded corner clipping. +#if defined(_ROUND_CORNERS) + float2 halfScale = i.scale.xy * 0.5; + float2 roundCornerPosition = distanceToEdge * halfScale; + + fixed currentCornerRadius; + +#if defined(_INDEPENDENT_CORNERS) + + _RoundCornersRadius = clamp(_RoundCornersRadius, 0, 0.5); + + if (i.uv.x < 0.5) + { + if (i.uv.y > 0.5) + { + currentCornerRadius = _RoundCornersRadius.x; + } + else + { + currentCornerRadius = _RoundCornersRadius.w; + } + } + else + { + if (i.uv.y > 0.5) + { + currentCornerRadius = _RoundCornersRadius.y; + } + else + { + currentCornerRadius = _RoundCornersRadius.z; + } + } +#else + currentCornerRadius = _RoundCornerRadius; +#endif + + float cornerCircleRadius = saturate(max(currentCornerRadius - _RoundCornerMargin, 0.01)) * i.scale.z; + + float2 cornerCircleDistance = halfScale - (_RoundCornerMargin * i.scale.z) - cornerCircleRadius; + + float roundCornerClip = RoundCorners(roundCornerPosition, cornerCircleDistance, cornerCircleRadius); +#endif + + albedo *= UNITY_ACCESS_INSTANCED_PROP(Props, _Color); + +#if defined(_VERTEX_COLORS) + albedo *= i.color; +#endif + +#if defined(_IRIDESCENCE) + albedo.rgb += i.iridescentColor; +#endif + + // Normal calculation. +#if defined(_NORMAL) + fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPosition.xyz)); +#if defined(_REFLECTIONS) || defined(_ENVIRONMENT_COLORING) + fixed3 incident = -worldViewDir; +#endif + fixed3 worldNormal; + +#if defined(_NORMAL_MAP) +#if defined(_TRIPLANAR_MAPPING) + fixed3 tangentNormalX = UnpackScaleNormal(tex2D(_NormalMap, uvX), _NormalMapScale); + fixed3 tangentNormalY = UnpackScaleNormal(tex2D(_NormalMap, uvY), _NormalMapScale); + fixed3 tangentNormalZ = UnpackScaleNormal(tex2D(_NormalMap, uvZ), _NormalMapScale); + tangentNormalX.x *= axisSign.x; + tangentNormalY.x *= axisSign.y; + tangentNormalZ.x *= -axisSign.z; + + // Swizzle world normals to match tangent space and apply Whiteout normal blend. + tangentNormalX = fixed3(tangentNormalX.xy + i.worldNormal.zy, tangentNormalX.z * i.worldNormal.x); + tangentNormalY = fixed3(tangentNormalY.xy + i.worldNormal.xz, tangentNormalY.z * i.worldNormal.y); + tangentNormalZ = fixed3(tangentNormalZ.xy + i.worldNormal.xy, tangentNormalZ.z * i.worldNormal.z); + + // Swizzle tangent normals to match world normal and blend together. + worldNormal = normalize(tangentNormalX.zyx * triplanarBlend.x + + tangentNormalY.xzy * triplanarBlend.y + + tangentNormalZ.xyz * triplanarBlend.z); +#else + fixed3 tangentNormal = UnpackScaleNormal(tex2D(_NormalMap, i.uv), _NormalMapScale); + worldNormal.x = dot(i.tangentX, tangentNormal); + worldNormal.y = dot(i.tangentY, tangentNormal); + worldNormal.z = dot(i.tangentZ, tangentNormal); + worldNormal = normalize(worldNormal) * facing; +#endif +#else + worldNormal = normalize(i.worldNormal) * facing; +#endif +#endif + + fixed pointToLight = 1.0; + fixed3 fluentLightColor = fixed3(0.0, 0.0, 0.0); + + // Hover light. +#if defined(_HOVER_LIGHT) + pointToLight = 0.0; + + [unroll] + for (int hoverLightIndex = 0; hoverLightIndex < HOVER_LIGHT_COUNT; ++hoverLightIndex) + { + int dataIndex = hoverLightIndex * HOVER_LIGHT_DATA_SIZE; + fixed hoverValue = HoverLight(_HoverLightData[dataIndex], _HoverLightData[dataIndex + 1].w, i.worldPosition.xyz); + pointToLight += hoverValue; +#if !defined(_HOVER_COLOR_OVERRIDE) + fluentLightColor += lerp(fixed3(0.0, 0.0, 0.0), _HoverLightData[dataIndex + 1].rgb, hoverValue); +#endif + } +#if defined(_HOVER_COLOR_OVERRIDE) + fluentLightColor = _HoverColorOverride.rgb * pointToLight; +#endif +#endif + + // Proximity light. +#if defined(_PROXIMITY_LIGHT) +#if !defined(_HOVER_LIGHT) + pointToLight = 0.0; +#endif + [unroll] + for (int proximityLightIndex = 0; proximityLightIndex < PROXIMITY_LIGHT_COUNT; ++proximityLightIndex) + { + int dataIndex = proximityLightIndex * PROXIMITY_LIGHT_DATA_SIZE; + fixed colorValue; + fixed proximityValue = ProximityLight(_ProximityLightData[dataIndex], _ProximityLightData[dataIndex + 1], _ProximityLightData[dataIndex + 2], i.worldPosition.xyz, worldNormal, colorValue); + pointToLight += proximityValue; +#if defined(_PROXIMITY_LIGHT_COLOR_OVERRIDE) + fixed3 proximityColor = MixProximityLightColor(_ProximityLightCenterColorOverride, _ProximityLightMiddleColorOverride, _ProximityLightOuterColorOverride, colorValue); +#else + fixed3 proximityColor = MixProximityLightColor(_ProximityLightData[dataIndex + 3], _ProximityLightData[dataIndex + 4], _ProximityLightData[dataIndex + 5], colorValue); +#endif +#if defined(_PROXIMITY_LIGHT_SUBTRACTIVE) + fluentLightColor -= lerp(fixed3(0.0, 0.0, 0.0), proximityColor, proximityValue); +#else + fluentLightColor += lerp(fixed3(0.0, 0.0, 0.0), proximityColor, proximityValue); +#endif + } +#endif + + // Border light. +#if defined(_BORDER_LIGHT) + fixed borderValue; +#if defined(_ROUND_CORNERS) + fixed borderMargin = _RoundCornerMargin + _BorderWidth * 0.5; + + cornerCircleRadius = saturate(max(currentCornerRadius - borderMargin, 0.01)) * i.scale.z; + + cornerCircleDistance = halfScale - (borderMargin * i.scale.z) - cornerCircleRadius; + + borderValue = 1.0 - RoundCornersSmooth(roundCornerPosition, cornerCircleDistance, cornerCircleRadius); +#else + borderValue = max(smoothstep(i.uv.z - _EdgeSmoothingValue, i.uv.z + _EdgeSmoothingValue, distanceToEdge.x), + smoothstep(i.uv.w - _EdgeSmoothingValue, i.uv.w + _EdgeSmoothingValue, distanceToEdge.y)); +#endif +#if defined(_HOVER_LIGHT) && defined(_BORDER_LIGHT_USES_HOVER_COLOR) && defined(_HOVER_COLOR_OVERRIDE) + fixed3 borderColor = _HoverColorOverride.rgb; +#else + fixed3 borderColor = fixed3(1.0, 1.0, 1.0); +#endif + fixed3 borderContribution = borderColor * borderValue * _BorderMinValue * _FluentLightIntensity; +#if defined(_BORDER_LIGHT_REPLACES_ALBEDO) + albedo.rgb = lerp(albedo.rgb, borderContribution, borderValue); +#else + albedo.rgb += borderContribution; +#endif +#if defined(_HOVER_LIGHT) || defined(_PROXIMITY_LIGHT) + albedo.rgb += (fluentLightColor * borderValue * pointToLight * _FluentLightIntensity) * 2.0; +#endif +#if defined(_BORDER_LIGHT_OPAQUE) + albedo.a = max(albedo.a, borderValue * _BorderLightOpaqueAlpha); +#endif +#endif + +#if defined(_ROUND_CORNERS) + albedo *= roundCornerClip; + pointToLight *= roundCornerClip; +#endif + +#ifdef UNITY_UI_CLIP_RECT + albedo.a *= UnityGet2DClipping(i.localPosition.xy, _ClipRect); +#endif + +#if defined(_ALPHA_CLIP) +#if !defined(_ALPHATEST_ON) + _Cutoff = 0.5; +#endif +#if defined(_CLIPPING_PRIMITIVE) + albedo *= (primitiveDistance > 0.0); +#endif + clip(albedo.a - _Cutoff); + albedo.a = 1.0; +#endif + + // Blinn phong lighting. +#if defined(_DIRECTIONAL_LIGHT) +#if defined(_RENDER_PIPELINE) + float4 directionalLightDirection = _MainLightPosition; +#else + float4 directionalLightDirection = _WorldSpaceLightPos0; +#endif + fixed diffuse = max(0.0, dot(worldNormal, directionalLightDirection)); +#if defined(_SPECULAR_HIGHLIGHTS) + fixed halfVector = max(0.0, dot(worldNormal, normalize(directionalLightDirection + worldViewDir))); + fixed specular = saturate(pow(halfVector, _Shininess * pow(_Smoothness, 4.0)) * (_Smoothness * 2.0) * _Metallic); +#else + fixed specular = 0.0; +#endif +#endif + + // Image based lighting (attempt to mimic the Standard shader). +#if defined(_REFLECTIONS) + fixed3 worldReflection = reflect(incident, worldNormal); + fixed4 iblData = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, worldReflection, (1.0 - _Smoothness) * UNITY_SPECCUBE_LOD_STEPS); + fixed3 ibl = DecodeHDR(iblData, unity_SpecCube0_HDR); +#if defined(_REFRACTION) + fixed4 refractColor = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, refract(incident, worldNormal, _RefractiveIndex)); + ibl *= DecodeHDR(refractColor, unity_SpecCube0_HDR); +#endif +#else + fixed3 ibl = unity_IndirectSpecColor.rgb; +#endif + + // Fresnel lighting. +#if defined(_FRESNEL) + fixed fresnel = 1.0 - saturate(abs(dot(worldViewDir, worldNormal))); +#if defined(_RIM_LIGHT) + fixed3 fresnelColor = _RimColor * pow(fresnel, _RimPower); +#else + fixed3 fresnelColor = unity_IndirectSpecColor.rgb * (pow(fresnel, _FresnelPower) * max(_Smoothness, 0.5)); +#endif +#endif + // Final lighting mix. + fixed4 output = albedo; +#if defined(_SPHERICAL_HARMONICS) + fixed3 ambient = i.ambient; +#else + fixed3 ambient = glstate_lightmodel_ambient + fixed3(0.25, 0.25, 0.25); +#endif + fixed minProperty = min(_Smoothness, _Metallic); +#if defined(_DIRECTIONAL_LIGHT) + fixed oneMinusMetallic = (1.0 - _Metallic); + output.rgb = lerp(output.rgb, ibl, minProperty); +#if defined(_RENDER_PIPELINE) + fixed3 directionalLightColor = _MainLightColor.rgb; +#else + fixed3 directionalLightColor = _LightColor0.rgb; +#endif + output.rgb *= lerp((ambient + directionalLightColor * diffuse + directionalLightColor * specular) * max(oneMinusMetallic, _MinMetallicLightContribution), albedo, minProperty); + output.rgb += (directionalLightColor * albedo * specular) + (directionalLightColor * specular * _Smoothness); + output.rgb += ibl * oneMinusMetallic * _IblContribution; +#elif defined(_REFLECTIONS) + output.rgb = lerp(output.rgb, ibl, minProperty); + output.rgb *= lerp(ambient, albedo, minProperty); +#elif defined(_SPHERICAL_HARMONICS) + output.rgb *= ambient; +#endif + +#if defined(_FRESNEL) +#if defined(_RIM_LIGHT) || !defined(_REFLECTIONS) + output.rgb += fresnelColor; +#else + output.rgb += fresnelColor * (1.0 - minProperty); +#endif +#endif + +#if defined(_EMISSION) +#if defined(_CHANNEL_MAP) + output.rgb += _EmissiveColor * channel.b; +#else + output.rgb += _EmissiveColor; +#endif +#endif + + // Inner glow. +#if defined(_INNER_GLOW) + fixed2 uvGlow = pow(distanceToEdge * _InnerGlowColor.a, _InnerGlowPower); + output.rgb += lerp(fixed3(0.0, 0.0, 0.0), _InnerGlowColor.rgb, uvGlow.x + uvGlow.y); +#endif + + // Environment coloring. +#if defined(_ENVIRONMENT_COLORING) + fixed3 environmentColor = incident.x * incident.x * _EnvironmentColorX + + incident.y * incident.y * _EnvironmentColorY + + incident.z * incident.z * _EnvironmentColorZ; + output.rgb += environmentColor * max(0.0, dot(incident, worldNormal) + _EnvironmentColorThreshold) * _EnvironmentColorIntensity; + +#endif + +#if defined(_NEAR_PLANE_FADE) + output *= i.worldPosition.w; +#endif + + // Hover and proximity lighting should occur after near plane fading. +#if defined(_HOVER_LIGHT) || defined(_PROXIMITY_LIGHT) + output.rgb += fluentLightColor * _FluentLightIntensity * pointToLight; +#endif + + // Perform non-alpha clipped primitive clipping on the final output. +#if defined(_CLIPPING_PRIMITIVE) && !defined(_ALPHA_CLIP) + output *= saturate(primitiveDistance * (1.0f / _BlendedClippingWidth)); +#endif + return output; + } + + ENDCG + } + + // Extracts information for lightmapping, GI (emission, albedo, ...) + // This pass it not used during regular rendering. + Pass + { + Name "Meta" + Tags { "LightMode" = "Meta" } + + CGPROGRAM + + #pragma vertex vert + #pragma fragment frag + + #pragma shader_feature EDITOR_VISUALIZATION + #pragma shader_feature _EMISSION + #pragma shader_feature _CHANNEL_MAP + + #include "UnityCG.cginc" + #include "UnityMetaPass.cginc" + + // This define will get commented in by the UpgradeShaderForUniversalRenderPipeline method. + //#define _RENDER_PIPELINE + + struct v2f + { + float4 vertex : SV_POSITION; + float2 uv : TEXCOORD0; + }; + + float4 _MainTex_ST; + + v2f vert(appdata_full v) + { + v2f o; + o.vertex = UnityMetaVertexPosition(v.vertex, v.texcoord1.xy, v.texcoord2.xy, unity_LightmapST, unity_DynamicLightmapST); + o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); + + return o; + } + + sampler2D _MainTex; + sampler2D _ChannelMap; + + fixed4 _Color; + fixed4 _EmissiveColor; + +#if defined(_RENDER_PIPELINE) + CBUFFER_START(_LightBuffer) + float4 _MainLightPosition; + half4 _MainLightColor; + CBUFFER_END +#else + fixed4 _LightColor0; +#endif + + half4 frag(v2f i) : SV_Target + { + UnityMetaInput output; + UNITY_INITIALIZE_OUTPUT(UnityMetaInput, output); + + output.Albedo = tex2D(_MainTex, i.uv) * _Color; +#if defined(_EMISSION) +#if defined(_CHANNEL_MAP) + output.Emission += tex2D(_ChannelMap, i.uv).b * _EmissiveColor; +#else + output.Emission += _EmissiveColor; +#endif +#endif +#if defined(_RENDER_PIPELINE) + output.SpecularColor = _MainLightColor.rgb; +#else + output.SpecularColor = _LightColor0.rgb; +#endif + + return UnityMetaFragment(output); + } + ENDCG + } + } + + Fallback "Hidden/InternalErrorShader" + CustomEditor "Microsoft.MixedReality.Toolkit.Editor.MixedRealityStandardShaderGUI" +} diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityStandard.shader.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityStandard.shader.meta new file mode 100644 index 00000000..7b6bb008 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityStandard.shader.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 5bdea20278144b11916d77503ba1467a +timeCreated: 1519154700 +licenseType: Pro +ShaderImporter: + externalObjects: {} + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityTextMeshPro.shader b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityTextMeshPro.shader new file mode 100644 index 00000000..078e5d6c --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityTextMeshPro.shader @@ -0,0 +1,377 @@ +// TextMesh Pro copyright © 2021 Unity Technologies ApS +// Licensed under the Unity Companion License for Unity-dependent projects--see http://www.unity3d.com/legal/licenses/Unity_Companion_License. +// Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Please review the license for details on these and other terms and conditions. + +// NOTE: MRTK Shaders are versioned via the MRTK.Shaders.sentinel file. +// When making changes to any shader's source file, the value in the sentinel _must_ be incremented. + +// Simplified SDF shader: +// - No Shading Option (bevel / bump / env map) +// - No Glow Option +// - Softness is applied on both side of the outline + +// MRTK Additions +// - Single Pass Instanced Stereo Rendering Support +// - Support for Clipping Primitives (Plane, Sphere, Box) +// - ZWrite Property + +Shader "Mixed Reality Toolkit/TextMeshPro" { + +Properties { + _FaceColor ("Face Color", Color) = (1,1,1,1) + _FaceDilate ("Face Dilate", Range(-1,1)) = 0 + + _OutlineColor ("Outline Color", Color) = (0,0,0,1) + _OutlineWidth ("Outline Thickness", Range(0,1)) = 0 + _OutlineSoftness ("Outline Softness", Range(0,1)) = 0 + + _UnderlayColor ("Border Color", Color) = (0,0,0,.5) + _UnderlayOffsetX ("Border OffsetX", Range(-1,1)) = 0 + _UnderlayOffsetY ("Border OffsetY", Range(-1,1)) = 0 + _UnderlayDilate ("Border Dilate", Range(-1,1)) = 0 + _UnderlaySoftness ("Border Softness", Range(0,1)) = 0 + + _WeightNormal ("Weight Normal", float) = 0 + _WeightBold ("Weight Bold", float) = .5 + + _ShaderFlags ("Flags", float) = 0 + _ScaleRatioA ("Scale RatioA", float) = 1 + _ScaleRatioB ("Scale RatioB", float) = 1 + _ScaleRatioC ("Scale RatioC", float) = 1 + + _MainTex ("Font Atlas", 2D) = "white" {} + _TextureWidth ("Texture Width", float) = 512 + _TextureHeight ("Texture Height", float) = 512 + _GradientScale ("Gradient Scale", float) = 5 + _ScaleX ("Scale X", float) = 1 + _ScaleY ("Scale Y", float) = 1 + _PerspectiveFilter ("Perspective Correction", Range(0, 1)) = 0.875 + _Sharpness ("Sharpness", Range(-1,1)) = 0 + + _VertexOffsetX ("Vertex OffsetX", float) = 0 + _VertexOffsetY ("Vertex OffsetY", float) = 0 + + _ClipRect ("Clip Rect", vector) = (-32767, -32767, 32767, 32767) + _MaskSoftnessX ("Mask SoftnessX", float) = 0 + _MaskSoftnessY ("Mask SoftnessY", float) = 0 + + _StencilComp ("Stencil Comparison", Float) = 8 + _Stencil ("Stencil ID", Float) = 0 + _StencilOp ("Stencil Operation", Float) = 0 + _StencilWriteMask ("Stencil Write Mask", Float) = 255 + _StencilReadMask ("Stencil Read Mask", Float) = 255 + + _ColorMask ("Color Mask", Float) = 15 + _ZWrite ("Depth Write", Float) = 0 +} + +SubShader { + Tags + { + "Queue"="Transparent" + "IgnoreProjector"="True" + "RenderType"="Transparent" + } + + + Stencil + { + Ref [_Stencil] + Comp [_StencilComp] + Pass [_StencilOp] + ReadMask [_StencilReadMask] + WriteMask [_StencilWriteMask] + } + + Cull [_CullMode] + ZWrite[_ZWrite] + Lighting Off + Fog { Mode Off } + ZTest [unity_GUIZTestMode] + Blend One OneMinusSrcAlpha + ColorMask [_ColorMask] + + Pass { + CGPROGRAM + #pragma vertex VertShader + #pragma fragment PixShader + #pragma shader_feature __ OUTLINE_ON + #pragma shader_feature __ UNDERLAY_ON UNDERLAY_INNER + + #pragma multi_compile __ UNITY_UI_CLIP_RECT + #pragma multi_compile __ UNITY_UI_ALPHACLIP + + #pragma multi_compile __ _CLIPPING_PLANE _CLIPPING_SPHERE _CLIPPING_BOX + + #include "UnityCG.cginc" + #include "UnityUI.cginc" + #include "MixedRealityShaderUtils.cginc" + +#if defined(_CLIPPING_PLANE) || defined(_CLIPPING_SPHERE) || defined(_CLIPPING_BOX) + #define _CLIPPING_PRIMITIVE +#else + #undef _CLIPPING_PRIMITIVE +#endif + + // Direct include for portability. + //#include "TMPro_Properties.cginc" + // UI Editable properties + uniform sampler2D _FaceTex; // Alpha : Signed Distance + uniform float _FaceUVSpeedX; + uniform float _FaceUVSpeedY; + uniform fixed4 _FaceColor; // RGBA : Color + Opacity + uniform float _FaceDilate; // v[ 0, 1] + uniform float _OutlineSoftness; // v[ 0, 1] + + uniform sampler2D _OutlineTex; // RGBA : Color + Opacity + uniform float _OutlineUVSpeedX; + uniform float _OutlineUVSpeedY; + uniform fixed4 _OutlineColor; // RGBA : Color + Opacity + uniform float _OutlineWidth; // v[ 0, 1] + + uniform float _Bevel; // v[ 0, 1] + uniform float _BevelOffset; // v[-1, 1] + uniform float _BevelWidth; // v[-1, 1] + uniform float _BevelClamp; // v[ 0, 1] + uniform float _BevelRoundness; // v[ 0, 1] + + uniform sampler2D _BumpMap; // Normal map + uniform float _BumpOutline; // v[ 0, 1] + uniform float _BumpFace; // v[ 0, 1] + + uniform samplerCUBE _Cube; // Cube / sphere map + uniform fixed4 _ReflectFaceColor; // RGB intensity + uniform fixed4 _ReflectOutlineColor; + uniform float3 _EnvMatrixRotation; + uniform float4x4 _EnvMatrix; + + uniform fixed4 _SpecularColor; // RGB intensity + uniform float _LightAngle; // v[ 0,Tau] + uniform float _SpecularPower; // v[ 0, 1] + uniform float _Reflectivity; // v[ 5, 15] + uniform float _Diffuse; // v[ 0, 1] + uniform float _Ambient; // v[ 0, 1] + + uniform fixed4 _UnderlayColor; // RGBA : Color + Opacity + uniform float _UnderlayOffsetX; // v[-1, 1] + uniform float _UnderlayOffsetY; // v[-1, 1] + uniform float _UnderlayDilate; // v[-1, 1] + uniform float _UnderlaySoftness; // v[ 0, 1] + + uniform fixed4 _GlowColor; // RGBA : Color + Intensity + uniform float _GlowOffset; // v[-1, 1] + uniform float _GlowOuter; // v[ 0, 1] + uniform float _GlowInner; // v[ 0, 1] + uniform float _GlowPower; // v[ 1, 1/(1+4*4)] + + // API Editable properties + uniform float _ShaderFlags; + uniform float _WeightNormal; + uniform float _WeightBold; + + uniform float _ScaleRatioA; + uniform float _ScaleRatioB; + uniform float _ScaleRatioC; + + uniform float _VertexOffsetX; + uniform float _VertexOffsetY; + + uniform float _MaskID; + uniform sampler2D _MaskTex; + uniform float4 _MaskCoord; + uniform float4 _ClipRect; // bottom left(x,y) : top right(z,w) + + uniform float _MaskSoftnessX; + uniform float _MaskSoftnessY; + + // Font Atlas properties + uniform sampler2D _MainTex; + uniform float _TextureWidth; + uniform float _TextureHeight; + uniform float _GradientScale; + uniform float _ScaleX; + uniform float _ScaleY; + uniform float _PerspectiveFilter; + uniform float _Sharpness; + +#if defined(_CLIPPING_PLANE) + fixed _ClipPlaneSide; + float4 _ClipPlane; +#endif + +#if defined(_CLIPPING_SPHERE) + fixed _ClipSphereSide; + float4x4 _ClipSphereInverseTransform; +#endif + +#if defined(_CLIPPING_BOX) + fixed _ClipBoxSide; + float4x4 _ClipBoxInverseTransform; +#endif + + struct vertex_t { + UNITY_VERTEX_INPUT_INSTANCE_ID + float4 vertex : POSITION; + float3 normal : NORMAL; + fixed4 color : COLOR; + float2 texcoord0 : TEXCOORD0; + float2 texcoord1 : TEXCOORD1; + }; + + struct pixel_t { + UNITY_VERTEX_INPUT_INSTANCE_ID + UNITY_VERTEX_OUTPUT_STEREO + float4 vertex : SV_POSITION; + fixed4 faceColor : COLOR; + fixed4 outlineColor : COLOR1; + float4 texcoord0 : TEXCOORD0; // Texture UV, Mask UV + half4 param : TEXCOORD1; // Scale(x), BiasIn(y), BiasOut(z), Bias(w) + half4 mask : TEXCOORD2; // Position in clip space(xy), Softness(zw) + #if (UNDERLAY_ON | UNDERLAY_INNER) + float4 texcoord1 : TEXCOORD3; // Texture UV, alpha, reserved + half2 underlayParam : TEXCOORD4; // Scale(x), Bias(y) + #endif +#if defined(_CLIPPING_PRIMITIVE) + float3 worldPosition : TEXCOORD5; +#endif + }; + + + pixel_t VertShader(vertex_t input) + { + pixel_t output; + + UNITY_INITIALIZE_OUTPUT(pixel_t, output); + UNITY_SETUP_INSTANCE_ID(input); + UNITY_TRANSFER_INSTANCE_ID(input, output); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); + + float bold = step(input.texcoord1.y, 0); + + float4 vert = input.vertex; + vert.x += _VertexOffsetX; + vert.y += _VertexOffsetY; + float4 vPosition = UnityObjectToClipPos(vert); + + float2 pixelSize = vPosition.w; + pixelSize /= float2(_ScaleX, _ScaleY) * abs(mul((float2x2)UNITY_MATRIX_P, _ScreenParams.xy)); + + float scale = rsqrt(dot(pixelSize, pixelSize)); + scale *= abs(input.texcoord1.y) * _GradientScale * (_Sharpness + 1); + if(UNITY_MATRIX_P[3][3] == 0) scale = lerp(abs(scale) * (1 - _PerspectiveFilter), scale, abs(dot(UnityObjectToWorldNormal(input.normal.xyz), normalize(WorldSpaceViewDir(vert))))); + + float weight = lerp(_WeightNormal, _WeightBold, bold) / 4.0; + weight = (weight + _FaceDilate) * _ScaleRatioA * 0.5; + + float layerScale = scale; + + scale /= 1 + (_OutlineSoftness * _ScaleRatioA * scale); + float bias = (0.5 - weight) * scale - 0.5; + float outline = _OutlineWidth * _ScaleRatioA * 0.5 * scale; + + float opacity = input.color.a; + #if (UNDERLAY_ON | UNDERLAY_INNER) + opacity = 1.0; + #endif + + fixed4 faceColor = fixed4(input.color.rgb, opacity) * _FaceColor; + faceColor.rgb *= faceColor.a; + + fixed4 outlineColor = _OutlineColor; + outlineColor.a *= opacity; + outlineColor.rgb *= outlineColor.a; + outlineColor = lerp(faceColor, outlineColor, sqrt(min(1.0, (outline * 2)))); + + #if (UNDERLAY_ON | UNDERLAY_INNER) + layerScale /= 1 + ((_UnderlaySoftness * _ScaleRatioC) * layerScale); + float layerBias = (.5 - weight) * layerScale - .5 - ((_UnderlayDilate * _ScaleRatioC) * .5 * layerScale); + + float x = -(_UnderlayOffsetX * _ScaleRatioC) * _GradientScale / _TextureWidth; + float y = -(_UnderlayOffsetY * _ScaleRatioC) * _GradientScale / _TextureHeight; + float2 layerOffset = float2(x, y); + #endif + + // Generate UV for the Masking Texture + float4 clampedRect = clamp(_ClipRect, -2e10, 2e10); + float2 maskUV = (vert.xy - clampedRect.xy) / (clampedRect.zw - clampedRect.xy); + + // Populate structure for pixel shader + output.vertex = vPosition; + output.faceColor = faceColor; + output.outlineColor = outlineColor; + output.texcoord0 = float4(input.texcoord0.x, input.texcoord0.y, maskUV.x, maskUV.y); + output.param = half4(scale, bias - outline, bias + outline, bias); + output.mask = half4(vert.xy * 2 - clampedRect.xy - clampedRect.zw, 0.25 / (0.25 * half2(_MaskSoftnessX, _MaskSoftnessY) + pixelSize.xy)); + #if (UNDERLAY_ON || UNDERLAY_INNER) + output.texcoord1 = float4(input.texcoord0 + layerOffset, input.color.a, 0); + output.underlayParam = half2(layerScale, layerBias); + #endif +#if defined(_CLIPPING_PRIMITIVE) + output.worldPosition = mul(unity_ObjectToWorld, vert).xyz; +#endif + + return output; + } + + + // PIXEL SHADER + fixed4 PixShader(pixel_t input) : SV_Target + { + UNITY_SETUP_INSTANCE_ID(input); + + half d = tex2D(_MainTex, input.texcoord0.xy).a * input.param.x; + half4 c = input.faceColor * saturate(d - input.param.w); + + #ifdef OUTLINE_ON + c = lerp(input.outlineColor, input.faceColor, saturate(d - input.param.z)); + c *= saturate(d - input.param.y); + #endif + + #if UNDERLAY_ON + d = tex2D(_MainTex, input.texcoord1.xy).a * input.underlayParam.x; + c += float4(_UnderlayColor.rgb * _UnderlayColor.a, _UnderlayColor.a) * saturate(d - input.underlayParam.y) * (1 - c.a); + #endif + + #if UNDERLAY_INNER + half sd = saturate(d - input.param.z); + d = tex2D(_MainTex, input.texcoord1.xy).a * input.underlayParam.x; + c += float4(_UnderlayColor.rgb * _UnderlayColor.a, _UnderlayColor.a) * (1 - saturate(d - input.underlayParam.y)) * sd * (1 - c.a); + #endif + + // Alternative implementation to UnityGet2DClipping with support for softness. + #if UNITY_UI_CLIP_RECT + half2 m = saturate((_ClipRect.zw - _ClipRect.xy - abs(input.mask.xy)) * input.mask.zw); + c *= m.x * m.y; + #endif + + #if (UNDERLAY_ON | UNDERLAY_INNER) + c *= input.texcoord1.z; + #endif + + // Primitive clipping. +#if defined(_CLIPPING_PRIMITIVE) + float primitiveDistance = 1.0; +#if defined(_CLIPPING_PLANE) + primitiveDistance = min(primitiveDistance, PointVsPlane(input.worldPosition, _ClipPlane) * _ClipPlaneSide); +#endif +#if defined(_CLIPPING_SPHERE) + primitiveDistance = min(primitiveDistance, PointVsSphere(input.worldPosition, _ClipSphereInverseTransform) * _ClipSphereSide); +#endif +#if defined(_CLIPPING_BOX) + primitiveDistance = min(primitiveDistance, PointVsBox(input.worldPosition, _ClipBoxInverseTransform) * _ClipBoxSide); +#endif + c *= step(0.0, primitiveDistance); +#endif + + #if UNITY_UI_ALPHACLIP + clip(c.a - 0.001); + #endif + + return c; + } + ENDCG + } +} + +CustomEditor "Microsoft.MixedReality.Toolkit.Editor.MixedRealityTextMeshProShaderGUI" +} diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityTextMeshPro.shader.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityTextMeshPro.shader.meta new file mode 100644 index 00000000..284d80fe --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityTextMeshPro.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 1c504b73bf66872479cd1215fb5ce0fe +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityTextMeshProSprite.shader b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityTextMeshProSprite.shader new file mode 100644 index 00000000..8aaa5411 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityTextMeshProSprite.shader @@ -0,0 +1,184 @@ +// TextMesh Pro copyright © 2021 Unity Technologies ApS +// Licensed under the Unity Companion License for Unity-dependent projects--see http://www.unity3d.com/legal/licenses/Unity_Companion_License. +// Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Please review the license for details on these and other terms and conditions. + +// NOTE: MRTK Shaders are versioned via the MRTK.Shaders.sentinel file. +// When making changes to any shader's source file, the value in the sentinel _must_ be incremented. + +// Text Mesh Pro Sprite shader with MRTK Additions + +// MRTK Additions +// - Single Pass Instanced Stereo Rendering Support +// - Support for Clipping Primitives (Plane, Sphere, Box) +// - Added to MRTK namespace + +Shader "Mixed Reality Toolkit/TextMeshProSprite" { + +Properties { + _MainTex ("Sprite Texture", 2D) = "white" {} + _Color ("Tint", Color) = (1,1,1,1) + + _StencilComp ("Stencil Comparison", Float) = 8 + _Stencil ("Stencil ID", Float) = 0 + _StencilOp ("Stencil Operation", Float) = 0 + _StencilWriteMask ("Stencil Write Mask", Float) = 255 + _StencilReadMask ("Stencil Read Mask", Float) = 255 + + _CullMode ("Cull Mode", Float) = 0 + _ColorMask ("Color Mask", Float) = 15 + _ClipRect ("Clip Rect", vector) = (-32767, -32767, 32767, 32767) + + [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0 +} + +SubShader { + Tags + { + "Queue"="Transparent" + "IgnoreProjector"="True" + "RenderType"="Transparent" + "PreviewType"="Plane" + "CanUseSpriteAtlas"="True" + } + + Stencil { + Ref [_Stencil] + Comp [_StencilComp] + Pass [_StencilOp] + ReadMask [_StencilReadMask] + WriteMask [_StencilWriteMask] + } + + Cull [_CullMode] + Lighting Off + ZWrite Off + ZTest [unity_GUIZTestMode] + Blend SrcAlpha OneMinusSrcAlpha + ColorMask [_ColorMask] + + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + #pragma multi_compile __ UNITY_UI_CLIP_RECT + #pragma multi_compile __ UNITY_UI_ALPHACLIP + + #pragma multi_compile __ _CLIPPING_PLANE _CLIPPING_SPHERE _CLIPPING_BOX + + #include "UnityCG.cginc" + #include "UnityUI.cginc" + #include "MixedRealityShaderUtils.cginc" + +#if defined(_CLIPPING_PLANE) || defined(_CLIPPING_SPHERE) || defined(_CLIPPING_BOX) + #define _CLIPPING_PRIMITIVE +#else + #undef _CLIPPING_PRIMITIVE +#endif + +#if defined(_CLIPPING_PLANE) + fixed _ClipPlaneSide; + float4 _ClipPlane; +#endif + +#if defined(_CLIPPING_SPHERE) + fixed _ClipSphereSide; + float4x4 _ClipSphereInverseTransform; +#endif + +#if defined(_CLIPPING_BOX) + fixed _ClipBoxSide; + float4x4 _ClipBoxInverseTransform; +#endif + + uniform float _VertexOffsetX; + uniform float _VertexOffsetY; + + struct appdata_t { + + float4 vertex : POSITION; + float4 color : COLOR; + float2 texcoord : TEXCOORD0; + UNITY_VERTEX_INPUT_INSTANCE_ID + }; + + struct v2f { + + float4 vertex : SV_POSITION; + fixed4 color : COLOR; + half2 texcoord : TEXCOORD0; + float3 worldPosition : TEXCOORD1; + + UNITY_VERTEX_INPUT_INSTANCE_ID + UNITY_VERTEX_OUTPUT_STEREO + }; + + fixed4 _Color; + fixed4 _TextureSampleAdd; + float4 _ClipRect; + + v2f vert(appdata_t IN) + { + v2f OUT; + + UNITY_SETUP_INSTANCE_ID(IN); + UNITY_TRANSFER_INSTANCE_ID(IN, OUT); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT); + + OUT.worldPosition = IN.vertex; + OUT.vertex = UnityObjectToClipPos(OUT.worldPosition); + + OUT.texcoord = IN.texcoord; + + float4 vertin = IN.vertex; + vertin.x += _VertexOffsetX; + vertin.y += _VertexOffsetY; + float4 vPosition = UnityObjectToClipPos(vertin); + +#ifdef UNITY_HALF_TEXEL_OFFSET + OUT.vertex.xy += (_ScreenParams.zw-1.0)*float2(-1,1); +#endif + + OUT.color = IN.color * _Color; +#if defined(_CLIPPING_PRIMITIVE) + OUT.worldPosition = mul(unity_ObjectToWorld, vertin).xyz; +#endif + + return OUT; + } + + sampler2D _MainTex; + + fixed4 frag(v2f IN) : SV_Target + { + half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color; + +#if UNITY_UI_CLIP_RECT + color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect); +#endif + + // Primitive clipping. +#if defined(_CLIPPING_PRIMITIVE) + float primitiveDistance = 1.0; +#if defined(_CLIPPING_PLANE) + primitiveDistance = min(primitiveDistance, PointVsPlane(IN.worldPosition, _ClipPlane) * _ClipPlaneSide); +#endif +#if defined(_CLIPPING_SPHERE) + primitiveDistance = min(primitiveDistance, PointVsSphere(IN.worldPosition, _ClipSphereInverseTransform) * _ClipSphereSide); +#endif +#if defined(_CLIPPING_BOX) + primitiveDistance = min(primitiveDistance, PointVsBox(IN.worldPosition, _ClipBoxInverseTransform) * _ClipBoxSide); +#endif + color *= step(0.0, primitiveDistance); +#endif + +#ifdef UNITY_UI_ALPHACLIP + clip (color.a - 0.001); +#endif + + return color; + } + ENDCG + } + } +} \ No newline at end of file diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityTextMeshProSprite.shader.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityTextMeshProSprite.shader.meta new file mode 100644 index 00000000..b76d3b66 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/MixedRealityTextMeshProSprite.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f11fd341db238f342a8b36d23162d67a +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/Text3DShader.shader b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/Text3DShader.shader new file mode 100644 index 00000000..a89716fe --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/Text3DShader.shader @@ -0,0 +1,180 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// NOTE: MRTK Shaders are versioned via the MRTK.Shaders.sentinel file. +// When making changes to any shader's source file, the value in the sentinel _must_ be incremented. + +/// +/// Basic 3D TextMesh shader with proper z-sorting and culling options. +/// +Shader "Mixed Reality Toolkit/Text3DShader" +{ + Properties + { + _MainTex("Alpha (A)", 2D) = "white" {} + [Enum(UnityEngine.Rendering.CullMode)] _Cull("Cull", Float) = 0 + + [HideInInspector] _Color("Main Color", Color) = (1,1,1,1) + [HideInInspector] _StencilComp("Stencil Comparison", Float) = 8 + [HideInInspector] _Stencil("Stencil ID", Float) = 0 + [HideInInspector] _StencilOp("Stencil Operation", Float) = 0 + [HideInInspector] _StencilWriteMask("Stencil Write Mask", Float) = 255 + [HideInInspector] _StencilReadMask("Stencil Read Mask", Float) = 255 + [HideInInspector] _ColorMask("Color Mask", Float) = 15 + } + + SubShader + { + LOD 200 + + Tags + { + "Queue" = "Transparent" + "IgnoreProjector" = "True" + "RenderType" = "Transparent" + "PreviewType" = "Plane" + } + + Stencil + { + Ref[_Stencil] + Comp[_StencilComp] + Pass[_StencilOp] + ReadMask[_StencilReadMask] + WriteMask[_StencilWriteMask] + } + + Cull[_Cull] + Lighting Off + ZWrite On + ZTest[unity_GUIZTestMode] + Offset -1, -1 + Fog { Mode Off } + Blend SrcAlpha OneMinusSrcAlpha + ColorMask[_ColorMask] + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + #pragma multi_compile_instancing + + #pragma multi_compile __ _CLIPPING_PLANE _CLIPPING_SPHERE _CLIPPING_BOX + + #if defined(_CLIPPING_PLANE) || defined(_CLIPPING_SPHERE) || defined(_CLIPPING_BOX) + #define _CLIPPING_PRIMITIVE + #else + #undef _CLIPPING_PRIMITIVE + #endif + + #include "UnityCG.cginc" + #include "MixedRealityShaderUtils.cginc" + + struct appdata_t + { + float4 vertex : POSITION; + half4 color : COLOR; + float2 texcoord : TEXCOORD0; + UNITY_VERTEX_INPUT_INSTANCE_ID + }; + + struct v2f + { + float4 vertex : POSITION; + half4 color : COLOR; + float2 texcoord : TEXCOORD0; + UNITY_VERTEX_INPUT_INSTANCE_ID + UNITY_VERTEX_OUTPUT_STEREO + + #if defined(_CLIPPING_PRIMITIVE) + float3 worldPosition : TEXCOORD5; + #endif + }; + + + sampler2D _MainTex; + float4 _MainTex_ST; + + UNITY_INSTANCING_BUFFER_START(Props) + UNITY_DEFINE_INSTANCED_PROP(fixed4, _Color) + + #if defined(_CLIPPING_PLANE) + UNITY_DEFINE_INSTANCED_PROP(fixed, _ClipPlaneSide) + UNITY_DEFINE_INSTANCED_PROP(float4, _ClipPlane) + #endif + + #if defined(_CLIPPING_SPHERE) + UNITY_DEFINE_INSTANCED_PROP(fixed, _ClipSphereSide) + UNITY_DEFINE_INSTANCED_PROP(float4x4, _ClipSphereInverseTransform) + #endif + + #if defined(_CLIPPING_BOX) + UNITY_DEFINE_INSTANCED_PROP(fixed, _ClipBoxSide) + UNITY_DEFINE_INSTANCED_PROP(float4x4, _ClipBoxInverseTransform) + #endif + + UNITY_INSTANCING_BUFFER_END(Props) + + v2f vert(appdata_t v) + { + v2f o; + + UNITY_SETUP_INSTANCE_ID(v); + UNITY_TRANSFER_INSTANCE_ID(v, o); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + + o.vertex = UnityObjectToClipPos(v.vertex); + o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); + o.color = v.color; + + #ifdef UNITY_HALF_TEXEL_OFFSET + o.vertex.xy += (_ScreenParams.zw - 1.0)*float2(-1,1); + #endif + + #if defined(_CLIPPING_PRIMITIVE) + o.worldPosition = mul(unity_ObjectToWorld, v.vertex).xyz; + #endif + + return o; + } + + half4 frag(v2f i) : COLOR + { + UNITY_SETUP_INSTANCE_ID(i); + + half4 col = i.color; + col.a *= tex2D(_MainTex, i.texcoord).a; + col = col * UNITY_ACCESS_INSTANCED_PROP(Props, _Color); + + // Primitive clipping. + #if defined(_CLIPPING_PRIMITIVE) + float primitiveDistance = 1.0; + #if defined(_CLIPPING_PLANE) + fixed clipPlaneSide = UNITY_ACCESS_INSTANCED_PROP(Props, _ClipPlaneSide); + float4 clipPlane = UNITY_ACCESS_INSTANCED_PROP(Props, _ClipPlane); + primitiveDistance = min(primitiveDistance, PointVsPlane(i.worldPosition.xyz, clipPlane) * clipPlaneSide); + #endif + #if defined(_CLIPPING_SPHERE) + fixed clipSphereSide = UNITY_ACCESS_INSTANCED_PROP(Props, _ClipSphereSide); + float4x4 clipSphereInverseTransform = UNITY_ACCESS_INSTANCED_PROP(Props, _ClipSphereInverseTransform); + primitiveDistance = min(primitiveDistance, PointVsSphere(i.worldPosition.xyz, clipSphereInverseTransform) * clipSphereSide); + #endif + #if defined(_CLIPPING_BOX) + fixed clipBoxSide = UNITY_ACCESS_INSTANCED_PROP(Props, _ClipBoxSide); + float4x4 clipBoxInverseTransform = UNITY_ACCESS_INSTANCED_PROP(Props, _ClipBoxInverseTransform); + primitiveDistance = min(primitiveDistance, PointVsBox(i.worldPosition.xyz, clipBoxInverseTransform) * clipBoxSide); + #endif + col *= step(0.0, primitiveDistance); + #endif + + clip(col.a - 0.01); + + return col; + } + ENDCG + } + } + CustomEditor "Microsoft.MixedReality.Toolkit.Editor.Text3DShaderGUI" +} diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/Text3DShader.shader.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/Text3DShader.shader.meta new file mode 100644 index 00000000..f17c4480 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/MRTK/Shaders/Text3DShader.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 80c006b91733f1a4991c49af89321ecd +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/Scenes.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/Scenes.meta new file mode 100644 index 00000000..83c741b2 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6ea315d0fd7389c41b19996891e99ae3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/Scenes/SampleScene.unity b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/Scenes/SampleScene.unity new file mode 100644 index 00000000..5a2d28c2 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/Scenes/SampleScene.unity @@ -0,0 +1,1826 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 705507994} + m_IndirectSpecularColor: {r: 0.18028378, g: 0.22571412, b: 0.30692285, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &97853868 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 97853871} + - component: {fileID: 97853870} + - component: {fileID: 97853869} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &97853869 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 97853868} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: "\u200B" + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4281479730 + m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 14 + m_fontSizeBase: 14 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 256 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 0 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 1 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &97853870 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 97853868} + m_CullTransparentMesh: 1 +--- !u!224 &97853871 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 97853868} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 143832582} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &143832581 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 143832582} + - component: {fileID: 143832583} + m_Layer: 5 + m_Name: Text Area + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &143832582 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 143832581} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1895741750} + - {fileID: 97853871} + m_Father: {fileID: 1187233980} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &143832583 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 143832581} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3312d7739989d2b4e91e6319e9a96d76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: {x: -8, y: -5, z: -8, w: -5} + m_Softness: {x: 0, y: 0} +--- !u!1 &165517764 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 165517765} + - component: {fileID: 165517767} + - component: {fileID: 165517766} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &165517765 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 165517764} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2092252165} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &165517766 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 165517764} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: 'Back + +' + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4281479730 + m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 24 + m_fontSizeBase: 24 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &165517767 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 165517764} + m_CullTransparentMesh: 1 +--- !u!1 &340263450 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 340263451} + m_Layer: 0 + m_Name: MixedRealityPlayspace + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &340263451 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 340263450} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 963194228} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &705507993 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 705507995} + - component: {fileID: 705507994} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &705507994 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 1 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &705507995 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &713828071 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 713828073} + - component: {fileID: 713828072} + m_Layer: 0 + m_Name: MixedRealityToolkit + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &713828072 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 713828071} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 83d9acc7968244a8886f3af591305bcb, type: 3} + m_Name: + m_EditorClassIdentifier: + activeProfile: {fileID: 11400000, guid: 7e7c962b9eb9dfa44993d5b2f2576752, type: 2} +--- !u!4 &713828073 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 713828071} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &963194225 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 963194228} + - component: {fileID: 963194227} + - component: {fileID: 963194226} + - component: {fileID: 963194231} + - component: {fileID: 963194230} + - component: {fileID: 963194229} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &963194226 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 +--- !u!20 &963194227 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0, g: 0, b: 0, a: 1} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.1 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &963194228 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 340263451} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &963194229 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bf98dd1206224111a38765365e98e207, type: 3} + m_Name: + m_EditorClassIdentifier: + lockCursorWhenFocusLocked: 1 + setCursorInvisibleWhenFocusLocked: 0 + maxGazeCollisionDistance: 10 + raycastLayerMasks: + - serializedVersion: 2 + m_Bits: 4294967291 + stabilizer: + storedStabilitySamples: 60 + gazeTransform: {fileID: 0} + minHeadVelocityThreshold: 0.5 + maxHeadVelocityThreshold: 2 +--- !u!114 &963194230 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7a21b486d0bb44444b1418aaa38b44de, type: 3} + m_Name: + m_EditorClassIdentifier: + m_SendPointerHoverToParent: 1 + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &963194231 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!1 &1054508622 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1054508623} + - component: {fileID: 1054508626} + - component: {fileID: 1054508625} + - component: {fileID: 1054508624} + - component: {fileID: 1054508628} + - component: {fileID: 1054508627} + - component: {fileID: 1054508629} + - component: {fileID: 1054508631} + - component: {fileID: 1054508630} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1054508623 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1054508622} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 1.5} + m_LocalScale: {x: 0.001, y: 0.001, z: 0.001} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1187233980} + - {fileID: 2092252165} + - {fileID: 1306366453} + - {fileID: 2082689488} + m_Father: {fileID: 1649518285} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 600, y: 400} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1054508624 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1054508622} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &1054508625 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1054508622} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 1 +--- !u!223 &1054508626 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1054508622} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 2 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 25 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!114 &1054508627 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1054508622} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.589771, g: 0.61052746, b: 0.6603774, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1054508628 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1054508622} + m_CullTransparentMesh: 1 +--- !u!114 &1054508629 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1054508622} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6df61a9a13528fd4f9365c233cb23bfb, type: 3} + m_Name: + m_EditorClassIdentifier: + m_RaycastTriggerInteraction: 1 + m_EventMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_MaxRayIntersections: 10 + m_EventCamera: {fileID: 0} +--- !u!114 &1054508630 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1054508622} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2fcaf896491074042b7ed7684454a412, type: 3} + m_Name: + m_EditorClassIdentifier: + eventsToReceive: 0 + debounceThreshold: 0.01 +--- !u!114 &1054508631 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1054508622} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ff4e3b9019304b5aaec5664de0778d21, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1001 &1184828600 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 1054508623} + m_Modifications: + - target: {fileID: 2311476450002457713, guid: 4410a2a17e71713438d8cf4ebc93d9a4, type: 3} + propertyPath: m_Name + value: WebView + objectReference: {fileID: 0} + - target: {fileID: 3231283774461358941, guid: 4410a2a17e71713438d8cf4ebc93d9a4, type: 3} + propertyPath: m_RootOrder + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 3231283774461358941, guid: 4410a2a17e71713438d8cf4ebc93d9a4, type: 3} + propertyPath: m_LocalScale.x + value: 570 + objectReference: {fileID: 0} + - target: {fileID: 3231283774461358941, guid: 4410a2a17e71713438d8cf4ebc93d9a4, type: 3} + propertyPath: m_LocalScale.y + value: 340 + objectReference: {fileID: 0} + - target: {fileID: 3231283774461358941, guid: 4410a2a17e71713438d8cf4ebc93d9a4, type: 3} + propertyPath: m_LocalScale.z + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3231283774461358941, guid: 4410a2a17e71713438d8cf4ebc93d9a4, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3231283774461358941, guid: 4410a2a17e71713438d8cf4ebc93d9a4, type: 3} + propertyPath: m_LocalPosition.y + value: -16 + objectReference: {fileID: 0} + - target: {fileID: 3231283774461358941, guid: 4410a2a17e71713438d8cf4ebc93d9a4, type: 3} + propertyPath: m_LocalPosition.z + value: -5 + objectReference: {fileID: 0} + - target: {fileID: 3231283774461358941, guid: 4410a2a17e71713438d8cf4ebc93d9a4, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3231283774461358941, guid: 4410a2a17e71713438d8cf4ebc93d9a4, type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3231283774461358941, guid: 4410a2a17e71713438d8cf4ebc93d9a4, type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3231283774461358941, guid: 4410a2a17e71713438d8cf4ebc93d9a4, type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3231283774461358941, guid: 4410a2a17e71713438d8cf4ebc93d9a4, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3231283774461358941, guid: 4410a2a17e71713438d8cf4ebc93d9a4, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3231283774461358941, guid: 4410a2a17e71713438d8cf4ebc93d9a4, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 4410a2a17e71713438d8cf4ebc93d9a4, type: 3} +--- !u!1 &1187233976 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1187233980} + - component: {fileID: 1187233979} + - component: {fileID: 1187233978} + - component: {fileID: 1187233977} + m_Layer: 5 + m_Name: AddressField (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1187233977 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1187233976} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2da0c512f12947e489f739169773d7ca, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1187233978} + m_TextViewport: {fileID: 143832582} + m_TextComponent: {fileID: 97853869} + m_Placeholder: {fileID: 1895741747} + m_VerticalScrollbar: {fileID: 0} + m_VerticalScrollbarEventHandler: {fileID: 0} + m_LayoutGroup: {fileID: 0} + m_ScrollSensitivity: 1 + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_HideSoftKeyboard: 0 + m_CharacterValidation: 0 + m_RegexValue: + m_GlobalPointSize: 14 + m_CharacterLimit: 0 + m_OnEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnSubmit: + m_PersistentCalls: + m_Calls: [] + m_OnSelect: + m_PersistentCalls: + m_Calls: [] + m_OnDeselect: + m_PersistentCalls: + m_Calls: [] + m_OnTextSelection: + m_PersistentCalls: + m_Calls: [] + m_OnEndTextSelection: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_OnTouchScreenKeyboardStatusChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_RichText: 1 + m_GlobalFontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_OnFocusSelectAll: 1 + m_ResetOnDeActivation: 1 + m_RestoreOriginalTextOnEscape: 1 + m_isRichTextEditingAllowed: 0 + m_LineLimit: 0 + m_InputValidator: {fileID: 0} +--- !u!114 &1187233978 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1187233976} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1187233979 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1187233976} + m_CullTransparentMesh: 1 +--- !u!224 &1187233980 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1187233976} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 143832582} + m_Father: {fileID: 1054508623} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -2, y: 178} + m_SizeDelta: {x: 390, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1306366452 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1306366453} + - component: {fileID: 1306366456} + - component: {fileID: 1306366455} + - component: {fileID: 1306366454} + m_Layer: 5 + m_Name: Go Button + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1306366453 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1306366452} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1959170144} + m_Father: {fileID: 1054508623} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 242, y: 178} + m_SizeDelta: {x: 75, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1306366454 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1306366452} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1306366455} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1306366455 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1306366452} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1306366456 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1306366452} + m_CullTransparentMesh: 1 +--- !u!1 &1649518283 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1649518285} + - component: {fileID: 1649518284} + m_Layer: 0 + m_Name: MixedRealitySceneContent + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1649518284 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1649518283} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c65c9dd2f312b8d41b8849d58e1053fa, type: 3} + m_Name: + m_EditorClassIdentifier: + alignmentType: 0 + containerObject: {fileID: 0} +--- !u!4 &1649518285 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1649518283} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1054508623} + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1895741746 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1895741750} + - component: {fileID: 1895741749} + - component: {fileID: 1895741747} + - component: {fileID: 1895741748} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1895741747 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1895741746} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Enter text... + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 2150773298 + m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 14 + m_fontSizeBase: 14 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 2 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 256 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 0 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 1 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!114 &1895741748 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1895741746} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreLayout: 1 + m_MinWidth: -1 + m_MinHeight: -1 + m_PreferredWidth: -1 + m_PreferredHeight: -1 + m_FlexibleWidth: -1 + m_FlexibleHeight: -1 + m_LayoutPriority: 1 +--- !u!222 &1895741749 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1895741746} + m_CullTransparentMesh: 1 +--- !u!224 &1895741750 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1895741746} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 143832582} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1959170143 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1959170144} + - component: {fileID: 1959170146} + - component: {fileID: 1959170145} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1959170144 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1959170143} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1306366453} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1959170145 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1959170143} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: 'Go + +' + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4281479730 + m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 24 + m_fontSizeBase: 24 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &1959170146 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1959170143} + m_CullTransparentMesh: 1 +--- !u!1 &2082689487 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 2311476450002457713, guid: 4410a2a17e71713438d8cf4ebc93d9a4, type: 3} + m_PrefabInstance: {fileID: 1184828600} + m_PrefabAsset: {fileID: 0} +--- !u!4 &2082689488 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 3231283774461358941, guid: 4410a2a17e71713438d8cf4ebc93d9a4, type: 3} + m_PrefabInstance: {fileID: 1184828600} + m_PrefabAsset: {fileID: 0} +--- !u!114 &2082689493 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2082689487} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9fdbada398537b44394e6233549c6146, type: 3} + m_Name: + m_EditorClassIdentifier: + BackButton: {fileID: 2092252166} + GoButton: {fileID: 1306366454} + URLField: {fileID: 1187233977} + Collider: {fileID: 2082689498} +--- !u!64 &2082689498 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2082689487} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 4 + m_Convex: 0 + m_CookingOptions: 30 + m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &2092252164 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2092252165} + - component: {fileID: 2092252168} + - component: {fileID: 2092252167} + - component: {fileID: 2092252166} + m_Layer: 5 + m_Name: Back Button + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2092252165 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2092252164} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 165517765} + m_Father: {fileID: 1054508623} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -248, y: 178} + m_SizeDelta: {x: 75, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2092252166 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2092252164} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 2092252167} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &2092252167 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2092252164} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &2092252168 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2092252164} + m_CullTransparentMesh: 1 diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/Scenes/SampleScene.unity.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/Scenes/SampleScene.unity.meta new file mode 100644 index 00000000..952bd1e9 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/Scenes/SampleScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9fc0d4010bbf28b4594072e72b8655ab +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/WebViewBrowser.cs b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/WebViewBrowser.cs new file mode 100644 index 00000000..22a8946a --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/WebViewBrowser.cs @@ -0,0 +1,112 @@ +using Microsoft.MixedReality.WebView; +using UnityEngine.UI; +using UnityEngine; +using TMPro; +using System; + +using Microsoft.MixedReality.Toolkit.Input; + +public class WebViewBrowser : MonoBehaviour, IMixedRealityPointerHandler +{ + // Declare UI elements: back button, go button, and URL input field + public Button BackButton; + public Button GoButton; + public TMP_InputField URLField; + public MeshCollider Collider; + private IWebView _webView; + + private void Start() + { + // Get the WebView component attached to the game object + var webViewComponent = gameObject.GetComponent(); + webViewComponent.GetWebViewWhenReady((IWebView webView) => + { + _webView = webView; + + // If the WebView supports browser history, enable the back button + if (webView is IWithBrowserHistory history) + { + // Add an event listener for the back button to navigate back in history + BackButton.onClick.AddListener(() => history.GoBack()); + + // Update the back button's enabled state based on whether there's any history to go back to + history.CanGoBackUpdated += CanGoBack; + } + + // Add an event listener for the go button to load the URL entered in the input field + GoButton.onClick.AddListener(() => webView.Load(new Uri(URLField.text))); + + // Subscribe to the Navigated event to update the URL input field whenever a navigation occurs + webView.Navigated += OnNavigated; + + // Set the initial value of the URL input field to the current URL of the WebView + if (webView.Page != null) + { + URLField.text = webView.Page.AbsoluteUri; + } + }); + } + + // Update the URL input field with the new path after navigation + private void OnNavigated(string path) + { + URLField.text = path; + } + + // Enable or disable the back button based on whether there's any history to go back to + private void CanGoBack(bool value) + { + BackButton.enabled = value; + } + + public void OnPointerDown(MixedRealityPointerEventData eventData) + { + TranslateToWebViewMouseEvent(eventData, WebViewMouseEventData.EventType.MouseDown); + } + + public void OnPointerUp(MixedRealityPointerEventData eventData) + { + TranslateToWebViewMouseEvent(eventData, WebViewMouseEventData.EventType.MouseUp); + } + + private void TranslateToWebViewMouseEvent(MixedRealityPointerEventData eventData, WebViewMouseEventData.EventType evenType) + { + var hitCoord = NormalizeWorldPoint(eventData.Pointer.Result.Details.Point); + + hitCoord.x *= _webView.Width; + hitCoord.y *= _webView.Height; + + var mouseEventsWebView = _webView as IWithMouseEvents; + WebViewMouseEventData mouseEvent = new WebViewMouseEventData + { + X = (int)hitCoord.x, + Y = (int)hitCoord.y, + Device = WebViewMouseEventData.DeviceType.Pointer, + Type = evenType, + Button = WebViewMouseEventData.MouseButton.ButtonLeft, + TertiaryAxisDeviceType = WebViewMouseEventData.TertiaryAxisDevice.PointingDevice + }; + + mouseEventsWebView.MouseEvent(mouseEvent); + } + + private Vector2 NormalizeWorldPoint(Vector3 worldPoint) + { + // Convert the world point to our control's local space. + Vector3 localPoint = transform.InverseTransformPoint(worldPoint); + + var boundsSize = Collider.sharedMesh.bounds.size; + var boundsExtents = Collider.sharedMesh.bounds.max; + + // Adjust the point to be based on a 0,0 origin. + var uvTouchPoint = new Vector2((localPoint.x + boundsExtents.x), -1.0f * (localPoint.y - boundsExtents.y)); + + // Normalize the point so it can be mapped to the WebView's texture. + var normalizedPoint = new Vector2(uvTouchPoint.x / boundsSize.x, uvTouchPoint.y / boundsSize.y); + + return normalizedPoint; + } + + public void OnPointerClicked(MixedRealityPointerEventData eventData) { } + public void OnPointerDragged(MixedRealityPointerEventData eventData) { } +} \ No newline at end of file diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/WebViewBrowser.cs.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/WebViewBrowser.cs.meta new file mode 100644 index 00000000..5b786265 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/WebViewBrowser.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9fdbada398537b44394e6233549c6146 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR.meta new file mode 100644 index 00000000..f87eb8e5 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 42093a716ec518641a9ae93aa9b3f0fa +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Loaders.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Loaders.meta new file mode 100644 index 00000000..b901710b --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Loaders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dc4ab6a9227501d47bfadcf341e33fed +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Loaders/Open XR Loader.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Loaders/Open XR Loader.asset new file mode 100644 index 00000000..15d4498d --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Loaders/Open XR Loader.asset @@ -0,0 +1,14 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d3552e428dc7646a88de3ed3650f87da, type: 3} + m_Name: Open XR Loader + m_EditorClassIdentifier: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Loaders/Open XR Loader.asset.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Loaders/Open XR Loader.asset.meta new file mode 100644 index 00000000..07912dfa --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Loaders/Open XR Loader.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 262e76e0ccf9dfd478466f1e6471f743 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Settings.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Settings.meta new file mode 100644 index 00000000..70f917a6 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Settings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b3adff16c52aac149af2a2eb342b4203 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Settings/OpenXR Editor Settings.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Settings/OpenXR Editor Settings.asset new file mode 100644 index 00000000..d06efa58 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Settings/OpenXR Editor Settings.asset @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 975057b4fdcfb8142b3080d19a5cc712, type: 3} + m_Name: OpenXR Editor Settings + m_EditorClassIdentifier: + Keys: 010000000e000000 + Values: + - featureSets: + - com.microsoft.openxr.featureset.wmr + - featureSets: + - com.microsoft.openxr.featureset.hololens diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Settings/OpenXR Editor Settings.asset.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Settings/OpenXR Editor Settings.asset.meta new file mode 100644 index 00000000..2ed1d1cf --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Settings/OpenXR Editor Settings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a141cb325af82a944a847907c601b6e9 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Settings/OpenXR Package Settings.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Settings/OpenXR Package Settings.asset new file mode 100644 index 00000000..1b1c4576 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Settings/OpenXR Package Settings.asset @@ -0,0 +1,752 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-9156128087838353666 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2d2e2731103cdda44af77955a0b4814c, type: 3} + m_Name: AppRemotingPlugin WSA + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: Holographic Remoting remote app + version: 1.8.0 + featureIdInternal: com.microsoft.openxr.feature.appremoting + openxrExtensionStrings: XR_MSFT_holographic_remoting XR_MSFT_holographic_remoting_speech + company: Microsoft + priority: -100 + required: 0 +--- !u!114 &-8791073877347979526 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3482401f887b8864183e401715462f46, type: 3} + m_Name: HPMixedRealityControllerProfile Standalone + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: HP Reverb G2 Controller Profile + version: 1.8.0 + featureIdInternal: com.microsoft.openxr.feature.interaction.hpmixedrealitycontroller + openxrExtensionStrings: XR_EXT_hp_mixed_reality_controller + company: Microsoft + priority: 0 + required: 0 +--- !u!114 &-8320375554670759756 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f928d0d73a35f294fbe357ca17aa3547, type: 3} + m_Name: MicrosoftHandInteraction WSA + m_EditorClassIdentifier: + m_enabled: 1 + nameUi: Microsoft Hand Interaction Profile + version: 0.0.1 + featureIdInternal: com.unity.openxr.feature.input.handtracking + openxrExtensionStrings: XR_MSFT_hand_interaction + company: Unity + priority: 0 + required: 0 +--- !u!114 &-8234964549452783826 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2d2e2731103cdda44af77955a0b4814c, type: 3} + m_Name: AppRemotingPlugin Standalone + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: Holographic Remoting remote app + version: 1.8.0 + featureIdInternal: com.microsoft.openxr.feature.appremoting + openxrExtensionStrings: XR_MSFT_holographic_remoting XR_MSFT_holographic_remoting_speech + company: Microsoft + priority: -100 + required: 0 +--- !u!114 &-6046135081374806543 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0c8f1ce8139888c4ab621f6b3c8bb558, type: 3} + m_Name: MotionControllerFeaturePlugin Standalone + m_EditorClassIdentifier: + m_enabled: 1 + nameUi: Motion Controller Model + version: 1.8.0 + featureIdInternal: com.microsoft.openxr.feature.controller + openxrExtensionStrings: XR_MSFT_controller_model XR_FB_render_model + company: Microsoft + priority: 0 + required: 0 +--- !u!114 &-5281385832365046672 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b5a1f07dc5afe854f9f12a4194aca3fb, type: 3} + m_Name: WSA + m_EditorClassIdentifier: + features: + - {fileID: -9156128087838353666} + - {fileID: 3509922356019969242} + - {fileID: -2579591891406222725} + - {fileID: 2236953091096034020} + - {fileID: 4108757663332930139} + - {fileID: 3944210153470645160} + - {fileID: -3558160564479299438} + - {fileID: -4324672991276254832} + - {fileID: -8320375554670759756} + - {fileID: 5540693242641560659} + - {fileID: -2857303689053143175} + - {fileID: 6203936439530748652} + - {fileID: -3643824036258635872} + - {fileID: 8943490906109707154} + - {fileID: -2453136439990797807} + m_renderMode: 1 + m_depthSubmissionMode: 1 +--- !u!114 &-4324672991276254832 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c4b862ee14fb479fbfe5fffe655d3ed3, type: 3} + m_Name: MetaQuestTouchProControllerProfile WSA + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: Meta Quest Touch Pro Controller Profile + version: 0.0.1 + featureIdInternal: com.unity.openxr.feature.input.metaquestpro + openxrExtensionStrings: XR_FB_touch_controller_pro + company: Unity + priority: 0 + required: 0 +--- !u!114 &-3643824036258635872 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: feeef8d85de8db242bdda70cc7ff5acd, type: 3} + m_Name: OculusTouchControllerProfile WSA + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: Oculus Touch Controller Profile + version: 0.0.1 + featureIdInternal: com.unity.openxr.feature.input.oculustouch + openxrExtensionStrings: + company: Unity + priority: 0 + required: 0 +--- !u!114 &-3572279281362214239 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7de993716e042c6499d0c18eed3a773c, type: 3} + m_Name: MockRuntime Standalone + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: Mock Runtime + version: 0.0.2 + featureIdInternal: com.unity.openxr.feature.mockruntime + openxrExtensionStrings: XR_UNITY_null_gfx XR_UNITY_android_present + company: Unity + priority: 0 + required: 0 + ignoreValidationErrors: 0 +--- !u!114 &-3558160564479299438 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0f6bfdbcb316ed242b30a8798c9eb853, type: 3} + m_Name: KHRSimpleControllerProfile WSA + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: Khronos Simple Controller Profile + version: 0.0.1 + featureIdInternal: com.unity.openxr.feature.input.khrsimpleprofile + openxrExtensionStrings: + company: Unity + priority: 0 + required: 0 +--- !u!114 &-3532219198906828149 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 056125dd64c0ed540b40a4af74f7b495, type: 3} + m_Name: RuntimeDebuggerOpenXRFeature Standalone + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: Runtime Debugger + version: 1 + featureIdInternal: com.unity.openxr.features.runtimedebugger + openxrExtensionStrings: + company: Unity + priority: 0 + required: 0 + cacheSize: 1048576 + perThreadCacheSize: 51200 +--- !u!114 &-3291161241438317336 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0f6bfdbcb316ed242b30a8798c9eb853, type: 3} + m_Name: KHRSimpleControllerProfile Standalone + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: Khronos Simple Controller Profile + version: 0.0.1 + featureIdInternal: com.unity.openxr.feature.input.khrsimpleprofile + openxrExtensionStrings: + company: Unity + priority: 0 + required: 0 +--- !u!114 &-3222691064925498647 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3f8ec2975f18d5e479159feb34b4dc86, type: 3} + m_Name: MixedRealityFeaturePlugin Standalone + m_EditorClassIdentifier: + m_enabled: 1 + nameUi: Mixed Reality Features + version: 1.8.0 + featureIdInternal: com.microsoft.openxr.feature.hololens + openxrExtensionStrings: XR_MSFT_holographic_window_attachment XR_KHR_win32_convert_performance_counter_time + XR_MSFT_unbounded_reference_space XR_MSFT_spatial_anchor XR_MSFT_secondary_view_configuration + XR_MSFT_first_person_observer XR_MSFT_spatial_graph_bridge XR_MSFT_perception_anchor_interop + XR_MSFT_spatial_anchor_persistence XR_MSFT_scene_understanding XR_MSFT_scene_understanding_serialization + XR_MSFT_spatial_anchor_export_preview XR_MSFT_composition_layer_reprojection + company: Microsoft + priority: 0 + required: 1 + disableFirstPersonObserver: 0 + enablePoseUpdateOnBeforeRender: 0 + validationRuleTarget: 0 +--- !u!114 &-3146378018228042552 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b3cf79659a011bd419c7a2a30eb74e9a, type: 3} + m_Name: EyeGazeInteraction Standalone + m_EditorClassIdentifier: + m_enabled: 1 + nameUi: Eye Gaze Interaction Profile + version: 0.0.1 + featureIdInternal: com.unity.openxr.feature.input.eyetracking + openxrExtensionStrings: XR_EXT_eye_gaze_interaction + company: Unity + priority: 0 + required: 0 +--- !u!114 &-2857303689053143175 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3f8ec2975f18d5e479159feb34b4dc86, type: 3} + m_Name: MixedRealityFeaturePlugin WSA + m_EditorClassIdentifier: + m_enabled: 1 + nameUi: Mixed Reality Features + version: 1.8.0 + featureIdInternal: com.microsoft.openxr.feature.hololens + openxrExtensionStrings: XR_MSFT_holographic_window_attachment XR_KHR_win32_convert_performance_counter_time + XR_MSFT_unbounded_reference_space XR_MSFT_spatial_anchor XR_MSFT_secondary_view_configuration + XR_MSFT_first_person_observer XR_MSFT_spatial_graph_bridge XR_MSFT_perception_anchor_interop + XR_MSFT_spatial_anchor_persistence XR_MSFT_scene_understanding XR_MSFT_scene_understanding_serialization + XR_MSFT_spatial_anchor_export_preview XR_MSFT_composition_layer_reprojection + company: Microsoft + priority: 0 + required: 1 + disableFirstPersonObserver: 0 + enablePoseUpdateOnBeforeRender: 0 + validationRuleTarget: 1 +--- !u!114 &-2579591891406222725 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b3cf79659a011bd419c7a2a30eb74e9a, type: 3} + m_Name: EyeGazeInteraction WSA + m_EditorClassIdentifier: + m_enabled: 1 + nameUi: Eye Gaze Interaction Profile + version: 0.0.1 + featureIdInternal: com.unity.openxr.feature.input.eyetracking + openxrExtensionStrings: XR_EXT_eye_gaze_interaction + company: Unity + priority: 0 + required: 0 +--- !u!114 &-2453136439990797807 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0d6ccd3d0ef0f1d458e69421dccbdae1, type: 3} + m_Name: ValveIndexControllerProfile WSA + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: Valve Index Controller Profile + version: 0.0.1 + featureIdInternal: com.unity.openxr.feature.input.valveindex + openxrExtensionStrings: + company: Unity + priority: 0 + required: 0 +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9f0ebc320a151d3408ea1e9fce54d40e, type: 3} + m_Name: OpenXR Package Settings + m_EditorClassIdentifier: + Keys: 010000000e000000 + Values: + - {fileID: 5469543864881237022} + - {fileID: -5281385832365046672} +--- !u!114 &1560007936489684005 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: feeef8d85de8db242bdda70cc7ff5acd, type: 3} + m_Name: OculusTouchControllerProfile Standalone + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: Oculus Touch Controller Profile + version: 0.0.1 + featureIdInternal: com.unity.openxr.feature.input.oculustouch + openxrExtensionStrings: + company: Unity + priority: 0 + required: 0 +--- !u!114 &1822772621369869403 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f928d0d73a35f294fbe357ca17aa3547, type: 3} + m_Name: MicrosoftHandInteraction Standalone + m_EditorClassIdentifier: + m_enabled: 1 + nameUi: Microsoft Hand Interaction Profile + version: 0.0.1 + featureIdInternal: com.unity.openxr.feature.input.handtracking + openxrExtensionStrings: XR_MSFT_hand_interaction + company: Unity + priority: 0 + required: 0 +--- !u!114 &2236953091096034020 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c79c911b38743a649b1c1eddb5097202, type: 3} + m_Name: HandTrackingFeaturePlugin WSA + m_EditorClassIdentifier: + m_enabled: 1 + nameUi: Hand Tracking + version: 1.8.0 + featureIdInternal: com.microsoft.openxr.feature.handtracking + openxrExtensionStrings: XR_EXT_hand_tracking XR_EXT_hand_joints_motion_range XR_MSFT_hand_tracking_mesh + company: Microsoft + priority: 0 + required: 0 + leftHandTrackingOptions: + motionRange: 0 + rightHandTrackingOptions: + motionRange: 0 +--- !u!114 &2692585085645271422 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0d6ccd3d0ef0f1d458e69421dccbdae1, type: 3} + m_Name: ValveIndexControllerProfile Standalone + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: Valve Index Controller Profile + version: 0.0.1 + featureIdInternal: com.unity.openxr.feature.input.valveindex + openxrExtensionStrings: + company: Unity + priority: 0 + required: 0 +--- !u!114 &3094208498748100248 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 486b5e28864f9a94b979b9620ce5006d, type: 3} + m_Name: ConformanceAutomationFeature Standalone + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: Conformance Automation + version: 0.0.1 + featureIdInternal: com.unity.openxr.feature.conformance + openxrExtensionStrings: XR_EXT_conformance_automation + company: Unity + priority: 0 + required: 0 +--- !u!114 &3371921894632598856 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 761fdd4502cb7a84e9ec7a2b24f33f37, type: 3} + m_Name: MicrosoftMotionControllerProfile Standalone + m_EditorClassIdentifier: + m_enabled: 1 + nameUi: Microsoft Motion Controller Profile + version: 0.0.1 + featureIdInternal: com.unity.openxr.feature.input.microsoftmotioncontroller + openxrExtensionStrings: + company: Unity + priority: 0 + required: 0 +--- !u!114 &3509922356019969242 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 486b5e28864f9a94b979b9620ce5006d, type: 3} + m_Name: ConformanceAutomationFeature WSA + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: Conformance Automation + version: 0.0.1 + featureIdInternal: com.unity.openxr.feature.conformance + openxrExtensionStrings: XR_EXT_conformance_automation + company: Unity + priority: 0 + required: 0 +--- !u!114 &3944210153470645160 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 274c02963f889a64e90bc2e596e21d13, type: 3} + m_Name: HTCViveControllerProfile WSA + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: HTC Vive Controller Profile + version: 0.0.1 + featureIdInternal: com.unity.openxr.feature.input.htcvive + openxrExtensionStrings: + company: Unity + priority: 0 + required: 0 +--- !u!114 &4108757663332930139 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3482401f887b8864183e401715462f46, type: 3} + m_Name: HPMixedRealityControllerProfile WSA + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: HP Reverb G2 Controller Profile + version: 1.8.0 + featureIdInternal: com.microsoft.openxr.feature.interaction.hpmixedrealitycontroller + openxrExtensionStrings: XR_EXT_hp_mixed_reality_controller + company: Microsoft + priority: 0 + required: 0 +--- !u!114 &5044288477980273724 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 274c02963f889a64e90bc2e596e21d13, type: 3} + m_Name: HTCViveControllerProfile Standalone + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: HTC Vive Controller Profile + version: 0.0.1 + featureIdInternal: com.unity.openxr.feature.input.htcvive + openxrExtensionStrings: + company: Unity + priority: 0 + required: 0 +--- !u!114 &5469543864881237022 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b5a1f07dc5afe854f9f12a4194aca3fb, type: 3} + m_Name: Standalone + m_EditorClassIdentifier: + features: + - {fileID: -8234964549452783826} + - {fileID: 3094208498748100248} + - {fileID: -3146378018228042552} + - {fileID: 7802046322106018668} + - {fileID: -8791073877347979526} + - {fileID: 5044288477980273724} + - {fileID: -3291161241438317336} + - {fileID: 6771435445132617576} + - {fileID: 1822772621369869403} + - {fileID: 3371921894632598856} + - {fileID: -3222691064925498647} + - {fileID: -3572279281362214239} + - {fileID: -6046135081374806543} + - {fileID: 1560007936489684005} + - {fileID: 8183488771817893027} + - {fileID: -3532219198906828149} + - {fileID: 2692585085645271422} + m_renderMode: 1 + m_depthSubmissionMode: 0 +--- !u!114 &5540693242641560659 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 761fdd4502cb7a84e9ec7a2b24f33f37, type: 3} + m_Name: MicrosoftMotionControllerProfile WSA + m_EditorClassIdentifier: + m_enabled: 1 + nameUi: Microsoft Motion Controller Profile + version: 0.0.1 + featureIdInternal: com.unity.openxr.feature.input.microsoftmotioncontroller + openxrExtensionStrings: + company: Unity + priority: 0 + required: 0 +--- !u!114 &6203936439530748652 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0c8f1ce8139888c4ab621f6b3c8bb558, type: 3} + m_Name: MotionControllerFeaturePlugin WSA + m_EditorClassIdentifier: + m_enabled: 1 + nameUi: Motion Controller Model + version: 1.8.0 + featureIdInternal: com.microsoft.openxr.feature.controller + openxrExtensionStrings: XR_MSFT_controller_model XR_FB_render_model + company: Microsoft + priority: 0 + required: 0 +--- !u!114 &6771435445132617576 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c4b862ee14fb479fbfe5fffe655d3ed3, type: 3} + m_Name: MetaQuestTouchProControllerProfile Standalone + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: Meta Quest Touch Pro Controller Profile + version: 0.0.1 + featureIdInternal: com.unity.openxr.feature.input.metaquestpro + openxrExtensionStrings: XR_FB_touch_controller_pro + company: Unity + priority: 0 + required: 0 +--- !u!114 &7802046322106018668 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c79c911b38743a649b1c1eddb5097202, type: 3} + m_Name: HandTrackingFeaturePlugin Standalone + m_EditorClassIdentifier: + m_enabled: 1 + nameUi: Hand Tracking + version: 1.8.0 + featureIdInternal: com.microsoft.openxr.feature.handtracking + openxrExtensionStrings: XR_EXT_hand_tracking XR_EXT_hand_joints_motion_range XR_MSFT_hand_tracking_mesh + company: Microsoft + priority: 0 + required: 0 + leftHandTrackingOptions: + motionRange: 0 + rightHandTrackingOptions: + motionRange: 0 +--- !u!114 &8183488771817893027 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9f34c86d1a130cc45a438373e1e8a4fc, type: 3} + m_Name: PlayModeRemotingPlugin Standalone + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: Holographic Remoting for Play Mode + version: 1.8.0 + featureIdInternal: com.microsoft.openxr.feature.playmoderemoting + openxrExtensionStrings: XR_MSFT_holographic_remoting XR_MSFT_holographic_remoting_speech + company: Microsoft + priority: -100 + required: 0 + m_remoteHostName: + m_remoteHostPort: 8265 + m_maxBitrate: 20000 + m_videoCodec: 0 + m_enableAudio: 0 +--- !u!114 &8943490906109707154 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 056125dd64c0ed540b40a4af74f7b495, type: 3} + m_Name: RuntimeDebuggerOpenXRFeature WSA + m_EditorClassIdentifier: + m_enabled: 0 + nameUi: Runtime Debugger + version: 1 + featureIdInternal: com.unity.openxr.features.runtimedebugger + openxrExtensionStrings: + company: Unity + priority: 0 + required: 0 + cacheSize: 1048576 + perThreadCacheSize: 51200 diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Settings/OpenXR Package Settings.asset.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Settings/OpenXR Package Settings.asset.meta new file mode 100644 index 00000000..f38e916b --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/Settings/OpenXR Package Settings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 541a1cf0c39d86043af97cfb801628fd +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/XRGeneralSettings.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/XRGeneralSettings.asset new file mode 100644 index 00000000..1046688d --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/XRGeneralSettings.asset @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-5444848369939482447 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d236b7d11115f2143951f1e14045df39, type: 3} + m_Name: WSA Settings + m_EditorClassIdentifier: + m_LoaderManagerInstance: {fileID: -3196427664074929696} + m_InitManagerOnStart: 1 +--- !u!114 &-3196427664074929696 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4c3631f5e58749a59194e0cf6baf6d5, type: 3} + m_Name: WSA Providers + m_EditorClassIdentifier: + m_RequiresSettingsUpdate: 0 + m_AutomaticLoading: 0 + m_AutomaticRunning: 0 + m_Loaders: + - {fileID: 11400000, guid: 262e76e0ccf9dfd478466f1e6471f743, type: 2} +--- !u!114 &-303432232004269184 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4c3631f5e58749a59194e0cf6baf6d5, type: 3} + m_Name: Standalone Providers + m_EditorClassIdentifier: + m_RequiresSettingsUpdate: 0 + m_AutomaticLoading: 0 + m_AutomaticRunning: 0 + m_Loaders: + - {fileID: 11400000, guid: 262e76e0ccf9dfd478466f1e6471f743, type: 2} +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d2dc886499c26824283350fa532d087d, type: 3} + m_Name: XRGeneralSettings + m_EditorClassIdentifier: + Keys: 010000000e000000 + Values: + - {fileID: 6284999351924105525} + - {fileID: -5444848369939482447} +--- !u!114 &6284999351924105525 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d236b7d11115f2143951f1e14045df39, type: 3} + m_Name: Standalone Settings + m_EditorClassIdentifier: + m_LoaderManagerInstance: {fileID: -303432232004269184} + m_InitManagerOnStart: 1 diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/XRGeneralSettings.asset.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/XRGeneralSettings.asset.meta new file mode 100644 index 00000000..be5a1f0d --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XR/XRGeneralSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 25312d4015a310f499767577dc2d8b23 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI.meta new file mode 100644 index 00000000..3af897f4 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 40fa1b7b9a81718498fefa8eac944707 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings.meta new file mode 100644 index 00000000..96175ce8 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f7193ce3b14052c41b52154ff924ebc8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/Resources.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/Resources.meta new file mode 100644 index 00000000..579654c8 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ce10c6a2c8cf55b41a654a1041d2306a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/Resources/InteractionLayerSettings.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/Resources/InteractionLayerSettings.asset new file mode 100644 index 00000000..3f314b5d --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/Resources/InteractionLayerSettings.asset @@ -0,0 +1,47 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 191492db6e452eb468b95433ec162164, type: 3} + m_Name: InteractionLayerSettings + m_EditorClassIdentifier: + m_LayerNames: + - Default + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/Resources/InteractionLayerSettings.asset.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/Resources/InteractionLayerSettings.asset.meta new file mode 100644 index 00000000..7dccc052 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/Resources/InteractionLayerSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3e0990ce069a176488c19380d6da111a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/Resources/XRDeviceSimulatorSettings.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/Resources/XRDeviceSimulatorSettings.asset new file mode 100644 index 00000000..7466a7d1 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/Resources/XRDeviceSimulatorSettings.asset @@ -0,0 +1,16 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 690929a59dc7a42da9030305190d391f, type: 3} + m_Name: XRDeviceSimulatorSettings + m_EditorClassIdentifier: + m_AutomaticallyInstantiateSimulatorPrefab: 0 + m_SimulatorPrefab: {fileID: 0} diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/Resources/XRDeviceSimulatorSettings.asset.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/Resources/XRDeviceSimulatorSettings.asset.meta new file mode 100644 index 00000000..7ed0a02c --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/Resources/XRDeviceSimulatorSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7f994e6ea9c904c41b88cdf098587bf3 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/XRInteractionEditorSettings.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/XRInteractionEditorSettings.asset new file mode 100644 index 00000000..529491b4 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/XRInteractionEditorSettings.asset @@ -0,0 +1,16 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2d38fb1463c5c804b8847c20e8873623, type: 3} + m_Name: XRInteractionEditorSettings + m_EditorClassIdentifier: + m_InteractionLayerUpdaterShown: 1 + m_ShowOldInteractionLayerMaskInInspector: 0 diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/XRInteractionEditorSettings.asset.meta b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/XRInteractionEditorSettings.asset.meta new file mode 100644 index 00000000..48adcca0 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Assets/XRI/Settings/XRInteractionEditorSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 183816796b8112449b485caafbe4f4ec +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Packages/manifest.json b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Packages/manifest.json new file mode 100644 index 00000000..be72753b --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Packages/manifest.json @@ -0,0 +1,50 @@ +{ + "dependencies": { + "com.microsoft.mixedreality.openxr": "file:MixedReality/com.microsoft.mixedreality.openxr-1.8.0.tgz", + "com.microsoft.mixedreality.toolkit.foundation": "file:MixedReality/com.microsoft.mixedreality.toolkit.foundation-2.8.3.tgz", + "com.microsoft.mixedreality.toolkit.standardassets": "file:MixedReality/com.microsoft.mixedreality.toolkit.standardassets-2.8.3.tgz", + "com.microsoft.mixedreality.webview.unity": "file:MixedReality/com.microsoft.mixedreality.webview.unity-0.17.1-pre.5.tgz", + "com.unity.collab-proxy": "2.0.3", + "com.unity.ide.rider": "3.0.20", + "com.unity.ide.visualstudio": "2.0.18", + "com.unity.ide.vscode": "1.2.5", + "com.unity.test-framework": "1.1.31", + "com.unity.textmeshpro": "3.0.6", + "com.unity.timeline": "1.6.4", + "com.unity.ugui": "1.0.0", + "com.unity.visualscripting": "1.8.0", + "com.unity.xr.interaction.toolkit": "2.3.1", + "com.unity.xr.openxr": "1.7.0", + "com.unity.modules.ai": "1.0.0", + "com.unity.modules.androidjni": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.cloth": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.physics2d": "1.0.0", + "com.unity.modules.screencapture": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.terrainphysics": "1.0.0", + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.umbra": "1.0.0", + "com.unity.modules.unityanalytics": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.unitywebrequesttexture": "1.0.0", + "com.unity.modules.unitywebrequestwww": "1.0.0", + "com.unity.modules.vehicles": "1.0.0", + "com.unity.modules.video": "1.0.0", + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.wind": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } +} diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Packages/manifest.json.backup b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Packages/manifest.json.backup new file mode 100644 index 00000000..9c226758 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Packages/manifest.json.backup @@ -0,0 +1,50 @@ +{ + "dependencies": { + "com.microsoft.mixedreality.openxr": "file:MixedReality/com.microsoft.mixedreality.openxr-1.8.0.tgz", + "com.microsoft.mixedreality.toolkit.foundation": "file:MixedReality/com.microsoft.mixedreality.toolkit.foundation-2.8.3.tgz", + "com.microsoft.mixedreality.toolkit.standardassets": "file:MixedReality/com.microsoft.mixedreality.toolkit.standardassets-2.8.3.tgz", + "com.microsoft.mixedreality.webview.unity": "file:MixedReality/com.microsoft.mixedreality.webview.unity-0.17.1-pre.2.tgz", + "com.unity.collab-proxy": "1.17.7", + "com.unity.ide.rider": "3.0.18", + "com.unity.ide.visualstudio": "2.0.17", + "com.unity.ide.vscode": "1.2.5", + "com.unity.test-framework": "1.1.31", + "com.unity.textmeshpro": "3.0.6", + "com.unity.timeline": "1.6.4", + "com.unity.ugui": "1.0.0", + "com.unity.visualscripting": "1.8.0", + "com.unity.xr.interaction.toolkit": "2.2.0", + "com.unity.xr.openxr": "1.7.0", + "com.unity.modules.ai": "1.0.0", + "com.unity.modules.androidjni": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.cloth": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.physics2d": "1.0.0", + "com.unity.modules.screencapture": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.terrainphysics": "1.0.0", + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.umbra": "1.0.0", + "com.unity.modules.unityanalytics": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.unitywebrequesttexture": "1.0.0", + "com.unity.modules.unitywebrequestwww": "1.0.0", + "com.unity.modules.vehicles": "1.0.0", + "com.unity.modules.video": "1.0.0", + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.wind": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } +} diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Packages/manifest.json.backup0 b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Packages/manifest.json.backup0 new file mode 100644 index 00000000..9c226758 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Packages/manifest.json.backup0 @@ -0,0 +1,50 @@ +{ + "dependencies": { + "com.microsoft.mixedreality.openxr": "file:MixedReality/com.microsoft.mixedreality.openxr-1.8.0.tgz", + "com.microsoft.mixedreality.toolkit.foundation": "file:MixedReality/com.microsoft.mixedreality.toolkit.foundation-2.8.3.tgz", + "com.microsoft.mixedreality.toolkit.standardassets": "file:MixedReality/com.microsoft.mixedreality.toolkit.standardassets-2.8.3.tgz", + "com.microsoft.mixedreality.webview.unity": "file:MixedReality/com.microsoft.mixedreality.webview.unity-0.17.1-pre.2.tgz", + "com.unity.collab-proxy": "1.17.7", + "com.unity.ide.rider": "3.0.18", + "com.unity.ide.visualstudio": "2.0.17", + "com.unity.ide.vscode": "1.2.5", + "com.unity.test-framework": "1.1.31", + "com.unity.textmeshpro": "3.0.6", + "com.unity.timeline": "1.6.4", + "com.unity.ugui": "1.0.0", + "com.unity.visualscripting": "1.8.0", + "com.unity.xr.interaction.toolkit": "2.2.0", + "com.unity.xr.openxr": "1.7.0", + "com.unity.modules.ai": "1.0.0", + "com.unity.modules.androidjni": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.cloth": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.physics2d": "1.0.0", + "com.unity.modules.screencapture": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.terrainphysics": "1.0.0", + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.umbra": "1.0.0", + "com.unity.modules.unityanalytics": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.unitywebrequesttexture": "1.0.0", + "com.unity.modules.unitywebrequestwww": "1.0.0", + "com.unity.modules.vehicles": "1.0.0", + "com.unity.modules.video": "1.0.0", + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.wind": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } +} diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Packages/packages-lock.json b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Packages/packages-lock.json new file mode 100644 index 00000000..41630da1 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/Packages/packages-lock.json @@ -0,0 +1,487 @@ +{ + "dependencies": { + "com.microsoft.mixedreality.openxr": { + "version": "file:MixedReality/com.microsoft.mixedreality.openxr-1.8.0.tgz", + "depth": 0, + "source": "local-tarball", + "dependencies": { + "com.unity.xr.arfoundation": "4.1.7", + "com.unity.xr.management": "4.2.0", + "com.unity.xr.openxr": "1.5.3", + "com.unity.xr.core-utils": "2.1.0" + } + }, + "com.microsoft.mixedreality.toolkit.foundation": { + "version": "file:MixedReality/com.microsoft.mixedreality.toolkit.foundation-2.8.3.tgz", + "depth": 0, + "source": "local-tarball", + "dependencies": { + "com.microsoft.mixedreality.toolkit.standardassets": "2.8.3" + } + }, + "com.microsoft.mixedreality.toolkit.standardassets": { + "version": "file:MixedReality/com.microsoft.mixedreality.toolkit.standardassets-2.8.3.tgz", + "depth": 0, + "source": "local-tarball", + "dependencies": { + "com.unity.textmeshpro": "2.1.4" + } + }, + "com.microsoft.mixedreality.webview.unity": { + "version": "file:MixedReality/com.microsoft.mixedreality.webview.unity-0.17.1-pre.5.tgz", + "depth": 0, + "source": "local-tarball", + "dependencies": { + "com.unity.inputsystem": "1.4.4" + } + }, + "com.unity.collab-proxy": { + "version": "2.0.3", + "depth": 0, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.ext.nunit": { + "version": "1.0.6", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.ide.rider": { + "version": "3.0.20", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ext.nunit": "1.0.6" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ide.visualstudio": { + "version": "2.0.18", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.1.9" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ide.vscode": { + "version": "1.2.5", + "depth": 0, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.inputsystem": { + "version": "1.5.1", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.modules.uielements": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.mathematics": { + "version": "1.2.6", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.subsystemregistration": { + "version": "1.1.0", + "depth": 3, + "source": "registry", + "dependencies": { + "com.unity.modules.subsystems": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.test-framework": { + "version": "1.1.31", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ext.nunit": "1.0.6", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.textmeshpro": { + "version": "3.0.6", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ugui": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.timeline": { + "version": "1.6.4", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.director": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ugui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0" + } + }, + "com.unity.visualscripting": { + "version": "1.8.0", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ugui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.xr.arfoundation": { + "version": "4.2.7", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.xr.arsubsystems": "4.2.7", + "com.unity.xr.management": "4.0.1", + "com.unity.modules.particlesystem": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.xr.arsubsystems": { + "version": "4.2.7", + "depth": 2, + "source": "registry", + "dependencies": { + "com.unity.subsystemregistration": "1.1.0", + "com.unity.xr.management": "4.0.1" + }, + "url": "https://packages.unity.com" + }, + "com.unity.xr.core-utils": { + "version": "2.2.0", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.modules.xr": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.xr.interaction.toolkit": { + "version": "2.3.1", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.inputsystem": "1.4.4", + "com.unity.mathematics": "1.2.6", + "com.unity.ugui": "1.0.0", + "com.unity.xr.core-utils": "2.2.0", + "com.unity.xr.legacyinputhelpers": "2.1.10", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.physics": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.xr.legacyinputhelpers": { + "version": "2.1.10", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.xr": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.xr.management": { + "version": "4.3.3", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.modules.subsystems": "1.0.0", + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.xr": "1.0.0", + "com.unity.xr.legacyinputhelpers": "2.1.7" + }, + "url": "https://packages.unity.com" + }, + "com.unity.xr.openxr": { + "version": "1.7.0", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.xr.management": "4.0.1", + "com.unity.xr.legacyinputhelpers": "2.1.2", + "com.unity.inputsystem": "1.4.4" + }, + "url": "https://packages.unity.com" + }, + "com.unity.modules.ai": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.androidjni": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.animation": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.assetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.audio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.cloth": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.director": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.animation": "1.0.0" + } + }, + "com.unity.modules.imageconversion": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.imgui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.jsonserialize": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.particlesystem": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics2d": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.screencapture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.subsystems": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.terrain": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.terrainphysics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.terrain": "1.0.0" + } + }, + "com.unity.modules.tilemap": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics2d": "1.0.0" + } + }, + "com.unity.modules.ui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.uielements": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.uielementsnative": "1.0.0" + } + }, + "com.unity.modules.uielementsnative": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.umbra": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unityanalytics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.unitywebrequest": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unitywebrequestassetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestaudio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.audio": "1.0.0" + } + }, + "com.unity.modules.unitywebrequesttexture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestwww": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.vehicles": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.video": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.vr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } + }, + "com.unity.modules.wind": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.xr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.subsystems": "1.0.0" + } + } + } +} diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/AudioManager.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/AudioManager.asset new file mode 100644 index 00000000..07ebfb05 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/AudioManager.asset @@ -0,0 +1,19 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!11 &1 +AudioManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Volume: 1 + Rolloff Scale: 1 + Doppler Factor: 1 + Default Speaker Mode: 2 + m_SampleRate: 0 + m_DSPBufferSize: 1024 + m_VirtualVoiceCount: 512 + m_RealVoiceCount: 32 + m_SpatializerPlugin: + m_AmbisonicDecoderPlugin: + m_DisableAudio: 0 + m_VirtualizeEffects: 1 + m_RequestedDSPBufferSize: 1024 diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/ClusterInputManager.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/ClusterInputManager.asset new file mode 100644 index 00000000..e7886b26 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/ClusterInputManager.asset @@ -0,0 +1,6 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!236 &1 +ClusterInputManager: + m_ObjectHideFlags: 0 + m_Inputs: [] diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/DynamicsManager.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/DynamicsManager.asset new file mode 100644 index 00000000..cdc1f3ea --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/DynamicsManager.asset @@ -0,0 +1,34 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!55 &1 +PhysicsManager: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_Gravity: {x: 0, y: -9.81, z: 0} + m_DefaultMaterial: {fileID: 0} + m_BounceThreshold: 2 + m_SleepThreshold: 0.005 + m_DefaultContactOffset: 0.01 + m_DefaultSolverIterations: 6 + m_DefaultSolverVelocityIterations: 1 + m_QueriesHitBackfaces: 0 + m_QueriesHitTriggers: 1 + m_EnableAdaptiveForce: 0 + m_ClothInterCollisionDistance: 0 + m_ClothInterCollisionStiffness: 0 + m_ContactsGeneration: 1 + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + m_AutoSimulation: 1 + m_AutoSyncTransforms: 0 + m_ReuseCollisionCallbacks: 1 + m_ClothInterCollisionSettingsToggle: 0 + m_ContactPairsMode: 0 + m_BroadphaseType: 0 + m_WorldBounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 250, y: 250, z: 250} + m_WorldSubdivisions: 8 + m_FrictionType: 0 + m_EnableEnhancedDeterminism: 0 + m_EnableUnifiedHeightmaps: 1 + m_DefaultMaxAngluarSpeed: 7 diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/EditorBuildSettings.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/EditorBuildSettings.asset new file mode 100644 index 00000000..ccce9056 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/EditorBuildSettings.asset @@ -0,0 +1,13 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1045 &1 +EditorBuildSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Scenes: + - enabled: 1 + path: Assets/Scenes/SampleScene.unity + guid: 9fc0d4010bbf28b4594072e72b8655ab + m_configObjects: + com.unity.xr.management.loader_settings: {fileID: 11400000, guid: 25312d4015a310f499767577dc2d8b23, type: 2} + com.unity.xr.openxr.settings4: {fileID: 11400000, guid: 541a1cf0c39d86043af97cfb801628fd, type: 2} diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/EditorSettings.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/EditorSettings.asset new file mode 100644 index 00000000..1e44a0a1 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/EditorSettings.asset @@ -0,0 +1,30 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!159 &1 +EditorSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_ExternalVersionControlSupport: Visible Meta Files + m_SerializationMode: 2 + m_LineEndingsForNewScripts: 0 + m_DefaultBehaviorMode: 0 + m_PrefabRegularEnvironment: {fileID: 0} + m_PrefabUIEnvironment: {fileID: 0} + m_SpritePackerMode: 0 + m_SpritePackerPaddingPower: 1 + m_EtcTextureCompressorBehavior: 1 + m_EtcTextureFastCompressor: 1 + m_EtcTextureNormalCompressor: 2 + m_EtcTextureBestCompressor: 4 + m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref + m_ProjectGenerationRootNamespace: + m_CollabEditorSettings: + inProgressEnabled: 1 + m_EnableTextureStreamingInEditMode: 1 + m_EnableTextureStreamingInPlayMode: 1 + m_AsyncShaderCompilation: 1 + m_EnterPlayModeOptionsEnabled: 0 + m_EnterPlayModeOptions: 3 + m_ShowLightmapResolutionOverlay: 1 + m_UseLegacyProbeSampleCount: 0 + m_SerializeInlineMappingsOnOneLine: 1 diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/GraphicsSettings.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/GraphicsSettings.asset new file mode 100644 index 00000000..43369e3c --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/GraphicsSettings.asset @@ -0,0 +1,63 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!30 &1 +GraphicsSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_Deferred: + m_Mode: 1 + m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} + m_DeferredReflections: + m_Mode: 1 + m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} + m_ScreenSpaceShadows: + m_Mode: 1 + m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} + m_LegacyDeferred: + m_Mode: 1 + m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} + m_DepthNormals: + m_Mode: 1 + m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} + m_MotionVectors: + m_Mode: 1 + m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} + m_LightHalo: + m_Mode: 1 + m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} + m_LensFlare: + m_Mode: 1 + m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} + m_AlwaysIncludedShaders: + - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} + m_PreloadedShaders: [] + m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, + type: 0} + m_CustomRenderPipeline: {fileID: 0} + m_TransparencySortMode: 0 + m_TransparencySortAxis: {x: 0, y: 0, z: 1} + m_DefaultRenderingPath: 1 + m_DefaultMobileRenderingPath: 1 + m_TierSettings: [] + m_LightmapStripping: 0 + m_FogStripping: 0 + m_InstancingStripping: 0 + m_LightmapKeepPlain: 1 + m_LightmapKeepDirCombined: 1 + m_LightmapKeepDynamicPlain: 1 + m_LightmapKeepDynamicDirCombined: 1 + m_LightmapKeepShadowMask: 1 + m_LightmapKeepSubtractive: 1 + m_FogKeepLinear: 1 + m_FogKeepExp: 1 + m_FogKeepExp2: 1 + m_AlbedoSwatchInfos: [] + m_LightsUseLinearIntensity: 0 + m_LightsUseColorTemperature: 0 + m_LogWhenShaderIsCompiled: 0 + m_AllowEnlightenSupportForUpgradedProject: 0 diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/InputManager.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/InputManager.asset new file mode 100644 index 00000000..7a28a619 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/InputManager.asset @@ -0,0 +1,776 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!13 &1 +InputManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Axes: + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: a + altPositiveButton: d + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: s + altPositiveButton: w + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: mouse 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: mouse 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: mouse 2 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: space + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse X + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse Y + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse ScrollWheel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 2 + joyNum: 0 + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 1 + type: 2 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 0 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 1 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 2 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 3 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: enter + altNegativeButton: + altPositiveButton: space + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Cancel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: escape + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 2 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_4 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 3 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_5 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 4 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_6 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 5 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_7 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 6 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_8 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 7 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_9 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 8 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_10 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 9 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_11 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 10 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_12 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 11 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_13 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 12 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_14 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 13 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_15 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 14 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_16 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 15 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_17 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 16 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_18 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 17 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_19 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 18 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_20 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 19 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_21 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 20 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_22 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 21 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_23 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 22 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_24 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 23 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_25 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 24 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_26 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 25 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_27 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 26 + joyNum: 0 + - serializedVersion: 3 + m_Name: AXIS_28 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 27 + joyNum: 0 + - serializedVersion: 3 + m_Name: UpDown + descriptiveName: + descriptiveNegativeName: + negativeButton: q + positiveButton: e + altNegativeButton: + altPositiveButton: + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: -1 + joyNum: 0 + - serializedVersion: 3 + m_Name: UpDown + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 2 + joyNum: 0 + m_UsePhysicalKeys: 0 diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/MemorySettings.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/MemorySettings.asset new file mode 100644 index 00000000..5b5facec --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/MemorySettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!387306366 &1 +MemorySettings: + m_ObjectHideFlags: 0 + m_EditorMemorySettings: + m_MainAllocatorBlockSize: -1 + m_ThreadAllocatorBlockSize: -1 + m_MainGfxBlockSize: -1 + m_ThreadGfxBlockSize: -1 + m_CacheBlockSize: -1 + m_TypetreeBlockSize: -1 + m_ProfilerBlockSize: -1 + m_ProfilerEditorBlockSize: -1 + m_BucketAllocatorGranularity: -1 + m_BucketAllocatorBucketsCount: -1 + m_BucketAllocatorBlockSize: -1 + m_BucketAllocatorBlockCount: -1 + m_ProfilerBucketAllocatorGranularity: -1 + m_ProfilerBucketAllocatorBucketsCount: -1 + m_ProfilerBucketAllocatorBlockSize: -1 + m_ProfilerBucketAllocatorBlockCount: -1 + m_TempAllocatorSizeMain: -1 + m_JobTempAllocatorBlockSize: -1 + m_BackgroundJobTempAllocatorBlockSize: -1 + m_JobTempAllocatorReducedBlockSize: -1 + m_TempAllocatorSizeGIBakingWorker: -1 + m_TempAllocatorSizeNavMeshWorker: -1 + m_TempAllocatorSizeAudioWorker: -1 + m_TempAllocatorSizeCloudWorker: -1 + m_TempAllocatorSizeGfx: -1 + m_TempAllocatorSizeJobWorker: -1 + m_TempAllocatorSizeBackgroundWorker: -1 + m_TempAllocatorSizePreloadManager: -1 + m_PlatformMemorySettings: {} diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/NavMeshAreas.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/NavMeshAreas.asset new file mode 100644 index 00000000..3b0b7c3d --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/NavMeshAreas.asset @@ -0,0 +1,91 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!126 &1 +NavMeshProjectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + areas: + - name: Walkable + cost: 1 + - name: Not Walkable + cost: 1 + - name: Jump + cost: 2 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + m_LastAgentTypeID: -887442657 + m_Settings: + - serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.75 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_SettingNames: + - Humanoid diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/PackageManagerSettings.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/PackageManagerSettings.asset new file mode 100644 index 00000000..112a053b --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/PackageManagerSettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 61 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_EnablePreReleasePackages: 0 + m_EnablePackageDependencies: 0 + m_AdvancedSettingsExpanded: 1 + m_ScopedRegistriesSettingsExpanded: 1 + m_SeeAllPackageVersions: 0 + oneTimeWarningShown: 0 + m_Registries: + - m_Id: main + m_Name: + m_Url: https://packages.unity.com + m_Scopes: [] + m_IsDefault: 1 + m_Capabilities: 7 + m_UserSelectedRegistryName: + m_UserAddingNewScopedRegistry: 0 + m_RegistryInfoDraft: + m_Modified: 0 + m_ErrorMessage: + m_UserModificationsInstanceId: -830 + m_OriginalInstanceId: -832 + m_LoadAssets: 0 diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/Physics2DSettings.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/Physics2DSettings.asset new file mode 100644 index 00000000..47880b1c --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/Physics2DSettings.asset @@ -0,0 +1,56 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!19 &1 +Physics2DSettings: + m_ObjectHideFlags: 0 + serializedVersion: 4 + m_Gravity: {x: 0, y: -9.81} + m_DefaultMaterial: {fileID: 0} + m_VelocityIterations: 8 + m_PositionIterations: 3 + m_VelocityThreshold: 1 + m_MaxLinearCorrection: 0.2 + m_MaxAngularCorrection: 8 + m_MaxTranslationSpeed: 100 + m_MaxRotationSpeed: 360 + m_BaumgarteScale: 0.2 + m_BaumgarteTimeOfImpactScale: 0.75 + m_TimeToSleep: 0.5 + m_LinearSleepTolerance: 0.01 + m_AngularSleepTolerance: 2 + m_DefaultContactOffset: 0.01 + m_JobOptions: + serializedVersion: 2 + useMultithreading: 0 + useConsistencySorting: 0 + m_InterpolationPosesPerJob: 100 + m_NewContactsPerJob: 30 + m_CollideContactsPerJob: 100 + m_ClearFlagsPerJob: 200 + m_ClearBodyForcesPerJob: 200 + m_SyncDiscreteFixturesPerJob: 50 + m_SyncContinuousFixturesPerJob: 50 + m_FindNearestContactsPerJob: 100 + m_UpdateTriggerContactsPerJob: 100 + m_IslandSolverCostThreshold: 100 + m_IslandSolverBodyCostScale: 1 + m_IslandSolverContactCostScale: 10 + m_IslandSolverJointCostScale: 10 + m_IslandSolverBodiesPerJob: 50 + m_IslandSolverContactsPerJob: 50 + m_AutoSimulation: 1 + m_QueriesHitTriggers: 1 + m_QueriesStartInColliders: 1 + m_CallbacksOnDisable: 1 + m_ReuseCollisionCallbacks: 1 + m_AutoSyncTransforms: 0 + m_AlwaysShowColliders: 0 + m_ShowColliderSleep: 1 + m_ShowColliderContacts: 0 + m_ShowColliderAABB: 0 + m_ContactArrowScale: 0.2 + m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} + m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} + m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} + m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/PresetManager.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/PresetManager.asset new file mode 100644 index 00000000..67a94dae --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/PresetManager.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1386491679 &1 +PresetManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_DefaultPresets: {} diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/ProjectSettings.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/ProjectSettings.asset new file mode 100644 index 00000000..32048859 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/ProjectSettings.asset @@ -0,0 +1,737 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!129 &1 +PlayerSettings: + m_ObjectHideFlags: 0 + serializedVersion: 24 + productGUID: 5644c80d498d50e4e9f702e2639c32a1 + AndroidProfiler: 0 + AndroidFilterTouchesWhenObscured: 0 + AndroidEnableSustainedPerformanceMode: 0 + defaultScreenOrientation: 4 + targetDevice: 2 + useOnDemandResources: 0 + accelerometerFrequency: 60 + companyName: Microsoft + productName: WebView2HoloLensSample + defaultCursor: {fileID: 0} + cursorHotspot: {x: 0, y: 0} + m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1} + m_ShowUnitySplashScreen: 1 + m_ShowUnitySplashLogo: 1 + m_SplashScreenOverlayOpacity: 1 + m_SplashScreenAnimation: 1 + m_SplashScreenLogoStyle: 1 + m_SplashScreenDrawMode: 0 + m_SplashScreenBackgroundAnimationZoom: 1 + m_SplashScreenLogoAnimationZoom: 1 + m_SplashScreenBackgroundLandscapeAspect: 1 + m_SplashScreenBackgroundPortraitAspect: 1 + m_SplashScreenBackgroundLandscapeUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenBackgroundPortraitUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenLogos: [] + m_VirtualRealitySplashScreen: {fileID: 0} + m_HolographicTrackingLossScreen: {fileID: 0} + defaultScreenWidth: 1920 + defaultScreenHeight: 1080 + defaultScreenWidthWeb: 960 + defaultScreenHeightWeb: 600 + m_StereoRenderingPath: 2 + m_ActiveColorSpace: 1 + m_MTRendering: 1 + mipStripping: 0 + numberOfMipsStripped: 0 + m_StackTraceTypes: 010000000100000001000000010000000100000001000000 + iosShowActivityIndicatorOnLoading: -1 + androidShowActivityIndicatorOnLoading: -1 + iosUseCustomAppBackgroundBehavior: 0 + iosAllowHTTPDownload: 1 + allowedAutorotateToPortrait: 1 + allowedAutorotateToPortraitUpsideDown: 1 + allowedAutorotateToLandscapeRight: 1 + allowedAutorotateToLandscapeLeft: 1 + useOSAutorotation: 1 + use32BitDisplayBuffer: 1 + preserveFramebufferAlpha: 0 + disableDepthAndStencilBuffers: 0 + androidStartInFullscreen: 1 + androidRenderOutsideSafeArea: 1 + androidUseSwappy: 1 + androidBlitType: 0 + androidResizableWindow: 0 + androidDefaultWindowWidth: 1920 + androidDefaultWindowHeight: 1080 + androidMinimumWindowWidth: 400 + androidMinimumWindowHeight: 300 + androidFullscreenMode: 1 + defaultIsNativeResolution: 1 + macRetinaSupport: 1 + runInBackground: 0 + captureSingleScreen: 0 + muteOtherAudioSources: 0 + Prepare IOS For Recording: 0 + Force IOS Speakers When Recording: 0 + deferSystemGesturesMode: 0 + hideHomeButton: 0 + submitAnalytics: 1 + usePlayerLog: 1 + bakeCollisionMeshes: 0 + forceSingleInstance: 0 + useFlipModelSwapchain: 1 + resizableWindow: 0 + useMacAppStoreValidation: 0 + macAppStoreCategory: public.app-category.games + gpuSkinning: 1 + xboxPIXTextureCapture: 0 + xboxEnableAvatar: 0 + xboxEnableKinect: 0 + xboxEnableKinectAutoTracking: 0 + xboxEnableFitness: 0 + visibleInBackground: 1 + allowFullscreenSwitch: 1 + fullscreenMode: 1 + xboxSpeechDB: 0 + xboxEnableHeadOrientation: 0 + xboxEnableGuest: 0 + xboxEnablePIXSampling: 0 + metalFramebufferOnly: 0 + xboxOneResolution: 0 + xboxOneSResolution: 0 + xboxOneXResolution: 3 + xboxOneMonoLoggingLevel: 0 + xboxOneLoggingLevel: 1 + xboxOneDisableEsram: 0 + xboxOneEnableTypeOptimization: 0 + xboxOnePresentImmediateThreshold: 0 + switchQueueCommandMemory: 0 + switchQueueControlMemory: 16384 + switchQueueComputeMemory: 262144 + switchNVNShaderPoolsGranularity: 33554432 + switchNVNDefaultPoolsGranularity: 16777216 + switchNVNOtherPoolsGranularity: 16777216 + switchNVNMaxPublicTextureIDCount: 0 + switchNVNMaxPublicSamplerIDCount: 0 + stadiaPresentMode: 0 + stadiaTargetFramerate: 0 + vulkanNumSwapchainBuffers: 3 + vulkanEnableSetSRGBWrite: 0 + vulkanEnablePreTransform: 1 + vulkanEnableLateAcquireNextImage: 0 + vulkanEnableCommandBufferRecycling: 1 + m_SupportedAspectRatios: + 4:3: 1 + 5:4: 1 + 16:10: 1 + 16:9: 1 + Others: 1 + bundleVersion: 0.1 + preloadedAssets: + - {fileID: -5444848369939482447, guid: 25312d4015a310f499767577dc2d8b23, type: 2} + - {fileID: -5281385832365046672, guid: 541a1cf0c39d86043af97cfb801628fd, type: 2} + metroInputSource: 0 + wsaTransparentSwapchain: 0 + m_HolographicPauseOnTrackingLoss: 1 + xboxOneDisableKinectGpuReservation: 1 + xboxOneEnable7thCore: 1 + vrSettings: + enable360StereoCapture: 0 + isWsaHolographicRemotingEnabled: 0 + enableFrameTimingStats: 0 + enableOpenGLProfilerGPURecorders: 1 + useHDRDisplay: 0 + D3DHDRBitDepth: 0 + m_ColorGamuts: 00000000 + targetPixelDensity: 30 + resolutionScalingMode: 0 + resetResolutionOnWindowResize: 0 + androidSupportedAspectRatio: 1 + androidMaxAspectRatio: 2.1 + applicationIdentifier: {} + buildNumber: + Standalone: 0 + iPhone: 0 + tvOS: 0 + overrideDefaultApplicationIdentifier: 0 + AndroidBundleVersionCode: 1 + AndroidMinSdkVersion: 22 + AndroidTargetSdkVersion: 0 + AndroidPreferredInstallLocation: 1 + aotOptions: + stripEngineCode: 1 + iPhoneStrippingLevel: 0 + iPhoneScriptCallOptimization: 0 + ForceInternetPermission: 0 + ForceSDCardPermission: 0 + CreateWallpaper: 0 + APKExpansionFiles: 0 + keepLoadedShadersAlive: 0 + StripUnusedMeshComponents: 1 + VertexChannelCompressionMask: 4054 + iPhoneSdkVersion: 988 + iOSTargetOSVersionString: 12.0 + tvOSSdkVersion: 0 + tvOSRequireExtendedGameController: 0 + tvOSTargetOSVersionString: 12.0 + uIPrerenderedIcon: 0 + uIRequiresPersistentWiFi: 0 + uIRequiresFullScreen: 1 + uIStatusBarHidden: 1 + uIExitOnSuspend: 0 + uIStatusBarStyle: 0 + appleTVSplashScreen: {fileID: 0} + appleTVSplashScreen2x: {fileID: 0} + tvOSSmallIconLayers: [] + tvOSSmallIconLayers2x: [] + tvOSLargeIconLayers: [] + tvOSLargeIconLayers2x: [] + tvOSTopShelfImageLayers: [] + tvOSTopShelfImageLayers2x: [] + tvOSTopShelfImageWideLayers: [] + tvOSTopShelfImageWideLayers2x: [] + iOSLaunchScreenType: 0 + iOSLaunchScreenPortrait: {fileID: 0} + iOSLaunchScreenLandscape: {fileID: 0} + iOSLaunchScreenBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreenFillPct: 100 + iOSLaunchScreenSize: 100 + iOSLaunchScreenCustomXibPath: + iOSLaunchScreeniPadType: 0 + iOSLaunchScreeniPadImage: {fileID: 0} + iOSLaunchScreeniPadBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreeniPadFillPct: 100 + iOSLaunchScreeniPadSize: 100 + iOSLaunchScreeniPadCustomXibPath: + iOSLaunchScreenCustomStoryboardPath: + iOSLaunchScreeniPadCustomStoryboardPath: + iOSDeviceRequirements: [] + iOSURLSchemes: [] + macOSURLSchemes: [] + iOSBackgroundModes: 0 + iOSMetalForceHardShadows: 0 + metalEditorSupport: 1 + metalAPIValidation: 1 + iOSRenderExtraFrameOnPause: 0 + iosCopyPluginsCodeInsteadOfSymlink: 0 + appleDeveloperTeamID: + iOSManualSigningProvisioningProfileID: + tvOSManualSigningProvisioningProfileID: + iOSManualSigningProvisioningProfileType: 0 + tvOSManualSigningProvisioningProfileType: 0 + appleEnableAutomaticSigning: 0 + iOSRequireARKit: 0 + iOSAutomaticallyDetectAndAddCapabilities: 1 + appleEnableProMotion: 0 + shaderPrecisionModel: 0 + clonedFromGUID: c0afd0d1d80e3634a9dac47e8a0426ea + templatePackageId: com.unity.template.3d@8.1.3 + templateDefaultScene: Assets/Scenes/SampleScene.unity + useCustomMainManifest: 0 + useCustomLauncherManifest: 0 + useCustomMainGradleTemplate: 0 + useCustomLauncherGradleManifest: 0 + useCustomBaseGradleTemplate: 0 + useCustomGradlePropertiesTemplate: 0 + useCustomProguardFile: 0 + AndroidTargetArchitectures: 1 + AndroidTargetDevices: 0 + AndroidSplashScreenScale: 0 + androidSplashScreen: {fileID: 0} + AndroidKeystoreName: + AndroidKeyaliasName: + AndroidBuildApkPerCpuArchitecture: 0 + AndroidTVCompatibility: 0 + AndroidIsGame: 1 + AndroidEnableTango: 0 + androidEnableBanner: 1 + androidUseLowAccuracyLocation: 0 + androidUseCustomKeystore: 0 + m_AndroidBanners: + - width: 320 + height: 180 + banner: {fileID: 0} + androidGamepadSupportLevel: 0 + chromeosInputEmulation: 1 + AndroidMinifyWithR8: 0 + AndroidMinifyRelease: 0 + AndroidMinifyDebug: 0 + AndroidValidateAppBundleSize: 1 + AndroidAppBundleSizeToValidate: 150 + m_BuildTargetIcons: [] + m_BuildTargetPlatformIcons: [] + m_BuildTargetBatching: + - m_BuildTarget: Standalone + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: tvOS + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: Android + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: iPhone + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: WebGL + m_StaticBatching: 0 + m_DynamicBatching: 0 + m_BuildTargetShaderSettings: [] + m_BuildTargetGraphicsJobs: + - m_BuildTarget: MacStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: Switch + m_GraphicsJobs: 1 + - m_BuildTarget: MetroSupport + m_GraphicsJobs: 0 + - m_BuildTarget: AppleTVSupport + m_GraphicsJobs: 0 + - m_BuildTarget: BJMSupport + m_GraphicsJobs: 1 + - m_BuildTarget: LinuxStandaloneSupport + m_GraphicsJobs: 1 + - m_BuildTarget: PS4Player + m_GraphicsJobs: 1 + - m_BuildTarget: iOSSupport + m_GraphicsJobs: 0 + - m_BuildTarget: WindowsStandaloneSupport + m_GraphicsJobs: 1 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobs: 1 + - m_BuildTarget: LuminSupport + m_GraphicsJobs: 0 + - m_BuildTarget: AndroidPlayer + m_GraphicsJobs: 0 + - m_BuildTarget: WebGLSupport + m_GraphicsJobs: 0 + m_BuildTargetGraphicsJobMode: + - m_BuildTarget: PS4Player + m_GraphicsJobMode: 0 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobMode: 0 + m_BuildTargetGraphicsAPIs: + - m_BuildTarget: AndroidPlayer + m_APIs: 0b00000008000000 + m_Automatic: 0 + - m_BuildTarget: iOSSupport + m_APIs: 10000000 + m_Automatic: 1 + - m_BuildTarget: AppleTVSupport + m_APIs: 10000000 + m_Automatic: 1 + - m_BuildTarget: WebGLSupport + m_APIs: 0b000000 + m_Automatic: 1 + m_BuildTargetVRSettings: + - m_BuildTarget: Standalone + m_Enabled: 0 + m_Devices: + - Oculus + - OpenVR + m_DefaultShaderChunkSizeInMB: 16 + m_DefaultShaderChunkCount: 0 + openGLRequireES31: 0 + openGLRequireES31AEP: 0 + openGLRequireES32: 0 + m_TemplateCustomTags: {} + mobileMTRendering: + Android: 1 + iPhone: 1 + tvOS: 1 + m_BuildTargetGroupLightmapEncodingQuality: + - m_BuildTarget: Android + m_EncodingQuality: 1 + - m_BuildTarget: iPhone + m_EncodingQuality: 1 + - m_BuildTarget: tvOS + m_EncodingQuality: 1 + m_BuildTargetGroupLightmapSettings: [] + m_BuildTargetNormalMapEncoding: + - m_BuildTarget: Android + m_Encoding: 1 + - m_BuildTarget: iPhone + m_Encoding: 1 + - m_BuildTarget: tvOS + m_Encoding: 1 + m_BuildTargetDefaultTextureCompressionFormat: [] + playModeTestRunnerEnabled: 0 + runPlayModeTestAsEditModeTest: 0 + actionOnDotNetUnhandledException: 1 + enableInternalProfiler: 0 + logObjCUncaughtExceptions: 1 + enableCrashReportAPI: 0 + cameraUsageDescription: + locationUsageDescription: + microphoneUsageDescription: + bluetoothUsageDescription: + switchNMETAOverride: + switchNetLibKey: + switchSocketMemoryPoolSize: 6144 + switchSocketAllocatorPoolSize: 128 + switchSocketConcurrencyLimit: 14 + switchScreenResolutionBehavior: 2 + switchUseCPUProfiler: 0 + switchUseGOLDLinker: 0 + switchLTOSetting: 0 + switchApplicationID: 0x01004b9000490000 + switchNSODependencies: + switchTitleNames_0: + switchTitleNames_1: + switchTitleNames_2: + switchTitleNames_3: + switchTitleNames_4: + switchTitleNames_5: + switchTitleNames_6: + switchTitleNames_7: + switchTitleNames_8: + switchTitleNames_9: + switchTitleNames_10: + switchTitleNames_11: + switchTitleNames_12: + switchTitleNames_13: + switchTitleNames_14: + switchTitleNames_15: + switchPublisherNames_0: + switchPublisherNames_1: + switchPublisherNames_2: + switchPublisherNames_3: + switchPublisherNames_4: + switchPublisherNames_5: + switchPublisherNames_6: + switchPublisherNames_7: + switchPublisherNames_8: + switchPublisherNames_9: + switchPublisherNames_10: + switchPublisherNames_11: + switchPublisherNames_12: + switchPublisherNames_13: + switchPublisherNames_14: + switchPublisherNames_15: + switchIcons_0: {fileID: 0} + switchIcons_1: {fileID: 0} + switchIcons_2: {fileID: 0} + switchIcons_3: {fileID: 0} + switchIcons_4: {fileID: 0} + switchIcons_5: {fileID: 0} + switchIcons_6: {fileID: 0} + switchIcons_7: {fileID: 0} + switchIcons_8: {fileID: 0} + switchIcons_9: {fileID: 0} + switchIcons_10: {fileID: 0} + switchIcons_11: {fileID: 0} + switchIcons_12: {fileID: 0} + switchIcons_13: {fileID: 0} + switchIcons_14: {fileID: 0} + switchIcons_15: {fileID: 0} + switchSmallIcons_0: {fileID: 0} + switchSmallIcons_1: {fileID: 0} + switchSmallIcons_2: {fileID: 0} + switchSmallIcons_3: {fileID: 0} + switchSmallIcons_4: {fileID: 0} + switchSmallIcons_5: {fileID: 0} + switchSmallIcons_6: {fileID: 0} + switchSmallIcons_7: {fileID: 0} + switchSmallIcons_8: {fileID: 0} + switchSmallIcons_9: {fileID: 0} + switchSmallIcons_10: {fileID: 0} + switchSmallIcons_11: {fileID: 0} + switchSmallIcons_12: {fileID: 0} + switchSmallIcons_13: {fileID: 0} + switchSmallIcons_14: {fileID: 0} + switchSmallIcons_15: {fileID: 0} + switchManualHTML: + switchAccessibleURLs: + switchLegalInformation: + switchMainThreadStackSize: 1048576 + switchPresenceGroupId: + switchLogoHandling: 0 + switchReleaseVersion: 0 + switchDisplayVersion: 1.0.0 + switchStartupUserAccount: 0 + switchSupportedLanguagesMask: 0 + switchLogoType: 0 + switchApplicationErrorCodeCategory: + switchUserAccountSaveDataSize: 0 + switchUserAccountSaveDataJournalSize: 0 + switchApplicationAttribute: 0 + switchCardSpecSize: -1 + switchCardSpecClock: -1 + switchRatingsMask: 0 + switchRatingsInt_0: 0 + switchRatingsInt_1: 0 + switchRatingsInt_2: 0 + switchRatingsInt_3: 0 + switchRatingsInt_4: 0 + switchRatingsInt_5: 0 + switchRatingsInt_6: 0 + switchRatingsInt_7: 0 + switchRatingsInt_8: 0 + switchRatingsInt_9: 0 + switchRatingsInt_10: 0 + switchRatingsInt_11: 0 + switchRatingsInt_12: 0 + switchLocalCommunicationIds_0: + switchLocalCommunicationIds_1: + switchLocalCommunicationIds_2: + switchLocalCommunicationIds_3: + switchLocalCommunicationIds_4: + switchLocalCommunicationIds_5: + switchLocalCommunicationIds_6: + switchLocalCommunicationIds_7: + switchParentalControl: 0 + switchAllowsScreenshot: 1 + switchAllowsVideoCapturing: 1 + switchAllowsRuntimeAddOnContentInstall: 0 + switchDataLossConfirmation: 0 + switchUserAccountLockEnabled: 0 + switchSystemResourceMemory: 16777216 + switchSupportedNpadStyles: 22 + switchNativeFsCacheSize: 32 + switchIsHoldTypeHorizontal: 0 + switchSupportedNpadCount: 8 + switchEnableTouchScreen: 1 + switchSocketConfigEnabled: 0 + switchTcpInitialSendBufferSize: 32 + switchTcpInitialReceiveBufferSize: 64 + switchTcpAutoSendBufferSizeMax: 256 + switchTcpAutoReceiveBufferSizeMax: 256 + switchUdpSendBufferSize: 9 + switchUdpReceiveBufferSize: 42 + switchSocketBufferEfficiency: 4 + switchSocketInitializeEnabled: 1 + switchNetworkInterfaceManagerInitializeEnabled: 1 + switchPlayerConnectionEnabled: 1 + switchUseNewStyleFilepaths: 0 + switchUseLegacyFmodPriorities: 1 + switchUseMicroSleepForYield: 1 + switchEnableRamDiskSupport: 0 + switchMicroSleepForYieldTime: 25 + switchRamDiskSpaceSize: 12 + ps4NPAgeRating: 12 + ps4NPTitleSecret: + ps4NPTrophyPackPath: + ps4ParentalLevel: 11 + ps4ContentID: ED1633-NPXX51362_00-0000000000000000 + ps4Category: 0 + ps4MasterVersion: 01.00 + ps4AppVersion: 01.00 + ps4AppType: 0 + ps4ParamSfxPath: + ps4VideoOutPixelFormat: 0 + ps4VideoOutInitialWidth: 1920 + ps4VideoOutBaseModeInitialWidth: 1920 + ps4VideoOutReprojectionRate: 60 + ps4PronunciationXMLPath: + ps4PronunciationSIGPath: + ps4BackgroundImagePath: + ps4StartupImagePath: + ps4StartupImagesFolder: + ps4IconImagesFolder: + ps4SaveDataImagePath: + ps4SdkOverride: + ps4BGMPath: + ps4ShareFilePath: + ps4ShareOverlayImagePath: + ps4PrivacyGuardImagePath: + ps4ExtraSceSysFile: + ps4NPtitleDatPath: + ps4RemotePlayKeyAssignment: -1 + ps4RemotePlayKeyMappingDir: + ps4PlayTogetherPlayerCount: 0 + ps4EnterButtonAssignment: 1 + ps4ApplicationParam1: 0 + ps4ApplicationParam2: 0 + ps4ApplicationParam3: 0 + ps4ApplicationParam4: 0 + ps4DownloadDataSize: 0 + ps4GarlicHeapSize: 2048 + ps4ProGarlicHeapSize: 2560 + playerPrefsMaxSize: 32768 + ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ + ps4pnSessions: 1 + ps4pnPresence: 1 + ps4pnFriends: 1 + ps4pnGameCustomData: 1 + playerPrefsSupport: 0 + enableApplicationExit: 0 + resetTempFolder: 1 + restrictedAudioUsageRights: 0 + ps4UseResolutionFallback: 0 + ps4ReprojectionSupport: 0 + ps4UseAudio3dBackend: 0 + ps4UseLowGarlicFragmentationMode: 1 + ps4SocialScreenEnabled: 0 + ps4ScriptOptimizationLevel: 0 + ps4Audio3dVirtualSpeakerCount: 14 + ps4attribCpuUsage: 0 + ps4PatchPkgPath: + ps4PatchLatestPkgPath: + ps4PatchChangeinfoPath: + ps4PatchDayOne: 0 + ps4attribUserManagement: 0 + ps4attribMoveSupport: 0 + ps4attrib3DSupport: 0 + ps4attribShareSupport: 0 + ps4attribExclusiveVR: 0 + ps4disableAutoHideSplash: 0 + ps4videoRecordingFeaturesUsed: 0 + ps4contentSearchFeaturesUsed: 0 + ps4CompatibilityPS5: 0 + ps4AllowPS5Detection: 0 + ps4GPU800MHz: 1 + ps4attribEyeToEyeDistanceSettingVR: 0 + ps4IncludedModules: [] + ps4attribVROutputEnabled: 0 + monoEnv: + splashScreenBackgroundSourceLandscape: {fileID: 0} + splashScreenBackgroundSourcePortrait: {fileID: 0} + blurSplashScreenBackground: 1 + spritePackerPolicy: + webGLMemorySize: 16 + webGLExceptionSupport: 1 + webGLNameFilesAsHashes: 0 + webGLDataCaching: 1 + webGLDebugSymbols: 0 + webGLEmscriptenArgs: + webGLModulesDirectory: + webGLTemplate: APPLICATION:Default + webGLAnalyzeBuildSize: 0 + webGLUseEmbeddedResources: 0 + webGLCompressionFormat: 1 + webGLWasmArithmeticExceptions: 0 + webGLLinkerTarget: 1 + webGLThreadsSupport: 0 + webGLDecompressionFallback: 0 + webGLPowerPreference: 2 + scriptingDefineSymbols: {} + additionalCompilerArguments: {} + platformArchitecture: {} + scriptingBackend: {} + il2cppCompilerConfiguration: {} + managedStrippingLevel: + EmbeddedLinux: 1 + GameCoreScarlett: 1 + GameCoreXboxOne: 1 + Lumin: 1 + Nintendo Switch: 1 + PS4: 1 + PS5: 1 + Stadia: 1 + WebGL: 1 + Windows Store Apps: 1 + XboxOne: 1 + iPhone: 1 + tvOS: 1 + incrementalIl2cppBuild: {} + suppressCommonWarnings: 1 + allowUnsafeCode: 0 + useDeterministicCompilation: 1 + enableRoslynAnalyzers: 1 + selectedPlatform: 0 + additionalIl2CppArgs: + scriptingRuntimeVersion: 1 + gcIncremental: 1 + assemblyVersionValidation: 1 + gcWBarrierValidation: 0 + apiCompatibilityLevelPerPlatform: {} + m_RenderingPath: 1 + m_MobileRenderingPath: 1 + metroPackageName: WebView2HoloLensSample + metroPackageVersion: 1.0.0.0 + metroCertificatePath: Assets/WSATestCertificate.pfx + metroCertificatePassword: + metroCertificateSubject: Microsoft + metroCertificateIssuer: Microsoft + metroCertificateNotAfter: 0058b1b2ed9cda01 + metroApplicationDescription: WebView2_Hololens_Sample + wsaImages: {} + metroTileShortName: MRTKAdaptiveCards2InclusionTest + metroTileShowName: 0 + metroMediumTileShowName: 0 + metroLargeTileShowName: 0 + metroWideTileShowName: 0 + metroSupportStreamingInstall: 0 + metroLastRequiredScene: 0 + metroDefaultTileSize: 1 + metroTileForegroundText: 2 + metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0} + metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, a: 1} + metroSplashScreenUseBackgroundColor: 0 + platformCapabilities: + WindowsStoreApps: + GazeInput: True + SpatialPerception: True + InternetClient: True + WebCam: True + Microphone: True + metroTargetDeviceFamilies: {} + metroFTAName: + metroFTAFileTypes: [] + metroProtocolName: + vcxProjDefaultLanguage: + XboxOneProductId: + XboxOneUpdateKey: + XboxOneSandboxId: + XboxOneContentId: + XboxOneTitleId: + XboxOneSCId: + XboxOneGameOsOverridePath: + XboxOnePackagingOverridePath: + XboxOneAppManifestOverridePath: + XboxOneVersion: 1.0.0.0 + XboxOnePackageEncryption: 0 + XboxOnePackageUpdateGranularity: 2 + XboxOneDescription: + XboxOneLanguage: + - enus + XboxOneCapability: [] + XboxOneGameRating: {} + XboxOneIsContentPackage: 0 + XboxOneEnhancedXboxCompatibilityMode: 0 + XboxOneEnableGPUVariability: 1 + XboxOneSockets: {} + XboxOneSplashScreen: {fileID: 0} + XboxOneAllowedProductIds: [] + XboxOnePersistentLocalStorageSize: 0 + XboxOneXTitleMemory: 8 + XboxOneOverrideIdentityName: + XboxOneOverrideIdentityPublisher: + vrEditorSettings: {} + cloudServicesEnabled: + UNet: 1 + luminIcon: + m_Name: + m_ModelFolderPath: + m_PortalFolderPath: + luminCert: + m_CertPath: + m_SignPackage: 1 + luminIsChannelApp: 0 + luminVersion: + m_VersionCode: 1 + m_VersionName: + apiCompatibilityLevel: 6 + activeInputHandler: 2 + windowsGamepadBackendHint: 0 + cloudProjectId: + framebufferDepthMemorylessMode: 0 + qualitySettingsNames: [] + projectName: + organizationId: + cloudEnabled: 0 + legacyClampBlendShapeWeights: 0 + playerDataPath: + forceSRGBBlit: 1 + virtualTexturingSupportEnabled: 0 diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/ProjectVersion.txt b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/ProjectVersion.txt new file mode 100644 index 00000000..6c676f05 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/ProjectVersion.txt @@ -0,0 +1,2 @@ +m_EditorVersion: 2021.3.24f1 +m_EditorVersionWithRevision: 2021.3.24f1 (cf10dcf7010d) diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/QualitySettings.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/QualitySettings.asset new file mode 100644 index 00000000..0a4842b2 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/QualitySettings.asset @@ -0,0 +1,240 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!47 &1 +QualitySettings: + m_ObjectHideFlags: 0 + serializedVersion: 5 + m_CurrentQuality: 0 + m_QualitySettings: + - serializedVersion: 2 + name: Very Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 15 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + skinWeights: 1 + textureQuality: 1 + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 0 + lodBias: 0.3 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 4 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + skinWeights: 2 + textureQuality: 0 + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 0 + lodBias: 0.4 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 16 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Medium + pixelLightCount: 1 + shadows: 1 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + skinWeights: 2 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 1 + lodBias: 0.7 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 64 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: High + pixelLightCount: 2 + shadows: 2 + shadowResolution: 1 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 40 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + skinWeights: 2 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 1 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 256 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Very High + pixelLightCount: 3 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 70 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + skinWeights: 4 + textureQuality: 0 + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 1.5 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 1024 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Ultra + pixelLightCount: 4 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 4 + shadowDistance: 150 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + skinWeights: 4 + textureQuality: 0 + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 2 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 4096 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + excludedTargetPlatforms: [] + m_PerPlatformDefaultQuality: + Android: 2 + GameCoreScarlett: 5 + GameCoreXboxOne: 5 + Lumin: 5 + Nintendo 3DS: 5 + Nintendo Switch: 5 + PS4: 5 + PS5: 5 + Stadia: 5 + Standalone: 5 + WebGL: 3 + Windows Store Apps: 5 + XboxOne: 5 + iPhone: 2 + tvOS: 2 diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/SceneTemplateSettings.json b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/SceneTemplateSettings.json new file mode 100644 index 00000000..6f3e60fd --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/SceneTemplateSettings.json @@ -0,0 +1,167 @@ +{ + "templatePinStates": [], + "dependencyTypeInfos": [ + { + "userAdded": false, + "type": "UnityEngine.AnimationClip", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.Animations.AnimatorController", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.AnimatorOverrideController", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.Audio.AudioMixerController", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.ComputeShader", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Cubemap", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.GameObject", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.LightingDataAsset", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": false + }, + { + "userAdded": false, + "type": "UnityEngine.LightingSettings", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Material", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.MonoScript", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicMaterial", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicsMaterial2D", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessResources", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.VolumeProfile", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.SceneAsset", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": false + }, + { + "userAdded": false, + "type": "UnityEngine.Shader", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.ShaderVariantCollection", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Texture", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Texture2D", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Timeline.TimelineAsset", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + } + ], + "defaultDependencyTypeInfo": { + "userAdded": false, + "type": "", + "ignore": false, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + "newSceneOverride": 0 +} \ No newline at end of file diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/TagManager.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/TagManager.asset new file mode 100644 index 00000000..6c060c6f --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/TagManager.asset @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!78 &1 +TagManager: + serializedVersion: 2 + tags: [] + layers: + - Default + - TransparentFX + - Ignore Raycast + - + - Water + - UI + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - Spatial Awareness + m_SortingLayers: + - name: Default + uniqueID: 0 + locked: 0 diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/TimeManager.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/TimeManager.asset new file mode 100644 index 00000000..558a017e --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/TimeManager.asset @@ -0,0 +1,9 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!5 &1 +TimeManager: + m_ObjectHideFlags: 0 + Fixed Timestep: 0.02 + Maximum Allowed Timestep: 0.33333334 + m_TimeScale: 1 + Maximum Particle Timestep: 0.03 diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/UnityConnectSettings.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/UnityConnectSettings.asset new file mode 100644 index 00000000..a88bee0f --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/UnityConnectSettings.asset @@ -0,0 +1,36 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!310 &1 +UnityConnectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 1 + m_Enabled: 0 + m_TestMode: 0 + m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events + m_EventUrl: https://cdp.cloud.unity3d.com/v1/events + m_ConfigUrl: https://config.uca.cloud.unity3d.com + m_DashboardUrl: https://dashboard.unity3d.com + m_TestInitMode: 0 + CrashReportingSettings: + m_EventUrl: https://perf-events.cloud.unity3d.com + m_Enabled: 0 + m_LogBufferSize: 10 + m_CaptureEditorExceptions: 1 + UnityPurchasingSettings: + m_Enabled: 0 + m_TestMode: 0 + UnityAnalyticsSettings: + m_Enabled: 0 + m_TestMode: 0 + m_InitializeOnStartup: 1 + m_PackageRequiringCoreStatsPresent: 0 + UnityAdsSettings: + m_Enabled: 0 + m_InitializeOnStartup: 1 + m_TestMode: 0 + m_IosGameId: + m_AndroidGameId: + m_GameIds: {} + m_GameId: + PerformanceReportingSettings: + m_Enabled: 0 diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/VFXManager.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/VFXManager.asset new file mode 100644 index 00000000..3a95c98b --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/VFXManager.asset @@ -0,0 +1,12 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!937362698 &1 +VFXManager: + m_ObjectHideFlags: 0 + m_IndirectShader: {fileID: 0} + m_CopyBufferShader: {fileID: 0} + m_SortShader: {fileID: 0} + m_StripUpdateShader: {fileID: 0} + m_RenderPipeSettingsPath: + m_FixedTimeStep: 0.016666668 + m_MaxDeltaTime: 0.05 diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/VersionControlSettings.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/VersionControlSettings.asset new file mode 100644 index 00000000..dca28814 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/VersionControlSettings.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!890905787 &1 +VersionControlSettings: + m_ObjectHideFlags: 0 + m_Mode: Visible Meta Files + m_CollabEditorSettings: + inProgressEnabled: 1 diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/XRPackageSettings.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/XRPackageSettings.asset new file mode 100644 index 00000000..7e791e17 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/XRPackageSettings.asset @@ -0,0 +1,5 @@ +{ + "m_Settings": [ + "RemoveLegacyInputHelpersForReload" + ] +} \ No newline at end of file diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/XRSettings.asset b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/XRSettings.asset new file mode 100644 index 00000000..482590c1 --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/XRSettings.asset @@ -0,0 +1,10 @@ +{ + "m_SettingKeys": [ + "VR Device Disabled", + "VR Device User Alert" + ], + "m_SettingValues": [ + "False", + "False" + ] +} \ No newline at end of file diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/boot.config b/GettingStartedGuides/HoloLens2_GettingStarted/HoloLens2GetStartedApp/ProjectSettings/boot.config new file mode 100644 index 00000000..e69de29b diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/README.md b/GettingStartedGuides/HoloLens2_GettingStarted/README.md new file mode 100644 index 00000000..2686858b --- /dev/null +++ b/GettingStartedGuides/HoloLens2_GettingStarted/README.md @@ -0,0 +1,32 @@ +--- +description: "Completed Unity project from the tutorial Get started with WebView2 in HoloLens 2 Unity apps." +languages: + - csharp +page_type: sample +products: + - microsoft-edge +urlFragment: HoloLens2_GettingStarted +--- +# Get started with WebView2 in HoloLens 2 Unity apps + +> [!IMPORTANT] +> WebView2 continues to be available. However, support for WebView2 on Hololens is discontinued (no bug fixes, content updates or technical support), and we can therefore make no guarantees that applications will continue to work for any extended period of time. + + +This sample, **HoloLens2_GettingStarted**, is the completed Unity project that results from following the steps in the tutorial [Get started with WebView2 in HoloLens 2 Unity apps](https://learn.microsoft.com/microsoft-edge/webview2/get-started/hololens2). + +![The running app from the finished HoloLens 2 tutorial](screenshots/hololens-getting-started-webview2.png) + + +Follow these steps to get started with this sample code. WebView2 is already included as a Unity package, but you will need to load it via the Mixed Reality Feature Tool. + +1. Clone this repository +2. Launch the Microsoft Mixed Reality Feature Tool + - Click **Start** + - Click the **...** button, navigate to the `HoloLens2GetStartedApp` folder, and select **Open** + - With the project path selected, click **Restore Features** to load the required packages for the Mixed Reality Toolkit and the WebView2 plugin package. +3. Close the Mixed Reality Feature Tool +4. Launch Unity Hub +5. In Unity Hub, click **Open**, navigate to the `HoloLens2GetStartedApp` folder, and select **Open**. This should open the project in the Unity Editor. +6. In the Unity Editor, find the SampleScene in the `Assets/Scenes` folder and double-click to load it. +7. Click the play button in the Unity Editor to quickly test the app. diff --git a/GettingStartedGuides/HoloLens2_GettingStarted/screenshots/hololens-getting-started-webview2.png b/GettingStartedGuides/HoloLens2_GettingStarted/screenshots/hololens-getting-started-webview2.png new file mode 100644 index 00000000..df16b60e Binary files /dev/null and b/GettingStartedGuides/HoloLens2_GettingStarted/screenshots/hololens-getting-started-webview2.png differ diff --git a/GettingStartedGuides/README.md b/GettingStartedGuides/README.md new file mode 100644 index 00000000..ba7b4b8b --- /dev/null +++ b/GettingStartedGuides/README.md @@ -0,0 +1,6 @@ +# Getting Started tutorial projects + + +These are completed Visual Studio projects that result from following the steps in the [Getting Started tutorials](https://learn.microsoft.com/microsoft-edge/webview2/get-started/get-started). + +These are baseline WebView2 projects with a few lines of WebView2 starter code to embed and use the WebView2 control. You can use one of these projects as a starting point to add additional WebView2 code. diff --git a/GettingStartedGuides/WPF_GettingStarted/README.md b/GettingStartedGuides/WPF_GettingStarted/README.md index 60b85e7e..08a525d3 100644 --- a/GettingStartedGuides/WPF_GettingStarted/README.md +++ b/GettingStartedGuides/WPF_GettingStarted/README.md @@ -1,14 +1,15 @@ --- -description: "Getting started with WebView2 in WPF doc" +description: "Completed Visual Studio project from the tutorial Get started with WebView2 in WPF apps." languages: - csharp page_type: sample products: - microsoft-edge -urlFragment: webview2-wpf-getting-started +urlFragment: WPF_GettingStarted --- -# Getting Started with WebView2 in WPF +# Get started with WebView2 in WPF apps -This sample relates to the [Getting started with WebView2 in WPF](https://docs.microsoft.com/microsoft-edge/webview2/gettingstarted/wpf) doc. + +This sample, **WPF_GettingStarted**, is the completed Visual Studio project that results from following the steps in the tutorial [Get started with WebView2 in WPF apps](https://learn.microsoft.com/microsoft-edge/webview2/get-started/wpf). -![sample snapshot](https://raw.githubusercontent.com/MicrosoftDocs/edge-developer/master/microsoft-edge/webview2/get-started/media/wpf-getting-started-app.png) +![The running app from the finished WinUI 3 (Windows App SDK) tutorial](screenshots/wpf-getting-started-bing.png) diff --git a/GettingStartedGuides/WPF_GettingStarted/screenshots/wpf-getting-started-bing.png b/GettingStartedGuides/WPF_GettingStarted/screenshots/wpf-getting-started-bing.png new file mode 100644 index 00000000..c0d362a2 Binary files /dev/null and b/GettingStartedGuides/WPF_GettingStarted/screenshots/wpf-getting-started-bing.png differ diff --git a/GettingStartedGuides/Win32_GettingStarted/HelloWebView.cpp b/GettingStartedGuides/Win32_GettingStarted/HelloWebView.cpp index 4243c716..8fec9603 100644 --- a/GettingStartedGuides/Win32_GettingStarted/HelloWebView.cpp +++ b/GettingStartedGuides/Win32_GettingStarted/HelloWebView.cpp @@ -6,8 +6,10 @@ #include #include #include +// // include WebView2 header #include "WebView2.h" +// using namespace Microsoft::WRL; @@ -28,7 +30,7 @@ LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); static wil::com_ptr webviewController; // Pointer to WebView window -static wil::com_ptr webviewWindow; +static wil::com_ptr webview; int CALLBACK WinMain( _In_ HINSTANCE hInstance, @@ -116,16 +118,16 @@ int CALLBACK WinMain( [hWnd](HRESULT result, ICoreWebView2Controller* controller) -> HRESULT { if (controller != nullptr) { webviewController = controller; - webviewController->get_CoreWebView2(&webviewWindow); + webviewController->get_CoreWebView2(&webview); } // Add a few settings for the webview // The demo step is redundant since the values are the default settings - ICoreWebView2Settings* Settings; - webviewWindow->get_Settings(&Settings); - Settings->put_IsScriptEnabled(TRUE); - Settings->put_AreDefaultScriptDialogsEnabled(TRUE); - Settings->put_IsWebMessageEnabled(TRUE); + wil::com_ptr settings; + webview->get_Settings(&settings); + settings->put_IsScriptEnabled(TRUE); + settings->put_AreDefaultScriptDialogsEnabled(TRUE); + settings->put_IsWebMessageEnabled(TRUE); // Resize WebView to fit the bounds of the parent window RECT bounds; @@ -133,53 +135,57 @@ int CALLBACK WinMain( webviewController->put_Bounds(bounds); // Schedule an async task to navigate to Bing - webviewWindow->Navigate(L"https://www.bing.com/"); + webview->Navigate(L"https://www.bing.com/"); + // // Step 4 - Navigation events // register an ICoreWebView2NavigationStartingEventHandler to cancel any non-https navigation EventRegistrationToken token; - webviewWindow->add_NavigationStarting(Callback( + webview->add_NavigationStarting(Callback( [](ICoreWebView2* webview, ICoreWebView2NavigationStartingEventArgs* args) -> HRESULT { - PWSTR uri; + wil::unique_cotaskmem_string uri; args->get_Uri(&uri); - std::wstring source(uri); + std::wstring source(uri.get()); if (source.substr(0, 5) != L"https") { args->put_Cancel(true); } - CoTaskMemFree(uri); return S_OK; }).Get(), &token); + // + // // Step 5 - Scripting // Schedule an async task to add initialization script that freezes the Object object - webviewWindow->AddScriptToExecuteOnDocumentCreated(L"Object.freeze(Object);", nullptr); + webview->AddScriptToExecuteOnDocumentCreated(L"Object.freeze(Object);", nullptr); // Schedule an async task to get the document URL - webviewWindow->ExecuteScript(L"window.document.URL;", Callback( + webview->ExecuteScript(L"window.document.URL;", Callback( [](HRESULT errorCode, LPCWSTR resultObjectAsJson) -> HRESULT { LPCWSTR URL = resultObjectAsJson; //doSomethingWithURL(URL); return S_OK; }).Get()); + // + // // Step 6 - Communication between host and web content // Set an event handler for the host to return received message back to the web content - webviewWindow->add_WebMessageReceived(Callback( + webview->add_WebMessageReceived(Callback( [](ICoreWebView2* webview, ICoreWebView2WebMessageReceivedEventArgs* args) -> HRESULT { - PWSTR message; + wil::unique_cotaskmem_string message; args->TryGetWebMessageAsString(&message); // processMessage(&message); - webview->PostWebMessageAsString(message); - CoTaskMemFree(message); + webview->PostWebMessageAsString(message.get()); return S_OK; }).Get(), &token); // Schedule an async task to add initialization script that // 1) Add an listener to print message from the host // 2) Post document URL to the host - webviewWindow->AddScriptToExecuteOnDocumentCreated( + webview->AddScriptToExecuteOnDocumentCreated( L"window.chrome.webview.addEventListener(\'message\', event => alert(event.data));" \ L"window.chrome.webview.postMessage(window.document.URL);", nullptr); + // return S_OK; }).Get()); diff --git a/GettingStartedGuides/Win32_GettingStarted/README.md b/GettingStartedGuides/Win32_GettingStarted/README.md index 397d4613..8d39dab7 100644 --- a/GettingStartedGuides/Win32_GettingStarted/README.md +++ b/GettingStartedGuides/Win32_GettingStarted/README.md @@ -1,14 +1,15 @@ --- -description: "Getting started with WebView2 for Win32 apps doc" +description: "Completed Visual Studio project from the tutorial Get started with WebView2 in Win32 apps." languages: - cpp page_type: sample products: - microsoft-edge -urlFragment: webview2-win32-getting-started +urlFragment: Win32_GettingStarted --- -# Getting Started with WebView2 for Win32 apps +# Get started with WebView2 in Win32 apps -This sample relates to the [Getting started with WebView2 for Win32 apps](https://docs.microsoft.com/microsoft-edge/webview2/gettingstarted/win32) doc. + +This sample, **Win32_GettingStarted**, is a completed Visual Studio project that includes WebView2 code already added for you. The tutorial [Get started with WebView2 in Win32 apps](https://learn.microsoft.com/microsoft-edge/webview2/get-started/win32) starts by opening this completed project. -![sample snapshot](https://raw.githubusercontent.com/MicrosoftDocs/edge-developer/master/microsoft-edge/webview2/media/bing-window.png) \ No newline at end of file +![The running app for the Win32 Get Started tutorial](screenshots/bing-window.png) diff --git a/GettingStartedGuides/Win32_GettingStarted/screenshots/bing-window.png b/GettingStartedGuides/Win32_GettingStarted/screenshots/bing-window.png new file mode 100644 index 00000000..86e0edb2 Binary files /dev/null and b/GettingStartedGuides/Win32_GettingStarted/screenshots/bing-window.png differ diff --git a/GettingStartedGuides/WinForms_GettingStarted/README.md b/GettingStartedGuides/WinForms_GettingStarted/README.md new file mode 100644 index 00000000..750e551e --- /dev/null +++ b/GettingStartedGuides/WinForms_GettingStarted/README.md @@ -0,0 +1,15 @@ +--- +description: "Completed Visual Studio project from the tutorial Get started with WebView2 in WinForms apps." +languages: + - csharp +page_type: sample +products: + - microsoft-edge +urlFragment: WinForms_GettingStarted +--- +# Get started with WebView2 in WinForms apps + + +This sample, **WinForms_GettingStarted**, is the completed Visual Studio project that results from following the steps in the tutorial [Get started with WebView2 in WinForms apps](https://learn.microsoft.com/microsoft-edge/webview2/get-started/winforms). + +![The running app from the finished WinForms tutorial](screenshots/winforms-bing.png) diff --git a/GettingStartedGuides/WinForms_GettingStarted/screenshots/winforms-bing.png b/GettingStartedGuides/WinForms_GettingStarted/screenshots/winforms-bing.png new file mode 100644 index 00000000..ff93a9c8 Binary files /dev/null and b/GettingStartedGuides/WinForms_GettingStarted/screenshots/winforms-bing.png differ diff --git a/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp.sln b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp.sln new file mode 100644 index 00000000..27927fd2 --- /dev/null +++ b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp.sln @@ -0,0 +1,51 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33122.133 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyUWPGetStartApp", "MyUWPGetStartApp\MyUWPGetStartApp.csproj", "{084E5E38-2616-4B38-964F-53D16E0F83C9}" +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 + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Debug|ARM.ActiveCfg = Debug|ARM + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Debug|ARM.Build.0 = Debug|ARM + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Debug|ARM.Deploy.0 = Debug|ARM + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Debug|ARM64.Build.0 = Debug|ARM64 + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Debug|x64.ActiveCfg = Debug|x64 + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Debug|x64.Build.0 = Debug|x64 + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Debug|x64.Deploy.0 = Debug|x64 + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Debug|x86.ActiveCfg = Debug|x86 + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Debug|x86.Build.0 = Debug|x86 + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Debug|x86.Deploy.0 = Debug|x86 + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Release|ARM.ActiveCfg = Release|ARM + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Release|ARM.Build.0 = Release|ARM + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Release|ARM.Deploy.0 = Release|ARM + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Release|ARM64.ActiveCfg = Release|ARM64 + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Release|ARM64.Build.0 = Release|ARM64 + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Release|ARM64.Deploy.0 = Release|ARM64 + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Release|x64.ActiveCfg = Release|x64 + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Release|x64.Build.0 = Release|x64 + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Release|x64.Deploy.0 = Release|x64 + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Release|x86.ActiveCfg = Release|x86 + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Release|x86.Build.0 = Release|x86 + {084E5E38-2616-4B38-964F-53D16E0F83C9}.Release|x86.Deploy.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3471BCDB-1792-4F87-A58A-EB77219A9098} + EndGlobalSection +EndGlobal diff --git a/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/App.xaml b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/App.xaml new file mode 100644 index 00000000..c3f61afc --- /dev/null +++ b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/App.xaml @@ -0,0 +1,7 @@ + + + diff --git a/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/App.xaml.cs b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/App.xaml.cs new file mode 100644 index 00000000..58bd7753 --- /dev/null +++ b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/App.xaml.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.ApplicationModel; +using Windows.ApplicationModel.Activation; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Navigation; + +namespace MyUWPGetStartApp +{ + /// + /// Provides application-specific behavior to supplement the default Application class. + /// + sealed partial class App : Application + { + /// + /// Initializes the singleton application object. This is the first line of authored code + /// executed, and as such is the logical equivalent of main() or WinMain(). + /// + public App() + { + this.InitializeComponent(); + this.Suspending += OnSuspending; + } + + /// + /// Invoked when the application is launched normally by the end user. Other entry points + /// will be used such as when the application is launched to open a specific file. + /// + /// Details about the launch request and process. + protected override void OnLaunched(LaunchActivatedEventArgs e) + { + Frame rootFrame = Window.Current.Content as Frame; + + // Do not repeat app initialization when the Window already has content, + // just ensure that the window is active + if (rootFrame == null) + { + // Create a Frame to act as the navigation context and navigate to the first page + rootFrame = new Frame(); + + rootFrame.NavigationFailed += OnNavigationFailed; + + if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) + { + //TODO: Load state from previously suspended application + } + + // Place the frame in the current Window + Window.Current.Content = rootFrame; + } + + if (e.PrelaunchActivated == false) + { + if (rootFrame.Content == null) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + rootFrame.Navigate(typeof(MainPage), e.Arguments); + } + // Ensure the current window is active + Window.Current.Activate(); + } + } + + /// + /// Invoked when Navigation to a certain page fails + /// + /// The Frame which failed navigation + /// Details about the navigation failure + void OnNavigationFailed(object sender, NavigationFailedEventArgs e) + { + throw new Exception("Failed to load Page " + e.SourcePageType.FullName); + } + + /// + /// Invoked when application execution is being suspended. Application state is saved + /// without knowing whether the application will be terminated or resumed with the contents + /// of memory still intact. + /// + /// The source of the suspend request. + /// Details about the suspend request. + private void OnSuspending(object sender, SuspendingEventArgs e) + { + var deferral = e.SuspendingOperation.GetDeferral(); + //TODO: Save application state and stop any background activity + deferral.Complete(); + } + } +} diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/Images/LockScreenLogo.scale-200.png b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Assets/LockScreenLogo.scale-200.png similarity index 100% rename from GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/Images/LockScreenLogo.scale-200.png rename to GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Assets/LockScreenLogo.scale-200.png diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/Images/SplashScreen.scale-200.png b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Assets/SplashScreen.scale-200.png similarity index 100% rename from GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/Images/SplashScreen.scale-200.png rename to GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Assets/SplashScreen.scale-200.png diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/Images/Square150x150Logo.scale-200.png b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Assets/Square150x150Logo.scale-200.png similarity index 100% rename from GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/Images/Square150x150Logo.scale-200.png rename to GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Assets/Square150x150Logo.scale-200.png diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/Images/Square44x44Logo.scale-200.png b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Assets/Square44x44Logo.scale-200.png similarity index 100% rename from GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/Images/Square44x44Logo.scale-200.png rename to GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Assets/Square44x44Logo.scale-200.png diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/Images/Square44x44Logo.targetsize-24_altform-unplated.png b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png similarity index 100% rename from GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/Images/Square44x44Logo.targetsize-24_altform-unplated.png rename to GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/Images/StoreLogo.png b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Assets/StoreLogo.png similarity index 100% rename from GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/Images/StoreLogo.png rename to GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Assets/StoreLogo.png diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/Images/Wide310x150Logo.scale-200.png b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Assets/Wide310x150Logo.scale-200.png similarity index 100% rename from GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/Images/Wide310x150Logo.scale-200.png rename to GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Assets/Wide310x150Logo.scale-200.png diff --git a/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/MainPage.xaml b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/MainPage.xaml new file mode 100644 index 00000000..2c58fd18 --- /dev/null +++ b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/MainPage.xaml @@ -0,0 +1,15 @@ + + + + + + diff --git a/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/MainPage.xaml.cs b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/MainPage.xaml.cs new file mode 100644 index 00000000..b73a07a8 --- /dev/null +++ b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/MainPage.xaml.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Navigation; + +// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 + +namespace MyUWPGetStartApp +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class MainPage : Page + { + public MainPage() + { + this.InitializeComponent(); + } + } +} diff --git a/SampleApps/webview2_sample_uwp/WebView2_UWP.csproj b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/MyUWPGetStartApp.csproj similarity index 92% rename from SampleApps/webview2_sample_uwp/WebView2_UWP.csproj rename to GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/MyUWPGetStartApp.csproj index e89618ba..4eabc450 100644 --- a/SampleApps/webview2_sample_uwp/WebView2_UWP.csproj +++ b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/MyUWPGetStartApp.csproj @@ -4,22 +4,20 @@ Debug x86 - {B27228A6-742A-4813-AA04-95014E620997} + {084E5E38-2616-4B38-964F-53D16E0F83C9} AppContainerExe Properties - WebView2_UWP - WebView2_UWP + MyUWPGetStartApp + MyUWPGetStartApp en-US UAP - 10.0.19041.0 + 10.0.22000.0 10.0.17763.0 14 512 {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} true - True - A286F6D6F7643BBBC3FFE24CDF744B16315C29D1 - WebView2_UWP_TemporaryKey.pfx + false true @@ -153,15 +151,12 @@ - 6.2.12 + 6.2.14 - 2.8.0-prerelease.210927001 + 2.8.2 - - - 14.0 diff --git a/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Package.appxmanifest b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Package.appxmanifest new file mode 100644 index 00000000..49506a3a --- /dev/null +++ b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Package.appxmanifest @@ -0,0 +1,49 @@ + + + + + + + + + + MyUWPGetStartApp + Microsoft + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Properties/AssemblyInfo.cs b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..5f2808f7 --- /dev/null +++ b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Properties/AssemblyInfo.cs @@ -0,0 +1,29 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MyUWPGetStartApp")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MyUWPGetStartApp")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Properties/Default.rd.xml b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Properties/Default.rd.xml new file mode 100644 index 00000000..af00722c --- /dev/null +++ b/GettingStartedGuides/WinUI2_GettingStarted/MyUWPGetStartApp/Properties/Default.rd.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/GettingStartedGuides/WinUI2_GettingStarted/README.md b/GettingStartedGuides/WinUI2_GettingStarted/README.md new file mode 100644 index 00000000..b405de5d --- /dev/null +++ b/GettingStartedGuides/WinUI2_GettingStarted/README.md @@ -0,0 +1,15 @@ +--- +description: "Completed Visual Studio project from the tutorial Get started with WebView2 in WinUI 2 (UWP) apps." +languages: + - csharp +page_type: sample +products: + - microsoft-edge +urlFragment: WinUI2_GettingStarted +--- +# Get started with WebView2 in WinUI 2 (UWP) apps + + +This sample, **WinUI2_GettingStarted**, is the completed Visual Studio project that results from following the steps in the tutorial [Get started with WebView2 in WinUI 2 (UWP) apps](https://learn.microsoft.com/microsoft-edge/webview2/get-started/winui2). + +![The running app from the finished WinUI 2 (UWP) tutorial](screenshots/winui2-getting-started-webview2-with-content.png) diff --git a/GettingStartedGuides/WinUI2_GettingStarted/screenshots/winui2-getting-started-webview2-with-content.png b/GettingStartedGuides/WinUI2_GettingStarted/screenshots/winui2-getting-started-webview2-with-content.png new file mode 100644 index 00000000..bff5108e Binary files /dev/null and b/GettingStartedGuides/WinUI2_GettingStarted/screenshots/winui2-getting-started-webview2-with-content.png differ diff --git a/GettingStartedGuides/WinUI3_GettingStarted/README.md b/GettingStartedGuides/WinUI3_GettingStarted/README.md index fe438503..9202cafb 100644 --- a/GettingStartedGuides/WinUI3_GettingStarted/README.md +++ b/GettingStartedGuides/WinUI3_GettingStarted/README.md @@ -1,14 +1,17 @@ --- -description: "Getting started with WebView2 in WinUI3 doc" +description: "Completed Visual Studio project from the tutorial Get started with WebView2 in WinUI 3 (Windows App SDK) apps." languages: - csharp page_type: sample products: - microsoft-edge -urlFragment: webview2-winui3-getting-started +urlFragment: WinUI3_GettingStarted --- -# Getting Started with WebView2 in WinUI3 +# Get started with WebView2 in WinUI 3 (Windows App SDK) apps -This sample relates to the [Getting started with WebView2 in WinUI3](https://docs.microsoft.com/microsoft-edge/webview2/gettingstarted/winui) doc. + +This sample, **WinUI3GetStarted**, is the completed Visual Studio project that results from following the steps in the tutorial [Get started with WebView2 in WinUI 3 (Windows App SDK) apps](https://learn.microsoft.com/microsoft-edge/webview2/get-started/winui). -![sample snapshot](https://raw.githubusercontent.com/MicrosoftDocs/edge-developer/master/microsoft-edge/webview2/get-started/media/winui-getting-started-part-3.png) +![The running app from the finished WinUI 3 (Windows App SDK) tutorial](screenshots/finished-app.png) + +Project updated Nov. 1, 2024. diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted.sln b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted.sln new file mode 100644 index 00000000..af18dbce --- /dev/null +++ b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted.sln @@ -0,0 +1,43 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35327.3 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinUI3GetStarted", "WinUI3GetStarted\WinUI3GetStarted.csproj", "{FBF1E5FC-C14D-4C2D-88D4-6B8B55821E52}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FBF1E5FC-C14D-4C2D-88D4-6B8B55821E52}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {FBF1E5FC-C14D-4C2D-88D4-6B8B55821E52}.Debug|ARM64.Build.0 = Debug|ARM64 + {FBF1E5FC-C14D-4C2D-88D4-6B8B55821E52}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {FBF1E5FC-C14D-4C2D-88D4-6B8B55821E52}.Debug|x64.ActiveCfg = Debug|x64 + {FBF1E5FC-C14D-4C2D-88D4-6B8B55821E52}.Debug|x64.Build.0 = Debug|x64 + {FBF1E5FC-C14D-4C2D-88D4-6B8B55821E52}.Debug|x64.Deploy.0 = Debug|x64 + {FBF1E5FC-C14D-4C2D-88D4-6B8B55821E52}.Debug|x86.ActiveCfg = Debug|x86 + {FBF1E5FC-C14D-4C2D-88D4-6B8B55821E52}.Debug|x86.Build.0 = Debug|x86 + {FBF1E5FC-C14D-4C2D-88D4-6B8B55821E52}.Debug|x86.Deploy.0 = Debug|x86 + {FBF1E5FC-C14D-4C2D-88D4-6B8B55821E52}.Release|ARM64.ActiveCfg = Release|ARM64 + {FBF1E5FC-C14D-4C2D-88D4-6B8B55821E52}.Release|ARM64.Build.0 = Release|ARM64 + {FBF1E5FC-C14D-4C2D-88D4-6B8B55821E52}.Release|ARM64.Deploy.0 = Release|ARM64 + {FBF1E5FC-C14D-4C2D-88D4-6B8B55821E52}.Release|x64.ActiveCfg = Release|x64 + {FBF1E5FC-C14D-4C2D-88D4-6B8B55821E52}.Release|x64.Build.0 = Release|x64 + {FBF1E5FC-C14D-4C2D-88D4-6B8B55821E52}.Release|x64.Deploy.0 = Release|x64 + {FBF1E5FC-C14D-4C2D-88D4-6B8B55821E52}.Release|x86.ActiveCfg = Release|x86 + {FBF1E5FC-C14D-4C2D-88D4-6B8B55821E52}.Release|x86.Build.0 = Release|x86 + {FBF1E5FC-C14D-4C2D-88D4-6B8B55821E52}.Release|x86.Deploy.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1334E548-2468-4E8F-84AF-B2B85C674856} + EndGlobalSection +EndGlobal diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/App.xaml b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/App.xaml new file mode 100644 index 00000000..4bcfd7ef --- /dev/null +++ b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/App.xaml @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/App.xaml.cs b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/App.xaml.cs similarity index 59% rename from GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/App.xaml.cs rename to GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/App.xaml.cs index fc450aef..94412f54 100644 --- a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/App.xaml.cs +++ b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/App.xaml.cs @@ -1,4 +1,12 @@ -using System; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Controls.Primitives; +using Microsoft.UI.Xaml.Data; +using Microsoft.UI.Xaml.Input; +using Microsoft.UI.Xaml.Media; +using Microsoft.UI.Xaml.Navigation; +using Microsoft.UI.Xaml.Shapes; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -7,17 +15,11 @@ using Windows.ApplicationModel.Activation; using Windows.Foundation; using Windows.Foundation.Collections; -using Microsoft.UI.Threading; -using Microsoft.UI.Xaml; -using Microsoft.UI.Xaml.Controls; -using Microsoft.UI.Xaml.Controls.Primitives; -using Microsoft.UI.Xaml.Data; -using Microsoft.UI.Xaml.Input; -using Microsoft.UI.Xaml.Media; -using Microsoft.UI.Xaml.Navigation; -using Microsoft.UI.Xaml.Shapes; -namespace WinUI_Sample +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + +namespace WinUI3GetStarted { /// /// Provides application-specific behavior to supplement the default Application class. @@ -31,12 +33,10 @@ public partial class App : Application public App() { this.InitializeComponent(); - this.Suspending += OnSuspending; } /// - /// Invoked when the application is launched normally by the end user. Other entry points - /// will be used such as when the application is launched to open a specific file. + /// Invoked when the application is launched. /// /// Details about the launch request and process. protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args) @@ -45,18 +45,6 @@ protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs ar m_window.Activate(); } - /// - /// Invoked when application execution is being suspended. Application state is saved - /// without knowing whether the application will be terminated or resumed with the contents - /// of memory still intact. - /// - /// The source of the suspend request. - /// Details about the suspend request. - private void OnSuspending(object sender, SuspendingEventArgs e) - { - // Save application state and stop any background activity - } - private Window m_window; } } diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/LockScreenLogo.scale-200.png b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/LockScreenLogo.scale-200.png new file mode 100644 index 00000000..7440f0d4 Binary files /dev/null and b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/LockScreenLogo.scale-200.png differ diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/SplashScreen.scale-200.png b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/SplashScreen.scale-200.png new file mode 100644 index 00000000..32f486a8 Binary files /dev/null and b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/SplashScreen.scale-200.png differ diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/Square150x150Logo.scale-200.png b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/Square150x150Logo.scale-200.png new file mode 100644 index 00000000..53ee3777 Binary files /dev/null and b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/Square150x150Logo.scale-200.png differ diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/Square44x44Logo.scale-200.png b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/Square44x44Logo.scale-200.png new file mode 100644 index 00000000..f713bba6 Binary files /dev/null and b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/Square44x44Logo.scale-200.png differ diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/Square44x44Logo.targetsize-24_altform-unplated.png new file mode 100644 index 00000000..dc9f5bea Binary files /dev/null and b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/Square44x44Logo.targetsize-24_altform-unplated.png differ diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/StoreLogo.png b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/StoreLogo.png new file mode 100644 index 00000000..a4586f26 Binary files /dev/null and b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/StoreLogo.png differ diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/Wide310x150Logo.scale-200.png b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/Wide310x150Logo.scale-200.png new file mode 100644 index 00000000..8b4a5d0d Binary files /dev/null and b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Assets/Wide310x150Logo.scale-200.png differ diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/MainWindow.xaml b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/MainWindow.xaml new file mode 100644 index 00000000..f2db9c7e --- /dev/null +++ b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/MainWindow.xaml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/MainWindow.xaml.cs b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/MainWindow.xaml.cs similarity index 65% rename from GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/MainWindow.xaml.cs rename to GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/MainWindow.xaml.cs index 236c128a..ec2b6d48 100644 --- a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/MainWindow.xaml.cs +++ b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/MainWindow.xaml.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices.WindowsRuntime; -using Windows.Foundation; -using Windows.Foundation.Collections; +using Microsoft.Web.WebView2.Core; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls.Primitives; @@ -12,11 +6,18 @@ using Microsoft.UI.Xaml.Input; using Microsoft.UI.Xaml.Media; using Microsoft.UI.Xaml.Navigation; -using ABI.Microsoft.UI.Private.Controls; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.Foundation; +using Windows.Foundation.Collections; -// The Blank Window item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. -namespace WinUI_Sample +namespace WinUI3GetStarted { /// /// An empty window that can be used on its own or navigated to within a Frame. @@ -27,17 +28,9 @@ public MainWindow() { this.InitializeComponent(); MyWebView.NavigationStarting += EnsureHttps; - //MyWebView.WebMessageReceived += UpdateAddressBar; - } - private void UpdateAddressBar(WebView2 sender, WebView2WebMessageReceivedEventArgs args) - { - //String uri = args.Source; - //addressBar.Text = uri; - } - - private void EnsureHttps(WebView2 sender, WebView2NavigationStartingEventArgs args) + private void EnsureHttps(WebView2 sender, CoreWebView2NavigationStartingEventArgs args) { String uri = args.Uri; if (!uri.StartsWith("https://")) @@ -51,11 +44,8 @@ private void EnsureHttps(WebView2 sender, WebView2NavigationStartingEventArgs ar } } - -private void myButton_Click(object sender, RoutedEventArgs e) + private void myButton_Click(object sender, RoutedEventArgs e) { - //myButton.Content = "Clicked"; - try { Uri targetUri = new Uri(addressBar.Text); @@ -63,9 +53,8 @@ private void myButton_Click(object sender, RoutedEventArgs e) } catch (FormatException ex) { - // Bad address. + // Incorrect address entered. } - } } } diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Package.appxmanifest b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Package.appxmanifest new file mode 100644 index 00000000..49bfdd40 --- /dev/null +++ b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Package.appxmanifest @@ -0,0 +1,51 @@ + + + + + + + + + + WinUI3GetStarted + v-mihoffman + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Properties/PublishProfiles/win-arm64.pubxml b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Properties/PublishProfiles/win-arm64.pubxml new file mode 100644 index 00000000..06da89e1 --- /dev/null +++ b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Properties/PublishProfiles/win-arm64.pubxml @@ -0,0 +1,19 @@ + + + + + FileSystem + ARM64 + win-arm64 + win10-arm64 + bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\ + true + False + False + True + False + True + + \ No newline at end of file diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Properties/PublishProfiles/win-x64.pubxml b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Properties/PublishProfiles/win-x64.pubxml new file mode 100644 index 00000000..3568f8d8 --- /dev/null +++ b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Properties/PublishProfiles/win-x64.pubxml @@ -0,0 +1,19 @@ + + + + + FileSystem + x64 + win-x64 + win10-x64 + bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\ + true + False + False + True + False + True + + \ No newline at end of file diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Properties/PublishProfiles/win-x86.pubxml b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Properties/PublishProfiles/win-x86.pubxml new file mode 100644 index 00000000..4ed30a5e --- /dev/null +++ b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Properties/PublishProfiles/win-x86.pubxml @@ -0,0 +1,19 @@ + + + + + FileSystem + x86 + win-x86 + win10-x86 + bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\ + true + False + False + True + False + True + + \ No newline at end of file diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Properties/launchSettings.json b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Properties/launchSettings.json new file mode 100644 index 00000000..e2cc93ed --- /dev/null +++ b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "profiles": { + "WinUI3GetStarted (Package)": { + "commandName": "MsixPackage" + }, + "WinUI3GetStarted (Unpackaged)": { + "commandName": "Project" + } + } +} \ No newline at end of file diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/WinUI3GetStarted.csproj b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/WinUI3GetStarted.csproj new file mode 100644 index 00000000..12e3cdda --- /dev/null +++ b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/WinUI3GetStarted.csproj @@ -0,0 +1,49 @@ + + + WinExe + net8.0-windows10.0.19041.0 + 10.0.17763.0 + WinUI3GetStarted + app.manifest + x86;x64;ARM64 + win-x86;win-x64;win-arm64 + win10-x86;win10-x64;win10-arm64 + win-$(Platform).pubxml + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + true + + \ No newline at end of file diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/app.manifest b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/app.manifest new file mode 100644 index 00000000..098f2310 --- /dev/null +++ b/GettingStartedGuides/WinUI3_GettingStarted/WinUI3GetStarted/WinUI3GetStarted/app.manifest @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + PerMonitorV2 + + + \ No newline at end of file diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/WinUI_Sample (Package).wapproj.user b/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/WinUI_Sample (Package).wapproj.user deleted file mode 100644 index 88a55094..00000000 --- a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/WinUI_Sample (Package).wapproj.user +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/build/LiftedWinRTClassRegistrations.xml b/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/build/LiftedWinRTClassRegistrations.xml deleted file mode 100644 index 5340f34a..00000000 --- a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/build/LiftedWinRTClassRegistrations.xml +++ /dev/null @@ -1,1701 +0,0 @@ - - - - dcompi.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CoreMessagingXP.dll - - - - - - - - - - - - Microsoft.UI.Input.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Microsoft.UI.Xaml.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Microsoft.UI.Xaml.Controls.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Microsoft.UI.Xaml.Phone.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/build/Microsoft.WinUI.AppX.targets b/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/build/Microsoft.WinUI.AppX.targets deleted file mode 100644 index f728cf13..00000000 --- a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample (Package)/build/Microsoft.WinUI.AppX.targets +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - $(MSBuildThisFileDirectory) - - - - - - - - - - - - - - - - - - - - - - - - - - $(MSBuildWarningsAsMessages);APPX1707 - - - - - UAP - Windows - 10.0 - - true - false - en-US - - - - - - - - - - - - - <_MuxRuntimeIdentifier Condition="'$(Platform)' == 'Win32'">win10-x86 - <_MuxRuntimeIdentifier Condition="'$(Platform)' != 'Win32'">win10-$(Platform) - - - - $([MSBuild]::MakeRelative($(MSBuildThisFileDirectory)..\runtimes\$(_MuxRuntimeIdentifier)\native\, %(RootDir)%(Directory))) - - - - - - - - - %(WapProjPackageFile.DestinationSubDirectory)%(TargetPath) - - - %(UploadWapProjPackageFile.DestinationSubDirectory)%(TargetPath) - - - - - diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample.sln b/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample.sln deleted file mode 100644 index 8c28caac..00000000 --- a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample.sln +++ /dev/null @@ -1,53 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30223.230 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "WinUI_Sample (Package)", "WinUI_Sample (Package)\WinUI_Sample (Package).wapproj", "{B820339B-BF7D-4F43-826D-D1A82A763178}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinUI_Sample", "WinUI_Sample\WinUI_Sample.csproj", "{D507D20A-6AFB-4B0F-AEF0-C5D99F3EBE08}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B820339B-BF7D-4F43-826D-D1A82A763178}.Debug|Any CPU.ActiveCfg = Debug|x86 - {B820339B-BF7D-4F43-826D-D1A82A763178}.Debug|x64.ActiveCfg = Debug|x64 - {B820339B-BF7D-4F43-826D-D1A82A763178}.Debug|x64.Build.0 = Debug|x64 - {B820339B-BF7D-4F43-826D-D1A82A763178}.Debug|x64.Deploy.0 = Debug|x64 - {B820339B-BF7D-4F43-826D-D1A82A763178}.Debug|x86.ActiveCfg = Debug|x86 - {B820339B-BF7D-4F43-826D-D1A82A763178}.Debug|x86.Build.0 = Debug|x86 - {B820339B-BF7D-4F43-826D-D1A82A763178}.Debug|x86.Deploy.0 = Debug|x86 - {B820339B-BF7D-4F43-826D-D1A82A763178}.Release|Any CPU.ActiveCfg = Release|x86 - {B820339B-BF7D-4F43-826D-D1A82A763178}.Release|x64.ActiveCfg = Release|x64 - {B820339B-BF7D-4F43-826D-D1A82A763178}.Release|x64.Build.0 = Release|x64 - {B820339B-BF7D-4F43-826D-D1A82A763178}.Release|x64.Deploy.0 = Release|x64 - {B820339B-BF7D-4F43-826D-D1A82A763178}.Release|x86.ActiveCfg = Release|x86 - {B820339B-BF7D-4F43-826D-D1A82A763178}.Release|x86.Build.0 = Release|x86 - {B820339B-BF7D-4F43-826D-D1A82A763178}.Release|x86.Deploy.0 = Release|x86 - {D507D20A-6AFB-4B0F-AEF0-C5D99F3EBE08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D507D20A-6AFB-4B0F-AEF0-C5D99F3EBE08}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D507D20A-6AFB-4B0F-AEF0-C5D99F3EBE08}.Debug|x64.ActiveCfg = Debug|x64 - {D507D20A-6AFB-4B0F-AEF0-C5D99F3EBE08}.Debug|x64.Build.0 = Debug|x64 - {D507D20A-6AFB-4B0F-AEF0-C5D99F3EBE08}.Debug|x86.ActiveCfg = Debug|x86 - {D507D20A-6AFB-4B0F-AEF0-C5D99F3EBE08}.Debug|x86.Build.0 = Debug|x86 - {D507D20A-6AFB-4B0F-AEF0-C5D99F3EBE08}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D507D20A-6AFB-4B0F-AEF0-C5D99F3EBE08}.Release|Any CPU.Build.0 = Release|Any CPU - {D507D20A-6AFB-4B0F-AEF0-C5D99F3EBE08}.Release|x64.ActiveCfg = Release|x64 - {D507D20A-6AFB-4B0F-AEF0-C5D99F3EBE08}.Release|x64.Build.0 = Release|x64 - {D507D20A-6AFB-4B0F-AEF0-C5D99F3EBE08}.Release|x86.ActiveCfg = Release|x86 - {D507D20A-6AFB-4B0F-AEF0-C5D99F3EBE08}.Release|x86.Build.0 = Release|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {AD0AABFA-D6C4-43AA-8C9D-D33713CD0977} - EndGlobalSection -EndGlobal diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/App.xaml b/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/App.xaml deleted file mode 100644 index adb802c6..00000000 --- a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/App.xaml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/MainWindow.xaml b/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/MainWindow.xaml deleted file mode 100644 index 42e1b302..00000000 --- a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/MainWindow.xaml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/WinUI_Sample.csproj b/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/WinUI_Sample.csproj deleted file mode 100644 index 6bf62cce..00000000 --- a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/WinUI_Sample.csproj +++ /dev/null @@ -1,36 +0,0 @@ - - - WinExe - netcoreapp5.0 - 10.0.18362.0 - 10.0.17134.0 - WinUI_Sample - - app.manifest - AnyCPU;x86;x64 - true - win-x86;win-x64 - win-$(Platform) - - - - - - - - - - - - - - - - MSBuild:Compile - - - MSBuild:Compile - - - - diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/obj/WinUI_Sample.csproj.nuget.dgspec.json b/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/obj/WinUI_Sample.csproj.nuget.dgspec.json deleted file mode 100644 index 46ec104d..00000000 --- a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/obj/WinUI_Sample.csproj.nuget.dgspec.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "format": 1, - "restore": { - "C:\\Users\\jasteph\\Desktop\\Apps\\WinUI\\WinUI_Sample\\WinUI_Sample\\WinUI_Sample.csproj": {} - }, - "projects": { - "C:\\Users\\jasteph\\Desktop\\Apps\\WinUI\\WinUI_Sample\\WinUI_Sample\\WinUI_Sample.csproj": { - "version": "1.0.0", - "restore": { - "projectUniqueName": "C:\\Users\\jasteph\\Desktop\\Apps\\WinUI\\WinUI_Sample\\WinUI_Sample\\WinUI_Sample.csproj", - "projectName": "WinUI_Sample", - "projectPath": "C:\\Users\\jasteph\\Desktop\\Apps\\WinUI\\WinUI_Sample\\WinUI_Sample\\WinUI_Sample.csproj", - "packagesPath": "C:\\Users\\jasteph\\.nuget\\packages\\", - "outputPath": "C:\\Users\\jasteph\\Desktop\\Apps\\WinUI\\WinUI_Sample\\WinUI_Sample\\obj\\", - "projectStyle": "PackageReference", - "configFilePaths": [ - "C:\\Users\\jasteph\\AppData\\Roaming\\NuGet\\NuGet.Config", - "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" - ], - "originalTargetFrameworks": [ - "net5.0" - ], - "sources": { - "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, - "https://api.nuget.org/v3/index.json": {} - }, - "frameworks": { - "net5.0": { - "projectReferences": {} - } - }, - "warningProperties": { - "warnAsError": [ - "NU1605" - ] - } - }, - "frameworks": { - "net5.0": { - "dependencies": { - "Microsoft.VCRTForwarders.140": { - "target": "Package", - "version": "[1.0.6, )" - }, - "Microsoft.WinUI": { - "target": "Package", - "version": "[3.0.0-preview1.200515.3, )" - } - }, - "imports": [ - "net461", - "net462", - "net47", - "net471", - "net472", - "net48", - "net461" - ], - "assetTargetFallback": true, - "warn": true, - "downloadDependencies": [ - { - "name": "Microsoft.AspNetCore.App.Runtime.win-x64", - "version": "[5.0.0-preview.4.20257.10, 5.0.0-preview.4.20257.10]" - }, - { - "name": "Microsoft.AspNetCore.App.Runtime.win-x86", - "version": "[5.0.0-preview.4.20257.10, 5.0.0-preview.4.20257.10]" - }, - { - "name": "Microsoft.NETCore.App.Runtime.win-x64", - "version": "[5.0.0-preview.4.20251.6, 5.0.0-preview.4.20251.6]" - }, - { - "name": "Microsoft.NETCore.App.Runtime.win-x86", - "version": "[5.0.0-preview.4.20251.6, 5.0.0-preview.4.20251.6]" - }, - { - "name": "Microsoft.WindowsDesktop.App.Runtime.win-x64", - "version": "[5.0.0-preview.4.20251.1, 5.0.0-preview.4.20251.1]" - }, - { - "name": "Microsoft.WindowsDesktop.App.Runtime.win-x86", - "version": "[5.0.0-preview.4.20251.1, 5.0.0-preview.4.20251.1]" - } - ], - "frameworkReferences": { - "Microsoft.NETCore.App": { - "privateAssets": "all" - } - }, - "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\5.0.100-preview.4.20268.1\\RuntimeIdentifierGraph.json" - } - }, - "runtimes": { - "win-x64": { - "#import": [] - }, - "win-x86": { - "#import": [] - } - } - } - } -} \ No newline at end of file diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/obj/WinUI_Sample.csproj.nuget.g.props b/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/obj/WinUI_Sample.csproj.nuget.g.props deleted file mode 100644 index 84fd7c00..00000000 --- a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/obj/WinUI_Sample.csproj.nuget.g.props +++ /dev/null @@ -1,25 +0,0 @@ - - - - True - NuGet - $(MSBuildThisFileDirectory)project.assets.json - $(UserProfile)\.nuget\packages\ - C:\Users\jasteph\.nuget\packages\ - PackageReference - 5.7.0 - - - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - - - - - - C:\Users\jasteph\.nuget\packages\microsoft.winui\3.0.0-preview1.200515.3 - - \ No newline at end of file diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/obj/WinUI_Sample.csproj.nuget.g.targets b/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/obj/WinUI_Sample.csproj.nuget.g.targets deleted file mode 100644 index cd2afc65..00000000 --- a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/obj/WinUI_Sample.csproj.nuget.g.targets +++ /dev/null @@ -1,11 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - - - - - - \ No newline at end of file diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/obj/project.assets.json b/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/obj/project.assets.json deleted file mode 100644 index b871ca01..00000000 --- a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/obj/project.assets.json +++ /dev/null @@ -1,880 +0,0 @@ -{ - "version": 3, - "targets": { - ".NETCoreApp,Version=v5.0": { - "Microsoft.VCRTForwarders.140/1.0.6": { - "type": "package", - "build": { - "build/netcoreapp2.0/Microsoft.VCRTForwarders.140.targets": {} - }, - "runtimeTargets": { - "runtimes/win10-arm64/native/debug/concrt140d_app.dll": { - "assetType": "native", - "rid": "win10-arm64" - }, - "runtimes/win10-arm64/native/debug/msvcp140_1d_app.dll": { - "assetType": "native", - "rid": "win10-arm64" - }, - "runtimes/win10-arm64/native/debug/msvcp140_2d_app.dll": { - "assetType": "native", - "rid": "win10-arm64" - }, - "runtimes/win10-arm64/native/debug/msvcp140d_app.dll": { - "assetType": "native", - "rid": "win10-arm64" - }, - "runtimes/win10-arm64/native/debug/vcamp140d_app.dll": { - "assetType": "native", - "rid": "win10-arm64" - }, - "runtimes/win10-arm64/native/debug/vccorlib140d_app.dll": { - "assetType": "native", - "rid": "win10-arm64" - }, - "runtimes/win10-arm64/native/debug/vcomp140d_app.dll": { - "assetType": "native", - "rid": "win10-arm64" - }, - "runtimes/win10-arm64/native/debug/vcruntime140d_app.dll": { - "assetType": "native", - "rid": "win10-arm64" - }, - "runtimes/win10-arm64/native/release/concrt140_app.dll": { - "assetType": "native", - "rid": "win10-arm64" - }, - "runtimes/win10-arm64/native/release/msvcp140_1_app.dll": { - "assetType": "native", - "rid": "win10-arm64" - }, - "runtimes/win10-arm64/native/release/msvcp140_2_app.dll": { - "assetType": "native", - "rid": "win10-arm64" - }, - "runtimes/win10-arm64/native/release/msvcp140_app.dll": { - "assetType": "native", - "rid": "win10-arm64" - }, - "runtimes/win10-arm64/native/release/vcamp140_app.dll": { - "assetType": "native", - "rid": "win10-arm64" - }, - "runtimes/win10-arm64/native/release/vccorlib140_app.dll": { - "assetType": "native", - "rid": "win10-arm64" - }, - "runtimes/win10-arm64/native/release/vcomp140_app.dll": { - "assetType": "native", - "rid": "win10-arm64" - }, - "runtimes/win10-arm64/native/release/vcruntime140_app.dll": { - "assetType": "native", - "rid": "win10-arm64" - }, - "runtimes/win10-x64/native/debug/concrt140d_app.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/debug/msvcp140_1d_app.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/debug/msvcp140_2d_app.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/debug/msvcp140d_app.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/debug/vcamp140d_app.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/debug/vccorlib140d_app.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/debug/vcomp140d_app.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/debug/vcruntime140_1d_app.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/debug/vcruntime140d_app.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/release/concrt140_app.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/release/msvcp140_1_app.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/release/msvcp140_2_app.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/release/msvcp140_app.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/release/vcamp140_app.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/release/vccorlib140_app.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/release/vcomp140_app.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/release/vcruntime140_1_app.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/release/vcruntime140_app.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x86/native/debug/concrt140d_app.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/debug/msvcp140_1d_app.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/debug/msvcp140_2d_app.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/debug/msvcp140d_app.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/debug/vcamp140d_app.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/debug/vccorlib140d_app.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/debug/vcomp140d_app.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/debug/vcruntime140d_app.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/release/concrt140_app.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/release/msvcp140_1_app.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/release/msvcp140_2_app.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/release/msvcp140_app.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/release/vcamp140_app.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/release/vccorlib140_app.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/release/vcomp140_app.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/release/vcruntime140_app.dll": { - "assetType": "native", - "rid": "win10-x86" - } - } - }, - "Microsoft.Windows.CsWinRT/0.1.0-prerelease.200512.7": { - "type": "package", - "compile": { - "lib/netcoreapp5.0/winrt.runtime.dll": {} - }, - "runtime": { - "lib/netcoreapp5.0/winrt.runtime.dll": {} - }, - "build": { - "build/Microsoft.Windows.CsWinRT.props": {}, - "build/Microsoft.Windows.CsWinRT.targets": {} - } - }, - "Microsoft.Windows.SDK.NET/10.0.18362.3-preview": { - "type": "package", - "dependencies": { - "Microsoft.Windows.CsWinRT": "0.1.0-prerelease.200512.7" - }, - "compile": { - "lib/netcoreapp5.0/Microsoft.Windows.SDK.NET.dll": {} - }, - "runtime": { - "lib/netcoreapp5.0/Microsoft.Windows.SDK.NET.dll": {} - } - }, - "Microsoft.WinUI/3.0.0-preview1.200515.3": { - "type": "package", - "dependencies": { - "Microsoft.Windows.CsWinRT": "0.1.0-prerelease.200512.7", - "Microsoft.Windows.SDK.NET": "10.0.18362.3-preview" - }, - "compile": { - "lib/netcoreapp5.0/Microsoft.WinUI.dll": {} - }, - "runtime": { - "lib/netcoreapp5.0/Microsoft.WinUI.dll": {} - }, - "build": { - "build/Microsoft.WinUI.props": {}, - "build/Microsoft.WinUI.targets": {} - }, - "runtimeTargets": { - "runtimes/win10-x64/native/CoreMessagingXP.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/DwmSceneI.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/InProcStubs.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/Microsoft.DirectManipulation.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/Microsoft.InputStateManager.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/Microsoft.Internal.XamlUDK.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/Microsoft.UI.Input.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/Microsoft.UI.Xaml.Controls.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/Microsoft.UI.Xaml.Controls.pri": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/Microsoft.UI.Xaml.Internal.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/Microsoft.UI.Xaml.Phone.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/Microsoft.UI.Xaml/Assets/NoiseAsset_256x256_PNG.png": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/Microsoft.ui.xaml.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/Microsoft.ui.xaml.resources.19h1.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/Microsoft.ui.xaml.resources.common.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/WebView2Loader.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/WinUIEdit.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/dcompi.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/dwmcorei.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/en-us/Microsoft.UI.Xaml.Phone.dll.mui": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/en-us/Microsoft.ui.xaml.dll.mui": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/marshal.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/marshal_umode.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x64/native/wuceffectsi.dll": { - "assetType": "native", - "rid": "win10-x64" - }, - "runtimes/win10-x86/native/CoreMessagingXP.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/DwmSceneI.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/InProcStubs.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/Microsoft.DirectManipulation.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/Microsoft.InputStateManager.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/Microsoft.Internal.XamlUDK.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/Microsoft.UI.Input.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/Microsoft.UI.Xaml.Controls.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/Microsoft.UI.Xaml.Controls.pri": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/Microsoft.UI.Xaml.Internal.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/Microsoft.UI.Xaml.Phone.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/Microsoft.UI.Xaml/Assets/NoiseAsset_256x256_PNG.png": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/Microsoft.ui.xaml.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/Microsoft.ui.xaml.resources.19h1.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/Microsoft.ui.xaml.resources.common.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/WebView2Loader.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/WinUIEdit.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/dcompi.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/dwmcorei.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/en-us/Microsoft.UI.Xaml.Phone.dll.mui": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/en-us/Microsoft.ui.xaml.dll.mui": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/marshal.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/marshal_umode.dll": { - "assetType": "native", - "rid": "win10-x86" - }, - "runtimes/win10-x86/native/wuceffectsi.dll": { - "assetType": "native", - "rid": "win10-x86" - } - } - } - }, - ".NETCoreApp,Version=v5.0/win-x64": { - "Microsoft.VCRTForwarders.140/1.0.6": { - "type": "package", - "build": { - "build/netcoreapp2.0/Microsoft.VCRTForwarders.140.targets": {} - } - }, - "Microsoft.Windows.CsWinRT/0.1.0-prerelease.200512.7": { - "type": "package", - "compile": { - "lib/netcoreapp5.0/winrt.runtime.dll": {} - }, - "runtime": { - "lib/netcoreapp5.0/winrt.runtime.dll": {} - }, - "build": { - "build/Microsoft.Windows.CsWinRT.props": {}, - "build/Microsoft.Windows.CsWinRT.targets": {} - } - }, - "Microsoft.Windows.SDK.NET/10.0.18362.3-preview": { - "type": "package", - "dependencies": { - "Microsoft.Windows.CsWinRT": "0.1.0-prerelease.200512.7" - }, - "compile": { - "lib/netcoreapp5.0/Microsoft.Windows.SDK.NET.dll": {} - }, - "runtime": { - "lib/netcoreapp5.0/Microsoft.Windows.SDK.NET.dll": {} - } - }, - "Microsoft.WinUI/3.0.0-preview1.200515.3": { - "type": "package", - "dependencies": { - "Microsoft.Windows.CsWinRT": "0.1.0-prerelease.200512.7", - "Microsoft.Windows.SDK.NET": "10.0.18362.3-preview" - }, - "compile": { - "lib/netcoreapp5.0/Microsoft.WinUI.dll": {} - }, - "runtime": { - "lib/netcoreapp5.0/Microsoft.WinUI.dll": {} - }, - "build": { - "build/Microsoft.WinUI.props": {}, - "build/Microsoft.WinUI.targets": {} - } - } - }, - ".NETCoreApp,Version=v5.0/win-x86": { - "Microsoft.VCRTForwarders.140/1.0.6": { - "type": "package", - "build": { - "build/netcoreapp2.0/Microsoft.VCRTForwarders.140.targets": {} - } - }, - "Microsoft.Windows.CsWinRT/0.1.0-prerelease.200512.7": { - "type": "package", - "compile": { - "lib/netcoreapp5.0/winrt.runtime.dll": {} - }, - "runtime": { - "lib/netcoreapp5.0/winrt.runtime.dll": {} - }, - "build": { - "build/Microsoft.Windows.CsWinRT.props": {}, - "build/Microsoft.Windows.CsWinRT.targets": {} - } - }, - "Microsoft.Windows.SDK.NET/10.0.18362.3-preview": { - "type": "package", - "dependencies": { - "Microsoft.Windows.CsWinRT": "0.1.0-prerelease.200512.7" - }, - "compile": { - "lib/netcoreapp5.0/Microsoft.Windows.SDK.NET.dll": {} - }, - "runtime": { - "lib/netcoreapp5.0/Microsoft.Windows.SDK.NET.dll": {} - } - }, - "Microsoft.WinUI/3.0.0-preview1.200515.3": { - "type": "package", - "dependencies": { - "Microsoft.Windows.CsWinRT": "0.1.0-prerelease.200512.7", - "Microsoft.Windows.SDK.NET": "10.0.18362.3-preview" - }, - "compile": { - "lib/netcoreapp5.0/Microsoft.WinUI.dll": {} - }, - "runtime": { - "lib/netcoreapp5.0/Microsoft.WinUI.dll": {} - }, - "build": { - "build/Microsoft.WinUI.props": {}, - "build/Microsoft.WinUI.targets": {} - } - } - } - }, - "libraries": { - "Microsoft.VCRTForwarders.140/1.0.6": { - "sha512": "CRemcSRRhH5wtdovxqcz3AgjttqgEXJzJuXSCjNStxW/JSm54xM7kSkwVb3tYen/mGCnGv/+PHvpEaliMEUxYA==", - "type": "package", - "path": "microsoft.vcrtforwarders.140/1.0.6", - "files": [ - ".nupkg.metadata", - ".signature.p7s", - "Unity/Editor/InitVCRTForwarders.cs", - "Unity/Editor/InitVCRTForwarders.cs.meta", - "Unity/Editor/Microsoft.VCRTForwarders.140.asmdef", - "Unity/Editor/Microsoft.VCRTForwarders.140.asmdef.meta", - "Unity/x64/concrt140_app.dll", - "Unity/x64/concrt140_app.dll.meta", - "Unity/x64/msvcp140_1_app.dll", - "Unity/x64/msvcp140_1_app.dll.meta", - "Unity/x64/msvcp140_2_app.dll", - "Unity/x64/msvcp140_2_app.dll.meta", - "Unity/x64/msvcp140_app.dll", - "Unity/x64/msvcp140_app.dll.meta", - "Unity/x64/vcamp140_app.dll", - "Unity/x64/vcamp140_app.dll.meta", - "Unity/x64/vccorlib140_app.dll", - "Unity/x64/vccorlib140_app.dll.meta", - "Unity/x64/vcomp140_app.dll", - "Unity/x64/vcomp140_app.dll.meta", - "Unity/x64/vcruntime140_1_app.dll", - "Unity/x64/vcruntime140_1_app.dll.meta", - "Unity/x64/vcruntime140_app.dll", - "Unity/x64/vcruntime140_app.dll.meta", - "build/native/Microsoft.VCRTForwarders.140.targets", - "build/net45/Microsoft.VCRTForwarders.140.targets", - "build/netcoreapp2.0/Microsoft.VCRTForwarders.140.targets", - "microsoft.vcrtforwarders.140.1.0.6.nupkg.sha512", - "microsoft.vcrtforwarders.140.nuspec", - "runtimes/win10-arm64/native/debug/concrt140d_app.dll", - "runtimes/win10-arm64/native/debug/msvcp140_1d_app.dll", - "runtimes/win10-arm64/native/debug/msvcp140_2d_app.dll", - "runtimes/win10-arm64/native/debug/msvcp140d_app.dll", - "runtimes/win10-arm64/native/debug/vcamp140d_app.dll", - "runtimes/win10-arm64/native/debug/vccorlib140d_app.dll", - "runtimes/win10-arm64/native/debug/vcomp140d_app.dll", - "runtimes/win10-arm64/native/debug/vcruntime140d_app.dll", - "runtimes/win10-arm64/native/release/concrt140_app.dll", - "runtimes/win10-arm64/native/release/msvcp140_1_app.dll", - "runtimes/win10-arm64/native/release/msvcp140_2_app.dll", - "runtimes/win10-arm64/native/release/msvcp140_app.dll", - "runtimes/win10-arm64/native/release/vcamp140_app.dll", - "runtimes/win10-arm64/native/release/vccorlib140_app.dll", - "runtimes/win10-arm64/native/release/vcomp140_app.dll", - "runtimes/win10-arm64/native/release/vcruntime140_app.dll", - "runtimes/win10-x64/native/debug/concrt140d_app.dll", - "runtimes/win10-x64/native/debug/msvcp140_1d_app.dll", - "runtimes/win10-x64/native/debug/msvcp140_2d_app.dll", - "runtimes/win10-x64/native/debug/msvcp140d_app.dll", - "runtimes/win10-x64/native/debug/vcamp140d_app.dll", - "runtimes/win10-x64/native/debug/vccorlib140d_app.dll", - "runtimes/win10-x64/native/debug/vcomp140d_app.dll", - "runtimes/win10-x64/native/debug/vcruntime140_1d_app.dll", - "runtimes/win10-x64/native/debug/vcruntime140d_app.dll", - "runtimes/win10-x64/native/release/concrt140_app.dll", - "runtimes/win10-x64/native/release/msvcp140_1_app.dll", - "runtimes/win10-x64/native/release/msvcp140_2_app.dll", - "runtimes/win10-x64/native/release/msvcp140_app.dll", - "runtimes/win10-x64/native/release/vcamp140_app.dll", - "runtimes/win10-x64/native/release/vccorlib140_app.dll", - "runtimes/win10-x64/native/release/vcomp140_app.dll", - "runtimes/win10-x64/native/release/vcruntime140_1_app.dll", - "runtimes/win10-x64/native/release/vcruntime140_app.dll", - "runtimes/win10-x86/native/debug/concrt140d_app.dll", - "runtimes/win10-x86/native/debug/msvcp140_1d_app.dll", - "runtimes/win10-x86/native/debug/msvcp140_2d_app.dll", - "runtimes/win10-x86/native/debug/msvcp140d_app.dll", - "runtimes/win10-x86/native/debug/vcamp140d_app.dll", - "runtimes/win10-x86/native/debug/vccorlib140d_app.dll", - "runtimes/win10-x86/native/debug/vcomp140d_app.dll", - "runtimes/win10-x86/native/debug/vcruntime140d_app.dll", - "runtimes/win10-x86/native/release/concrt140_app.dll", - "runtimes/win10-x86/native/release/msvcp140_1_app.dll", - "runtimes/win10-x86/native/release/msvcp140_2_app.dll", - "runtimes/win10-x86/native/release/msvcp140_app.dll", - "runtimes/win10-x86/native/release/vcamp140_app.dll", - "runtimes/win10-x86/native/release/vccorlib140_app.dll", - "runtimes/win10-x86/native/release/vcomp140_app.dll", - "runtimes/win10-x86/native/release/vcruntime140_app.dll" - ] - }, - "Microsoft.Windows.CsWinRT/0.1.0-prerelease.200512.7": { - "sha512": "Z7Nlf0X8aHGPREUYYSSAmGUU/Y7ZoNz6O3PHyAMBy5f7skDQwFolrTt6V1EMBu1yJpQ2+IDqymS26QBlyt4BFw==", - "type": "package", - "path": "microsoft.windows.cswinrt/0.1.0-prerelease.200512.7", - "files": [ - ".nupkg.metadata", - ".signature.p7s", - "LICENSE", - "build/Microsoft.Windows.CsWinRT.props", - "build/Microsoft.Windows.CsWinRT.targets", - "cswinrt.exe", - "lib/netcoreapp5.0/winrt.runtime.dll", - "lib/netstandard2.0/winrt.runtime.dll", - "microsoft.windows.cswinrt.0.1.0-prerelease.200512.7.nupkg.sha512", - "microsoft.windows.cswinrt.nuspec", - "readme.txt" - ] - }, - "Microsoft.Windows.SDK.NET/10.0.18362.3-preview": { - "sha512": "CBgUuymZfnPJyZPzR5YuWY0SHTJuCUNimlkvNYt5NTX2TnO4sp8pHBLIOcbAUGBLR9I5ieAr0i0WHJq/ABbF4Q==", - "type": "package", - "path": "microsoft.windows.sdk.net/10.0.18362.3-preview", - "files": [ - ".nupkg.metadata", - ".signature.p7s", - "lib/netcoreapp5.0/Microsoft.Windows.SDK.NET.dll", - "lib/netcoreapp5.0/Microsoft.Windows.SDK.NET.xml", - "lib/netstandard2.0/Microsoft.Windows.SDK.NET.dll", - "lib/netstandard2.0/Microsoft.Windows.SDK.NET.xml", - "microsoft.windows.sdk.net.10.0.18362.3-preview.nupkg.sha512", - "microsoft.windows.sdk.net.nuspec" - ] - }, - "Microsoft.WinUI/3.0.0-preview1.200515.3": { - "sha512": "HhmU25DZyRkarbfQy51/xSVuUhWNIIDFs1bjSyUSYxjYurAcVTxtp4MNSkGgdnb7HL8PJxNPL8rkjffI8CAxuQ==", - "type": "package", - "path": "microsoft.winui/3.0.0-preview1.200515.3", - "hasTools": true, - "files": [ - ".nupkg.metadata", - ".signature.p7s", - "build/LiftedWinRTClassRegistrations.xml", - "build/Microsoft.UI.Xaml.Markup.Compiler.interop.targets", - "build/Microsoft.UI.Xaml.Markup.Compiler.props", - "build/Microsoft.UI.Xaml.Markup.Compiler.targets", - "build/Microsoft.WinUI.AppX.targets", - "build/Microsoft.WinUI.NET.Markup.Compiler.targets", - "build/Microsoft.WinUI.References.targets", - "build/Microsoft.WinUI.props", - "build/Microsoft.WinUI.targets", - "build/native/Microsoft.WinUI.References.targets", - "build/native/Microsoft.WinUI.props", - "build/native/Microsoft.WinUI.targets", - "include/microsoft.ui.xaml.hosting.desktopwindowxamlsource.h", - "include/microsoft.ui.xaml.hosting.desktopwindowxamlsource.idl", - "include/microsoft.ui.xaml.hosting.referencetracker.h", - "include/microsoft.ui.xaml.hosting.referencetracker.idl", - "include/microsoft.ui.xaml.media.dxinterop.h", - "include/microsoft.ui.xaml.media.dxinterop.idl", - "include/microsoft.ui.xaml.window.h", - "include/microsoft.ui.xaml.window.idl", - "include/microsoft.ui.xaml.xamlroot.h", - "include/microsoft.ui.xaml.xamlroot.idl", - "lib/netcoreapp5.0/Microsoft.WinUI.dll", - "lib/netcoreapp5.0/Microsoft.WinUI.xml", - "lib/uap10.0/Microsoft.Graphics.winmd", - "lib/uap10.0/Microsoft.System.winmd", - "lib/uap10.0/Microsoft.System.xml", - "lib/uap10.0/Microsoft.UI.Xaml/Themes/generic.xaml", - "lib/uap10.0/Microsoft.UI.winmd", - "lib/uap10.0/Microsoft.UI.xml", - "license.txt", - "microsoft.winui.3.0.0-preview1.200515.3.nupkg.sha512", - "microsoft.winui.nuspec", - "readme.txt", - "runtimes/win10-x64/native/CoreMessagingXP.dll", - "runtimes/win10-x64/native/DwmSceneI.dll", - "runtimes/win10-x64/native/InProcStubs.dll", - "runtimes/win10-x64/native/Microsoft.DirectManipulation.dll", - "runtimes/win10-x64/native/Microsoft.InputStateManager.dll", - "runtimes/win10-x64/native/Microsoft.Internal.XamlUDK.dll", - "runtimes/win10-x64/native/Microsoft.UI.Input.dll", - "runtimes/win10-x64/native/Microsoft.UI.Xaml.Controls.dll", - "runtimes/win10-x64/native/Microsoft.UI.Xaml.Controls.pri", - "runtimes/win10-x64/native/Microsoft.UI.Xaml.Internal.dll", - "runtimes/win10-x64/native/Microsoft.UI.Xaml.Phone.dll", - "runtimes/win10-x64/native/Microsoft.UI.Xaml/Assets/NoiseAsset_256x256_PNG.png", - "runtimes/win10-x64/native/Microsoft.ui.xaml.dll", - "runtimes/win10-x64/native/Microsoft.ui.xaml.resources.19h1.dll", - "runtimes/win10-x64/native/Microsoft.ui.xaml.resources.common.dll", - "runtimes/win10-x64/native/WebView2Loader.dll", - "runtimes/win10-x64/native/WinUIEdit.dll", - "runtimes/win10-x64/native/dcompi.dll", - "runtimes/win10-x64/native/dwmcorei.dll", - "runtimes/win10-x64/native/en-us/Microsoft.UI.Xaml.Phone.dll.mui", - "runtimes/win10-x64/native/en-us/Microsoft.ui.xaml.dll.mui", - "runtimes/win10-x64/native/marshal.dll", - "runtimes/win10-x64/native/marshal_umode.dll", - "runtimes/win10-x64/native/wuceffectsi.dll", - "runtimes/win10-x86/native/CoreMessagingXP.dll", - "runtimes/win10-x86/native/DwmSceneI.dll", - "runtimes/win10-x86/native/InProcStubs.dll", - "runtimes/win10-x86/native/Microsoft.DirectManipulation.dll", - "runtimes/win10-x86/native/Microsoft.InputStateManager.dll", - "runtimes/win10-x86/native/Microsoft.Internal.XamlUDK.dll", - "runtimes/win10-x86/native/Microsoft.UI.Input.dll", - "runtimes/win10-x86/native/Microsoft.UI.Xaml.Controls.dll", - "runtimes/win10-x86/native/Microsoft.UI.Xaml.Controls.pri", - "runtimes/win10-x86/native/Microsoft.UI.Xaml.Internal.dll", - "runtimes/win10-x86/native/Microsoft.UI.Xaml.Phone.dll", - "runtimes/win10-x86/native/Microsoft.UI.Xaml/Assets/NoiseAsset_256x256_PNG.png", - "runtimes/win10-x86/native/Microsoft.ui.xaml.dll", - "runtimes/win10-x86/native/Microsoft.ui.xaml.resources.19h1.dll", - "runtimes/win10-x86/native/Microsoft.ui.xaml.resources.common.dll", - "runtimes/win10-x86/native/WebView2Loader.dll", - "runtimes/win10-x86/native/WinUIEdit.dll", - "runtimes/win10-x86/native/dcompi.dll", - "runtimes/win10-x86/native/dwmcorei.dll", - "runtimes/win10-x86/native/en-us/Microsoft.UI.Xaml.Phone.dll.mui", - "runtimes/win10-x86/native/en-us/Microsoft.ui.xaml.dll.mui", - "runtimes/win10-x86/native/marshal.dll", - "runtimes/win10-x86/native/marshal_umode.dll", - "runtimes/win10-x86/native/wuceffectsi.dll", - "tools/Microsoft.Build.Framework.dll", - "tools/Microsoft.Build.Utilities.Core.dll", - "tools/Microsoft.UI.Xaml.Markup.Compiler.IO.dll", - "tools/Microsoft.UI.Xaml.Markup.Compiler.MSBuildInterop.dll", - "tools/Microsoft.UI.Xaml.Markup.Compiler.dll", - "tools/NOTICE.txt", - "tools/Newtonsoft.Json.dll", - "tools/XamlCompiler.exe", - "tools/x64/GenXbf.dll", - "tools/x86/GenXbf.dll" - ] - } - }, - "projectFileDependencyGroups": { - ".NETCoreApp,Version=v5.0": [ - "Microsoft.VCRTForwarders.140 >= 1.0.6", - "Microsoft.WinUI >= 3.0.0-preview1.200515.3" - ] - }, - "packageFolders": { - "C:\\Users\\jasteph\\.nuget\\packages\\": {} - }, - "project": { - "version": "1.0.0", - "restore": { - "projectUniqueName": "C:\\Users\\jasteph\\Desktop\\Apps\\WinUI\\WinUI_Sample\\WinUI_Sample\\WinUI_Sample.csproj", - "projectName": "WinUI_Sample", - "projectPath": "C:\\Users\\jasteph\\Desktop\\Apps\\WinUI\\WinUI_Sample\\WinUI_Sample\\WinUI_Sample.csproj", - "packagesPath": "C:\\Users\\jasteph\\.nuget\\packages\\", - "outputPath": "C:\\Users\\jasteph\\Desktop\\Apps\\WinUI\\WinUI_Sample\\WinUI_Sample\\obj\\", - "projectStyle": "PackageReference", - "configFilePaths": [ - "C:\\Users\\jasteph\\AppData\\Roaming\\NuGet\\NuGet.Config", - "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" - ], - "originalTargetFrameworks": [ - "net5.0" - ], - "sources": { - "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, - "https://api.nuget.org/v3/index.json": {} - }, - "frameworks": { - "net5.0": { - "projectReferences": {} - } - }, - "warningProperties": { - "warnAsError": [ - "NU1605" - ] - } - }, - "frameworks": { - "net5.0": { - "dependencies": { - "Microsoft.VCRTForwarders.140": { - "target": "Package", - "version": "[1.0.6, )" - }, - "Microsoft.WinUI": { - "target": "Package", - "version": "[3.0.0-preview1.200515.3, )" - } - }, - "imports": [ - "net461", - "net462", - "net47", - "net471", - "net472", - "net48", - "net461" - ], - "assetTargetFallback": true, - "warn": true, - "downloadDependencies": [ - { - "name": "Microsoft.AspNetCore.App.Runtime.win-x64", - "version": "[5.0.0-preview.4.20257.10, 5.0.0-preview.4.20257.10]" - }, - { - "name": "Microsoft.AspNetCore.App.Runtime.win-x86", - "version": "[5.0.0-preview.4.20257.10, 5.0.0-preview.4.20257.10]" - }, - { - "name": "Microsoft.NETCore.App.Runtime.win-x64", - "version": "[5.0.0-preview.4.20251.6, 5.0.0-preview.4.20251.6]" - }, - { - "name": "Microsoft.NETCore.App.Runtime.win-x86", - "version": "[5.0.0-preview.4.20251.6, 5.0.0-preview.4.20251.6]" - }, - { - "name": "Microsoft.WindowsDesktop.App.Runtime.win-x64", - "version": "[5.0.0-preview.4.20251.1, 5.0.0-preview.4.20251.1]" - }, - { - "name": "Microsoft.WindowsDesktop.App.Runtime.win-x86", - "version": "[5.0.0-preview.4.20251.1, 5.0.0-preview.4.20251.1]" - } - ], - "frameworkReferences": { - "Microsoft.NETCore.App": { - "privateAssets": "all" - } - }, - "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\5.0.100-preview.4.20268.1\\RuntimeIdentifierGraph.json" - } - }, - "runtimes": { - "win-x64": { - "#import": [] - }, - "win-x86": { - "#import": [] - } - } - } -} \ No newline at end of file diff --git a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/obj/project.nuget.cache b/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/obj/project.nuget.cache deleted file mode 100644 index 784865ee..00000000 --- a/GettingStartedGuides/WinUI3_GettingStarted/WinUI_Sample/WinUI_Sample/obj/project.nuget.cache +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": 2, - "dgSpecHash": "VM3DInBJgC4iVlQJemCkraG4ukAMuIu0I5PAiAHlsBSpqWi0rPIz+GCWbNE+vcJSPIrSvbN8X1DTeoP+9WCheA==", - "success": true, - "projectFilePath": "C:\\Users\\jasteph\\Desktop\\Apps\\WinUI\\WinUI_Sample\\WinUI_Sample\\WinUI_Sample.csproj", - "expectedPackageFiles": [ - "C:\\Users\\jasteph\\.nuget\\packages\\microsoft.vcrtforwarders.140\\1.0.6\\microsoft.vcrtforwarders.140.1.0.6.nupkg.sha512", - "C:\\Users\\jasteph\\.nuget\\packages\\microsoft.windows.cswinrt\\0.1.0-prerelease.200512.7\\microsoft.windows.cswinrt.0.1.0-prerelease.200512.7.nupkg.sha512", - "C:\\Users\\jasteph\\.nuget\\packages\\microsoft.windows.sdk.net\\10.0.18362.3-preview\\microsoft.windows.sdk.net.10.0.18362.3-preview.nupkg.sha512", - "C:\\Users\\jasteph\\.nuget\\packages\\microsoft.winui\\3.0.0-preview1.200515.3\\microsoft.winui.3.0.0-preview1.200515.3.nupkg.sha512", - "C:\\Users\\jasteph\\.nuget\\packages\\microsoft.windowsdesktop.app.runtime.win-x86\\5.0.0-preview.4.20251.1\\microsoft.windowsdesktop.app.runtime.win-x86.5.0.0-preview.4.20251.1.nupkg.sha512", - "C:\\Users\\jasteph\\.nuget\\packages\\microsoft.windowsdesktop.app.runtime.win-x64\\5.0.0-preview.4.20251.1\\microsoft.windowsdesktop.app.runtime.win-x64.5.0.0-preview.4.20251.1.nupkg.sha512", - "C:\\Users\\jasteph\\.nuget\\packages\\microsoft.netcore.app.runtime.win-x64\\5.0.0-preview.4.20251.6\\microsoft.netcore.app.runtime.win-x64.5.0.0-preview.4.20251.6.nupkg.sha512", - "C:\\Users\\jasteph\\.nuget\\packages\\microsoft.aspnetcore.app.runtime.win-x64\\5.0.0-preview.4.20257.10\\microsoft.aspnetcore.app.runtime.win-x64.5.0.0-preview.4.20257.10.nupkg.sha512", - "C:\\Users\\jasteph\\.nuget\\packages\\microsoft.netcore.app.runtime.win-x86\\5.0.0-preview.4.20251.6\\microsoft.netcore.app.runtime.win-x86.5.0.0-preview.4.20251.6.nupkg.sha512", - "C:\\Users\\jasteph\\.nuget\\packages\\microsoft.aspnetcore.app.runtime.win-x86\\5.0.0-preview.4.20257.10\\microsoft.aspnetcore.app.runtime.win-x86.5.0.0-preview.4.20257.10.nupkg.sha512" - ], - "logs": [] -} \ No newline at end of file diff --git a/GettingStartedGuides/WinUI3_GettingStarted/screenshots/finished-app.png b/GettingStartedGuides/WinUI3_GettingStarted/screenshots/finished-app.png new file mode 100644 index 00000000..1792c884 Binary files /dev/null and b/GettingStartedGuides/WinUI3_GettingStarted/screenshots/finished-app.png differ diff --git a/README.md b/README.md index 35d6fe25..ce2b6914 100644 --- a/README.md +++ b/README.md @@ -1,64 +1,33 @@ # WebView2 Samples -This repository contains getting started apps as well as sample apps that demonstrate the features and usage patterns of [WebView2](https://aka.ms/webview2). As we add more features to WebView2, we will regularly update our samples. +Welcome to the WebView2Samples repo. This repo contains several types of samples for [WebView2](https://learn.microsoft.com/microsoft-edge/webview2/): -In the ``GettingStarted`` folder you will find the starter code for its respective guide listed below: -- [Win32 Getting Started](https://docs.microsoft.com/microsoft-edge/webview2/gettingstarted/win32) -- [WPF Getting Started](https://docs.microsoft.com/microsoft-edge/webview2/gettingstarted/wpf) -- [WinForms Getting Started](https://docs.microsoft.com/microsoft-edge/webview2/gettingstarted/winforms) -- [WinUI Getting Started](https://docs.microsoft.com/microsoft-edge/webview2/gettingstarted/winui) +* Getting Started tutorial projects - Completed Visual Studio projects that result from following the steps in the [Getting Started tutorials](https://learn.microsoft.com/microsoft-edge/webview2/get-started/get-started). These are like Hello World basic apps. -In the ``Sample Apps`` folder you will find: -- [WebView2Samples.sln](SampleApps/WebView2Samples.sln) - a collective solution that includes [WebView2APISample.vcxproj](SampleApps/WebView2APISample/WebView2APISample.vcxproj), [WebView2SampleWinComp.vcxproj](SampleApps/WebView2SampleWinComp/WebView2SampleWinComp.vcxproj), [WebView2WpfBrowser.csproj](SampleApps/WebView2WpfBrowser/WebView2WpfBrowser.csproj), [WebView2WindowsFormsBrowser.csproj](SampleApps/WebView2WindowsFormsBrowser/WebView2WindowsFormsBrowser.csproj), [WV2DeploymentWiXCustomActionSample](/SampleApps/WV2DeploymentWiXCustomActionSample/README.md), and [WV2DeploymentWiXBurnBundleSample](/SampleApps/WV2DeploymentWiXBurnBundleSample/README.md). +* Sample apps - WebView2 sample apps for various frameworks and platforms, as Visual Studio projects. These samples have menus and demonstrate various APIs. For more information, see [Sample apps](https://learn.microsoft.com/microsoft-edge/webview2/code-samples-links). -Please leave feedback in our [our feedback repo](https://aka.ms/webviewfeedback)! +* Deployment samples - Samples that demonstrate deploying the WebView2 Runtime. For more information, see [Deployment samples](https://learn.microsoft.com/microsoft-edge/webview2/samples/deployment-samples). -## Win32 C/C++ -#### Getting Started +## Contributing -Start with the [Win32 WebView2 getting-started guide](https://docs.microsoft.com/microsoft-edge/webview2/gettingstarted/win32) to learn how to setup a WebView within a Win32 application. +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. -This will require downloading the [Getting Started Guide](https://github.com/MicrosoftEdge/WebView2Samples/tree/master/GettingStartedGuide) directory. +When you submit a pull request, a CLA bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. -#### Comprehensive API Sample +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. -The **Win32 C++ Sample** can be found in the [WebView2APISample](./SampleApps/WebView2APISample) directory and [WebView2SampleWinComp](./SampleApps/WebView2SampleWinComp) directory. -#### Multiple WebViews Sample +## Trademarks -The [WebView2Browser](https://github.com/MicrosoftEdge/WebView2Browser) is an additional Win32 WebView2 sample project that uses multiple WebViews in a single application. Clone this project by running `git clone https://github.com/MicrosoftEdge/WebView2Browser.git`. - -Follow the [WebView2Browser guide](https://github.com/MicrosoftEdge/WebView2Browser) to learn how to build an application that utilizes multiple WebViews. - -## .NET (WPF and Windows Forms) - -#### Getting Started - -* Checkout the [WPF getting started guide](https://docs.microsoft.com/microsoft-edge/webview2/gettingstarted/wpf) for WebView2 in WPF applications -* Checkout the [Windows Forms getting started guide](https://docs.microsoft.com/microsoft-edge/webview2/gettingstarted/winforms) for WebView2 in WinForms applications - -#### Comprehensive API Sample - -* The **WPF Sample** can be found in the [WebView2WpfBrowser](./SampleApps/WebView2WpfBrowser) directory. -* The **Windows Forms Sample** can be found in the [WebView2WindowsFormsBrowser](./SampleApps/WebView2WindowsFormsBrowser) directory. - -## UWP/WinUI - -#### Comprehensive API Sample - -The **UWP WinUI Sample** can be found in the [WinUI Controls Gallery](https://github.com/microsoft/Xaml-Controls-Gallery/tree/winui3preview). - -## WebView2 Deployment - -To help developers understand how to [deploy Evergreen WebView2 Runtime](https://docs.microsoft.com/microsoft-edge/webview2/concepts/distribution#deploying-the-evergreen-webview2-runtime) with your applications, we have the following samples: - -* [WV2DeploymentWiXCustomActionSample](/SampleApps/WV2DeploymentWiXCustomActionSample/README.md) creates a [WiX](https://wixtoolset.org/) installer for [WebView2APISample](./SampleApps/WebView2APISample/README.md) and uses [WiX Custom Action](https://wixtoolset.org/documentation/manual/v3/wixdev/extensions/authoring_custom_actions.html) to chain-install the Evergreen WebView2 Runtime. -* [WV2DeploymentWiXBurnBundleSample](/SampleApps/WV2DeploymentWiXBurnBundleSample/README.md) creates a [WiX](https://wixtoolset.org/) installer for [WebView2APISample](./SampleApps/WebView2APISample/README.md) and uses [WiX Burn Bundle](https://wixtoolset.org/documentation/manual/v3/bundle/) to chain-install the Evergreen WebView2 Runtime. -* [WV2DeploymentVSInstallerSample](/SampleApps/WV2DeploymentVSInstallerSample/README.md) uses the [Microsoft Visual Studio Installer Projects](https://marketplace.visualstudio.com/items?itemName=visualstudioclient.MicrosoftVisualStudio2017InstallerProjects) to create an installer for [WebView2APISample](./SampleApps/WebView2APISample/README.md) and chain-install the Evergreen WebView2 Runtime. - -## Next Steps - -* Checkout [Introduction to Microsoft Edge WebView2](https://aka.ms/webview) to learn more about WebView2 -* Please leave us feedback specifically about the samples in [this repo](https://github.com/MicrosoftEdge/WebView2Samples/issues). -* Please leave us feedback about the WebView2 control in our [feedback repo](https://aka.ms/webviewfeedback). +This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft +trademarks or logos is subject to and must follow +[Microsoft Trademark and Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). +Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. +Any use of third-party trademarks or logos are subject to those third-party's policies. diff --git a/SampleApps/README.md b/SampleApps/README.md new file mode 100644 index 00000000..f5034e11 --- /dev/null +++ b/SampleApps/README.md @@ -0,0 +1,8 @@ +# Sample apps and Deployment samples + + +This directory contains: + +* Sample apps - WebView2 sample apps for various frameworks and platforms, as Visual Studio projects. For more information, see [Sample apps](https://learn.microsoft.com/microsoft-edge/webview2/code-samples-links). + +* Deployment samples - Samples that demonstrate deploying the WebView2 Runtime. For more information, see [Deployment samples](https://learn.microsoft.com/microsoft-edge/webview2/samples/deployment-samples). diff --git a/SampleApps/WV2CDPExtensionWPFSample/MainWindow.xaml b/SampleApps/WV2CDPExtensionWPFSample/MainWindow.xaml index 0d5757d6..97c1e5b0 100644 --- a/SampleApps/WV2CDPExtensionWPFSample/MainWindow.xaml +++ b/SampleApps/WV2CDPExtensionWPFSample/MainWindow.xaml @@ -54,6 +54,10 @@ + + + + diff --git a/SampleApps/WV2CDPExtensionWPFSample/MainWindow.xaml.cs b/SampleApps/WV2CDPExtensionWPFSample/MainWindow.xaml.cs index de469c9d..c35ab41b 100644 --- a/SampleApps/WV2CDPExtensionWPFSample/MainWindow.xaml.cs +++ b/SampleApps/WV2CDPExtensionWPFSample/MainWindow.xaml.cs @@ -7,6 +7,7 @@ using Microsoft.Web.WebView2.Core.DevToolsProtocolExtension; using System.Text; using System.Linq; +using System.Text.Json; namespace WV2CDPExtensionSample { @@ -194,6 +195,30 @@ void PrintDownloadWillBegin(object sender, Page.DownloadWillBeginEventArgs args) { Trace.WriteLine(String.Format("DownloadWillBegin Event Args - FrameId: {0} Guid: {1} URL: {2}", args.FrameId, args.Guid, args.Url)); } + + async void SubscribeToNetworkBasics(object sender, RoutedEventArgs e) + { + await cdpHelper.Network.EnableAsync(); + cdpHelper.Network.ResponseReceived += PrintResponseInfo; + cdpHelper.Network.RequestWillBeSent += PrintRequestInfo; + } + + void PrintResponseInfo(object sender, Network.ResponseReceivedEventArgs args) + { + Trace.WriteLine(JsonSerializer.Serialize(args)); + } + + void PrintRequestInfo(object sender, Network.RequestWillBeSentEventArgs args) + { + Trace.WriteLine(JsonSerializer.Serialize(args)); + } + + async void UnsubscribeFromNetworkBasics(object sender, RoutedEventArgs e) + { + cdpHelper.Network.ResponseReceived -= PrintResponseInfo; + cdpHelper.Network.RequestWillBeSent -= PrintRequestInfo; + await cdpHelper.Network.DisableAsync(); + } #endregion } } diff --git a/SampleApps/WV2CDPExtensionWPFSample/README.md b/SampleApps/WV2CDPExtensionWPFSample/README.md index 6ce6881f..0f251f21 100644 --- a/SampleApps/WV2CDPExtensionWPFSample/README.md +++ b/SampleApps/WV2CDPExtensionWPFSample/README.md @@ -1,5 +1,5 @@ --- -description: "Demonstrate the usage patterns of WebView2 CDP Extension in WPF." +description: "Demonstrates the usage patterns of WebView2 and the WebView2 CDP Extension in WPF apps." extendedZipContent: - path: SharedContent @@ -12,37 +12,15 @@ languages: page_type: sample products: - microsoft-edge -urlFragment: WV2CDPExtensionSample +urlFragment: WV2CDPExtensionWPFSample --- # WebView2 CDP Extension -This application built with the [WebView2 CDP Extension](https://aka.ms/webviewcdp) that defines all CDP methods, events, and types. + +This sample, **WV2CDPExtensionWPFSample**, is built with the WebView2 CDP Extension. This sample calls Chrome DevTools Protocol (CDP) methods on a `DevToolsProtocolHelper` object in WebView2. -The WV2CDPExtensionSample showcases of Utilizing Chrome DevTools Protocol functions using a DevToolsProtocolHelper object in WebView2. It is built as a WPF [Visual Studio 2019](https://visualstudio.microsoft.com/vs/) project and makes use of C# in the WebView2 environment. +This sample is built as a WPF Visual Studio 2019 project. It uses C# in the WebView2 environment. -If this is your first time using WebView2, we recommend first following the [Getting Started](https://docs.microsoft.com/microsoft-edge/webview2/gettingstarted/wpf) guide, which goes over how to create a WebView2 and walks through some basic WebView2 functionality. +To use this sample, see [WPF sample app with CDP extension](https://learn.microsoft.com/microsoft-edge/webview2/samples/wv2cdpextensionwpfsample). -## Prerequisites - -- [Microsoft Edge (Chromium)](https://www.microsoftedgeinsider.com/download/) installed on a supported OS. Currently we recommend the latest version of the Edge Canary channel. -- [Visual Studio](https://visualstudio.microsoft.com/vs/) with .NET support installed. -- Latest version of our [WebView2 SDK](https://aka.ms/webviewnuget), which is included in this project. -- Latest release version of our [WebView2 CDP Extension](https://aka.ms/webviewcdpnuget), which is included in this project. - -## Build the WebView2 WPF Browser - -Clone the repository and open the solution in Visual Studio. WebView2 and WebView2 DevToolsProtocolExtension is already included as a NuGet package* in this project. - -- Open the solution in Visual Studio 2019** -- Set the target you want to build (Debug/Release, AnyCPU) -- Build the project file: _WV2CDPExtensionSample.csproj_ - -That's it! Everything should be ready to just launch the app. - -*You can get the WebView2 and WebView2 DevToolsProtocolExtension NugetPackage through the Visual Studio NuGet Package Manager. - -**You can also use Visual Studio 2017 by changing the project's Platform Toolset in Project Properties/Configuration properties/General/Platform Toolset. You might also need to change the Windows SDK to the latest version available to you. - -## Code of Conduct - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact opencode@microsoft.com with any additional questions or comments. +![CDP Extension sample app running](screenshots/wv2cdpextensionwpfsample-app-running.png) diff --git a/SampleApps/WV2CDPExtensionWPFSample/screenshots/wv2cdpextensionwpfsample-app-running.png b/SampleApps/WV2CDPExtensionWPFSample/screenshots/wv2cdpextensionwpfsample-app-running.png new file mode 100644 index 00000000..c566bfcf Binary files /dev/null and b/SampleApps/WV2CDPExtensionWPFSample/screenshots/wv2cdpextensionwpfsample-app-running.png differ diff --git a/SampleApps/WV2DeploymentVSInstallerSample/README.md b/SampleApps/WV2DeploymentVSInstallerSample/README.md index 6689e105..3d4d1326 100644 --- a/SampleApps/WV2DeploymentVSInstallerSample/README.md +++ b/SampleApps/WV2DeploymentVSInstallerSample/README.md @@ -14,50 +14,11 @@ products: - microsoft-edge urlFragment: WV2DeploymentVSInstallerSample --- -# WebView2 Deployment VS Installer Sample +# WebView2 Deployment Visual Studio installer -To help developers understand how to [deploy the Evergreen WebView2 Runtime](https://docs.microsoft.com/microsoft-edge/webview2/concepts/distribution#deploying-the-evergreen-webview2-runtime) with your application, this sample uses the [Microsoft Visual Studio Installer Projects](https://marketplace.visualstudio.com/items?itemName=visualstudioclient.MicrosoftVisualStudio2017InstallerProjects) to create an installer for [WebView2APISample](./SampleApps/WebView2APISample/README.md) and chain-install the Evergreen WebView2 Runtime. + +This sample, **WV2DeploymentVSInstallerSample**, demonstrates how to deploy the Evergreen WebView2 Runtime with your application. This sample uses Microsoft Visual Studio Installer Projects to create an installer for the [WebView2APISample](../WebView2APISample//README.md) and chain-install the Evergreen WebView2 Runtime. -This sample showcases [deployment workflows](https://docs.microsoft.com/microsoft-edge/webview2/concepts/distribution#deploying-the-evergreen-webview2-runtime) for, +For more information, see [WebView2 Deployment Visual Studio installer](https://learn.microsoft.com/microsoft-edge/webview2/samples/wv2deploymentvsinstallersample). -* Download the Evergreen WebView2 Runtime Bootstrapper through link. -* Package the Evergreen WebView2 Runtime Bootstrapper. -* Package the Evergreen WebView2 Runtime Standalone Installer. - -## Prerequisites - -* [Visual Studio](https://visualstudio.microsoft.com/vs/) with C++ support installed. -* [Microsoft Visual Studio Installer Projects](https://marketplace.visualstudio.com/items?itemName=visualstudioclient.MicrosoftVisualStudio2017InstallerProjects). - -## Build steps - -To create a VS installer that chain-install the Evergreen WebView2 Runtime, - -1. Clone the repo. -1. Edit the `product.xml` file depending on the workflow you wish to use. - * For "Package the Evergreen WebView2 Runtime Bootstrapper", - * Within the `` and `` section, un-comment the line ``, and comment out other lines. - * Within the `` and `` section, make sure `PackageFile` points to `"MicrosoftEdgeWebview2Setup.exe"` so that the VS installer would be using the Bootstrapper. - * For "Download the Evergreen WebView2 Runtime Bootstrapper through link", - * Within the `` and `` section, un-comment the line ``, and comment out other lines. Note that the PublicKey for the WebView2 Runtime Bootstrapper may change without notice and we are working on addressing this issue. For now, you may need to replace it with an updated PublicKey. - * Within the `` and `` section, make sure `PackageFile` points to `"MicrosoftEdgeWebview2Setup.exe"` so that the VS installer would be using the Bootstrapper. - * For "Package the Evergreen WebView2 Runtime Standalone Installer", - * Within the `` and `` section, un-comment the line ``, and comment out other lines. - * Within the `` and `` section, make sure `PackageFile` points to `"MicrosoftEdgeWebView2RuntimeInstallerX64.exe"` so that the VS installer would be using the Standalone Installer. - * If you're targeting non-X64 devices, you may also want to edit the `MicrosoftEdgeWebView2RuntimeInstallerX64` filename to reflect the correct architecture. -1. If you plan to package either the Bootstrapper or the Standalone Installer, [download](https://developer.microsoft.com/microsoft-edge/webview2/) the Bootstrapper or the Standalone Installer and place it under the `WV2DeploymentVSInstallerSample` folder. -1. Copy the entire `WV2DeploymentVSInstallerSample` folder, and paste it under either, - * `Program Files (x86)\Microsoft SDKs\ClickOnce Bootstrapper\Packages\`, or - * `\MSBuild\Microsoft\VisualStudio\BootstrapperPackages\` (requires at least VS 2019 Update 7). -1. Create a Setup Project in Visual Studio. - * In Visual Studio menu, select `File > New > Project`. - * Search for `Setup Project`. - ![alt text](../../media/CreateSetupProject.PNG) - * Create a Setup Project. -1. Add WebView2 Runtime as a prerequisite. - * In Visual Studio menu, select `Project > Properties`. - * In the Property page, select `Prerequisites..`. - ![alt text](../../media/SetupPrerequisites.PNG) - * Check `Edge WebView2 runtime`, and un-check other prerequisites. Select `OK`. - ![alt text](../../media/SelectPrerequisites.PNG) -1. Build the Setup project. +![The deployment project](./screenshots/new-empty-deployment-project-2019.png) diff --git a/SampleApps/WV2DeploymentVSInstallerSample/screenshots/new-empty-deployment-project-2019.png b/SampleApps/WV2DeploymentVSInstallerSample/screenshots/new-empty-deployment-project-2019.png new file mode 100644 index 00000000..75fb9c7c Binary files /dev/null and b/SampleApps/WV2DeploymentVSInstallerSample/screenshots/new-empty-deployment-project-2019.png differ diff --git a/SampleApps/WV2DeploymentWiXBurnBundleSample/README.md b/SampleApps/WV2DeploymentWiXBurnBundleSample/README.md index 521fcf1a..ecbd3d1f 100644 --- a/SampleApps/WV2DeploymentWiXBurnBundleSample/README.md +++ b/SampleApps/WV2DeploymentWiXBurnBundleSample/README.md @@ -14,32 +14,9 @@ products: - microsoft-edge urlFragment: WV2DeploymentWiXBurnBundleSample --- -# WebView2 Deployment WiX Burn Bundle Sample +# WiX Burn Bundle to deploy the WebView2 Runtime -To help developers understand how to [deploy the Evergreen WebView2 Runtime](https://docs.microsoft.com/microsoft-edge/webview2/concepts/distribution#deploying-the-evergreen-webview2-runtime) with your application, this sample creates a [WiX](https://wixtoolset.org/) installer for [WebView2APISample](../WebView2APISample/README.md) and uses [WiX Burn Bundle](https://wixtoolset.org/documentation/manual/v3/bundle/) to chain-install the Evergreen WebView2 Runtime. + +This sample, **WV2DeploymentWiXBurnBundleSample**, demonstrates how to deploy the Evergreen WebView2 Runtime with your app. This sample creates a WiX installer for [WebView2APISample](../WebView2APISample/README.md) and uses WiX Burn Bundle to chain-install the Evergreen WebView2 Runtime. -This sample showcases [deployment workflows](https://docs.microsoft.com/microsoft-edge/webview2/concepts/distribution#deploying-the-evergreen-webview2-runtime) for, - -* Download the Evergreen WebView2 Runtime Bootstrapper through link. -* Package the Evergreen WebView2 Runtime Bootstrapper. - -Packaging the Evergreen WebView2 Runtime Standalone Installer is very similar to packaging the Evergreen WebView2 Runtime Bootstrapper. - -## Prerequisites - -* [Visual Studio 2019](https://visualstudio.microsoft.com/vs/) with C++ support installed. -* [WiX Toolset](https://wixtoolset.org/). -* [WiX Toolset Visual Studio 2019 Extension](https://marketplace.visualstudio.com/items?itemName=WixToolset.WixToolsetVisualStudio2019Extension). - -## Build steps - -To create a WiX installer that chain-installs the Evergreen WebView2 Runtime through Burn Bundle, - -1. Clone the repo. -1. Open `../WebView2Samples.sln` with Visual Studio. -1. This sample is an extension to the [WV2DeploymentWiXCustomActionSample](../WV2DeploymentWiXCustomActionSample/README.md) sample. Let's open `Product.wxs` under the `WV2DeploymentWiXCustomActionSample` project, and comment out all the ``, ``, and `` elements under `` and `` so that Custom Action is not used. -1. Open `Bundle.wxs` under the `WV2DeploymentWiXBurnBundleSample` project. Edit `Bundle.wxs` depending on the workflow you wish to use. - * For "Package the Evergreen WebView2 Runtime Bootstrapper", uncomment the `` element below ``, and comment out other `` elements. - * For "Download the Evergreen WebView2 Runtime Bootstrapper through link", uncomment the `` element below ``, and comment out other `` elements. -1. If you plan to package the Evergreen WebView2 Runtime Bootstrapper, [download](https://developer.microsoft.com/microsoft-edge/webview2/) the Bootstrapper and place it under the enclosing `SampleApps` folder. -1. Build the `WV2DeploymentWiXBurnBundleSample` project. +For more information about this sample, see [WiX Burn Bundle to deploy the WebView2 Runtime](https://learn.microsoft.com/microsoft-edge/webview2/samples/wv2deploymentwixburnbundlesample). diff --git a/SampleApps/WV2DeploymentWiXCustomActionSample/Product.wxs b/SampleApps/WV2DeploymentWiXCustomActionSample/Product.wxs index 7083803b..62d6603e 100644 --- a/SampleApps/WV2DeploymentWiXCustomActionSample/Product.wxs +++ b/SampleApps/WV2DeploymentWiXCustomActionSample/Product.wxs @@ -43,7 +43,7 @@ - + diff --git a/SampleApps/WV2DeploymentWiXCustomActionSample/README.md b/SampleApps/WV2DeploymentWiXCustomActionSample/README.md index b7357d40..8987360e 100644 --- a/SampleApps/WV2DeploymentWiXCustomActionSample/README.md +++ b/SampleApps/WV2DeploymentWiXCustomActionSample/README.md @@ -14,36 +14,9 @@ products: - microsoft-edge urlFragment: WV2DeploymentWiXCustomActionSample --- -# WebView2 Deployment WiX Custom Action Sample +# WiX Custom Action to deploy the WebView2 Runtime -To help developers understand how to [deploy the Evergreen WebView2 Runtime](https://docs.microsoft.com/microsoft-edge/webview2/concepts/distribution#deploying-the-evergreen-webview2-runtime) with your application, this sample creates a [WiX](https://wixtoolset.org/) installer for [WebView2APISample](../WebView2APISample/README.md) and uses [WiX Custom Action](https://wixtoolset.org/documentation/manual/v3/wixdev/extensions/authoring_custom_actions.html) to chain-install the Evergreen WebView2 Runtime. + +This sample, **WV2DeploymentWiXCustomActionSample**, demonstrates how to deploy the Evergreen WebView2 Runtime with your app. This sample creates a WiX installer for [WebView2APISample](../WebView2APISample/README.md) and uses WiX Custom Action to chain-install the Evergreen WebView2 Runtime. -This sample showcases [deployment workflows](https://docs.microsoft.com/microsoft-edge/webview2/concepts/distribution#deploying-the-evergreen-webview2-runtime) for, - -* Download the Evergreen WebView2 Runtime Bootstrapper through link. -* Package the Evergreen WebView2 Runtime Bootstrapper. -* Package the Evergreen WebView2 Runtime Standalone Installer. - -## Prerequisites - -* [Visual Studio 2019](https://visualstudio.microsoft.com/vs/) with C++ support installed. -* [WiX Toolset](https://wixtoolset.org/). -* [WiX Toolset Visual Studio 2019 Extension](https://marketplace.visualstudio.com/items?itemName=WixToolset.WixToolsetVisualStudio2019Extension). - -## Build steps - -To create a WiX installer that chain-installs the Evergreen WebView2 Runtime through Custom Action, - -1. Clone the repo. -1. Open `../WebView2Samples.sln` with Visual Studio, then open `Product.wxs` under the `WV2DeploymentWiXCustomActionSample` project. Edit `Product.wxs` depending on the workflow you wish to use. - * For "Download the Evergreen WebView2 Runtime Bootstrapper through link", - * Under ``, uncomment the `` element below ``. Comment out other `` and `` elements. - * Under ``, uncomment the `` element below ``. Comment out other `` elements. - * For "Package the Evergreen WebView2 Runtime Bootstrapper", - * Under ``, uncomment the `` and `` elements below ``. Comment out other `` and `` elements. - * Under ``, uncomment the `` element below ``. Comment out other `` elements. - * For "Package the Evergreen WebView2 Runtime Standalone Installer", - * Under ``, uncomment the `` and `` elements below ``. Comment out other `` and `` elements. If you're targeting non-X64 devices, you may also want to edit the `MicrosoftEdgeWebView2RuntimeInstallerX64` filename to reflect the correct architecture. - * Under ``, uncomment the `` element below ``. Comment out other `` elements. -1. If you plan to package either the Bootstrapper or the Standalone Installer, [download](https://developer.microsoft.com/microsoft-edge/webview2/) the Bootstrapper or the Standalone Installer and place it under the enclosing `SampleApps` folder. -1. Build the `WV2DeploymentVSInstallerSample` project. +For more information about this sample, see [WiX Custom Action to deploy the WebView2 Runtime](https://learn.microsoft.com/microsoft-edge/webview2/samples/wv2deploymentwixcustomactionsample). diff --git a/SampleApps/WebView2APISample/.gitignore b/SampleApps/WebView2APISample/.gitignore index 2a22dcf7..497bada7 100644 --- a/SampleApps/WebView2APISample/.gitignore +++ b/SampleApps/WebView2APISample/.gitignore @@ -2,8 +2,6 @@ Debug/ Release/ S Debug/ S Release/ -Win7 Debug/ -Win7 Release/ ipch/ x64/ x86/ diff --git a/SampleApps/WebView2APISample/App.cpp b/SampleApps/WebView2APISample/App.cpp index aa2683e3..70f549f1 100644 --- a/SampleApps/WebView2APISample/App.cpp +++ b/SampleApps/WebView2APISample/App.cpp @@ -25,13 +25,11 @@ static int RunMessagePump(); static DWORD WINAPI ThreadProc(void* pvParam); static void WaitForOtherThreads(); -#define NEXT_PARAM_CONTAINS(command) \ +#define NEXT_PARAM_CONTAINS(command) \ _wcsnicmp(nextParam.c_str(), command, ARRAYSIZE(command) - 1) == 0 -int APIENTRY wWinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - PWSTR lpCmdLine, - int nCmdShow) +int APIENTRY +wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR lpCmdLine, int nCmdShow) { g_hInstance = hInstance; UNREFERENCED_PARAMETER(hPrevInstance); @@ -39,12 +37,12 @@ int APIENTRY wWinMain(HINSTANCE hInstance, // Default DPI awareness to PerMonitorV2. The commandline parameters can // override this. - DPI_AWARENESS_CONTEXT dpiAwarenessContext = - DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2; + DPI_AWARENESS_CONTEXT dpiAwarenessContext = DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2; std::wstring appId(L"EBWebView.SampleApp"); - std::wstring userDirectoryFolder(L""); + std::wstring userDataFolder(L""); std::wstring initialUri; DWORD creationModeId = IDM_CREATION_MODE_WINDOWED; + WebViewCreateOption opt; if (lpCmdLine && lpCmdLine[0]) { @@ -92,9 +90,9 @@ int APIENTRY wWinMain(HINSTANCE hInstance, { initialUri = nextParam.substr(nextParam.find(L'=') + 1); } - else if (NEXT_PARAM_CONTAINS(L"userdirectoryfolder=")) + else if (NEXT_PARAM_CONTAINS(L"userdatafolder=")) { - userDirectoryFolder = nextParam.substr(nextParam.find(L'=') + 1); + userDataFolder = nextParam.substr(nextParam.find(L'=') + 1); } else if (NEXT_PARAM_CONTAINS(L"creationmode=")) { @@ -103,6 +101,10 @@ int APIENTRY wWinMain(HINSTANCE hInstance, { creationModeId = IDM_CREATION_MODE_WINDOWED; } + else if (NEXT_PARAM_CONTAINS(L"allowhostinput")) + { + creationModeId = IDM_CREATION_MODE_HOST_INPUT_PROCESSING; + } else if (NEXT_PARAM_CONTAINS(L"visualdcomp")) { creationModeId = IDM_CREATION_MODE_VISUAL_DCOMP; @@ -111,12 +113,10 @@ int APIENTRY wWinMain(HINSTANCE hInstance, { creationModeId = IDM_CREATION_MODE_TARGET_DCOMP; } -#ifdef USE_WEBVIEW2_WIN10 else if (NEXT_PARAM_CONTAINS(L"visualwincomp")) { creationModeId = IDM_CREATION_MODE_VISUAL_WINCOMP; } -#endif } } LocalFree(params); @@ -125,7 +125,7 @@ int APIENTRY wWinMain(HINSTANCE hInstance, DpiUtil::SetProcessDpiAwarenessContext(dpiAwarenessContext); - new AppWindow(creationModeId, WebViewCreateOption(), initialUri, userDirectoryFolder, true); + new AppWindow(creationModeId, opt, initialUri, userDataFolder, true); int retVal = RunMessagePump(); @@ -137,8 +137,7 @@ int APIENTRY wWinMain(HINSTANCE hInstance, // Run the message pump for one thread. static int RunMessagePump() { - HACCEL hAccelTable = - LoadAccelerators(g_hInstance, MAKEINTRESOURCE(IDC_WEBVIEW2APISAMPLE)); + HACCEL hAccelTable = LoadAccelerators(g_hInstance, MAKEINTRESOURCE(IDC_WEBVIEW2APISAMPLE)); MSG msg; @@ -206,8 +205,8 @@ static void WaitForOtherThreads() HANDLE* handleArray = threadHandles.data(); DWORD dwIndex = MsgWaitForMultipleObjects( - static_cast(threadHandles.size()), threadHandles.data(), FALSE, - INFINITE, QS_ALLEVENTS); + static_cast(threadHandles.size()), threadHandles.data(), FALSE, INFINITE, + QS_ALLEVENTS); if (dwIndex == WAIT_OBJECT_0 + threadHandles.size()) { diff --git a/SampleApps/WebView2APISample/AppStartPage.cpp b/SampleApps/WebView2APISample/AppStartPage.cpp index 669542f4..ae180d65 100644 --- a/SampleApps/WebView2APISample/AppStartPage.cpp +++ b/SampleApps/WebView2APISample/AppStartPage.cpp @@ -4,12 +4,8 @@ #include "stdafx.h" -#ifdef USE_WEBVIEW2_WIN10 #include -#else -#include -#endif -#include +#include #include "AppStartPage.h" #include "AppWindow.h" @@ -34,16 +30,8 @@ bool AreFileUrisEqual(std::wstring leftUri, std::wstring rightUri) std::wstring ResolvePathAndTrimFile(std::wstring path) { wchar_t resultPath[MAX_PATH]; -#ifdef USE_WEBVIEW2_WIN10 PathCchCanonicalize(resultPath, ARRAYSIZE(resultPath), path.c_str()); PathCchRemoveFileSpec(resultPath, ARRAYSIZE(resultPath)); -#else - // Supress compiler warning for PathCanonicalize. It is only used on Win7 - // where PathCchCanonicalize doesn't exist. - #pragma warning(suppress : 4995) - PathCanonicalize(resultPath, path.c_str()); - PathRemoveFileSpec(resultPath); -#endif return resultPath; } diff --git a/SampleApps/WebView2APISample/AppWindow.cpp b/SampleApps/WebView2APISample/AppWindow.cpp index dafe578c..ccb2c20c 100644 --- a/SampleApps/WebView2APISample/AppWindow.cpp +++ b/SampleApps/WebView2APISample/AppWindow.cpp @@ -7,15 +7,15 @@ #include "AppWindow.h" #include +#include +#include +#include #include +#include #include +#include #include #include -#include -#include -#include -#include -#include #include #include "App.h" @@ -27,23 +27,49 @@ #include "FileComponent.h" #include "ProcessComponent.h" #include "Resource.h" +#include "ScenarioAcceleratorKeyPressed.h" #include "ScenarioAddHostObject.h" #include "ScenarioAuthentication.h" #include "ScenarioClientCertificateRequested.h" #include "ScenarioCookieManagement.h" #include "ScenarioCustomDownloadExperience.h" +#include "ScenarioCustomScheme.h" +#include "ScenarioCustomSchemeNavigate.h" #include "ScenarioDOMContentLoaded.h" +#include "ScenarioDedicatedWorker.h" +#include "ScenarioDedicatedWorkerPostMessage.h" +#include "ScenarioDefaultBackgroundColor.h" +#include "ScenarioDragDrop.h" +#include "ScenarioDragDropOverride.h" +#include "ScenarioExtensionsManagement.h" +#include "ScenarioFileSystemHandleShare.h" +#include "ScenarioFileTypePolicy.h" #include "ScenarioIFrameDevicePermission.h" #include "ScenarioNavigateWithWebResourceRequest.h" +#include "ScenarioNonClientRegionSupport.h" +#include "ScenarioNotificationReceived.h" +#include "ScenarioPermissionManagement.h" +#include "ScenarioServiceWorkerManager.h" +#include "ScenarioServiceWorkerPostMessage.h" +#include "ScenarioServiceWorkerPostMessageSetting.h" +#include "ScenarioSharedWorkerManager.h" +#include "ScenarioSaveAs.h" +#include "ScenarioScreenCapture.h" +#include "ScenarioSensitivityLabel.h" +#include "ScenarioServiceWorkerWRR.h" +#include "ScenarioSharedBuffer.h" +#include "ScenarioSharedWorkerWRR.h" +#include "ScenarioThrottlingControl.h" #include "ScenarioVirtualHostMappingForPopUpWindow.h" #include "ScenarioVirtualHostMappingForSW.h" #include "ScenarioWebMessage.h" +#include "ScenarioWebRtcUdpPortConfiguration.h" #include "ScenarioWebViewEventMonitor.h" +#include "ScenarioWindowControlsOverlay.h" #include "ScriptComponent.h" #include "SettingsComponent.h" #include "TextInputDialog.h" #include "ViewComponent.h" - using namespace Microsoft::WRL; static constexpr size_t s_maxLoadString = 100; static constexpr UINT s_runAsyncWindowMessage = WM_APP; @@ -56,19 +82,21 @@ static constexpr int s_minNewWindowSize = 100; // Run Download and Install in another thread so we don't block the UI thread DWORD WINAPI DownloadAndInstallWV2RT(_In_ LPVOID lpParameter) { - AppWindow* appWindow = (AppWindow*) lpParameter; + AppWindow* appWindow = (AppWindow*)lpParameter; int returnCode = 2; // Download failed // Use fwlink to download WebView2 Bootstrapper at runtime and invoke installation // Broken/Invalid Https Certificate will fail to download - // Use of the download link below is governed by the below terms. You may acquire the link for your use at https://developer.microsoft.com/microsoft-edge/webview2/. - // Microsoft owns all legal right, title, and interest in and to the - // WebView2 Runtime Bootstrapper ("Software") and related documentation, - // including any intellectual property in the Software. You must acquire all - // code, including any code obtained from a Microsoft URL, under a separate - // license directly from Microsoft, including a Microsoft download site + // Use of the download link below is governed by the below terms. You may acquire the link + // for your use at https://developer.microsoft.com/microsoft-edge/webview2/. Microsoft owns + // all legal right, title, and interest in and to the WebView2 Runtime Bootstrapper + // ("Software") and related documentation, including any intellectual property in the + // Software. You must acquire all code, including any code obtained from a Microsoft URL, + // under a separate license directly from Microsoft, including a Microsoft download site // (e.g., https://developer.microsoft.com/microsoft-edge/webview2/). - HRESULT hr = URLDownloadToFile(NULL, L"https://go.microsoft.com/fwlink/p/?LinkId=2124703", L".\\MicrosoftEdgeWebview2Setup.exe", 0, 0); + HRESULT hr = URLDownloadToFile( + NULL, L"https://go.microsoft.com/fwlink/p/?LinkId=2124703", + L".\\MicrosoftEdgeWebview2Setup.exe", 0, 0); if (hr == S_OK) { // Either Package the WebView2 Bootstrapper with your app or download it using fwlink @@ -86,7 +114,7 @@ DWORD WINAPI DownloadAndInstallWV2RT(_In_ LPVOID lpParameter) if (ShellExecuteEx(&shExInfo)) { - returnCode = 0; // Install successfull + returnCode = 0; // Install successful } else { @@ -111,9 +139,11 @@ static INT_PTR CALLBACK DlgProcStatic(HWND hDlg, UINT message, WPARAM wParam, LP SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)app); SetDlgItemText(hDlg, IDC_EDIT_PROFILE, app->GetWebViewOption().profile.c_str()); - SetDlgItemText(hDlg, IDC_EDIT_DOWNLOAD_PATH, - app->GetWebViewOption().downloadPath.c_str()); + SetDlgItemText( + hDlg, IDC_EDIT_DOWNLOAD_PATH, app->GetWebViewOption().downloadPath.c_str()); + SetDlgItemText(hDlg, IDC_EDIT_LOCALE, app->GetWebViewOption().scriptLocale.c_str()); CheckDlgButton(hDlg, IDC_CHECK_INPRIVATE, app->GetWebViewOption().isInPrivate); + return (INT_PTR)TRUE; } case WM_COMMAND: @@ -125,15 +155,21 @@ static INT_PTR CALLBACK DlgProcStatic(HWND hDlg, UINT message, WPARAM wParam, LP GetDlgItemText(hDlg, IDC_EDIT_PROFILE, text, length + 1); bool inPrivate = IsDlgButtonChecked(hDlg, IDC_CHECK_INPRIVATE); - int downloadPathLength = GetWindowTextLength( - GetDlgItem(hDlg, IDC_EDIT_DOWNLOAD_PATH)); + int downloadPathLength = + GetWindowTextLength(GetDlgItem(hDlg, IDC_EDIT_DOWNLOAD_PATH)); wchar_t downloadPath[MAX_PATH] = {}; - GetDlgItemText(hDlg, IDC_EDIT_DOWNLOAD_PATH, downloadPath, - downloadPathLength + 1); + GetDlgItemText(hDlg, IDC_EDIT_DOWNLOAD_PATH, downloadPath, downloadPathLength + 1); + + int scriptLocaleLength = GetWindowTextLength(GetDlgItem(hDlg, IDC_EDIT_LOCALE)); + wchar_t scriptLocale[MAX_PATH] = {}; + GetDlgItemText(hDlg, IDC_EDIT_LOCALE, scriptLocale, scriptLocaleLength + 1); + + bool useOsRegion = IsDlgButtonChecked(hDlg, IDC_CHECK_USE_OS_REGION); - WebViewCreateOption opt(std::wstring(std::move(text)), inPrivate, - std::wstring(std::move(downloadPath)), - WebViewCreateEntry::EVER_FROM_CREATE_WITH_OPTION_MENU); + WebViewCreateOption opt( + std::wstring(std::move(text)), inPrivate, std::wstring(std::move(downloadPath)), + std::wstring(std::move(scriptLocale)), + WebViewCreateEntry::EVER_FROM_CREATE_WITH_OPTION_MENU, useOsRegion); // create app window new AppWindow(app->GetCreationModeId(), opt); @@ -160,23 +196,14 @@ void WebViewCreateOption::PopupDialog(AppWindow* app) (LPARAM)app); } - // Creates a new window which is a copy of the entire app, but on the same thread. AppWindow::AppWindow( - UINT creationModeId, - const WebViewCreateOption& opt, - const std::wstring& initialUri, - const std::wstring& userDataFolderParam, - bool isMainWindow, - std::function webviewCreatedCallback, - bool customWindowRect, - RECT windowRect, - bool shouldHaveToolbar - ) - : m_creationModeId(creationModeId), - m_webviewOption(opt), - m_initialUri(initialUri), - m_onWebViewFirstInitialized(webviewCreatedCallback) + UINT creationModeId, const WebViewCreateOption& opt, const std::wstring& initialUri, + const std::wstring& userDataFolderParam, bool isMainWindow, + std::function webviewCreatedCallback, bool customWindowRect, RECT windowRect, + bool shouldHaveToolbar, bool isPopup) + : m_creationModeId(creationModeId), m_webviewOption(opt), m_initialUri(initialUri), + m_onWebViewFirstInitialized(webviewCreatedCallback), m_isPopupWindow(isPopup) { // Initialize COM as STA. CHECK_FAILURE(OleInitialize(NULL)); @@ -186,6 +213,13 @@ AppWindow::AppWindow( WCHAR szTitle[s_maxLoadString]; // The title bar text LoadStringW(g_hInstance, IDS_APP_TITLE, szTitle, s_maxLoadString); m_appTitle = szTitle; + DWORD windowStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + if (m_webviewOption.useWco) + { + windowStyle &= ~WS_OVERLAPPEDWINDOW; + windowStyle |= (WS_POPUP | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX); + } + if (userDataFolderParam.length() > 0) { @@ -195,33 +229,33 @@ AppWindow::AppWindow( if (customWindowRect) { m_mainWindow = CreateWindowExW( - WS_EX_CONTROLPARENT, GetWindowClass(), szTitle, WS_OVERLAPPEDWINDOW, windowRect.left, - windowRect.top, windowRect.right-windowRect.left, windowRect.bottom-windowRect.top, nullptr, nullptr, g_hInstance, nullptr); + WS_EX_CONTROLPARENT, GetWindowClass(), szTitle, windowStyle, windowRect.left, + windowRect.top, windowRect.right - windowRect.left, + windowRect.bottom - windowRect.top, nullptr, nullptr, g_hInstance, nullptr); } else { m_mainWindow = CreateWindowExW( - WS_EX_CONTROLPARENT, GetWindowClass(), szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, - 0, CW_USEDEFAULT, 0, nullptr, nullptr, g_hInstance, nullptr); + WS_EX_CONTROLPARENT, GetWindowClass(), szTitle, windowStyle, CW_USEDEFAULT, 0, + CW_USEDEFAULT, 0, nullptr, nullptr, g_hInstance, nullptr); } m_appBackgroundImageHandle = (HBITMAP)LoadImage( - g_hInstance, MAKEINTRESOURCE(IDI_WEBVIEW2_BACKGROUND), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + g_hInstance, MAKEINTRESOURCE(IDI_WEBVIEW2_BACKGROUND), IMAGE_BITMAP, 0, 0, + LR_DEFAULTCOLOR); GetObject(m_appBackgroundImageHandle, sizeof(m_appBackgroundImage), &m_appBackgroundImage); m_memHdc = CreateCompatibleDC(GetDC(m_mainWindow)); SelectObject(m_memHdc, m_appBackgroundImageHandle); SetWindowLongPtr(m_mainWindow, GWLP_USERDATA, (LONG_PTR)this); -#ifdef USE_WEBVIEW2_WIN10 //! [TextScaleChanged1] if (winrt::try_get_activation_factory()) { m_uiSettings = winrt::Windows::UI::ViewManagement::UISettings(); - m_uiSettings.TextScaleFactorChanged({ this, &AppWindow::OnTextScaleChanged }); + m_uiSettings.TextScaleFactorChanged({this, &AppWindow::OnTextScaleChanged}); } //! [TextScaleChanged1] -#endif if (shouldHaveToolbar) { @@ -231,6 +265,12 @@ AppWindow::AppWindow( UpdateCreationModeMenu(); ShowWindow(m_mainWindow, g_nCmdShow); UpdateWindow(m_mainWindow); + if (m_webviewOption.useWco) + { + SetMenu(m_mainWindow, NULL); + SetWindowPos(m_mainWindow, nullptr, 0, 0, 1800, 900, 0); + m_toolbar.Hide(); + } // If no WebView2 Runtime installed, create new thread to do install/download. // Otherwise just initialize webview. @@ -238,19 +278,20 @@ AppWindow::AppWindow( HRESULT hr = GetAvailableCoreWebView2BrowserVersionString(nullptr, &version_info); if (hr == S_OK && version_info != nullptr) { - RunAsync([this] { - InitializeWebView(); - }); + RunAsync([this] { InitializeWebView(); }); } else { - if (isMainWindow) { + if (isMainWindow) + { AddRef(); - CreateThread(0, 0, DownloadAndInstallWV2RT, (void*) this, 0, 0); + CreateThread(0, 0, DownloadAndInstallWV2RT, (void*)this, 0, 0); } else { - MessageBox(m_mainWindow, L"WebView Runtime not installed", L"WebView Runtime Installation status", MB_OK); + MessageBox( + m_mainWindow, L"WebView Runtime not installed", + L"WebView Runtime Installation status", MB_OK); } } } @@ -265,7 +306,8 @@ AppWindow::~AppWindow() PCWSTR AppWindow::GetWindowClass() { // Only do this once - static PCWSTR windowClass = [] { + static PCWSTR windowClass = [] + { static WCHAR windowClass[s_maxLoadString]; LoadStringW(g_hInstance, IDC_WEBVIEW2APISAMPLE, windowClass, s_maxLoadString); @@ -282,7 +324,7 @@ PCWSTR AppWindow::GetWindowClass() wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WEBVIEW2APISAMPLE); wcex.lpszClassName = windowClass; - wcex.hIconSm = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SMALL)); + wcex.hIconSm = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_WEBVIEW2APISAMPLE)); RegisterClassExW(&wcex); return windowClass; @@ -339,13 +381,10 @@ bool AppWindow::HandleWindowMessage( } RECT* const newWindowSize = reinterpret_cast(lParam); - SetWindowPos(hWnd, - nullptr, - newWindowSize->left, - newWindowSize->top, + SetWindowPos( + hWnd, nullptr, newWindowSize->left, newWindowSize->top, newWindowSize->right - newWindowSize->left, - newWindowSize->bottom - newWindowSize->top, - SWP_NOZORDER | SWP_NOACTIVATE); + newWindowSize->bottom - newWindowSize->top, SWP_NOZORDER | SWP_NOACTIVATE); return true; } break; @@ -358,9 +397,10 @@ bool AppWindow::HandleWindowMessage( hdc = GetDC(hWnd); - StretchBlt(hdc, m_appBackgroundImageRect.left, m_appBackgroundImageRect.top, - m_appBackgroundImageRect.right, m_appBackgroundImageRect.bottom, m_memHdc, - 0, 0, m_appBackgroundImage.bmWidth, m_appBackgroundImage.bmHeight, SRCCOPY); + StretchBlt( + hdc, m_appBackgroundImageRect.left, m_appBackgroundImageRect.top, + m_appBackgroundImageRect.right, m_appBackgroundImageRect.bottom, m_memHdc, 0, 0, + m_appBackgroundImage.bmWidth, m_appBackgroundImage.bmHeight, SRCCOPY); EndPaint(hWnd, &ps); return true; @@ -414,6 +454,7 @@ bool AppWindow::HandleWindowMessage( break; //! [RestartManager] case WM_KEYDOWN: + case WM_SYSKEYDOWN: { // If bit 30 is set, it means the WM_KEYDOWN message is autorepeated. // We want to ignore it in that case. @@ -458,17 +499,25 @@ bool AppWindow::ExecuteWebViewCommands(WPARAM wParam, LPARAM lParam) case IDM_GET_USER_DATA_FOLDER: { //! [GetUserDataFolder] - auto environment7 = - m_webViewEnvironment.try_query(); + auto environment7 = m_webViewEnvironment.try_query(); CHECK_FEATURE_RETURN(environment7); wil::unique_cotaskmem_string userDataFolder; environment7->get_UserDataFolder(&userDataFolder); - MessageBox( - m_mainWindow, userDataFolder.get(), L"User Data Folder", - MB_OK); + MessageBox(m_mainWindow, userDataFolder.get(), L"User Data Folder", MB_OK); //! [GetUserDataFolder] return true; } + case IDM_GET_FAILURE_REPORT_FOLDER: + { + //! [GetFailureReportFolder] + auto environment11 = m_webViewEnvironment.try_query(); + CHECK_FEATURE_RETURN(environment11); + wil::unique_cotaskmem_string failureReportFolder; + environment11->get_FailureReportFolderPath(&failureReportFolder); + MessageBox(m_mainWindow, failureReportFolder.get(), L"Failure Report Folder", MB_OK); + //! [GetFailureReportFolder] + return true; + } case IDM_CLOSE_WEBVIEW: { CloseWebView(); @@ -484,6 +533,11 @@ bool AppWindow::ExecuteWebViewCommands(WPARAM wParam, LPARAM lParam) NewComponent(this); return true; } + case IDM_SCENARIO_WEBRTC_UDP_PORT_CONFIGURATION: + { + NewComponent(this); + return true; + } case IDM_SCENARIO_ADD_HOST_OBJECT: { NewComponent(this); @@ -525,7 +579,6 @@ bool AppWindow::ExecuteWebViewCommands(WPARAM wParam, LPARAM lParam) case IDM_SCENARIO_AUTHENTICATION: { NewComponent(this); - return true; } case IDM_SCENARIO_COOKIE_MANAGEMENT: @@ -533,6 +586,64 @@ bool AppWindow::ExecuteWebViewCommands(WPARAM wParam, LPARAM lParam) NewComponent(this); return true; } + case IDM_SCENARIO_COOKIE_MANAGEMENT_PROFILE: + { + NewComponent(this, true); + MessageBox( + m_mainWindow, L"Got CookieManager from Profile instead of ICoreWebView2.", + L"CookieManagement", MB_OK); + return true; + } + case IDM_SCENARIO_EXTENSIONS_MANAGEMENT_INSTALL_DEFAULT: + { + NewComponent(this, false); + return true; + } + case IDM_SCENARIO_EXTENSIONS_MANAGEMENT_OFFLOAD_DEFAULT: + { + NewComponent(this, true); + return true; + } + case IDM_SCENARIO_DRAG_DROP_OVERRIDE: + { + if (m_dcompDevice || m_wincompCompositor) + { + NewComponent(this); + } + else + { + MessageBox( + m_mainWindow, + L"Drag and Drop Override is only supported in visual hosting mode", + L"Drag and Drop Override", MB_OK); + } + return true; + } + case IDM_SCENARIO_CUSTOM_SCHEME: + { + NewComponent(this); + return true; + } + case IDM_SCENARIO_CUSTOM_SCHEME_NAVIGATE: + { + NewComponent(this); + return true; + } + case IDM_SCENARIO_SHARED_WORKER: + { + NewComponent(this); + return true; + } + case IDM_SCENARIO_SERVICE_WORKER_WRR: + { + NewComponent(this); + return true; + } + case IDM_SCENARIO_SHARED_BUFFER: + { + NewComponent(this); + return true; + } case IDM_SCENARIO_DOM_CONTENT_LOADED: { NewComponent(this); @@ -543,6 +654,35 @@ bool AppWindow::ExecuteWebViewCommands(WPARAM wParam, LPARAM lParam) NewComponent(this); return true; } + case IDM_SCENARIO_NOTIFICATION: + { + NewComponent(this); + return true; + } + case IDM_SCENARIO_PIRM_SET_ALLOWLIST: + { + auto sensitivityLabelComponent = GetOrCreateComponent(); + sensitivityLabelComponent->SetPageRestrictionManagerAllowlist(); + return true; + } + case IDM_SCENARIO_PIRM_CHECK_AVAILABILITY: + { + auto sensitivityLabelComponent = GetOrCreateComponent(); + sensitivityLabelComponent->CheckPageRestrictionManagerAvailability(); + return true; + } + case IDM_SCENARIO_SENSITIVITY_LABEL_START_TEST: + { + auto sensitivityLabelComponent = GetOrCreateComponent(); + sensitivityLabelComponent->LaunchLabelDemoPage(); + return true; + } + case IDM_SCENARIO_SENSITIVITY_LABEL_TOGGLE_EVENTS: + { + auto sensitivityLabelComponent = GetOrCreateComponent(); + sensitivityLabelComponent->ToggleEventListener(); + return true; + } case IDM_SCENARIO_TESTING_FOCUS: { WCHAR testingFocusPath[] = L"ScenarioTestingFocus.html"; @@ -575,6 +715,171 @@ bool AppWindow::ExecuteWebViewCommands(WPARAM wParam, LPARAM lParam) NewComponent(this); return true; } + case IDM_SCENARIO_BROWSER_PRINT_PREVIEW: + { + return ShowPrintUI(COREWEBVIEW2_PRINT_DIALOG_KIND_BROWSER); + } + case IDM_SCENARIO_SYSTEM_PRINT: + { + return ShowPrintUI(COREWEBVIEW2_PRINT_DIALOG_KIND_SYSTEM); + } + case IDM_SCENARIO_PRINT_TO_DEFAULT_PRINTER: + { + return PrintToDefaultPrinter(); + } + case IDM_SCENARIO_PRINT_TO_PRINTER: + { + return PrintToPrinter(); + } + case IDM_SCENARIO_PRINT_TO_PDF_STREAM: + { + return PrintToPdfStream(); + } + case IDM_SCENARIO_NON_CLIENT_REGION_SUPPORT: + { + NewComponent(this); + return true; + } + case IDM_SCENARIO_WINDOW_CONTROLS_OVERLAY: + { + NewComponent(this); + return true; + } + case IDM_SCENARIO_ACCELERATOR_KEY_PRESSED: + { + NewComponent(this); + return true; + } + case IDM_SCENARIO_THROTTLING_CONTROL: + { + NewComponent(this); + return true; + } + case IDM_SCENARIO_SERVICE_WORKER_REGISTRATION_REQUESTED: + { + if (!GetComponent()) + { + NewComponent(this); + } + return true; + } + case IDM_SCENARIO_SERVICE_WORKER_POST_MESSAGE: + { + NewComponent(this); + return true; + } + case IDM_SCENARIO_DEDICATED_WORKER: + { + if (!GetComponent()) + { + NewComponent(this); + } + return true; + } + case IDM_SCENARIO_DEDICATED_WORKER_POST_MESSAGE: + { + NewComponent(this); + return true; + } + case IDM_SCENARIO_SHARED_WORKER_MANAGER: + { + if (!GetComponent()) + { + NewComponent(this); + } + return true; + } + case IDM_SCENARIO_GET_SERVICE_WORKER_REGISTRATIONS: + { + auto worker_manager = GetComponent(); + if (!worker_manager) + { + NewComponent(this); + worker_manager = GetComponent(); + } + worker_manager->GetAllServiceWorkerRegistrations(); + return true; + } + case IDM_SCENARIO_GET_SERVICE_WORKER_REGISTERED_FOR_SCOPE: + { + auto worker_manager = GetComponent(); + if (!worker_manager) + { + NewComponent(this); + worker_manager = GetComponent(); + } + worker_manager->GetServiceWorkerRegisteredForScope(); + return true; + } + case IDM_SCENARIO_GET_SHARED_WORKERS: + { + auto worker_manager = GetComponent(); + if (!worker_manager) + { + NewComponent(this); + worker_manager = GetComponent(); + } + worker_manager->GetAllSharedWorkers(); + return true; + } + case IDM_TOGGLE_SERVICE_WORKER_JS_API_SETTING: + { + auto component = GetComponent(); + if (!component) + { + NewComponent(this); + component = GetComponent(); + } + component->ToggleServiceWorkerJsApiSetting(); + return true; + } + case IDM_SCENARIO_SCREEN_CAPTURE: + { + NewComponent(this); + return true; + } + case IDM_SCENARIO_FILE_TYPE_POLICY: + { + NewComponent(this); + return true; + } + case IDM_START_FIND: + { + std::wstring searchTerm = L"webview"; // Replace with the actual term + return Start(searchTerm); + } + case IDM_STOP_FIND: + { + return StopFind(); + } + case IDM_GET_MATCHES: + { + return GetMatchCount(); + } + case IDM_GET_ACTIVE_MATCH_INDEX: + { + return GetActiveMatchIndex(); + } + case IDC_FIND_TERM: + { + return FindTerm(); + } + case IDC_IS_CASE_SENSITIVE: + { + return IsCaseSensitive(); + } + case IDC_SHOULD_MATCH_WHOLE_WORD: + { + return ShouldMatchWord(); + } + case IDC_SHOULD_HIGHLIGHT_ALL_MATCHES: + { + return ShouldHighlightAllMatches(); + } + case IDC_SUPPRESS_DEFAULT_FIND_DIALOG: + { + return SuppressDefaultFindDialog(); + } } return false; } @@ -613,8 +918,9 @@ bool AppWindow::ExecuteAppCommands(WPARAM wParam, LPARAM lParam) CHECK_FEATURE_RETURN(experimentalEnvironment3); HRESULT hr = experimentalEnvironment3->UpdateRuntime( Callback( - [](HRESULT errorCode, - ICoreWebView2ExperimentalUpdateRuntimeResult* result) -> HRESULT { + [this](HRESULT errorCode, ICoreWebView2ExperimentalUpdateRuntimeResult* result) + -> HRESULT + { HRESULT updateError = E_FAIL; COREWEBVIEW2_UPDATE_RUNTIME_STATUS status = COREWEBVIEW2_UPDATE_RUNTIME_STATUS_FAILED; @@ -627,12 +933,12 @@ bool AppWindow::ExecuteAppCommands(WPARAM wParam, LPARAM lParam) formattedMessage << "UpdateRuntime result (0x" << std::hex << errorCode << "), status(" << status << "), extendedError(" << updateError << ")"; - MessageBox(nullptr, formattedMessage.str().c_str(), nullptr, MB_OK); + AsyncMessageBox(std::move(formattedMessage.str()), L"UpdateRuntimeResult"); return S_OK; }) .Get()); if (FAILED(hr)) - ShowFailure(hr, L"Call to TryUpdateRuntime failed"); + ShowFailure(hr, L"Call to UpdateRuntime failed"); //! [UpdateRuntime] return true; } @@ -640,11 +946,10 @@ bool AppWindow::ExecuteAppCommands(WPARAM wParam, LPARAM lParam) CloseAppWindow(); return true; case IDM_CREATION_MODE_WINDOWED: + case IDM_CREATION_MODE_HOST_INPUT_PROCESSING: case IDM_CREATION_MODE_VISUAL_DCOMP: case IDM_CREATION_MODE_TARGET_DCOMP: -#ifdef USE_WEBVIEW2_WIN10 case IDM_CREATION_MODE_VISUAL_WINCOMP: -#endif m_creationModeId = LOWORD(wParam); UpdateCreationModeMenu(); return true; @@ -668,14 +973,22 @@ bool AppWindow::ExecuteAppCommands(WPARAM wParam, LPARAM lParam) return true; case IDM_TOGGLE_TOPMOST_WINDOW: { - bool isCurrentlyTopMost = (GetWindowLong(m_mainWindow, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0; - SetWindowPos(m_mainWindow, isCurrentlyTopMost ? HWND_NOTOPMOST : HWND_TOPMOST, - 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); + bool isCurrentlyTopMost = + (GetWindowLong(m_mainWindow, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0; + SetWindowPos( + m_mainWindow, isCurrentlyTopMost ? HWND_NOTOPMOST : HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); return true; } case IDM_TOGGLE_EXCLUSIVE_USER_DATA_FOLDER_ACCESS: ToggleExclusiveUserDataFolderAccess(); return true; + case IDM_TOGGLE_CUSTOM_CRASH_REPORTING: + ToggleCustomCrashReporting(); + return true; + case IDM_TOGGLE_TRACKING_PREVENTION: + ToggleTrackingPrevention(); + return true; case IDM_SCENARIO_CLEAR_BROWSING_DATA_COOKIES: { return ClearBrowsingData(COREWEBVIEW2_BROWSING_DATA_KINDS_COOKIES); @@ -698,9 +1011,9 @@ bool AppWindow::ExecuteAppCommands(WPARAM wParam, LPARAM lParam) } case IDM_SCENARIO_CLEAR_BROWSING_DATA_AUTOFILL: { - return ClearBrowsingData( - (COREWEBVIEW2_BROWSING_DATA_KINDS)(COREWEBVIEW2_BROWSING_DATA_KINDS_GENERAL_AUTOFILL | - COREWEBVIEW2_BROWSING_DATA_KINDS_PASSWORD_AUTOSAVE)); + return ClearBrowsingData(( + COREWEBVIEW2_BROWSING_DATA_KINDS)(COREWEBVIEW2_BROWSING_DATA_KINDS_GENERAL_AUTOFILL | + COREWEBVIEW2_BROWSING_DATA_KINDS_PASSWORD_AUTOSAVE)); } case IDM_SCENARIO_CLEAR_BROWSING_DATA_BROWSING_HISTORY: { @@ -708,78 +1021,685 @@ bool AppWindow::ExecuteAppCommands(WPARAM wParam, LPARAM lParam) } case IDM_SCENARIO_CLEAR_BROWSING_DATA_ALL_PROFILE: { - return ClearBrowsingData(COREWEBVIEW2_BROWSING_DATA_KINDS_ALL_PROFILE); - } + return ClearBrowsingData(COREWEBVIEW2_BROWSING_DATA_KINDS_ALL_PROFILE); + } + case IDM_SCENARIO_CLEAR_CUSTOM_DATA_PARTITION: + { + return ClearCustomDataPartition(); + } + } + return false; +} +//! [ClearBrowsingData] +bool AppWindow::ClearBrowsingData(COREWEBVIEW2_BROWSING_DATA_KINDS dataKinds) +{ + auto webView2_13 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_13); + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + CHECK_FEATURE_RETURN(webView2Profile); + auto webView2Profile2 = webView2Profile.try_query(); + CHECK_FEATURE_RETURN(webView2Profile2); + // Clear the browsing data from the last hour. + double endTime = (double)std::time(nullptr); + double startTime = endTime - 3600.0; + CHECK_FAILURE(webView2Profile2->ClearBrowsingDataInTimeRange( + dataKinds, startTime, endTime, + Callback( + [this](HRESULT error) -> HRESULT + { + AsyncMessageBox(L"Completed", L"Clear Browsing Data"); + return S_OK; + }) + .Get())); + return true; +} +//! [ClearBrowsingData] + +//! [ClearCustomDataPartition] +bool AppWindow::ClearCustomDataPartition() +{ + auto webView2_13 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_13); + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + CHECK_FEATURE_RETURN(webView2Profile); + auto webView2Profile7 = webView2Profile.try_query(); + CHECK_FEATURE_RETURN(webView2Profile7); + std::wstring partitionToClearData; + wil::com_ptr webViewStaging20; + webViewStaging20 = m_webView.try_query(); + wil::unique_cotaskmem_string partitionId; + CHECK_FAILURE(webViewStaging20->get_CustomDataPartitionId(&partitionId)); + if (!partitionId.get() || !*partitionId.get()) + { + TextInputDialog dialog( + GetMainWindow(), L"Custom Data Partition Id", L"Custom Data Partition Id:", + L"Enter custom data partition id"); + if (dialog.confirmed) + { + partitionToClearData = dialog.input.c_str(); + } + } + else + { + // Use partition id from the WebView. + partitionToClearData = partitionId.get(); + } + if (!partitionToClearData.empty()) + { + CHECK_FAILURE(webView2Profile7->ClearCustomDataPartition( + partitionToClearData.c_str(), + Callback( + [this](HRESULT result) -> HRESULT + { + if (SUCCEEDED(result)) + { + AsyncMessageBox(L"Completed", L"Clear Custom Data Partition"); + } + else + { + std::wstringstream message; + message << L"Failed: " << std::to_wstring(result) << L"(0x" << std::hex + << result << L")" << std::endl; + AsyncMessageBox(message.str(), L"Clear Custom Data Partition"); + } + return S_OK; + }) + .Get())); + } + return true; +} +//! [ClearCustomDataPartition] + +// Prompt the user for a new language string +void AppWindow::ChangeLanguage() +{ + TextInputDialog dialog( + GetMainWindow(), L"Language", L"Language:", + L"Enter a language to use for WebView, or leave blank to restore default.", + m_language.empty() ? L"zh-cn" : m_language.c_str()); + if (dialog.confirmed) + { + m_language = (dialog.input); + } +} + +// Toggle AAD SSO enabled +void AppWindow::ToggleAADSSO() +{ + m_AADSSOEnabled = !m_AADSSOEnabled; + MessageBox( + nullptr, + m_AADSSOEnabled ? L"AAD single sign on will be enabled for new WebView " + L"created after all webviews are closed." + : L"AAD single sign on will be disabled for new WebView" + L" created after all webviews are closed.", + L"AAD SSO change", MB_OK); +} + +void AppWindow::ToggleExclusiveUserDataFolderAccess() +{ + m_ExclusiveUserDataFolderAccess = !m_ExclusiveUserDataFolderAccess; + MessageBox( + nullptr, + m_ExclusiveUserDataFolderAccess + ? L"Will request exclusive access to user data folder " + L"for new WebView created after all webviews are closed." + : L"Will not request exclusive access to user data folder " + L"for new WebView created after all webviews are closed.", + L"Exclusive User Data Folder Access change", MB_OK); +} + +void AppWindow::ToggleCustomCrashReporting() +{ + m_CustomCrashReportingEnabled = !m_CustomCrashReportingEnabled; + MessageBox( + nullptr, + m_CustomCrashReportingEnabled ? L"Crash reporting will be disabled for new WebView " + L"created after all webviews are closed." + : L"Crash reporting will be enabled for new WebView " + L"created after all webviews are closed.", + L"Custom Crash Reporting", MB_OK); +} + +void AppWindow::ToggleTrackingPrevention() +{ + m_TrackingPreventionEnabled = !m_TrackingPreventionEnabled; + MessageBox( + nullptr, + m_TrackingPreventionEnabled ? L"Tracking prevention will be enabled for new WebView " + L"created after all webviews are closed." + : L"Tracking prevention will be disabled for new WebView " + L"created after all webviews are closed.", + L"Tracking Prevention", MB_OK); +} + +//! [ShowPrintUI] +// Shows the user a print dialog. If `printDialogKind` is +// COREWEBVIEW2_PRINT_DIALOG_KIND_BROWSER, opens a browser print preview dialog, +// COREWEBVIEW2_PRINT_DIALOG_KIND_SYSTEM opens a system print dialog. +bool AppWindow::ShowPrintUI(COREWEBVIEW2_PRINT_DIALOG_KIND printDialogKind) +{ + auto webView2_16 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_16); + CHECK_FAILURE(webView2_16->ShowPrintUI(printDialogKind)); + return true; +} +//! [ShowPrintUI] + +// This example prints the current web page without a print dialog to default printer +// with the default print settings. +bool AppWindow::PrintToDefaultPrinter() +{ + wil::com_ptr webView2_16; + CHECK_FAILURE(m_webView->QueryInterface(IID_PPV_ARGS(&webView2_16))); + + wil::unique_cotaskmem_string title; + CHECK_FAILURE(m_webView->get_DocumentTitle(&title)); + + // Passing nullptr for `ICoreWebView2PrintSettings` results in default print settings used. + // Prints current web page with the default page and printer settings. + CHECK_FAILURE(webView2_16->Print( + nullptr, Callback( + [title = std::move(title), + this](HRESULT errorCode, COREWEBVIEW2_PRINT_STATUS printStatus) -> HRESULT + { + std::wstring message = L""; + if (errorCode == S_OK && + printStatus == COREWEBVIEW2_PRINT_STATUS_SUCCEEDED) + { + message = L"Printing " + std::wstring(title.get()) + + L" document to printer is succeeded"; + } + else if ( + errorCode == S_OK && + printStatus == COREWEBVIEW2_PRINT_STATUS_PRINTER_UNAVAILABLE) + { + message = L"Printer is not available, offline or error state"; + } + else if (errorCode == E_ABORT) + { + message = L"Printing " + std::wstring(title.get()) + + L" document is in progress"; + } + else + { + message = L"Printing " + std::wstring(title.get()) + + L" document to printer is failed"; + } + + AsyncMessageBox(message, L"Print to default printer"); + + return S_OK; + }) + .Get())); + return true; +} + +// Function to get printer name by displaying printer text input dialog to the user. +// User has to specify the desired printer name by querying the installed printers list on the +// OS to print the web page. You may also choose to display printers list to the user and return +// user selected printer. +std::wstring AppWindow::GetPrinterName() +{ + std::wstring printerName; + + TextInputDialog dialog( + GetMainWindow(), L"Printer Name", L"Printer Name:", + L"Specify a printer name from the installed printers list on the OS.", L""); + + if (dialog.confirmed) + { + printerName = (dialog.input).c_str(); + } + return printerName; + + // or + // + // Use win32 EnumPrinters function to get locally installed printers. + // Display the printer list to the user and get the user desired printer to print. + // Return the user selected printer name. +} + +// Function to get print settings for the selected printer. +// You may also choose get the capabilties from the native printer API, display to the user to +// get the print settings for the current web page and for the selected printer. +SamplePrintSettings AppWindow::GetSelectedPrinterPrintSettings(std::wstring printerName) +{ + SamplePrintSettings samplePrintSettings; + samplePrintSettings.PrintBackgrounds = true; + samplePrintSettings.HeaderAndFooter = true; + + return samplePrintSettings; + + // or + // + // Use win32 DeviceCapabilitiesA function to get the capabilities of the selected printer. + // Display the printer capabilities to the user along with the page settings. + // Return the user selected settings. +} + +//! [PrintToPrinter] +// This example prints the current web page to a specified printer with the settings. +bool AppWindow::PrintToPrinter() +{ + std::wstring printerName = GetPrinterName(); + // Host apps custom print settings based on the user selection. + SamplePrintSettings samplePrintSettings = GetSelectedPrinterPrintSettings(printerName); + + wil::com_ptr webView2_16; + CHECK_FAILURE(m_webView->QueryInterface(IID_PPV_ARGS(&webView2_16))); + + wil::com_ptr webviewEnvironment6; + CHECK_FAILURE(m_webViewEnvironment->QueryInterface(IID_PPV_ARGS(&webviewEnvironment6))); + + wil::com_ptr printSettings; + CHECK_FAILURE(webviewEnvironment6->CreatePrintSettings(&printSettings)); + + wil::com_ptr printSettings2; + CHECK_FAILURE(printSettings->QueryInterface(IID_PPV_ARGS(&printSettings2))); + + CHECK_FAILURE(printSettings->put_Orientation(samplePrintSettings.Orientation)); + CHECK_FAILURE(printSettings2->put_Copies(samplePrintSettings.Copies)); + CHECK_FAILURE(printSettings2->put_PagesPerSide(samplePrintSettings.PagesPerSide)); + CHECK_FAILURE(printSettings2->put_PageRanges(samplePrintSettings.Pages.c_str())); + if (samplePrintSettings.Media == COREWEBVIEW2_PRINT_MEDIA_SIZE_CUSTOM) + { + CHECK_FAILURE(printSettings->put_PageWidth(samplePrintSettings.PaperWidth)); + CHECK_FAILURE(printSettings->put_PageHeight(samplePrintSettings.PaperHeight)); + } + CHECK_FAILURE(printSettings2->put_ColorMode(samplePrintSettings.ColorMode)); + CHECK_FAILURE(printSettings2->put_Collation(samplePrintSettings.Collation)); + CHECK_FAILURE(printSettings2->put_Duplex(samplePrintSettings.Duplex)); + CHECK_FAILURE(printSettings->put_ScaleFactor(samplePrintSettings.ScaleFactor)); + CHECK_FAILURE( + printSettings->put_ShouldPrintBackgrounds(samplePrintSettings.PrintBackgrounds)); + CHECK_FAILURE( + printSettings->put_ShouldPrintBackgrounds(samplePrintSettings.PrintBackgrounds)); + CHECK_FAILURE( + printSettings->put_ShouldPrintHeaderAndFooter(samplePrintSettings.HeaderAndFooter)); + CHECK_FAILURE(printSettings->put_HeaderTitle(samplePrintSettings.HeaderTitle.c_str())); + CHECK_FAILURE(printSettings->put_FooterUri(samplePrintSettings.FooterUri.c_str())); + CHECK_FAILURE(printSettings2->put_PrinterName(printerName.c_str())); + + wil::unique_cotaskmem_string title; + CHECK_FAILURE(m_webView->get_DocumentTitle(&title)); + + CHECK_FAILURE(webView2_16->Print( + printSettings.get(), + Callback( + [title = std::move(title), + this](HRESULT errorCode, COREWEBVIEW2_PRINT_STATUS printStatus) -> HRESULT + { + std::wstring message = L""; + if (errorCode == S_OK && printStatus == COREWEBVIEW2_PRINT_STATUS_SUCCEEDED) + { + message = L"Printing " + std::wstring(title.get()) + + L" document to printer is succeeded"; + } + else if ( + errorCode == S_OK && + printStatus == COREWEBVIEW2_PRINT_STATUS_PRINTER_UNAVAILABLE) + { + message = L"Selected printer is not found, not available, offline or " + L"error state."; + } + else if (errorCode == E_INVALIDARG) + { + message = L"Invalid settings provided for the specified printer"; + } + else if (errorCode == E_ABORT) + { + message = L"Printing " + std::wstring(title.get()) + + L" document already in progress"; + } + else + { + message = L"Printing " + std::wstring(title.get()) + + L" document to printer is failed"; + } + + AsyncMessageBox(message, L"Print to printer"); + + return S_OK; + }) + .Get())); + return true; +} +//! [PrintToPrinter] + +// Function to display current web page pdf data in a custom print preview dialog. +static void DisplayPdfDataInPrintDialog(IStream* pdfData) +{ + // You can display the printable pdf data in a custom print preview dialog to the end user. +} + +//! [PrintToPdfStream] +// This example prints the Pdf data of the current page to a stream. +bool AppWindow::PrintToPdfStream() +{ + wil::com_ptr webView2_16; + CHECK_FAILURE(m_webView->QueryInterface(IID_PPV_ARGS(&webView2_16))); + + wil::unique_cotaskmem_string title; + CHECK_FAILURE(m_webView->get_DocumentTitle(&title)); + + // Passing nullptr for `ICoreWebView2PrintSettings` results in default print settings used. + CHECK_FAILURE(webView2_16->PrintToPdfStream( + nullptr, + Callback( + [title = std::move(title), this](HRESULT errorCode, IStream* pdfData) -> HRESULT + { + DisplayPdfDataInPrintDialog(pdfData); + + std::wstring message = + L"Printing " + std::wstring(title.get()) + L" document to PDF Stream " + + ((errorCode == S_OK && pdfData != nullptr) ? L"succedded" : L"failed"); + + AsyncMessageBox(message, L"Print to PDF Stream"); + + return S_OK; + }) + .Get())); + return true; +} +//! [PrintToPdfStream] + +//! [Start] +bool AppWindow::Start(const std::wstring& searchTerm) +{ + auto webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); + SetupFindEventHandlers(webView2find); + + // Initialize find configuration/settings + if (!findOptions) + { + findOptions = SetDefaultFindOptions(); + } + + // Check if the search term has changed to determine if UI needs to be updated + if (m_findOnPageLastSearchTerm != searchTerm) + { + m_findOnPageLastSearchTerm = + searchTerm; // Update the last search term for future comparisons + } + + // Start the find operation + CHECK_FAILURE(webView2find->Start( + findOptions.get(), Callback( + [this](HRESULT result) -> HRESULT { return S_OK; }) + .Get())); + return true; +} +//! [Start] + +//! [FindNext] +bool AppWindow::FindNext() +{ + auto webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); + CHECK_FAILURE(webView2find->FindNext()); + + return true; +} +//! [FindNext] + +//! [FindPrevious] +bool AppWindow::FindPrevious() +{ + auto webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); + + CHECK_FAILURE(webView2find->FindPrevious()); + + return true; +} +//! [FindPrevious] + +//! [Stop] +bool AppWindow::StopFind() +{ + auto webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); + // Note, I am not 100% sure if this is the best way to remove the event handlers + // Because it would rely on the user clicking stopfind. Maybe put in destructor or when + // startfind completes? + CHECK_FAILURE(webView2find->remove_MatchCountChanged(m_matchCountChangedToken)); + CHECK_FAILURE(webView2find->remove_ActiveMatchIndexChanged(m_activeMatchIndexChangedToken)); + CHECK_FAILURE(webView2find->Stop()); + return true; +} +//! [Stop] + +//! [MatchCount] +bool AppWindow::GetMatchCount() +{ + auto webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); + int32_t matchCount; + CHECK_FAILURE(webView2find->get_MatchCount(&matchCount)); + + std::wstring matchCountStr = L"Match Count: " + std::to_wstring(matchCount); + MessageBox(m_mainWindow, matchCountStr.c_str(), L"Find Operation", MB_OK); + + return true; +} +//! [MatchCount] + +//! [ActiveMatchIndex] +bool AppWindow::GetActiveMatchIndex() +{ + auto webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); + int32_t activeMatchIndex; + CHECK_FAILURE(webView2find->get_ActiveMatchIndex(&activeMatchIndex)); + + std::wstring activeMatchIndexStr = + L"Active Match Index: " + std::to_wstring(activeMatchIndex); + MessageBox(m_mainWindow, activeMatchIndexStr.c_str(), L"Find Operation", MB_OK); + + return true; +} +//! [ActiveMatchIndex] + +//! [IsCaseSensitive] +bool AppWindow::IsCaseSensitive() +{ + auto webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); + + auto m_env15 = m_webViewEnvironment.try_query(); + CHECK_FEATURE_RETURN(m_env15); + CHECK_FAILURE(webView2find->Stop()); + + if (!findOptions) + { + findOptions = SetDefaultFindOptions(); } - return false; + BOOL caseSensitive; + findOptions->get_IsCaseSensitive(&caseSensitive); + CHECK_FAILURE(findOptions->put_IsCaseSensitive(!caseSensitive)); + + CHECK_FAILURE(webView2find->Start( + findOptions.get(), Callback( + [this](HRESULT result) -> HRESULT { return S_OK; }) + .Get())); + return true; } -//! [ClearBrowsingData] -bool AppWindow::ClearBrowsingData(COREWEBVIEW2_BROWSING_DATA_KINDS dataKinds) +//! [IsCaseSensitive] + +//! [ShouldHighlightAllMatches] +bool AppWindow::ShouldHighlightAllMatches() { - auto webView2Experimental8 = - m_webView.try_query(); - CHECK_FEATURE_RETURN(webView2Experimental8); - wil::com_ptr webView2ExperimentalProfile; - CHECK_FAILURE(webView2Experimental8->get_Profile(&webView2ExperimentalProfile)); - CHECK_FEATURE_RETURN(webView2ExperimentalProfile); - auto webView2ExperimentalProfile4 = webView2ExperimentalProfile.try_query(); - CHECK_FEATURE_RETURN(webView2ExperimentalProfile4); - // Clear the browsing data from the last hour. - double endTime = (double)std::time(nullptr); - double startTime = endTime - 3600.0; - CHECK_FAILURE(webView2ExperimentalProfile4->ClearBrowsingDataInTimeRange( - dataKinds, startTime, endTime, - Callback( - [this](HRESULT error) - -> HRESULT { - RunAsync([this]() { - MessageBox(nullptr, L"Completed", L"Clear Browsing Data", MB_OK); - }); - return S_OK; - }) - .Get())); + auto webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); + + auto m_env15 = m_webViewEnvironment.try_query(); + CHECK_FEATURE_RETURN(m_env15); + CHECK_FAILURE(webView2find->Stop()); + + if (!findOptions) + { + findOptions = SetDefaultFindOptions(); + } + BOOL shouldHighlightAllMatches; + CHECK_FAILURE(findOptions->get_ShouldHighlightAllMatches(&shouldHighlightAllMatches)); + CHECK_FAILURE(findOptions->put_ShouldHighlightAllMatches(!shouldHighlightAllMatches)); + CHECK_FAILURE(webView2find->Start( + findOptions.get(), Callback( + [this](HRESULT result) -> HRESULT { return S_OK; }) + .Get())); return true; } -//! [ClearBrowsingData] +//! [ShouldHighlightAllMatches] -// Prompt the user for a new language string -void AppWindow::ChangeLanguage() +//! [ShouldMatchWord] +bool AppWindow::ShouldMatchWord() +{ + auto webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); + + auto m_env15 = m_webViewEnvironment.try_query(); + CHECK_FEATURE_RETURN(m_env15); + CHECK_FAILURE(webView2find->Stop()); + + if (!findOptions) + { + findOptions = SetDefaultFindOptions(); + } + BOOL shouldMatchWord; + findOptions->get_ShouldMatchWord(&shouldMatchWord); + CHECK_FAILURE(findOptions->put_ShouldMatchWord(!shouldMatchWord)); + CHECK_FAILURE(webView2find->Start( + findOptions.get(), Callback( + [this](HRESULT result) -> HRESULT { return S_OK; }) + .Get())); + return true; +} +//! [ShouldMatchWord] + +//! [SuppressDefaultFindDialog] +bool AppWindow::SuppressDefaultFindDialog() { + auto webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); + + auto m_env15 = m_webViewEnvironment.try_query(); + CHECK_FEATURE_RETURN(m_env15); + CHECK_FAILURE(webView2find->Stop()); + + if (!findOptions) + { + findOptions = SetDefaultFindOptions(); + } + BOOL suppressDefaultDialog; + findOptions->get_SuppressDefaultFindDialog(&suppressDefaultDialog); + CHECK_FAILURE(findOptions->put_SuppressDefaultFindDialog(!suppressDefaultDialog)); + CHECK_FAILURE(webView2find->Stop()); + CHECK_FAILURE(webView2find->Start( + findOptions.get(), Callback( + [this](HRESULT result) -> HRESULT { return S_OK; }) + .Get())); + return true; +} +//! [SuppressDefaultFindDialog] + +//! [FindTerm] +bool AppWindow::FindTerm() +{ + auto webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); + TextInputDialog dialog( - GetMainWindow(), L"Language", L"Language:", - L"Enter a language to use for WebView, or leave blank to restore default.", - m_language.empty() ? L"zh-cn" : m_language.c_str()); - if (dialog.confirmed) + GetMainWindow(), L"Find on Page Term", L"Find on Page Term:", L"Enter Find Term"); + + auto m_env15 = m_webViewEnvironment.try_query(); + CHECK_FEATURE_RETURN(m_env15); + CHECK_FAILURE(webView2find->Stop()); + + if (!findOptions) { - m_language = (dialog.input); + findOptions = SetDefaultFindOptions(); } + CHECK_FAILURE(findOptions->put_FindTerm(dialog.input.c_str())); + CHECK_FAILURE(webView2find->Start( + findOptions.get(), Callback( + [this](HRESULT result) -> HRESULT { return S_OK; }) + .Get())); + return true; } +//! [FindTerm] -// Toggle AAD SSO enabled -void AppWindow::ToggleAADSSO() +wil::com_ptr AppWindow::SetDefaultFindOptions() { - m_AADSSOEnabled = !m_AADSSOEnabled; - MessageBox( - nullptr, - m_AADSSOEnabled ? L"AAD single sign on will be enabled for new WebView " - L"created after all webviews are closed." : - L"AAD single sign on will be disabled for new WebView" - L" created after all webviews are closed.", - L"AAD SSO change", - MB_OK); + auto m_env15 = m_webViewEnvironment.try_query(); + + // Initialize find configuration/settings + wil::com_ptr findOptions; + CHECK_FAILURE(m_env15->CreateFindOptions(&findOptions)); + CHECK_FAILURE(findOptions->put_FindTerm(L"Webview2")); + CHECK_FAILURE(findOptions->put_IsCaseSensitive(false)); + CHECK_FAILURE(findOptions->put_ShouldMatchWord(false)); + CHECK_FAILURE(findOptions->put_SuppressDefaultFindDialog(false)); + CHECK_FAILURE(findOptions->put_ShouldHighlightAllMatches(true)); + + return findOptions; } -void AppWindow::ToggleExclusiveUserDataFolderAccess() +void AppWindow::SetupFindEventHandlers(wil::com_ptr webView2find) { - m_ExclusiveUserDataFolderAccess = !m_ExclusiveUserDataFolderAccess; - MessageBox( - nullptr, - m_ExclusiveUserDataFolderAccess ? - L"Will request exclusive access to user data folder " - L"for new WebView created after all webviews are closed." : - L"Will not request exclusive access to user data folder " - L"for new WebView created after all webviews are closed.", - L"Exclusive User Data Folder Access change", MB_OK); + CHECK_FAILURE(webView2find->add_MatchCountChanged( + Callback( + [this](ICoreWebView2Find* sender, IUnknown* args) -> HRESULT + { + int matchCount = 0; + if (sender) + { + CHECK_FAILURE(sender->get_MatchCount(&matchCount)); + } + return S_OK; + }) + .Get(), + &m_matchCountChangedToken)); + + CHECK_FAILURE(webView2find->add_ActiveMatchIndexChanged( + Callback( + [this](ICoreWebView2Find* sender, IUnknown* args) -> HRESULT + { + int activeIndex = -1; + if (sender) + { + CHECK_FAILURE(sender->get_ActiveMatchIndex(&activeIndex)); + } + return S_OK; + }) + .Get(), + &m_activeMatchIndexChangedToken)); } // Message handler for about dialog. @@ -815,7 +1735,8 @@ std::function AppWindow::GetAcceleratorKeyFunction(UINT key) case 'Q': return [this] { CloseAppWindow(); }; case 'S': - return [this] { + return [this] + { if (auto file = GetComponent()) { file->SaveScreenshot(); @@ -827,6 +1748,14 @@ std::function AppWindow::GetAcceleratorKeyFunction(UINT key) return [this] { CloseWebView(); }; } } + if (GetKeyState(VK_MENU) < 0) // VK_MENU == Alt key + { + switch (key) + { + case 'D': // Alt+D focuses and selects the address bar, like the browser. + return [this] { m_toolbar.SelectAddressBar(); }; + } + } return nullptr; } @@ -839,9 +1768,7 @@ void AppWindow::InitializeWebView() // getting created which will apply the browser switches. CloseWebView(); m_dcompDevice = nullptr; -#ifdef USE_WEBVIEW2_WIN10 m_wincompCompositor = nullptr; -#endif LPCWSTR subFolder = nullptr; if (m_creationModeId == IDM_CREATION_MODE_VISUAL_DCOMP || @@ -859,7 +1786,6 @@ void AppWindow::InitializeWebView() return; } } -#ifdef USE_WEBVIEW2_WIN10 else if (m_creationModeId == IDM_CREATION_MODE_VISUAL_WINCOMP) { HRESULT hr = TryCreateDispatcherQueue(); @@ -875,16 +1801,88 @@ void AppWindow::InitializeWebView() } m_wincompCompositor = winrtComp::Compositor(); } -#endif //! [CreateCoreWebView2EnvironmentWithOptions] + + std::wstring args; + // Page Interaction Restriction Manager requires msPageInteractionManagerWebview2 to be + // enabled from the args, as by default it's disabled in the browser. If you want to + // test these scenarios, this flag should be enabled. + args.append( + L"--enable-features=ThirdPartyStoragePartitioning,PartitionedCookies," + L"msPageInteractionManagerWebview2"); auto options = Microsoft::WRL::Make(); + options->put_AdditionalBrowserArguments(args.c_str()); CHECK_FAILURE( - options->put_AllowSingleSignOnUsingOSPrimaryAccount( - m_AADSSOEnabled ? TRUE : FALSE)); + options->put_AllowSingleSignOnUsingOSPrimaryAccount(m_AADSSOEnabled ? TRUE : FALSE)); CHECK_FAILURE(options->put_ExclusiveUserDataFolderAccess( m_ExclusiveUserDataFolderAccess ? TRUE : FALSE)); if (!m_language.empty()) CHECK_FAILURE(options->put_Language(m_language.c_str())); + CHECK_FAILURE(options->put_IsCustomCrashReportingEnabled( + m_CustomCrashReportingEnabled ? TRUE : FALSE)); + + //! [CoreWebView2CustomSchemeRegistration] + Microsoft::WRL::ComPtr options4; + if (options.As(&options4) == S_OK) + { + const WCHAR* allowedOrigins[1] = {L"https://*.example.com"}; + + auto customSchemeRegistration = + Microsoft::WRL::Make(L"custom-scheme"); + customSchemeRegistration->SetAllowedOrigins(1, allowedOrigins); + auto customSchemeRegistration2 = + Microsoft::WRL::Make(L"wv2rocks"); + customSchemeRegistration2->put_TreatAsSecure(TRUE); + customSchemeRegistration2->SetAllowedOrigins(1, allowedOrigins); + customSchemeRegistration2->put_HasAuthorityComponent(TRUE); + auto customSchemeRegistration3 = + Microsoft::WRL::Make( + L"custom-scheme-not-in-allowed-origins"); + ICoreWebView2CustomSchemeRegistration* registrations[3] = { + customSchemeRegistration.Get(), customSchemeRegistration2.Get(), + customSchemeRegistration3.Get()}; + options4->SetCustomSchemeRegistrations( + 2, static_cast(registrations)); + } + //! [CoreWebView2CustomSchemeRegistration] + + Microsoft::WRL::ComPtr options5; + if (options.As(&options5) == S_OK) + { + CHECK_FAILURE( + options5->put_EnableTrackingPrevention(m_TrackingPreventionEnabled ? TRUE : FALSE)); + } + + Microsoft::WRL::ComPtr options6; + if (options.As(&options6) == S_OK) + { + CHECK_FAILURE(options6->put_AreBrowserExtensionsEnabled(TRUE)); + } + + Microsoft::WRL::ComPtr options8; + if (options.As(&options8) == S_OK) + { + COREWEBVIEW2_SCROLLBAR_STYLE style = COREWEBVIEW2_SCROLLBAR_STYLE_FLUENT_OVERLAY; + CHECK_FAILURE(options8->put_ScrollBarStyle(style)); + } + + Microsoft::WRL::ComPtr optionsExperimental; + if (options.As(&optionsExperimental) == S_OK) + { + // Configure port ranges for WebRTC UDP traffic to work within enterprise firewalls + // Set UDP port range (example: 50000-55000 for enterprise environments) + const INT32 udpMin = 50000, udpMax = 55000; + + CHECK_FAILURE(optionsExperimental->SetAllowedPortRange( + COREWEBVIEW2_ALLOWED_PORT_RANGE_SCOPE_WEB_RTC, + COREWEBVIEW2_TRANSPORT_PROTOCOL_KIND_UDP, udpMin, udpMax)); + + // Get the configured port range + CHECK_FAILURE(optionsExperimental->GetEffectiveAllowedPortRange( + COREWEBVIEW2_ALLOWED_PORT_RANGE_SCOPE_WEB_RTC, + COREWEBVIEW2_TRANSPORT_PROTOCOL_KIND_UDP, &m_udpPortRange.minPort, + &m_udpPortRange.maxPort)); + } HRESULT hr = CreateCoreWebView2EnvironmentWithOptions( subFolder, m_userDataFolder.c_str(), options.Get(), @@ -896,38 +1894,40 @@ void AppWindow::InitializeWebView() { switch (hr) { - case HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND): - { - MessageBox( - m_mainWindow, - L"Couldn't find Edge WebView2 Runtime. " - "Do you have a version installed?", - nullptr, MB_OK); - } - break; - case HRESULT_FROM_WIN32(ERROR_FILE_EXISTS): - { - MessageBox( - m_mainWindow, L"User data folder cannot be created because a file with the same name already exists.", nullptr, MB_OK); - } - break; - case E_ACCESSDENIED: - { - MessageBox( - m_mainWindow, L"Unable to create user data folder, Access Denied.", nullptr, MB_OK); - } - break; - case E_FAIL: - { - MessageBox( - m_mainWindow, L"Edge runtime unable to start", nullptr, MB_OK); - } - break; - default: - { - ShowFailure( - hr, L"Failed to create WebView2 environment"); - } + case HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND): + { + MessageBox( + m_mainWindow, + L"Couldn't find Edge WebView2 Runtime. " + "Do you have a version installed?", + nullptr, MB_OK); + } + break; + case HRESULT_FROM_WIN32(ERROR_FILE_EXISTS): + { + MessageBox( + m_mainWindow, + L"User data folder cannot be created because a file with the same name already " + L"exists.", + nullptr, MB_OK); + } + break; + case E_ACCESSDENIED: + { + MessageBox( + m_mainWindow, L"Unable to create user data folder, Access Denied.", nullptr, + MB_OK); + } + break; + case E_FAIL: + { + MessageBox(m_mainWindow, L"Edge runtime unable to start", nullptr, MB_OK); + } + break; + default: + { + ShowFailure(hr, L"Failed to create WebView2 environment"); + } } } } @@ -936,29 +1936,30 @@ void AppWindow::InitializeWebView() HRESULT AppWindow::OnCreateEnvironmentCompleted( HRESULT result, ICoreWebView2Environment* environment) { - CHECK_FAILURE(result); + if (result != S_OK) + { + ShowFailure(result, L"Failed to create environment object."); + return S_OK; + } m_webViewEnvironment = environment; - if (m_webviewOption.entry == WebViewCreateEntry::EVER_FROM_CREATE_WITH_OPTION_MENU) + if (m_webviewOption.entry == WebViewCreateEntry::EVER_FROM_CREATE_WITH_OPTION_MENU || + m_creationModeId == IDM_CREATION_MODE_HOST_INPUT_PROCESSING + ) { return CreateControllerWithOptions(); } + auto webViewEnvironment3 = m_webViewEnvironment.try_query(); - auto webViewEnvironment3 = - m_webViewEnvironment.try_query(); -#ifdef USE_WEBVIEW2_WIN10 if (webViewEnvironment3 && (m_dcompDevice || m_wincompCompositor)) -#else - if (webViewEnvironment3 && m_dcompDevice) -#endif { CHECK_FAILURE(webViewEnvironment3->CreateCoreWebView2CompositionController( m_mainWindow, - Callback< - ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler>( + Callback( [this]( HRESULT result, - ICoreWebView2CompositionController* compositionController) -> HRESULT { + ICoreWebView2CompositionController* compositionController) -> HRESULT + { auto controller = wil::com_ptr(compositionController) .query(); @@ -981,17 +1982,16 @@ HRESULT AppWindow::OnCreateEnvironmentCompleted( HRESULT AppWindow::CreateControllerWithOptions() { //! [CreateControllerWithOptions] - auto webViewEnvironment8 = - m_webViewEnvironment.try_query(); - if (!webViewEnvironment8) + auto webViewEnvironment10 = m_webViewEnvironment.try_query(); + if (!webViewEnvironment10) { FeatureNotAvailable(); return S_OK; } - Microsoft::WRL::ComPtr options; - HRESULT hr = webViewEnvironment8->CreateCoreWebView2ControllerOptions( - m_webviewOption.profile.c_str(), m_webviewOption.isInPrivate, options.GetAddressOf()); + wil::com_ptr options; + // The validation of parameters occurs when setting the properties. + HRESULT hr = webViewEnvironment10->CreateCoreWebView2ControllerOptions(&options); if (hr == E_INVALIDARG) { ShowFailure(hr, L"Unable to create WebView2 due to an invalid profile name."); @@ -1001,29 +2001,74 @@ HRESULT AppWindow::CreateControllerWithOptions() CHECK_FAILURE(hr); //! [CreateControllerWithOptions] -#ifdef USE_WEBVIEW2_WIN10 + // If call 'put_ProfileName' with an invalid profile name, the 'E_INVALIDARG' returned + // immediately. ProfileName could be reused. + CHECK_FAILURE(options->put_ProfileName(m_webviewOption.profile.c_str())); + CHECK_FAILURE(options->put_IsInPrivateModeEnabled(m_webviewOption.isInPrivate)); + + //! [ScriptLocaleSetting] + wil::com_ptr webView2ControllerOptions2; + if (SUCCEEDED(options->QueryInterface(IID_PPV_ARGS(&webView2ControllerOptions2)))) + { + if (m_webviewOption.useOSRegion) + { + wchar_t osLocale[LOCALE_NAME_MAX_LENGTH] = {0}; + GetUserDefaultLocaleName(osLocale, LOCALE_NAME_MAX_LENGTH); + CHECK_FAILURE(webView2ControllerOptions2->put_ScriptLocale(osLocale)); + } + else if (!m_webviewOption.scriptLocale.empty()) + { + CHECK_FAILURE(webView2ControllerOptions2->put_ScriptLocale( + m_webviewOption.scriptLocale.c_str())); + } + } + //! [ScriptLocaleSetting] + + //! [AllowHostInputProcessing] + if (m_creationModeId == IDM_CREATION_MODE_HOST_INPUT_PROCESSING) + { + wil::com_ptr webView2ControllerOptions4; + if (SUCCEEDED(options->QueryInterface(IID_PPV_ARGS(&webView2ControllerOptions4)))) + { + CHECK_FAILURE(webView2ControllerOptions4->put_AllowHostInputProcessing(TRUE)); + } + } + //! [AllowHostInputProcessing] + + //! [DefaultBackgroundColor] + if (m_webviewOption.bg_color) + { + wil::com_ptr webView2ControllerOptions3; + if (SUCCEEDED(options->QueryInterface(IID_PPV_ARGS(&webView2ControllerOptions3)))) + { + CHECK_FAILURE( + webView2ControllerOptions3->put_DefaultBackgroundColor(*m_webviewOption.bg_color)); + } + } + //! [DefaultBackgroundColor] + if (m_dcompDevice || m_wincompCompositor) -#else - if (m_dcompDevice) -#endif { - CHECK_FAILURE(webViewEnvironment8->CreateCoreWebView2CompositionControllerWithOptions( - m_mainWindow, options.Get(), + //! [OnCreateCoreWebView2ControllerCompleted] + CHECK_FAILURE(webViewEnvironment10->CreateCoreWebView2CompositionControllerWithOptions( + m_mainWindow, options.get(), Callback( [this]( HRESULT result, - ICoreWebView2CompositionController* compositionController) -> HRESULT { + ICoreWebView2CompositionController* compositionController) -> HRESULT + { auto controller = wil::com_ptr(compositionController) .query(); return OnCreateCoreWebView2ControllerCompleted(result, controller.get()); }) .Get())); + //! [OnCreateCoreWebView2ControllerCompleted] } else { - CHECK_FAILURE(webViewEnvironment8->CreateCoreWebView2ControllerWithOptions( - m_mainWindow, options.Get(), + CHECK_FAILURE(webViewEnvironment10->CreateCoreWebView2ControllerWithOptions( + m_mainWindow, options.get(), Callback( this, &AppWindow::OnCreateCoreWebView2ControllerCompleted) .Get())); @@ -1034,35 +2079,23 @@ HRESULT AppWindow::CreateControllerWithOptions() void AppWindow::SetAppIcon(bool inPrivate) { - HICON newSmallIcon = nullptr; - HICON newBigIcon = nullptr; - if (inPrivate) - { - static HICON smallInPrivateIcon = reinterpret_cast(LoadImage( - g_hInstance, MAKEINTRESOURCEW(IDI_WEBVIEW2APISAMPLE_INPRIVATE), IMAGE_ICON, 16, 16, - LR_DEFAULTCOLOR)); - static HICON bigInPrivateIcon = reinterpret_cast(LoadImage( - g_hInstance, MAKEINTRESOURCEW(IDI_WEBVIEW2APISAMPLE_INPRIVATE), IMAGE_ICON, 32, 32, - LR_DEFAULTCOLOR)); - newSmallIcon = smallInPrivateIcon; - newBigIcon = bigInPrivateIcon; - } - else - { - static HICON smallIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_WEBVIEW2APISAMPLE)); - static HICON bigIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SMALL)); - newSmallIcon = smallIcon; - newBigIcon = bigIcon; - } + int iconID = inPrivate ? IDI_WEBVIEW2APISAMPLE_INPRIVATE : IDI_WEBVIEW2APISAMPLE; + + HICON newSmallIcon = reinterpret_cast( + LoadImage(g_hInstance, MAKEINTRESOURCEW(iconID), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR)); + HICON newBigIcon = reinterpret_cast( + LoadImage(g_hInstance, MAKEINTRESOURCEW(iconID), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR)); + reinterpret_cast(SendMessage( m_mainWindow, WM_SETICON, ICON_SMALL, reinterpret_cast(newSmallIcon))); reinterpret_cast( SendMessage(m_mainWindow, WM_SETICON, ICON_BIG, reinterpret_cast(newBigIcon))); } -// This is the callback passed to CreateCoreWebView2Controller. Here we initialize all WebView-related -// state and register most of our event handlers with the WebView. -HRESULT AppWindow::OnCreateCoreWebView2ControllerCompleted(HRESULT result, ICoreWebView2Controller* controller) +// This is the callback passed to CreateCoreWebView2Controller. Here we initialize all +// WebView-related state and register most of our event handlers with the WebView. +HRESULT AppWindow::OnCreateCoreWebView2ControllerCompleted( + HRESULT result, ICoreWebView2Controller* controller) { if (result == S_OK) { @@ -1081,33 +2114,43 @@ HRESULT AppWindow::OnCreateCoreWebView2ControllerCompleted(HRESULT result, ICore // available. CHECK_FAILURE(m_webView->get_BrowserProcessId(&m_newestBrowserPid)); //! [CoreWebView2Profile] - auto webview2Experimental8 = coreWebView2.try_query(); - if (webview2Experimental8) + auto webView2_13 = coreWebView2.try_query(); + if (webView2_13) { - wil::com_ptr profile; - CHECK_FAILURE(webview2Experimental8->get_Profile(&profile)); - wil::unique_cotaskmem_string profile_path; - CHECK_FAILURE(profile->get_ProfilePath(&profile_path)); - std::wstring str(profile_path.get()); - m_profileDirName = str.substr(str.find_last_of(L'\\') + 1); + wil::com_ptr profile; + CHECK_FAILURE(webView2_13->get_Profile(&profile)); + wil::unique_cotaskmem_string profile_name; + CHECK_FAILURE(profile->get_ProfileName(&profile_name)); + m_profileName = profile_name.get(); BOOL inPrivate = FALSE; CHECK_FAILURE(profile->get_IsInPrivateModeEnabled(&inPrivate)); if (!m_webviewOption.downloadPath.empty()) { - auto webView2ExperimentalProfile3 = - profile.try_query(); - CHECK_FAILURE(webView2ExperimentalProfile3-> - put_DefaultDownloadFolderPath( - m_webviewOption.downloadPath.c_str())); + CHECK_FAILURE(profile->put_DefaultDownloadFolderPath( + m_webviewOption.downloadPath.c_str())); } - // update window title with m_profileDirName + // update window title with m_profileName UpdateAppTitle(); // update window icon SetAppIcon(inPrivate); } //! [CoreWebView2Profile] + //! [WindowControlsOverlay] + if (m_webviewOption.useWco) + { + auto webview2Experimental31 = m_webView.try_query(); + if (webview2Experimental31) + { + wil::com_ptr wco; + CHECK_FAILURE(webview2Experimental31->get_WindowControlsOverlay(&wco)); + CHECK_FAILURE(wco->put_IsEnabled(true)); + CHECK_FAILURE(wco->put_Height(48)); + CHECK_FAILURE(wco->put_BackgroundColor({0, 0, 0, 0})); + } + } + //! [WindowControlsOverlay] // Create components. These will be deleted when the WebView is closed. NewComponent(this); NewComponent(this); @@ -1116,10 +2159,7 @@ HRESULT AppWindow::OnCreateCoreWebView2ControllerCompleted(HRESULT result, ICore this, m_webViewEnvironment.get(), m_oldSettingsComponent.get()); m_oldSettingsComponent = nullptr; NewComponent( - this, m_dcompDevice.get(), -#ifdef USE_WEBVIEW2_WIN10 - m_wincompCompositor, -#endif + this, m_dcompDevice.get(), m_wincompCompositor, m_creationModeId == IDM_CREATION_MODE_TARGET_DCOMP); NewComponent(this); NewComponent(this, &m_toolbar); @@ -1134,6 +2174,9 @@ HRESULT AppWindow::OnCreateCoreWebView2ControllerCompleted(HRESULT result, ICore COREWEBVIEW2_HOST_RESOURCE_ACCESS_KIND_DENY_CORS); //! [AddVirtualHostNameToFolderMapping] } + NewComponent(this); + NewComponent(this); + NewComponent(this); // We have a few of our own event handlers to register here as well RegisterEventHandlers(); @@ -1149,10 +2192,29 @@ HRESULT AppWindow::OnCreateCoreWebView2ControllerCompleted(HRESULT result, ICore if (m_initialUri != L"none") { - std::wstring initialUri = m_initialUri.empty() ? AppStartPage::GetUri(this) : m_initialUri; + std::wstring initialUri = + m_initialUri.empty() ? AppStartPage::GetUri(this) : m_initialUri; CHECK_FAILURE(m_webView->Navigate(initialUri.c_str())); } } + else if (result == E_ABORT) + { + // Webview creation was aborted because the user closed this window. + // No need to report this as an error. + } + else if (result == HRESULT_FROM_WIN32(ERROR_DELETE_PENDING)) + { + RunAsync( + [this, result]() + { + ShowFailure( + result, + L"Failed to create webview, because the profile's name has been marked as " + L"deleted, please use a different profile's name"); + m_webviewOption.PopupDialog(this); + CloseAppWindow(); + }); + } else { ShowFailure(result, L"Failed to create webview"); @@ -1235,7 +2297,8 @@ void AppWindow::RegisterEventHandlers() // Register a handler for the ContainsFullScreenChanged event. CHECK_FAILURE(m_webView->add_ContainsFullScreenElementChanged( Callback( - [this](ICoreWebView2* sender, IUnknown* args) -> HRESULT { + [this](ICoreWebView2* sender, IUnknown* args) -> HRESULT + { CHECK_FAILURE( sender->get_ContainsFullScreenElement(&m_containsFullscreenElement)); if (m_containsFullscreenElement) @@ -1259,12 +2322,41 @@ void AppWindow::RegisterEventHandlers() // the request. CHECK_FAILURE(m_webView->add_NewWindowRequested( Callback( - [this](ICoreWebView2* sender, ICoreWebView2NewWindowRequestedEventArgs* args) { + [this](ICoreWebView2* sender, ICoreWebView2NewWindowRequestedEventArgs* args) + { if (!m_shouldHandleNewWindowRequest) { args->put_Handled(FALSE); return S_OK; } + wil::com_ptr args_as_comptr = args; + auto args3 = + args_as_comptr.try_query(); + if (args3) + { + wil::com_ptr frame_info; + CHECK_FAILURE(args3->get_OriginalSourceFrameInfo(&frame_info)); + wil::unique_cotaskmem_string source; + CHECK_FAILURE(frame_info->get_Source(&source)); + // The host can decide how to open based on source frame info, + // such as URI. + static const wchar_t* browser_launching_domain = L"www.example.com"; + wil::unique_bstr source_domain = GetDomainOfUri(source.get()); + const wchar_t* source_domain_as_wchar = source_domain.get(); + if (source_domain_as_wchar && + wcscmp(browser_launching_domain, source_domain_as_wchar) == 0) + { + // Open the URI in the default browser. + wil::unique_cotaskmem_string target_uri; + CHECK_FAILURE(args->get_Uri(&target_uri)); + ShellExecute( + nullptr, L"open", target_uri.get(), nullptr, nullptr, + SW_SHOWNORMAL); + CHECK_FAILURE(args->put_Handled(TRUE)); + return S_OK; + } + } + wil::com_ptr deferral; CHECK_FAILURE(args->GetDeferral(&deferral)); AppWindow* newAppWindow; @@ -1312,10 +2404,12 @@ void AppWindow::RegisterEventHandlers() } else { - newAppWindow = new AppWindow(m_creationModeId, GetWebViewOption(), L"none"); + newAppWindow = new AppWindow( + m_creationModeId, GetWebViewOption(), L"none", m_userDataFolder); } newAppWindow->m_isPopupWindow = true; - newAppWindow->m_onWebViewFirstInitialized = [args, deferral, newAppWindow]() { + newAppWindow->m_onWebViewFirstInitialized = [args, deferral, newAppWindow]() + { CHECK_FAILURE(args->put_NewWindow(newAppWindow->m_webView.get())); CHECK_FAILURE(args->put_Handled(TRUE)); CHECK_FAILURE(deferral->Complete()); @@ -1330,15 +2424,16 @@ void AppWindow::RegisterEventHandlers() // Register a handler for the WindowCloseRequested event. // This handler will close the app window if it is not the main window. CHECK_FAILURE(m_webView->add_WindowCloseRequested( - Callback([this]( - ICoreWebView2* sender, - IUnknown* args) { - if (m_isPopupWindow) + Callback( + [this](ICoreWebView2* sender, IUnknown* args) { - CloseAppWindow(); - } - return S_OK; - }).Get(), + if (m_isPopupWindow) + { + CloseAppWindow(); + } + return S_OK; + }) + .Get(), nullptr)); //! [WindowCloseRequested] @@ -1348,36 +2443,130 @@ void AppWindow::RegisterEventHandlers() // This handler tells when there is a new Edge version available on the machine. CHECK_FAILURE(m_webViewEnvironment->add_NewBrowserVersionAvailable( Callback( - [this](ICoreWebView2Environment* sender, IUnknown* args) -> HRESULT { - std::wstring message = L"We detected there is a new version for the browser."; - if (m_webView) - { - message += L"Do you want to restart the app? \n\n"; - message += L"Click No if you only want to re-create the webviews. \n"; - message += L"Click Cancel for no action. \n"; - } - int response = MessageBox( - m_mainWindow, message.c_str(), L"New available version", - m_webView ? MB_YESNOCANCEL : MB_OK); + [this](ICoreWebView2Environment* sender, IUnknown* args) -> HRESULT + { + // Don't block the event handler with a message box + RunAsync( + [this] + { + std::wstring message = + L"We detected there is a new version for the browser."; + if (m_webView) + { + message += L"Do you want to restart the app? \n\n"; + message += + L"Click No if you only want to re-create the webviews. \n"; + message += L"Click Cancel for no action. \n"; + } + int response = MessageBox( + m_mainWindow, message.c_str(), L"New available version", + m_webView ? MB_YESNOCANCEL : MB_OK); - if (response == IDYES) - { - RestartApp(); - } - else if (response == IDNO) + if (response == IDYES) + { + RestartApp(); + } + else if (response == IDNO) + { + ReinitializeWebViewWithNewBrowser(); + } + else + { + // do nothing + } + }); + + return S_OK; + }) + .Get(), + nullptr)); + //! [NewBrowserVersionAvailable] + + //! [RestartRequested] + // After the environment is successfully created, + // register a handler for + auto exp_env15 = m_webViewEnvironment.try_query(); + CHECK_FAILURE(exp_env15->add_RestartRequested( + Callback( + [this]( + ICoreWebView2Environment* sender, + ICoreWebView2ExperimentalRestartRequestedEventArgs* args) -> HRESULT + { + COREWEBVIEW2_RESTART_REQUESTED_PRIORITY priority; + args->get_Priority(&priority); + if (priority == COREWEBVIEW2_RESTART_REQUESTED_PRIORITY_NORMAL) { - ReinitializeWebViewWithNewBrowser(); + // Remaind user to restart the app when they get a chance. + // Don't force user to restart. + MessageBox( + m_mainWindow, L"Please restart your app when you get a chance", + L"WebView Restart Requested", MB_OK); } - else + else if (priority == COREWEBVIEW2_RESTART_REQUESTED_PRIORITY_HIGH) { - // do nothing + // Don't block the event handler with a message box + RunAsync( + [this]() + { + std::wstring message = L"We detected there is a critical " + L"update for WebView2 runtime."; + if (m_webView) + { + message += L"Do you want to restart the app? \n\n"; + message += L"Click No if you only want to re-create the " + L"webviews. \n"; + message += L"Click Cancel for no action. \n"; + } + int response = MessageBox( + m_mainWindow, message.c_str(), L"Critical Update Avaliable", + m_webView ? MB_YESNOCANCEL : MB_OK); + + if (response == IDYES) + { + RestartApp(); + } + else if (response == IDNO) + { + ReinitializeWebViewWithNewBrowser(); + } + else + { + // do nothing + } + }); } return S_OK; }) .Get(), nullptr)); - //! [NewBrowserVersionAvailable] + //! [RestartRequested] + + //! [ProfileDeleted] + auto webView2_13 = m_webView.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webView2_13); + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + CHECK_FEATURE_RETURN_EMPTY(webView2Profile); + auto webView2Profile8 = webView2Profile.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webView2Profile8); + CHECK_FAILURE(webView2Profile8->add_Deleted( + Microsoft::WRL::Callback( + [this](ICoreWebView2Profile* sender, IUnknown* args) + { + RunAsync( + [this]() + { + std::wstring message = L"The profile has been marked for deletion. Any " + L"associated webview2 objects will be closed."; + MessageBox(m_mainWindow, message.c_str(), L"webview2 closed", MB_OK); + CloseAppWindow(); + }); + return S_OK; + }) + .Get(), + nullptr)); + //! [ProfileDeleted] } // Updates the sizing and positioning of everything in the window. @@ -1386,7 +2575,9 @@ void AppWindow::ResizeEverything() RECT availableBounds = {0}; GetClientRect(m_mainWindow, &availableBounds); - if (!m_containsFullscreenElement) + if (!m_containsFullscreenElement + && !m_webviewOption.useWco + ) { availableBounds = m_toolbar.Resize(availableBounds); } @@ -1406,8 +2597,8 @@ bool AppWindow::CloseWebView(bool cleanupUserDataFolder) { if (file->IsPrintToPdfInProgress()) { - int selection = MessageBox(m_mainWindow, - L"Print to PDF is in progress. Continue closing?", + int selection = MessageBox( + m_mainWindow, L"Print to PDF is in progress. Continue closing?", L"Print to PDF", MB_YESNO); if (selection == IDNO) { @@ -1423,8 +2614,7 @@ bool AppWindow::CloseWebView(bool cleanupUserDataFolder) wil::com_ptr environment5; if (m_webViewEnvironment) { - environment5 = - m_webViewEnvironment.try_query(); + environment5 = m_webViewEnvironment.try_query(); } if (cleanupUserDataFolder && environment5) { @@ -1434,7 +2624,8 @@ bool AppWindow::CloseWebView(bool cleanupUserDataFolder) Callback( [environment5, this]( ICoreWebView2Environment* sender, - ICoreWebView2BrowserProcessExitedEventArgs* args) { + ICoreWebView2BrowserProcessExitedEventArgs* args) + { COREWEBVIEW2_BROWSER_PROCESS_EXIT_KIND kind; UINT32 pid; CHECK_FAILURE(args->get_BrowserProcessExitKind(&kind)); @@ -1466,12 +2657,9 @@ bool AppWindow::CloseWebView(bool cleanupUserDataFolder) // The exiting process is not the last in use. Do not attempt cleanup // as we might still have a webview open over the user data folder. // Do not block from event handler. - RunAsync([this]() { - MessageBox( - m_mainWindow, - L"A new browser process prevented cleanup of the user data folder.", - L"Cleanup User Data Folder", MB_OK); - }); + AsyncMessageBox( + L"A new browser process prevented cleanup of the user data folder.", + L"Cleanup User Data Folder"); } return S_OK; @@ -1510,7 +2698,7 @@ bool AppWindow::CloseWebView(bool cleanupUserDataFolder) } // reset profile name - m_profileDirName = L""; + m_profileName = L""; m_documentTitle = L""; return true; } @@ -1523,7 +2711,7 @@ void AppWindow::CleanupUserDataFolder() // developers specify userDataFolder during WebView environment // creation, they would need to pass in that explicit value here. // For more information about userDataFolder: - // https://docs.microsoft.com/microsoft-edge/webview2/reference/win32/webview2-idl#createcorewebview2environmentwithoptions + // https://learn.microsoft.com/microsoft-edge/webview2/reference/win32/webview2-idl#createcorewebview2environmentwithoptions WCHAR userDataFolder[MAX_PATH] = L""; // Obtain the absolute path for relative paths that include "./" or "../" _wfullpath(userDataFolder, GetLocalPath(L".WebView2", true).c_str(), MAX_PATH); @@ -1626,11 +2814,12 @@ std::wstring AppWindow::GetDocumentTitle() return m_documentTitle; } -void AppWindow::UpdateAppTitle() { +void AppWindow::UpdateAppTitle() +{ std::wstring str(m_appTitle); - if (!m_profileDirName.empty()) + if (!m_profileName.empty()) { - str += L" - " + m_profileDirName; + str += L" - " + m_profileName; } if (!m_documentTitle.empty()) { @@ -1676,7 +2865,6 @@ std::wstring AppWindow::GetLocalUri( else { std::wstring path = GetLocalPath(L"assets\\" + relativePath, false); - wil::com_ptr uri; CHECK_FAILURE(CreateUri(path.c_str(), Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME, 0, &uri)); @@ -1692,6 +2880,12 @@ void AppWindow::RunAsync(std::function callback) PostMessage(m_mainWindow, s_runAsyncWindowMessage, reinterpret_cast(task), 0); } +void AppWindow::AsyncMessageBox(std::wstring message, std::wstring title) +{ + RunAsync([this, message = std::move(message), title = std::move(title)] + { MessageBox(m_mainWindow, message.c_str(), title.c_str(), MB_OK); }); +} + void AppWindow::EnterFullScreen() { DWORD style = GetWindowLong(m_mainWindow, GWL_STYLE); @@ -1756,7 +2950,7 @@ HRESULT AppWindow::TryCreateDispatcherQueue() namespace winSystem = winrt::Windows::System; HRESULT hr = S_OK; - thread_local winSystem::DispatcherQueueController dispatcherQueueController{ nullptr }; + thread_local winSystem::DispatcherQueueController dispatcherQueueController{nullptr}; if (dispatcherQueueController == nullptr) { @@ -1775,13 +2969,9 @@ HRESULT AppWindow::TryCreateDispatcherQueue() } if (fnCreateDispatcherQueueController != nullptr) { - winSystem::DispatcherQueueController controller{ nullptr }; - DispatcherQueueOptions options - { - sizeof(DispatcherQueueOptions), - DQTYPE_THREAD_CURRENT, - DQTAT_COM_STA - }; + winSystem::DispatcherQueueController controller{nullptr}; + DispatcherQueueOptions options{ + sizeof(DispatcherQueueOptions), DQTYPE_THREAD_CURRENT, DQTAT_COM_STA}; hr = fnCreateDispatcherQueueController( options, reinterpret_cast( winrt::put_abi(controller))); @@ -1792,36 +2982,29 @@ HRESULT AppWindow::TryCreateDispatcherQueue() return hr; } -#ifdef USE_WEBVIEW2_WIN10 //! [TextScaleChanged2] void AppWindow::OnTextScaleChanged( winrt::Windows::UI::ViewManagement::UISettings const& settings, winrt::Windows::Foundation::IInspectable const& args) { - RunAsync([this] { - m_toolbar.UpdateDpiAndTextScale(); - if (auto view = GetComponent()) + RunAsync( + [this] { - view->UpdateDpiAndTextScale(); - } - }); + m_toolbar.UpdateDpiAndTextScale(); + if (auto view = GetComponent()) + { + view->UpdateDpiAndTextScale(); + } + }); } //! [TextScaleChanged2] -#endif void AppWindow::UpdateCreationModeMenu() { HMENU hMenu = GetMenu(m_mainWindow); CheckMenuRadioItem( - hMenu, - IDM_CREATION_MODE_WINDOWED, -#ifdef USE_WEBVIEW2_WIN10 - IDM_CREATION_MODE_VISUAL_WINCOMP, -#else - IDM_CREATION_MODE_TARGET_DCOMP, -#endif - m_creationModeId, - MF_BYCOMMAND); + hMenu, IDM_CREATION_MODE_WINDOWED, IDM_CREATION_MODE_HOST_INPUT_PROCESSING, + m_creationModeId, MF_BYCOMMAND); } double AppWindow::GetDpiScale() @@ -1831,21 +3014,17 @@ double AppWindow::GetDpiScale() double AppWindow::GetTextScale() { -#ifdef USE_WEBVIEW2_WIN10 return m_uiSettings ? m_uiSettings.TextScaleFactor() : 1.0f; -#else - return 1.0f; -#endif } void AppWindow::AddRef() { - InterlockedIncrement((LONG *)&m_refCount); + InterlockedIncrement((LONG*)&m_refCount); } void AppWindow::Release() { - uint32_t refCount = InterlockedDecrement((LONG *)&m_refCount); + uint32_t refCount = InterlockedDecrement((LONG*)&m_refCount); if (refCount == 0) { delete this; @@ -1868,17 +3047,19 @@ void AppWindow::InstallComplete(int return_code) { if (return_code == 0) { - RunAsync([this] { - InitializeWebView(); - }); + RunAsync([this] { InitializeWebView(); }); } else if (return_code == 1) { - MessageBox(m_mainWindow, L"WebView Runtime failed to Install", L"WebView Runtime Installation status", MB_OK); + MessageBox( + m_mainWindow, L"WebView Runtime failed to Install", + L"WebView Runtime Installation status", MB_OK); } else if (return_code == 2) { - MessageBox(m_mainWindow, L"WebView Bootstrapper failled to download", L"WebView Bootstrapper Download status", MB_OK); + MessageBox( + m_mainWindow, L"WebView Bootstrapper failled to download", + L"WebView Bootstrapper Download status", MB_OK); } } } diff --git a/SampleApps/WebView2APISample/AppWindow.cpp.bak b/SampleApps/WebView2APISample/AppWindow.cpp.bak index 0a0a6592..e82f293d 100644 --- a/SampleApps/WebView2APISample/AppWindow.cpp.bak +++ b/SampleApps/WebView2APISample/AppWindow.cpp.bak @@ -1071,7 +1071,7 @@ void AppWindow::CloseWebView(bool cleanupUserDataFolder) // developers specify userDataFolder during WebView environment // creation, they would need to pass in that explicit value here. // For more information about userDataFolder: - // https://docs.microsoft.com/microsoft-edge/webview2/reference/win32/webview2-idl#createcorewebview2environmentwithoptions + // https://learn.microsoft.com/microsoft-edge/webview2/reference/win32/webview2-idl#createcorewebview2environmentwithoptions WCHAR userDataFolder[MAX_PATH] = L""; // Obtain the absolute path for relative paths that include "./" or "../" _wfullpath( diff --git a/SampleApps/WebView2APISample/AppWindow.h b/SampleApps/WebView2APISample/AppWindow.h index 67aceb61..5b1cf2ea 100644 --- a/SampleApps/WebView2APISample/AppWindow.h +++ b/SampleApps/WebView2APISample/AppWindow.h @@ -16,12 +16,10 @@ #include #include #include -#ifdef USE_WEBVIEW2_WIN10 #include #include namespace winrtComp = winrt::Windows::UI::Composition; -#endif class SettingsComponent; @@ -36,17 +34,22 @@ struct WebViewCreateOption std::wstring profile; bool isInPrivate = false; std::wstring downloadPath; - + std::wstring scriptLocale; // This value is inherited from the operated AppWindow WebViewCreateEntry entry = WebViewCreateEntry::OTHER; + bool useOSRegion = false; + std::optional bg_color; + bool useWco = false; WebViewCreateOption() { } - - WebViewCreateOption(const std::wstring& profile_, bool inPrivate, - const std::wstring& downloadPath, WebViewCreateEntry entry_) - : profile(profile_), isInPrivate(inPrivate), - downloadPath(downloadPath), entry(entry_) + WebViewCreateOption( + const std::wstring& profile_, bool inPrivate, const std::wstring& downloadPath, + const std::wstring& scriptLocale_, WebViewCreateEntry entry_, bool useOSRegion_, + bool useWco_ = false, const std::optional& bg_color_ = std::nullopt) + : profile(profile_), isInPrivate(inPrivate), downloadPath(downloadPath), + scriptLocale(scriptLocale_), entry(entry_), useOSRegion(useOSRegion_), + useWco(useWco_), bg_color(bg_color_) { } @@ -55,25 +58,53 @@ struct WebViewCreateOption profile = opt.profile; isInPrivate = opt.isInPrivate; downloadPath = opt.downloadPath; + scriptLocale = opt.scriptLocale; entry = opt.entry; + useOSRegion = opt.useOSRegion; + useWco = opt.useWco; + bg_color = opt.bg_color; } - void PopupDialog(AppWindow* app); }; +// SamplePrintSettings also defaults to the defaults of the ICoreWebView2PrintSettings +// defaults. +struct SamplePrintSettings +{ + COREWEBVIEW2_PRINT_ORIENTATION Orientation = COREWEBVIEW2_PRINT_ORIENTATION_PORTRAIT; + int Copies = 1; + int PagesPerSide = 1; + std::wstring Pages = L""; + COREWEBVIEW2_PRINT_COLLATION Collation = COREWEBVIEW2_PRINT_COLLATION_DEFAULT; + COREWEBVIEW2_PRINT_COLOR_MODE ColorMode = COREWEBVIEW2_PRINT_COLOR_MODE_DEFAULT; + COREWEBVIEW2_PRINT_DUPLEX Duplex = COREWEBVIEW2_PRINT_DUPLEX_DEFAULT; + COREWEBVIEW2_PRINT_MEDIA_SIZE Media = COREWEBVIEW2_PRINT_MEDIA_SIZE_DEFAULT; + double PaperWidth = 8.5; + double PaperHeight = 11; + double ScaleFactor = 1.0; + bool PrintBackgrounds = false; + bool HeaderAndFooter = false; + bool ShouldPrintSelectionOnly = false; + std::wstring HeaderTitle = L""; + std::wstring FooterUri = L""; +}; + +// Port range configuration +struct PortRangeConfig +{ + INT32 minPort = 0; + INT32 maxPort = 0; +}; + class AppWindow { public: AppWindow( - UINT creationModeId, - const WebViewCreateOption& opt, - const std::wstring& initialUri = L"", - const std::wstring& userDataFolderParam = L"", - bool isMainWindow = false, - std::function webviewCreatedCallback = nullptr, - bool customWindowRect = false, - RECT windowRect = { 0 }, - bool shouldHaveToolbar = true); + UINT creationModeId, const WebViewCreateOption& opt, + const std::wstring& initialUri = L"", const std::wstring& userDataFolderParam = L"", + bool isMainWindow = false, std::function webviewCreatedCallback = nullptr, + bool customWindowRect = false, RECT windowRect = {0}, bool shouldHaveToolbar = true, + bool isPopup = false); ~AppWindow(); @@ -107,10 +138,22 @@ class AppWindow template ComponentType* GetComponent(); + template ComponentType* GetOrCreateComponent(); + void DeleteComponent(ComponentBase* scenario); + // Runs a function by posting it to the event loop. Use this to do things + // that shouldn't be done in event handlers, like show message boxes. + // If you use this in a component, capture a pointer to this AppWindow + // instead of the component, because the component could get deleted before + // the AppWindow. void RunAsync(std::function callback); + // Calls win32 MessageBox inside RunAsync. Always uses MB_OK. If you need + // to get the return value from MessageBox, you'll have to use RunAsync + // yourself. + void AsyncMessageBox(std::wstring message, std::wstring title); + void InstallComplete(int return_code); void AddRef(); @@ -137,6 +180,11 @@ class AppWindow return m_webviewOption; } + const PortRangeConfig& GetUdpPortRange() const + { + return m_udpPortRange; + } + private: static PCWSTR GetWindowClass(); @@ -168,13 +216,39 @@ class AppWindow void UpdateCreationModeMenu(); void ToggleAADSSO(); bool ClearBrowsingData(COREWEBVIEW2_BROWSING_DATA_KINDS dataKinds); + bool ClearCustomDataPartition(); void UpdateAppTitle(); void ToggleExclusiveUserDataFolderAccess(); -#ifdef USE_WEBVIEW2_WIN10 + void ToggleCustomCrashReporting(); void OnTextScaleChanged( winrt::Windows::UI::ViewManagement::UISettings const& uiSettings, winrt::Windows::Foundation::IInspectable const& args); -#endif + bool ShowPrintUI(COREWEBVIEW2_PRINT_DIALOG_KIND printDialogKind); + bool PrintToDefaultPrinter(); + bool PrintToPrinter(); + std::wstring GetPrinterName(); + SamplePrintSettings GetSelectedPrinterPrintSettings(std::wstring printerName); + bool PrintToPdfStream(); + void ToggleTrackingPrevention(); + bool Start(const std::wstring& searchTerm); + bool FindNext(); + bool FindPrevious(); + bool StopFind(); + bool GetMatchCount(); + bool GetActiveMatchIndex(); + bool FindTerm(); + bool ShouldHighlightAllMatches(); + bool ShouldMatchWord(); + bool SuppressDefaultFindDialog(); + bool IsCaseSensitive(); + wil::com_ptr SetDefaultFindOptions(); + + void SetupFindEventHandlers(wil::com_ptr webView2find); + // Find on Page member + std::wstring m_findOnPageLastSearchTerm; + wil::com_ptr findOptions; + EventRegistrationToken m_activeMatchIndexChangedToken = {}; + EventRegistrationToken m_matchCountChangedToken = {}; std::wstring GetLocalPath(std::wstring path, bool keep_exe_path); void DeleteAllComponents(); @@ -212,11 +286,12 @@ class AppWindow std::vector> m_components; // options for creation of webview controller WebViewCreateOption m_webviewOption; - std::wstring m_profileDirName; + std::wstring m_profileName; std::unique_ptr m_oldSettingsComponent; std::wstring m_language; + std::wstring m_region; // app title, initialized in constructor std::wstring m_appTitle; @@ -227,6 +302,10 @@ class AppWindow bool m_AADSSOEnabled = false; bool m_ExclusiveUserDataFolderAccess = false; + bool m_CustomCrashReportingEnabled = false; + bool m_TrackingPreventionEnabled = true; + PortRangeConfig m_udpPortRange; +private: // Fullscreen related code RECT m_previousWindowRect; HMENU m_hMenu; @@ -241,10 +320,8 @@ class AppWindow HRESULT TryCreateDispatcherQueue(); wil::com_ptr m_dcompDevice; -#ifdef USE_WEBVIEW2_WIN10 winrtComp::Compositor m_wincompCompositor{ nullptr }; - winrt::Windows::UI::ViewManagement::UISettings m_uiSettings{ nullptr }; -#endif + winrt::Windows::UI::ViewManagement::UISettings m_uiSettings{nullptr}; // Background Image members HBITMAP m_appBackgroundImageHandle; @@ -253,6 +330,7 @@ class AppWindow RECT m_appBackgroundImageRect; }; +// Creates and registers a component on this `AppWindow`. template void AppWindow::NewComponent(Args&&... args) { m_components.emplace_back(new ComponentType(std::forward(args)...)); @@ -269,3 +347,14 @@ template ComponentType* AppWindow::GetComponent() } return nullptr; } + +template ComponentType* AppWindow::GetOrCreateComponent() +{ + auto component = GetComponent(); + if (!component) + { + NewComponent(this); + component = GetComponent(); + } + return component; +} diff --git a/SampleApps/WebView2APISample/CheckFailure.cpp b/SampleApps/WebView2APISample/CheckFailure.cpp index 992076b0..252da18a 100644 --- a/SampleApps/WebView2APISample/CheckFailure.cpp +++ b/SampleApps/WebView2APISample/CheckFailure.cpp @@ -10,7 +10,8 @@ void ShowFailure(HRESULT hr, const std::wstring& message) { std::wstringstream formattedMessage; - formattedMessage << message << ": 0x" << std::hex << std::setw(8) << hr; + formattedMessage << message << ": 0x" << std::hex << std::setw(8) << hr << " (" + << winrt::hresult_error(hr).message().c_str() << ")"; MessageBox(nullptr, formattedMessage.str().c_str(), nullptr, MB_OK); } diff --git a/SampleApps/WebView2APISample/CheckFailure.h b/SampleApps/WebView2APISample/CheckFailure.h index 763ceded..9eb953e8 100644 --- a/SampleApps/WebView2APISample/CheckFailure.h +++ b/SampleApps/WebView2APISample/CheckFailure.h @@ -35,3 +35,13 @@ void FeatureNotAvailable(); // Returns nothing, which is different from CHECK_FEATURE_RETURN #define CHECK_FEATURE_RETURN_EMPTY(feature) { if (!feature) { FeatureNotAvailable(); return; } } + +// Returns S_OK, which is different from CHECK_FEATURE_RETURN +#define CHECK_FEATURE_RETURN_HRESULT(feature) \ + { \ + if (!feature) \ + { \ + FeatureNotAvailable(); \ + return S_OK; \ + } \ + } diff --git a/SampleApps/WebView2APISample/ClientCertificateSelectionDialog.cpp b/SampleApps/WebView2APISample/ClientCertificateSelectionDialog.cpp index 40cad221..10863afe 100644 --- a/SampleApps/WebView2APISample/ClientCertificateSelectionDialog.cpp +++ b/SampleApps/WebView2APISample/ClientCertificateSelectionDialog.cpp @@ -2,24 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include #include #include "stdafx.h" #include "App.h" -#include "resource.h" #include "ClientCertificateSelectionDialog.h" - -std::wstring UnixEpochToDateTime(double value) { - WCHAR rawResult[32] = {}; - std::time_t rawTime = std::time_t(value); - struct tm timeStruct = {}; - gmtime_s(&timeStruct, &rawTime); - _wasctime_s(rawResult, 32, &timeStruct); - std::wstring result(rawResult); - return result; -} +#include "Util.h" +#include "resource.h" static INT_PTR CALLBACK ClientCertificateSelectionBoxDlg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { @@ -95,9 +85,13 @@ static INT_PTR CALLBACK ClientCertificateSelectionBoxDlg(HWND hDlg, UINT message int i = (int)SendMessage(hwndList, LB_GETITEMDATA, lbItem, 0); TCHAR buff[MAX_PATH]; - StringCbPrintf(buff, ARRAYSIZE(buff), + StringCbPrintf( + buff, ARRAYSIZE(buff), TEXT("Subject: %s\nValid From: %s\nValid To: %s\nCertificate Kind: %s"), - self->clientCertificates[i].Subject, UnixEpochToDateTime(self->clientCertificates[i].ValidFrom).c_str(), UnixEpochToDateTime(self->clientCertificates[i].ValidTo).c_str(), self->clientCertificates[i].CertificateKind); + self->clientCertificates[i].Subject, + Util::UnixEpochToDateTime(self->clientCertificates[i].ValidFrom).c_str(), + Util::UnixEpochToDateTime(self->clientCertificates[i].ValidTo).c_str(), + self->clientCertificates[i].CertificateKind); SetDlgItemText(hDlg, IDC_CERTIFICATE_STATIC, buff); return TRUE; diff --git a/SampleApps/WebView2APISample/ComponentBase.h b/SampleApps/WebView2APISample/ComponentBase.h index 1d23338e..aca1ce3d 100644 --- a/SampleApps/WebView2APISample/ComponentBase.h +++ b/SampleApps/WebView2APISample/ComponentBase.h @@ -6,6 +6,18 @@ #include "stdafx.h" +// A component is meant to encapsulate all details required for a specific +// capability of the AppWindow, typically demonstrating usage of a WebView2 API. +// +// Component instances are owned by an AppWindow, which will give each of its +// components a chance to handle any messages it gets. AppWindow deletes all its +// components when WebView is closed. +// +// Components are meant to be created and registered by AppWindow itself, +// through `AppWindow::NewComponent(...)`. For example, the +// AppWindow might create a new component upon selection of a menu item by the +// user. Components typically take and keep a pointer to their owning AppWindow +// so they can control the WebView. class ComponentBase { public: diff --git a/SampleApps/WebView2APISample/ControlComponent.cpp b/SampleApps/WebView2APISample/ControlComponent.cpp index 53b4cd30..9633c49b 100644 --- a/SampleApps/WebView2APISample/ControlComponent.cpp +++ b/SampleApps/WebView2APISample/ControlComponent.cpp @@ -119,10 +119,10 @@ ControlComponent::ControlComponent(AppWindow* appWindow, Toolbar* toolbar) // The web page can cancel its own iframe loads, so we'll ignore that. if (webErrorStatus != COREWEBVIEW2_WEB_ERROR_STATUS_OPERATION_CANCELED) { - std::wstring error_msg = WebErrorStatusToString(webErrorStatus); - MessageBox(nullptr, - (std::wstring(L"IFrame navigation failed: ") + error_msg).c_str(), - L"Navigation Failure", MB_OK); + m_appWindow->AsyncMessageBox( + L"Iframe navigation failed: " + + WebErrorStatusToString(webErrorStatus), + L"Navigation Failure"); } } return S_OK; @@ -187,8 +187,8 @@ ControlComponent::ControlComponent(AppWindow* appWindow, Toolbar* toolbar) UINT key; CHECK_FAILURE(args->get_VirtualKey(&key)); // Check if the key is one we want to handle. - if (std::function action = - m_appWindow->GetAcceleratorKeyFunction(key)) + std::function action = m_appWindow->GetAcceleratorKeyFunction(key); + if (action) { // Keep the browser from handling this key, whether it's autorepeated or // not. @@ -291,7 +291,7 @@ bool ControlComponent::HandleChildWindowMessage( // If not calling IsDialogMessage to handle tab traversal automatically, // detect tab traversal and cycle focus through address bar, go button, and // elements in WebView. - if (message == WM_KEYDOWN) + if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN) { //! [MoveFocus1] if (wParam == VK_TAB) @@ -320,6 +320,12 @@ bool ControlComponent::HandleChildWindowMessage( NavigateToAddressBar(); return true; } + // Ctrl+A is SelectAll + else if ((GetKeyState(VK_CONTROL) < 0) && ((UINT)wParam == 'A')) + { + m_toolbar->SelectAll(); + return true; + } else { // If bit 30 is set, it means the WM_KEYDOWN message is autorepeated. @@ -370,7 +376,7 @@ void ControlComponent::NavigateToAddressBar() } else { - // Otherwise treat it as a web search. + // Otherwise treat it as a web search. std::wstring urlEscaped(2048, ' '); DWORD dwEscaped = (DWORD)urlEscaped.length(); UrlEscapeW(uri.c_str(), &urlEscaped[0], &dwEscaped, URL_ESCAPE_ASCII_URI_COMPONENT); @@ -429,7 +435,6 @@ ControlComponent::~ControlComponent() m_webView->remove_FrameNavigationCompleted(m_frameNavigationCompletedToken); m_controller->remove_MoveFocusRequested(m_moveFocusRequestedToken); m_controller->remove_AcceleratorKeyPressed(m_acceleratorKeyPressedToken); - // Undo our modifications to the toolbar elements for (auto pair : m_tabbableWindows) { diff --git a/SampleApps/WebView2APISample/ControlComponent.h b/SampleApps/WebView2APISample/ControlComponent.h index 30a5fdb3..1a11de8e 100644 --- a/SampleApps/WebView2APISample/ControlComponent.h +++ b/SampleApps/WebView2APISample/ControlComponent.h @@ -40,7 +40,6 @@ class ControlComponent : public ComponentBase wil::com_ptr m_controller; wil::com_ptr m_webView; Toolbar* m_toolbar; - std::vector> m_tabbableWindows; EventRegistrationToken m_navigationStartingToken = {}; @@ -49,5 +48,6 @@ class ControlComponent : public ComponentBase EventRegistrationToken m_navigationCompletedToken = {}; EventRegistrationToken m_moveFocusRequestedToken = {}; EventRegistrationToken m_acceleratorKeyPressedToken = {}; + EventRegistrationToken m_unhandledKeyPressedToken = {}; EventRegistrationToken m_frameNavigationCompletedToken = {}; }; diff --git a/SampleApps/WebView2APISample/DiscardsComponent.cpp b/SampleApps/WebView2APISample/DiscardsComponent.cpp new file mode 100644 index 00000000..f97435da --- /dev/null +++ b/SampleApps/WebView2APISample/DiscardsComponent.cpp @@ -0,0 +1,23 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "DiscardsComponent.h" + +DiscardsComponent::DiscardsComponent(AppWindow* appWindow) : m_appWindow(appWindow) +{ + m_appWindowDiscardsView = new AppWindow( + IDM_CREATION_MODE_WINDOWED, appWindow->GetWebViewOption(), L"edge://discards/graph", + appWindow->GetUserDataFolder(), false /* isMainWindow */, + nullptr /* webviewCreatedCallback */, true /* customWindowRect */, {100, 100, 900, 900}, + false /* shouldHaveToolbar */); + + m_appWindowDiscardsView->SetOnAppWindowClosing([&] { m_appWindow->DeleteComponent(this); }); +} + +DiscardsComponent::~DiscardsComponent() +{ + m_appWindowDiscardsView->SetOnAppWindowClosing(nullptr); +} diff --git a/SampleApps/WebView2APISample/DiscardsComponent.h b/SampleApps/WebView2APISample/DiscardsComponent.h new file mode 100644 index 00000000..cf9c52c1 --- /dev/null +++ b/SampleApps/WebView2APISample/DiscardsComponent.h @@ -0,0 +1,23 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "stdafx.h" + +#include "AppWindow.h" +#include "ComponentBase.h" + +class DiscardsComponent : public ComponentBase +{ +public: + DiscardsComponent(AppWindow* appWindow); + ~DiscardsComponent() override; + +private: + AppWindow* m_appWindow = nullptr; + + // The AppWindow showing discards. + AppWindow* m_appWindowDiscardsView; +}; diff --git a/SampleApps/WebView2APISample/DropTarget.cpp b/SampleApps/WebView2APISample/DropTarget.cpp index 3063e3cb..d9982f50 100644 --- a/SampleApps/WebView2APISample/DropTarget.cpp +++ b/SampleApps/WebView2APISample/DropTarget.cpp @@ -7,9 +7,11 @@ #include "DropTarget.h" #include "ViewComponent.h" #include -#include +#include -DropTarget::DropTarget() : m_window(nullptr) {} +DropTarget::DropTarget() : m_window(nullptr) +{ +} DropTarget::~DropTarget() { @@ -17,75 +19,40 @@ DropTarget::~DropTarget() void DropTarget::Init( HWND window, ViewComponent* viewComponent, - ICoreWebView2ExperimentalCompositionController3* webViewExperimentalCompositionController3) + ICoreWebView2CompositionController3* webViewCompositionController3) { - m_webViewExperimentalCompositionController3 = webViewExperimentalCompositionController3; + m_webViewCompositionController3 = webViewCompositionController3; m_viewComponent = viewComponent; m_window = window; ::RegisterDragDrop(m_window, this); } -wil::com_ptr DropTarget::DropHelper() { - if (!m_dropTargetHelper) - { - CoCreateInstance( - CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER, IID_IDropTargetHelper, - reinterpret_cast(&m_dropTargetHelper)); - } - return m_dropTargetHelper; -} - //! [DragEnter] HRESULT DropTarget::DragEnter( IDataObject* dataObject, DWORD keyState, POINTL cursorPosition, DWORD* effect) { - POINT point = { cursorPosition.x, cursorPosition.y}; - // Tell the helper that we entered so it can update the drag image and get - // the correct effect. - wil::com_ptr dropHelper = DropHelper(); - if (dropHelper) - { - dropHelper->DragEnter(GetHWND(), dataObject, &point, *effect); - } - + POINT point = {cursorPosition.x, cursorPosition.y}; // Convert the screen point to client coordinates add the WebView's offset. m_viewComponent->OffsetPointToWebView(&point); - return m_webViewExperimentalCompositionController3->DragEnter( - dataObject, keyState, point, effect); + return m_webViewCompositionController3->DragEnter(dataObject, keyState, point, effect); } //! [DragEnter] //! [DragOver] HRESULT DropTarget::DragOver(DWORD keyState, POINTL cursorPosition, DWORD* effect) { - POINT point = { cursorPosition.x, cursorPosition.y}; - // Tell the helper that we moved over it so it can update the drag image - // and get the correct effect. - wil::com_ptr dropHelper = DropHelper(); - if (dropHelper) - { - dropHelper->DragOver(&point, *effect); - } - + POINT point = {cursorPosition.x, cursorPosition.y}; // Convert the screen point to client coordinates add the WebView's offset. // This returns whether the resultant point is over the WebView visual. m_viewComponent->OffsetPointToWebView(&point); - return m_webViewExperimentalCompositionController3->DragOver( - keyState, point, effect); + return m_webViewCompositionController3->DragOver(keyState, point, effect); } //! [DragOver] //! [DragLeave] HRESULT DropTarget::DragLeave() { - // Tell the helper that we moved out of it so it can update the drag image. - wil::com_ptr dropHelper = DropHelper(); - if (dropHelper) - { - dropHelper->DragLeave(); - } - - return m_webViewExperimentalCompositionController3->DragLeave(); + return m_webViewCompositionController3->DragLeave(); } //! [DragLeave] @@ -93,18 +60,10 @@ HRESULT DropTarget::DragLeave() HRESULT DropTarget::Drop( IDataObject* dataObject, DWORD keyState, POINTL cursorPosition, DWORD* effect) { - POINT point = { cursorPosition.x, cursorPosition.y}; - // Tell the helper that we dropped onto it so it can update the drag image and - // get the correct effect. - wil::com_ptr dropHelper = DropHelper(); - if (dropHelper) - { - dropHelper->Drop(dataObject, &point, *effect); - } - + POINT point = {cursorPosition.x, cursorPosition.y}; // Convert the screen point to client coordinates add the WebView's offset. // This returns whether the resultant point is over the WebView visual. m_viewComponent->OffsetPointToWebView(&point); - return m_webViewExperimentalCompositionController3->Drop(dataObject, keyState, point, effect); + return m_webViewCompositionController3->Drop(dataObject, keyState, point, effect); } //! [Drop] \ No newline at end of file diff --git a/SampleApps/WebView2APISample/DropTarget.h b/SampleApps/WebView2APISample/DropTarget.h index b4e0c107..8080ebb1 100644 --- a/SampleApps/WebView2APISample/DropTarget.h +++ b/SampleApps/WebView2APISample/DropTarget.h @@ -19,7 +19,7 @@ class DropTarget : public Microsoft::WRL::RuntimeClass< // Initialize the drop target by associating it with the given HWND. void Init( HWND window, ViewComponent* viewComponent, - ICoreWebView2ExperimentalCompositionController3* webViewExperimentalCompositionController3); + ICoreWebView2CompositionController3* webViewCompositionController3); // IDropTarget implementation: HRESULT __stdcall DragEnter(IDataObject* dataObject, @@ -41,13 +41,9 @@ class DropTarget : public Microsoft::WRL::RuntimeClass< // Returns the hosting HWND. HWND GetHWND() { return m_window; } - wil::com_ptr DropHelper(); - wil::com_ptr m_dropTargetHelper; - // The HWND of the source. This HWND is used to determine coordinates for // mouse events that are sent to the renderer notifying various drag states. HWND m_window; - wil::com_ptr - m_webViewExperimentalCompositionController3; + wil::com_ptr m_webViewCompositionController3; }; \ No newline at end of file diff --git a/SampleApps/WebView2APISample/FileComponent.cpp b/SampleApps/WebView2APISample/FileComponent.cpp index fad98b3f..fd1c819b 100644 --- a/SampleApps/WebView2APISample/FileComponent.cpp +++ b/SampleApps/WebView2APISample/FileComponent.cpp @@ -82,15 +82,12 @@ void FileComponent::SaveScreenshot() defaultName, STGM_READWRITE | STGM_CREATE, FILE_ATTRIBUTE_NORMAL, TRUE, nullptr, &stream)); - HWND mainWindow = m_appWindow->GetMainWindow(); - CHECK_FAILURE(m_webView->CapturePreview( COREWEBVIEW2_CAPTURE_PREVIEW_IMAGE_FORMAT_PNG, stream.get(), Callback( - [mainWindow](HRESULT error_code) -> HRESULT { + [appWindow{m_appWindow}](HRESULT error_code) -> HRESULT { CHECK_FAILURE(error_code); - - MessageBox(mainWindow, L"Preview Captured", L"Preview Captured", MB_OK); + appWindow->AsyncMessageBox(L"Preview Captured", L"Preview Captured"); return S_OK; }) .Get())); @@ -133,14 +130,10 @@ void FileComponent::PrintToPdf(bool enableLandscape) [this](HRESULT errorCode, BOOL isSuccessful) -> HRESULT { CHECK_FAILURE(errorCode); m_printToPdfInProgress = false; - auto showDialog = [isSuccessful] { - MessageBox( - nullptr, - (isSuccessful) ? L"Print to PDF succeeded" - : L"Print to PDF failed", - L"Print to PDF Completed", MB_OK); - }; - m_appWindow->RunAsync([showDialog]() { showDialog(); }); + m_appWindow->AsyncMessageBox( + (isSuccessful) ? L"Print to PDF succeeded" + : L"Print to PDF failed", + L"Print to PDF Completed"); return S_OK; }) .Get())); diff --git a/SampleApps/WebView2APISample/PermissionDialog.cpp b/SampleApps/WebView2APISample/PermissionDialog.cpp new file mode 100644 index 00000000..ff0a8828 --- /dev/null +++ b/SampleApps/WebView2APISample/PermissionDialog.cpp @@ -0,0 +1,84 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "PermissionDialog.h" + +#include "App.h" +#include "ScenarioPermissionManagement.h" +#include "resource.h" + +static INT_PTR CALLBACK DlgProcStatic(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + auto self = (PermissionDialog*)GetWindowLongPtr(hDlg, GWLP_USERDATA); + + switch (message) + { + case WM_INITDIALOG: + { + self = (PermissionDialog*)lParam; + SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)self); + HWND hwndList = GetDlgItem(hDlg, IDC_PERMISSION_KIND); + for (COREWEBVIEW2_PERMISSION_KIND kind_enum : self->permissionKinds) + { + int pos = (int)SendMessage( + hwndList, CB_ADDSTRING, 0, (LPARAM)PermissionKindToString(kind_enum).c_str()); + SendMessage(hwndList, CB_SETITEMDATA, pos, (LPARAM)kind_enum); + } + hwndList = GetDlgItem(hDlg, IDC_PERMISSION_STATE); + for (COREWEBVIEW2_PERMISSION_STATE state_enum : self->permissionStates) + { + int pos = (int)SendMessage( + hwndList, CB_ADDSTRING, 0, (LPARAM)PermissionStateToString(state_enum).c_str()); + SendMessage(hwndList, CB_SETITEMDATA, pos, (LPARAM)state_enum); + } + return (INT_PTR)TRUE; + } + case WM_COMMAND: + { + if (LOWORD(wParam) == IDOK) + { + int length = GetWindowTextLength(GetDlgItem(hDlg, IDC_EDIT_PERMISSION_ORIGIN)); + wchar_t origin[MAX_PATH] = {}; + GetDlgItemText(hDlg, IDC_EDIT_PERMISSION_ORIGIN, origin, length + 1); + self->origin = origin; + + HWND hwndList = GetDlgItem(hDlg, IDC_PERMISSION_KIND); + int index = (int)SendMessage(hwndList, CB_GETCURSEL, 0, 0); + COREWEBVIEW2_PERMISSION_KIND kind = + (COREWEBVIEW2_PERMISSION_KIND)SendMessage(hwndList, CB_GETITEMDATA, index, 0); + self->kind = kind; + + hwndList = GetDlgItem(hDlg, IDC_PERMISSION_STATE); + index = (int)SendMessage(hwndList, CB_GETCURSEL, 0, 0); + COREWEBVIEW2_PERMISSION_STATE state = + (COREWEBVIEW2_PERMISSION_STATE)SendMessage(hwndList, CB_GETITEMDATA, index, 0); + self->state = state; + + self->confirmed = true; + } + + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) + { + EndDialog(hDlg, LOWORD(wParam)); + return (INT_PTR)TRUE; + } + break; + } + case WM_NCDESTROY: + SetWindowLongPtr(hDlg, GWLP_USERDATA, NULL); + return (INT_PTR)TRUE; + } + return (INT_PTR)FALSE; +} + +PermissionDialog::PermissionDialog( + HWND parent, std::vector kinds, + std::vector states) + : permissionKinds(kinds), permissionStates(states) +{ + DialogBoxParam( + g_hInstance, MAKEINTRESOURCE(IDD_SET_PERMISSION), parent, DlgProcStatic, (LPARAM)this); +} diff --git a/SampleApps/WebView2APISample/PermissionDialog.h b/SampleApps/WebView2APISample/PermissionDialog.h new file mode 100644 index 00000000..fbe9e281 --- /dev/null +++ b/SampleApps/WebView2APISample/PermissionDialog.h @@ -0,0 +1,25 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "stdafx.h" + +// Constructing this struct will show a client certificate selection dialog and return when +// the user dismisses it. If the user clicks the OK button, confirmed will be true with the +// selected certificate. +struct PermissionDialog +{ + PermissionDialog( + HWND parent, std::vector kinds, + std::vector states); + + std::vector permissionKinds; + std::vector permissionStates; + + std::wstring origin; + COREWEBVIEW2_PERMISSION_KIND kind = COREWEBVIEW2_PERMISSION_KIND_UNKNOWN_PERMISSION; + COREWEBVIEW2_PERMISSION_STATE state = COREWEBVIEW2_PERMISSION_STATE_DEFAULT; + bool confirmed = false; +}; diff --git a/SampleApps/WebView2APISample/ProcessComponent.cpp b/SampleApps/WebView2APISample/ProcessComponent.cpp index 611e0e69..a5b9f85b 100644 --- a/SampleApps/WebView2APISample/ProcessComponent.cpp +++ b/SampleApps/WebView2APISample/ProcessComponent.cpp @@ -53,7 +53,7 @@ ProcessComponent::ProcessComponent(AppWindow* appWindow) // needed. ScheduleReloadIfSelectedByUser( L"Browser render process exited unexpectedly. Reload page?", - L"Web page unresponsive"); + L"Render process exited"); } // Check the runtime event args implements the newer interface. auto args2 = args.try_query(); @@ -100,21 +100,28 @@ ProcessComponent::ProcessComponent(AppWindow* appWindow) COREWEBVIEW2_PROCESS_FAILED_REASON reason; wil::unique_cotaskmem_string processDescription; int exitCode; + wil::unique_cotaskmem_string failedModule; CHECK_FAILURE(args2->get_Reason(&reason)); CHECK_FAILURE(args2->get_ProcessDescription(&processDescription)); CHECK_FAILURE(args2->get_ExitCode(&exitCode)); + auto argFailedModule = + args.try_query(); + if (argFailedModule) + { + CHECK_FAILURE( + argFailedModule->get_FailureSourceModulePath(&failedModule)); + } + std::wstringstream message; - message << L"Kind: " << ProcessFailedKindToString(kind) << L"\n" - << L"Reason: " << ProcessFailedReasonToString(reason) << L"\n" - << L"Exit code: " << std::to_wstring(exitCode) << L"\n" - << L"Process description: " << processDescription.get() << std::endl; - m_appWindow->RunAsync([this, message = message.str()]() { - MessageBox( - m_appWindow->GetMainWindow(), message.c_str(), - L"Child process failed", MB_OK); - }); + message << L"Kind: " << ProcessFailedKindToString(kind) << L"\n" + << L"Reason: " << ProcessFailedReasonToString(reason) << L"\n" + << L"Exit code: " << exitCode << L"\n" + << L"Process description: " << processDescription.get() << std::endl + << (failedModule ? L"Failed module: " : L"") + << (failedModule ? failedModule.get() : L""); + m_appWindow->AsyncMessageBox( std::move(message.str()), L"Child process failed"); } return S_OK; }) @@ -180,13 +187,17 @@ bool ProcessComponent::HandleWindowMessage( case IDM_PERFORMANCE_INFO: PerformanceInfo(); return true; + case IDM_PROCESS_EXTENDED_INFO: + ShowProcessExtendedInfo(); + return true; } } return false; } // Show the WebView's PID to the user. -void ProcessComponent::ShowBrowserProcessInfo() { +void ProcessComponent::ShowBrowserProcessInfo() +{ UINT32 processId; m_webView->get_BrowserProcessId(&processId); @@ -195,6 +206,213 @@ void ProcessComponent::ShowBrowserProcessInfo() { MessageBox(m_appWindow->GetMainWindow(), buffer, L"Process Info", MB_OK); } +// Get a string for the frame kind enum value. +std::wstring ProcessComponent::FrameKindToString(const COREWEBVIEW2_FRAME_KIND kind) +{ + switch (kind) + { +#define KIND_ENTRY(kindValue) \ + case kindValue: \ + return L#kindValue; + + KIND_ENTRY(COREWEBVIEW2_FRAME_KIND_MAIN_FRAME); + KIND_ENTRY(COREWEBVIEW2_FRAME_KIND_IFRAME); + KIND_ENTRY(COREWEBVIEW2_FRAME_KIND_EMBED); + KIND_ENTRY(COREWEBVIEW2_FRAME_KIND_OBJECT); + KIND_ENTRY(COREWEBVIEW2_FRAME_KIND_UNKNOWN); + +#undef KIND_ENTRY + } + + return std::to_wstring(static_cast(kind)); +} + +void ProcessComponent::AppendFrameInfo( + wil::com_ptr frameInfo, std::wstringstream& result) +{ + UINT32 frameId = 0; + UINT32 parentFrameId = 0; + UINT32 mainFrameId = 0; + UINT32 childFrameId = 0; + std::wstring type = L"other child frame"; + wil::unique_cotaskmem_string nameRaw; + wil::unique_cotaskmem_string sourceRaw; + COREWEBVIEW2_FRAME_KIND frameKind = COREWEBVIEW2_FRAME_KIND_UNKNOWN; + + CHECK_FAILURE(frameInfo->get_Name(&nameRaw)); + std::wstring name = nameRaw.get()[0] ? nameRaw.get() : L"none"; + CHECK_FAILURE(frameInfo->get_Source(&sourceRaw)); + std::wstring source = sourceRaw.get()[0] ? sourceRaw.get() : L"none"; + + wil::com_ptr frameInfo2; + CHECK_FAILURE(frameInfo->QueryInterface(IID_PPV_ARGS(&frameInfo2))); + frameInfo2->get_FrameId(&frameId); + frameInfo2->get_FrameKind(&frameKind); + + wil::com_ptr parentFrameInfo; + CHECK_FAILURE(frameInfo2->get_ParentFrameInfo(&parentFrameInfo)); + if (parentFrameInfo) + { + CHECK_FAILURE(parentFrameInfo->QueryInterface(IID_PPV_ARGS(&frameInfo2))); + CHECK_FAILURE(frameInfo2->get_FrameId(&parentFrameId)); + } + + wil::com_ptr mainFrameInfo = GetAncestorMainFrameInfo(frameInfo); + if (mainFrameInfo == frameInfo) + { + type = L"main frame"; + } + CHECK_FAILURE(mainFrameInfo->QueryInterface(IID_PPV_ARGS(&frameInfo2))); + CHECK_FAILURE(frameInfo2->get_FrameId(&mainFrameId)); + + wil::com_ptr childFrameInfo = + GetAncestorMainFrameDirectChildFrameInfo(frameInfo); + if (childFrameInfo == frameInfo) + { + type = L"first level frame"; + } + if (childFrameInfo) + { + CHECK_FAILURE(childFrameInfo->QueryInterface(IID_PPV_ARGS(&frameInfo2))); + CHECK_FAILURE(frameInfo2->get_FrameId(&childFrameId)); + } + + result << L"{frame name:" << name << L" | frame Id:" << frameId << L" | parent frame Id:" + << ((parentFrameId == 0) ? L"none" : std::to_wstring(parentFrameId)) + << L" | frame type:" << type << L"\n" + << L" | ancestor main frame Id:" << mainFrameId + << L" | ancestor main frame's direct child frame Id:" + << ((childFrameId == 0) ? L"none" : std::to_wstring(childFrameId)) << L"\n" + << L" | frame kind:" << FrameKindToString(frameKind) << L"\n" + << L" | frame source:" << source << L"}," << std::endl; +} + +// Get the ancestor main frameInfo. +// Return itself if it's a main frame. +wil::com_ptr ProcessComponent::GetAncestorMainFrameInfo( + wil::com_ptr frameInfo) +{ + wil::com_ptr mainFrameInfo; + wil::com_ptr frameInfo2; + while (frameInfo) + { + mainFrameInfo = frameInfo; + CHECK_FAILURE(frameInfo->QueryInterface(IID_PPV_ARGS(&frameInfo2))); + CHECK_FAILURE(frameInfo2->get_ParentFrameInfo(&frameInfo)); + } + return mainFrameInfo; +} + +// Get the frame's corresponding main frame's direct child frameInfo. +// Example: +// A (main frame/CoreWebView2) +// | \ +// (frame) B C (frame) +// | | +// (frame) D E (frame) +// | +// F (frame) +// C GetAncestorMainFrameDirectChildFrameInfo returns C. +// D GetAncestorMainFrameDirectChildFrameInfo returns B. +// F GetAncestorMainFrameDirectChildFrameInfo returns C. +wil::com_ptr ProcessComponent::GetAncestorMainFrameDirectChildFrameInfo( + wil::com_ptr frameInfo) +{ + wil::com_ptr mainFrameInfo; + wil::com_ptr childFrameInfo; + wil::com_ptr frameInfo2; + while (frameInfo) + { + childFrameInfo = mainFrameInfo; + mainFrameInfo = frameInfo; + CHECK_FAILURE(frameInfo->QueryInterface(IID_PPV_ARGS(&frameInfo2))); + CHECK_FAILURE(frameInfo2->get_ParentFrameInfo(&frameInfo)); + } + return childFrameInfo; +} + +void ProcessComponent::ShowProcessExtendedInfo() +{ + auto environment13 = m_webViewEnvironment.try_query(); + if (environment13) + { + //! [GetProcessExtendedInfos] + CHECK_FAILURE(environment13->GetProcessExtendedInfos( + Callback( + [this]( + HRESULT error, + ICoreWebView2ProcessExtendedInfoCollection* processCollection) -> HRESULT + { + UINT32 processCount = 0; + UINT32 rendererProcessCount = 0; + CHECK_FAILURE(processCollection->get_Count(&processCount)); + std::wstringstream otherProcessInfos; + std::wstringstream rendererProcessInfos; + for (UINT32 i = 0; i < processCount; i++) + { + Microsoft::WRL::ComPtr + processExtendedInfo; + CHECK_FAILURE( + processCollection->GetValueAtIndex(i, &processExtendedInfo)); + Microsoft::WRL::ComPtr processInfo; + CHECK_FAILURE(processExtendedInfo->get_ProcessInfo(&processInfo)); + COREWEBVIEW2_PROCESS_KIND kind; + CHECK_FAILURE(processInfo->get_Kind(&kind)); + INT32 processId = 0; + CHECK_FAILURE(processInfo->get_ProcessId(&processId)); + if (kind == COREWEBVIEW2_PROCESS_KIND_RENDERER) + { + //! [AssociatedFrameInfos] + std::wstringstream rendererProcess; + wil::com_ptr frameInfoCollection; + CHECK_FAILURE(processExtendedInfo->get_AssociatedFrameInfos( + &frameInfoCollection)); + wil::com_ptr iterator; + CHECK_FAILURE(frameInfoCollection->GetIterator(&iterator)); + BOOL hasCurrent = FALSE; + UINT32 frameInfoCount = 0; + while (SUCCEEDED(iterator->get_HasCurrent(&hasCurrent)) && + hasCurrent) + { + wil::com_ptr frameInfo; + CHECK_FAILURE(iterator->GetCurrent(&frameInfo)); + + AppendFrameInfo(frameInfo, rendererProcess); + + BOOL hasNext = FALSE; + CHECK_FAILURE(iterator->MoveNext(&hasNext)); + frameInfoCount++; + } + rendererProcessInfos + << frameInfoCount + << L" frameInfo(s) found in Renderer Process ID:" << processId + << L"\n" + << rendererProcess.str() << std::endl; + //! [AssociatedFrameInfos] + rendererProcessCount++; + } + else + { + otherProcessInfos << L"Process Id:" << processId + << L" | Process Kind:" + << ProcessKindToString(kind) << std::endl; + } + } + std::wstringstream message; + message << processCount << L" process(es) found, from which " + << rendererProcessCount << L" renderer process(es) found\n\n" + << rendererProcessInfos.str() << L"Remaining Process(es) Infos:\n" + << otherProcessInfos.str(); + + m_appWindow->AsyncMessageBox( + std::move(message.str()), L"Process Extended Info"); + return S_OK; + }) + .Get())); + //! [GetProcessExtendedInfos] + } +} + // Get a string for the failure kind enum value. std::wstring ProcessComponent::ProcessFailedKindToString( const COREWEBVIEW2_PROCESS_FAILED_KIND kind) diff --git a/SampleApps/WebView2APISample/ProcessComponent.h b/SampleApps/WebView2APISample/ProcessComponent.h index 21549e76..075fd76f 100644 --- a/SampleApps/WebView2APISample/ProcessComponent.h +++ b/SampleApps/WebView2APISample/ProcessComponent.h @@ -32,6 +32,7 @@ class ProcessComponent : public ComponentBase void CrashBrowserProcess(); void CrashRenderProcess(); void PerformanceInfo(); + void ShowProcessExtendedInfo(); ~ProcessComponent() override; @@ -50,7 +51,13 @@ class ProcessComponent : public ComponentBase UINT m_browserProcessId = 0; wil::com_ptr m_processCollection; - EventRegistrationToken m_processFailedToken = {}; EventRegistrationToken m_processInfosChangedToken = {}; + void AppendFrameInfo( + wil::com_ptr frameInfo, std::wstringstream& result); + wil::com_ptr GetAncestorMainFrameDirectChildFrameInfo( + wil::com_ptr frameInfo); + wil::com_ptr GetAncestorMainFrameInfo( + wil::com_ptr frameInfo); + std::wstring FrameKindToString(const COREWEBVIEW2_FRAME_KIND kind); }; diff --git a/SampleApps/WebView2APISample/README.md b/SampleApps/WebView2APISample/README.md index c7ebf4d8..fecdaa42 100644 --- a/SampleApps/WebView2APISample/README.md +++ b/SampleApps/WebView2APISample/README.md @@ -1,5 +1,5 @@ --- -description: "Demonstrate the features and usage patterns of WebView2 in Win32." +description: "Demonstrates the features and usage patterns of WebView2 in a Win32 app." extendedZipContent: - path: SharedContent @@ -14,346 +14,23 @@ products: - microsoft-edge urlFragment: WebView2APISample --- -# WebView2 API Sample +# Win32 sample app -This is a hybrid application built with the [Microsoft Edge WebView2](https://aka.ms/webview2) control. + -![Sample App Snapshot](https://raw.githubusercontent.com/MicrosoftEdge/WebView2Samples/master/SampleApps/WebView2APISample/documentation/screenshots/sample-app-screenshot.png) + +This sample, **WebView2APISample**, embeds a WebView2 control within a Win32 application. -The WebView2APISample is an example of an application that embeds a WebView within a Win32 native application. It is built as a Win32 [Visual Studio 2019](https://visualstudio.microsoft.com/vs/) project and makes use of both C++ and HTML/CSS/JavaScript in the WebView2 environment. + +This sample is built as a Win32 Visual Studio 2019 project. It uses C++ in the native environment together with HTML/CSS/JavaScript in the WebView2 environment. This sample showcases many of WebView2's event handlers and API methods that allow a native Win32 application to directly interact with a WebView, and vice versa. -The API Sample showcases a selection of WebView2's event handlers and API methods that allow a native Win32 application to directly interact with a WebView and vice versa. + +The solution file for this sample is in the parent directory: `SampleApps/WebView2Samples.sln`. The solution file includes a copy of some of the other, sibling samples for other frameworks or platforms. -If this is your first time using WebView, we recommend first following the [Getting Started](https://docs.microsoft.com/microsoft-edge/webview2/gettingstarted/win32) guide, which goes over how to create a WebView2 and walks through some basic WebView2 functionality. + +To use this sample, see [Win32 sample app](https://learn.microsoft.com/microsoft-edge/webview2/samples/webview2apissample). -To learn more specifics about events and API Handlers in WebView2, you can refer to the [WebView2 Reference Documentation](https://docs.microsoft.com/microsoft-edge/webview2/webview2-api-reference). + +This is the main WebView2 sample. The running **WebView2APISample** app window shows the WebView2 SDK version and also the WebView2 Runtime version and path. The **WebView2APISample** app has several menus containing many menuitems that demonstrate a broad range of WebView2 APIs: -## Prerequisites - -- [Microsoft Edge (Chromium)](https://www.microsoftedgeinsider.com/download/) installed on a supported OS. Currently we recommend the latest version of the Edge Canary channel. -- [Visual Studio](https://visualstudio.microsoft.com/vs/) with C++ support installed. -- Latest pre-release version of our [WebView2 SDK](https://aka.ms/webviewnuget), which is included in this project. - -## Build the WebView2 API Sample - -Clone the repository and open the solution in Visual Studio. WebView2 is already included as a NuGet package* in this project. - -- Clone this repository -- Open the solution in Visual Studio 2019** -- Set the target you want to build (Debug/Release, x86/x64/ARM64) -- Build the project file: _WebView2APISample.vcxproj_ - -That's it! Everything should be ready to just launch the app. - -*You can get the WebView2 NugetPackage through the Visual Studio NuGet Package Manager. - -**You can also use Visual Studio 2017 by changing the project's Platform Toolset in Project Properties/Configuration properties/General/Platform Toolset. You might also need to change the Windows SDK to the latest version available to you. - -## Application architecture - -The API Sample App is an example of a hybrid application. It has two parts: a Win32 native part and a WebView part. The Win32 part can access native Windows APIs, while the WebView container can utilize standard web technologies (HTML, CSS, JavaScript). - -This hybrid approach allows you to create and iterate faster using web technologies, while still being able to take advantage of native functionalities. The Sample App specifically demonstrates how both components can interact with each other. - -Both of these parts of the Sample App are displayed in the image below: - -![alt text](https://raw.githubusercontent.com/MicrosoftEdge/WebView2Samples/master/SampleApps/WebView2APISample/documentation/screenshots/sample-app-layout-diagram.png) - -1. Section One: The top part of the Sample App is a Win32 component written in C++. This part of the application takes in UI inputs from the user and uses them to control the WebView. - -2. Section Two: The main part of the Sample App is a WebView that can be repurposed using standard web technologies (HTML/CSS/JavaScript). It can be navigated to websites or local content. - -## Project Files - -This section briefly explains some key files within the repository. The WebView2APISample is divided vertically into components, instead of horizontally into layers. Each component implements the whole workflow of a category of example features, from listening for menu commands, to calling WebView API methods to implement them. - -#### 1. App.cpp - -This is the top-level file that runs the Sample App. It reads command line options, sets up the process environment, and handles the app's threading model. - -#### 2. AppWindow.cpp - -This file implements the application window. In this file, we first set up all the Win32 controls. Second, we initialize the WebView Environment and the WebView. Third, we add some event handlers to the WebView and create all the components that handle various features of the application. The `AppWindow` class itself handles commands from the application's Window menu. - -#### 3. FileComponent.cpp - -This component handles commands from the File menu (except for Exit), as well as the `DocumentTitleChanged` event. - -#### 4. ScriptComponent.cpp - -This component handles commands from the Script menu, which involve interacting with the WebView by injecting JavaScript, posting WebMessages, adding native objects to the webpage, or using the DevTools protocol to communicate with the webpage. - -#### 5. ProcessComponent.cpp - -This component handles commands from the Process menu, which involve interaction with the browser's process. It also handles the ProcessFailed event, in case the browser process or one of its render process crashes or is unresponsive. - -#### 6. SettingsComponent.cpp - -This component handles commands from the Settings menu, and is also in charge of copying settings from an old WebView when a new one is created. Most code that interacts with the `ICoreWebView2Settings` interface can be found here. - -#### 7. ViewComponent.cpp - -This component handles commands from the View menu, and any functionality related to sizing and visibility of the WebView. When the app window is resized, minimized, or restored, `ViewComponent` will resize, hide, or show the WebView in response. It also responds to the `ZoomFactorChanged` event. - -#### 8. ScenarioWebMessage.cpp and ScenarioWebMessage.html - -This component is created when you select the Scenario/Web Messaging menu item. It implements an example application with a C++ part and an HTML+JavaScript part, which communicate with each other by asynchronously posting and receiving messages. - -![alt text](https://raw.githubusercontent.com/MicrosoftEdge/WebView2Samples/master/SampleApps/WebView2APISample/documentation/screenshots/sample-app-webmessaging-screenshot.png) - -#### 9. ScenarioAddHostObject.cpp and ScenarioAddHostObject.html - -This component is created when you select the Scenario/Host Objects menu item. It demonstrates communication between the native app and the HTML webpage by means of host object injection. The interface of the host object is declared in `HostObjectSample.idl`, and the object itself is implemented in `HostObjectSampleImpl.cpp`. - -## Key Functions - -The section below briefly explains some of the key functions in the Sample App. - -### AppWindow.cpp - -#### InitializeWebView() - -In the AppWindow file, we use the InitializeWebView() function to create the WebView2 environment by using [CreateCoreWebView2EnvironmentWithOptions](https://docs.microsoft.com/microsoft-edge/webview2/reference/win32/webview2-idl#createcorewebview2environmentwithoptions). - -Once we've created the environment, we create the WebView by using `CreateCoreWebView2Controller`. - -To see these API calls in action, refer to the following code snippet from `InitializeWebView()`. - -```cpp -HRESULT hr = CreateCoreWebView2EnvironmentWithOptions( - subFolder, nullptr, options.Get(), - Callback( - this, &AppWindow::OnCreateEnvironmentCompleted) - .Get()); -if (!SUCCEEDED(hr)) -{ - if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) - { - MessageBox( - m_mainWindow, - L"Couldn't find Edge installation. " - "Do you have a version installed that's compatible with this " - "WebView2 SDK version?", - nullptr, MB_OK); - } - else - { - ShowFailure(hr, L"Failed to create webview environment"); - } -} -``` - -#### OnCreateEnvironmentCompleted() - -This callback function is passed to `CreateCoreWebView2EnvironmentWithOptions` in `InitializeWebView()`. It stored the environment pointer and then uses it to create a new WebView. - -```cpp -HRESULT AppWindow::OnCreateEnvironmentCompleted( - HRESULT result, ICoreWebView2Environment* environment) -{ - CHECK_FAILURE(result); - - m_webViewEnvironment = environment; - - CHECK_FAILURE(m_webViewEnvironment->CreateCoreWebView2Controller( - m_mainWindow, Callback( - this, &AppWindow::OnCreateCoreWebView2ControllerCompleted) - .Get())); - return S_OK; -} -``` - -#### OnCreateCoreWebView2ControllerCompleted() - -This callback function is passed to `CreateCoreWebView2Controller` in `InitializeWebView()`. Here, we initialize the WebView-related state, register some event handlers, and create the app components. - -#### RegisterEventHandlers() - -This function is called within `CreateCoreWebView2Controller`. It sets up some of the event handlers used by the application, and adds them to the WebView. - -To read more about event handlers in WebView2, you can refer to this [documentation](https://docs.microsoft.com/microsoft-edge/webview2/reference/win32/icorewebview2). - -Below is a code snippet from `RegisterEventHandlers()`, where we set up an event handler for the `NewWindowRequested` event. This event is fired when JavaScript in the webpage calls `window.open()`, and our handler makes a new `AppWindow` and passes the new window's WebView back to the browser so it can return it from the `window.open()` call. Unlike our calls to `CreateCoreWebView2EnvironmentWithOptions` and `CreateCoreWebView2Controller`, instead of providing a method for the callback, we just provide a C++ lambda right then and there. - -```cpp -CHECK_FAILURE(m_webView->add_NewWindowRequested( - Callback( - [this]( - ICoreWebView2* sender, - ICoreWebView2NewWindowRequestedEventArgs* args) { - wil::com_ptr deferral; - CHECK_FAILURE(args->GetDeferral(&deferral)); - - auto newAppWindow = new AppWindow(L""); - newAppWindow->m_isPopupWindow = true; - newAppWindow->m_onWebViewFirstInitialized = [args, deferral, newAppWindow]() { - CHECK_FAILURE(args->put_NewWindow(newAppWindow->m_webView.get())); - CHECK_FAILURE(args->put_Handled(TRUE)); - CHECK_FAILURE(deferral->Complete()); - }; - - return S_OK; - }) - .Get(), - nullptr)); -``` - -### ScenarioWebMessage - -The `ScenarioWebMessage` files show how the Win32 Host can modify the WebView, how the WebView can modify the Win32Host, and how the WebView can modify itself by accessing information from the Win32 Host. This is done asynchronously. - -The following sections demonstrate how each discrete function works using the Sample App and then explains how to implement this functionality. - -First, navigate to the ScenarioWebMessage application within the Sample App, using the following steps: - -1. Open the Sample App -2. Click on Scenario -3. Click on Web Messaging - -The WebView should display a simple webpage titled: "WebMessage sample page". The code for this page can be found in the `ScenarioWebMessage.html` file. - -![alt text](https://raw.githubusercontent.com/MicrosoftEdge/WebView2Samples/master/SampleApps/WebView2APISample/documentation/screenshots/sample-app-webmessaging-screenshot.png) - -To better understand ScenarioWebMessage functionality, you can either follow the instructions on the page or the steps detailed below. - -#### 1. Posting Messages (Win32 Host to WebView) - -The following steps show how the Win32 Host can modify a WebView. In this example, you will turn the text blue: - -1. Click on Script in the Toolbar -2. Click on Post Web Message JSON - -A dialog box with the pre-written code `{"SetColor":"blue"}` should appear. - -3. Click OK - -The text under Posting Messages should now be blue. - -Here's how it works: - -1. In `ScriptComponent.cpp`, we use [PostWebMessageAsJson](https://docs.microsoft.com/microsoft-edge/webview2/reference/win32/icorewebview2#postwebmessageasjson) to post user input to the `ScenarioMessage.html` web application. - -```cpp -// Prompt the user for some JSON and then post it as a web message. -void ScriptComponent::SendJsonWebMessage() -{ - TextInputDialog dialog( - m_appWindow->GetMainWindow(), - L"Post Web Message JSON", - L"Web message JSON:", - L"Enter the web message as JSON.", - L"{\"SetColor\":\"blue\"}"); - if (dialog.confirmed) - { - m_webView->PostWebMessageAsJson(dialog.input.c_str()); - } -} -``` - -2. Within the web application, event listeners are used to receive and respond to the web message. The code snippet below is from `ScenarioWebMessage.html`. The event listener changes the color of the text if it reads "SetColor". - -```js -window.chrome.webview.addEventListener('message', arg => { - if ("SetColor" in arg.data) { - document.getElementById("colorable").style.color = arg.data.SetColor; - } -}); -``` - -#### 2. Receiving Messages (WebView to Win32 Host) - -The following steps show how the WebView can modify the Win32 Host App by changing the title of the Win32 App: - -1. Locate the Title of the Sample App - the top left of the window next to the icon. -2. Under the Receiving Message section, fill out the form with the new title of your choice. -3. Click Send - -Locate the Title of the Sample App, it should have changed to the title you have just inputted. - -Here's how it works: - -1. Within `ScenarioWebMessage.html`, we call [window.chrome.webview.postMessage()](https://developer.mozilla.org/docs/Web/API/Window/postMessage) to send the user input to the host application. Refer to code snippet below: - -```js -function SetTitleText() { - let titleText = document.getElementById("title-text"); - window.chrome.webview.postMessage(`SetTitleText ${titleText.value}`); -} -``` - -2. Within `ScenarioWebMessage.cpp`, we use [add_WebMessageReceived](https://docs.microsoft.com/microsoft-edge/webview2/reference/win32/icorewebview2#add_webmessagereceived) to register the event handler. When we receive the event, after validating the input, we change the title of the App Window. - -```cpp -// Setup the web message received event handler before navigating to -// ensure we don't miss any messages. -CHECK_FAILURE(m_webview->add_WebMessageReceived( - Microsoft::WRL::Callback( - [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) -{ - wil::unique_cotaskmem_string uri; - CHECK_FAILURE(args->get_Source(&uri)); - - // Always validate that the origin of the message is what you expect. - if (uri.get() != m_sampleUri) - { - return S_OK; - } - wil::unique_cotaskmem_string messageRaw; - CHECK_FAILURE(args->TryGetWebMessageAsString(&messageRaw)); - std::wstring message = messageRaw.get(); - - if (message.compare(0, 13, L"SetTitleText ") == 0) - { - m_appWindow->SetTitleText(message.substr(13).c_str()); - } - return S_OK; -}).Get(), &m_webMessageReceivedToken)); -``` - -#### 3. Roundtrip (WebView to WebView) - -The following steps show how the WebView can get information from the Win32 Host and modify itself by displaying the size of the Win32 App. - -1. Under RoundTrip, click GetWindowBounds - -The box underneath the button should display the bounds for the Sample App. - -Here's how it works: - -1. When the 'Get window bounds' button is clicked, the `GetWindowBounds` function in `ScenarioWebMessage.html` gets called. It uses [window.chrome.webview.postMessage()](https://developer.mozilla.org/docs/Web/API/Window/postMessage) to send a message to the host application. - -```js -function GetWindowBounds() { - window.chrome.webview.postMessage("GetWindowBounds"); - } -``` - -2. Within `ScenarioWebMessage.cpp`, we use [add_WebMessageReceived](https://docs.microsoft.com/microsoft-edge/webview2/reference/win32/icorewebview2#add_webmessagereceived) to register the received event handler. After validating the input, the event handler gets window bounds from the App Window. [PostWebMessageAsJson](https://docs.microsoft.com/microsoft-edge/webview2/reference/win32/icorewebview2#postwebmessageasjson) sends the bounds to the web application. - -```cpp -if (message.compare(L"GetWindowBounds") == 0) -{ - RECT bounds = m_appWindow->GetWindowBounds(); - std::wstring reply = - L"{\"WindowBounds\":\"Left:" + std::to_wstring(bounds.left) - + L"\\nTop:" + std::to_wstring(bounds.top) - + L"\\nRight:" + std::to_wstring(bounds.right) - + L"\\nBottom:" + std::to_wstring(bounds.bottom) - + L"\"}"; - CHECK_FAILURE(sender->PostWebMessageAsJson(reply.c_str())); -} -``` - -3. Within `ScenarioWebMessage.html`, an event listener responds to the WindowBounds message and displays the bounds of the window. - -```js -window.chrome.webview.addEventListener('message', arg => { - if ("WindowBounds" in arg.data) { - document.getElementById("window-bounds").value = arg.data.WindowBounds; - } -}); -``` - -## Code of Conduct - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact opencode@microsoft.com with any additional questions or comments. +![The WebView2APISample sample app running](./documentation/screenshots/sample-app-screenshot.png) diff --git a/SampleApps/WebView2APISample/ScenarioAcceleratorKeyPressed.cpp b/SampleApps/WebView2APISample/ScenarioAcceleratorKeyPressed.cpp new file mode 100644 index 00000000..dadaf811 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioAcceleratorKeyPressed.cpp @@ -0,0 +1,145 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "ScenarioAcceleratorKeyPressed.h" + +#include "AppWindow.h" +#include "CheckFailure.h" + +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = L"ScenarioAcceleratorKeyPressed.html"; +ScenarioAcceleratorKeyPressed::ScenarioAcceleratorKeyPressed(AppWindow* appWindow) + : m_appWindow(appWindow), m_controller(appWindow->GetWebViewController()), + m_webView(appWindow->GetWebView()) +{ + m_sampleUri = m_appWindow->GetLocalUri(c_samplePath); + wil::com_ptr settings; + CHECK_FAILURE(m_webView->get_Settings(&settings)); + m_settings3 = settings.try_query(); + // Setup the web message received event handler before navigating to + // ensure we don't miss any messages. + CHECK_FAILURE(m_webView->add_WebMessageReceived( + Microsoft::WRL::Callback( + [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) + { + wil::unique_cotaskmem_string uri; + CHECK_FAILURE(args->get_Source(&uri)); + + // Always validate that the origin of the message is what you expect. + if (uri.get() != m_sampleUri) + { + return S_OK; + } + wil::unique_cotaskmem_string messageRaw; + CHECK_FAILURE(args->TryGetWebMessageAsString(&messageRaw)); + std::wstring message = messageRaw.get(); + std::wstring reply; + + if (message.compare(0, 26, L"DisableBrowserAccelerators") == 0) + { + CHECK_FAILURE(m_settings3->put_AreBrowserAcceleratorKeysEnabled(FALSE)); + MessageBox( + nullptr, + L"Browser-specific accelerator keys, for example: \n" + L"Ctrl+F and F3 for Find on Page\n" + L"Ctrl+P for Print\n" + L"Ctrl+R and F5 for Reload\n" + L"Ctrl+Plus and Ctrl+Minus for zooming\n" + L"Ctrl+Shift-C and F12 for DevTools\n" + L"Special keys for browser functions, such as Back, Forward, and " + L"Search \n" + L"will be disabled after the next navigation except for F7.", + L"Settings change", MB_OK); + } + else if (message.compare(0, 25, L"EnableBrowserAccelerators") == 0) + { + CHECK_FAILURE(m_settings3->put_AreBrowserAcceleratorKeysEnabled(TRUE)); + MessageBox( + nullptr, + L"Browser-specific accelerator keys, for example: \n" + L"Ctrl+F and F3 for Find on Page\n" + L"Ctrl+R and F5 for Reload\n" + L"Ctrl+Plus and Ctrl+Minus for zooming\n" + L"Ctrl+Shift-C and F12 for DevTools\n" + L"Special keys for browser functions, such as Back, Forward, and " + L"Search \n" + L"will be enabled after the next navigation except for Ctr + P.", + L"Settings change", MB_OK); + } + return S_OK; + }) + .Get(), + &m_webMessageReceivedToken)); + + //! [IsBrowserAcceleratorKeyEnabled] + if (m_settings3) + { + // Register a handler for the AcceleratorKeyPressed event. + CHECK_FAILURE(m_controller->add_AcceleratorKeyPressed( + Callback( + [this]( + ICoreWebView2Controller* sender, + ICoreWebView2AcceleratorKeyPressedEventArgs* args) -> HRESULT + { + COREWEBVIEW2_KEY_EVENT_KIND kind; + CHECK_FAILURE(args->get_KeyEventKind(&kind)); + // We only care about key down events. + if (kind == COREWEBVIEW2_KEY_EVENT_KIND_KEY_DOWN || + kind == COREWEBVIEW2_KEY_EVENT_KIND_SYSTEM_KEY_DOWN) + { + UINT key; + CHECK_FAILURE(args->get_VirtualKey(&key)); + + wil::com_ptr args2; + + args->QueryInterface(IID_PPV_ARGS(&args2)); + if (args2) + { + if (key == 'P' && (GetKeyState(VK_CONTROL) < 0)) + { + // tell the browser to skip the key + CHECK_FAILURE(args2->put_IsBrowserAcceleratorKeyEnabled(FALSE)); + } + if (key == VK_F7) + { + // tell the browser to process the key + CHECK_FAILURE(args2->put_IsBrowserAcceleratorKeyEnabled(TRUE)); + } + } + } + return S_OK; + }) + .Get(), + &m_acceleratorKeyPressedToken)); + } + //! [IsBrowserAcceleratorKeyEnabled] + + // Turn off this scenario if we navigate away from the sample page + CHECK_FAILURE(m_webView->add_ContentLoading( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2ContentLoadingEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string uri; + sender->get_Source(&uri); + if (uri.get() != m_sampleUri) + { + m_appWindow->DeleteComponent(this); + } + return S_OK; + }) + .Get(), + &m_contentLoadingToken)); + + CHECK_FAILURE(m_webView->Navigate(m_sampleUri.c_str())); +} + +ScenarioAcceleratorKeyPressed::~ScenarioAcceleratorKeyPressed() +{ + m_webView->remove_WebMessageReceived(m_webMessageReceivedToken); + m_controller->remove_AcceleratorKeyPressed(m_acceleratorKeyPressedToken); + m_webView->remove_ContentLoading(m_contentLoadingToken); +} diff --git a/SampleApps/WebView2APISample/ScenarioAcceleratorKeyPressed.h b/SampleApps/WebView2APISample/ScenarioAcceleratorKeyPressed.h new file mode 100644 index 00000000..da287090 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioAcceleratorKeyPressed.h @@ -0,0 +1,29 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once +#include "stdafx.h" + +#include + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioAcceleratorKeyPressed : public ComponentBase +{ +public: + ScenarioAcceleratorKeyPressed(AppWindow* appWindow); + ~ScenarioAcceleratorKeyPressed() override; + +private: + EventRegistrationToken m_acceleratorKeyPressedToken = {}; + EventRegistrationToken m_contentLoadingToken = {}; + EventRegistrationToken m_webMessageReceivedToken = {}; + + AppWindow* m_appWindow = nullptr; + std::wstring m_sampleUri; + wil::com_ptr m_controller; + wil::com_ptr m_webView; + wil::com_ptr m_settings3; +}; \ No newline at end of file diff --git a/SampleApps/WebView2APISample/ScenarioAddHostObject.cpp b/SampleApps/WebView2APISample/ScenarioAddHostObject.cpp index 4e133ec4..c219f63c 100644 --- a/SampleApps/WebView2APISample/ScenarioAddHostObject.cpp +++ b/SampleApps/WebView2APISample/ScenarioAddHostObject.cpp @@ -32,48 +32,50 @@ ScenarioAddHostObject::ScenarioAddHostObject(AppWindow* appWindow) m_hostObject = Microsoft::WRL::Make( [appWindow = m_appWindow](std::function callback) - { - appWindow->RunAsync(callback); - }); + { appWindow->RunAsync(callback); }); CHECK_FAILURE(m_webView->add_NavigationStarting( Microsoft::WRL::Callback( - [this, sampleUri](ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args) -> HRESULT - { - wil::unique_cotaskmem_string navigationTargetUri; - CHECK_FAILURE(args->get_Uri(&navigationTargetUri)); - std::wstring uriTarget(navigationTargetUri.get()); - - if (AreFileUrisEqual(sampleUri, uriTarget)) - { - //! [AddHostObjectToScript] - VARIANT remoteObjectAsVariant = {}; - m_hostObject.query_to(&remoteObjectAsVariant.pdispVal); - remoteObjectAsVariant.vt = VT_DISPATCH; - - // We can call AddHostObjectToScript multiple times in a row without - // calling RemoveHostObject first. This will replace the previous object - // with the new object. In our case this is the same object and everything - // is fine. - CHECK_FAILURE( - m_webView->AddHostObjectToScript(L"sample", &remoteObjectAsVariant)); - remoteObjectAsVariant.pdispVal->Release(); - //! [AddHostObjectToScript] - } - else - { - // We can call RemoveHostObject multiple times in a row without - // calling AddHostObjectToScript first. This will produce an error - // result so we ignore the failure. - m_webView->RemoveHostObjectFromScript(L"sample"); - - // When we navigate elsewhere we're off of the sample - // scenario page and so should remove the scenario. - m_appWindow->DeleteComponent(this); - } - - return S_OK; - }).Get(), &m_navigationStartingToken)); + [this, sampleUri]( + ICoreWebView2* sender, + ICoreWebView2NavigationStartingEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string navigationTargetUri; + CHECK_FAILURE(args->get_Uri(&navigationTargetUri)); + std::wstring uriTarget(navigationTargetUri.get()); + + if (AreFileUrisEqual(sampleUri, uriTarget)) + { + //! [AddHostObjectToScript] + VARIANT remoteObjectAsVariant = {}; + m_hostObject.query_to(&remoteObjectAsVariant.pdispVal); + remoteObjectAsVariant.vt = VT_DISPATCH; + + // We can call AddHostObjectToScript multiple times in a row without + // calling RemoveHostObject first. This will replace the previous object + // with the new object. In our case this is the same object and everything + // is fine. + CHECK_FAILURE( + m_webView->AddHostObjectToScript(L"sample", &remoteObjectAsVariant)); + remoteObjectAsVariant.pdispVal->Release(); + //! [AddHostObjectToScript] + } + else + { + // We can call RemoveHostObject multiple times in a row without + // calling AddHostObjectToScript first. This will produce an error + // result so we ignore the failure. + m_webView->RemoveHostObjectFromScript(L"sample"); + + // When we navigate elsewhere we're off of the sample + // scenario page and so should remove the scenario. + m_appWindow->DeleteComponent(this); + } + + return S_OK; + }) + .Get(), + &m_navigationStartingToken)); wil::com_ptr webview2_4 = m_webView.try_query(); if (webview2_4) @@ -83,63 +85,70 @@ ScenarioAddHostObject::ScenarioAddHostObject(AppWindow* appWindow) CHECK_FAILURE(webview2_4->add_FrameCreated( Callback( [this]( - ICoreWebView2* sender, - ICoreWebView2FrameCreatedEventArgs* args) -> HRESULT - { - wil::com_ptr webviewFrame; - CHECK_FAILURE(args->get_Frame(&webviewFrame)); - - wil::unique_cotaskmem_string name; - CHECK_FAILURE(webviewFrame->get_Name(&name)); - if (std::wcscmp(name.get(), L"iframe_name") == 0) - { - //! [AddHostObjectToScriptWithOrigins] - wil::unique_variant remoteObjectAsVariant; - // It will throw if m_hostObject fails the QI, but because it is our object - // it should always succeed. - m_hostObject.query_to(&remoteObjectAsVariant.pdispVal); - remoteObjectAsVariant.vt = VT_DISPATCH; - - // Create list of origins which will be checked. - // iframe will have access to host object only if its origin belongs - // to this list. - LPCWSTR origin = L"https://appassets.example/"; - - CHECK_FAILURE(webviewFrame->AddHostObjectToScriptWithOrigins( - L"sample", &remoteObjectAsVariant, 1, &origin)); - //! [AddHostObjectToScriptWithOrigins] - } - - // Subscribe to frame name changed event - webviewFrame->add_NameChanged( - Callback( - [this](ICoreWebView2Frame* sender, IUnknown* args) -> HRESULT { - wil::unique_cotaskmem_string newName; - CHECK_FAILURE(sender->get_Name(&newName)); - // Handle name changed event - return S_OK; - }).Get(), NULL); - - // Subscribe to frame destroyed event - webviewFrame->add_Destroyed( - Callback( - [this](ICoreWebView2Frame* sender, IUnknown* args) -> HRESULT { - /*Cleanup on frame destruction*/ - return S_OK; - }) - .Get(), - NULL); - return S_OK; - }).Get(), &m_frameCreatedToken)); + ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args) -> HRESULT + { + wil::com_ptr webviewFrame; + CHECK_FAILURE(args->get_Frame(&webviewFrame)); + + wil::unique_cotaskmem_string name; + CHECK_FAILURE(webviewFrame->get_Name(&name)); + if (std::wcscmp(name.get(), L"iframe_name") == 0) + { + //! [AddHostObjectToScriptWithOrigins] + wil::unique_variant remoteObjectAsVariant; + // It will throw if m_hostObject fails the QI, but because it is our + // object it should always succeed. + m_hostObject.query_to(&remoteObjectAsVariant.pdispVal); + remoteObjectAsVariant.vt = VT_DISPATCH; + + // Create list of origins which will be checked. + // iframe will have access to host object only if its origin belongs + // to this list. + LPCWSTR origin = L"https://appassets.example/"; + + CHECK_FAILURE(webviewFrame->AddHostObjectToScriptWithOrigins( + L"sample", &remoteObjectAsVariant, 1, &origin)); + //! [AddHostObjectToScriptWithOrigins] + } + + // Subscribe to frame name changed event + webviewFrame->add_NameChanged( + Callback( + [this](ICoreWebView2Frame* sender, IUnknown* args) -> HRESULT + { + wil::unique_cotaskmem_string newName; + CHECK_FAILURE(sender->get_Name(&newName)); + // Handle name changed event + return S_OK; + }) + .Get(), + NULL); + + // Subscribe to frame destroyed event + webviewFrame->add_Destroyed( + Callback( + [this](ICoreWebView2Frame* sender, IUnknown* args) -> HRESULT + { + /*Cleanup on frame destruction*/ + return S_OK; + }) + .Get(), + NULL); + return S_OK; + }) + .Get(), + &m_frameCreatedToken)); } - CHECK_FAILURE(m_webView->Navigate(sampleUri.c_str())); } - ScenarioAddHostObject::~ScenarioAddHostObject() { m_webView->RemoveHostObjectFromScript(L"sample"); m_webView->remove_NavigationStarting(m_navigationStartingToken); + if (m_navigationCompletedToken.value) + { + m_webView->remove_NavigationCompleted(m_navigationCompletedToken); + } wil::com_ptr webview2_4 = m_webView.try_query(); if (webview2_4) { diff --git a/SampleApps/WebView2APISample/ScenarioAddHostObject.h b/SampleApps/WebView2APISample/ScenarioAddHostObject.h index 822ef2d0..bda254ce 100644 --- a/SampleApps/WebView2APISample/ScenarioAddHostObject.h +++ b/SampleApps/WebView2APISample/ScenarioAddHostObject.h @@ -24,5 +24,6 @@ class ScenarioAddHostObject : public ComponentBase wil::com_ptr m_hostObject; EventRegistrationToken m_navigationStartingToken = {}; + EventRegistrationToken m_navigationCompletedToken = {}; EventRegistrationToken m_frameCreatedToken = {}; }; diff --git a/SampleApps/WebView2APISample/ScenarioAuthentication.cpp b/SampleApps/WebView2APISample/ScenarioAuthentication.cpp index d1d590e7..d87b5f0a 100644 --- a/SampleApps/WebView2APISample/ScenarioAuthentication.cpp +++ b/SampleApps/WebView2APISample/ScenarioAuthentication.cpp @@ -33,9 +33,9 @@ ScenarioAuthentication::ScenarioAuthentication(AppWindow* appWindow) : wil::unique_cotaskmem_string authHeaderValue; if (requestHeaders->GetHeader(L"Authorization", &authHeaderValue) == S_OK) { - std::wstring message(L"Authorization: "); - message += authHeaderValue.get(); - MessageBox(nullptr, message.c_str(), nullptr, MB_OK); + m_appWindow->AsyncMessageBox( + std::wstring(L"Authorization: ") + authHeaderValue.get(), + L"Authentication result"); m_appWindow->DeleteComponent(this); } } diff --git a/SampleApps/WebView2APISample/ScenarioClientCertificateRequested.cpp b/SampleApps/WebView2APISample/ScenarioClientCertificateRequested.cpp index 5f76f707..b66f1432 100644 --- a/SampleApps/WebView2APISample/ScenarioClientCertificateRequested.cpp +++ b/SampleApps/WebView2APISample/ScenarioClientCertificateRequested.cpp @@ -9,7 +9,7 @@ using namespace Microsoft::WRL; -static PCWSTR NameOfCertificateKind(COREWEBVIEW2_CERTIFICATE_KIND kind); +static PCWSTR NameOfCertificateKind(COREWEBVIEW2_CLIENT_CERTIFICATE_KIND kind); ScenarioClientCertificateRequested::ScenarioClientCertificateRequested(AppWindow* appWindow) : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) @@ -23,13 +23,15 @@ ScenarioClientCertificateRequested::ScenarioClientCertificateRequested(AppWindow m_webView2_5 = m_webView.try_query(); if (m_webView2_5) { - CHECK_FAILURE(m_webView2_5->add_ClientCertificateRequested( - Callback( - [this]( - ICoreWebView2* sender, - ICoreWebView2ClientCertificateRequestedEventArgs* args) { + CHECK_FAILURE( + m_webView2_5->add_ClientCertificateRequested( + Callback( + [this]( + ICoreWebView2* sender, + ICoreWebView2ClientCertificateRequestedEventArgs* args) { auto showDialog = [this, args] { - wil::com_ptr certificateCollection; + wil::com_ptr + certificateCollection; CHECK_FAILURE(args->get_MutuallyTrustedCertificates(&certificateCollection)); wil::unique_cotaskmem_string host; @@ -41,7 +43,7 @@ ScenarioClientCertificateRequested::ScenarioClientCertificateRequested(AppWindow UINT certificateCollectionCount; CHECK_FAILURE(certificateCollection->get_Count(&certificateCollectionCount)); - wil::com_ptr certificate = nullptr; + wil::com_ptr certificate = nullptr; if (certificateCollectionCount > 0) { @@ -57,7 +59,7 @@ ScenarioClientCertificateRequested::ScenarioClientCertificateRequested(AppWindow CHECK_FAILURE(certificate->get_Issuer(&clientCertificate.Issuer)); - COREWEBVIEW2_CERTIFICATE_KIND Kind; + COREWEBVIEW2_CLIENT_CERTIFICATE_KIND Kind; CHECK_FAILURE( certificate->get_Kind(&Kind)); clientCertificate.CertificateKind = NameOfCertificateKind(Kind); @@ -107,9 +109,9 @@ ScenarioClientCertificateRequested::ScenarioClientCertificateRequested(AppWindow }); return S_OK; - }) - .Get(), - &m_ClientCertificateRequestedToken)); + }) + .Get(), + &m_ClientCertificateRequestedToken)); MessageBox( nullptr, L"Custom Client Certificate selection dialog will be used next when WebView2 " @@ -123,13 +125,13 @@ ScenarioClientCertificateRequested::ScenarioClientCertificateRequested(AppWindow //! [ClientCertificateRequested2] } -static PCWSTR NameOfCertificateKind(COREWEBVIEW2_CERTIFICATE_KIND kind) +static PCWSTR NameOfCertificateKind(COREWEBVIEW2_CLIENT_CERTIFICATE_KIND kind) { switch (kind) { - case COREWEBVIEW2_CERTIFICATE_KIND_SMART_CARD: + case COREWEBVIEW2_CLIENT_CERTIFICATE_KIND_SMART_CARD: return L"Smart Card"; - case COREWEBVIEW2_CERTIFICATE_KIND_PIN: + case COREWEBVIEW2_CLIENT_CERTIFICATE_KIND_PIN: return L"PIN"; default: return L"Other"; diff --git a/SampleApps/WebView2APISample/ScenarioCookieManagement.cpp b/SampleApps/WebView2APISample/ScenarioCookieManagement.cpp index 67b1f02f..691044b4 100644 --- a/SampleApps/WebView2APISample/ScenarioCookieManagement.cpp +++ b/SampleApps/WebView2APISample/ScenarioCookieManagement.cpp @@ -15,7 +15,7 @@ using namespace Microsoft::WRL; static constexpr WCHAR c_samplePath[] = L"ScenarioCookieManagement.html"; -ScenarioCookieManagement::ScenarioCookieManagement(AppWindow* appWindow) +ScenarioCookieManagement::ScenarioCookieManagement(AppWindow* appWindow, bool isFromProfile) : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) { m_sampleUri = m_appWindow->GetLocalUri(c_samplePath); @@ -24,12 +24,26 @@ ScenarioCookieManagement::ScenarioCookieManagement(AppWindow* appWindow) CHECK_FAILURE(m_webView->get_Settings(&settings)); CHECK_FAILURE(settings->put_IsWebMessageEnabled(TRUE)); - //! [CookieManager] - wil::com_ptr m_webview2; - CHECK_FAILURE(m_appWindow->GetWebView()->QueryInterface(IID_PPV_ARGS(&m_webview2))); - CHECK_FAILURE(m_webview2->get_CookieManager(&m_cookieManager)); - //! [CookieManager] - + if (isFromProfile) + { + //! [CookieManagerProfile] + auto webView2_13 = m_webView.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webView2_13); + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + auto webView2Profile5 = webView2Profile.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webView2Profile5); + CHECK_FAILURE(webView2Profile5->get_CookieManager(&m_cookieManager)); + //! [CookieManagerProfile] + } + else + { + //! [CookieManager] + auto webview2_2 = m_webView.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webview2_2); + CHECK_FAILURE(webview2_2->get_CookieManager(&m_cookieManager)); + //! [CookieManager] + } SetupEventsOnWebview(); CHECK_FAILURE(m_webView->Navigate(m_sampleUri.c_str())); @@ -224,7 +238,7 @@ void ScenarioCookieManagement::GetCookiesHelper(std::wstring uri) } result += L"]"; } - MessageBox(nullptr, result.c_str(), L"GetCookies Result", MB_OK); + m_appWindow->AsyncMessageBox(std::move(result), L"GetCookies Result"); return S_OK; }) .Get())); diff --git a/SampleApps/WebView2APISample/ScenarioCookieManagement.h b/SampleApps/WebView2APISample/ScenarioCookieManagement.h index b8bbb57d..8af2e2c3 100644 --- a/SampleApps/WebView2APISample/ScenarioCookieManagement.h +++ b/SampleApps/WebView2APISample/ScenarioCookieManagement.h @@ -13,7 +13,7 @@ class ScenarioCookieManagement : public ComponentBase { public: - ScenarioCookieManagement(AppWindow* appWindow); + ScenarioCookieManagement(AppWindow* appWindow, bool isFromProfile = false); ~ScenarioCookieManagement() override; private: diff --git a/SampleApps/WebView2APISample/ScenarioCustomScheme.cpp b/SampleApps/WebView2APISample/ScenarioCustomScheme.cpp new file mode 100644 index 00000000..0afdf737 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioCustomScheme.cpp @@ -0,0 +1,112 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "stdafx.h" + +#include "ScenarioCustomScheme.h" + +#include "AppWindow.h" +#include "CheckFailure.h" + +#include + +using namespace Microsoft::WRL; + +ScenarioCustomScheme::ScenarioCustomScheme(AppWindow* appWindow) : m_appWindow(appWindow) +{ + m_appWindow->GetWebView()->QueryInterface(IID_PPV_ARGS(&m_webView2_22)); + CHECK_FEATURE_RETURN_EMPTY(m_webView2_22); + CHECK_FAILURE(m_webView2_22->AddWebResourceRequestedFilterWithRequestSourceKinds( + L"custom-scheme*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL, + COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_DOCUMENT)); + CHECK_FAILURE(m_appWindow->GetWebView()->add_WebResourceRequested( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2WebResourceRequestedEventArgs* args) + { + wil::com_ptr request; + wil::com_ptr response; + CHECK_FAILURE(args->get_Request(&request)); + wil::unique_cotaskmem_string uri; + CHECK_FAILURE(request->get_Uri(&uri)); + if (wcsncmp(uri.get(), L"custom-scheme", ARRAYSIZE(L"custom-scheme") - 1) == 0) + { + std::wstring assetsFilePath = L"assets/"; + assetsFilePath += wcsstr(uri.get(), L":") + 1; + wil::com_ptr stream; + SHCreateStreamOnFileEx( + assetsFilePath.c_str(), STGM_READ, FILE_ATTRIBUTE_NORMAL, FALSE, + nullptr, &stream); + if (stream) + { + CHECK_FAILURE( + m_appWindow->GetWebViewEnvironment()->CreateWebResourceResponse( + stream.get(), 200, L"OK", + L"Content-Type: application/json\nAccess-Control-Allow-Origin: " + L"*", + &response)); + CHECK_FAILURE(args->put_Response(response.get())); + } + else + { + CHECK_FAILURE( + m_appWindow->GetWebViewEnvironment()->CreateWebResourceResponse( + nullptr, 404, L"Not Found", L"", &response)); + CHECK_FAILURE(args->put_Response(response.get())); + } + return S_OK; + } + + return S_OK; + }) + .Get(), + &m_webResourceRequestedToken)); + + m_appWindow->GetWebView()->add_NavigationCompleted( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2NavigationCompletedEventArgs* args) + { + // The following XHR will execute in the context of https://www.example.com page + // and will succeed. WebResourceRequested event will be raised for this request + // as *.example.com is in the allowed origin list of custom-scheme. Since the + // response header provided in WebResourceRequested handler allows all origins + // for CORS the XHR succeeds. + CHECK_FAILURE(m_appWindow->GetWebView()->ExecuteScript( + L"function reqListener(e) { console.log(e.data) };" + L"function errListener(e) { console.log(e.error) };" + L"var oReq = new XMLHttpRequest();" + L"oReq.addEventListener(\"load\", reqListener);" + L"oReq.addEventListener(\"error\", errListener);" + L"oReq.open(\"GET\", \"custom-scheme:ScenarioCustomScheme.json\");" + L"oReq.send();", + Callback( + [](HRESULT error, PCWSTR result) -> HRESULT { return S_OK; }) + .Get())); + // The following XHR will fail because *.example.com is not in the allowed + // origin list of custom-scheme-not-in-allowed-origins. The WebResourceRequested + // event will not be raised for this request. + CHECK_FAILURE(m_appWindow->GetWebView()->ExecuteScript( + L"var oReq = new XMLHttpRequest();" + L"oReq.addEventListener(\"load\", reqListener);" + L"oReq.addEventListener(\"error\", errListener);" + L"oReq.open(\"GET\", " + L"\"custom-scheme-not-in-allowed-origins://" + L"ScenarioCustomScheme.json\");" + L"oReq.send();", + Callback( + [](HRESULT error, PCWSTR result) -> HRESULT { return S_OK; }) + .Get())); + CHECK_FAILURE(m_appWindow->GetWebView()->remove_NavigationCompleted( + m_navigationCompletedToken)); + m_navigationCompletedToken = {0}; + return S_OK; + }) + .Get(), + &m_navigationCompletedToken); + m_appWindow->GetWebView()->Navigate(L"https://www.example.com"); +} + +ScenarioCustomScheme::~ScenarioCustomScheme() +{ + CHECK_FAILURE( + m_appWindow->GetWebView()->remove_WebResourceRequested(m_webResourceRequestedToken)); +} diff --git a/SampleApps/WebView2APISample/ScenarioCustomScheme.h b/SampleApps/WebView2APISample/ScenarioCustomScheme.h new file mode 100644 index 00000000..1b617c41 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioCustomScheme.h @@ -0,0 +1,26 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once +#include "stdafx.h" + +#include + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioCustomScheme : public ComponentBase +{ +public: + ScenarioCustomScheme(AppWindow* appWindow); + ~ScenarioCustomScheme() override; + +private: + EventRegistrationToken m_webResourceRequestedToken = {}; + EventRegistrationToken m_navigationCompletedToken = {}; + + wil::com_ptr m_webView2_22; + + AppWindow* m_appWindow = nullptr; +}; diff --git a/SampleApps/WebView2APISample/ScenarioCustomSchemeNavigate.cpp b/SampleApps/WebView2APISample/ScenarioCustomSchemeNavigate.cpp new file mode 100644 index 00000000..ce911d3d --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioCustomSchemeNavigate.cpp @@ -0,0 +1,105 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "stdafx.h" + +#include "ScenarioCustomSchemeNavigate.h" + +#include "AppWindow.h" +#include "CheckFailure.h" + +#include + +using namespace Microsoft::WRL; + +ScenarioCustomSchemeNavigate::ScenarioCustomSchemeNavigate(AppWindow* appWindow) + : m_appWindow(appWindow) +{ + m_appWindow->GetWebView()->QueryInterface(IID_PPV_ARGS(&m_webView2_22)); + CHECK_FEATURE_RETURN_EMPTY(m_webView2_22); + CHECK_FAILURE(m_webView2_22->AddWebResourceRequestedFilterWithRequestSourceKinds( + L"wv2rocks*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL, + COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_DOCUMENT)); + CHECK_FAILURE(m_appWindow->GetWebView()->add_WebResourceRequested( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2WebResourceRequestedEventArgs* args) + { + wil::com_ptr request; + wil::com_ptr response; + CHECK_FAILURE(args->get_Request(&request)); + wil::com_ptr content; + request->get_Content(&content); + wil::unique_cotaskmem_string uri; + CHECK_FAILURE(request->get_Uri(&uri)); + if (wcsncmp( + uri.get(), L"wv2rocks://domain/", + ARRAYSIZE(L"wv2rocks://domain/") - 1) == 0) + { + std::wstring assetsFilePath = L"assets/"; + assetsFilePath += + wcsstr(uri.get(), L"://domain/") + ARRAYSIZE(L"://domain/") - 1; + wil::com_ptr stream; + SHCreateStreamOnFileEx( + assetsFilePath.c_str(), STGM_READ, FILE_ATTRIBUTE_NORMAL, FALSE, + nullptr, &stream); + if (stream) + { + std::wstring headers; + if (assetsFilePath.substr(assetsFilePath.find_last_of(L".") + 1) == + L"html") + { + headers = L"Content-Type: text/html"; + } + else if ( + assetsFilePath.substr(assetsFilePath.find_last_of(L".") + 1) == + L"jpg") + { + headers = L"Content-Type: image/jpeg"; + } + else if ( + assetsFilePath.substr(assetsFilePath.find_last_of(L".") + 1) == + L"png") + { + headers = L"Content-Type: image/png"; + } + else if ( + assetsFilePath.substr(assetsFilePath.find_last_of(L".") + 1) == + L"css") + { + headers = L"Content-Type: text/css"; + } + else if ( + assetsFilePath.substr(assetsFilePath.find_last_of(L".") + 1) == + L"js") + { + headers = L"Content-Type: application/javascript"; + } + + CHECK_FAILURE( + m_appWindow->GetWebViewEnvironment()->CreateWebResourceResponse( + stream.get(), 200, L"OK", headers.c_str(), &response)); + CHECK_FAILURE(args->put_Response(response.get())); + } + else + { + CHECK_FAILURE( + m_appWindow->GetWebViewEnvironment()->CreateWebResourceResponse( + nullptr, 404, L"Not Found", L"", &response)); + CHECK_FAILURE(args->put_Response(response.get())); + } + return S_OK; + } + + return S_OK; + }) + .Get(), + &m_webResourceRequestedToken)); + + m_appWindow->GetWebView()->Navigate(L"wv2rocks://domain/ScenarioCustomScheme.html"); +} + +ScenarioCustomSchemeNavigate::~ScenarioCustomSchemeNavigate() +{ + CHECK_FAILURE( + m_appWindow->GetWebView()->remove_WebResourceRequested(m_webResourceRequestedToken)); +} diff --git a/SampleApps/WebView2APISample/ScenarioCustomSchemeNavigate.h b/SampleApps/WebView2APISample/ScenarioCustomSchemeNavigate.h new file mode 100644 index 00000000..7eec6232 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioCustomSchemeNavigate.h @@ -0,0 +1,26 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once +#include "stdafx.h" + +#include + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioCustomSchemeNavigate : public ComponentBase +{ +public: + ScenarioCustomSchemeNavigate(AppWindow* appWindow); + ~ScenarioCustomSchemeNavigate() override; + +private: + EventRegistrationToken m_webResourceRequestedToken = {}; + EventRegistrationToken m_navigationCompletedToken = {}; + + AppWindow* m_appWindow = nullptr; + + wil::com_ptr m_webView2_22; +}; diff --git a/SampleApps/WebView2APISample/ScenarioDedicatedWorker.cpp b/SampleApps/WebView2APISample/ScenarioDedicatedWorker.cpp new file mode 100644 index 00000000..83616ed1 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDedicatedWorker.cpp @@ -0,0 +1,129 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "CheckFailure.h" +#include "ScenarioDedicatedWorker.h" + +using namespace Microsoft::WRL; + +ScenarioDedicatedWorker::ScenarioDedicatedWorker(AppWindow* appWindow) : m_appWindow(appWindow) +{ + //! [DedicatedWorkerCreated] + m_appWindow->GetWebView()->QueryInterface(IID_PPV_ARGS(&m_webView2Experimental_30)); + CHECK_FEATURE_RETURN_EMPTY(m_webView2Experimental_30); + + CHECK_FAILURE(m_webView2Experimental_30->add_DedicatedWorkerCreated( + Callback( + [this]( + ICoreWebView2* sender, + ICoreWebView2ExperimentalDedicatedWorkerCreatedEventArgs* args) + { + wil::com_ptr dedicatedWorker; + CHECK_FAILURE(args->get_Worker(&dedicatedWorker)); + + wil::unique_cotaskmem_string scriptUri; + CHECK_FAILURE(dedicatedWorker->get_ScriptUri(&scriptUri)); + + std::wstring scriptUriStr(scriptUri.get()); + m_appWindow->AsyncMessageBox(scriptUriStr, L"Dedicated worker is created"); + + // Subscribe to worker destroying event + dedicatedWorker->add_Destroying( + Callback( + [this, scriptUriStr]( + ICoreWebView2ExperimentalDedicatedWorker* sender, + IUnknown* args) -> HRESULT + { + /*Cleanup on worker destruction*/ + m_appWindow->AsyncMessageBox( + scriptUriStr, L"Dedicated worker is destroyed"); + return S_OK; + }) + .Get(), + nullptr); + + return S_OK; + }) + .Get(), + &m_dedicatedWorkerCreatedToken)); + //! [DedicatedWorkerCreated] + + wil::com_ptr m_webView2_4; + m_appWindow->GetWebView()->QueryInterface(IID_PPV_ARGS(&m_webView2_4)); + CHECK_FEATURE_RETURN_EMPTY(m_webView2_4); + + CHECK_FAILURE(m_webView2_4->add_FrameCreated( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args) -> HRESULT + { + wil::com_ptr webviewFrame; + CHECK_FAILURE(args->get_Frame(&webviewFrame)); + + wil::com_ptr m_frameExperimental_9 = + webviewFrame.try_query(); + + m_frameExperimental_9->add_DedicatedWorkerCreated( + Callback( + [this]( + ICoreWebView2Frame* sender, + ICoreWebView2ExperimentalDedicatedWorkerCreatedEventArgs* args) + -> HRESULT + { + // frameInfo that created the worker. + wil::com_ptr frameInfo; + CHECK_FAILURE(args->get_OriginalSourceFrameInfo(&frameInfo)); + + wil::com_ptr frameInfo2; + CHECK_FAILURE(frameInfo->QueryInterface(IID_PPV_ARGS(&frameInfo2))); + + wil::unique_cotaskmem_string frameSource; + CHECK_FAILURE(frameInfo->get_Source(&frameSource)); + + UINT32 source_frameId; + CHECK_FAILURE(frameInfo2->get_FrameId(&source_frameId)); + + wil::com_ptr + dedicatedWorker; + CHECK_FAILURE(args->get_Worker(&dedicatedWorker)); + + wil::unique_cotaskmem_string scriptUri; + CHECK_FAILURE(dedicatedWorker->get_ScriptUri(&scriptUri)); + + std::wstring scriptUriStr(scriptUri.get()); + m_appWindow->AsyncMessageBox( + scriptUriStr, L"Dedicated worker is created"); + + // Subscribe to worker destroying event + dedicatedWorker->add_Destroying( + Callback< + ICoreWebView2ExperimentalDedicatedWorkerDestroyingEventHandler>( + [this, scriptUriStr]( + ICoreWebView2ExperimentalDedicatedWorker* sender, + IUnknown* args) -> HRESULT + { + /*Cleanup on worker destruction*/ + m_appWindow->AsyncMessageBox( + scriptUriStr, L"Dedicated worker is destroyed"); + return S_OK; + }) + .Get(), + nullptr); + + return S_OK; + }) + .Get(), + nullptr); + + return S_OK; + }) + .Get(), + nullptr)); +} + +ScenarioDedicatedWorker::~ScenarioDedicatedWorker() +{ + m_webView2Experimental_30->remove_DedicatedWorkerCreated(m_dedicatedWorkerCreatedToken); +} diff --git a/SampleApps/WebView2APISample/ScenarioDedicatedWorker.h b/SampleApps/WebView2APISample/ScenarioDedicatedWorker.h new file mode 100644 index 00000000..9c206e9c --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDedicatedWorker.h @@ -0,0 +1,20 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioDedicatedWorker : public ComponentBase +{ +public: + ScenarioDedicatedWorker(AppWindow* appWindow); + ~ScenarioDedicatedWorker() override; + +private: + AppWindow* m_appWindow; + wil::com_ptr m_webView2Experimental_30; + EventRegistrationToken m_dedicatedWorkerCreatedToken = {}; +}; diff --git a/SampleApps/WebView2APISample/ScenarioDedicatedWorkerPostMessage.cpp b/SampleApps/WebView2APISample/ScenarioDedicatedWorkerPostMessage.cpp new file mode 100644 index 00000000..7e088899 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDedicatedWorkerPostMessage.cpp @@ -0,0 +1,123 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" +#include + +#include "CheckFailure.h" +#include "TextInputDialog.h" + +#include "ScenarioDedicatedWorkerPostMessage.h" + +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = L"ScenarioDedicatedWorkerPostMessage.html"; + +ScenarioDedicatedWorkerPostMessage::ScenarioDedicatedWorkerPostMessage(AppWindow* appWindow) + : m_appWindow(appWindow) +{ + //! [DedicatedWorkerCreated] + m_appWindow->GetWebView()->QueryInterface(IID_PPV_ARGS(&m_webView2Experimental_30)); + CHECK_FEATURE_RETURN_EMPTY(m_webView2Experimental_30); + + CHECK_FAILURE(m_webView2Experimental_30->add_DedicatedWorkerCreated( + Callback( + [this]( + ICoreWebView2* sender, + ICoreWebView2ExperimentalDedicatedWorkerCreatedEventArgs* args) + { + wil::com_ptr dedicatedWorker; + CHECK_FAILURE(args->get_Worker(&dedicatedWorker)); + + wil::unique_cotaskmem_string scriptUri; + CHECK_FAILURE(dedicatedWorker->get_ScriptUri(&scriptUri)); + + std::wstring scriptUriStr(scriptUri.get()); + m_appWindow->AsyncMessageBox(scriptUriStr, L"Dedicated worker is created"); + + SetupEventsOnDedicatedWorker(dedicatedWorker); + ComputeWithDedicatedWorker(dedicatedWorker); + + return S_OK; + }) + .Get(), + &m_dedicatedWorkerCreatedToken)); + //! [DedicatedWorkerCreated] + + // Turn off this scenario if we navigate away from the sample page. + CHECK_FAILURE(m_appWindow->GetWebView()->add_ContentLoading( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2ContentLoadingEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string uri; + sender->get_Source(&uri); + if (uri.get() != m_sampleUri) + { + m_appWindow->DeleteComponent(this); + } + return S_OK; + }) + .Get(), + &m_contentLoadingToken)); + + m_sampleUri = m_appWindow->GetLocalUri(c_samplePath); + CHECK_FAILURE(m_appWindow->GetWebView()->Navigate(m_sampleUri.c_str())); +} + +void ScenarioDedicatedWorkerPostMessage::SetupEventsOnDedicatedWorker( + wil::com_ptr dedicatedWorker) +{ + //! [WebMessageReceived] + dedicatedWorker->add_WebMessageReceived( + Callback( + [this]( + ICoreWebView2ExperimentalDedicatedWorker* sender, + ICoreWebView2WebMessageReceivedEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string scriptUri; + CHECK_FAILURE(args->get_Source(&scriptUri)); + + wil::unique_cotaskmem_string messageRaw; + CHECK_FAILURE(args->TryGetWebMessageAsString(&messageRaw)); + std::wstring messageFromWorker = messageRaw.get(); + + std::wstringstream message{}; + message << L"Dedicated Worker: " << std::endl << scriptUri.get() << std::endl; + message << std::endl; + message << L"Message: " << std::endl << messageFromWorker << std::endl; + m_appWindow->AsyncMessageBox(message.str(), L"Message from Dedicated Worker"); + + return S_OK; + }) + .Get(), + nullptr); + //! [WebMessageReceived] +} + +void ScenarioDedicatedWorkerPostMessage::ComputeWithDedicatedWorker( + wil::com_ptr dedicatedWorker) +{ + //! [PostWebMessageAsJson] + // Do not block from event handler + m_appWindow->RunAsync( + [this, dedicatedWorker] + { + TextInputDialog dialog( + m_appWindow->GetMainWindow(), L"Post Web Message JSON", L"Web message JSON", + L"Enter the web message as JSON.", + L"{\"command\":\"ADD\",\"first\":2,\"second\":3}"); + // Ex: {"command":"ADD","first":2,"second":3} + if (dialog.confirmed) + { + dedicatedWorker->PostWebMessageAsJson(dialog.input.c_str()); + } + }); + //! [PostWebMessageAsJson] +} + +ScenarioDedicatedWorkerPostMessage::~ScenarioDedicatedWorkerPostMessage() +{ + m_webView2Experimental_30->remove_DedicatedWorkerCreated(m_dedicatedWorkerCreatedToken); + m_appWindow->GetWebView()->remove_ContentLoading(m_contentLoadingToken); +} diff --git a/SampleApps/WebView2APISample/ScenarioDedicatedWorkerPostMessage.h b/SampleApps/WebView2APISample/ScenarioDedicatedWorkerPostMessage.h new file mode 100644 index 00000000..c465679f --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDedicatedWorkerPostMessage.h @@ -0,0 +1,27 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioDedicatedWorkerPostMessage : public ComponentBase +{ +public: + ScenarioDedicatedWorkerPostMessage(AppWindow* appWindow); + ~ScenarioDedicatedWorkerPostMessage() override; + +private: + void SetupEventsOnDedicatedWorker( + wil::com_ptr dedicatedWorker); + void ComputeWithDedicatedWorker( + wil::com_ptr dedicatedWorker); + + AppWindow* m_appWindow; + wil::com_ptr m_webView2Experimental_30; + std::wstring m_sampleUri; + EventRegistrationToken m_contentLoadingToken = {}; + EventRegistrationToken m_dedicatedWorkerCreatedToken = {}; +}; diff --git a/SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.cpp b/SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.cpp new file mode 100644 index 00000000..33491f75 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.cpp @@ -0,0 +1,28 @@ +#include "stdafx.h" + +#include "AppWindow.h" +#include "CheckFailure.h" +#include "ScenarioDefaultBackgroundColor.h" +#include +#include + +using namespace Microsoft::WRL; +using namespace std; + +static constexpr wchar_t c_samplePath[] = L"ScenarioDefaultBackgroundColor.html"; + +ScenarioDefaultBackgroundColor::ScenarioDefaultBackgroundColor(AppWindow* appWindow) +{ + std::wstring sampleUri = appWindow->GetLocalUri(c_samplePath); + WebViewCreateOption options = appWindow->GetWebViewOption(); + + options.bg_color = {255, 225, 0, 225}; + AppWindow* appWindowWco = new AppWindow(appWindow->GetCreationModeId(), options, sampleUri); + // Delete this component when the window closes. + appWindowWco->SetOnAppWindowClosing([this, appWindow] + { appWindow->DeleteComponent(this); }); +} + +ScenarioDefaultBackgroundColor::~ScenarioDefaultBackgroundColor() +{ +} \ No newline at end of file diff --git a/SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.h b/SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.h new file mode 100644 index 00000000..2c71f0ff --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.h @@ -0,0 +1,17 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "stdafx.h" + +#include "ComponentBase.h" +#include + +class ScenarioDefaultBackgroundColor : public ComponentBase +{ +public: + ScenarioDefaultBackgroundColor(AppWindow* appWindow); + ~ScenarioDefaultBackgroundColor() override; +}; diff --git a/SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.html b/SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.html new file mode 100644 index 00000000..bcda4fdc --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.html @@ -0,0 +1,11 @@ + + + + + + WebView with CoreWebViewControllerOptions.DefaultBackgroundColor + + +

CoreWebViewControllerOptions.DefaultBackgroundColor

+ + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/ScenarioDragDrop.cpp b/SampleApps/WebView2APISample/ScenarioDragDrop.cpp new file mode 100644 index 00000000..e8045bda --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDragDrop.cpp @@ -0,0 +1,87 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "stdafx.h" + +#include "ScenarioDragDrop.h" + +#include "AppWindow.h" +#include "CheckFailure.h" + +#include + +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = L"ScenarioDragDrop.html"; + +ScenarioDragDrop::ScenarioDragDrop(AppWindow* appWindow) : m_appWindow(appWindow) +{ + m_webView = m_appWindow->GetWebView(); + + //! [DroppedFilePath] + CHECK_FAILURE(m_webView->add_WebMessageReceived( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) + { + wil::com_ptr args2 = + wil::com_ptr(args) + .query(); + wil::com_ptr objectsCollection; + args2->get_AdditionalObjects(&objectsCollection); + unsigned int length; + objectsCollection->get_Count(&length); + + // Array of file paths to be sent back to the webview as JSON + std::wstring pathObjects = L"["; + for (unsigned int i = 0; i < length; i++) + { + wil::com_ptr object; + objectsCollection->GetValueAtIndex(i, &object); + + wil::com_ptr file = object.query(); + if (file) + { + // Add the file to message to be sent back to webview + wil::unique_cotaskmem_string path; + file->get_Path(&path); + std::wstring pathObject = + L"{\"path\":\"" + std::wstring(path.get()) + L"\"}"; + // Escape backslashes + std::wstring pathObjectEscaped; + for (const auto& c : pathObject) + { + if (c == L'\\') + { + pathObjectEscaped += L"\\\\"; + } + else + { + pathObjectEscaped += c; + } + } + pathObjects += pathObjectEscaped; + + if (i < length - 1) + { + pathObjects += L","; + } + } + } + pathObjects += L"]"; + + // Post the message back to the webview so path is accessible to content + m_webView->PostWebMessageAsJson(pathObjects.c_str()); + + return S_OK; + }) + .Get(), + &m_webMessageReceivedToken)); + //! [DroppedFilePath] + + CHECK_FAILURE(m_webView->Navigate(m_appWindow->GetLocalUri(c_samplePath).c_str())); +} + +ScenarioDragDrop::~ScenarioDragDrop() +{ + CHECK_FAILURE(m_webView->remove_WebMessageReceived(m_webMessageReceivedToken)); +} \ No newline at end of file diff --git a/SampleApps/WebView2APISample/ScenarioDragDrop.h b/SampleApps/WebView2APISample/ScenarioDragDrop.h new file mode 100644 index 00000000..152bd8b4 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDragDrop.h @@ -0,0 +1,22 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once +#include "stdafx.h" + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioDragDrop : public ComponentBase +{ +public: + ScenarioDragDrop(AppWindow* appWindow); + ~ScenarioDragDrop() override; + +private: + EventRegistrationToken m_webMessageReceivedToken = {}; + + AppWindow* m_appWindow = nullptr; + wil::com_ptr m_webView = nullptr; +}; diff --git a/SampleApps/WebView2APISample/ScenarioDragDropOverride.cpp b/SampleApps/WebView2APISample/ScenarioDragDropOverride.cpp new file mode 100644 index 00000000..7215f5b6 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDragDropOverride.cpp @@ -0,0 +1,134 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "stdafx.h" + +#include "CheckFailure.h" + +#include "ScenarioDragDropOverride.h" +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = L"ScenarioDragDropOverride.html"; +static constexpr WCHAR c_webmessageDefault[] = L"default"; +static constexpr WCHAR c_webmessageOverride[] = L"override"; +static constexpr WCHAR c_webmessageNoop[] = L"noop"; + +ScenarioDragDropOverride::ScenarioDragDropOverride(AppWindow* appWindow) + : m_appWindow(appWindow) +{ + m_sampleUri = m_appWindow->GetLocalUri(c_samplePath); + m_webView = m_appWindow->GetWebView(); + wil::com_ptr controller = appWindow->GetWebViewController(); + wil::com_ptr compController = + controller.try_query(); + if (!compController) + { + return; + } + + m_compController5 = compController.try_query(); + if (!m_compController5) + { + return; + } + + CHECK_FAILURE(m_webView->add_WebMessageReceived( + Microsoft::WRL::Callback( + [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) + { + wil::unique_cotaskmem_string uri; + CHECK_FAILURE(args->get_Source(&uri)); + + // Always validate that the origin of the message is what you expect. + if (uri.get() != m_sampleUri) + { + return S_OK; + } + wil::unique_cotaskmem_string messageRaw; + CHECK_FAILURE(args->TryGetWebMessageAsString(&messageRaw)); + std::wstring message = messageRaw.get(); + + if (message == c_webmessageDefault) + { + m_dragOverrideMode = DragOverrideMode::DEFAULT; + } + else if (message == c_webmessageOverride) + { + m_dragOverrideMode = DragOverrideMode::OVERRIDE; + } + else if (message == c_webmessageNoop) + { + m_dragOverrideMode = DragOverrideMode::NOOP; + } + + return S_OK; + }) + .Get(), + &m_webMessageReceivedToken)); + + //! [DragStarting] + // Using DragStarting to simply make a synchronous DoDragDrop call instead of + // having WebView2 do it. + CHECK_FAILURE(m_compController5->add_DragStarting( + Callback( + [this]( + ICoreWebView2CompositionController* sender, + ICoreWebView2DragStartingEventArgs* args) + { + if (m_dragOverrideMode != DragOverrideMode::OVERRIDE) + { + // If the event is marked handled, WebView2 will not execute its drag logic. + args->put_Handled(m_dragOverrideMode == DragOverrideMode::NOOP); + return S_OK; + } + + wil::com_ptr dragData; + DWORD okEffects = DROPEFFECT_NONE; + CHECK_FAILURE(args->get_AllowedDropEffects(&okEffects)); + CHECK_FAILURE(args->get_Data(&dragData)); + + // This member refers to an implementation of IDropSource. It is an + // OLE interface that is necessary to initiate drag in an application. + // https://learn.microsoft.com/en-us/windows/win32/api/oleidl/nn-oleidl-idropsource + if (!m_dropSource) + { + m_dropSource = Make(); + } + + DWORD effect = DROPEFFECT_NONE; + HRESULT hr = DoDragDrop(dragData.get(), m_dropSource.get(), okEffects, &effect); + args->put_Handled(TRUE); + + return hr; + }) + .Get(), + &m_dragStartingToken)); + //! [DragStarting] + + CHECK_FAILURE(m_webView->add_ContentLoading( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2ContentLoadingEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string uri; + sender->get_Source(&uri); + if (uri.get() != m_sampleUri) + { + m_appWindow->DeleteComponent(this); + } + return S_OK; + }) + .Get(), + &m_contentLoadingToken)); + + CHECK_FAILURE(m_webView->Navigate(m_sampleUri.c_str())); +} + +ScenarioDragDropOverride::~ScenarioDragDropOverride() +{ + if (m_compController5) + { + CHECK_FAILURE(m_compController5->remove_DragStarting(m_dragStartingToken)); + } + CHECK_FAILURE(m_webView->remove_WebMessageReceived(m_webMessageReceivedToken)); + CHECK_FAILURE(m_webView->remove_ContentLoading(m_contentLoadingToken)); +} diff --git a/SampleApps/WebView2APISample/ScenarioDragDropOverride.h b/SampleApps/WebView2APISample/ScenarioDragDropOverride.h new file mode 100644 index 00000000..564033df --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDragDropOverride.h @@ -0,0 +1,61 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once +#include "stdafx.h" + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioDragDropOverride : public ComponentBase +{ +public: + ScenarioDragDropOverride(AppWindow* appWindow); + ~ScenarioDragDropOverride() override; + +private: + // Barebones IDropSource implementation to serve the example drag drop override. + class ScenarioDragDropOverrideDropSource + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags, IDropSource> + { + public: + // IDropSource implementation: + STDMETHODIMP QueryContinueDrag(BOOL escapePressed, DWORD keyState) override + { + if (escapePressed) + { + return DRAGDROP_S_CANCEL; + } + if (!(keyState & (MK_LBUTTON | MK_RBUTTON))) + { + return DRAGDROP_S_DROP; + } + return S_OK; + } + + STDMETHODIMP GiveFeedback(DWORD dwEffect) override + { + return DRAGDROP_S_USEDEFAULTCURSORS; + } + }; + + enum class DragOverrideMode + { + DEFAULT = 0, + OVERRIDE = 1, + NOOP = 2, + }; + + EventRegistrationToken m_dragStartingToken = {}; + EventRegistrationToken m_webMessageReceivedToken = {}; + EventRegistrationToken m_contentLoadingToken = {}; + + AppWindow* m_appWindow = nullptr; + std::wstring m_sampleUri; + wil::com_ptr m_webView = nullptr; + wil::com_ptr m_compController5; + wil::com_ptr m_dropSource; + DragOverrideMode m_dragOverrideMode = DragOverrideMode::DEFAULT; +}; \ No newline at end of file diff --git a/SampleApps/WebView2APISample/ScenarioExtensionsManagement.cpp b/SampleApps/WebView2APISample/ScenarioExtensionsManagement.cpp new file mode 100644 index 00000000..392a4708 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioExtensionsManagement.cpp @@ -0,0 +1,186 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "ScenarioExtensionsManagement.h" + +#include "AppWindow.h" +#include "CheckFailure.h" +#include + +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = L"extensions/example-devtools-extension"; +ScenarioExtensionsManagement::ScenarioExtensionsManagement(AppWindow* appWindow, bool offload) + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) +{ + if (!offload) + { + InstallDefaultExtensions(); + } + else + { + OffloadDefaultExtensionsIfExtraExtensionsInstalled(); + } +} + +void ScenarioExtensionsManagement::InstallDefaultExtensions() +{ + auto webView2_13 = m_webView.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webView2_13); + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + auto profile7 = webView2Profile.try_query(); + CHECK_FEATURE_RETURN_EMPTY(profile7); + + std::wstring extension_path_file = m_appWindow->GetLocalUri(c_samplePath, false); + // Remove "file:///" from the beginning of extension_path_file + std::wstring extension_path = extension_path_file.substr(8); + + profile7->GetBrowserExtensions( + Callback( + [this, profile7, extension_path]( + HRESULT error, ICoreWebView2BrowserExtensionList* extensions) -> HRESULT + { + std::wstring extensionIdString; + bool extensionInstalled = false; + UINT extensionsCount = 0; + extensions->get_Count(&extensionsCount); + + for (UINT index = 0; index < extensionsCount; ++index) + { + wil::com_ptr extension; + extensions->GetValueAtIndex(index, &extension); + + wil::unique_cotaskmem_string id; + wil::unique_cotaskmem_string name; + BOOL enabled = false; + std::wstring message; + + extension->get_IsEnabled(&enabled); + extension->get_Id(&id); + extension->get_Name(&name); + extensionIdString = id.get(); + + if (extensionIdString.compare(m_extensionId) == 0) + { + extensionInstalled = true; + message += L"Extension already installed"; + if (enabled) + { + message += L" and enabled."; + } + else + { + message += L" but was disabled."; + extension->Enable( + !enabled, + Callback( + [](HRESULT error) -> HRESULT + { + if (error != S_OK) + { + ShowFailure(error, L"Enable Extension failed"); + } + return S_OK; + }) + .Get()); + message += L" Extension has now been enabled."; + } + MessageBox(nullptr, message.c_str(), name.get(), MB_OK); + break; + } + } + + if (!extensionInstalled) + { + CHECK_FAILURE(profile7->AddBrowserExtension( + extension_path.c_str(), + Callback( + [](HRESULT error, + ICoreWebView2BrowserExtension* extension) -> HRESULT + { + if (error != S_OK) + { + ShowFailure(error, L"Fail to add browser extension"); + return S_OK; + } + + wil::unique_cotaskmem_string name; + extension->get_Name(&name); + + MessageBox( + nullptr, + L"Extension was not installed, has now been installed and " + L"enabled.", + name.get(), MB_OK); + return S_OK; + }) + .Get())); + } + return S_OK; + }) + .Get()); +} + +void ScenarioExtensionsManagement::OffloadDefaultExtensionsIfExtraExtensionsInstalled() +{ + auto webView2_13 = m_webView.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webView2_13); + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + auto profile7 = webView2Profile.try_query(); + CHECK_FEATURE_RETURN_EMPTY(profile7); + + profile7->GetBrowserExtensions( + Callback( + [this](HRESULT error, ICoreWebView2BrowserExtensionList* extensions) -> HRESULT + { + std::wstring extensionIdString; + UINT extensionsCount = 0; + extensions->get_Count(&extensionsCount); + + if (extensionsCount > m_maxInstalledExtensions) + { + for (UINT index = 0; index < extensionsCount; ++index) + { + wil::com_ptr extension; + extensions->GetValueAtIndex(index, &extension); + + wil::unique_cotaskmem_string id; + extension->get_Id(&id); + extensionIdString = id.get(); + + if (extensionIdString.compare(m_extensionId) == 0) + { + extension->Remove( + Callback( + [extension](HRESULT error) -> HRESULT + { + if (error != S_OK) + { + ShowFailure(error, L"Remove Extension failed"); + } + wil::unique_cotaskmem_string name; + extension->get_Name(&name); + MessageBox( + nullptr, + L"Extension was installed, but has now been " + L"removed.", + name.get(), MB_OK); + return S_OK; + }) + .Get()); + } + } + } + else + { + MessageBox(nullptr, L"No extra extensions to offload.", L"OK", MB_OK); + } + return S_OK; + }) + .Get()); +} \ No newline at end of file diff --git a/SampleApps/WebView2APISample/ScenarioExtensionsManagement.h b/SampleApps/WebView2APISample/ScenarioExtensionsManagement.h new file mode 100644 index 00000000..97a4187d --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioExtensionsManagement.h @@ -0,0 +1,54 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once +#include "stdafx.h" + +#include + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioExtensionsManagement : public ComponentBase +{ +public: + ScenarioExtensionsManagement(AppWindow* appWindow, bool offload); + +private: + // If this scenario is run, then the user is choosing to install all default extensions. + // Any extension marked as default would be installed if it is not already installed. + // If it is already installed but is disabled, it would be enabled. If it is already + // installed and enabled, then there is no work to be done. The user can also manually + // install any extension marked as default. This scenario is just a way to install and + // enable all default extensions (if not already installed and enabled). + void InstallDefaultExtensions(); + + // If this scenario is run, then the user is choosing to offload default extensions. + // These default extensions would only be removed if there are too many extensions + // installed. In the case of this scenario, "too many extensions" is considered to be more + // than `m_maxInstalledExtensions` which is set to 2, however this is just a simplified way + // to indicate having too many extensions installed. The user can manually remove any + // extensions before running the scenario. When the scenario is run, if the number of + // installed extensions is less than or equal to `m_maxInstalledExtensions`, then none of + // them would be offloaded (regardless of whether any of those extensions are marked as + // default). If more than `m_maxInstalledExtensions` extensions are installed, then all + // default extensions would be offloaded since we have the case of "too many extensions". + void OffloadDefaultExtensionsIfExtraExtensionsInstalled(); + + AppWindow* m_appWindow; + wil::com_ptr m_webViewEnvironment; + wil::com_ptr m_webView; + + // This extension ID is for the "Example DevTools Extension" located under + // assets/extensions. This extension is treated as the default extension for the + // `InstallDefaultExtensions` and `OffloadDefaultExtensionsIfExtraExtensionsInstalled` + // scenarios. + const std::wstring m_extensionId = L"apaahjmopbjicnjjcnionchiganhjpcd"; + + // `m_maxInstalledExtensions` is considered to be the maximum number of extensions we can + // have installed, before we have the case of "too many extensions". If we have too many + // extensions, then the `OffloadDefaultExtensionsIfExtraExtensionsInstalled` scenario + // offloads the default extensions. + const UINT m_maxInstalledExtensions = 2; +}; diff --git a/SampleApps/WebView2APISample/ScenarioFileSystemHandleShare.cpp b/SampleApps/WebView2APISample/ScenarioFileSystemHandleShare.cpp new file mode 100644 index 00000000..16604e9f --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioFileSystemHandleShare.cpp @@ -0,0 +1,74 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "stdafx.h" + +#include "ScenarioFileSystemHandleShare.h" + +#include "AppWindow.h" +#include "CheckFailure.h" + +#include + +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = L"ScenarioFileSystemHandleShare.html"; + +extern wil::unique_bstr GetDomainOfUri(PWSTR uri); + +//! [PostWebMessageWithAdditionalObjects] +ScenarioFileSystemHandleShare::ScenarioFileSystemHandleShare(AppWindow* appWindow) + : m_appWindow(appWindow) +{ + m_webView = m_appWindow->GetWebView(); + + CHECK_FAILURE(m_webView->Navigate(m_appWindow->GetLocalUri(c_samplePath).c_str())); + + CHECK_FAILURE(m_webView->add_NavigationCompleted( + Callback( + [this, appWindow]( + ICoreWebView2* sender, + ICoreWebView2NavigationCompletedEventArgs* args) -> HRESULT + { + wil::com_ptr webview23 = + m_webView.try_query(); + CHECK_FEATURE_RETURN_HRESULT(webview23); + wil::com_ptr environment = + appWindow->GetWebViewEnvironment(); + wil::com_ptr + environment14 = + environment.try_query(); + CHECK_FEATURE_RETURN_HRESULT(environment14); + wil::com_ptr rootHandle; + CHECK_FAILURE(environment14->CreateWebFileSystemDirectoryHandle( + L"C:\\", COREWEBVIEW2_FILE_SYSTEM_HANDLE_PERMISSION_READ_ONLY, + &rootHandle)); + wil::com_ptr webObjectCollection; + IUnknown* webObjects[] = {rootHandle.get()}; + CHECK_FAILURE(environment14->CreateObjectCollection( + ARRAYSIZE(webObjects), webObjects, &webObjectCollection)); + wil::unique_cotaskmem_string source; + CHECK_FAILURE(m_webView->get_Source(&source)); + + static const wchar_t* expectedDomain = L"appassets.example"; + wil::unique_bstr sourceDomain = GetDomainOfUri(source.get()); + + // Check the source to ensure the message is sent to the correct target content. + if (std::wstring(expectedDomain) == sourceDomain.get()) + { + CHECK_FAILURE(webview23->PostWebMessageAsJsonWithAdditionalObjects( + L"{ \"messageType\" : \"RootDirectoryHandle\" }", + webObjectCollection.get())); + } + + return S_OK; + }) + .Get(), + &m_navigationCompletedToken)); +} +//! [PostWebMessageWithAdditionalObjects] + +ScenarioFileSystemHandleShare::~ScenarioFileSystemHandleShare() +{ + CHECK_FAILURE(m_webView->remove_WebMessageReceived(m_navigationCompletedToken)); +} \ No newline at end of file diff --git a/SampleApps/WebView2APISample/ScenarioFileSystemHandleShare.h b/SampleApps/WebView2APISample/ScenarioFileSystemHandleShare.h new file mode 100644 index 00000000..7e986148 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioFileSystemHandleShare.h @@ -0,0 +1,22 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once +#include "stdafx.h" + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioFileSystemHandleShare : public ComponentBase +{ +public: + ScenarioFileSystemHandleShare(AppWindow* appWindow); + ~ScenarioFileSystemHandleShare() override; + +private: + EventRegistrationToken m_navigationCompletedToken = {}; + + AppWindow* m_appWindow = nullptr; + wil::com_ptr m_webView = nullptr; +}; \ No newline at end of file diff --git a/SampleApps/WebView2APISample/ScenarioFileTypePolicy.cpp b/SampleApps/WebView2APISample/ScenarioFileTypePolicy.cpp new file mode 100644 index 00000000..2dfd4c6e --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioFileTypePolicy.cpp @@ -0,0 +1,199 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "AppWindow.h" +#include "CheckFailure.h" +#include "ScenarioFileTypePolicy.h" + +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = L"SecnarioFileTypePolicy.html"; + +ScenarioFileTypePolicy::ScenarioFileTypePolicy(AppWindow* appWindow) + : m_appWindow(appWindow), m_webView2(appWindow->GetWebView()) +{ + if (m_webView2) + { + m_webView2_2 = m_webView2.try_query(); + + m_sampleUri = m_appWindow->GetLocalUri(c_samplePath); + CHECK_FAILURE(m_webView2->Navigate(m_sampleUri.c_str())); + SuppressPolicyForExtension(); + ListenToWebMessages(); + // Turn off this scenario if we navigate away from the demo page. + CHECK_FAILURE(m_webView2_2->add_DOMContentLoaded( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2DOMContentLoadedEventArgs* args) + -> HRESULT + { + wil::unique_cotaskmem_string uri; + sender->get_Source(&uri); + if (uri.get() != m_sampleUri) + m_appWindow->DeleteComponent(this); + return S_OK; + }) + .Get(), + &m_DOMcontentLoadedToken)); + } +} + +//! [SuppressPolicyForExtension] +// This example will register the event with two custom rules. +// 1. Suppressing file type policy, security dialog, and allows saving ".eml" files +// directly; when the URI is trusted. +// 2. Showing customized warning UI when saving ".iso" files. It allows to block +// the saving directly. +bool ScenarioFileTypePolicy::SuppressPolicyForExtension() +{ + m_webView2_26 = m_webView2.try_query(); + if (!m_webView2_26) + return false; + m_webView2_26->add_SaveFileSecurityCheckStarting( + Callback( + [this]( + ICoreWebView2* sender, + ICoreWebView2SaveFileSecurityCheckStartingEventArgs* args) -> HRESULT + { + // Get the file extension for file to be saved. + // And convert the extension to lower case for a + // case-insensitive comparasion. + wil::unique_cotaskmem_string extension; + CHECK_FAILURE(args->get_FileExtension(&extension)); + std::wstring extension_lower = extension.get(); + std::transform( + extension_lower.begin(), extension_lower.end(), extension_lower.begin(), + ::towlower); + + // Suppress default policy for ".eml" file. + if (wcscmp(extension_lower.c_str(), L".eml") == 0) + { + CHECK_FAILURE(args->put_SuppressDefaultPolicy(TRUE)); + } + + // Cancel save/download for ".iso" file. + if (wcscmp(extension_lower.c_str(), L".iso") == 0) + { + wil::com_ptr deferral; + CHECK_FAILURE(args->GetDeferral(&deferral)); + + m_appWindow->RunAsync( + [this, args = wil::make_com_ptr(args), deferral]() + { + // With the deferral, the cancel decision and + // message box can be replaced with a customized UI. + CHECK_FAILURE(args->put_CancelSave(TRUE)); + MessageBox( + m_appWindow->GetMainWindow(), L"The saving has been blocked", + L"Info", MB_OK); + CHECK_FAILURE(deferral->Complete()); + }); + } + if (wcscmp(extension_lower.c_str(), L".exe") == 0) + { + if (is_exe_blocked.has_value()) + { + if (is_exe_blocked.value()) + { + args->put_CancelSave(true); + } + else + { + args->put_SuppressDefaultPolicy(true); + } + } + } + if (wcscmp(extension_lower.c_str(), L".emlx") == 0) + { + wil::com_ptr deferral; + CHECK_FAILURE(args->GetDeferral(&deferral)); + m_appWindow->RunAsync( + [this, args = wil::make_com_ptr(args), deferral]() + { + // With the deferral, the cancel decision and + // message box can be replaced with a customized UI. + auto selection = MessageBox( + m_appWindow->GetMainWindow(), L"Block the download?", + L"Info", MB_OKCANCEL); + if (selection == IDOK) + { + CHECK_FAILURE(args->put_CancelSave(TRUE)); + } + else if (selection == IDCANCEL) + { + CHECK_FAILURE(args->put_SuppressDefaultPolicy(TRUE)); + + } + CHECK_FAILURE(deferral->Complete()); + }); + } + return S_OK; + }) + .Get(), + &m_saveFileSecurityCheckStartingToken); + + MessageBox( + m_appWindow->GetMainWindow(), + (L"Example rules of Dangerous File Security Policy has been applied in this demo page"), + L"Info", MB_OK); + return true; +} +//! [SuppressPolicyForExtension] + +void ScenarioFileTypePolicy::ListenToWebMessages() +{ + CHECK_FAILURE(m_webView2->add_WebMessageReceived( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) + -> HRESULT + { + LPWSTR message; + args->TryGetWebMessageAsString(&message); + ICoreWebView2Settings* settings; + sender->get_Settings(&settings); + ICoreWebView2Settings8* settings8; + settings->QueryInterface(IID_PPV_ARGS(&settings8)); + if (wcscmp(message, L"enable_smartscreen") == 0) + { + + settings8->put_IsReputationCheckingRequired(true); + MessageBox( + m_appWindow->GetMainWindow(), (L"Enabled Smartscreen"), L"Info", MB_OK); + } + else if (wcscmp(L"disable_smartscreen", message) == 0) + { + settings8->put_IsReputationCheckingRequired(false); + MessageBox( + m_appWindow->GetMainWindow(), (L"Disabled Smartscreen"), L"Info", + MB_OK); + } + else if (wcscmp(L"block_exe", message) == 0) + { + is_exe_blocked = true; + } + else if (wcscmp(L"allow_exe", message) == 0) + { + is_exe_blocked = false; + } + else if (wcscmp(L"clear_exe_policy", message) == 0) + { + is_exe_blocked = std::nullopt; + } + return S_OK; + }) + .Get(), + &m_webMessageReceivedToken)); +} + +ScenarioFileTypePolicy::~ScenarioFileTypePolicy() +{ + if (m_webView2_26) + { + CHECK_FAILURE(m_webView2_26->remove_SaveFileSecurityCheckStarting( + m_saveFileSecurityCheckStartingToken)); + } + CHECK_FAILURE(m_webView2_2->remove_WebResourceResponseReceived(m_webMessageReceivedToken)); + CHECK_FAILURE(m_webView2_2->remove_DOMContentLoaded(m_DOMcontentLoadedToken)); +} \ No newline at end of file diff --git a/SampleApps/WebView2APISample/ScenarioFileTypePolicy.h b/SampleApps/WebView2APISample/ScenarioFileTypePolicy.h new file mode 100644 index 00000000..b3e4e3cc --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioFileTypePolicy.h @@ -0,0 +1,31 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioFileTypePolicy : public ComponentBase +{ +public: + ScenarioFileTypePolicy(AppWindow* appWindow); + ~ScenarioFileTypePolicy(); + +private: + bool SuppressPolicyForExtension(); + void ListenToWebMessages(); + + AppWindow* m_appWindow; + wil::com_ptr m_webView2; + wil::com_ptr m_webView2_2; + wil::com_ptr m_webView2_26; + EventRegistrationToken m_saveFileSecurityCheckStartingToken = {}; + EventRegistrationToken m_DOMcontentLoadedToken = {}; + EventRegistrationToken m_webMessageReceivedToken = {}; + std::wstring m_sampleUri; + std::optional is_exe_blocked = std::nullopt; +}; diff --git a/SampleApps/WebView2APISample/ScenarioIFrameDevicePermission.cpp b/SampleApps/WebView2APISample/ScenarioIFrameDevicePermission.cpp index 51ddb1ef..c8ee5877 100644 --- a/SampleApps/WebView2APISample/ScenarioIFrameDevicePermission.cpp +++ b/SampleApps/WebView2APISample/ScenarioIFrameDevicePermission.cpp @@ -8,7 +8,7 @@ #include "AppWindow.h" #include "CheckFailure.h" -#include "SettingsComponent.h" +#include "ScenarioPermissionManagement.h" using namespace Microsoft::WRL; @@ -19,7 +19,7 @@ ScenarioIFrameDevicePermission::ScenarioIFrameDevicePermission(AppWindow* appWin { m_sampleUri = m_appWindow->GetLocalUri(c_samplePath); - //! [PermissionRequested] + //! [PermissionRequested0] m_webView4 = m_webView.try_query(); if (m_webView4) { @@ -34,103 +34,23 @@ ScenarioIFrameDevicePermission::ScenarioIFrameDevicePermission(AppWindow* appWin { CHECK_FAILURE(m_frame3->add_PermissionRequested( Callback( - [this](ICoreWebView2Frame* sender, - ICoreWebView2PermissionRequestedEventArgs2* args) - -> HRESULT { - // If we set Handled to true, then we will not fire the PermissionRequested - // event off of the CoreWebView2. - args->put_Handled(true); - - auto showDialog = [this, args] - { - COREWEBVIEW2_PERMISSION_KIND kind = - COREWEBVIEW2_PERMISSION_KIND_UNKNOWN_PERMISSION; - BOOL userInitiated = FALSE; - wil::unique_cotaskmem_string uri; - - CHECK_FAILURE(args->get_PermissionKind(&kind)); - CHECK_FAILURE(args->get_IsUserInitiated(&userInitiated)); - CHECK_FAILURE(args->get_Uri(&uri)); - - auto cached_key = std::make_tuple( - std::wstring(uri.get()), kind, userInitiated); - - auto cached_permission = - m_cached_permissions.find(cached_key); - if (cached_permission != m_cached_permissions.end()) - { - bool allow = cached_permission->second; - if (allow) - { - CHECK_FAILURE(args->put_State( - COREWEBVIEW2_PERMISSION_STATE_ALLOW)); - } - else - { - CHECK_FAILURE(args->put_State( - COREWEBVIEW2_PERMISSION_STATE_DENY)); - } - return S_OK; - } - - std::wstring message = - L"An iframe has requested device permission for "; - message += SettingsComponent::NameOfPermissionKind(kind); - message += L" to the website at "; - message += uri.get(); - message += L"?\n\n"; - message += L"Do you want to grant permission?\n"; - message += - (userInitiated - ? L"This request came from a user gesture." - : L"This request did not come from a user " - L"gesture."); - - int response = MessageBox( - nullptr, message.c_str(), L"Permission Request", - MB_YESNOCANCEL | MB_ICONWARNING); - - if (response == IDYES) - { - m_cached_permissions[cached_key] = true; - } - - if (response == IDNO) - { - m_cached_permissions[cached_key] = false; - } - - COREWEBVIEW2_PERMISSION_STATE state = - response == IDYES - ? COREWEBVIEW2_PERMISSION_STATE_ALLOW - : response == IDNO ? COREWEBVIEW2_PERMISSION_STATE_DENY - : COREWEBVIEW2_PERMISSION_STATE_DEFAULT; - - CHECK_FAILURE(args->put_State(state)); - return S_OK; - }; - - // Obtain a deferral for the event so that the CoreWebView2 - // doesn't examine the properties we set on the event args until - // after we call the Complete method asynchronously later. - wil::com_ptr deferral; - CHECK_FAILURE(args->GetDeferral(&deferral)); - - m_appWindow->RunAsync([deferral, showDialog]() { - showDialog(); - CHECK_FAILURE(deferral->Complete()); - }); - - return S_OK; - }).Get(), + this, &ScenarioIFrameDevicePermission::OnPermissionRequested + ).Get(), &m_PermissionRequestedToken)); } - + else { + m_appWindow->RunAsync([]{ FeatureNotAvailable(); }); + } + m_webView4->remove_FrameCreated(m_FrameCreatedToken); return S_OK; }).Get(), &m_FrameCreatedToken)); } - //! [PermissionRequested] + else + { + FeatureNotAvailable(); + } + //! [PermissionRequested0] // Turn off this scenario if we navigate away from the sample page CHECK_FAILURE(m_webView->add_ContentLoading( @@ -149,8 +69,78 @@ ScenarioIFrameDevicePermission::ScenarioIFrameDevicePermission(AppWindow* appWin &m_ContentLoadingToken)); CHECK_FAILURE(m_webView->Navigate(m_sampleUri.c_str())); +} +//! [PermissionRequested1] +HRESULT ScenarioIFrameDevicePermission::OnPermissionRequested( + ICoreWebView2Frame* sender, ICoreWebView2PermissionRequestedEventArgs2* args) +{ + // If we set Handled to true, then we will not fire the PermissionRequested + // event off of the CoreWebView2. + args->put_Handled(true); + + // Obtain a deferral for the event so that the CoreWebView2 + // doesn't examine the properties we set on the event args until + // after we call the Complete method asynchronously later. + wil::com_ptr deferral; + CHECK_FAILURE(args->GetDeferral(&deferral)); + + // Do the rest asynchronously, to avoid calling MessageBox in an event handler. + m_appWindow->RunAsync([this, deferral, args] + { + COREWEBVIEW2_PERMISSION_KIND kind = COREWEBVIEW2_PERMISSION_KIND_UNKNOWN_PERMISSION; + BOOL userInitiated = FALSE; + wil::unique_cotaskmem_string uri; + CHECK_FAILURE(args->get_PermissionKind(&kind)); + CHECK_FAILURE(args->get_IsUserInitiated(&userInitiated)); + CHECK_FAILURE(args->get_Uri(&uri)); + + COREWEBVIEW2_PERMISSION_STATE state; + + auto cached_key = std::make_tuple(std::wstring(uri.get()), kind, userInitiated); + auto cached_permission = m_cached_permissions.find(cached_key); + if (cached_permission != m_cached_permissions.end()) + { + state = (cached_permission->second + ? COREWEBVIEW2_PERMISSION_STATE_ALLOW + : COREWEBVIEW2_PERMISSION_STATE_DENY); + } + else + { + std::wstring message = L"An iframe has requested device permission for "; + message += PermissionKindToString(kind); + message += L" to the website at "; + message += uri.get(); + message += L"?\n\n"; + message += L"Do you want to grant permission?\n"; + message += (userInitiated + ? L"This request came from a user gesture." + : L"This request did not come from a user gesture."); + + int response = MessageBox( + nullptr, message.c_str(), L"Permission Request", + MB_YESNOCANCEL | MB_ICONWARNING); + switch (response) { + case IDYES: + m_cached_permissions[cached_key] = true; + state = COREWEBVIEW2_PERMISSION_STATE_ALLOW; + break; + case IDNO: + m_cached_permissions[cached_key] = false; + state = COREWEBVIEW2_PERMISSION_STATE_DENY; + break; + default: + state = COREWEBVIEW2_PERMISSION_STATE_DEFAULT; + break; + } + } + + CHECK_FAILURE(args->put_State(state)); + CHECK_FAILURE(deferral->Complete()); + }); + return S_OK; } +//! [PermissionRequested1] ScenarioIFrameDevicePermission::~ScenarioIFrameDevicePermission() { @@ -164,4 +154,4 @@ ScenarioIFrameDevicePermission::~ScenarioIFrameDevicePermission() } m_cached_permissions.clear(); CHECK_FAILURE(m_webView->remove_ContentLoading(m_ContentLoadingToken)); -} \ No newline at end of file +} diff --git a/SampleApps/WebView2APISample/ScenarioIFrameDevicePermission.h b/SampleApps/WebView2APISample/ScenarioIFrameDevicePermission.h index cb04977e..887cffae 100644 --- a/SampleApps/WebView2APISample/ScenarioIFrameDevicePermission.h +++ b/SampleApps/WebView2APISample/ScenarioIFrameDevicePermission.h @@ -17,6 +17,8 @@ class ScenarioIFrameDevicePermission : public ComponentBase ~ScenarioIFrameDevicePermission() override; private: + HRESULT OnPermissionRequested( + ICoreWebView2Frame* sender, ICoreWebView2PermissionRequestedEventArgs2* args); AppWindow* m_appWindow = nullptr; wil::com_ptr m_webView; wil::com_ptr m_webView4; diff --git a/SampleApps/WebView2APISample/ScenarioNonClientRegionSupport.cpp b/SampleApps/WebView2APISample/ScenarioNonClientRegionSupport.cpp new file mode 100644 index 00000000..3188b7fc --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioNonClientRegionSupport.cpp @@ -0,0 +1,111 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "stdafx.h" + +#include "AppWindow.h" +#include "CheckFailure.h" +#include "ScenarioNonClientRegionSupport.h" + +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = L"ScenarioNonClientRegionSupport.html"; + +ScenarioNonClientRegionSupport::ScenarioNonClientRegionSupport(AppWindow* appWindow) + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) +{ + m_sampleUri = m_appWindow->GetLocalUri(c_samplePath); + + wil::com_ptr controller = appWindow->GetWebViewController(); + wil::com_ptr compController = + controller.try_query(); + if (compController) + { + m_compController4 = compController.try_query(); + } + + CHECK_FAILURE(m_webView->get_Settings(&m_settings)); + + m_settings9 = m_settings.try_query(); + + CHECK_FAILURE(m_webView->add_NavigationStarting( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args) + -> HRESULT + { + wil::unique_cotaskmem_string uri; + CHECK_FAILURE(args->get_Uri(&uri)); + CHECK_FEATURE_RETURN(m_settings9); + + BOOL enabled = 0; + CHECK_FAILURE(m_settings9->get_IsNonClientRegionSupportEnabled(&enabled)); + + if (uri.get() == m_sampleUri && !enabled) + { + CHECK_FAILURE(m_settings9->put_IsNonClientRegionSupportEnabled(TRUE)); + AddChangeListener(); + } + else if (uri.get() != m_sampleUri && enabled) + { + CHECK_FAILURE(m_settings9->put_IsNonClientRegionSupportEnabled(FALSE)); + } + return S_OK; + }) + .Get(), + &m_navigationStartingToken)); + + // Turn off this scenario if we navigate away from the sample page + CHECK_FAILURE(m_webView->add_ContentLoading( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2ContentLoadingEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string uri; + sender->get_Source(&uri); + if (uri.get() != m_sampleUri) + { + m_appWindow->DeleteComponent(this); + } + return S_OK; + }) + .Get(), + &m_ContentLoadingToken)); + + CHECK_FAILURE(m_webView->Navigate(m_sampleUri.c_str())); +} +//! [AddChangeListener] +void ScenarioNonClientRegionSupport::AddChangeListener() +{ + if (m_compController4) + { + CHECK_FAILURE(m_compController4->add_NonClientRegionChanged( + Callback( + [this]( + ICoreWebView2CompositionController* sender, + ICoreWebView2NonClientRegionChangedEventArgs* args) -> HRESULT + { + COREWEBVIEW2_NON_CLIENT_REGION_KIND region = + COREWEBVIEW2_NON_CLIENT_REGION_KIND_NOWHERE; + args->get_RegionKind(®ion); + wil::com_ptr regionsCollection; + m_compController4->QueryNonClientRegion(region, ®ionsCollection); + UINT32 count = 0; + regionsCollection->get_Count(&count); + RECT rect; + regionsCollection->GetValueAtIndex(0, &rect); + return S_OK; + }) + .Get(), + &m_nonClientRegionChanged)); + } +} +//! [AddChangeListener] +ScenarioNonClientRegionSupport::~ScenarioNonClientRegionSupport() +{ + CHECK_FAILURE(m_webView->remove_NavigationStarting(m_navigationStartingToken)); + CHECK_FAILURE(m_webView->remove_ContentLoading(m_ContentLoadingToken)); + if (m_compController4) + { + CHECK_FAILURE( + m_compController4->remove_NonClientRegionChanged(m_nonClientRegionChanged)); + } +} \ No newline at end of file diff --git a/SampleApps/WebView2APISample/ScenarioNonClientRegionSupport.h b/SampleApps/WebView2APISample/ScenarioNonClientRegionSupport.h new file mode 100644 index 00000000..3db0d145 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioNonClientRegionSupport.h @@ -0,0 +1,32 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once +#include "stdafx.h" + +#include + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioNonClientRegionSupport : public ComponentBase +{ +public: + ScenarioNonClientRegionSupport(AppWindow* appWindow); + void AddChangeListener(); + ~ScenarioNonClientRegionSupport() override; + +private: + AppWindow* m_appWindow; + wil::com_ptr m_webView; + wil::com_ptr m_settings; + + wil::com_ptr m_settings9; + wil::com_ptr m_compController4; + std::wstring m_sampleUri; + + EventRegistrationToken m_navigationStartingToken = {}; + EventRegistrationToken m_ContentLoadingToken = {}; + EventRegistrationToken m_nonClientRegionChanged = {}; +}; \ No newline at end of file diff --git a/SampleApps/WebView2APISample/ScenarioNotificationReceived.cpp b/SampleApps/WebView2APISample/ScenarioNotificationReceived.cpp new file mode 100644 index 00000000..8d15ce7a --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioNotificationReceived.cpp @@ -0,0 +1,159 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" +#include +#include +#include +#include +#include + +#include "ScenarioNotificationReceived.h" + +#include "App.h" +#include "CheckFailure.h" +#include "Util.h" +#include "resource.h" + +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = L"ScenarioNotificationReceived.html"; + +ScenarioNotificationReceived::ScenarioNotificationReceived(AppWindow* appWindow) + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) +{ + m_sampleUri = m_appWindow->GetLocalUri(c_samplePath); + m_webView2_24 = m_webView.try_query(); + if (!m_webView2_24) + return; + //! [NotificationReceived] + // Register a handler for the NotificationReceived event. + CHECK_FAILURE(m_webView2_24->add_NotificationReceived( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2NotificationReceivedEventArgs* args) + -> HRESULT + { + // Block notifications from specific URIs and set Handled to + // true so the the default notification UI will not be + // shown by WebView2 either. + CHECK_FAILURE(args->put_Handled(TRUE)); + + Microsoft::WRL::ComPtr deferral; + CHECK_FAILURE(args->GetDeferral(&deferral)); + wil::unique_cotaskmem_string origin; + CHECK_FAILURE(args->get_SenderOrigin(&origin)); + std::wstring originString = origin.get(); + Microsoft::WRL::ComPtr notification; + CHECK_FAILURE(args->get_Notification(¬ification)); + + notification->add_CloseRequested( + Callback( + [this, &sender]( + ICoreWebView2Notification* notification, IUnknown* args) -> HRESULT + { + // Remove the notification from the list of active + // notifications. + RemoveNotification(notification); + return S_OK; + }) + .Get(), + &m_notificationCloseRequestedToken); + + m_appWindow->RunAsync( + [this, + notificationCom = + wil::make_com_ptr(notification.Get()), + deferral, originString]() + { + ShowNotification(notificationCom.get(), originString); + deferral->Complete(); + }); + + return S_OK; + }) + .Get(), + &m_notificationReceivedToken)); + //! [NotificationReceived] +} + +bool ScenarioNotificationReceived::HandleWindowMessage( + HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* result) +{ + if (message == WM_COMMAND) + { + switch (LOWORD(wParam)) + { + case IDM_SCENARIO_NOTIFICATION: + NavigateToNotificationPage(); + return true; + } + } + return false; +} + +void ScenarioNotificationReceived::ShowNotification( + ICoreWebView2Notification* notification, std::wstring origin) +{ + ICoreWebView2* webView = m_webView.get(); + wil::unique_cotaskmem_string title; + CHECK_FAILURE(notification->get_Title(&title)); + wil::unique_cotaskmem_string body; + CHECK_FAILURE(notification->get_Body(&body)); + wil::unique_cotaskmem_string language; + CHECK_FAILURE(notification->get_Language(&language)); + wil::unique_cotaskmem_string tag; + CHECK_FAILURE(notification->get_Tag(&tag)); + wil::unique_cotaskmem_string iconUri; + CHECK_FAILURE(notification->get_IconUri(&iconUri)); + wil::unique_cotaskmem_string badgeUri; + CHECK_FAILURE(notification->get_BadgeUri(&badgeUri)); + wil::unique_cotaskmem_string imageUri; + CHECK_FAILURE(notification->get_BodyImageUri(&imageUri)); + double timestamp; + CHECK_FAILURE(notification->get_Timestamp(×tamp)); + BOOL requireInteraction; + CHECK_FAILURE(notification->get_RequiresInteraction(&requireInteraction)); + BOOL silent; + CHECK_FAILURE(notification->get_IsSilent(&silent)); + BOOL renotify; + CHECK_FAILURE(notification->get_ShouldRenotify(&renotify)); + + std::wstringstream message; + message << L"WebView2 has received an Notification: " << L"\n\t" << L"Sender origin: " + << origin << L"\n\t" << L"Title: " << title.get() << L"\n\t" << L"Body: " + << body.get() << L"\n\t" << L"Language: " << language.get() << L"\n\t" << L"Tag: " + << tag.get() << L"\n\t" << L"IconUri: " << iconUri.get() << L"\n\t" << L"BadgeUri: " + << badgeUri.get() << L"\n\t" << L"ImageUri: " << imageUri.get() << L"\n\t" + << L"Timestamp: " << Util::UnixEpochToDateTime(timestamp) << L"\n\t" + << L"RequireInteraction: " << ((!!requireInteraction) ? L"true" : L"false") + << L"\n\t" << L"Silent: " << ((!!silent) ? L"true" : L"false") << L"\n\t" + << L"Renotify: " << ((!!renotify) ? L"true" : L"false"); + + message << std::endl; + + int response = MessageBox(nullptr, message.str().c_str(), title.get(), MB_OKCANCEL); + notification->ReportShown(); + (response == IDOK) ? notification->ReportClicked() : notification->ReportClosed(); +} + +void ScenarioNotificationReceived::RemoveNotification(ICoreWebView2Notification* notification) +{ + // Close custom notification. + + // Unsubscribe from notification event. + CHECK_FAILURE(notification->remove_CloseRequested(m_notificationCloseRequestedToken)); +} + +void ScenarioNotificationReceived::NavigateToNotificationPage() +{ + CHECK_FAILURE(m_webView->Navigate(m_sampleUri.c_str())); +} + +ScenarioNotificationReceived::~ScenarioNotificationReceived() +{ + if (m_webView2_24) + { + CHECK_FAILURE(m_webView2_24->remove_NotificationReceived(m_notificationReceivedToken)); + } +} diff --git a/SampleApps/WebView2APISample/ScenarioNotificationReceived.h b/SampleApps/WebView2APISample/ScenarioNotificationReceived.h new file mode 100644 index 00000000..de113afe --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioNotificationReceived.h @@ -0,0 +1,33 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once +#include "stdafx.h" + +#include + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioNotificationReceived : public ComponentBase +{ +public: + ScenarioNotificationReceived(AppWindow* appWindow); + ~ScenarioNotificationReceived() override; + + bool HandleWindowMessage( + HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* result) override; + +private: + void NavigateToNotificationPage(); + void ShowNotification(ICoreWebView2Notification* notification, std::wstring origin); + void RemoveNotification(ICoreWebView2Notification* notification); + + AppWindow* m_appWindow = nullptr; + wil::com_ptr m_webView; + wil::com_ptr m_webView2_24; + std::wstring m_sampleUri; + EventRegistrationToken m_notificationReceivedToken = {}; + EventRegistrationToken m_notificationCloseRequestedToken = {}; +}; diff --git a/SampleApps/WebView2APISample/ScenarioPermissionManagement.cpp b/SampleApps/WebView2APISample/ScenarioPermissionManagement.cpp new file mode 100644 index 00000000..b17ea8c5 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioPermissionManagement.cpp @@ -0,0 +1,231 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "ScenarioPermissionManagement.h" + +#include "App.h" +#include "CheckFailure.h" +#include "PermissionDialog.h" +#include "resource.h" + +using namespace Microsoft::WRL; + +std::wstring PermissionStateToString(COREWEBVIEW2_PERMISSION_STATE state) +{ + switch (state) + { + case COREWEBVIEW2_PERMISSION_STATE_ALLOW: + return L"allow"; + case COREWEBVIEW2_PERMISSION_STATE_DENY: + return L"deny"; + default: + return L"default"; + } +} +std::wstring PermissionKindToString(COREWEBVIEW2_PERMISSION_KIND type) +{ + switch (type) + { + case COREWEBVIEW2_PERMISSION_KIND_MULTIPLE_AUTOMATIC_DOWNLOADS: + return L"auto downloads"; + case COREWEBVIEW2_PERMISSION_KIND_AUTOPLAY: + return L"autoplay"; + case COREWEBVIEW2_PERMISSION_KIND_CAMERA: + return L"camera"; + case COREWEBVIEW2_PERMISSION_KIND_CLIPBOARD_READ: + return L"clipboard read"; + case COREWEBVIEW2_PERMISSION_KIND_FILE_READ_WRITE: + return L"file read and write"; + case COREWEBVIEW2_PERMISSION_KIND_GEOLOCATION: + return L"geolocation"; + case COREWEBVIEW2_PERMISSION_KIND_LOCAL_FONTS: + return L"local fonts"; + case COREWEBVIEW2_PERMISSION_KIND_MICROPHONE: + return L"mic"; + case COREWEBVIEW2_PERMISSION_KIND_NOTIFICATIONS: + return L"notifications"; + case COREWEBVIEW2_PERMISSION_KIND_OTHER_SENSORS: + return L"other sensors"; + case COREWEBVIEW2_PERMISSION_KIND_MIDI_SYSTEM_EXCLUSIVE_MESSAGES: + return L"midi sysex"; + case COREWEBVIEW2_PERMISSION_KIND_WINDOW_MANAGEMENT: + return L"window management"; + case COREWEBVIEW2_PERMISSION_KIND_PERSISTENT_STORAGE: + return L"persistent storage"; + default: + return L"unknown"; + } +} + +static constexpr WCHAR c_samplePath[] = L"ScenarioPermissionManagement.html"; + +std::vector permissionStates{ + COREWEBVIEW2_PERMISSION_STATE_ALLOW, COREWEBVIEW2_PERMISSION_STATE_DENY, + COREWEBVIEW2_PERMISSION_STATE_DEFAULT}; + +std::vector permissionKinds{ + COREWEBVIEW2_PERMISSION_KIND_MULTIPLE_AUTOMATIC_DOWNLOADS, + COREWEBVIEW2_PERMISSION_KIND_AUTOPLAY, + COREWEBVIEW2_PERMISSION_KIND_CAMERA, + COREWEBVIEW2_PERMISSION_KIND_CLIPBOARD_READ, + COREWEBVIEW2_PERMISSION_KIND_FILE_READ_WRITE, + COREWEBVIEW2_PERMISSION_KIND_GEOLOCATION, + COREWEBVIEW2_PERMISSION_KIND_LOCAL_FONTS, + COREWEBVIEW2_PERMISSION_KIND_MICROPHONE, + COREWEBVIEW2_PERMISSION_KIND_NOTIFICATIONS, + COREWEBVIEW2_PERMISSION_KIND_OTHER_SENSORS, + COREWEBVIEW2_PERMISSION_KIND_MIDI_SYSTEM_EXCLUSIVE_MESSAGES, + COREWEBVIEW2_PERMISSION_KIND_WINDOW_MANAGEMENT, + COREWEBVIEW2_PERMISSION_KIND_PERSISTENT_STORAGE}; + +ScenarioPermissionManagement::ScenarioPermissionManagement(AppWindow* appWindow) + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) +{ + m_sampleUri = m_appWindow->GetLocalUri(c_samplePath); + auto webView2_13 = m_webView.try_query(); + wil::com_ptr profile; + if (!webView2_13) + return; + CHECK_FAILURE(webView2_13->get_Profile(&profile)); + m_webViewProfile4 = profile.try_query(); + if (!m_webViewProfile4) + return; + + //! [GetNonDefaultPermissionSettings] + CHECK_FAILURE(webView2_13->add_DOMContentLoaded( + Callback( + [this]( + ICoreWebView2* sender, ICoreWebView2DOMContentLoadedEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string source; + CHECK_FAILURE(sender->get_Source(&source)); + // Permission management APIs are only used on the app's + // permission management page. + if (source.get() != m_sampleUri) + { + return S_OK; + } + // Get all the nondefault permissions and post them to the + // app's permission management page. The permission management + // page can present a list of custom permissions set for this + // profile and let the end user modify them. + CHECK_FAILURE(m_webViewProfile4->GetNonDefaultPermissionSettings( + Callback( + [this, sender]( + HRESULT code, + ICoreWebView2PermissionSettingCollectionView* collectionView) + -> HRESULT + { + UINT32 count; + collectionView->get_Count(&count); + for (UINT32 i = 0; i < count; i++) + { + wil::com_ptr setting; + CHECK_FAILURE(collectionView->GetValueAtIndex(i, &setting)); + COREWEBVIEW2_PERMISSION_KIND kind; + CHECK_FAILURE(setting->get_PermissionKind(&kind)); + std::wstring kind_string = PermissionKindToString(kind); + COREWEBVIEW2_PERMISSION_STATE state; + CHECK_FAILURE(setting->get_PermissionState(&state)); + wil::unique_cotaskmem_string origin; + CHECK_FAILURE(setting->get_PermissionOrigin(&origin)); + std::wstring state_string = PermissionStateToString(state); + std::wstring reply = L"{\"PermissionSetting\": \"" + + kind_string + L", " + origin.get() + + L", " + state_string + L"\"}"; + CHECK_FAILURE(sender->PostWebMessageAsJson(reply.c_str())); + } + return S_OK; + }) + .Get())); + return S_OK; + }) + .Get(), + &m_DOMContentLoadedToken)); + //! [GetNonDefaultPermissionSettings] + + // Called when the user wants to change permission state from the custom + // permission management page. + CHECK_FAILURE(m_webView->add_WebMessageReceived( + Microsoft::WRL::Callback( + [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) + -> HRESULT + { + wil::unique_cotaskmem_string source; + CHECK_FAILURE(args->get_Source(&source)); + if (source.get() != m_sampleUri) + { + return S_OK; + } + wil::unique_cotaskmem_string message; + CHECK_FAILURE(args->TryGetWebMessageAsString(&message)); + if (wcscmp(message.get(), L"SetPermission") == 0) + { + m_appWindow->RunAsync([this] { ShowSetPermissionDialog(); }); + } + return S_OK; + }) + .Get(), + &m_webMessageReceivedToken)); +} + +//! [SetPermissionState] +// The app's permission management page can provide a way for the end user to +// change permissions. For example, a button on the page can trigger a dialog, +// where the user specifies the desired permission kind, origin, and state. +void ScenarioPermissionManagement::ShowSetPermissionDialog() +{ + PermissionDialog dialog(m_appWindow->GetMainWindow(), permissionKinds, permissionStates); + if (dialog.confirmed && m_webViewProfile4) + { + // Example: m_webViewProfile4->SetPermissionState( + // COREWEBVIEW2_PERMISSION_KIND_GEOLOCATION, + // L"https://example.com", + // COREWEBVIEW2_PERMISSION_STATE_DENY + // SetPermissionStateCallback); + CHECK_FAILURE(m_webViewProfile4->SetPermissionState( + dialog.kind, dialog.origin.c_str(), dialog.state, + Callback( + [this](HRESULT error) -> HRESULT + { + m_webView->Reload(); + return S_OK; + }) + .Get())); + } +} +//! [SetPermissionState] + +bool ScenarioPermissionManagement::HandleWindowMessage( + HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* result) +{ + if (message == WM_COMMAND) + { + switch (LOWORD(wParam)) + { + case IDM_PERMISSION_MANAGEMENT: + NavigateToPermissionManager(); + return true; + } + } + return false; +} + +void ScenarioPermissionManagement::NavigateToPermissionManager() +{ + CHECK_FAILURE(m_webView->Navigate(m_sampleUri.c_str())); +} + +ScenarioPermissionManagement::~ScenarioPermissionManagement() +{ + if (!m_webViewProfile4) + return; + if (m_webView2) + { + CHECK_FAILURE(m_webView2->remove_DOMContentLoaded(m_DOMContentLoadedToken)); + } + CHECK_FAILURE(m_webView->remove_WebMessageReceived(m_webMessageReceivedToken)); +} diff --git a/SampleApps/WebView2APISample/ScenarioPermissionManagement.h b/SampleApps/WebView2APISample/ScenarioPermissionManagement.h new file mode 100644 index 00000000..17f5d4f1 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioPermissionManagement.h @@ -0,0 +1,37 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once +#include "stdafx.h" + +#include + +#include "AppWindow.h" +#include "ComponentBase.h" + +std::wstring PermissionKindToString(COREWEBVIEW2_PERMISSION_KIND type); + +std::wstring PermissionStateToString(COREWEBVIEW2_PERMISSION_STATE state); + +class ScenarioPermissionManagement : public ComponentBase +{ +public: + ScenarioPermissionManagement(AppWindow* appWindow); + ~ScenarioPermissionManagement() override; + + bool HandleWindowMessage( + HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* result) override; + +private: + void NavigateToPermissionManager(); + void ShowSetPermissionDialog(); + + AppWindow* m_appWindow = nullptr; + wil::com_ptr m_webView; + wil::com_ptr m_webView2; + wil::com_ptr m_webViewProfile4; + std::wstring m_sampleUri; + EventRegistrationToken m_DOMContentLoadedToken = {}; + EventRegistrationToken m_webMessageReceivedToken = {}; +}; diff --git a/SampleApps/WebView2APISample/ScenarioSaveAs.cpp b/SampleApps/WebView2APISample/ScenarioSaveAs.cpp new file mode 100644 index 00000000..8db6f5ef --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioSaveAs.cpp @@ -0,0 +1,234 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "ScenarioSaveAs.h" + +#include "App.h" +#include "AppWindow.h" +#include "CheckFailure.h" +#include "Shlwapi.h" +#include "TextInputDialog.h" +#include "resource.h" + +using namespace Microsoft::WRL; + +ScenarioSaveAs::ScenarioSaveAs(AppWindow* appWindow) + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) +{ + if (m_webView) + { + m_webView2_25 = m_webView.try_query(); + } +} + +std::initializer_list saveAsKind{ + COREWEBVIEW2_SAVE_AS_KIND_DEFAULT, COREWEBVIEW2_SAVE_AS_KIND_HTML_ONLY, + COREWEBVIEW2_SAVE_AS_KIND_SINGLE_FILE, COREWEBVIEW2_SAVE_AS_KIND_COMPLETE}; +// Sync with COREWEBVIEW2_SAVE_AS_KIND. +std::array saveAsKindString{ + L"DEFAULT", L"HTML_ONLY", L"SIGNLE_FILE", L"COMPLETE"}; +// Sync with COREWEBVIEW2_SAVE_AS_UI_RESULTS. +std::array saveAsUIResultString{ + L"SUCCESS", L"INVALID_PATH", L"FILE_ALREADY_EXISTS", L"KIND_NOT_SUPPORTED", L"CANCELLED"}; + +//! [ToggleSilent] +// Turn on/off Silent SaveAs, which won't show the system default save as dialog. +// This example hides the default save as dialog and shows a customized dialog. +bool ScenarioSaveAs::ToggleSilent() +{ + if (!m_webView2_25) + return false; + m_silentSaveAs = !m_silentSaveAs; + if (m_silentSaveAs && m_saveAsUIShowingToken.value == 0) + { + // Register a handler for the `SaveAsUIShowing` event. + m_webView2_25->add_SaveAsUIShowing( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2SaveAsUIShowingEventArgs* args) + -> HRESULT + { + // Hide the system default save as dialog. + CHECK_FAILURE(args->put_SuppressDefaultDialog(TRUE)); + + auto showCustomizedDialog = [this, args = wil::make_com_ptr(args)] + { + // Preview the content mime type, optional. + wil::unique_cotaskmem_string mimeType; + CHECK_FAILURE(args->get_ContentMimeType(&mimeType)); + + SaveAsDialog dialog(m_appWindow->GetMainWindow(), saveAsKind); + if (dialog.confirmed) + { + // Set the SaveAsFilePath, Kind, AllowReplace for the event + // args from this customized dialog inputs, optional. If nothing + // needs to input, the event args will provide default values. + CHECK_FAILURE(args->put_SaveAsFilePath(dialog.path.c_str())); + CHECK_FAILURE(args->put_Kind(dialog.selectedKind)); + CHECK_FAILURE(args->put_AllowReplace(dialog.allowReplace)); + + BOOL allowReplace; + CHECK_FAILURE(args->get_AllowReplace(&allowReplace)); + wil::unique_cotaskmem_string path; + CHECK_FAILURE(args->get_SaveAsFilePath(&path)); + COREWEBVIEW2_SAVE_AS_KIND selectedKind; + CHECK_FAILURE(args->get_Kind(&selectedKind)); + + // Preview silent save as event args inputs, optional. + MessageBox( + m_appWindow->GetMainWindow(), + (std::wstring(L"Content Mime Type: ") + mimeType.get() + L"\n" + + L"Fullpath: " + path.get() + L"\n" + L"Allow Replace: " + + (allowReplace ? L"true" : L"false") + L"\n" + + L"Selected Save As Kind: " + saveAsKindString[selectedKind]) + .c_str(), + L"Silent Save As Parameters Preview", MB_OK); + } + else + { + // Save As cancelled from this customized dialog. + CHECK_FAILURE(args->put_Cancel(TRUE)); + } + }; + + wil::com_ptr deferral; + CHECK_FAILURE(args->GetDeferral(&deferral)); + + m_appWindow->RunAsync( + [deferral, showCustomizedDialog]() + { + showCustomizedDialog(); + CHECK_FAILURE(deferral->Complete()); + }); + return S_OK; + }) + .Get(), + &m_saveAsUIShowingToken); + } + else + { + // Unregister the handler for the `SaveAsUIShowing` event. + m_webView2_25->remove_SaveAsUIShowing(m_saveAsUIShowingToken); + m_saveAsUIShowingToken.value = 0; + } + MessageBox( + m_appWindow->GetMainWindow(), + (m_silentSaveAs ? L"Silent Save As Enabled" : L"Silent Save As Disabled"), L"Info", + MB_OK); + return true; +} +//! [ToggleSilent] + +//! [ProgrammaticSaveAs] +// Call ShowSaveAsUI method to trigger the programmatic save as. +bool ScenarioSaveAs::ProgrammaticSaveAs() +{ + if (!m_webView2_25) + return false; + m_webView2_25->ShowSaveAsUI( + Callback( + [this](HRESULT errorCode, COREWEBVIEW2_SAVE_AS_UI_RESULT result) -> HRESULT + { + // Show ShowSaveAsUI returned result, optional. + MessageBox( + m_appWindow->GetMainWindow(), + (L"ShowSaveAsUI " + saveAsUIResultString[result]).c_str(), L"Info", MB_OK); + return S_OK; + }) + .Get()); + return true; +} +//! [ProgrammaticSaveAs] + +bool ScenarioSaveAs::HandleWindowMessage( + HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* result) +{ + if (message == WM_COMMAND) + { + switch (LOWORD(wParam)) + { + case IDM_SCENARIO_SAVE_AS_TOGGLE_SILENT: + { + return ToggleSilent(); + } + case IDM_SCENARIO_SAVE_AS_PROGRAMMATIC: + { + return ProgrammaticSaveAs(); + } + } + } + return false; +} + +ScenarioSaveAs::~ScenarioSaveAs() +{ + if (m_webView2_25) + { + m_webView2_25->remove_SaveAsUIShowing(m_saveAsUIShowingToken); + } +} + +static INT_PTR CALLBACK DlgProcStatic(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + auto self = (SaveAsDialog*)GetWindowLongPtr(hDlg, GWLP_USERDATA); + switch (message) + { + case WM_INITDIALOG: + { + self = (SaveAsDialog*)lParam; + SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)self); + HWND hwndList = GetDlgItem(hDlg, IDC_SAVE_AS_KIND); + for (COREWEBVIEW2_SAVE_AS_KIND kind : self->kinds) + { + SendMessage(hwndList, CB_ADDSTRING, kind, (LPARAM)saveAsKindString[kind].c_str()); + SendMessage(hwndList, CB_SETITEMDATA, kind, (LPARAM)kind); + } + SendMessage(hwndList, CB_SETCURSEL, 0, 0); + return (INT_PTR)TRUE; + } + case WM_COMMAND: + { + if (LOWORD(wParam) == IDOK) + { + HWND hwndList = GetDlgItem(hDlg, IDC_SAVE_AS_KIND); + + wchar_t path[MAX_PATH] = {}; + int length = GetWindowTextLength(GetDlgItem(hDlg, IDC_EDIT_SAVE_AS_DIRECTORY)) + + GetWindowTextLength(GetDlgItem(hDlg, IDC_EDIT_SAVE_AS_FILENAME)); + wchar_t directory[MAX_PATH] = {}; + GetDlgItemText(hDlg, IDC_EDIT_SAVE_AS_DIRECTORY, directory, length + 1); + wchar_t filename[MAX_PATH] = {}; + GetDlgItemText(hDlg, IDC_EDIT_SAVE_AS_FILENAME, filename, length + 1); + PathCombineW(path, directory, filename); + self->path = path; + + self->allowReplace = IsDlgButtonChecked(hDlg, IDC_CHECK_SAVE_AS_ALLOW_REPLACE); + + int index = (int)SendMessage(hwndList, CB_GETCURSEL, 0, 0); + self->selectedKind = + (COREWEBVIEW2_SAVE_AS_KIND)SendMessage(hwndList, CB_GETITEMDATA, index, 0); + + self->confirmed = true; + } + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) + { + EndDialog(hDlg, LOWORD(wParam)); + return (INT_PTR)TRUE; + } + break; + } + case WM_NCDESTROY: + SetWindowLongPtr(hDlg, GWLP_USERDATA, NULL); + return (INT_PTR)TRUE; + } + return (INT_PTR)FALSE; +} + +SaveAsDialog::SaveAsDialog(HWND parent, std::initializer_list kinds) + : kinds(kinds) +{ + DialogBoxParam( + g_hInstance, MAKEINTRESOURCE(IDD_SAVE_CONTENT_AS), parent, DlgProcStatic, (LPARAM)this); +} \ No newline at end of file diff --git a/SampleApps/WebView2APISample/ScenarioSaveAs.h b/SampleApps/WebView2APISample/ScenarioSaveAs.h new file mode 100644 index 00000000..ca9726cc --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioSaveAs.h @@ -0,0 +1,39 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioSaveAs : public ComponentBase +{ +public: + ScenarioSaveAs(AppWindow* appWindow); + bool ProgrammaticSaveAs(); + bool ToggleSilent(); + bool HandleWindowMessage( + HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* result) override; + +private: + ~ScenarioSaveAs() override; + AppWindow* m_appWindow = nullptr; + wil::com_ptr m_webView; + wil::com_ptr m_webView2_25; + EventRegistrationToken m_saveAsUIShowingToken = {}; + bool m_silentSaveAs = false; +}; + +struct SaveAsDialog +{ + SaveAsDialog(HWND parent, std::initializer_list kinds); + + std::initializer_list kinds; + std::wstring path; + bool allowReplace = false; + COREWEBVIEW2_SAVE_AS_KIND selectedKind = COREWEBVIEW2_SAVE_AS_KIND_DEFAULT; + bool confirmed = false; +}; \ No newline at end of file diff --git a/SampleApps/WebView2APISample/ScenarioScreenCapture.cpp b/SampleApps/WebView2APISample/ScenarioScreenCapture.cpp new file mode 100644 index 00000000..f65fd001 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioScreenCapture.cpp @@ -0,0 +1,256 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "ScenarioScreenCapture.h" + +#include "AppWindow.h" +#include "CheckFailure.h" + +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = L"ScenarioScreenCapture.html"; + +ScenarioScreenCapture::ScenarioScreenCapture(AppWindow* appWindow) + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) +{ + m_sampleUri = m_appWindow->GetLocalUri(c_samplePath); + + //! [ScreenCaptureStarting0] + m_webView2_27 = m_webView.try_query(); + if (m_webView2_27) + { + m_webView2_27->add_ScreenCaptureStarting( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2ScreenCaptureStartingEventArgs* args) + -> HRESULT + { + // Get Frame Info + wil::com_ptr frameInfo; + CHECK_FAILURE(args->get_OriginalSourceFrameInfo(&frameInfo)); + + wil::com_ptr frameInfo2; + CHECK_FAILURE(frameInfo->QueryInterface(IID_PPV_ARGS(&frameInfo2))); + + UINT32 source_frameId; + CHECK_FAILURE(frameInfo2->get_FrameId(&source_frameId)); + + BOOL cancel = m_mainFramePermission == FALSE; + CHECK_FAILURE(args->put_Cancel(cancel)); + return S_OK; + }) + .Get(), + &m_screenCaptureStartingToken); + } + //! [ScreenCaptureStarting0] + + //! [ScreenCaptureStarting1] + m_webView4 = m_webView.try_query(); + if (m_webView4) + { + CHECK_FAILURE(m_webView4->add_FrameCreated( + Callback( + [this]( + ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args) -> HRESULT + { + wil::com_ptr webviewFrame; + CHECK_FAILURE(args->get_Frame(&webviewFrame)); + + auto frame5 = webviewFrame.try_query(); + + UINT32 frameId; + frame5->get_FrameId(&frameId); + + m_screenCaptureFrameIdPermission[frameId] = TRUE; + + wil::com_ptr webviewFrame2 = + webviewFrame.try_query(); + if (!webviewFrame2) + { + return S_OK; + } + + bool cancel_on_frame = false; + + CHECK_FAILURE(webviewFrame2->add_WebMessageReceived( + Microsoft::WRL::Callback< + ICoreWebView2FrameWebMessageReceivedEventHandler>( + [this, frameId]( + ICoreWebView2Frame* sender, + ICoreWebView2WebMessageReceivedEventArgs* args) -> HRESULT + { + BOOL cancel = false; + + wil::unique_cotaskmem_string messageRaw; + HRESULT hr = args->TryGetWebMessageAsString(&messageRaw); + if (hr == E_INVALIDARG) + { + // Was not a string message. Ignore. + return hr; + } + // Any other problems are fatal. + CHECK_FAILURE(hr); + std::wstring message = messageRaw.get(); + + if (message == L"EnableScreenCapture") + { + cancel = false; + } + else if (message == L"DisableScreenCapture") + { + cancel = true; + } + else + { + // Ignore unrecognized messages, but log for further + // investigation since it suggests a mismatch between the + // web content and the host. + OutputDebugString( + std::wstring( + L"Unexpected message from main page:" + message) + .c_str()); + } + + m_screenCaptureFrameIdPermission[frameId] = (cancel == FALSE); + + return S_OK; + }) + .Get(), + nullptr)); + + m_frame6 = webviewFrame.try_query(); + + m_frame6->add_ScreenCaptureStarting( + Callback( + [this]( + ICoreWebView2Frame* sender, + ICoreWebView2ScreenCaptureStartingEventArgs* args) -> HRESULT + { + args->put_Handled(TRUE); + + bool cancel = FALSE; + + // Get Frame Info + wil::com_ptr frameInfo; + CHECK_FAILURE(args->get_OriginalSourceFrameInfo(&frameInfo)); + + wil::com_ptr frameInfo2; + CHECK_FAILURE( + frameInfo->QueryInterface(IID_PPV_ARGS(&frameInfo2))); + + // Frame Source + wil::unique_cotaskmem_string frameSource; + CHECK_FAILURE(frameInfo->get_Source(&frameSource)); + + UINT32 source_frameId; + CHECK_FAILURE(frameInfo2->get_FrameId(&source_frameId)); + + cancel = + (m_screenCaptureFrameIdPermission[source_frameId] == FALSE); + + CHECK_FAILURE(args->put_Cancel(cancel)); + return S_OK; + }) + .Get(), + &m_frameScreenCaptureStartingToken); + + return S_OK; + }) + .Get(), + &m_frameCreatedToken)); + } + else + { + FeatureNotAvailable(); + } + //! [ScreenCaptureStarting1] + + // Turn off this scenario if we navigate away from the sample page + CHECK_FAILURE(m_webView->add_ContentLoading( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2ContentLoadingEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string uri; + sender->get_Source(&uri); + if (uri.get() != m_sampleUri) + { + m_appWindow->DeleteComponent(this); + } + return S_OK; + }) + .Get(), + &m_contentLoadingToken)); + + CHECK_FAILURE(m_webView->add_WebMessageReceived( + Microsoft::WRL::Callback( + [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) + -> HRESULT + { + BOOL cancel = FALSE; + wil::unique_cotaskmem_string uri; + CHECK_FAILURE(args->get_Source(&uri)); + + // Always validate that the origin of the message is what you + // expect. + if (uri.get() != m_sampleUri) + { + // Ignore messages from untrusted sources. + return E_INVALIDARG; + } + wil::unique_cotaskmem_string messageRaw; + HRESULT hr = args->TryGetWebMessageAsString(&messageRaw); + if (hr == E_INVALIDARG) + { + // Was not a string message. Ignore. + return hr; + } + // Any other problems are fatal. + CHECK_FAILURE(hr); + std::wstring message = messageRaw.get(); + + if (message == L"EnableScreenCapture") + { + cancel = FALSE; + } + else if (message == L"DisableScreenCapture") + { + cancel = TRUE; + } + else + { + // Ignore unrecognized messages, but log for further + // investigation since it suggests a mismatch between the + // web content and the host. + OutputDebugString( + std::wstring(L"Unexpected message from main page:" + message).c_str()); + } + m_mainFramePermission = (cancel == FALSE); + return S_OK; + }) + .Get(), + &m_webMessageReceivedToken)); + + CHECK_FAILURE(m_webView->Navigate(m_sampleUri.c_str())); +} + +ScenarioScreenCapture::~ScenarioScreenCapture() +{ + m_webView->remove_ContentLoading(m_contentLoadingToken); + m_webView->remove_WebMessageReceived(m_webMessageReceivedToken); + if (m_webView2_27) + { + CHECK_FAILURE( + m_webView2_27->remove_ScreenCaptureStarting(m_screenCaptureStartingToken)); + } + if (m_frame6) + { + CHECK_FAILURE( + m_frame6->remove_ScreenCaptureStarting(m_frameScreenCaptureStartingToken)); + } + if (m_webView4) + { + CHECK_FAILURE(m_webView4->remove_FrameCreated(m_frameCreatedToken)); + } +} diff --git a/SampleApps/WebView2APISample/ScenarioScreenCapture.h b/SampleApps/WebView2APISample/ScenarioScreenCapture.h new file mode 100644 index 00000000..42f18ac9 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioScreenCapture.h @@ -0,0 +1,33 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once +#include "stdafx.h" + +#include + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioScreenCapture : public ComponentBase +{ +public: + ScenarioScreenCapture(AppWindow* appWindow); + ~ScenarioScreenCapture() override; + +private: + AppWindow* m_appWindow = nullptr; + wil::com_ptr m_webView; + wil::com_ptr m_webView4; + wil::com_ptr m_webView2_27; + wil::com_ptr m_frame6; + std::wstring m_sampleUri; + std::map m_screenCaptureFrameIdPermission; + BOOL m_mainFramePermission = TRUE; + EventRegistrationToken m_contentLoadingToken = {}; + EventRegistrationToken m_webMessageReceivedToken = {}; + EventRegistrationToken m_frameCreatedToken = {}; + EventRegistrationToken m_screenCaptureStartingToken = {}; + EventRegistrationToken m_frameScreenCaptureStartingToken = {}; +}; diff --git a/SampleApps/WebView2APISample/ScenarioScreenCaptureIFrame2.html b/SampleApps/WebView2APISample/ScenarioScreenCaptureIFrame2.html new file mode 100644 index 00000000..6c7f330f --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioScreenCaptureIFrame2.html @@ -0,0 +1,32 @@ + + + + ScenarioScreenCaptureIFrame2 + + +

Screen Capture Test From Top Level IFrame 2

+ + +
+ + + + diff --git a/SampleApps/WebView2APISample/ScenarioSensitivityLabel.cpp b/SampleApps/WebView2APISample/ScenarioSensitivityLabel.cpp new file mode 100644 index 00000000..7965d45a --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioSensitivityLabel.cpp @@ -0,0 +1,390 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "ScenarioSensitivityLabel.h" + +#include "AppWindow.h" +#include "CheckFailure.h" +#include "TextInputDialog.h" +#include "Util.h" + +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = L"ScenarioSensitivityLabelChanged.html"; + +ScenarioSensitivityLabel::ScenarioSensitivityLabel(AppWindow* appWindow) + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) +{ + m_sampleUri = m_appWindow->GetLocalUri(c_samplePath); +} + +ScenarioSensitivityLabel::~ScenarioSensitivityLabel() +{ + UnregisterSensitivityLabelChange(); +} + +void ScenarioSensitivityLabel::SetPageRestrictionManagerAllowlist() +{ + std::vector allowlist = ShowAllowlistInputDialog(); + + if (allowlist.empty()) + { + m_appWindow->AsyncMessageBox( + L"No URLs entered. Allowlist not modified.", L"Sensitivity Label - Set Allowlist"); + return; + } + + std::vector items; + items.reserve(allowlist.size()); + for (const auto& str : allowlist) + { + items.push_back(str.c_str()); + } + + HRESULT hr = SetAllowlistOnProfile(items); + if (FAILED(hr)) + { + m_appWindow->AsyncMessageBox( + L"Failed to set PageInteractionRestrictionManager allowlist.", + L"Sensitivity Label - Set Allowlist Error"); + return; + } + + std::wstring message = + L"PageInteractionRestrictionManager allowlist set successfully with " + + std::to_wstring(allowlist.size()) + L" URLs:\n\n"; + for (const auto& url : allowlist) + { + message += L"- " + url + L"\n"; + } + + m_appWindow->AsyncMessageBox(message, L"Sensitivity Label - Allowlist Set"); +} + +void ScenarioSensitivityLabel::CheckPageRestrictionManagerAvailability() +{ + // Execute script to check if navigator.pageInteractionRestrictionManager exists + std::wstring script = + L"(() => {" + L" try {" + L" return typeof navigator.pageInteractionRestrictionManager !== 'undefined' && " + L" navigator.pageInteractionRestrictionManager !== null;" + L" } catch (e) {" + L" return false;" + L" }" + L"})();"; + + CHECK_FAILURE(m_webView->ExecuteScript( + script.c_str(), + Callback( + [this](HRESULT errorCode, LPCWSTR resultObjectAsJson) -> HRESULT + { + if (FAILED(errorCode)) + { + m_appWindow->AsyncMessageBox( + L"Failed to execute script to check PageInteractionRestrictionManager " + L"availability.", + L"Sensitivity Label - Error"); + return S_OK; + } + + bool isAvailable = + (resultObjectAsJson && wcscmp(resultObjectAsJson, L"true") == 0); + + std::wstring message; + if (isAvailable) + { + message = L"PageInteractionRestrictionManager is AVAILABLE\n\n" + L"The navigator.pageInteractionRestrictionManager object " + L"exists and can be used for sensitivity labeling."; + } + else + { + wil::unique_cotaskmem_string currentUri; + message = L"PageInteractionRestrictionManager is NOT AVAILABLE\n\n"; + + if (SUCCEEDED(m_webView->get_Source(¤tUri)) && currentUri.get()) + { + message += L"Current URL: " + std::wstring(currentUri.get()) + L"\n\n"; + } + + message += + L"To enable: Go to Scenario -> Sensitivity Label -> Set PIRM Allowlist"; + } + + m_appWindow->AsyncMessageBox( + message, L"Sensitivity Label - Availability Check"); + return S_OK; + }) + .Get())); +} + +void ScenarioSensitivityLabel::LaunchLabelDemoPage() +{ + RegisterForSensitivityLabelChange(); + + CHECK_FAILURE(m_webView->Navigate(m_sampleUri.c_str())); +} + +void ScenarioSensitivityLabel::ToggleEventListener() +{ + if (m_isEventListenerRegistered) + { + UnregisterSensitivityLabelChange(); + + m_appWindow->AsyncMessageBox( + L"Sensitivity label event listener has been turned OFF.\n\n" + L"The application will no longer receive notifications when sensitivity labels " + L"change.", + L"Event Listener - OFF"); + } + else + { + RegisterForSensitivityLabelChange(); + + m_appWindow->AsyncMessageBox( + L"Sensitivity label event listener has been turned ON.\n\n" + L"The application will now receive notifications when sensitivity labels change.", + L"Event Listener - ON"); + } +} + +std::vector ScenarioSensitivityLabel::ShowAllowlistInputDialog() +{ + std::vector result; + + std::wstring prompt = L"Enter URLs for the PageInteractionRestrictionManager Allowlist " + L"separated by semicolons (;):"; + + std::wstring description = + L"Example: https://site1.com/;https://site2.com/*;https://*.site3.com/*"; + + std::wstring defaultValue = + L"https://*example.com*;https://microsoft.com*;https://github.com*"; + + TextInputDialog dialog( + m_appWindow->GetMainWindow(), L"PageInteractionRestrictionManager Allowlist", + prompt.c_str(), description.c_str(), defaultValue); + + if (dialog.confirmed && !dialog.input.empty()) + { + // Use the utility function to split the input string by semicolons and trim whitespace + result = Util::SplitString(dialog.input, L';'); + } + + return result; +} + +void ScenarioSensitivityLabel::RegisterForSensitivityLabelChange() +{ + // If event is already registered return + if (m_sensitivityInfoChangedToken.value != 0) + { + return; + } + + auto webView32 = m_webView.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webView32); + //! [SensitivityInfoChanged] + CHECK_FAILURE(webView32->add_SensitivityInfoChanged( + Callback( + [this](ICoreWebView2* sender, IUnknown* args) -> HRESULT + { + auto webView32 = this->m_webView.try_query(); + Microsoft::WRL::ComPtr + sensitivityInfo; + webView32->get_SensitivityInfo(&sensitivityInfo); + + OnSensitivityChanged(sensitivityInfo.Get()); + + return S_OK; + }) + .Get(), + &m_sensitivityInfoChangedToken)); + //! [SensitivityInfoChanged] + + m_isEventListenerRegistered = true; +} + +void ScenarioSensitivityLabel::UnregisterSensitivityLabelChange() +{ + if (m_sensitivityInfoChangedToken.value != 0) + { + auto webView32 = m_webView.try_query(); + webView32->remove_SensitivityInfoChanged(m_sensitivityInfoChangedToken); + m_sensitivityInfoChangedToken = {}; + m_isEventListenerRegistered = false; + } +} + +HRESULT ScenarioSensitivityLabel::SetAllowlistOnProfile(std::vector allowlist) +{ + //! [SetAllowList] + auto webView2_13 = m_webView.try_query(); + if (!webView2_13) + { + return E_NOINTERFACE; + } + + wil::com_ptr webView2Profile; + HRESULT hr = webView2_13->get_Profile(&webView2Profile); + if (FAILED(hr)) + { + return hr; + } + + auto experimentalProfile14 = + webView2Profile.try_query(); + if (!experimentalProfile14) + { + return E_NOINTERFACE; + } + + // allowlist consists of URL patterns that can access PageInteractionRestrictionManager API + // Examples: "https://example.com/*", "https://*.trusted-domain.com/*", "*://site.com/*" + return experimentalProfile14->SetPageInteractionRestrictionManagerAllowList( + static_cast(allowlist.size()), allowlist.data()); + //! [SetAllowList] +} + +std::wstring ScenarioSensitivityLabel::GetSensitivityLabelStrings( + COREWEBVIEW2_SENSITIVITY_LABELS_STATE& sensitivityLabelsState) +{ + std::wstring labelsString; + switch (sensitivityLabelsState) + { + case COREWEBVIEW2_SENSITIVITY_LABELS_STATE_NOT_APPLICABLE: + labelsString = L"No allowlisted pages loaded"; + break; + case COREWEBVIEW2_SENSITIVITY_LABELS_STATE_PENDING: + labelsString = L"Labels undetermined - allowlisted page loaded but no " + L"labels detected yet"; + break; + case COREWEBVIEW2_SENSITIVITY_LABELS_STATE_AVAILABLE: + labelsString = L"Labels determined"; + break; + } + return labelsString; +} + +void ScenarioSensitivityLabel::OnSensitivityChanged( + ICoreWebView2ExperimentalSensitivityInfo* sensitivityInfo) +{ + if (!sensitivityInfo) + { + return; + } + + //! [SensitivityInfo] + COREWEBVIEW2_SENSITIVITY_LABELS_STATE sensitivityLabelsState; + CHECK_FAILURE(sensitivityInfo->get_SensitivityLabelsState(&sensitivityLabelsState)); + Microsoft::WRL::ComPtr + sensitivityLabelsCollection; + if (sensitivityLabelsState == COREWEBVIEW2_SENSITIVITY_LABELS_STATE_AVAILABLE) + { + CHECK_FAILURE(sensitivityInfo->get_SensitivityLabels(&sensitivityLabelsCollection)); + } + //! [SensitivityInfo] + + std::wstring labelsString = GetSensitivityLabelStrings(sensitivityLabelsState); + + if (sensitivityLabelsCollection) + { + // Get the count of labels + UINT32 labelCount = 0; + CHECK_FAILURE(sensitivityLabelsCollection->get_Count(&labelCount)); + + if (labelCount == 0) + { + labelsString += L"\n\nNo labels present"; + } + else + { + // Extract label information into a vector of pairs + std::vector> labelInfos = + ExtractSensitivityLabelInfo(sensitivityLabelsCollection.Get()); + + // Generate the formatted string from the label information + labelsString += L"\n\nDetected " + std::to_wstring(labelCount) + L" label(s):\n"; + labelsString += GenerateLabelInfoString(labelInfos); + } + } + + // Show the sensitivity labels in a popup dialog + // Using a sync message box here to ensure the user sees the label change + // in the right order if multiple changes occur quickly + MessageBoxW( + m_appWindow->GetMainWindow(), labelsString.c_str(), L"Sensitivity Label Changed", + MB_OK | MB_ICONINFORMATION); +} + +//! [SensitivityLabels] +std::vector> ScenarioSensitivityLabel:: + ExtractSensitivityLabelInfo( + ICoreWebView2ExperimentalSensitivityLabelCollectionView* labelCollection) +{ + std::vector> labelInfos; + + if (!labelCollection) + { + return labelInfos; + } + + UINT32 labelCount = 0; + CHECK_FAILURE(labelCollection->get_Count(&labelCount)); + + for (UINT32 i = 0; i < labelCount; ++i) + { + Microsoft::WRL::ComPtr sensitivityLabel; + CHECK_FAILURE(labelCollection->GetValueAtIndex(i, &sensitivityLabel)); + + COREWEBVIEW2_SENSITIVITY_LABEL_KIND labelKind; + CHECK_FAILURE(sensitivityLabel->get_LabelKind(&labelKind)); + if (labelKind == COREWEBVIEW2_SENSITIVITY_LABEL_KIND_MIP) + { + //! [MipSensitivityLabels] + Microsoft::WRL::ComPtr mipLabel; + if (SUCCEEDED(sensitivityLabel.As(&mipLabel))) + { + wil::unique_cotaskmem_string labelId; + wil::unique_cotaskmem_string organizationId; + CHECK_FAILURE(mipLabel->get_LabelId(&labelId)); + CHECK_FAILURE(mipLabel->get_OrganizationId(&organizationId)); + + // Store the label id and organization id as a pair. Can be used + // to query Purview for the allowed rights on the document + labelInfos.emplace_back( + std::wstring(labelId.get()), std::wstring(organizationId.get())); + } + //! [MipSensitivityLabels] + } + } + return labelInfos; +} +//! [SensitivityLabels] + +std::wstring ScenarioSensitivityLabel::GenerateLabelInfoString( + const std::vector>& labelInfos) +{ + std::wstring result; + + if (labelInfos.empty()) + { + result += L"\n\nNo MIP labels present"; + return result; + } + + for (size_t i = 0; i < labelInfos.size(); ++i) + { + const auto& labelInfo = labelInfos[i]; + + result += L"\n" + std::to_wstring(i + 1) + L". "; + result += + L"MIP Label\n ID: " + labelInfo.first + L"\n Organization: " + labelInfo.second; + } + + return result; +} diff --git a/SampleApps/WebView2APISample/ScenarioSensitivityLabel.h b/SampleApps/WebView2APISample/ScenarioSensitivityLabel.h new file mode 100644 index 00000000..08400805 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioSensitivityLabel.h @@ -0,0 +1,52 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ComponentBase.h" +#include "stdafx.h" + +#include +#include +#include + +class AppWindow; +struct ICoreWebView2ExperimentalSensitivityInfo; + +class ScenarioSensitivityLabel : public ComponentBase +{ +public: + ScenarioSensitivityLabel(AppWindow* appWindow); + ~ScenarioSensitivityLabel() override; + + // PageInteractionRestrictionManager Allowlist functionality + void SetPageRestrictionManagerAllowlist(); + void CheckPageRestrictionManagerAvailability(); + void LaunchLabelDemoPage(); + void ToggleEventListener(); + +private: + AppWindow* m_appWindow = nullptr; + wil::com_ptr m_webView; + EventRegistrationToken m_sensitivityInfoChangedToken = {}; + std::wstring m_sampleUri; + bool m_isEventListenerRegistered = false; + + // UI method for collecting user input + std::vector ShowAllowlistInputDialog(); + + // Sensitivity label event handling + void RegisterForSensitivityLabelChange(); + void UnregisterSensitivityLabelChange(); + std::wstring GetSensitivityLabelStrings( + COREWEBVIEW2_SENSITIVITY_LABELS_STATE& sensitivityLabelsState); + void OnSensitivityChanged(ICoreWebView2ExperimentalSensitivityInfo* sensitivityInfo); + + // Label processing helpers + std::vector> ExtractSensitivityLabelInfo( + ICoreWebView2ExperimentalSensitivityLabelCollectionView* labelCollection); + std::wstring GenerateLabelInfoString( + const std::vector>& labelInfos); + + // Helper methods + HRESULT SetAllowlistOnProfile(std::vector allowlist); +}; diff --git a/SampleApps/WebView2APISample/ScenarioServiceWorkerManager.cpp b/SampleApps/WebView2APISample/ScenarioServiceWorkerManager.cpp new file mode 100644 index 00000000..e738d51d --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioServiceWorkerManager.cpp @@ -0,0 +1,275 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" +#include + +#include "CheckFailure.h" +#include "TextInputDialog.h" + +#include "ScenarioServiceWorkerManager.h" + +using namespace Microsoft::WRL; + +ScenarioServiceWorkerManager::ScenarioServiceWorkerManager(AppWindow* appWindow) + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) +{ + CreateServiceWorkerManager(); + SetupEventsOnWebview(); +} + +void ScenarioServiceWorkerManager::CreateServiceWorkerManager() +{ + //! [ServiceWorkerManager] + auto webView2_13 = m_webView.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webView2_13); + + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + auto webViewExperimentalProfile13 = + webView2Profile.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webViewExperimentalProfile13); + CHECK_FAILURE( + webViewExperimentalProfile13->get_ServiceWorkerManager(&m_serviceWorkerManager)); + //! [ServiceWorkerManager] +} + +void ScenarioServiceWorkerManager::SetupEventsOnWebview() +{ + if (!m_serviceWorkerManager) + { + return; + } + + //! [ServiceWorkerRegistered] + CHECK_FAILURE(m_serviceWorkerManager->add_ServiceWorkerRegistered( + Callback( + [this]( + ICoreWebView2ExperimentalServiceWorkerManager* sender, + ICoreWebView2ExperimentalServiceWorkerRegisteredEventArgs* args) + { + wil::com_ptr + serviceWorkerRegistration; + CHECK_FAILURE(args->get_ServiceWorkerRegistration(&serviceWorkerRegistration)); + + if (serviceWorkerRegistration) + { + wil::unique_cotaskmem_string scopeUri; + CHECK_FAILURE(serviceWorkerRegistration->get_ScopeUri(&scopeUri)); + std::wstring scopeUriStr(scopeUri.get()); + + wil::unique_cotaskmem_string origin; + CHECK_FAILURE(serviceWorkerRegistration->get_Origin(&origin)); + + wil::unique_cotaskmem_string topLevelOrigin; + CHECK_FAILURE( + serviceWorkerRegistration->get_TopLevelOrigin(&topLevelOrigin)); + + // Subscribe to worker registration unregistering event + serviceWorkerRegistration->add_Unregistering( + Callback< + ICoreWebView2ExperimentalServiceWorkerRegistrationUnregisteringEventHandler>( + [this, scopeUriStr]( + ICoreWebView2ExperimentalServiceWorkerRegistration* sender, + IUnknown* args) -> HRESULT + { + /*Cleanup on worker registration destruction*/ + m_appWindow->AsyncMessageBox( + scopeUriStr, L"Service worker is unregistered"); + return S_OK; + }) + .Get(), + nullptr); + + wil::com_ptr serviceWorker; + CHECK_FAILURE( + serviceWorkerRegistration->get_ActiveServiceWorker(&serviceWorker)); + + if (serviceWorker) + { + wil::unique_cotaskmem_string scriptUri; + CHECK_FAILURE(serviceWorker->get_ScriptUri(&scriptUri)); + std::wstring scriptUriStr(scriptUri.get()); + + // Subscribe to worker destroying event + serviceWorker->add_Destroying( + Callback< + ICoreWebView2ExperimentalServiceWorkerDestroyingEventHandler>( + [this, scriptUriStr]( + ICoreWebView2ExperimentalServiceWorker* sender, + IUnknown* args) -> HRESULT + { + /*Cleanup on worker destruction*/ + m_appWindow->AsyncMessageBox( + scriptUriStr, L"Service worker is destroyed"); + return S_OK; + }) + .Get(), + nullptr); + } + else + { + CHECK_FAILURE(serviceWorkerRegistration->add_ServiceWorkerActivated( + Callback< + ICoreWebView2ExperimentalServiceWorkerActivatedEventHandler>( + [this]( + ICoreWebView2ExperimentalServiceWorkerRegistration* sender, + ICoreWebView2ExperimentalServiceWorkerActivatedEventArgs* + args) -> HRESULT + { + wil::com_ptr + serviceWorker; + CHECK_FAILURE( + args->get_ActiveServiceWorker(&serviceWorker)); + wil::unique_cotaskmem_string scriptUri; + CHECK_FAILURE(serviceWorker->get_ScriptUri(&scriptUri)); + std::wstring scriptUriStr(scriptUri.get()); + + // Subscribe to worker destroying event + serviceWorker->add_Destroying( + Callback< + ICoreWebView2ExperimentalServiceWorkerDestroyingEventHandler>( + [this, scriptUriStr]( + ICoreWebView2ExperimentalServiceWorker* sender, + IUnknown* args) -> HRESULT + { + /*Cleanup on worker destruction*/ + m_appWindow->AsyncMessageBox( + scriptUriStr, + L"Service worker is destroyed"); + return S_OK; + }) + .Get(), + nullptr); + + m_appWindow->AsyncMessageBox( + L"Service worker is activated", L"Service worker"); + + return S_OK; + }) + .Get(), + nullptr)); + } + + m_appWindow->AsyncMessageBox(scopeUriStr, L"Service worker is registered"); + } + + return S_OK; + }) + .Get(), + &m_serviceWorkerRegisteredToken)); + //! [ServiceWorkerRegistered] +} + +void ScenarioServiceWorkerManager::GetAllServiceWorkerRegistrations() +{ + CHECK_FEATURE_RETURN_EMPTY(m_serviceWorkerManager); + CHECK_FAILURE(m_serviceWorkerManager->GetServiceWorkerRegistrations( + Callback( + [this]( + HRESULT error, ICoreWebView2ExperimentalServiceWorkerRegistrationCollectionView* + workerRegistrationCollection) -> HRESULT + { + CHECK_FAILURE(error); + UINT32 workersCount = 0; + CHECK_FAILURE(workerRegistrationCollection->get_Count(&workersCount)); + + std::wstringstream message{}; + message << L"Number of service workers registered: " << workersCount + << std::endl; + + for (UINT32 i = 0; i < workersCount; i++) + { + ComPtr + serviceWorkerRegistration; + CHECK_FAILURE(workerRegistrationCollection->GetValueAtIndex( + i, &serviceWorkerRegistration)); + + wil::unique_cotaskmem_string scopeUri; + CHECK_FAILURE(serviceWorkerRegistration->get_ScopeUri(&scopeUri)); + + wil::unique_cotaskmem_string origin; + CHECK_FAILURE(serviceWorkerRegistration->get_Origin(&origin)); + + wil::unique_cotaskmem_string topLevelOrigin; + CHECK_FAILURE( + serviceWorkerRegistration->get_TopLevelOrigin(&topLevelOrigin)); + + message << L"ScopeUri: " << scopeUri.get() << std::endl; + message << L"Origin: " << origin.get() << std::endl; + message << L"TopLevelOrigin: " << topLevelOrigin.get() << std::endl; + } + + m_appWindow->AsyncMessageBox( + std::move(message.str()), L"Registered service workers"); + + return S_OK; + }) + .Get())); +} + +void ScenarioServiceWorkerManager::GetServiceWorkerRegisteredForScope() +{ + CHECK_FEATURE_RETURN_EMPTY(m_serviceWorkerManager); + TextInputDialog dialog( + m_appWindow->GetMainWindow(), L"Service Worker", L"Scope:", + L"Specify a scope to get the service worker", L""); + + if (dialog.confirmed) + { + std::wstring scope = dialog.input.c_str(); + CHECK_FAILURE(m_serviceWorkerManager->GetServiceWorkerRegistrationsForScope( + scope.c_str(), + Callback( + [this, scope]( + HRESULT error, + ICoreWebView2ExperimentalServiceWorkerRegistrationCollectionView* + workerRegistrationCollection) -> HRESULT + { + CHECK_FAILURE(error); + UINT32 workersCount = 0; + CHECK_FAILURE(workerRegistrationCollection->get_Count(&workersCount)); + + std::wstringstream message{}; + message << L"Number of service workers registered for the scope (" + << scope.c_str() << ") : " << workersCount << std::endl; + + for (UINT32 i = 0; i < workersCount; i++) + { + ComPtr + serviceWorkerRegistration; + CHECK_FAILURE(workerRegistrationCollection->GetValueAtIndex( + i, &serviceWorkerRegistration)); + + wil::unique_cotaskmem_string scopeUri; + CHECK_FAILURE(serviceWorkerRegistration->get_ScopeUri(&scopeUri)); + + wil::unique_cotaskmem_string origin; + CHECK_FAILURE(serviceWorkerRegistration->get_Origin(&origin)); + + wil::unique_cotaskmem_string topLevelOrigin; + CHECK_FAILURE( + serviceWorkerRegistration->get_TopLevelOrigin(&topLevelOrigin)); + + message << L"ScopeUri: " << scopeUri.get() << std::endl; + message << L"Origin: " << origin.get() << std::endl; + message << L"TopLevelOrigin: " << topLevelOrigin.get() << std::endl; + } + + m_appWindow->AsyncMessageBox( + std::move(message.str()), L"Registered service workers for scope"); + + return S_OK; + }) + .Get())); + } +} + +ScenarioServiceWorkerManager::~ScenarioServiceWorkerManager() +{ + if (m_serviceWorkerManager) + { + m_serviceWorkerManager->remove_ServiceWorkerRegistered(m_serviceWorkerRegisteredToken); + } +} diff --git a/SampleApps/WebView2APISample/ScenarioServiceWorkerManager.h b/SampleApps/WebView2APISample/ScenarioServiceWorkerManager.h new file mode 100644 index 00000000..2a47f533 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioServiceWorkerManager.h @@ -0,0 +1,27 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioServiceWorkerManager : public ComponentBase +{ +public: + ScenarioServiceWorkerManager(AppWindow* appWindow); + ~ScenarioServiceWorkerManager() override; + + void GetAllServiceWorkerRegistrations(); + void GetServiceWorkerRegisteredForScope(); + +private: + void SetupEventsOnWebview(); + void CreateServiceWorkerManager(); + + AppWindow* m_appWindow; + wil::com_ptr m_webView; + wil::com_ptr m_serviceWorkerManager; + EventRegistrationToken m_serviceWorkerRegisteredToken = {}; +}; diff --git a/SampleApps/WebView2APISample/ScenarioServiceWorkerPostMessage.cpp b/SampleApps/WebView2APISample/ScenarioServiceWorkerPostMessage.cpp new file mode 100644 index 00000000..f592f540 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioServiceWorkerPostMessage.cpp @@ -0,0 +1,168 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" +#include + +#include "CheckFailure.h" + +#include "ScenarioServiceWorkerPostMessage.h" + +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = L"scenario_sw_post_msg_scope/index.html"; + +ScenarioServiceWorkerPostMessage::ScenarioServiceWorkerPostMessage(AppWindow* appWindow) + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) +{ + CreateServiceWorkerManager(); + SetupEventsOnWebview(); +} + +void ScenarioServiceWorkerPostMessage::CreateServiceWorkerManager() +{ + auto webView2_13 = m_webView.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webView2_13); + + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + auto webViewExperimentalProfile13 = + webView2Profile.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webViewExperimentalProfile13); + CHECK_FAILURE( + webViewExperimentalProfile13->get_ServiceWorkerManager(&m_serviceWorkerManager)); +} + +void ScenarioServiceWorkerPostMessage::SetupEventsOnWebview() +{ + if (!m_serviceWorkerManager) + { + return; + } + + CHECK_FAILURE(m_serviceWorkerManager->add_ServiceWorkerRegistered( + Callback( + [this]( + ICoreWebView2ExperimentalServiceWorkerManager* sender, + ICoreWebView2ExperimentalServiceWorkerRegisteredEventArgs* args) + { + wil::com_ptr + serviceWorkerRegistration; + CHECK_FAILURE(args->get_ServiceWorkerRegistration(&serviceWorkerRegistration)); + + if (serviceWorkerRegistration) + { + wil::unique_cotaskmem_string scopeUri; + CHECK_FAILURE(serviceWorkerRegistration->get_ScopeUri(&scopeUri)); + std::wstring scopeUriStr(scopeUri.get()); + + wil::com_ptr serviceWorker; + CHECK_FAILURE( + serviceWorkerRegistration->get_ActiveServiceWorker(&serviceWorker)); + + if (serviceWorker) + { + SetupEventsOnServiceWorker(serviceWorker); + AddToCache(L"img.jpg", serviceWorker); + } + else + { + CHECK_FAILURE(serviceWorkerRegistration->add_ServiceWorkerActivated( + Callback< + ICoreWebView2ExperimentalServiceWorkerActivatedEventHandler>( + [this]( + ICoreWebView2ExperimentalServiceWorkerRegistration* sender, + ICoreWebView2ExperimentalServiceWorkerActivatedEventArgs* + args) -> HRESULT + { + wil::com_ptr + serviceWorker; + CHECK_FAILURE( + args->get_ActiveServiceWorker(&serviceWorker)); + + SetupEventsOnServiceWorker(serviceWorker); + AddToCache(L"img.jpg", serviceWorker); + + return S_OK; + }) + .Get(), + nullptr)); + } + + m_appWindow->AsyncMessageBox(scopeUriStr, L"Service worker is registered"); + } + + return S_OK; + }) + .Get(), + &m_serviceWorkerRegisteredToken)); + + // Turn off this scenario if we navigate away from the sample page. + CHECK_FAILURE(m_webView->add_ContentLoading( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2ContentLoadingEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string uri; + sender->get_Source(&uri); + if (uri.get() != m_sampleUri) + { + m_appWindow->DeleteComponent(this); + } + return S_OK; + }) + .Get(), + &m_contentLoadingToken)); + + m_sampleUri = m_appWindow->GetLocalUri(c_samplePath); + CHECK_FAILURE(m_webView->Navigate(m_sampleUri.c_str())); +} + +void ScenarioServiceWorkerPostMessage::SetupEventsOnServiceWorker( + wil::com_ptr serviceWorker) +{ + //! [WebMessageReceived] + serviceWorker->add_WebMessageReceived( + Callback( + [this]( + ICoreWebView2ExperimentalServiceWorker* sender, + ICoreWebView2WebMessageReceivedEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string scriptUri; + CHECK_FAILURE(args->get_Source(&scriptUri)); + + wil::unique_cotaskmem_string messageRaw; + CHECK_FAILURE(args->TryGetWebMessageAsString(&messageRaw)); + std::wstring messageFromWorker = messageRaw.get(); + + std::wstringstream message{}; + message << L"Service Worker: " << std::endl << scriptUri.get() << std::endl; + message << std::endl; + message << L"Message: " << std::endl << messageFromWorker << std::endl; + m_appWindow->AsyncMessageBox(message.str(), L"Message from Service Worker"); + + return S_OK; + }) + .Get(), + nullptr); + //! [WebMessageReceived] +} + +void ScenarioServiceWorkerPostMessage::AddToCache( + std::wstring url, wil::com_ptr serviceWorker) +{ + //! [PostWebMessageAsJson] + std::wstring msg = L"{\"command\":\"ADD_TO_CACHE\",\"url\":\"" + url + L"\"}"; + serviceWorker->PostWebMessageAsJson(msg.c_str()); + //! [PostWebMessageAsJson] +} + +ScenarioServiceWorkerPostMessage::~ScenarioServiceWorkerPostMessage() +{ + if (m_serviceWorkerManager) + { + m_serviceWorkerManager->remove_ServiceWorkerRegistered(m_serviceWorkerRegisteredToken); + } + + m_webView->remove_ContentLoading(m_contentLoadingToken); +} diff --git a/SampleApps/WebView2APISample/ScenarioServiceWorkerPostMessage.h b/SampleApps/WebView2APISample/ScenarioServiceWorkerPostMessage.h new file mode 100644 index 00000000..2c83d25d --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioServiceWorkerPostMessage.h @@ -0,0 +1,30 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioServiceWorkerPostMessage : public ComponentBase +{ +public: + ScenarioServiceWorkerPostMessage(AppWindow* appWindow); + ~ScenarioServiceWorkerPostMessage() override; + +private: + void SetupEventsOnWebview(); + void CreateServiceWorkerManager(); + void SetupEventsOnServiceWorker( + wil::com_ptr serviceWorker); + void AddToCache( + std::wstring url, wil::com_ptr serviceWorker); + + AppWindow* m_appWindow; + wil::com_ptr m_webView; + std::wstring m_sampleUri; + wil::com_ptr m_serviceWorkerManager; + EventRegistrationToken m_contentLoadingToken = {}; + EventRegistrationToken m_serviceWorkerRegisteredToken = {}; +}; diff --git a/SampleApps/WebView2APISample/ScenarioServiceWorkerPostMessageSetting.cpp b/SampleApps/WebView2APISample/ScenarioServiceWorkerPostMessageSetting.cpp new file mode 100644 index 00000000..7044b1cc --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioServiceWorkerPostMessageSetting.cpp @@ -0,0 +1,209 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "stdafx.h" +#include + +#include "CheckFailure.h" + +#include "ScenarioServiceWorkerPostMessageSetting.h" + +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = L"scenario_sw_post_msg_scope/index2.html"; + +ScenarioServiceWorkerPostMessageSetting::ScenarioServiceWorkerPostMessageSetting( + AppWindow* appWindow) + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) +{ + SetupEventsOnWebview(); +} + +ScenarioServiceWorkerPostMessageSetting::~ScenarioServiceWorkerPostMessageSetting() +{ + UnregisterAllServiceWorkers(); + m_webView->remove_ContentLoading(m_contentLoadingToken); + m_webView->remove_WebMessageReceived(m_webMessageReceivedToken); + if (m_serviceWorkerManager) + { + m_serviceWorkerManager->remove_ServiceWorkerRegistered(m_serviceWorkerRegisteredToken); + } +} + +void ScenarioServiceWorkerPostMessageSetting::UnregisterAllServiceWorkers() +{ + m_webView->ExecuteScript( + L"navigator.serviceWorker.getRegistrations().then(function(registrations) {" + L" for(let registration of registrations) {" + L" registration.unregister();" + L" }" + L"});", + nullptr); +} + +void ScenarioServiceWorkerPostMessageSetting::ToggleServiceWorkerJsApiSetting() +{ + // Unregister all the existing service workers before toggling the setting. + // So that the setting can be applied to new service workers. + UnregisterAllServiceWorkers(); + auto webView2_13 = m_webView.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webView2_13); + + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + auto webViewExperimentalProfile15 = + webView2Profile.try_query(); + + if (webViewExperimentalProfile15) + { + BOOL isEnabled; + //! [AreWebViewScriptApisEnabledForServiceWorkers] + CHECK_FAILURE( + webViewExperimentalProfile15->get_AreWebViewScriptApisEnabledForServiceWorkers( + &isEnabled)); + CHECK_FAILURE( + webViewExperimentalProfile15->put_AreWebViewScriptApisEnabledForServiceWorkers( + !isEnabled)); + //! [AreWebViewScriptApisEnabledForServiceWorkers] + + MessageBox( + nullptr, + (std::wstring(L"Service Worker JS API setting has been ") + + (!isEnabled ? L"enabled." : L"disabled.")) + .c_str(), + L"Service Worker JS API Setting", MB_OK); + } + + // Setup events on webview2 to listen message from service worker + // main thread. + m_sampleUri = m_appWindow->GetLocalUri(c_samplePath); + CHECK_FAILURE(m_webView->Navigate(m_sampleUri.c_str())); +} + +void ScenarioServiceWorkerPostMessageSetting::SetupEventsOnWebview() +{ + + // Turn off this scenario if we navigate away from the sample page. + CHECK_FAILURE(m_webView->add_ContentLoading( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2ContentLoadingEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string uri; + sender->get_Source(&uri); + if (uri.get() != m_sampleUri) + { + m_appWindow->DeleteComponent(this); + } + return S_OK; + }) + .Get(), + &m_contentLoadingToken)); + + // Setup WebMessageReceived event to receive message from main thread. + m_webView->add_WebMessageReceived( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) + -> HRESULT + { + wil::unique_cotaskmem_string message; + CHECK_FAILURE(args->TryGetWebMessageAsString(&message)); + + std::wstring msgStr = message.get(); + if (msgStr == L"MessageFromMainThread") + { + std::wstringstream message{}; + message << L"Message: " << std::endl + << L"Service Worker Message from Main thread. Service worker " + L"direct messaging disabled." + << std::endl; + m_appWindow->AsyncMessageBox(message.str(), L"Message from Service Worker"); + } + return S_OK; + }) + .Get(), + &m_webMessageReceivedToken); + + // Get ServiceWorkerManager from profile and setup events to listen to service worker post + // messages. + auto webView2_13 = m_webView.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webView2_13); + + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + auto webViewExperimentalProfile13 = + webView2Profile.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webViewExperimentalProfile13); + CHECK_FAILURE( + webViewExperimentalProfile13->get_ServiceWorkerManager(&m_serviceWorkerManager)); + + CHECK_FAILURE(m_serviceWorkerManager->add_ServiceWorkerRegistered( + Callback( + [this]( + ICoreWebView2ExperimentalServiceWorkerManager* sender, + ICoreWebView2ExperimentalServiceWorkerRegisteredEventArgs* args) + { + wil::com_ptr + serviceWorkerRegistration; + CHECK_FAILURE(args->get_ServiceWorkerRegistration(&serviceWorkerRegistration)); + + if (serviceWorkerRegistration) + { + wil::com_ptr serviceWorker; + CHECK_FAILURE( + serviceWorkerRegistration->get_ActiveServiceWorker(&serviceWorker)); + + if (serviceWorker) + { + SetupEventsOnServiceWorker(serviceWorker); + } + else + { + CHECK_FAILURE(serviceWorkerRegistration->add_ServiceWorkerActivated( + Callback< + ICoreWebView2ExperimentalServiceWorkerActivatedEventHandler>( + [this]( + ICoreWebView2ExperimentalServiceWorkerRegistration* sender, + ICoreWebView2ExperimentalServiceWorkerActivatedEventArgs* + args) -> HRESULT + { + wil::com_ptr + serviceWorker; + CHECK_FAILURE( + args->get_ActiveServiceWorker(&serviceWorker)); + SetupEventsOnServiceWorker(serviceWorker); + + return S_OK; + }) + .Get(), + nullptr)); + } + } + + return S_OK; + }) + .Get(), + &m_serviceWorkerRegisteredToken)); +} + +void ScenarioServiceWorkerPostMessageSetting::SetupEventsOnServiceWorker( + wil::com_ptr serviceWorker) +{ + serviceWorker->add_WebMessageReceived( + Callback( + [this]( + ICoreWebView2ExperimentalServiceWorker* sender, + ICoreWebView2WebMessageReceivedEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string messageRaw; + CHECK_FAILURE(args->TryGetWebMessageAsString(&messageRaw)); + std::wstring messageFromWorker = messageRaw.get(); + + std::wstringstream message{}; + message << L"Message: " << std::endl << messageFromWorker << std::endl; + m_appWindow->AsyncMessageBox(message.str(), L"Message from Service Worker"); + + return S_OK; + }) + .Get(), + nullptr); +} diff --git a/SampleApps/WebView2APISample/ScenarioServiceWorkerPostMessageSetting.h b/SampleApps/WebView2APISample/ScenarioServiceWorkerPostMessageSetting.h new file mode 100644 index 00000000..cd85aeaf --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioServiceWorkerPostMessageSetting.h @@ -0,0 +1,31 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once +#include "stdafx.h" + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioServiceWorkerPostMessageSetting : public ComponentBase +{ +public: + ScenarioServiceWorkerPostMessageSetting(AppWindow* appWindow); + ~ScenarioServiceWorkerPostMessageSetting() override; + void SetupEventsOnWebview(); + void SetupEventsOnServiceWorker( + wil::com_ptr serviceWorker); + + void ToggleServiceWorkerJsApiSetting(); + void UnregisterAllServiceWorkers(); + +private: + AppWindow* m_appWindow; + wil::com_ptr m_webView; + wil::com_ptr m_serviceWorkerManager; + std::wstring m_sampleUri; + EventRegistrationToken m_serviceWorkerRegisteredToken = {}; + EventRegistrationToken m_contentLoadingToken = {}; + EventRegistrationToken m_webMessageReceivedToken = {}; +}; diff --git a/SampleApps/WebView2APISample/ScenarioServiceWorkerWRR.cpp b/SampleApps/WebView2APISample/ScenarioServiceWorkerWRR.cpp new file mode 100644 index 00000000..c2c91b21 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioServiceWorkerWRR.cpp @@ -0,0 +1,100 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "ScenarioServiceWorkerWRR.h" + +#include "AppWindow.h" +#include "CheckFailure.h" + +#include "shlwapi.h" + +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = + L"https://mdn.github.io/dom-examples/service-worker/simple-service-worker/"; +static constexpr WCHAR c_wrrUrlPattern[] = L"*"; + +ScenarioServiceWorkerWRR::ScenarioServiceWorkerWRR(AppWindow* appWindow) + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()), m_sampleUri(c_samplePath) +{ + wil::com_ptr webView_22 = m_webView.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webView_22); + + webView_22->AddWebResourceRequestedFilterWithRequestSourceKinds( + c_wrrUrlPattern, COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL, + COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL); + webView_22->add_WebResourceRequested( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2WebResourceRequestedEventArgs* args) + -> HRESULT + { + COREWEBVIEW2_WEB_RESOURCE_CONTEXT resourceContext; + args->get_ResourceContext(&resourceContext); + wil::com_ptr request; + CHECK_FAILURE(args->get_Request(&request)); + wil::unique_cotaskmem_string uri; + CHECK_FAILURE(request->get_Uri(&uri)); + if (wcscmp(uri.get(), c_samplePath) != 0) + { + return S_OK; + } + + wil::com_ptr stream; + // Create a stream with some text content + std::string content = "

Response from WV2 " + "interceptor!

"; + + stream.attach(SHCreateMemStream( + reinterpret_cast(content.c_str()), + static_cast(content.size()))); + + wil::com_ptr response; + wil::com_ptr environment; + wil::com_ptr webview2; + m_webView->QueryInterface(IID_PPV_ARGS(&webview2)); + webview2->get_Environment(&environment); + environment->CreateWebResourceResponse( + stream.get(), 200, L"OK", L"Content-Type: text/html", &response); + args->put_Response(response.get()); + return S_OK; + }) + .Get(), + &m_webResourceRequestedToken); + + // Turn off this scenario if we navigate away from the sample page. + CHECK_FAILURE(m_webView->add_ContentLoading( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2ContentLoadingEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string uri; + sender->get_Source(&uri); + if (uri.get() != m_sampleUri) + { + m_appWindow->DeleteComponent(this); + } + return S_OK; + }) + .Get(), + &m_contentLoadingToken)); + + CHECK_FAILURE(m_webView->Navigate(m_sampleUri.c_str())); +} + +ScenarioServiceWorkerWRR::~ScenarioServiceWorkerWRR() +{ + wil::com_ptr webView_22 = m_webView.try_query(); + if (webView_22) + { + CHECK_FAILURE(webView_22->RemoveWebResourceRequestedFilterWithRequestSourceKinds( + c_wrrUrlPattern, COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL, + COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL)); + } + + CHECK_FAILURE(m_webView->remove_WebResourceRequested(m_webResourceRequestedToken)); + m_webView->remove_ContentLoading(m_contentLoadingToken); +} diff --git a/SampleApps/WebView2APISample/ScenarioServiceWorkerWRR.h b/SampleApps/WebView2APISample/ScenarioServiceWorkerWRR.h new file mode 100644 index 00000000..5d0e6ce0 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioServiceWorkerWRR.h @@ -0,0 +1,26 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include + +#include "AppWindow.h" +#include "ComponentBase.h" + +// This sample demonstrates how to intercept Service Worker requests with +// WebResourceRequested event. +class ScenarioServiceWorkerWRR : public ComponentBase +{ +public: + ScenarioServiceWorkerWRR(AppWindow* appWindow); + ~ScenarioServiceWorkerWRR() override; + +private: + AppWindow* m_appWindow; + wil::com_ptr m_webView; + std::wstring m_sampleUri; + EventRegistrationToken m_contentLoadingToken = {}; + EventRegistrationToken m_webResourceRequestedToken = {}; +}; diff --git a/SampleApps/WebView2APISample/ScenarioSharedBuffer.cpp b/SampleApps/WebView2APISample/ScenarioSharedBuffer.cpp new file mode 100644 index 00000000..45bd4c81 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioSharedBuffer.cpp @@ -0,0 +1,233 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include +#include + +#include "ScenarioSharedBuffer.h" + +#include "AppWindow.h" +#include "CheckFailure.h" + +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = L"ScenarioSharedBuffer.html"; + +ScenarioSharedBuffer::ScenarioSharedBuffer(AppWindow* appWindow) + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) +{ + m_webView17 = m_webView.try_query(); + if (!m_webView17) + { + // Feature not supported. + return; + } + + m_sampleUri = m_appWindow->GetLocalUri(c_samplePath); + + // Turn off this scenario if we navigate away from the sample page + CHECK_FAILURE(m_webView->add_ContentLoading( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2ContentLoadingEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string uri; + sender->get_Source(&uri); + if (uri.get() != m_sampleUri) + { + m_appWindow->DeleteComponent(this); + } + return S_OK; + }) + .Get(), + &m_contentLoadingToken)); + + CHECK_FAILURE(m_webView->add_WebMessageReceived( + Microsoft::WRL::Callback( + [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) + { + WebViewMessageReceived(args, false); + return S_OK; + }) + .Get(), + &m_webMessageReceivedToken)); + + wil::com_ptr webview2_4 = m_webView.try_query(); + if (webview2_4) + { + CHECK_FAILURE(webview2_4->add_FrameCreated( + Callback( + [this]( + ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args) -> HRESULT + { + wil::com_ptr webviewFrame; + CHECK_FAILURE(args->get_Frame(&webviewFrame)); + wil::com_ptr webviewFrame2 = + webviewFrame.try_query(); + if (!webviewFrame2) + { + return S_OK; + } + CHECK_FAILURE(webviewFrame2->add_WebMessageReceived( + Microsoft::WRL::Callback< + ICoreWebView2FrameWebMessageReceivedEventHandler>( + [this]( + ICoreWebView2Frame* sender, + ICoreWebView2WebMessageReceivedEventArgs* args) + { + WebViewMessageReceived(args, true); + return S_OK; + }) + .Get(), + nullptr)); + m_webviewFrame4 = webviewFrame.try_query(); + return S_OK; + }) + .Get(), + &m_frameCreatedToken)); + } + + // Changes to CoreWebView2 settings apply to the next document to which we navigate. + CHECK_FAILURE(m_webView->Navigate(m_sampleUri.c_str())); +} + +void ScenarioSharedBuffer::DisplaySharedBufferData() +{ + if (!m_sharedBuffer) + { + m_appWindow->AsyncMessageBox(L"Share Buffer not setup", L"Shared Buffer Data"); + return; + } + BYTE* buffer = nullptr; + UINT64 size = 0; + CHECK_FAILURE(m_sharedBuffer->get_Buffer(&buffer)); + CHECK_FAILURE(m_sharedBuffer->get_Size(&size)); + // Display first 256 bytes of the data + std::wstringstream message; + message << L"Share Buffer Data:" << std::endl; + for (int i = 0; i < size && i < 256; ++i) + { + if (isprint(buffer[i])) + message << (char)buffer[i]; + else + message << "0x" << std::hex << std::setfill(L'0') << std::setw(2) << buffer[i]; + } + message << std::endl; + m_appWindow->AsyncMessageBox(std::move(message.str()), L"Shared Buffer Data"); +} + +void ScenarioSharedBuffer::WebViewMessageReceived( + ICoreWebView2WebMessageReceivedEventArgs* args, bool fromFrame) +{ + wil::unique_cotaskmem_string uri; + CHECK_FAILURE(args->get_Source(&uri)); + + // Always validate that the origin of the message is what you expect. + if (uri.get() != m_sampleUri) + { + // Ignore messages from untrusted sources. + return; + } + wil::unique_cotaskmem_string messageRaw; + HRESULT hr = args->TryGetWebMessageAsString(&messageRaw); + if (hr == E_INVALIDARG) + { + // Was not a string message. Ignore. + return; + } + // Any other problems are fatal. + CHECK_FAILURE(hr); + std::wstring message = messageRaw.get(); + + if (message == L"SharedBufferDataUpdated") + { + // Shared buffer updated, display it. + DisplaySharedBufferData(); + } + else if (message == L"RequestShareBuffer") + { + EnsureSharedBuffer(); + if (fromFrame) + { + m_webviewFrame4->PostSharedBufferToScript( + m_sharedBuffer.get(), COREWEBVIEW2_SHARED_BUFFER_ACCESS_READ_WRITE, nullptr); + } + else + { + m_webView17->PostSharedBufferToScript( + m_sharedBuffer.get(), COREWEBVIEW2_SHARED_BUFFER_ACCESS_READ_WRITE, nullptr); + } + } + else if (message == L"RequestOneTimeShareBuffer") + { + const UINT64 bufferSize = 128; + BYTE data[] = "some read only data"; + //! [OneTimeShareBuffer] + wil::com_ptr environment; + CHECK_FAILURE( + m_appWindow->GetWebViewEnvironment()->QueryInterface(IID_PPV_ARGS(&environment))); + + wil::com_ptr sharedBuffer; + CHECK_FAILURE(environment->CreateSharedBuffer(bufferSize, &sharedBuffer)); + // Set data into the shared memory via IStream. + wil::com_ptr stream; + CHECK_FAILURE(sharedBuffer->OpenStream(&stream)); + CHECK_FAILURE(stream->Write(data, sizeof(data), nullptr)); + PCWSTR additionalDataAsJson = L"{\"myBufferType\":\"bufferType1\"}"; + if (fromFrame) + { + m_webviewFrame4->PostSharedBufferToScript( + sharedBuffer.get(), COREWEBVIEW2_SHARED_BUFFER_ACCESS_READ_ONLY, + additionalDataAsJson); + } + else + { + m_webView17->PostSharedBufferToScript( + sharedBuffer.get(), COREWEBVIEW2_SHARED_BUFFER_ACCESS_READ_ONLY, + additionalDataAsJson); + } + // Explicitly close the one time shared buffer to ensure that the resource is released. + sharedBuffer->Close(); + //! [OneTimeShareBuffer] + } + else + { + // Ignore unrecognized messages, but log for further investigation + // since it suggests a mismatch between the web content and the host. + OutputDebugString( + std::wstring(L"Unexpected message from main page:" + message).c_str()); + } +} + +void ScenarioSharedBuffer::EnsureSharedBuffer() +{ + if (m_sharedBuffer) + { + // already created + return; + } + wil::com_ptr environment; + CHECK_FAILURE( + m_appWindow->GetWebViewEnvironment()->QueryInterface(IID_PPV_ARGS(&environment))); + + const UINT64 size = 128; + CHECK_FAILURE(environment->CreateSharedBuffer(size, &m_sharedBuffer)); + // Set some data into the shared memory + BYTE* buffer = nullptr; + CHECK_FAILURE(m_sharedBuffer->get_Buffer(&buffer)); + BYTE data[] = "some app data"; + memcpy(buffer, data, sizeof(data)); +} + +ScenarioSharedBuffer::~ScenarioSharedBuffer() +{ + m_webView->remove_ContentLoading(m_contentLoadingToken); + m_webView->remove_WebMessageReceived(m_webMessageReceivedToken); + wil::com_ptr webview2_4 = m_webView.try_query(); + if (webview2_4) + { + webview2_4->remove_FrameCreated(m_frameCreatedToken); + } +} diff --git a/SampleApps/WebView2APISample/ScenarioSharedBuffer.h b/SampleApps/WebView2APISample/ScenarioSharedBuffer.h new file mode 100644 index 00000000..28970f1d --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioSharedBuffer.h @@ -0,0 +1,35 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "stdafx.h" + +#include + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioSharedBuffer : public ComponentBase +{ +public: + ScenarioSharedBuffer(AppWindow* appWindow); + + ~ScenarioSharedBuffer() override; + +private: + void WebViewMessageReceived(ICoreWebView2WebMessageReceivedEventArgs* args, bool fromFrame); + void EnsureSharedBuffer(); + void DisplaySharedBufferData(); + + AppWindow* m_appWindow; + wil::com_ptr m_webView; + wil::com_ptr m_webView17; + wil::com_ptr m_webviewFrame4; + wil::com_ptr m_sharedBuffer; + std::wstring m_sampleUri; + EventRegistrationToken m_webMessageReceivedToken = {}; + EventRegistrationToken m_contentLoadingToken = {}; + EventRegistrationToken m_frameCreatedToken = {}; +}; diff --git a/SampleApps/WebView2APISample/ScenarioSharedWorkerManager.cpp b/SampleApps/WebView2APISample/ScenarioSharedWorkerManager.cpp new file mode 100644 index 00000000..0d682155 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioSharedWorkerManager.cpp @@ -0,0 +1,132 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" +#include + +#include "CheckFailure.h" + +#include "ScenarioSharedWorkerManager.h" + +using namespace Microsoft::WRL; + +ScenarioSharedWorkerManager::ScenarioSharedWorkerManager(AppWindow* appWindow) + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) +{ + GetSharedWorkerManager(); + SetupEventsOnWebview(); +} + +void ScenarioSharedWorkerManager::GetSharedWorkerManager() +{ + //! [SharedWorkerManager] + auto webView2_13 = m_webView.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webView2_13); + + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + auto webViewExperimentalProfile13 = + webView2Profile.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webViewExperimentalProfile13); + CHECK_FAILURE( + webViewExperimentalProfile13->get_SharedWorkerManager(&m_sharedWorkerManager)); + //! [SharedWorkerManager] +} + +void ScenarioSharedWorkerManager::SetupEventsOnWebview() +{ + if (!m_sharedWorkerManager) + { + return; + } + + //! [SharedWorkerCreated] + CHECK_FAILURE(m_sharedWorkerManager->add_SharedWorkerCreated( + Callback( + [this]( + ICoreWebView2ExperimentalSharedWorkerManager* sender, + ICoreWebView2ExperimentalSharedWorkerCreatedEventArgs* args) + { + wil::com_ptr sharedWorker; + CHECK_FAILURE(args->get_Worker(&sharedWorker)); + + wil::unique_cotaskmem_string scriptUri; + CHECK_FAILURE(sharedWorker->get_ScriptUri(&scriptUri)); + + std::wstring scriptUriStr(scriptUri.get()); + m_appWindow->AsyncMessageBox(scriptUriStr, L"Shared worker is created"); + + // Subscribe to worker destroying event + sharedWorker->add_Destroying( + Callback( + [this, scriptUriStr]( + ICoreWebView2ExperimentalSharedWorker* sender, + IUnknown* args) -> HRESULT + { + /*Cleanup on worker destruction*/ + m_appWindow->AsyncMessageBox( + scriptUriStr, L"Shared worker is destroyed"); + return S_OK; + }) + .Get(), + nullptr); + + return S_OK; + }) + .Get(), + &m_sharedWorkerCreatedToken)); + //! [SharedWorkerCreated] +} + +void ScenarioSharedWorkerManager::GetAllSharedWorkers() +{ + CHECK_FEATURE_RETURN_EMPTY(m_sharedWorkerManager); + CHECK_FAILURE(m_sharedWorkerManager->GetSharedWorkers( + Callback( + [this]( + HRESULT error, + ICoreWebView2ExperimentalSharedWorkerCollectionView* workersCollection) + -> HRESULT + { + UINT32 workersCount = 0; + CHECK_FAILURE(workersCollection->get_Count(&workersCount)); + + std::wstringstream message{}; + message << L"Number of shared workers created: " << workersCount << std::endl; + + for (UINT32 i = 0; i < workersCount; i++) + { + ComPtr sharedWorker; + CHECK_FAILURE(workersCollection->GetValueAtIndex(i, &sharedWorker)); + + wil::unique_cotaskmem_string scriptUri; + CHECK_FAILURE(sharedWorker->get_ScriptUri(&scriptUri)); + + wil::unique_cotaskmem_string origin; + CHECK_FAILURE(sharedWorker->get_Origin(&origin)); + + wil::unique_cotaskmem_string topLevelOrigin; + CHECK_FAILURE(sharedWorker->get_TopLevelOrigin(&topLevelOrigin)); + + message << L"ScriptUri: " << scriptUri.get(); + message << L" Origin: " << origin.get(); + message << L" TopLevelOrigin: " << topLevelOrigin.get(); + message << std::endl; + } + + m_appWindow->AsyncMessageBox( + std::move(message.str()), L"Get all shared workers"); + + return S_OK; + }) + .Get())); +} + +ScenarioSharedWorkerManager::~ScenarioSharedWorkerManager() +{ + if (m_sharedWorkerManager) + { + m_sharedWorkerManager->remove_SharedWorkerCreated(m_sharedWorkerCreatedToken); + } +} diff --git a/SampleApps/WebView2APISample/ScenarioSharedWorkerManager.h b/SampleApps/WebView2APISample/ScenarioSharedWorkerManager.h new file mode 100644 index 00000000..021d11dd --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioSharedWorkerManager.h @@ -0,0 +1,26 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioSharedWorkerManager : public ComponentBase +{ +public: + ScenarioSharedWorkerManager(AppWindow* appWindow); + ~ScenarioSharedWorkerManager() override; + + void GetAllSharedWorkers(); + +private: + void SetupEventsOnWebview(); + void GetSharedWorkerManager(); + + AppWindow* m_appWindow; + wil::com_ptr m_webView; + wil::com_ptr m_sharedWorkerManager; + EventRegistrationToken m_sharedWorkerCreatedToken = {}; +}; diff --git a/SampleApps/WebView2APISample/ScenarioSharedWorkerWRR.cpp b/SampleApps/WebView2APISample/ScenarioSharedWorkerWRR.cpp new file mode 100644 index 00000000..02470aa1 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioSharedWorkerWRR.cpp @@ -0,0 +1,81 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "stdafx.h" + +#include "ScenarioSharedWorkerWRR.h" + +#include "AppWindow.h" +#include "CheckFailure.h" + +#include + +using namespace Microsoft::WRL; + +ScenarioSharedWorkerWRR::ScenarioSharedWorkerWRR(AppWindow* appWindow) + : m_webView(appWindow->GetWebView()) +{ + //! [WebResourceRequested2] + wil::com_ptr webView = m_webView.try_query(); + if (webView) + { + // Filter must be added for application to receive any WebResourceRequested event + CHECK_FAILURE(webView->AddWebResourceRequestedFilterWithRequestSourceKinds( + L"*worker.js", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL, + COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL)); + CHECK_FAILURE(m_webView->add_WebResourceRequested( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2WebResourceRequestedEventArgs* args) + { + wil::com_ptr + webResourceRequestArgs; + if (SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&webResourceRequestArgs)))) + { + COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS requestSourceKind = + COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL; + CHECK_FAILURE(webResourceRequestArgs->get_RequestedSourceKind( + &requestSourceKind)); + // Ensure that script is from shared worker source + if (requestSourceKind == + COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_SHARED_WORKER) + { + Microsoft::WRL::ComPtr response_stream; + CHECK_FAILURE(SHCreateStreamOnFileEx( + L"assets/DemoWorker.js", STGM_READ, FILE_ATTRIBUTE_NORMAL, + FALSE, nullptr, &response_stream)); + + Microsoft::WRL::ComPtr response; + // Get the default webview environment + Microsoft::WRL::ComPtr webview2; + CHECK_FAILURE(sender->QueryInterface(IID_PPV_ARGS(&webview2))); + + Microsoft::WRL::ComPtr environment; + CHECK_FAILURE(webview2->get_Environment(&environment)); + CHECK_FAILURE(environment->CreateWebResourceResponse( + response_stream.Get(), 200, L"OK", L"", &response)); + + CHECK_FAILURE(args->put_Response(response.Get())); + } + } + return S_OK; + }) + .Get(), + &m_webResourceRequestedToken)); + } + //! [WebResourceRequested2] + + CHECK_FAILURE(m_webView->Navigate( + L"https://mdn.github.io/dom-examples/web-workers/simple-shared-worker/index2.html")); +} + +ScenarioSharedWorkerWRR::~ScenarioSharedWorkerWRR() +{ + wil::com_ptr webView = m_webView.try_query(); + if (webView) + { + CHECK_FAILURE(webView->RemoveWebResourceRequestedFilterWithRequestSourceKinds( + L"*worker.js", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL, + COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL)); + } + CHECK_FAILURE(m_webView->remove_WebResourceRequested(m_webResourceRequestedToken)); +} diff --git a/SampleApps/WebView2APISample/ScenarioSharedWorkerWRR.h b/SampleApps/WebView2APISample/ScenarioSharedWorkerWRR.h new file mode 100644 index 00000000..51145cc7 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioSharedWorkerWRR.h @@ -0,0 +1,23 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once +#include "stdafx.h" + +#include + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioSharedWorkerWRR : public ComponentBase +{ +public: + ScenarioSharedWorkerWRR(AppWindow* appWindow); + ~ScenarioSharedWorkerWRR() override; + +private: + EventRegistrationToken m_webResourceRequestedToken = {}; + + wil::com_ptr m_webView; +}; diff --git a/SampleApps/WebView2APISample/ScenarioThrottlingControl.cpp b/SampleApps/WebView2APISample/ScenarioThrottlingControl.cpp new file mode 100644 index 00000000..8e75cf7e --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioThrottlingControl.cpp @@ -0,0 +1,291 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "ScenarioThrottlingControl.h" + +#include "CheckFailure.h" +#include "ScriptComponent.h" + +using namespace Microsoft::WRL; + +ScenarioThrottlingControl::ScenarioThrottlingControl(AppWindow* appWindow) + : m_appWindow(appWindow), m_webview(appWindow->GetWebView()) +{ +#pragma region init_monitor + m_appWindow->EnableHandlingNewWindowRequest(false); + CHECK_FAILURE(m_webview->add_NewWindowRequested( + Callback( + [this, + appWindow](ICoreWebView2* sender, ICoreWebView2NewWindowRequestedEventArgs* args) + { + wil::com_ptr deferral; + CHECK_FAILURE(args->GetDeferral(&deferral)); + + auto initCallback = [args, deferral, this]() + { + m_monitorWebview = m_monitorAppWindow->GetWebView(); + CHECK_FAILURE(args->put_NewWindow(m_monitorAppWindow->GetWebView())); + CHECK_FAILURE(args->put_Handled(TRUE)); + + CHECK_FAILURE(m_monitorWebview->add_WebMessageReceived( + Microsoft::WRL::Callback( + [this]( + ICoreWebView2* sender, + ICoreWebView2WebMessageReceivedEventArgs* args) + { + WebViewMessageReceived(args); + return S_OK; + }) + .Get(), + &m_webMessageReceivedToken)); + + CHECK_FAILURE(deferral->Complete()); + }; + + // passing "none" as uri as its a noinitialnavigation + m_monitorAppWindow = new AppWindow( + IDM_CREATION_MODE_WINDOWED, appWindow->GetWebViewOption(), L"none", + appWindow->GetUserDataFolder(), false /* isMainWindow */, + initCallback /* webviewCreatedCallback */, true /* customWindowRect */, + {100, 100, 1720, 1360}, false /* shouldHaveToolbar */, true /* isPopup */); + + m_monitorAppWindow->SetOnAppWindowClosing( + [&] { m_appWindow->DeleteComponent(this); }); + + return S_OK; + }) + .Get(), + nullptr)); +#pragma endregion init_monitor + +#pragma region init_target + // Turn off this scenario if we navigate away from the sample page + CHECK_FAILURE(m_webview->add_ContentLoading( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2ContentLoadingEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string uri; + sender->get_Source(&uri); + if (uri.get() != m_targetUri) + { + m_appWindow->DeleteComponent(this); + } + return S_OK; + }) + .Get(), + &m_contentLoadingToken)); + + // While actual WebView creation in this sample app is outside the scope of + // this component, calling these functions here is equivalent to calling + // them upon WebView creation for the purposes of this feature. In a real + // application, you would usually call these after WebView is created and + // before the first navigation. + OnWebViewCreated(); + SetupIsolatedFramesHandler(); + + m_targetUri = m_appWindow->GetLocalUri(std::wstring(L"ScenarioThrottlingControl.html")); + m_webview->Navigate(m_targetUri.c_str()); +#pragma endregion init_target +} + +// App is responsible for calling this function. An app would usually call this +// function from within the callback passed to +// CreateCoreWebView2Controller(WithOptions). +void ScenarioThrottlingControl::OnWebViewCreated() +{ + wil::com_ptr settings; + m_webview->get_Settings(&settings); + auto settings9 = settings.try_query(); + + // Store the default values from the WebView2 Runtime so we can restore them + // later. + CHECK_FAILURE(settings9->get_PreferredForegroundTimerWakeIntervalInMilliseconds( + &m_defaultIntervalForeground)); + CHECK_FAILURE(settings9->get_PreferredBackgroundTimerWakeIntervalInMilliseconds( + &m_defaultIntervalBackground)); + CHECK_FAILURE(settings9->get_PreferredIntensiveTimerWakeIntervalInMilliseconds( + &m_defaultIntervalIntensive)); + CHECK_FAILURE(settings9->get_PreferredOverrideTimerWakeIntervalInMilliseconds( + &m_defaultIntervalOverride)); +} + +// The primary use-case here is an app embedding 3rd party content and wanting +// to be able to independently limit the performance impact of it. Generally, +// that's something like "low battery, throttle more" or "giving the frame N +// seconds to run some logic, throttle less". +void ScenarioThrottlingControl::SetupIsolatedFramesHandler() +{ + auto webview4 = m_webview.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webview4); + + // You can use the frame properties to determine whether it should be + // marked to be throttled separately from main frame. + CHECK_FAILURE(webview4->add_FrameCreated( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args) -> HRESULT + { + wil::com_ptr webviewFrame; + CHECK_FAILURE(args->get_Frame(&webviewFrame)); + + auto webviewExperimentalFrame7 = + webviewFrame.try_query(); + CHECK_FEATURE_RETURN_HRESULT(webviewExperimentalFrame7); + + wil::unique_cotaskmem_string name; + CHECK_FAILURE(webviewFrame->get_Name(&name)); + if (wcscmp(name.get(), L"untrusted") == 0) + { + CHECK_FAILURE( + webviewExperimentalFrame7->put_UseOverrideTimerWakeInterval(TRUE)); + } + + return S_OK; + }) + .Get(), + &m_frameCreatedToken)); + + wil::com_ptr settings; + m_webview->get_Settings(&settings); + auto settings9 = settings.try_query(); + + // Restrict frames selected by the above callback to always match the default + // timer interval for background frames. + CHECK_FAILURE(settings9->put_PreferredOverrideTimerWakeIntervalInMilliseconds( + m_defaultIntervalBackground)); +} + +void ScenarioThrottlingControl::WebViewMessageReceived( + ICoreWebView2WebMessageReceivedEventArgs* args) +{ + // received command from monitor, handle + wil::unique_cotaskmem_string json; + CHECK_FAILURE(args->get_WebMessageAsJson(&json)); + + auto command = GetJSONStringField(json.get(), L"command"); + if (command.compare(L"set-interval") == 0) + { + auto category = GetJSONStringField(json.get(), L"priority"); + auto interval = GetJSONStringField(json.get(), L"intervalMs"); + + wil::com_ptr settings; + m_webview->get_Settings(&settings); + auto settings9 = settings.try_query(); + CHECK_FEATURE_RETURN_EMPTY(settings9); + + if (category.compare(L"foreground") == 0) + { + CHECK_FAILURE(settings9->put_PreferredForegroundTimerWakeIntervalInMilliseconds( + std::stoul(interval))); + } + else if (category.compare(L"background") == 0) + { + CHECK_FAILURE(settings9->put_PreferredBackgroundTimerWakeIntervalInMilliseconds( + std::stoul(interval))); + } + else if (category.compare(L"untrusted") == 0) + { + CHECK_FAILURE(settings9->put_PreferredOverrideTimerWakeIntervalInMilliseconds( + std::stoul(interval))); + } + } + else if (command.compare(L"toggle-visibility") == 0) + { + BOOL visible; + m_appWindow->GetWebViewController()->get_IsVisible(&visible); + m_appWindow->GetWebViewController()->put_IsVisible(!visible); + } + else if (command.compare(L"scenario") == 0) + { + auto label = GetJSONStringField(json.get(), L"label"); + if (label.compare(L"interaction-throttle") == 0) + { + OnNoUserInteraction(); + } + else if (label.compare(L"interaction-reset") == 0) + { + OnUserInteraction(); + } + else if (label.compare(L"hidden-unthrottle") == 0) + { + HideWebView(); + } + else if (label.compare(L"hidden-reset") == 0) + { + ShowWebView(); + } + } +} + +// This sample app calls this method when receiving a simulated event from its +// control monitor, but your app can decide how and when to go into this state. +void ScenarioThrottlingControl::OnNoUserInteraction() +{ + wil::com_ptr settings; + m_webview->get_Settings(&settings); + auto settings9 = settings.try_query(); + CHECK_FEATURE_RETURN_EMPTY(settings9); + + // User is not interactive, keep webview visible but throttle foreground + // timers to 500ms. + CHECK_FAILURE(settings9->put_PreferredForegroundTimerWakeIntervalInMilliseconds(500)); +} + +void ScenarioThrottlingControl::OnUserInteraction() +{ + wil::com_ptr settings; + m_webview->get_Settings(&settings); + auto settings9 = settings.try_query(); + CHECK_FEATURE_RETURN_EMPTY(settings9); + + // User is interactive again, set foreground timer interval back to its + // default value. + CHECK_FAILURE(settings9->put_PreferredForegroundTimerWakeIntervalInMilliseconds( + m_defaultIntervalForeground)); +} + +// Prepares the WebView to go into hidden mode with no background timer +// throttling. +void ScenarioThrottlingControl::HideWebView() +{ + wil::com_ptr settings; + m_webview->get_Settings(&settings); + auto settings9 = settings.try_query(); + CHECK_FEATURE_RETURN_EMPTY(settings9); + + // This WebView2 will remain hidden but needs to keep running timers. + // Unthrottle background timers. + CHECK_FAILURE(settings9->put_PreferredBackgroundTimerWakeIntervalInMilliseconds(0)); + // Effectively disable intensive throttling by overriding its timer interval. + CHECK_FAILURE(settings9->put_PreferredIntensiveTimerWakeIntervalInMilliseconds(0)); + + CHECK_FAILURE(m_appWindow->GetWebViewController()->put_IsVisible(FALSE)); +} + +// Shows the WebView and restores default throttling behavior. +void ScenarioThrottlingControl::ShowWebView() +{ + CHECK_FAILURE(m_appWindow->GetWebViewController()->put_IsVisible(TRUE)); + + wil::com_ptr settings; + m_webview->get_Settings(&settings); + auto settings9 = settings.try_query(); + CHECK_FEATURE_RETURN_EMPTY(settings9); + + CHECK_FAILURE(settings9->put_PreferredBackgroundTimerWakeIntervalInMilliseconds( + m_defaultIntervalBackground)); + CHECK_FAILURE(settings9->put_PreferredIntensiveTimerWakeIntervalInMilliseconds( + m_defaultIntervalIntensive)); +} + +ScenarioThrottlingControl::~ScenarioThrottlingControl() +{ + if (m_monitorAppWindow) + { + m_monitorAppWindow->SetOnAppWindowClosing(nullptr); + ::PostMessage(m_monitorAppWindow->GetMainWindow(), WM_CLOSE, NULL, NULL); + m_monitorAppWindow = nullptr; + } +} diff --git a/SampleApps/WebView2APISample/ScenarioThrottlingControl.h b/SampleApps/WebView2APISample/ScenarioThrottlingControl.h new file mode 100644 index 00000000..5313305a --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioThrottlingControl.h @@ -0,0 +1,48 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "stdafx.h" + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioThrottlingControl : public ComponentBase +{ +public: + ScenarioThrottlingControl(AppWindow* appWindow); + ~ScenarioThrottlingControl() override; + +private: + void WebViewMessageReceived(ICoreWebView2WebMessageReceivedEventArgs* args); + + // Owner/target AppWindow. + AppWindow* m_appWindow = nullptr; + wil::com_ptr m_webview; + void OnWebViewCreated(); + void SetupIsolatedFramesHandler(); + + int m_defaultIntervalForeground = 0; + int m_defaultIntervalBackground = 0; + int m_defaultIntervalIntensive = 0; + int m_defaultIntervalOverride = 0; + + // Monitor AppWindow + AppWindow* m_monitorAppWindow = nullptr; + wil::com_ptr m_monitorWebview; + + std::wstring m_targetUri; + EventRegistrationToken m_contentLoadingToken = {}; + EventRegistrationToken m_frameCreatedToken = {}; + + // Handles commands from the monitor AppWindow + EventRegistrationToken m_webMessageReceivedToken = {}; + + // Scenarios + void OnNoUserInteraction(); + void OnUserInteraction(); + void HideWebView(); + void ShowWebView(); +}; diff --git a/SampleApps/WebView2APISample/ScenarioWebRtcUdpPortConfiguration.cpp b/SampleApps/WebView2APISample/ScenarioWebRtcUdpPortConfiguration.cpp new file mode 100644 index 00000000..3b2809e2 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioWebRtcUdpPortConfiguration.cpp @@ -0,0 +1,48 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "CheckFailure.h" +#include "TextInputDialog.h" + +#include "ScenarioWebRtcUdpPortConfiguration.h" + +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = L"ScenarioWebRtcUdpPortConfiguration.html"; + +ScenarioWebRtcUdpPortConfiguration::ScenarioWebRtcUdpPortConfiguration(AppWindow* appWindow) + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) +{ + // Demonstrates how to configure a custom WebRTC UDP port range using the + // new ICoreWebView2WebRtcPortConfiguration exposed via + // ICoreWebView2ExperimentalEnvironmentOptions. + + // Navigate to a demo page that will trigger WebRTC usage. + m_sampleUri = m_appWindow->GetLocalUri(c_samplePath); + CHECK_FAILURE(m_webView->Navigate(m_sampleUri.c_str())); + + // If we navigate away from the demo page, turn off this scenario. + CHECK_FAILURE(m_webView->add_ContentLoading( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2ContentLoadingEventArgs* /*args*/) + -> HRESULT + { + wil::unique_cotaskmem_string uri; + CHECK_FAILURE(sender->get_Source(&uri)); + if (uri.get() != m_sampleUri) + { + m_appWindow->DeleteComponent(this); + } + return S_OK; + }) + .Get(), + &m_contentLoadingToken)); +} + +ScenarioWebRtcUdpPortConfiguration::~ScenarioWebRtcUdpPortConfiguration() +{ + CHECK_FAILURE(m_webView->remove_ContentLoading(m_contentLoadingToken)); +} \ No newline at end of file diff --git a/SampleApps/WebView2APISample/ScenarioWebRtcUdpPortConfiguration.h b/SampleApps/WebView2APISample/ScenarioWebRtcUdpPortConfiguration.h new file mode 100644 index 00000000..99dcef1f --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioWebRtcUdpPortConfiguration.h @@ -0,0 +1,22 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "AppWindow.h" +#include "ComponentBase.h" + +// Demonstrates configuring WebRTC UDP port ranges via WebView2 environment options. +class ScenarioWebRtcUdpPortConfiguration : public ComponentBase +{ +public: + ScenarioWebRtcUdpPortConfiguration(AppWindow* appWindow); + ~ScenarioWebRtcUdpPortConfiguration() override; + +private: + AppWindow* m_appWindow = nullptr; + wil::com_ptr m_webView; + EventRegistrationToken m_contentLoadingToken = {}; + std::wstring m_sampleUri; +}; diff --git a/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.cpp b/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.cpp index bd1ced12..9a01daa0 100644 --- a/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.cpp +++ b/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.cpp @@ -8,17 +8,34 @@ #include "AppWindow.h" #include "CheckFailure.h" +#include "ScenarioPermissionManagement.h" #include "ScenarioWebViewEventMonitor.h" #include -#include -#include #include #include +#include +#include using namespace Microsoft::WRL; using namespace std; static constexpr wchar_t c_samplePath[] = L"ScenarioWebViewEventMonitor.html"; +const int first_level_iframe_depth = 1; + +std::wstring WebResourceSourceToString(COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS source) +{ + switch (source) + { + case COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_DOCUMENT: + return L"\"main\""; + case COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_SHARED_WORKER: + return L"\"shared_worker\""; + case COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_SERVICE_WORKER: + return L"\"service_worker\""; + default: + return L"\"unknown_source\""; + } +} ScenarioWebViewEventMonitor::ScenarioWebViewEventMonitor(AppWindow* appWindowEventSource) : m_appWindowEventSource(appWindowEventSource), @@ -308,10 +325,16 @@ std::wstring WebViewPropertiesToJsonString(ICoreWebView2* webview) CHECK_FAILURE(webview->get_DocumentTitle(&documentTitle)); wil::unique_cotaskmem_string source; CHECK_FAILURE(webview->get_Source(&source)); + BOOL canGoBack = FALSE; + CHECK_FAILURE(webview->get_CanGoBack(&canGoBack)); + BOOL canGoForward = FALSE; + CHECK_FAILURE(webview->get_CanGoForward(&canGoForward)); std::wstring result = L", \"webview\": {" L"\"documentTitle\": " + EncodeQuote(documentTitle.get()) + L", " - + L"\"source\": " + EncodeQuote(source.get()) + L" " + + L"\"source\": " + EncodeQuote(source.get()) + L", " + + L"\"canGoBack\": " + BoolToString(canGoBack) + L", " + + L"\"canGoForward\": " + BoolToString(canGoForward) + L"}"; return result; @@ -409,6 +432,21 @@ std::wstring DOMContentLoadedArgsToJsonString( return message; } +std::wstring WebResourceRequestedToJsonString( + ICoreWebView2WebResourceRequest* webResourceRequest, + const std::wstring& source = std::wstring()) +{ + std::wstring message = L"{ \"kind\": \"event\", \"name\": " + L"\"WebResourceRequested\", \"args\": {" + L"\"request\": " + + RequestToJsonString(webResourceRequest) + + L", " + L"\"response\": null" + + source + L"}"; + + return message; +} + void ScenarioWebViewEventMonitor::EnableWebResourceResponseReceivedEvent(bool enable) { if (!enable && m_webResourceResponseReceivedToken.value != 0) { @@ -419,8 +457,10 @@ void ScenarioWebViewEventMonitor::EnableWebResourceResponseReceivedEvent(bool en { m_webviewEventSource2->add_WebResourceResponseReceived( Callback( - [this](ICoreWebView2* webview, ICoreWebView2WebResourceResponseReceivedEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* webview, + ICoreWebView2WebResourceResponseReceivedEventArgs* args) noexcept -> HRESULT + { wil::com_ptr webResourceRequest; CHECK_FAILURE(args->get_Request(&webResourceRequest)); wil::com_ptr @@ -466,23 +506,48 @@ void ScenarioWebViewEventMonitor::EnableWebResourceRequestedEvent(bool enable) } else if (enable && m_webResourceRequestedToken.value == 0) { - m_webviewEventSource->AddWebResourceRequestedFilter( - L"*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL); + auto webView2_22 = m_webviewEventSource.try_query(); + if (webView2_22) + { + webView2_22->AddWebResourceRequestedFilterWithRequestSourceKinds( + L"*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL, + COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL); + } + m_webviewEventSource->add_WebResourceRequested( Callback( - [this](ICoreWebView2* webview, ICoreWebView2WebResourceRequestedEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* webview, + ICoreWebView2WebResourceRequestedEventArgs* args) noexcept -> HRESULT + { wil::com_ptr webResourceRequest; CHECK_FAILURE(args->get_Request(&webResourceRequest)); wil::com_ptr webResourceResponse; CHECK_FAILURE(args->get_Response(&webResourceResponse)); - std::wstring message = L"{ \"kind\": \"event\", \"name\": " - L"\"WebResourceRequested\", \"args\": {" - L"\"request\": " + RequestToJsonString(webResourceRequest.get()) + L", " - L"\"response\": null" - L"}"; + std::wstring message = + WebResourceRequestedToJsonString(webResourceRequest.get()); + + wil::com_ptr argsPtr = args; + wil::com_ptr + webResourceRequestArgs = + argsPtr.try_query(); + if (webResourceRequestArgs) + { + COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS requestedSourceKind = + COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL; + CHECK_FAILURE(webResourceRequestArgs->get_RequestedSourceKind( + &requestedSourceKind)); + if (requestedSourceKind != + COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL) + { + std::wstring source = L", \"source\": " + WebResourceSourceToString( + requestedSourceKind); + message = WebResourceRequestedToJsonString( + webResourceRequest.get(), source); + } + } message += WebViewPropertiesToJsonString(m_webviewEventSource.get()); message += L"}"; PostEventMessage(message); @@ -500,8 +565,10 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventView->add_WebMessageReceived( Callback( - [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* sender, + ICoreWebView2WebMessageReceivedEventArgs* args) noexcept -> HRESULT + { wil::unique_cotaskmem_string source; CHECK_FAILURE(args->get_Source(&source)); wil::unique_cotaskmem_string webMessageAsString; @@ -536,8 +603,10 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_WebMessageReceived( Callback( - [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* sender, + ICoreWebView2WebMessageReceivedEventArgs* args) noexcept -> HRESULT + { wil::unique_cotaskmem_string source; CHECK_FAILURE(args->get_Source(&source)); wil::unique_cotaskmem_string webMessageAsString; @@ -573,8 +642,10 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_NewWindowRequested( Callback( - [this](ICoreWebView2* sender, ICoreWebView2NewWindowRequestedEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* sender, + ICoreWebView2NewWindowRequestedEventArgs* args) noexcept -> HRESULT + { BOOL handled = FALSE; CHECK_FAILURE(args->get_Handled(&handled)); BOOL isUserInitiated = FALSE; @@ -587,21 +658,49 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven wil::unique_cotaskmem_string name; std::wstring encodedName = EncodeQuote(L""); - if (SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&args2)))) { + if (SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&args2)))) + { CHECK_FAILURE(args2->get_Name(&name)); encodedName = EncodeQuote(name.get()); } + wil::com_ptr args3; + std::wstring frameName = EncodeQuote(L""); + std::wstring frameUri = EncodeQuote(L""); + if (SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&args3)))) + { + wil::com_ptr frame_info; + CHECK_FAILURE(args3->get_OriginalSourceFrameInfo(&frame_info)); + wil::unique_cotaskmem_string name; + CHECK_FAILURE(frame_info->get_Name(&name)); + frameName = EncodeQuote(name.get()); + wil::unique_cotaskmem_string source; + CHECK_FAILURE(frame_info->get_Source(&source)); + frameUri = EncodeQuote(source.get()); + } + std::wstring message = L"{ \"kind\": \"event\", \"name\": \"NewWindowRequested\", \"args\": {" - L"\"handled\": " + BoolToString(handled) + L", " - L"\"isUserInitiated\": " + BoolToString(isUserInitiated) + L", " - L"\"uri\": " + EncodeQuote(uri.get()) + L", " - L"\"name\": " + encodedName + L", " - L"\"newWindow\": null" - L"}" - + WebViewPropertiesToJsonString(m_webviewEventSource.get()) - + L"}"; + L"\"handled\": " + + BoolToString(handled) + + L", " + L"\"isUserInitiated\": " + + BoolToString(isUserInitiated) + + L", " + L"\"uri\": " + + EncodeQuote(uri.get()) + + L", " + L"\"name\": " + + encodedName + + L", " + L"\"newWindow\": null" + + L", " + L"\"frameName\": " + + frameName + + L", " + L"\"frameUri\": " + + frameUri + L"}" + + WebViewPropertiesToJsonString(m_webviewEventSource.get()) + L"}"; PostEventMessage(message); return S_OK; @@ -611,8 +710,10 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_NavigationStarting( Callback( - [this](ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* sender, + ICoreWebView2NavigationStartingEventArgs* args) noexcept -> HRESULT + { std::wstring message = NavigationStartingArgsToJsonString(sender, args, L"NavigationStarting"); PostEventMessage(message); @@ -624,8 +725,10 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_FrameNavigationStarting( Callback( - [this](ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* sender, + ICoreWebView2NavigationStartingEventArgs* args) noexcept -> HRESULT + { std::wstring message = NavigationStartingArgsToJsonString( sender, args, L"FrameNavigationStarting"); PostEventMessage(message); @@ -637,8 +740,9 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_SourceChanged( Callback( - [this](ICoreWebView2* sender, ICoreWebView2SourceChangedEventArgs* args) - -> HRESULT { + [this](ICoreWebView2* sender, ICoreWebView2SourceChangedEventArgs* args) noexcept + -> HRESULT + { BOOL isNewDocument = FALSE; CHECK_FAILURE(args->get_IsNewDocument(&isNewDocument)); @@ -655,9 +759,9 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_ContentLoading( Callback( - [this]( - ICoreWebView2* sender, - ICoreWebView2ContentLoadingEventArgs* args) -> HRESULT { + [this](ICoreWebView2* sender, ICoreWebView2ContentLoadingEventArgs* args) noexcept + -> HRESULT + { std::wstring message = ContentLoadingArgsToJsonString(sender, args, L"ContentLoading"); PostEventMessage(message); @@ -669,7 +773,8 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_HistoryChanged( Callback( - [this](ICoreWebView2* sender, IUnknown* args) -> HRESULT { + [this](ICoreWebView2* sender, IUnknown* args) noexcept -> HRESULT + { std::wstring message = L"{ \"kind\": \"event\", \"name\": \"HistoryChanged\", \"args\": {"; message += @@ -683,8 +788,10 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_NavigationCompleted( Callback( - [this](ICoreWebView2* sender, ICoreWebView2NavigationCompletedEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* sender, + ICoreWebView2NavigationCompletedEventArgs* args) noexcept -> HRESULT + { std::wstring message = NavigationCompletedArgsToJsonString(sender, args, L"NavigationCompleted"); PostEventMessage(message); @@ -694,10 +801,12 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven .Get(), &m_navigationCompletedToken); - m_webviewEventSource->add_FrameNavigationCompleted( + m_webviewEventSource->add_FrameNavigationCompleted( Callback( - [this](ICoreWebView2* sender, ICoreWebView2NavigationCompletedEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* sender, + ICoreWebView2NavigationCompletedEventArgs* args) noexcept -> HRESULT + { std::wstring message = NavigationCompletedArgsToJsonString( sender, args, L"FrameNavigationCompleted"); PostEventMessage(message); @@ -709,8 +818,9 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource2->add_DOMContentLoaded( Callback( - [this](ICoreWebView2* sender, ICoreWebView2DOMContentLoadedEventArgs* args) - -> HRESULT { + [this](ICoreWebView2* sender, ICoreWebView2DOMContentLoadedEventArgs* args) noexcept + -> HRESULT + { std::wstring message = DOMContentLoadedArgsToJsonString(sender, args, L"DOMContentLoaded"); PostEventMessage(message); @@ -722,7 +832,8 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_DocumentTitleChanged( Callback( - [this](ICoreWebView2* sender, IUnknown* args) -> HRESULT { + [this](ICoreWebView2* sender, IUnknown* args) noexcept -> HRESULT + { std::wstring message = L"{ \"kind\": \"event\", \"name\": \"DocumentTitleChanged\", \"args\": {" L"}" + @@ -739,8 +850,10 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven if (m_webviewEventSource4) { m_webviewEventSource4->add_DownloadStarting( Callback( - [this](ICoreWebView2* sender, ICoreWebView2DownloadStartingEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* sender, + ICoreWebView2DownloadStartingEventArgs* args) noexcept -> HRESULT + { wil::com_ptr download; CHECK_FAILURE(args->get_DownloadOperation(&download)); @@ -773,8 +886,8 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven Callback( [this, download]( ICoreWebView2DownloadOperation* sender, - IUnknown* args) - -> HRESULT { + IUnknown* args) noexcept -> HRESULT + { COREWEBVIEW2_DOWNLOAD_STATE state; CHECK_FAILURE(download->get_State(&state)); @@ -820,10 +933,11 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven &m_stateChangedToken); download->add_BytesReceivedChanged( - Callback< - ICoreWebView2BytesReceivedChangedEventHandler>( + Callback( [this, download]( - ICoreWebView2DownloadOperation* sender, IUnknown* args) -> HRESULT { + ICoreWebView2DownloadOperation* sender, + IUnknown* args) noexcept -> HRESULT + { INT64 bytesReceived = 0; CHECK_FAILURE(download->get_BytesReceived( &bytesReceived)); @@ -847,7 +961,9 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven download->add_EstimatedEndTimeChanged( Callback( [this, download]( - ICoreWebView2DownloadOperation* sender, IUnknown* args) -> HRESULT { + ICoreWebView2DownloadOperation* sender, + IUnknown* args) noexcept -> HRESULT + { wil::unique_cotaskmem_string estimatedEndTime; CHECK_FAILURE(download->get_EstimatedEndTime(&estimatedEndTime)); @@ -890,13 +1006,12 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource4->add_FrameCreated( Callback( - [this](ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args) - -> HRESULT { + [this](ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args) noexcept + -> HRESULT + { wil::com_ptr webviewFrame; CHECK_FAILURE(args->get_Frame(&webviewFrame)); - - InitializeFrameEventView(webviewFrame); - + InitializeFrameEventView(webviewFrame, first_level_iframe_depth + 1); wil::unique_cotaskmem_string name; CHECK_FAILURE(webviewFrame->get_Name(&name)); @@ -904,6 +1019,21 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven L"{ \"kind\": \"event\", \"name\": \"FrameCreated\", \"args\": {"; message += L"\"frame\": " + EncodeQuote(name.get()); + auto webView2_20 = wil::try_com_query(sender); + if (webView2_20) + { + UINT32 frameId = 0; + CHECK_FAILURE(webView2_20->get_FrameId(&frameId)); + message += + L",\"sender main frame id\": " + std::to_wstring((int)frameId); + } + auto frame5 = webviewFrame.try_query(); + if (frame5) + { + UINT32 frameId = 0; + CHECK_FAILURE(frame5->get_FrameId(&frameId)); + message += L",\"frame id\": " + std::to_wstring((int)frameId); + } message += L"}" + WebViewPropertiesToJsonString(m_webviewEventSource.get()) + L"}"; PostEventMessage(message); @@ -916,8 +1046,8 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_controllerEventSource->add_GotFocus( Callback( - [this](ICoreWebView2Controller* sender, IUnknown* args) - -> HRESULT { + [this](ICoreWebView2Controller* sender, IUnknown* args) noexcept -> HRESULT + { std::wstring message = L"{ \"kind\": \"event\", \"name\": \"GotFocus\", \"args\": {} }"; PostEventMessage(message); @@ -927,8 +1057,8 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven &m_gotFocusToken); m_controllerEventSource->add_LostFocus( Callback( - [this](ICoreWebView2Controller* sender, IUnknown* args) - -> HRESULT { + [this](ICoreWebView2Controller* sender, IUnknown* args) noexcept -> HRESULT + { std::wstring message = L"{ \"kind\": \"event\", \"name\": \"LostFocus\", \"args\": {} }"; PostEventMessage(message); @@ -942,8 +1072,8 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven { m_webViewEventSource9->add_IsDefaultDownloadDialogOpenChanged( Callback( - [this]( - ICoreWebView2* sender, IUnknown* args) -> HRESULT { + [this](ICoreWebView2* sender, IUnknown* args) noexcept -> HRESULT + { std::wstring message = L"{ \"kind\": \"event\", \"name\": " L"\"IsDefaultDownloadDialogOpenChanged\", \"args\": {"; @@ -961,32 +1091,51 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_PermissionRequested( Callback( - [this](ICoreWebView2* sender, ICoreWebView2PermissionRequestedEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* sender, + ICoreWebView2PermissionRequestedEventArgs* args) noexcept -> HRESULT + { wil::unique_cotaskmem_string uri; CHECK_FAILURE(args->get_Uri(&uri)); - + COREWEBVIEW2_PERMISSION_KIND kind; + CHECK_FAILURE(args->get_PermissionKind(&kind)); + COREWEBVIEW2_PERMISSION_STATE state; + CHECK_FAILURE(args->get_State(&state)); + wil::com_ptr extended_args; + CHECK_FAILURE(args->QueryInterface(IID_PPV_ARGS(&extended_args))); + BOOL saves_in_profile = TRUE; + CHECK_FAILURE(extended_args->get_SavesInProfile(&saves_in_profile)); std::wstring message = L"{ \"kind\": \"event\", \"name\": \"PermissionRequested\", \"args\": {" - L"\"uri\": " + EncodeQuote(uri.get()) + - L"}" - + WebViewPropertiesToJsonString(m_webviewEventSource.get()) - + L"}"; + L"\"uri\": " + + EncodeQuote(uri.get()) + + L", " + L"\"kind\": " + + EncodeQuote(PermissionKindToString(kind)) + + L", " + L"\"state\": " + + EncodeQuote(PermissionStateToString(state)) + L", \"SavesInProfile\": " + + BoolToString(saves_in_profile) + L"}" + + WebViewPropertiesToJsonString(m_webviewEventSource.get()) + L"}"; PostEventMessage(message); return S_OK; - }) - .Get(), + }) + .Get(), &m_permissionRequestedToken); } void ScenarioWebViewEventMonitor::InitializeFrameEventView( - wil::com_ptr webviewFrame) + wil::com_ptr webviewFrame, int depth) { webviewFrame->add_Destroyed( Callback( - [this](ICoreWebView2Frame* sender, IUnknown* args) -> HRESULT { + [this](ICoreWebView2Frame* sender, IUnknown* args) noexcept -> HRESULT + { + wil::unique_cotaskmem_string name; + CHECK_FAILURE(sender->get_Name(&name)); std::wstring message = L"{ \"kind\": \"event\", \"name\": " L"\"CoreWebView2Frame::Destroyed\", \"args\": {"; + message += L"\"frame name\": " + EncodeQuote(name.get()); message += L"}" + WebViewPropertiesToJsonString(m_webviewEventSource.get()) + L"}"; PostEventMessage(message); @@ -1002,7 +1151,8 @@ void ScenarioWebViewEventMonitor::InitializeFrameEventView( Callback( [this]( ICoreWebView2Frame* sender, - ICoreWebView2NavigationStartingEventArgs* args) -> HRESULT { + ICoreWebView2NavigationStartingEventArgs* args) noexcept -> HRESULT + { std::wstring message = NavigationStartingArgsToJsonString( m_webviewEventSource.get(), args, L"CoreWebView2Frame::NavigationStarting"); @@ -1015,8 +1165,10 @@ void ScenarioWebViewEventMonitor::InitializeFrameEventView( frame2->add_ContentLoading( Callback( - [this](ICoreWebView2Frame* sender, ICoreWebView2ContentLoadingEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2Frame* sender, + ICoreWebView2ContentLoadingEventArgs* args) noexcept -> HRESULT + { std::wstring message = ContentLoadingArgsToJsonString( m_webviewEventSource.get(), args, L"CoreWebView2Frame::ContentLoading"); PostEventMessage(message); @@ -1030,7 +1182,8 @@ void ScenarioWebViewEventMonitor::InitializeFrameEventView( Callback( [this]( ICoreWebView2Frame* sender, - ICoreWebView2NavigationCompletedEventArgs* args) -> HRESULT { + ICoreWebView2NavigationCompletedEventArgs* args) noexcept -> HRESULT + { std::wstring message = NavigationCompletedArgsToJsonString( m_webviewEventSource.get(), args, L"CoreWebView2Frame::NavigationCompleted"); @@ -1043,8 +1196,10 @@ void ScenarioWebViewEventMonitor::InitializeFrameEventView( frame2->add_DOMContentLoaded( Callback( - [this](ICoreWebView2Frame* sender, ICoreWebView2DOMContentLoadedEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2Frame* sender, + ICoreWebView2DOMContentLoadedEventArgs* args) noexcept -> HRESULT + { std::wstring message = DOMContentLoadedArgsToJsonString( m_webviewEventSource.get(), args, L"CoreWebView2Frame::DOMContentLoaded"); @@ -1054,6 +1209,89 @@ void ScenarioWebViewEventMonitor::InitializeFrameEventView( }) .Get(), NULL); + frame2->add_WebMessageReceived( + Callback( + [this]( + ICoreWebView2Frame* sender, + ICoreWebView2WebMessageReceivedEventArgs* args) noexcept -> HRESULT + { + wil::unique_cotaskmem_string source; + CHECK_FAILURE(args->get_Source(&source)); + wil::unique_cotaskmem_string webMessageAsString; + if (SUCCEEDED(args->TryGetWebMessageAsString(&webMessageAsString))) + { + std::wstring message = + L"{ \"kind\": \"event\", \"name\": " + L"\"CoreWebView2Frame::WebMessageReceived\", \"args\": {"; + + wil::unique_cotaskmem_string uri; + CHECK_FAILURE(args->get_Source(&uri)); + message += L"\"source\": " + EncodeQuote(uri.get()) + L", "; + message += L"\"webMessageAsString\": " + + EncodeQuote(webMessageAsString.get()) + L" "; + + UINT32 frameId = 0; + auto frame5 = wil::try_com_query(sender); + if (frame5) + { + CHECK_FAILURE(frame5->get_FrameId(&frameId)); + message += L",\"sender webview frame id\": " + + std::to_wstring((int)frameId); + } + message += L"}" + + WebViewPropertiesToJsonString(m_webviewEventSource.get()) + + L"}"; + PostEventMessage(message); + } + + return S_OK; + }) + .Get(), + NULL); + } + auto frame7 = webviewFrame.try_query(); + if (frame7) + { + //! [FrameCreated] + frame7->add_FrameCreated( + Callback( + [this, depth]( + ICoreWebView2Frame* sender, + ICoreWebView2FrameCreatedEventArgs* args) noexcept -> HRESULT + { + wil::com_ptr webviewFrame; + CHECK_FAILURE(args->get_Frame(&webviewFrame)); + wil::unique_cotaskmem_string name; + CHECK_FAILURE(webviewFrame->get_Name(&name)); + + InitializeFrameEventView(webviewFrame, depth + 1); + + std::wstring message = L"{ \"kind\": \"event\", \"name\": " + L"\"CoreWebView2Frame::FrameCreated\", \"args\": {"; + message += L"\"frame name\": " + EncodeQuote(name.get()); + message += L",\"depth\": " + std::to_wstring(depth); + auto frame5 = webviewFrame.try_query(); + UINT32 frameId = 0; + if (frame5) + { + CHECK_FAILURE(frame5->get_FrameId(&frameId)); + message += L",\"webview frame id\": " + std::to_wstring((int)frameId); + } + frame5 = wil::try_com_query(sender); + if (frame5) + { + CHECK_FAILURE(frame5->get_FrameId(&frameId)); + message += + L",\"sender webview frame id\": " + std::to_wstring((int)frameId); + } + message += + L"}" + WebViewPropertiesToJsonString(m_webviewEventSource.get()) + L"}"; + PostEventMessage(message); + return S_OK; + }) + .Get(), + &m_frameCreatedToken); + //! [FrameCreated] } } void ScenarioWebViewEventMonitor::PostEventMessage(std::wstring message) diff --git a/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.h b/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.h index d689e4d1..daf0fc8d 100644 --- a/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.h +++ b/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.h @@ -23,7 +23,7 @@ class ScenarioWebViewEventMonitor : public ComponentBase void InitializeEventView(ICoreWebView2* webviewEventView); private: - void InitializeFrameEventView(wil::com_ptr webviewFrame); + void InitializeFrameEventView(wil::com_ptr webviewFrame, int depth); // Because WebResourceRequested fires so much more often than // all other events, we default to it off and it is configurable. void EnableWebResourceRequestedEvent(bool enable); diff --git a/SampleApps/WebView2APISample/ScenarioWindowControlsOverlay.cpp b/SampleApps/WebView2APISample/ScenarioWindowControlsOverlay.cpp new file mode 100644 index 00000000..6d2e3a8e --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioWindowControlsOverlay.cpp @@ -0,0 +1,25 @@ +#include "stdafx.h" + +#include "AppWindow.h" +#include "CheckFailure.h" +#include "ScenarioWindowControlsOverlay.h" +#include + +using namespace Microsoft::WRL; +using namespace std; + +static constexpr wchar_t c_samplePath[] = L"ScenarioWindowControlsOverlay.html"; + +ScenarioWindowControlsOverlay::ScenarioWindowControlsOverlay(AppWindow* appWindow) +{ + //! [WindowControlsOverlay] + std::wstring sampleUri = appWindow->GetLocalUri(c_samplePath); + WebViewCreateOption options = appWindow->GetWebViewOption(); + options.useWco = true; + AppWindow* appWindowWco = new AppWindow(appWindow->GetCreationModeId(), options, sampleUri); + //! [WindowControlsOverlay] +} + +ScenarioWindowControlsOverlay::~ScenarioWindowControlsOverlay() +{ +} diff --git a/SampleApps/WebView2APISample/ScenarioWindowControlsOverlay.h b/SampleApps/WebView2APISample/ScenarioWindowControlsOverlay.h new file mode 100644 index 00000000..4b82e90d --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioWindowControlsOverlay.h @@ -0,0 +1,17 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "stdafx.h" + +#include "ComponentBase.h" +#include + +class ScenarioWindowControlsOverlay : public ComponentBase +{ +public: + ScenarioWindowControlsOverlay(AppWindow* appWindow); + ~ScenarioWindowControlsOverlay() override; +}; diff --git a/SampleApps/WebView2APISample/ScriptComponent.cpp b/SampleApps/WebView2APISample/ScriptComponent.cpp index 017faf5f..62e98745 100644 --- a/SampleApps/WebView2APISample/ScriptComponent.cpp +++ b/SampleApps/WebView2APISample/ScriptComponent.cpp @@ -6,6 +6,9 @@ #include #include +#include + +#include #include "ProcessComponent.h" #include "ScriptComponent.h" @@ -153,10 +156,181 @@ bool ScriptComponent::HandleWindowMessage( case IDM_POST_WEB_MESSAGE_JSON_FRAME: SendJsonWebMessageIFrame(); return true; + case IDM_INJECT_SCRIPT_WITH_RESULT: + ExecuteScriptWithResult(); + return true; + case IDM_ADD_EXTENSION: + AddBrowserExtension(); + return true; + case IDM_REMOVE_EXTENSION: + RemoveOrDisableBrowserExtension(true); + return true; + case IDM_DISABLE_EXTENSION: + RemoveOrDisableBrowserExtension(false); + return true; } } return false; } +void ScriptComponent::AddBrowserExtension() +{ + + // Get the profile object. + auto webView2_13 = m_webView.try_query(); + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + auto profile7 = webView2Profile.try_query(); + CHECK_FEATURE_RETURN_EMPTY(profile7); + + OPENFILENAME openFileName = {}; + openFileName.lStructSize = sizeof(openFileName); + openFileName.hwndOwner = nullptr; + openFileName.hInstance = nullptr; + WCHAR fileName[MAX_PATH] = L""; + openFileName.lpstrFile = fileName; + openFileName.lpstrFilter = L"Manifest\0manifest.json\0\0"; + openFileName.nMaxFile = ARRAYSIZE(fileName); + openFileName.Flags = OFN_OVERWRITEPROMPT; + + if (GetOpenFileName(&openFileName)) + { + // Remove the filename part of the path. + *wcsrchr(fileName, L'\\') = L'\0'; + profile7->AddBrowserExtension( + fileName, + Callback( + [](HRESULT error, ICoreWebView2BrowserExtension* extension) -> HRESULT + { + if (error != S_OK) + { + ShowFailure(error, L"Faile to add browser extension"); + } + wil::unique_cotaskmem_string id; + extension->get_Id(&id); + + wil::unique_cotaskmem_string name; + extension->get_Name(&name); + + std::wstring extensionInfo; + extensionInfo.append(L"Added "); + extensionInfo.append(id.get()); + extensionInfo.append(L" "); + extensionInfo.append(name.get()); + MessageBox( + nullptr, extensionInfo.c_str(), L"AddBrowserExtension Result", MB_OK); + return S_OK; + }) + .Get()); + } +} + +void ScriptComponent::RemoveOrDisableBrowserExtension(const bool remove) +{ + // Get the profile object. + auto webView2_13 = m_webView.try_query(); + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + auto profile7 = webView2Profile.try_query(); + CHECK_FEATURE_RETURN_EMPTY(profile7); + + profile7->GetBrowserExtensions( + Callback( + [this, profile7, + remove](HRESULT error, ICoreWebView2BrowserExtensionList* extensions) -> HRESULT + { + std::wstring extensionIdString; + UINT extensionsCount = 0; + extensions->get_Count(&extensionsCount); + + for (UINT index = 0; index < extensionsCount; ++index) + { + wil::com_ptr extension; + extensions->GetValueAtIndex(index, &extension); + + wil::unique_cotaskmem_string id; + wil::unique_cotaskmem_string name; + BOOL enabled = false; + + extension->get_IsEnabled(&enabled); + extension->get_Id(&id); + extension->get_Name(&name); + + extensionIdString += id.get(); + extensionIdString += L" "; + extensionIdString += name.get(); + if (!enabled) + { + extensionIdString += L" (disabled)"; + } + else + { + extensionIdString += L" (enabled)"; + } + extensionIdString += L"\n\r\n"; + } + + TextInputDialog dialog( + m_appWindow->GetMainWindow(), + remove ? L"Remove Extension" : L"Disable/Enable Extension", + L"Extension ID:", extensionIdString.c_str()); + if (dialog.confirmed) + { + for (UINT index = 0; index < extensionsCount; ++index) + { + wil::com_ptr extension; + extensions->GetValueAtIndex(index, &extension); + + wil::unique_cotaskmem_string id; + wil::unique_cotaskmem_string name; + + extension->get_Id(&id); + if (_wcsicmp(id.get(), dialog.input.c_str()) == 0) + { + if (remove) + { + extension->Remove( + Callback< + ICoreWebView2BrowserExtensionRemoveCompletedHandler>( + [](HRESULT error) -> HRESULT + { + if (error != S_OK) + { + ShowFailure(error, L"Remove Extension failed"); + } + MessageBox( + nullptr, L"Done", L"Remove Extension", MB_OK); + return S_OK; + }) + .Get()); + } + else + { + BOOL enabled = FALSE; + extension->get_IsEnabled(&enabled); + + extension->Enable( + !enabled, + Callback< + ICoreWebView2BrowserExtensionEnableCompletedHandler>( + [](HRESULT error) -> HRESULT + { + if (error != S_OK) + { + ShowFailure(error, L"Enable Extension failed"); + } + MessageBox( + nullptr, L"Done", L"Toggled Extension", MB_OK); + return S_OK; + }) + .Get()); + } + } + } + } + return S_OK; + }) + .Get()); +} //! [ExecuteScript] // Prompt the user for some script and then execute it. @@ -172,12 +346,12 @@ void ScriptComponent::InjectScript() { m_webView->ExecuteScript(dialog.input.c_str(), Callback( - [](HRESULT error, PCWSTR result) -> HRESULT + [appWindow = m_appWindow](HRESULT error, PCWSTR result) -> HRESULT { if (error != S_OK) { ShowFailure(error, L"ExecuteScript failed"); } - MessageBox(nullptr, result, L"ExecuteScript Result", MB_OK); + appWindow->AsyncMessageBox(result, L"ExecuteScript Result"); return S_OK; }).Get()); } @@ -224,12 +398,18 @@ void ScriptComponent::InjectScriptInIFrame() frame2->ExecuteScript( dialogScript.input.c_str(), Callback( - [](HRESULT error, PCWSTR result) -> HRESULT { - if (error != S_OK) + [this](HRESULT error, PCWSTR result) -> HRESULT { + m_appWindow->RunAsync([error, result = std::wstring(result)] { - ShowFailure(error, L"ExecuteScript failed"); - } - MessageBox(nullptr, result, L"ExecuteScript Result", MB_OK); + if (error != S_OK) + { + ShowFailure(error, L"ExecuteScript failed"); + } + else + { + MessageBox(nullptr, result.c_str(), L"ExecuteScript Result", MB_OK); + } + }); return S_OK; }) .Get()); @@ -262,7 +442,8 @@ void ScriptComponent::AddInitializeScript() [this](HRESULT error, PCWSTR id) -> HRESULT { m_lastInitializeScriptId = id; - MessageBox(nullptr, id, L"AddScriptToExecuteOnDocumentCreated Id", MB_OK); + m_appWindow->AsyncMessageBox( + m_lastInitializeScriptId, L"AddScriptToExecuteOnDocumentCreated Id"); return S_OK; }).Get()); @@ -379,8 +560,7 @@ void ScriptComponent::HandleCDPTargets() CHECK_FAILURE(args->get_ParameterObjectAsJson(¶meterObjectAsJson)); std::wstring eventSourceLabel; std::wstring eventDetails = parameterObjectAsJson.get(); - wil::com_ptr - args2; + wil::com_ptr args2; if (SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&args2)))) { wil::unique_cotaskmem_string sessionId; @@ -426,8 +606,8 @@ void ScriptComponent::HandleCDPTargets() std::wstring type = GetJSONStringField(jsonMessage.get(), L"type"); std::wstring url = GetJSONStringField(jsonMessage.get(), L"url"); m_devToolsTargetLabelMap.insert_or_assign(targetId, type + L"," + url); - wil::com_ptr webview2 = - m_webView.try_query(); + wil::com_ptr webview2 = + m_webView.try_query(); if (webview2) { // Auto-attach to targets further created from this target (identified by @@ -469,33 +649,6 @@ void ScriptComponent::HandleCDPTargets() .Get(), &m_targetDetachedToken)); receiver.reset(); - CHECK_FAILURE( - m_webView->GetDevToolsProtocolEventReceiver(L"Target.targetCreated", &receiver)); - CHECK_FAILURE(receiver->add_DevToolsProtocolEventReceived( - Callback( - [this]( - ICoreWebView2* sender, - ICoreWebView2DevToolsProtocolEventReceivedEventArgs* args) -> HRESULT - { - // Shared worker targets are not auto attached. Have to attach it explicitly. - wil::unique_cotaskmem_string jsonMessage; - CHECK_FAILURE(args->get_ParameterObjectAsJson(&jsonMessage)); - std::wstring type = GetJSONStringField(jsonMessage.get(), L"type"); - if (type == L"shared_worker") - { - std::wstring targetId = GetJSONStringField(jsonMessage.get(), L"targetId"); - std::wstring parameters = - L"{\"targetId\":\"" + targetId + L"\",\"flatten\": true}"; - // Call Target.attachToTarget and ignore returned value, let - // Target.attachedToTarget to handle the result. - m_webView->CallDevToolsProtocolMethod( - L"Target.attachToTarget", parameters.c_str(), nullptr); - } - return S_OK; - }) - .Get(), - &m_targetCreatedToken)); - receiver.reset(); CHECK_FAILURE( m_webView->GetDevToolsProtocolEventReceiver(L"Target.targetInfoChanged", &receiver)); CHECK_FAILURE(receiver->add_DevToolsProtocolEventReceived( @@ -539,8 +692,7 @@ void ScriptComponent::CollectHeapUsageViaCdp() // Already collecting, return return; } - wil::com_ptr webview2 = - m_webView.try_query(); + wil::com_ptr webview2 = m_webView.try_query(); CHECK_FEATURE_RETURN_EMPTY(webview2); m_pendingHeapUsageCollectionCount = 0; m_heapUsageResult.clear(); @@ -625,16 +777,14 @@ void ScriptComponent::SubscribeToCdpEvent() Callback( [this, eventName]( ICoreWebView2* sender, - ICoreWebView2DevToolsProtocolEventReceivedEventArgs* args) -> HRESULT + ICoreWebView2DevToolsProtocolEventReceivedEventArgs* args) -> HRESULT { wil::unique_cotaskmem_string parameterObjectAsJson; CHECK_FAILURE(args->get_ParameterObjectAsJson(¶meterObjectAsJson)); std::wstring title = eventName; std::wstring details = parameterObjectAsJson.get(); //! [DevToolsProtocolEventReceivedSessionId] - wil::com_ptr< - ICoreWebView2ExperimentalDevToolsProtocolEventReceivedEventArgs> - args2; + wil::com_ptr args2; if (SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&args2)))) { wil::unique_cotaskmem_string sessionId; @@ -649,10 +799,7 @@ void ScriptComponent::SubscribeToCdpEvent() } } //! [DevToolsProtocolEventReceivedSessionId] - // Use TextInputDialog to show the result for easy copy & paste. - TextInputDialog resultDialog( - m_appWindow->GetMainWindow(), L"CDP Event Fired", title.c_str(), - details.c_str(), L"", true); + m_appWindow->AsyncMessageBox(details, L"CDP Event Fired: " + title); return S_OK; }) .Get(), @@ -682,17 +829,10 @@ void ScriptComponent::CallCdpMethod() : L"{}"); m_webView->CallDevToolsProtocolMethod( - methodName.c_str(), - methodParams.c_str(), + methodName.c_str(), methodParams.c_str(), Callback( - [this](HRESULT error, PCWSTR resultJson) -> HRESULT - { - // Use TextInputDialog to show the result for easy copy & paste. - TextInputDialog resultDialog( - m_appWindow->GetMainWindow(), L"CDP Method Call Result", - L"CDP method Result:", resultJson, L"", true); - return S_OK; - }).Get()); + this, &ScriptComponent::CDPMethodCallback) + .Get()); } } //! [CallDevToolsProtocolMethod] @@ -701,7 +841,7 @@ void ScriptComponent::CallCdpMethod() // Prompt the user for the sessionid, name and parameters of a CDP method, then call it. void ScriptComponent::CallCdpMethodForSession() { - wil::com_ptr webview2 = m_webView.try_query(); + wil::com_ptr webview2 = m_webView.try_query(); CHECK_FEATURE_RETURN_EMPTY(webview2); std::wstring sessionList = L"Sessions:"; for (auto& target : m_devToolsSessionMap) @@ -733,19 +873,26 @@ void ScriptComponent::CallCdpMethodForSession() webview2->CallDevToolsProtocolMethodForSession( sessionId.c_str(), methodName.c_str(), methodParams.c_str(), Callback( - [this](HRESULT error, PCWSTR resultJson) -> HRESULT - { - // Use TextInputDialog to show the result for easy copy & paste. - TextInputDialog resultDialog( - m_appWindow->GetMainWindow(), L"CDP Method Call Result", - L"CDP method Result:", resultJson, L"", true); - return S_OK; - }) + this, &ScriptComponent::CDPMethodCallback) .Get()); } } //! [CallDevToolsProtocolMethodForSession] +HRESULT ScriptComponent::CDPMethodCallback(HRESULT error, PCWSTR resultJson) +{ + std::wostringstream message; + if (SUCCEEDED(error)) + { + message << "Success!\nResult = " << resultJson; + } + else + { + message << "Error!\nHRESULT = 0x" << std::hex << error << "\nResult = " << resultJson; + } + m_appWindow->AsyncMessageBox(message.str(), L"CDP method call result"); + return S_OK; +} void ScriptComponent::AddComObject() { @@ -821,6 +968,158 @@ void ScriptComponent::AddSiteEmbeddingIFrame() } } +//! [ExecuteScriptWithResult] +void ScriptComponent::ExecuteScriptWithResult() +{ + TextInputDialog dialog( + m_appWindow->GetMainWindow(), L"Execute Script With Result", L"Enter script code:", + L"Enter the JavaScript code to run in the webview.", L""); + if (dialog.confirmed) + { + wil::com_ptr webView = m_webView.try_query(); + + if (!webView) + { + MessageBox( + nullptr, L"Get webview2 failed!", L"ExecuteScriptWithResult Result", MB_OK); + return; + } + + // The main interface for excute script, the first param is the string + // which user want to execute, the second param is the callback to process + // the result, here use a lamada to the param. + webView->ExecuteScriptWithResult( + dialog.input.c_str(), + // The callback function has two param, the first one is the status of call.s + // it will always be the S_OK for now, and the second is the result struct. + Callback( + [this](HRESULT errorCode, ICoreWebView2ExecuteScriptResult* result) -> HRESULT + { + if (errorCode != S_OK || result == nullptr) + { + MessageBox( + nullptr, L"Call interface failed!", + L"ExecuteScriptWithResult Result", MB_OK); + return S_OK; + } + else + { + wil::com_ptr exception; + BOOL isSuccess; + + // User should always invoke the get_Success firstly to get if execute + // success. + if (result->get_Succeeded(&isSuccess) != S_OK) + { + MessageBox( + nullptr, L"Get execute status failed!", + L"ExecuteScriptWithResult Result", MB_OK); + return S_OK; + } + + // If execute success, then we can get the raw json data, and try to get + // the string. + if (isSuccess) + { + wil::unique_cotaskmem_string rawJsonData; + // Get the raw json. + if (result->get_ResultAsJson(&rawJsonData) == S_OK) + { + MessageBox( + nullptr, rawJsonData.get(), + L"ExecuteScriptWithResult Json Result", MB_OK); + } + else + { + MessageBox( + nullptr, L"Get raw json data failed", + L"ExecuteScriptWithResult Json Result", MB_OK); + } + + // Get the string, and if the result is not the string type, + // it will return the E_INVALIDARG. + wil::unique_cotaskmem_string stringData; + BOOL isString = FALSE; + if (result->TryGetResultAsString(&stringData, &isString) == S_OK && + isString) + { + MessageBox( + nullptr, stringData.get(), + L"ExecuteScriptWithResult String Result", MB_OK); + } + else + { + MessageBox( + nullptr, L"Get string failed", + L"ExecuteScriptWithResult String Result", MB_OK); + } + } + else // If execute failed, then we can get the exception struct to get + // the reason of failed. + { + if (result->get_Exception(&exception) == S_OK) + { + // Get the exception name, this could return the empty string, + // such as `throw 1`. + wil::unique_cotaskmem_string exceptionName; + if (exception && exception->get_Name(&exceptionName) == S_OK) + { + MessageBox( + nullptr, exceptionName.get(), + L"ExecuteScriptWithResult Exception Name", MB_OK); + } + + // Get the exception message, this could return the empty + // string, such as `throw 1`. + wil::unique_cotaskmem_string exceptionMessage; + if (exception && + exception->get_Message(&exceptionMessage) == S_OK) + { + MessageBox( + nullptr, exceptionMessage.get(), + L"ExecuteScriptWithResult Exception Message", MB_OK); + } + + // Get the exception detail, it's a json struct data with all + // exception infomation , we can parse it and get the detail + // what we need. + wil::unique_cotaskmem_string exceptionDetail; + if (exception && + exception->get_ToJson(&exceptionDetail) == S_OK) + { + MessageBox( + nullptr, exceptionDetail.get(), + L"ExecuteScriptWithResult Exception Detail", MB_OK); + } + + uint32_t lineNumber = 0; + uint32_t columnNumber = 0; + if (exception && + exception->get_LineNumber(&lineNumber) == S_OK && + exception->get_ColumnNumber(&columnNumber) == S_OK) + { + auto exceptionLocationInfo = + L"LineNumber:" + std::to_wstring(lineNumber) + + L", ColumnNumber:" + std::to_wstring(columnNumber); + MessageBox( + nullptr, exceptionLocationInfo.c_str(), + L"ExecuteScriptWithResult Exception Location", MB_OK); + } + } + else + { + MessageBox( + nullptr, L"Get exception failed", + L"ExecuteScriptWithResult Result", MB_OK); + } + } + } + return S_OK; + }) + .Get()); + } +} +//! [ExecuteScriptWithResult] void ScriptComponent::HandleIFrames() { @@ -865,8 +1164,8 @@ void ScriptComponent::HandleIFrames() // embedding a site. The result is recorded in m_siteEmbeddingIFrameCount. CHECK_FAILURE(webview2_4->add_FrameCreated( Callback( - [this](ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args) - -> HRESULT + [this]( + ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args) -> HRESULT { wil::com_ptr webviewFrame; CHECK_FAILURE(args->get_Frame(&webviewFrame)); diff --git a/SampleApps/WebView2APISample/ScriptComponent.h b/SampleApps/WebView2APISample/ScriptComponent.h index 66e93261..3319ff47 100644 --- a/SampleApps/WebView2APISample/ScriptComponent.h +++ b/SampleApps/WebView2APISample/ScriptComponent.h @@ -9,11 +9,14 @@ #include #include +#include #include #include "AppWindow.h" #include "ComponentBase.h" +const std::wstring GetJSONStringField(PCWSTR jsonMessage, PCWSTR fieldName); + // This component handles commands from the Script menu. class ScriptComponent : public ComponentBase { @@ -38,6 +41,7 @@ class ScriptComponent : public ComponentBase void CallCdpMethod(); void HandleCDPTargets(); void CallCdpMethodForSession(); + HRESULT CDPMethodCallback(HRESULT error, PCWSTR resultJson); void CollectHeapUsageViaCdp(); void HandleHeapUsageResult(std::wstring targetInfo, PCWSTR resultJson); void AddComObject(); @@ -46,9 +50,10 @@ class ScriptComponent : public ComponentBase void SendJsonWebMessageIFrame(); void AddSiteEmbeddingIFrame(); - + void ExecuteScriptWithResult(); + void AddBrowserExtension(); + void RemoveOrDisableBrowserExtension(const bool remove); ~ScriptComponent() override; - void HandleIFrames(); std::wstring IFramesToString(); std::vector> m_frames; diff --git a/SampleApps/WebView2APISample/SettingsComponent.cpp b/SampleApps/WebView2APISample/SettingsComponent.cpp index d0965a17..a6e93995 100644 --- a/SampleApps/WebView2APISample/SettingsComponent.cpp +++ b/SampleApps/WebView2APISample/SettingsComponent.cpp @@ -7,12 +7,15 @@ #include "SettingsComponent.h" #include "CheckFailure.h" +#include "ScenarioPermissionManagement.h" #include "TextInputDialog.h" +#include +#include #include -using namespace Microsoft::WRL; +#include +#include -// Some utility functions -static wil::unique_bstr GetDomainOfUri(PWSTR uri); +using namespace Microsoft::WRL; SettingsComponent::SettingsComponent( AppWindow* appWindow, ICoreWebView2Environment* environment, SettingsComponent* old) @@ -26,12 +29,19 @@ SettingsComponent::SettingsComponent( m_settings4 = m_settings.try_query(); m_settings5 = m_settings.try_query(); m_settings6 = m_settings.try_query(); + m_settings7 = m_settings.try_query(); + m_settings8 = m_settings.try_query(); m_controller = m_appWindow->GetWebViewController(); m_controller3 = m_controller.try_query(); m_webView2_5 = m_webView.try_query(); - m_webViewExperimental5 = m_webView.try_query(); - m_webViewExperimental6 = m_webView.try_query(); - m_webViewExperimental13 = m_webView.try_query(); + m_webView2_11 = m_webView.try_query(); + m_webView2_12 = m_webView.try_query(); + m_webView2_13 = m_webView.try_query(); + m_webView2_14 = m_webView.try_query(); + m_webView2_15 = m_webView.try_query(); + m_webView2_18 = m_webView.try_query(); + m_webView2_22 = m_webView.try_query(); + // Copy old settings if desired if (old) { @@ -84,13 +94,24 @@ SettingsComponent::SettingsComponent( CHECK_FAILURE(old->m_settings6->get_IsSwipeNavigationEnabled(&setting)); CHECK_FAILURE(m_settings6->put_IsSwipeNavigationEnabled(setting)); } + if (old->m_settings7 && m_settings7) + { + COREWEBVIEW2_PDF_TOOLBAR_ITEMS hiddenPdfToolbarItems; + CHECK_FAILURE(old->m_settings7->get_HiddenPdfToolbarItems(&hiddenPdfToolbarItems)); + CHECK_FAILURE(m_settings7->put_HiddenPdfToolbarItems(hiddenPdfToolbarItems)); + } + if (old->m_settings8 && m_settings8) + { + CHECK_FAILURE(old->m_settings8->get_IsReputationCheckingRequired(&setting)); + CHECK_FAILURE(m_settings8->put_IsReputationCheckingRequired(setting)); + } SetBlockImages(old->m_blockImages); SetReplaceImages(old->m_replaceImages); - m_deferScriptDialogs = old->m_deferScriptDialogs; m_isScriptEnabled = old->m_isScriptEnabled; m_blockedSitesSet = old->m_blockedSitesSet; m_blockedSites = std::move(old->m_blockedSites); EnableCustomClientCertificateSelection(); + ToggleCustomServerCertificateSupport(); } //! [NavigationStarting] @@ -102,7 +123,8 @@ SettingsComponent::SettingsComponent( CHECK_FAILURE(m_webView->add_NavigationStarting( Callback( [this](ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args) - -> HRESULT { + -> HRESULT + { wil::unique_cotaskmem_string uri; CHECK_FAILURE(args->get_Uri(&uri)); @@ -147,6 +169,15 @@ SettingsComponent::SettingsComponent( } } //! [UserAgent] + // [NavigationKind] + wil::com_ptr args3; + if (SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&args3)))) + { + COREWEBVIEW2_NAVIGATION_KIND kind = + COREWEBVIEW2_NAVIGATION_KIND_NEW_DOCUMENT; + CHECK_FAILURE(args3->get_NavigationKind(&kind)); + } + // ! [NavigationKind] return S_OK; }) .Get(), @@ -159,7 +190,8 @@ SettingsComponent::SettingsComponent( CHECK_FAILURE(m_webView->add_FrameNavigationStarting( Callback( [this](ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args) - -> HRESULT { + -> HRESULT + { wil::unique_cotaskmem_string uri; CHECK_FAILURE(args->get_Uri(&uri)); @@ -173,177 +205,232 @@ SettingsComponent::SettingsComponent( &m_frameNavigationStartingToken)); //! [FrameNavigationStarting] + //! [FaviconChanged] + // Register a handler for the FaviconUriChanged event. + // This will provided the current favicon of the page, as well + // as any changes that occur during the page lifetime + if (m_webView2_15) + { + Gdiplus::GdiplusStartupInput gdiplusStartupInput; + + // Initialize GDI+. + Gdiplus::GdiplusStartup(&gdiplusToken_, &gdiplusStartupInput, NULL); + CHECK_FAILURE(m_webView2_15->add_FaviconChanged( + Callback( + [this](ICoreWebView2* sender, IUnknown* args) -> HRESULT + { + if (m_faviconChanged) + { + wil::unique_cotaskmem_string url; + Microsoft::WRL::ComPtr webview2; + CHECK_FAILURE(sender->QueryInterface(IID_PPV_ARGS(&webview2))); + + CHECK_FAILURE(webview2->get_FaviconUri(&url)); + std::wstring strUrl(url.get()); + + webview2->GetFavicon( + COREWEBVIEW2_FAVICON_IMAGE_FORMAT_PNG, + Callback( + [this, + strUrl](HRESULT errorCode, IStream* iconStream) -> HRESULT + { + CHECK_FAILURE(errorCode); + Gdiplus::Bitmap iconBitmap(iconStream); + wil::unique_hicon icon; + if (iconBitmap.GetHICON(&icon) == Gdiplus::Status::Ok) + { + m_favicon = std::move(icon); + SendMessage( + m_appWindow->GetMainWindow(), WM_SETICON, + ICON_SMALL, (LPARAM)m_favicon.get()); + m_statusBar.Show(strUrl); + } + else + { + SendMessage( + m_appWindow->GetMainWindow(), WM_SETICON, + ICON_SMALL, (LPARAM)IDC_NO); + m_statusBar.Show(L"No Icon"); + } + + return S_OK; + }) + .Get()); + } + return S_OK; + }) + .Get(), + &m_faviconChangedToken)); + } + //! [FaviconChanged] + //! [ScriptDialogOpening] // Register a handler for the ScriptDialogOpening event. - // This handler will set up a custom prompt dialog for the user, - // and may defer the event if the setting to defer dialogs is enabled. + // This handler will set up a custom prompt dialog for the user. Because + // running a message loop inside of an event handler causes problems, we + // defer the event and handle it asynchronously. CHECK_FAILURE(m_webView->add_ScriptDialogOpening( Callback( [this](ICoreWebView2* sender, ICoreWebView2ScriptDialogOpeningEventArgs* args) - -> HRESULT { + -> HRESULT + { + AppWindow* appWindow = m_appWindow; wil::com_ptr eventArgs = args; - auto showDialog = [this, eventArgs] { - wil::unique_cotaskmem_string uri; - COREWEBVIEW2_SCRIPT_DIALOG_KIND type; - wil::unique_cotaskmem_string message; - wil::unique_cotaskmem_string defaultText; - - CHECK_FAILURE(eventArgs->get_Uri(&uri)); - CHECK_FAILURE(eventArgs->get_Kind(&type)); - CHECK_FAILURE(eventArgs->get_Message(&message)); - CHECK_FAILURE(eventArgs->get_DefaultText(&defaultText)); - - std::wstring promptString = - std::wstring(L"The page at '") + uri.get() + L"' says:"; - TextInputDialog dialog( - m_appWindow->GetMainWindow(), L"Script Dialog", promptString.c_str(), - message.get(), defaultText.get(), - /* readonly */ type != COREWEBVIEW2_SCRIPT_DIALOG_KIND_PROMPT); - if (dialog.confirmed) + wil::com_ptr deferral; + CHECK_FAILURE(args->GetDeferral(&deferral)); + appWindow->RunAsync( + [appWindow, eventArgs, deferral] { - CHECK_FAILURE(eventArgs->put_ResultText(dialog.input.c_str())); - CHECK_FAILURE(eventArgs->Accept()); - } - }; + wil::unique_cotaskmem_string uri; + COREWEBVIEW2_SCRIPT_DIALOG_KIND type; + wil::unique_cotaskmem_string message; + wil::unique_cotaskmem_string defaultText; - if (m_deferScriptDialogs) - { - wil::com_ptr deferral; - CHECK_FAILURE(args->GetDeferral(&deferral)); - m_completeDeferredDialog = [showDialog, deferral] { - showDialog(); - CHECK_FAILURE(deferral->Complete()); - }; - } - else - { - showDialog(); - } + CHECK_FAILURE(eventArgs->get_Uri(&uri)); + CHECK_FAILURE(eventArgs->get_Kind(&type)); + CHECK_FAILURE(eventArgs->get_Message(&message)); + CHECK_FAILURE(eventArgs->get_DefaultText(&defaultText)); + std::wstring promptString = + std::wstring(L"The page at '") + uri.get() + L"' says:"; + TextInputDialog dialog( + appWindow->GetMainWindow(), L"Script Dialog", promptString.c_str(), + message.get(), defaultText.get(), + /* readonly */ type != COREWEBVIEW2_SCRIPT_DIALOG_KIND_PROMPT); + if (dialog.confirmed) + { + CHECK_FAILURE(eventArgs->put_ResultText(dialog.input.c_str())); + CHECK_FAILURE(eventArgs->Accept()); + } + deferral->Complete(); + }); return S_OK; }) .Get(), &m_scriptDialogOpeningToken)); //! [ScriptDialogOpening] - //! [PermissionRequested] + //! [PermissionRequested0] // Register a handler for the PermissionRequested event. - // This handler prompts the user to allow or deny the request. + // This handler prompts the user to allow or deny the request, and remembers + // the user's choice for later. CHECK_FAILURE(m_webView->add_PermissionRequested( Callback( - [this](ICoreWebView2* sender, ICoreWebView2PermissionRequestedEventArgs* args) - -> HRESULT { - // We avoid potential reentrancy from running a message loop - // in the permission requested event handler by showing the - // dialog via lambda run asynchronously outside of this event - // handler. - auto showDialog = [this, args] - { - wil::unique_cotaskmem_string uri; - COREWEBVIEW2_PERMISSION_KIND kind = - COREWEBVIEW2_PERMISSION_KIND_UNKNOWN_PERMISSION; - BOOL userInitiated = FALSE; + this, &SettingsComponent::OnPermissionRequested) + .Get(), + &m_permissionRequestedToken)); + //! [PermissionRequested0] - CHECK_FAILURE(args->get_Uri(&uri)); - CHECK_FAILURE(args->get_PermissionKind(&kind)); - CHECK_FAILURE(args->get_IsUserInitiated(&userInitiated)); - auto cached_key = - std::tuple( - std::wstring(uri.get()), kind, userInitiated); - auto cached_permission = m_cached_permissions.find(cached_key); - if (cached_permission != m_cached_permissions.end()) + if (m_webView2_12) + { + //! [StatusBarTextChanged] + m_statusBar.Initialize(appWindow); + // Registering a listener for status bar message changes + CHECK_FAILURE(m_webView2_12->add_StatusBarTextChanged( + Microsoft::WRL::Callback( + [this](ICoreWebView2* sender, IUnknown* args) -> HRESULT + { + if (m_customStatusBar) { - bool allow = cached_permission->second; - if (allow) + wil::unique_cotaskmem_string value; + Microsoft::WRL::ComPtr wv; + CHECK_FAILURE(sender->QueryInterface(IID_PPV_ARGS(&wv))); + + CHECK_FAILURE(wv->get_StatusBarText(&value)); + std::wstring valueString = value.get(); + if (valueString.length() != 0) { - CHECK_FAILURE(args->put_State(COREWEBVIEW2_PERMISSION_STATE_ALLOW)); + m_statusBar.Show(valueString); } else { - CHECK_FAILURE(args->put_State(COREWEBVIEW2_PERMISSION_STATE_DENY)); + m_statusBar.Hide(); } - return S_OK; } - std::wstring message = L"Do you want to grant permission for "; - message += NameOfPermissionKind(kind); - message += L" to the website at "; - message += uri.get(); - message += L"?\n\n"; - message += - (userInitiated ? L"This request came from a user gesture." - : L"This request did not come from a user gesture."); - - int response = MessageBox( - nullptr, message.c_str(), L"Permission Request", - MB_YESNOCANCEL | MB_ICONWARNING); - if (response == IDYES) - { - m_cached_permissions[cached_key] = true; - } + return S_OK; + }) + .Get(), + &m_statusBarTextChangedToken)); + //! [StatusBarTextChanged] + } +} - if (response == IDNO) - { - m_cached_permissions[cached_key] = false; - } - COREWEBVIEW2_PERMISSION_STATE state = - response == IDYES ? COREWEBVIEW2_PERMISSION_STATE_ALLOW - : response == IDNO ? COREWEBVIEW2_PERMISSION_STATE_DENY - : COREWEBVIEW2_PERMISSION_STATE_DEFAULT; - CHECK_FAILURE(args->put_State(state)); +//! [PermissionRequested1] +HRESULT SettingsComponent::OnPermissionRequested( + ICoreWebView2* sender, ICoreWebView2PermissionRequestedEventArgs* args) +{ + // Obtain a deferral for the event so that the CoreWebView2 + // doesn't examine the properties we set on the event args until + // after we call the Complete method asynchronously later. + wil::com_ptr deferral; + CHECK_FAILURE(args->GetDeferral(&deferral)); - return S_OK; - }; + // Do not save state to the profile so that the PermissionRequested event is + // always raised and the app is in control of all permission requests. In + // this example, the app listens to all requests and caches permission on + // its own to decide whether to show custom UI to the user. + wil::com_ptr extended_args; + CHECK_FAILURE(args->QueryInterface(IID_PPV_ARGS(&extended_args))); + CHECK_FAILURE(extended_args->put_SavesInProfile(FALSE)); - // Obtain a deferral for the event so that the CoreWebView2 - // doesn't examine the properties we set on the event args until - // after we call the Complete method asynchronously later. - wil::com_ptr deferral; - CHECK_FAILURE(args->GetDeferral(&deferral)); + // Do the rest asynchronously, to avoid calling MessageBox in an event handler. + m_appWindow->RunAsync( + [this, deferral, args = wil::com_ptr(args)] + { + wil::unique_cotaskmem_string uri; + COREWEBVIEW2_PERMISSION_KIND kind = COREWEBVIEW2_PERMISSION_KIND_UNKNOWN_PERMISSION; + BOOL userInitiated = FALSE; + CHECK_FAILURE(args->get_Uri(&uri)); + CHECK_FAILURE(args->get_PermissionKind(&kind)); + CHECK_FAILURE(args->get_IsUserInitiated(&userInitiated)); - m_appWindow->RunAsync([deferral, showDialog]() { - showDialog(); - CHECK_FAILURE(deferral->Complete()); - }); + COREWEBVIEW2_PERMISSION_STATE state = COREWEBVIEW2_PERMISSION_STATE_DEFAULT; - return S_OK; - }) - .Get(), - &m_permissionRequestedToken)); - //! [PermissionRequested] - - if(m_webViewExperimental13) { - // ![StatusBarTextChanged] - m_statusBar.Initialize(appWindow); - // Registering a listener for status bar message changes - CHECK_FAILURE(m_webViewExperimental13->add_StatusBarTextChanged( - Microsoft::WRL::Callback( - [this](ICoreWebView2* sender, IUnknown* args) -> HRESULT { - if (m_customStatusBar) - { - wil::unique_cotaskmem_string value; - Microsoft::WRL::ComPtr wv; - CHECK_FAILURE(sender->QueryInterface(IID_PPV_ARGS(&wv))); + auto cached_key = std::make_tuple(std::wstring(uri.get()), kind, userInitiated); + auto cached_permission = m_cached_permissions.find(cached_key); + if (cached_permission != m_cached_permissions.end()) + { + state = + (cached_permission->second ? COREWEBVIEW2_PERMISSION_STATE_ALLOW + : COREWEBVIEW2_PERMISSION_STATE_DENY); + } + else + { + std::wstring message = L"An iframe has requested device permission for "; + message += PermissionKindToString(kind); + message += L" to the website at "; + message += uri.get(); + message += L"?\n\n"; + message += L"Do you want to grant permission?\n"; + message += + (userInitiated ? L"This request came from a user gesture." + : L"This request did not come from a user gesture."); - CHECK_FAILURE(wv->get_StatusBarText(&value)); - std::wstring valueString = value.get(); - if (valueString.length() != 0) - { - m_statusBar.Show(valueString); - } - else - { - m_statusBar.Hide(); - } + int response = MessageBox( + nullptr, message.c_str(), L"Permission Request", + MB_YESNOCANCEL | MB_ICONWARNING); + switch (response) + { + case IDYES: + m_cached_permissions[cached_key] = true; + state = COREWEBVIEW2_PERMISSION_STATE_ALLOW; + break; + case IDNO: + m_cached_permissions[cached_key] = false; + state = COREWEBVIEW2_PERMISSION_STATE_DENY; + break; + default: + state = COREWEBVIEW2_PERMISSION_STATE_DEFAULT; + break; } - - return S_OK; - }) - .Get(), - &m_statusBarTextChangedToken)); - // ![StatusBarTextChanged] - } + } + CHECK_FAILURE(args->put_State(state)); + CHECK_FAILURE(deferral->Complete()); + }); + return S_OK; } +//! [PermissionRequested1] bool SettingsComponent::HandleWindowMessage( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* result) @@ -357,6 +444,11 @@ bool SettingsComponent::HandleWindowMessage( ChangeBlockedSites(); return true; } + case ID_CUSTOM_DATA_PARTITION: + { + SetCustomDataPartitionId(); + return true; + } case ID_SETTINGS_SETUSERAGENT: { CHECK_FEATURE_RETURN(m_settings2); @@ -404,6 +496,16 @@ bool SettingsComponent::HandleWindowMessage( L"Settings change", MB_OK); return true; } + case ID_SETTINGS_TOGGLE_POST_STATUS_BAR_ACTIVITY: + { + m_customStatusBar = !m_customStatusBar; + return true; + } + case ID_SETTINGS_TOGGLE_POST_FAVICON_CHANGED: + { + m_faviconChanged = !m_faviconChanged; + return true; + } case ID_SETTINGS_DEV_TOOLS_ENABLED: { BOOL areDevToolsEnabled = FALSE; @@ -418,68 +520,18 @@ bool SettingsComponent::HandleWindowMessage( L"Settings change", MB_OK); return true; } - case IDM_USE_DEFAULT_SCRIPT_DIALOGS: - { - BOOL defaultCurrentlyEnabled; - m_settings->get_AreDefaultScriptDialogsEnabled(&defaultCurrentlyEnabled); - if (!defaultCurrentlyEnabled) - { - m_settings->put_AreDefaultScriptDialogsEnabled(TRUE); - MessageBox( - nullptr, L"Default script dialogs will be used after the next navigation.", - L"Settings change", MB_OK); - } - return true; - } - case IDM_USE_CUSTOM_SCRIPT_DIALOGS: - { - BOOL defaultCurrentlyEnabled; - m_settings->get_AreDefaultScriptDialogsEnabled(&defaultCurrentlyEnabled); - if (defaultCurrentlyEnabled) - { - m_settings->put_AreDefaultScriptDialogsEnabled(FALSE); - m_deferScriptDialogs = false; - MessageBox( - nullptr, - L"Custom script dialogs without deferral will be used after the next " - L"navigation.", - L"Settings change", MB_OK); - } - else if (m_deferScriptDialogs) - { - m_deferScriptDialogs = false; - MessageBox( - nullptr, L"Custom script dialogs without deferral will be used now.", - L"Settings change", MB_OK); - } - return true; - } - case IDM_USE_DEFERRED_SCRIPT_DIALOGS: - { - BOOL defaultCurrentlyEnabled; - m_settings->get_AreDefaultScriptDialogsEnabled(&defaultCurrentlyEnabled); - if (defaultCurrentlyEnabled) - { - m_settings->put_AreDefaultScriptDialogsEnabled(FALSE); - m_deferScriptDialogs = true; - MessageBox( - nullptr, - L"Custom script dialogs with deferral will be used after the next " - L"navigation.", - L"Settings change", MB_OK); - } - else if (!m_deferScriptDialogs) - { - m_deferScriptDialogs = true; - MessageBox( - nullptr, L"Custom script dialogs with deferral will be used now.", - L"Settings change", MB_OK); - } - return true; - } - case IDM_COMPLETE_JAVASCRIPT_DIALOG: + case IDM_TOGGLE_DEFAULT_SCRIPT_DIALOGS: { - CompleteScriptDialogDeferral(); + BOOL currentlyEnabled; + m_settings->get_AreDefaultScriptDialogsEnabled(¤tlyEnabled); + m_settings->put_AreDefaultScriptDialogsEnabled(!currentlyEnabled); + MessageBox( + nullptr, + (std::wstring(L"Default script dialogs will be") + + (!currentlyEnabled ? L"enabled" : L"disabled") + + L" after the next navigation.") + .c_str(), + L"Settings change", MB_OK); return true; } case ID_SETTINGS_BLOCKALLIMAGES: @@ -532,19 +584,21 @@ bool SettingsComponent::HandleWindowMessage( //! [EnableCustomMenu] if (m_allowCustomMenus) { - m_webViewExperimental6->add_ContextMenuRequested( - Callback( + m_webView2_11->add_ContextMenuRequested( + Callback( [this]( ICoreWebView2* sender, - ICoreWebView2ExperimentalContextMenuRequestedEventArgs* eventArgs) { - wil::com_ptr - args = eventArgs; - wil::com_ptr items; + ICoreWebView2ContextMenuRequestedEventArgs* eventArgs) + { + wil::com_ptr args = + eventArgs; + wil::com_ptr items; CHECK_FAILURE(args->get_MenuItems(&items)); + UINT32 itemsCount; CHECK_FAILURE(items->get_Count(&itemsCount)); - wil::com_ptr target; + wil::com_ptr target; CHECK_FAILURE(args->get_ContextMenuTarget(&target)); COREWEBVIEW2_CONTEXT_MENU_TARGET_KIND targetKind; @@ -553,7 +607,8 @@ bool SettingsComponent::HandleWindowMessage( if (targetKind == COREWEBVIEW2_CONTEXT_MENU_TARGET_KIND_SELECTED_TEXT) { - auto showMenu = [this, args, itemsCount, items, target] { + auto showMenu = [this, args, itemsCount, items, target] + { CHECK_FAILURE(args->put_Handled(true)); HMENU hPopupMenu = CreatePopupMenu(); AddMenuItems(hPopupMenu, items); @@ -583,17 +638,19 @@ bool SettingsComponent::HandleWindowMessage( }; wil::com_ptr deferral; CHECK_FAILURE(args->GetDeferral(&deferral)); - m_appWindow->RunAsync([deferral, showMenu]() { - showMenu(); - CHECK_FAILURE(deferral->Complete()); - }); + m_appWindow->RunAsync( + [deferral, showMenu]() + { + showMenu(); + CHECK_FAILURE(deferral->Complete()); + }); } // Removing the 'Save image as' context menu item for image context // selections. else if (targetKind == COREWEBVIEW2_CONTEXT_MENU_TARGET_KIND_IMAGE) { UINT32 removeIndex = itemsCount; - wil::com_ptr current; + wil::com_ptr current; for (UINT32 i = 0; i < itemsCount; i++) { CHECK_FAILURE(items->GetValueAtIndex(i, ¤t)); @@ -609,19 +666,18 @@ bool SettingsComponent::HandleWindowMessage( CHECK_FAILURE(items->RemoveValueAtIndex(removeIndex)); } } - // Adding a custom context menu item for the page that will display the - // page's URI. + // Adding a custom context menu item for the page that will display + // the page's URI. else if (targetKind == COREWEBVIEW2_CONTEXT_MENU_TARGET_KIND_PAGE) { // Custom items should be reused whenever possible. if (!m_displayPageUrlContextSubMenuItem) { - wil::com_ptr - webviewEnvironment; + wil::com_ptr webviewEnvironment; CHECK_FAILURE( m_appWindow->GetWebViewEnvironment()->QueryInterface( IID_PPV_ARGS(&webviewEnvironment))); - wil::com_ptr + wil::com_ptr displayPageUrlItem; wil::com_ptr iconStream; CHECK_FAILURE(SHCreateStreamOnFileEx( @@ -632,23 +688,15 @@ bool SettingsComponent::HandleWindowMessage( COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND_COMMAND, &displayPageUrlItem)); CHECK_FAILURE(displayPageUrlItem->add_CustomItemSelected( - Callback< - ICoreWebView2ExperimentalCustomItemSelectedEventHandler>( - [this, target]( - ICoreWebView2ExperimentalContextMenuItem* - sender, + Callback( + [appWindow = m_appWindow, target]( + ICoreWebView2ContextMenuItem* sender, IUnknown* args) { wil::unique_cotaskmem_string pageUri; CHECK_FAILURE(target->get_PageUri(&pageUri)); - std::wstring pageString = pageUri.get(); - m_appWindow->RunAsync( - [this, pageString]() { - MessageBox( - m_appWindow->GetMainWindow(), - pageString.c_str(), - L"Display Page Uri", MB_OK); - }); + appWindow->AsyncMessageBox( + pageUri.get(), L"Display Page Uri"); return S_OK; }) .Get(), @@ -657,15 +705,13 @@ bool SettingsComponent::HandleWindowMessage( L"New Submenu", nullptr, COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND_SUBMENU, &m_displayPageUrlContextSubMenuItem)); - wil::com_ptr< - ICoreWebView2ExperimentalContextMenuItemCollection> + wil::com_ptr m_displayPageUrlContextSubMenuItemChildren; CHECK_FAILURE( m_displayPageUrlContextSubMenuItem->get_Children( - &m_displayPageUrlContextSubMenuItemChildren)); + &m_displayPageUrlContextSubMenuItemChildren)); m_displayPageUrlContextSubMenuItemChildren - ->InsertValueAtIndex( - 0, displayPageUrlItem.get()); + ->InsertValueAtIndex(0, displayPageUrlItem.get()); } CHECK_FAILURE(items->InsertValueAtIndex( @@ -684,7 +730,7 @@ bool SettingsComponent::HandleWindowMessage( } else { - m_webViewExperimental6->remove_ContextMenuRequested(m_contextMenuRequestedToken); + m_webView2_11->remove_ContextMenuRequested(m_contextMenuRequestedToken); MessageBox( nullptr, L"Custom Context menus are now disabled.", L"Settings change", MB_OK); @@ -738,6 +784,19 @@ bool SettingsComponent::HandleWindowMessage( //! [DisableZoomControl] return true; } + case ID_SETTINGS_PROFILE_DELETE: + { + //! [DeleteProfile] + CHECK_FEATURE_RETURN(m_webView2_13); + wil::com_ptr webView2ProfileBase; + m_webView2_13->get_Profile(&webView2ProfileBase); + CHECK_FEATURE_RETURN(webView2ProfileBase); + auto webView2Profile = webView2ProfileBase.try_query(); + CHECK_FEATURE_RETURN(webView2Profile); + webView2Profile->Delete(); + //! [DeleteProfile] + return true; + } case ID_SETTINGS_PINCH_ZOOM_ENABLED: { //! [TogglePinchZoomEnabled] @@ -795,14 +854,14 @@ bool SettingsComponent::HandleWindowMessage( { CHECK_FAILURE(m_settings4->put_IsPasswordAutosaveEnabled(FALSE)); MessageBox( - nullptr, L"Password autosave will be disabled after the next navigation.", + nullptr, L"Password autosave will be disabled immediately.", L"Settings change", MB_OK); } else { CHECK_FAILURE(m_settings4->put_IsPasswordAutosaveEnabled(TRUE)); MessageBox( - nullptr, L"Password autosave will be enabled after the next navigation.", + nullptr, L"Password autosave will be enabled immediately.", L"Settings change", MB_OK); } //! [PasswordAutosaveEnabled] @@ -819,14 +878,14 @@ bool SettingsComponent::HandleWindowMessage( { CHECK_FAILURE(m_settings4->put_IsGeneralAutofillEnabled(FALSE)); MessageBox( - nullptr, L"General autofill will be disabled after the next navigation.", + nullptr, L"General autofill will be disabled immediately.", L"Settings change", MB_OK); } else { CHECK_FAILURE(m_settings4->put_IsGeneralAutofillEnabled(TRUE)); MessageBox( - nullptr, L"General autofill will be enabled after the next navigation.", + nullptr, L"General autofill will be enabled immediately.", L"Settings change", MB_OK); } //! [GeneralAutofillEnabled] @@ -894,36 +953,83 @@ bool SettingsComponent::HandleWindowMessage( //! [ToggleSwipeNavigationEnabled] return true; } - case ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS: + case ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_NONE: + case ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_LEFT: + case ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_CENTER: + case ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_RIGHT: + case ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_ALL: { //! [ToggleHidePdfToolbarItems] - wil::com_ptr experimentalSettings6; - experimentalSettings6 = m_settings.try_query(); - CHECK_FEATURE_RETURN(experimentalSettings6); + CHECK_FEATURE_RETURN(m_settings7); - COREWEBVIEW2_PDF_TOOLBAR_ITEMS hiddenPdfToolbarItems; - CHECK_FAILURE( - experimentalSettings6->get_HiddenPdfToolbarItems(&hiddenPdfToolbarItems)); - if (hiddenPdfToolbarItems == - COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_NONE) + COREWEBVIEW2_PDF_TOOLBAR_ITEMS itemsToHide = + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_NONE; + std::wstring message; + + switch (LOWORD(wParam)) { - CHECK_FAILURE(experimentalSettings6->put_HiddenPdfToolbarItems( + case ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_NONE: + // Show all items (hide none) + itemsToHide = + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_NONE; + message = L"All PDF toolbar items are shown after the next navigation."; + break; + case ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_LEFT: + // Left items: Bookmarks + itemsToHide = static_cast( + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_BOOKMARKS); + message = + L"PDF toolbar left items (Bookmarks) are hidden after the next navigation."; + break; + case ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_CENTER: + // Center items: Page Selector, Zoom In, Zoom Out, Fit Page, Page Layout, Rotate + itemsToHide = static_cast( + COREWEBVIEW2_PDF_TOOLBAR_ITEMS:: + COREWEBVIEW2_PDF_TOOLBAR_ITEMS_PAGE_SELECTOR | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_ZOOM_IN | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_ZOOM_OUT | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_FIT_PAGE | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_PAGE_LAYOUT | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_ROTATE); + message = L"PDF toolbar center items (Page Selector, Zoom, Fit Page, Page " + L"Layout, Rotate) are hidden after the next navigation."; + break; + case ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_RIGHT: + // Right items: Search, Print, Save, Full Screen, More Settings + itemsToHide = static_cast( + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_SEARCH | COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_PRINT | - COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_SAVE)); - MessageBox( - nullptr, - L"PDF toolbar print and save buttons are hidden after the next navigation.", - L"Settings change", MB_OK); - } - else - { - CHECK_FAILURE(experimentalSettings6->put_HiddenPdfToolbarItems( - COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_NONE)); - MessageBox( - nullptr, - L"PDF toolbar print and save buttons are shown after the next navigation.", - L"Settings change", MB_OK); + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_SAVE | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_FULL_SCREEN | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS:: + COREWEBVIEW2_PDF_TOOLBAR_ITEMS_MORE_SETTINGS); + message = L"PDF toolbar right items (Search, Print, Save, Full Screen, More " + L"Settings) are hidden after the next navigation."; + break; + case ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_ALL: + // All items + itemsToHide = static_cast( + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_PRINT | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_SAVE | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_BOOKMARKS | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_FIT_PAGE | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_PAGE_LAYOUT | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_ROTATE | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_SEARCH | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_ZOOM_IN | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_ZOOM_OUT | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_SAVE_AS | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS:: + COREWEBVIEW2_PDF_TOOLBAR_ITEMS_PAGE_SELECTOR | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_FULL_SCREEN | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS:: + COREWEBVIEW2_PDF_TOOLBAR_ITEMS_MORE_SETTINGS); + message = L"All PDF toolbar items are hidden after the next navigation."; + break; } + + CHECK_FAILURE(m_settings7->put_HiddenPdfToolbarItems(itemsToHide)); + MessageBox(nullptr, message.c_str(), L"Settings change", MB_OK); //! [ToggleHidePdfToolbarItems] return true; } @@ -932,39 +1038,339 @@ bool SettingsComponent::HandleWindowMessage( //! [ToggleAllowExternalDrop] wil::com_ptr controller = m_appWindow->GetWebViewController(); - wil::com_ptr controllerExperimental = - controller.try_query(); - if (controllerExperimental) + wil::com_ptr controller4 = + controller.try_query(); + if (controller4) { BOOL allowExternalDrop; - CHECK_FAILURE( - controllerExperimental->get_AllowExternalDrop(&allowExternalDrop)); + CHECK_FAILURE(controller4->get_AllowExternalDrop(&allowExternalDrop)); if (allowExternalDrop) { - CHECK_FAILURE(controllerExperimental->put_AllowExternalDrop(FALSE)); + CHECK_FAILURE(controller4->put_AllowExternalDrop(FALSE)); MessageBox( nullptr, L"WebView disallows dropping files now.", - L"WebView AllowDrop property changed", MB_OK); + L"WebView AllowExternalDrop property changed", MB_OK); } else { - CHECK_FAILURE(controllerExperimental->put_AllowExternalDrop(TRUE)); + CHECK_FAILURE(controller4->put_AllowExternalDrop(TRUE)); MessageBox( nullptr, L"WebView allows dropping files now.", - L"WebView AllowDrop property changed", MB_OK); + L"WebView AllowExternalDrop property changed", MB_OK); } } //! [ToggleAllowExternalDrop] return true; } + case ID_SETTINGS_SMART_SCREEN_ENABLED: + { + //! [ToggleSmartScreen] + CHECK_FEATURE_RETURN(m_settings8); + + BOOL is_smart_screen_enabled; + CHECK_FAILURE( + m_settings8->get_IsReputationCheckingRequired(&is_smart_screen_enabled)); + if (is_smart_screen_enabled) + { + CHECK_FAILURE(m_settings8->put_IsReputationCheckingRequired(false)); + MessageBox( + nullptr, L"SmartScreen is disabled after the next navigation.", + L"Settings change", MB_OK); + } + else + { + CHECK_FAILURE(m_settings8->put_IsReputationCheckingRequired(true)); + MessageBox( + nullptr, L"SmartScreen is enabled after the next navigation.", + L"Settings change", MB_OK); + } + //! [ToggleSmartScreen] + return true; + } + case ID_SETTINGS_PROFILE_PASSWORD_AUTOSAVE_ENABLED: + { + //! [ToggleProfilePasswordAutosaveEnabled] + // Get the profile object. + auto webView2_13 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_13); + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + CHECK_FEATURE_RETURN(webView2Profile); + auto webView2Profile6 = webView2Profile.try_query(); + CHECK_FEATURE_RETURN(webView2Profile6); + + BOOL enabled; + CHECK_FAILURE(webView2Profile6->get_IsPasswordAutosaveEnabled(&enabled)); + // Set password-autosave property to the opposite value to current value. + if (enabled) + { + CHECK_FAILURE(webView2Profile6->put_IsPasswordAutosaveEnabled(FALSE)); + MessageBox( + nullptr, + L"Password autosave will be disabled immediately in all " + L"WebView2 with the same profile.", + L"Profile settings change", MB_OK); + } + else + { + CHECK_FAILURE(webView2Profile6->put_IsPasswordAutosaveEnabled(TRUE)); + MessageBox( + nullptr, + L"Password autosave will be enabled immediately in all " + L"WebView2 with the same profile.", + L"Profile settings change", MB_OK); + } + //! [ToggleProfilePasswordAutosaveEnabled] + return true; + } + case ID_SETTINGS_PROFILE_GENERAL_AUTOFILL_ENABLED: + { + //! [ToggleProfileGeneralAutofillEnabled] + // Get the profile object. + auto webView2_13 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_13); + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + CHECK_FEATURE_RETURN(webView2Profile); + auto webView2Profile6 = webView2Profile.try_query(); + CHECK_FEATURE_RETURN(webView2Profile6); + + BOOL enabled; + CHECK_FAILURE(webView2Profile6->get_IsGeneralAutofillEnabled(&enabled)); + // Set general-autofill property to the opposite value to current value. + if (enabled) + { + CHECK_FAILURE(webView2Profile6->put_IsGeneralAutofillEnabled(FALSE)); + MessageBox( + nullptr, + L"General autofill will be disabled immediately in all WebView2 with the " + L"same profile.", + L"Profile settings change", MB_OK); + } + else + { + CHECK_FAILURE(webView2Profile6->put_IsGeneralAutofillEnabled(TRUE)); + MessageBox( + nullptr, + L"General autofill will be enabled immediately in all WebView2 with the " + L"same profile.", + L"Profile settings change", MB_OK); + } + //! [ToggleProfileGeneralAutofillEnabled] + return true; + } + case ID_TOGGLE_LAUNCHING_EXTERNAL_URI_SCHEME_ENABLED: + { + //! [ToggleLaunchingExternalUriScheme] + m_launchingExternalUriScheme = !m_launchingExternalUriScheme; + CHECK_FEATURE_RETURN(m_webView2_18); + if (m_launchingExternalUriScheme) + { + CHECK_FAILURE(m_webView2_18->add_LaunchingExternalUriScheme( + Callback( + [this]( + ICoreWebView2* sender, + ICoreWebView2LaunchingExternalUriSchemeEventArgs* args) + { + auto showDialog = [this, args] + { + wil::unique_cotaskmem_string uri; + CHECK_FAILURE(args->get_Uri(&uri)); + if (wcscmp(uri.get(), L"calculator://") == 0) + { + // Set the event args to cancel the event and launch the + // calculator app. This will always allow the external + // URI scheme launch. + args->put_Cancel(true); + std::wstring schemeUrl = L"calculator://"; + SHELLEXECUTEINFO info = {sizeof(info)}; + info.fMask = SEE_MASK_NOASYNC; + info.lpVerb = L"open"; + info.lpFile = schemeUrl.c_str(); + info.nShow = SW_SHOWNORMAL; + ::ShellExecuteEx(&info); + } + else if (wcscmp(uri.get(), L"malicious://") == 0) + { + // Always block the request in this case by cancelling + // the event. + args->put_Cancel(true); + } + else if (wcscmp(uri.get(), L"contoso://") == 0) + { + // To display a custom dialog we cancel the launch, + // display a custom dialog, and then manually launch the + // external URI scheme depending on the user's + // selection. + args->put_Cancel(true); + wil::unique_cotaskmem_string initiatingOrigin; + CHECK_FAILURE( + args->get_InitiatingOrigin(&initiatingOrigin)); + std::wstring message = + L"Launching External URI Scheme request"; + std::wstring initiatingOriginString = + initiatingOrigin.get(); + if (initiatingOriginString.empty()) + { + message += L" from "; + message += initiatingOriginString; + } + message += L" to "; + message += uri.get(); + message += L"?\n\n"; + message += L"Do you want to grant permission?\n"; + int response = MessageBox( + nullptr, message.c_str(), + L"Launching External URI Scheme", + MB_YESNO | MB_ICONWARNING); + if (response == IDYES) + { + std::wstring schemeUrl = uri.get(); + SHELLEXECUTEINFO info = {sizeof(info)}; + info.fMask = SEE_MASK_NOASYNC; + info.lpVerb = L"open"; + info.lpFile = schemeUrl.c_str(); + info.nShow = SW_SHOWNORMAL; + ::ShellExecuteEx(&info); + } + } + else + { + // Do not cancel the event, allowing the request to use + // the default dialog. + } + return S_OK; + }; + showDialog(); + return S_OK; + // A deferral may be taken for the event so that the + // CoreWebView2 doesn't examine the properties we set on the + // event args until after we call the Complete method + // asynchronously later. This will give the user more time to + // decide whether to launch the external URI scheme or not. + // A deferral doesn't need to be taken in this case, so taking + // a deferral is commented out here. + // wil::com_ptr deferral; + // CHECK_FAILURE(args->GetDeferral(&deferral)); + + // m_appWindow->RunAsync( + // [deferral, showDialog]() + // { + // showDialog(); + // CHECK_FAILURE(deferral->Complete()); + // }); + // return S_OK; + }) + .Get(), + &m_launchingExternalUriSchemeToken)); + } + else + { + m_webView2_18->remove_LaunchingExternalUriScheme( + m_launchingExternalUriSchemeToken); + } + MessageBox( + nullptr, + (std::wstring(L"Launching External URI Scheme support has been ") + + (m_launchingExternalUriScheme ? L"enabled." : L"disabled.")) + .c_str(), + L"Launching External URI Scheme", MB_OK); + return true; + //! [ToggleLaunchingExternalUriScheme] + } + case ID_TOGGLE_CUSTOM_SERVER_CERTIFICATE_SUPPORT: + { + ToggleCustomServerCertificateSupport(); + MessageBox( + nullptr, + (std::wstring(L"Custom server certificate support has been ") + + (m_ServerCertificateErrorToken.value != 0 ? L"enabled." : L"disabled.")) + .c_str(), + L"Custom server certificate support", MB_OK); + return true; + } + case ID_CLEAR_SERVER_CERTIFICATE_ERROR_ACTIONS: + { + CHECK_FEATURE_RETURN(m_webView2_14); + // This example clears `AlwaysAllow` response that are added for proceeding with TLS + // certificate errors. + CHECK_FAILURE(m_webView2_14->ClearServerCertificateErrorActions( + Callback( + [this](HRESULT result) -> HRESULT + { + auto showDialog = [result] + { + MessageBox( + nullptr, + (result == S_OK) + ? L"Clear server certificate error actions are succeeded." + : L"Clear server certificate error actions are failed.", + L"Clear server certificate error actions", MB_OK); + }; + + m_appWindow->RunAsync([showDialog]() { showDialog(); }); + + return S_OK; + }) + .Get())); + return true; + } + case IDM_TRACKING_PREVENTION_LEVEL_NONE: + SetTrackingPreventionLevel(COREWEBVIEW2_TRACKING_PREVENTION_LEVEL_NONE); + return true; + case IDM_TRACKING_PREVENTION_LEVEL_BASIC: + SetTrackingPreventionLevel(COREWEBVIEW2_TRACKING_PREVENTION_LEVEL_BASIC); + return true; + case IDM_TRACKING_PREVENTION_LEVEL_BALANCED: + SetTrackingPreventionLevel(COREWEBVIEW2_TRACKING_PREVENTION_LEVEL_BALANCED); + return true; + case IDM_TRACKING_PREVENTION_LEVEL_STRICT: + SetTrackingPreventionLevel(COREWEBVIEW2_TRACKING_PREVENTION_LEVEL_STRICT); + return true; + case IDM_ENHANCED_SECURITY_MODE_LEVEL_OFF: + SetEnhancedSecurityModeLevel(COREWEBVIEW2_ENHANCED_SECURITY_MODE_LEVEL_OFF); + return true; + case IDM_ENHANCED_SECURITY_MODE_LEVEL_STRICT: + SetEnhancedSecurityModeLevel(COREWEBVIEW2_ENHANCED_SECURITY_MODE_LEVEL_STRICT); + return true; + case ID_SETTINGS_NON_CLIENT_REGION_SUPPORT_ENABLED: + { + //![ToggleNonClientRegionSupportEnabled] + BOOL nonClientRegionSupportEnabled; + wil::com_ptr settings; + settings = m_settings.try_query(); + CHECK_FEATURE_RETURN(settings); + + CHECK_FAILURE( + settings->get_IsNonClientRegionSupportEnabled(&nonClientRegionSupportEnabled)); + if (nonClientRegionSupportEnabled) + { + CHECK_FAILURE(settings->put_IsNonClientRegionSupportEnabled(FALSE)); + MessageBox( + nullptr, + L"Non-client region support will be disabled after the next navigation", + L"Settings change", MB_OK); + } + else + { + CHECK_FAILURE(settings->put_IsNonClientRegionSupportEnabled(TRUE)); + MessageBox( + nullptr, + L"Non-client region support will be enabled after the next navigation", + L"Settings change", MB_OK); + } + //! [ToggleNonClientRegionSupportEnabled] + return true; + } } } return false; } + void SettingsComponent::AddMenuItems( - HMENU hPopupMenu, wil::com_ptr items) + HMENU hPopupMenu, wil::com_ptr items) { - wil::com_ptr current; + wil::com_ptr current; UINT32 itemsCount; CHECK_FAILURE(items->get_Count(&itemsCount)); for (UINT32 i = 0; i < itemsCount; i++) @@ -996,7 +1402,7 @@ void SettingsComponent::AddMenuItems( else if (kind == COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND_SUBMENU) { HMENU newMenu = CreateMenu(); - wil::com_ptr submenuItems; + wil::com_ptr submenuItems; CHECK_FAILURE(current->get_Children(&submenuItems)); AddMenuItems(newMenu, submenuItems); AppendMenu(hPopupMenu, MF_POPUP, (UINT_PTR)newMenu, labelString.c_str()); @@ -1075,6 +1481,9 @@ void SettingsComponent::ChangeBlockedSites() { m_blockedSitesSet = true; m_blockedSites.clear(); + dialog.input.erase( + std::remove_if(dialog.input.begin(), dialog.input.end(), isspace), + dialog.input.end()); size_t begin = 0; size_t end = 0; while (end != std::wstring::npos) @@ -1104,6 +1513,29 @@ bool SettingsComponent::ShouldBlockUri(PWSTR uri) return false; } +void SettingsComponent::SetCustomDataPartitionId() +{ + //! [CustomDataPartitionId] + wil::com_ptr webViewStaging20; + webViewStaging20 = m_webView.try_query(); + if (webViewStaging20) + { + wil::unique_cotaskmem_string partitionId; + CHECK_FAILURE(webViewStaging20->get_CustomDataPartitionId(&partitionId)); + TextInputDialog dialog( + m_appWindow->GetMainWindow(), L"Custom Datga Partition Id", + L"Custom Datga Partition Id:", + L"Enter data storage partition id, or leave blank to clear data storage " + L"partition.", + std::wstring(partitionId.get())); + if (dialog.confirmed) + { + webViewStaging20->put_CustomDataPartitionId(dialog.input.c_str()); + } + } + //! [CustomDataPartitionId] +} + // Decide whether a website should have script disabled. Since we're only using this // for sample code and we don't actually want to break any websites, just return false. bool SettingsComponent::ShouldBlockScriptForUri(PWSTR uri) @@ -1122,13 +1554,15 @@ void SettingsComponent::SetBlockImages(bool blockImages) //! [WebResourceRequested0] if (m_blockImages) { - m_webView->AddWebResourceRequestedFilter( - L"*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_IMAGE); + CHECK_FEATURE_RETURN_EMPTY(m_webView2_22); + m_webView2_22->AddWebResourceRequestedFilterWithRequestSourceKinds( + L"*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_IMAGE, + COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_DOCUMENT); CHECK_FAILURE(m_webView->add_WebResourceRequested( Callback( [this]( - ICoreWebView2* sender, - ICoreWebView2WebResourceRequestedEventArgs* args) { + ICoreWebView2* sender, ICoreWebView2WebResourceRequestedEventArgs* args) + { COREWEBVIEW2_WEB_RESOURCE_CONTEXT resourceContext; CHECK_FAILURE(args->get_ResourceContext(&resourceContext)); // Ensure that the type is image @@ -1137,7 +1571,8 @@ void SettingsComponent::SetBlockImages(bool blockImages) return E_INVALIDARG; } // Override the response with an empty one to block the image. - // If put_Response is not called, the request will continue as normal. + // If put_Response is not called, the request will + // continue as normal. wil::com_ptr response; wil::com_ptr environment; wil::com_ptr webview2; @@ -1172,13 +1607,15 @@ void SettingsComponent::SetReplaceImages(bool replaceImages) //! [WebResourceRequested1] if (m_replaceImages) { - m_webView->AddWebResourceRequestedFilter( - L"*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_IMAGE); + CHECK_FEATURE_RETURN_EMPTY(m_webView2_22); + m_webView2_22->AddWebResourceRequestedFilterWithRequestSourceKinds( + L"*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_IMAGE, + COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_DOCUMENT); CHECK_FAILURE(m_webView->add_WebResourceRequested( Callback( [this]( - ICoreWebView2* sender, - ICoreWebView2WebResourceRequestedEventArgs* args) { + ICoreWebView2* sender, ICoreWebView2WebResourceRequestedEventArgs* args) + { COREWEBVIEW2_WEB_RESOURCE_CONTEXT resourceContext; CHECK_FAILURE(args->get_ResourceContext(&resourceContext)); // Ensure that the type is image @@ -1187,7 +1624,11 @@ void SettingsComponent::SetReplaceImages(bool replaceImages) return E_INVALIDARG; } // Override the response with an another image. - // If put_Response is not called, the request will continue as normal. + // If put_Response is not called, the request will + // continue as normal. + // It's not required for this scenario, but generally you should examine + // relevant HTTP request headers just like an HTTP server would do when + // producing a response stream. wil::com_ptr stream; CHECK_FAILURE(SHCreateStreamOnFileEx( L"assets/EdgeWebView2-80.jpg", STGM_READ, FILE_ATTRIBUTE_NORMAL, @@ -1265,8 +1706,9 @@ void SettingsComponent::EnableCustomClientCertificateSelection() Callback( [this]( ICoreWebView2* sender, - ICoreWebView2ClientCertificateRequestedEventArgs* args) { - wil::com_ptr + ICoreWebView2ClientCertificateRequestedEventArgs* args) + { + wil::com_ptr certificateCollection; CHECK_FAILURE( args->get_MutuallyTrustedCertificates(&certificateCollection)); @@ -1274,7 +1716,7 @@ void SettingsComponent::EnableCustomClientCertificateSelection() UINT certificateCollectionCount = 0; CHECK_FAILURE( certificateCollection->get_Count(&certificateCollectionCount)); - wil::com_ptr certificate = nullptr; + wil::com_ptr certificate = nullptr; if (certificateCollectionCount > 0) { @@ -1307,35 +1749,138 @@ void SettingsComponent::EnableCustomClientCertificateSelection() } //! [ClientCertificateRequested1] -void SettingsComponent::CompleteScriptDialogDeferral() +// Function to validate the server certificate for untrusted root or self-signed certificate. +// You may also choose to defer server certificate validation. +static bool ValidateServerCertificate(ICoreWebView2Certificate* certificate) +{ + // You may want to validate certificates in different ways depending on your app and + // scenario. One way might be the following: + // First, get the list of host app trusted certificates and its thumbprint. + // + // Then get the last chain element using + // `ICoreWebView2Certificate::get_PemEncodedIssuerCertificateChain` that contains the raw + // data of the untrusted root CA/self-signed certificate. Get the untrusted root CA/self + // signed certificate thumbprint from the raw certificate data and validate the thumbprint + // against the host app trusted certificate list. + // + // Finally, return true if it exists in the host app's certificate trusted list, or + // otherwise return false. + return true; +} + +//! [ServerCertificateErrorDetected1] +// When WebView2 doesn't trust a TLS certificate but host app does, this example bypasses +// the default TLS interstitial page using the ServerCertificateErrorDetected event handler and +// continues the request to a server. Otherwise, cancel the request. +void SettingsComponent::ToggleCustomServerCertificateSupport() +{ + if (m_webView2_14) + { + if (m_ServerCertificateErrorToken.value == 0) + { + CHECK_FAILURE(m_webView2_14->add_ServerCertificateErrorDetected( + Callback( + [this]( + ICoreWebView2* sender, + ICoreWebView2ServerCertificateErrorDetectedEventArgs* args) + { + COREWEBVIEW2_WEB_ERROR_STATUS errorStatus; + CHECK_FAILURE(args->get_ErrorStatus(&errorStatus)); + + wil::com_ptr certificate = nullptr; + CHECK_FAILURE(args->get_ServerCertificate(&certificate)); + + // Continues the request to a server with a TLS certificate if the error + // status is of type + // `COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_IS_INVALID` and trusted by + // the host app. + if (errorStatus == + COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_IS_INVALID && + ValidateServerCertificate(certificate.get())) + { + CHECK_FAILURE(args->put_Action( + COREWEBVIEW2_SERVER_CERTIFICATE_ERROR_ACTION_ALWAYS_ALLOW)); + } + else + { + // Cancel the request for other TLS certificate error types or if + // untrusted by the host app. + CHECK_FAILURE(args->put_Action( + COREWEBVIEW2_SERVER_CERTIFICATE_ERROR_ACTION_CANCEL)); + } + return S_OK; + }) + .Get(), + &m_ServerCertificateErrorToken)); + } + else + { + CHECK_FAILURE(m_webView2_14->remove_ServerCertificateErrorDetected( + m_ServerCertificateErrorToken)); + m_ServerCertificateErrorToken.value = 0; + } + } + else + { + FeatureNotAvailable(); + } +} +//! [ServerCertificateErrorDetected1] + +//! [SetTrackingPreventionLevel] +void SettingsComponent::SetTrackingPreventionLevel(COREWEBVIEW2_TRACKING_PREVENTION_LEVEL value) { - if (m_completeDeferredDialog) + wil::com_ptr webView2_13; + webView2_13 = m_webView.try_query(); + + if (webView2_13) { - m_completeDeferredDialog(); - m_completeDeferredDialog = nullptr; + wil::com_ptr profile; + CHECK_FAILURE(webView2_13->get_Profile(&profile)); + + auto profile3 = profile.try_query(); + if (profile3) + { + CHECK_FAILURE(profile3->put_PreferredTrackingPreventionLevel(value)); + MessageBox( + nullptr, L"Tracking prevention level is set successfully", + L"Tracking Prevention Level", MB_OK); + } } } +//! [SetTrackingPreventionLevel] -PCWSTR SettingsComponent::NameOfPermissionKind(COREWEBVIEW2_PERMISSION_KIND kind) +//! [SetEnhancedSecurityModeLevel] +void SettingsComponent::SetEnhancedSecurityModeLevel( + COREWEBVIEW2_ENHANCED_SECURITY_MODE_LEVEL value) { - switch (kind) + wil::com_ptr webView2_13; + webView2_13 = m_webView.try_query(); + + if (webView2_13) { - case COREWEBVIEW2_PERMISSION_KIND_MICROPHONE: - return L"Microphone"; - case COREWEBVIEW2_PERMISSION_KIND_CAMERA: - return L"Camera"; - case COREWEBVIEW2_PERMISSION_KIND_GEOLOCATION: - return L"Geolocation"; - case COREWEBVIEW2_PERMISSION_KIND_NOTIFICATIONS: - return L"Notifications"; - case COREWEBVIEW2_PERMISSION_KIND_OTHER_SENSORS: - return L"Generic Sensors"; - case COREWEBVIEW2_PERMISSION_KIND_CLIPBOARD_READ: - return L"Clipboard Read"; - default: - return L"Unknown resources"; + wil::com_ptr profile; + CHECK_FAILURE(webView2_13->get_Profile(&profile)); + + auto experimentalProfile9 = profile.try_query(); + if (experimentalProfile9) + { + CHECK_FAILURE(experimentalProfile9->put_EnhancedSecurityModeLevel(value)); + + const wchar_t* levelText = L"Off"; + if (value == COREWEBVIEW2_ENHANCED_SECURITY_MODE_LEVEL_STRICT) + { + levelText = L"Strict"; + } + + MessageBox( + nullptr, + (std::wstring(L"Enhanced Security Mode level is set to ") + levelText).c_str(), + L"Enhanced Security Mode Level", MB_OK); + } } } +//! [SetEnhancedSecurityModeLevel] SettingsComponent::~SettingsComponent() { @@ -1346,10 +1891,15 @@ SettingsComponent::~SettingsComponent() m_webView->remove_PermissionRequested(m_permissionRequestedToken); } // Take advantage of urlmon's URI library to parse a URI -static wil::unique_bstr GetDomainOfUri(PWSTR uri) +wil::unique_bstr GetDomainOfUri(PWSTR uri) { wil::com_ptr uriObject; - CreateUri(uri, Uri_CREATE_CANONICALIZE | Uri_CREATE_NO_DECODE_EXTRA_INFO, 0, &uriObject); + HRESULT hr = CreateUri( + uri, Uri_CREATE_CANONICALIZE | Uri_CREATE_NO_DECODE_EXTRA_INFO, 0, &uriObject); + if (FAILED(hr)) + { + return nullptr; + } wil::unique_bstr domain; uriObject->GetHost(&domain); return domain; diff --git a/SampleApps/WebView2APISample/SettingsComponent.h b/SampleApps/WebView2APISample/SettingsComponent.h index 9cd65275..109328be 100644 --- a/SampleApps/WebView2APISample/SettingsComponent.h +++ b/SampleApps/WebView2APISample/SettingsComponent.h @@ -14,6 +14,9 @@ #include "ComponentBase.h" #include "CustomStatusBar.h" +// Some utility functions +wil::unique_bstr GetDomainOfUri(PWSTR uri); + // This component handles commands from the Settings menu. It also handles the // NavigationStarting, FrameNavigationStarting, WebResourceRequested, ScriptDialogOpening, // and PermissionRequested events. @@ -28,7 +31,7 @@ class SettingsComponent : public ComponentBase HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* result) override; void AddMenuItems( - HMENU hPopupMenu, wil::com_ptr items); + HMENU hPopupMenu, wil::com_ptr items); void ChangeBlockedSites(); bool ShouldBlockUri(PWSTR uri); @@ -37,33 +40,44 @@ class SettingsComponent : public ComponentBase void SetReplaceImages(bool replaceImages); void ChangeUserAgent(); void SetUserAgent(const std::wstring& userAgent); - void CompleteScriptDialogDeferral(); void EnableCustomClientCertificateSelection(); + void ToggleCustomServerCertificateSupport(); + void SetCustomDataPartitionId(); + + void SetTrackingPreventionLevel(COREWEBVIEW2_TRACKING_PREVENTION_LEVEL value); - static PCWSTR NameOfPermissionKind(COREWEBVIEW2_PERMISSION_KIND kind); + void SetEnhancedSecurityModeLevel(COREWEBVIEW2_ENHANCED_SECURITY_MODE_LEVEL value); ~SettingsComponent() override; private: + HRESULT OnPermissionRequested( + ICoreWebView2* sender, ICoreWebView2PermissionRequestedEventArgs* args); AppWindow* m_appWindow = nullptr; - wil::com_ptr m_webViewEnvironment; wil::com_ptr m_webView; + wil::com_ptr m_webView2_5; + wil::com_ptr m_webView2_11; + wil::com_ptr m_webView2_12; + wil::com_ptr m_webView2_13; + wil::com_ptr m_webView2_14; + wil::com_ptr m_webView2_15; + wil::com_ptr m_webView2_18; + wil::com_ptr m_webView2_22; wil::com_ptr m_settings; wil::com_ptr m_settings2; wil::com_ptr m_settings3; wil::com_ptr m_settings4; wil::com_ptr m_settings5; wil::com_ptr m_settings6; - wil::com_ptr m_webView2_5; + wil::com_ptr m_settings7; + wil::com_ptr m_settings8; wil::com_ptr m_controller; wil::com_ptr m_controller3; - wil::com_ptr m_webViewExperimental5; - wil::com_ptr m_webViewExperimental6; - wil::com_ptr m_webViewExperimental13; - wil::com_ptr m_displayPageUrlContextSubMenuItem; + wil::com_ptr m_webViewEnvironment; + wil::com_ptr m_displayPageUrlContextSubMenuItem; + bool m_blockImages = false; bool m_replaceImages = false; - bool m_deferScriptDialogs = false; bool m_changeUserAgent = false; bool m_isScriptEnabled = true; bool m_blockedSitesSet = false; @@ -73,9 +87,13 @@ class SettingsComponent : public ComponentBase m_cached_permissions; std::vector m_blockedSites; std::wstring m_overridingUserAgent; - std::function m_completeDeferredDialog; + ULONG_PTR gdiplusToken_; + bool m_faviconChanged = false; + wil::unique_hicon m_favicon; CustomStatusBar m_statusBar; bool m_customStatusBar = false; + bool m_raiseServerCertificateError = false; + bool m_launchingExternalUriScheme = false; EventRegistrationToken m_navigationStartingToken = {}; EventRegistrationToken m_frameNavigationStartingToken = {}; @@ -86,5 +104,8 @@ class SettingsComponent : public ComponentBase EventRegistrationToken m_permissionRequestedToken = {}; EventRegistrationToken m_ClientCertificateRequestedToken = {}; EventRegistrationToken m_contextMenuRequestedToken = {}; + EventRegistrationToken m_faviconChangedToken = {}; EventRegistrationToken m_statusBarTextChangedToken = {}; + EventRegistrationToken m_ServerCertificateErrorToken = {}; + EventRegistrationToken m_launchingExternalUriSchemeToken = {}; }; diff --git a/SampleApps/WebView2APISample/Toolbar.cpp b/SampleApps/WebView2APISample/Toolbar.cpp index da772891..deee617d 100644 --- a/SampleApps/WebView2APISample/Toolbar.cpp +++ b/SampleApps/WebView2APISample/Toolbar.cpp @@ -37,7 +37,7 @@ void Toolbar::Initialize(AppWindow* appWindow) L"button", L"Cancel", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 0, 0, 0, 0, mainWindow, (HMENU)IDE_CANCEL, nullptr, 0); m_items[Item_AddressBar] = CreateWindow( - L"edit", nullptr, WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 0, 0, 0, 0, + L"edit", nullptr, WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL, 0, 0, 0, 0, mainWindow, (HMENU)IDE_ADDRESSBAR, nullptr, 0); m_items[Item_GoButton] = CreateWindow( L"button", L"Go", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | BS_DEFPUSHBUTTON, @@ -56,6 +56,15 @@ void Toolbar::SetItemEnabled(Item item, bool enabled) EnableWindow(m_items[item], enabled); } +void Toolbar::Hide() +{ + DisableAllItems(); + for (HWND hwnd : m_items) + { + ShowWindow(hwnd, SW_HIDE); + } +} + void Toolbar::DisableAllItems() { for (HWND hwnd : m_items) @@ -143,3 +152,14 @@ void Toolbar::UpdateFont() StringCchCopy(logFont.lfFaceName, ARRAYSIZE(logFont.lfFaceName), s_fontName); m_font = CreateFontIndirect(&logFont); } + +void Toolbar::SelectAll() +{ + SendMessage(m_items[Item_AddressBar], EM_SETSEL, 0, -1); +} + +void Toolbar::SelectAddressBar() +{ + SetFocus(m_items[Item_AddressBar]); + SelectAll(); +} diff --git a/SampleApps/WebView2APISample/Toolbar.h b/SampleApps/WebView2APISample/Toolbar.h index db6660c3..d6c0b05d 100644 --- a/SampleApps/WebView2APISample/Toolbar.h +++ b/SampleApps/WebView2APISample/Toolbar.h @@ -33,6 +33,9 @@ class Toolbar // Returns remaining available area for the WebView RECT Resize(RECT availableBounds); void UpdateDpiAndTextScale(); + void SelectAll(); + void SelectAddressBar(); + void Hide(); private: int GetItemLogicalWidth(Item item, int clientLogicalWidth) const; diff --git a/SampleApps/WebView2APISample/Util.cpp b/SampleApps/WebView2APISample/Util.cpp new file mode 100644 index 00000000..28b346ed --- /dev/null +++ b/SampleApps/WebView2APISample/Util.cpp @@ -0,0 +1,76 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "stdafx.h" + +#include "CheckFailure.h" +#include "Util.h" + +std::wstring Util::UnixEpochToDateTime(double value) +{ + WCHAR rawResult[32] = {}; + std::time_t rawTime = std::time_t(value / 1000); + struct tm timeStruct = {}; + gmtime_s(&timeStruct, &rawTime); + _wasctime_s(rawResult, 32, &timeStruct); + std::wstring result(rawResult); + return result; +} + +std::wstring Util::TrimWhitespace(const std::wstring& text) +{ + if (text.empty()) + { + return text; + } + + std::wstring trimmedText = text; + trimmedText.erase(0, trimmedText.find_first_not_of(L" \t\r\n")); + trimmedText.erase(trimmedText.find_last_not_of(L" \t\r\n") + 1); + + return trimmedText; +} + +std::vector Util::SplitString(const std::wstring& input, wchar_t delimiter) +{ + std::vector result; + + if (input.empty()) + { + return result; + } + + std::wstring::size_type start = 0; + std::wstring::size_type end = 0; + + end = input.find(delimiter, start); + while (end != std::wstring::npos) + { + std::wstring token = input.substr(start, end - start); + token = TrimWhitespace(token); + + if (!token.empty()) + { + result.push_back(token); + } + + start = end + 1; + end = input.find(delimiter, start); + } + + // Handle the last token after the final delimiter (or the only token if there's no + // delimiter) + if (start < input.length()) + { + std::wstring token = input.substr(start); + token = TrimWhitespace(token); + + if (!token.empty()) + { + result.push_back(token); + } + } + + return result; +} \ No newline at end of file diff --git a/SampleApps/WebView2APISample/Util.h b/SampleApps/WebView2APISample/Util.h new file mode 100644 index 00000000..ba8839be --- /dev/null +++ b/SampleApps/WebView2APISample/Util.h @@ -0,0 +1,18 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include + +#include "stdafx.h" + +class Util +{ +public: + static std::wstring UnixEpochToDateTime(double value); + static std::vector SplitString(const std::wstring& input, wchar_t delimiter); + static std::wstring TrimWhitespace(const std::wstring& text); +}; diff --git a/SampleApps/WebView2APISample/ViewComponent.cpp b/SampleApps/WebView2APISample/ViewComponent.cpp index 13e22cc5..9e126ca9 100644 --- a/SampleApps/WebView2APISample/ViewComponent.cpp +++ b/SampleApps/WebView2APISample/ViewComponent.cpp @@ -8,13 +8,11 @@ #include "DCompTargetImpl.h" #include "AppStartPage.h" +#include "DropTarget.h" #include #include -#include -#ifdef USE_WEBVIEW2_WIN10 #include -#endif -#include "DropTarget.h" +#include #include "CheckFailure.h" @@ -37,18 +35,11 @@ static void UpdateDocumentTitle(AppWindow* appWindow, const std::wstring& prefix }; ViewComponent::ViewComponent( - AppWindow* appWindow, - IDCompositionDevice* dcompDevice, -#ifdef USE_WEBVIEW2_WIN10 - winrtComp::Compositor wincompCompositor, -#endif - bool isDcompTargetMode) + AppWindow* appWindow, IDCompositionDevice* dcompDevice, + winrtComp::Compositor wincompCompositor, bool isDcompTargetMode) : m_appWindow(appWindow), m_controller(appWindow->GetWebViewController()), m_webView(appWindow->GetWebView()), m_dcompDevice(dcompDevice), -#ifdef USE_WEBVIEW2_WIN10 - m_wincompCompositor(wincompCompositor), -#endif - m_isDcompTargetMode(isDcompTargetMode) + m_wincompCompositor(wincompCompositor), m_isDcompTargetMode(isDcompTargetMode) { //! [ZoomFactorChanged] // Register a handler for the ZoomFactorChanged event. @@ -82,35 +73,24 @@ ViewComponent::ViewComponent( if (appStartPage.compare(0, queryIndex, newUri.get(), queryIndex) == 0) { // When navigating to the app start page, make the background of - // the html be the WebView2 logo. On Win10, we do this by making + // the html be the WebView2 logo. We do this by making // the background color transparent so the WebView2 logo in the AppWindow - // shows through. On Win7, transparency is not supported, so we need to - // enable a CSS style to add the WebView2 logo as the background image. -#if USE_WEBVIEW2_WIN10 - COREWEBVIEW2_COLOR transparentColor = { 0, 255, 255, 255 }; + // shows through. + COREWEBVIEW2_COLOR transparentColor = {0, 0, 0, 0}; wil::com_ptr controller2 = m_controller.query(); // Save the previous background color to restore when navigating away. CHECK_FAILURE(controller2->get_DefaultBackgroundColor(&m_webViewColor)); CHECK_FAILURE(controller2->put_DefaultBackgroundColor(transparentColor)); -#else - std::wstring setBackgroundImageScript = - L"document.addEventListener('DOMContentLoaded', () => {" - L" document.documentElement.classList.add('logo-background');" - L"});"; - m_webView->ExecuteScript(setBackgroundImageScript.c_str(), nullptr); -#endif } else if (appStartPage.compare(0, queryIndex, oldUri.get(), queryIndex) == 0) { -#if USE_WEBVIEW2_WIN10 // When navigating away from the app start page, set the background color // back to the previous value. If the user changed the background color, // m_webViewColor will have changed. wil::com_ptr controller2 = m_controller.query(); CHECK_FAILURE(controller2->put_DefaultBackgroundColor(m_webViewColor)); -#endif } return S_OK; }).Get(), &m_navigationStartingToken)); @@ -160,13 +140,11 @@ ViewComponent::ViewComponent( CHECK_FAILURE(m_dcompDevice->Commit()); //! [SetRootVisualTarget] } -#ifdef USE_WEBVIEW2_WIN10 else if (m_wincompCompositor) { BuildWinCompVisualTree(); CHECK_FAILURE(m_compositionController->put_RootVisualTarget(m_wincompWebViewVisual.as().get())); } -#endif else { FAIL_FAST(); @@ -179,6 +157,7 @@ ViewComponent::ViewComponent( -> HRESULT { HRESULT hr = S_OK; HCURSOR cursor; + if (!m_useCursorId) { CHECK_FAILURE(sender->get_Cursor(&cursor)); @@ -189,35 +168,37 @@ ViewComponent::ViewComponent( UINT32 cursorId; CHECK_FAILURE(m_compositionController->get_SystemCursorId(&cursorId)); cursor = ::LoadCursor(nullptr, MAKEINTRESOURCE(cursorId)); - if (cursor == nullptr) + + if (cursorId != NULL && cursor == nullptr) { hr = HRESULT_FROM_WIN32(GetLastError()); } //! [SystemCursorId] } - if (SUCCEEDED(hr)) + if (cursor != nullptr) { SetClassLongPtr( m_appWindow->GetMainWindow(), GCLP_HCURSOR, (LONG_PTR)cursor); } + else if (SUCCEEDED(hr)) + { + SetCursor(NULL); + } + return hr; }) .Get(), &m_cursorChangedToken)); //! [CursorChanged] - wil::com_ptr compositionController3 = - m_controller.query(); + wil::com_ptr compositionController3 = + m_controller.query(); m_dropTarget = Make(); m_dropTarget->Init( m_appWindow->GetMainWindow(), this, compositionController3.get()); } - else if (m_dcompDevice -#ifdef USE_WEBVIEW2_WIN10 - || m_wincompCompositor -#endif - ) + else if (m_dcompDevice || m_wincompCompositor) { FAIL_FAST(); } @@ -235,6 +216,32 @@ ViewComponent::ViewComponent( bool ViewComponent::HandleWindowMessage( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* result) { + wil::com_ptr compositionController4; + + if (m_compositionController) + { + compositionController4 = + m_compositionController.try_query(); + } + + //! [DraggableRegions1] + if (message == WM_NCHITTEST && compositionController4) + { + POINT point{GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; + ScreenToClient(hWnd, &point); + if (PtInRect(&m_webViewBounds, point)) + { + point.x -= m_webViewBounds.left; + point.y -= m_webViewBounds.top; + + COREWEBVIEW2_NON_CLIENT_REGION_KIND region = + COREWEBVIEW2_NON_CLIENT_REGION_KIND_NOWHERE; + CHECK_FAILURE(compositionController4->GetNonClientRegionAtPoint(point, ®ion)); + *result = region; + return true; + } + } + //! [DraggableRegions1] if (message == WM_COMMAND) { switch (LOWORD(wParam)) @@ -261,7 +268,7 @@ bool ViewComponent::HandleWindowMessage( SetBackgroundColor(RGB(0, 0, 255), false); return true; case IDM_BACKGROUNDCOLOR_TRANSPARENT: - SetBackgroundColor(RGB(255, 255, 255), true); + SetBackgroundColor(RGB(0, 0, 0), true); return true; case IDM_ZOOM_05: SetZoomFactor(0.5f); @@ -383,16 +390,18 @@ bool ViewComponent::HandleWindowMessage( } } //! [ToggleIsVisibleOnMinimize] - if ((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) || message == WM_MOUSELEAVE) + if ((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) + || (message == WM_NCRBUTTONUP || message == WM_NCRBUTTONDOWN) + || message == WM_MOUSELEAVE) { - OnMouseMessage(message, wParam, lParam); + return OnMouseMessage(message, wParam, lParam); } else if ( message == WM_POINTERACTIVATE || message == WM_POINTERDOWN || message == WM_POINTERENTER || message == WM_POINTERLEAVE || message == WM_POINTERUP || message == WM_POINTERUPDATE) { - OnPointerMessage(message, wParam, lParam); + return OnPointerMessage(message, wParam, lParam); } //! [NotifyParentWindowPositionChanged] if (message == WM_MOVE || message == WM_MOVING) @@ -407,20 +416,14 @@ bool ViewComponent::HandleWindowMessage( //! [SetPreferredColorScheme] void ViewComponent::SetPreferredColorScheme(COREWEBVIEW2_PREFERRED_COLOR_SCHEME value) { - wil::com_ptr webViewExperimental8; - webViewExperimental8 = m_webView.try_query(); + wil::com_ptr webView2_13; + webView2_13 = m_webView.try_query(); - if (webViewExperimental8) + if (webView2_13) { - wil::com_ptr profile; - CHECK_FAILURE(webViewExperimental8->get_Profile(&profile)); - - auto profileExperimental2 = - profile.try_query(); - if (profileExperimental2) - { - profileExperimental2->put_PreferredColorScheme(value); - } + wil::com_ptr profile; + CHECK_FAILURE(webView2_13->get_Profile(&profile)); + profile->put_PreferredColorScheme(value); } } //! [SetPreferredColorScheme] @@ -454,20 +457,17 @@ void ViewComponent::Suspend() { wil::com_ptr webView; webView = m_webView.try_query(); - if (!webView) - { - ShowFailure(E_NOINTERFACE, L"TrySuspend API not available"); - return; - } + CHECK_FEATURE_RETURN_EMPTY(webView); HRESULT hr = webView->TrySuspend( Callback( - [](HRESULT errorCode, BOOL isSuccessful) -> HRESULT { + [this](HRESULT errorCode, BOOL isSuccessful) -> HRESULT { if ((errorCode != S_OK) || !isSuccessful) { std::wstringstream formattedMessage; formattedMessage << "TrySuspend result (0x" << std::hex << errorCode << ") " << (isSuccessful ? "succeeded" : "failed"); - MessageBox(nullptr, formattedMessage.str().c_str(), nullptr, MB_OK); + m_appWindow->AsyncMessageBox( + std::move(formattedMessage.str()), L"TrySuspend result"); } return S_OK; }) @@ -480,13 +480,9 @@ void ViewComponent::Suspend() //! [MemoryUsageTargetLevel] void ViewComponent::ToggleMemoryUsageTargetLevel() { - wil::com_ptr webView; - webView = m_webView.try_query(); - if (!webView) - { - ShowFailure(E_NOINTERFACE, L"MemoryUsageTargetLevel API not available"); - return; - } + wil::com_ptr webView; + webView = m_webView.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webView); COREWEBVIEW2_MEMORY_USAGE_TARGET_LEVEL memory_target_level = COREWEBVIEW2_MEMORY_USAGE_TARGET_LEVEL_NORMAL; CHECK_FAILURE(webView->get_MemoryUsageTargetLevel(&memory_target_level)); @@ -508,11 +504,7 @@ void ViewComponent::Resume() { wil::com_ptr webView; webView = m_webView.try_query(); - if (!webView) - { - ShowFailure(E_NOINTERFACE, L"Resume API not available"); - return; - } + CHECK_FEATURE_RETURN_EMPTY(webView); webView->Resume(); } //! [Resume] @@ -604,7 +596,6 @@ void ViewComponent::ResizeWebView() {0, 0, float(webViewSize.cx), float(webViewSize.cy)})); CHECK_FAILURE(m_dcompDevice->Commit()); } -#ifdef USE_WEBVIEW2_WIN10 else if (m_wincompCompositor) { if (m_wincompRootVisual != nullptr) @@ -621,7 +612,6 @@ void ViewComponent::ResizeWebView() m_wincompRootVisual.Clip(insetClip.as()); } } -#endif } } //! [ResizeWebView] @@ -685,18 +675,13 @@ void ViewComponent::SetTransform(TransformType transformType) m_webViewTransformMatrix = D2D1::Matrix4x4F(); } -#ifdef USE_WEBVIEW2_WIN10 if (m_dcompDevice && !m_wincompCompositor) -#else - if (m_dcompDevice) -#endif { wil::com_ptr dcompWebViewVisual3; m_dcompWebViewVisual->QueryInterface(IID_PPV_ARGS(&dcompWebViewVisual3)); CHECK_FAILURE(dcompWebViewVisual3->SetTransform(m_webViewTransformMatrix)); CHECK_FAILURE(m_dcompDevice->Commit()); } -#ifdef USE_WEBVIEW2_WIN10 else if (m_wincompCompositor && !m_dcompDevice) { if (m_wincompWebViewVisual != nullptr) @@ -705,7 +690,6 @@ void ViewComponent::SetTransform(TransformType transformType) *reinterpret_cast(&m_webViewTransformMatrix)); } } -#endif else { FAIL_FAST(); @@ -754,15 +738,16 @@ static D2D1_MATRIX_4X4_F Convert3x2MatrixTo4x4Matrix(D2D1_MATRIX_3X2_F* matrix3x bool ViewComponent::OnMouseMessage(UINT message, WPARAM wParam, LPARAM lParam) { // Manually relay mouse messages to the WebView -#ifdef USE_WEBVIEW2_WIN10 if (m_dcompDevice || m_wincompCompositor) -#else - if (m_dcompDevice) -#endif { POINT point; POINTSTOPOINT(point, lParam); - if (message == WM_MOUSEWHEEL || message == WM_MOUSEHWHEEL) + if (message == WM_MOUSEWHEEL || + message == WM_MOUSEHWHEEL + //! [DraggableRegions2] + || message == WM_NCRBUTTONDOWN || message == WM_NCRBUTTONUP + //! [DraggableRegions2] + ) { // Mouse wheel messages are delivered in screen coordinates. // SendMouseInput expects client coordinates for the WebView, so convert @@ -859,11 +844,7 @@ bool ViewComponent::OnMouseMessage(UINT message, WPARAM wParam, LPARAM lParam) bool ViewComponent::OnPointerMessage(UINT message, WPARAM wParam, LPARAM lParam) { bool handled = false; -#ifdef USE_WEBVIEW2_WIN10 if (m_dcompDevice || m_wincompCompositor) -#else - if (m_dcompDevice) -#endif { POINT point; POINTSTOPOINT(point, lParam); @@ -963,7 +944,6 @@ void ViewComponent::DestroyDCompVisualTree() } } -#ifdef USE_WEBVIEW2_WIN10 void ViewComponent::BuildWinCompVisualTree() { namespace abiComp = ABI::Windows::UI::Composition; @@ -997,7 +977,6 @@ void ViewComponent::DestroyWinCompVisualTree() m_wincompHwndTarget = nullptr; } } -#endif //! [ToggleDefaultDownloadDialog] void ViewComponent::ToggleDefaultDownloadDialog() @@ -1113,8 +1092,6 @@ ViewComponent::~ViewComponent() // is destroyed. If the webview is closed explicitly, this will succeed. m_compositionController->put_RootVisualTarget(nullptr); DestroyDCompVisualTree(); -#ifdef USE_WEBVIEW2_WIN10 DestroyWinCompVisualTree(); -#endif } } diff --git a/SampleApps/WebView2APISample/ViewComponent.h b/SampleApps/WebView2APISample/ViewComponent.h index a24b3df1..b2536fe8 100644 --- a/SampleApps/WebView2APISample/ViewComponent.h +++ b/SampleApps/WebView2APISample/ViewComponent.h @@ -10,9 +10,7 @@ #include "ComponentBase.h" #include #include -#ifdef USE_WEBVIEW2_WIN10 #include -#endif // This component handles commands from the View menu, as well as the ZoomFactorChanged // event, and any functionality related to sizing and visibility of the WebView. @@ -27,13 +25,8 @@ class ViewComponent : public ComponentBase public: ViewComponent( - AppWindow* appWindow, - IDCompositionDevice* dcompDevice, -#ifdef USE_WEBVIEW2_WIN10 - winrtComp::Compositor wincompCompositor, -#endif - bool isDCompTargetMode - ); + AppWindow* appWindow, IDCompositionDevice* dcompDevice, + winrtComp::Compositor wincompCompositor, bool isDCompTargetMode); bool HandleWindowMessage( HWND hWnd, @@ -102,7 +95,7 @@ class ViewComponent : public ComponentBase const int m_downloadsButtonMargin = 50; const int m_downloadsButtonWidth = 120; const int m_downloadsButtonHeight = 80; - HWND m_downloadsButton; + HWND m_downloadsButton = nullptr; EventRegistrationToken m_zoomFactorChangedToken = {}; EventRegistrationToken m_rasterizationScaleChangedToken = {}; @@ -127,15 +120,13 @@ class ViewComponent : public ComponentBase wil::com_ptr m_dcompRootVisual; wil::com_ptr m_dcompWebViewVisual; -#ifdef USE_WEBVIEW2_WIN10 void BuildWinCompVisualTree(); void DestroyWinCompVisualTree(); winrt::Windows::UI::Composition::Compositor m_wincompCompositor{ nullptr }; winrt::Windows::UI::Composition::Desktop::DesktopWindowTarget m_wincompHwndTarget{ nullptr }; winrt::Windows::UI::Composition::ContainerVisual m_wincompRootVisual{ nullptr }; - winrt::Windows::UI::Composition::ContainerVisual m_wincompWebViewVisual{ nullptr }; -#endif + winrt::Windows::UI::Composition::ContainerVisual m_wincompWebViewVisual{nullptr}; // This member is used to exercise the put_RootVisualTarget API with an IDCompositionTarget. // Distinct/unrelated to the dcompHwndTarget diff --git a/SampleApps/WebView2APISample/WebView2APISample.ico b/SampleApps/WebView2APISample/WebView2APISample.ico index b3ec03bd..f36635ca 100644 Binary files a/SampleApps/WebView2APISample/WebView2APISample.ico and b/SampleApps/WebView2APISample/WebView2APISample.ico differ diff --git a/SampleApps/WebView2APISample/WebView2APISample.rc b/SampleApps/WebView2APISample/WebView2APISample.rc index e7a031b8..36b69f38 100644 --- a/SampleApps/WebView2APISample/WebView2APISample.rc +++ b/SampleApps/WebView2APISample/WebView2APISample.rc @@ -33,7 +33,6 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // remains consistent on all systems. IDI_WEBVIEW2APISAMPLE ICON "WebView2APISample.ico" IDI_WEBVIEW2APISAMPLE_INPRIVATE ICON "WebView2APISample_Inprivate.ico" -IDI_SMALL ICON "small.ico" IDI_WEBVIEW2_BACKGROUND BITMAP "AppBackground.bmp" @@ -56,6 +55,7 @@ BEGIN MENUITEM "Get Browser Version After Creation", IDM_GET_BROWSER_VERSION_AFTER_CREATION MENUITEM "Get Browser Version Before Creation", IDM_GET_BROWSER_VERSION_BEFORE_CREATION MENUITEM "Get User Data Folder", IDM_GET_USER_DATA_FOLDER + MENUITEM "Get Failure Report Folder", IDM_GET_FAILURE_REPORT_FOLDER MENUITEM "Update WebView2 Runtime", IDM_UPDATE_RUNTIME MENUITEM "E&xit", IDM_EXIT END @@ -63,6 +63,7 @@ BEGIN BEGIN MENUITEM "Inject Script", IDM_INJECT_SCRIPT MENUITEM "Inject Script Into IFrame", IDM_INJECT_SCRIPT_FRAME + MENUITEM "Inject Script With Result", IDM_INJECT_SCRIPT_WITH_RESULT MENUITEM "Add Initialize Script", ID_ADD_INITIALIZE_SCRIPT MENUITEM "Remove Initialize Script", ID_REMOVE_INITIALIZE_SCRIPT MENUITEM SEPARATOR @@ -82,23 +83,29 @@ BEGIN MENUITEM SEPARATOR MENUITEM "Open DevTools Window", IDM_OPEN_DEVTOOLS_WINDOW MENUITEM "Open Task Manager Window", IDM_OPEN_TASK_MANAGER_WINDOW + MENUITEM SEPARATOR + MENUITEM "Add Browser Extension", IDM_ADD_EXTENSION + MENUITEM "Remove Browser Extension", IDM_REMOVE_EXTENSION + MENUITEM "Enable/Disable Extension", IDM_DISABLE_EXTENSION + MENUITEM "Start Find", IDM_START_FIND END POPUP "&Window" BEGIN MENUITEM "Set WebView Language", IDM_SET_LANGUAGE MENUITEM "Toggle AAD SSO enabled", IDM_TOGGLE_AAD_SSO MENUITEM "Toggle exclusive user data folder access", IDM_TOGGLE_EXCLUSIVE_USER_DATA_FOLDER_ACCESS + MENUITEM "Toggle Custom Crash Reporting" IDM_TOGGLE_CUSTOM_CRASH_REPORTING + MENUITEM "Toggle Tracking Prevention Disabled", IDM_TOGGLE_TRACKING_PREVENTION MENUITEM "Close WebView", IDM_CLOSE_WEBVIEW MENUITEM "Close WebView and Delete User Data Folder", IDM_CLOSE_WEBVIEW_CLEANUP MENUITEM SEPARATOR POPUP "WebView Creation Mode" BEGIN MENUITEM "Windowed", IDM_CREATION_MODE_WINDOWED + MENUITEM "Windowed - HostInputProcessing", IDM_CREATION_MODE_HOST_INPUT_PROCESSING MENUITEM "Visual - DComp", IDM_CREATION_MODE_VISUAL_DCOMP MENUITEM "Target - DComp", IDM_CREATION_MODE_TARGET_DCOMP -#ifdef USE_WEBVIEW2_WIN10 MENUITEM "Visual - WinComp", IDM_CREATION_MODE_VISUAL_WINCOMP -#endif END MENUITEM "Create WebView" IDM_REINIT MENUITEM "Create New Window With Option" IDM_CREATE_WITH_OPTION @@ -112,18 +119,13 @@ BEGIN MENUITEM "Crash Browser Process", IDM_CRASH_PROCESS MENUITEM "Crash Render Process", IDM_CRASH_RENDER_PROCESS MENUITEM "Show Performance Info", IDM_PERFORMANCE_INFO + MENUITEM "Show Process Extended Info", IDM_PROCESS_EXTENDED_INFO END POPUP "S&ettings" BEGIN MENUITEM "Blocked Domains", ID_BLOCKEDSITES - POPUP "JavaScript Dialogs" - BEGIN - MENUITEM "Use Default Script Dialogs", IDM_USE_DEFAULT_SCRIPT_DIALOGS - MENUITEM "Use Custom Script Dialogs", IDM_USE_CUSTOM_SCRIPT_DIALOGS - MENUITEM "Use Deferred Script Dialogs", IDM_USE_DEFERRED_SCRIPT_DIALOGS - MENUITEM "Complete Deferred Script Dialog", IDM_COMPLETE_JAVASCRIPT_DIALOG - END - MENUITEM "Set User Agent", ID_SETTINGS_SETUSERAGENT + MENUITEM "Set Custom Data Partition Id", ID_CUSTOM_DATA_PARTITION + MENUITEM "Set User Agent", ID_SETTINGS_SETUSERAGENT MENUITEM "Toggle Allow External Drop", ID_TOGGLE_ALLOW_EXTERNAL_DROP MENUITEM "Toggle Block Images", ID_SETTINGS_BLOCKALLIMAGES MENUITEM "Toggle Browser Accelerator Keys Enabled", ID_SETTINGS_BROWSER_ACCELERATOR_KEYS_ENABLED @@ -131,18 +133,51 @@ BEGIN MENUITEM "Toggle Client Certificate Requested", ID_TOGGLE_CLIENT_CERTIFICATE_REQUESTED MENUITEM "Toggle Context Menus Enabled", ID_SETTINGS_CONTEXT_MENUS_ENABLED MENUITEM "Toggle Custom Context Menu", ID_TOGGLE_CUSTOM_CONTEXT_MENU + MENUITEM "Toggle Favicon Changed Listener", ID_SETTINGS_TOGGLE_POST_FAVICON_CHANGED + MENUITEM "Toggle Custom Status Bar", ID_SETTINGS_TOGGLE_POST_STATUS_BAR_ACTIVITY + MENUITEM "Toggle Default Script Dialogs", IDM_TOGGLE_DEFAULT_SCRIPT_DIALOGS MENUITEM "Toggle DevTools Enabled", ID_SETTINGS_DEV_TOOLS_ENABLED MENUITEM "Toggle General Autofill", ID_SETTINGS_GENERAL_AUTOFILL_ENABLED - MENUITEM "Toggle Hide PDF Toolbar Items", ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS + POPUP "Toggle Hide PDF Toolbar Items" + BEGIN + MENUITEM "None (Show All)", ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_NONE + MENUITEM "Hide Left Items", ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_LEFT + MENUITEM "Hide Center Items", ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_CENTER + MENUITEM "Hide Right Items", ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_RIGHT + MENUITEM "Hide All Items", ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_ALL + END MENUITEM "Toggle Host Objects Allowed", ID_SETTINGS_HOST_OBJECTS_ALLOWED MENUITEM "Toggle JavaScript", IDM_TOGGLE_JAVASCRIPT MENUITEM "Toggle Password Autosave", ID_SETTINGS_PASSWORD_AUTOSAVE_ENABLED MENUITEM "Toggle Pinch Zoom Enabled", ID_SETTINGS_PINCH_ZOOM_ENABLED + MENUITEM "Toggle Profile General Autofill", ID_SETTINGS_PROFILE_GENERAL_AUTOFILL_ENABLED + MENUITEM "Toggle Profile Password Autosave", ID_SETTINGS_PROFILE_PASSWORD_AUTOSAVE_ENABLED + MENUITEM "Toggle Profile Smart Screen", ID_SETTINGS_SMART_SCREEN_ENABLED MENUITEM "Toggle Replace Images", ID_SETTINGS_REPLACEALLIMAGES + POPUP "Server Certificate Error" + BEGIN + MENUITEM "Toggle Custom Server Certificate Support", ID_TOGGLE_CUSTOM_SERVER_CERTIFICATE_SUPPORT + MENUITEM "Clear Server Certificate Error Actions", ID_CLEAR_SERVER_CERTIFICATE_ERROR_ACTIONS + END MENUITEM "Toggle Status Bar Enabled", ID_SETTINGS_STATUS_BAR_ENABLED MENUITEM "Toggle Swipe navigation Enabled", ID_SETTINGS_SWIPE_NAVIGATION_ENABLED MENUITEM "Toggle Web Messaging", IDM_TOGGLE_WEB_MESSAGING MENUITEM "Toggle Zoom Control Enabled", ID_SETTINGS_ZOOM_ENABLED + MENUITEM "Delete This Profile", ID_SETTINGS_PROFILE_DELETE + MENUITEM "Toggle Launching External URI Scheme", ID_TOGGLE_LAUNCHING_EXTERNAL_URI_SCHEME_ENABLED + POPUP "Tracking Prevention Level" + BEGIN + MENUITEM "None", IDM_TRACKING_PREVENTION_LEVEL_NONE + MENUITEM "Basic", IDM_TRACKING_PREVENTION_LEVEL_BASIC + MENUITEM "Balanced", IDM_TRACKING_PREVENTION_LEVEL_BALANCED + MENUITEM "Strict", IDM_TRACKING_PREVENTION_LEVEL_STRICT + END + POPUP "Enhanced Security Mode Level" + BEGIN + MENUITEM "Off", IDM_ENHANCED_SECURITY_MODE_LEVEL_OFF + MENUITEM "Strict", IDM_ENHANCED_SECURITY_MODE_LEVEL_STRICT + END + MENUITEM "Toggle Non-Client Region Support", ID_SETTINGS_NON_CLIENT_REGION_SUPPORT_ENABLED END POPUP "&View" BEGIN @@ -225,12 +260,27 @@ BEGIN MENUITEM "Cookies", IDM_SCENARIO_CLEAR_BROWSING_DATA_COOKIES MENUITEM "Disk Cache", IDM_SCENARIO_CLEAR_BROWSING_DATA_DISK_CACHE MENUITEM "Download History", IDM_SCENARIO_CLEAR_BROWSING_DATA_DOWNLOAD_HISTORY + MENUITEM "Custom Data Partition", IDM_SCENARIO_CLEAR_CUSTOM_DATA_PARTITION END POPUP "Client Certificate Requested" BEGIN MENUITEM "Use Deferred Custom Client Certificate Selection Dialog", IDM_SCENARIO_USE_DEFERRED_CUSTOM_CLIENT_CERTIFICATE_DIALOG END MENUITEM "Cookie Management", IDM_SCENARIO_COOKIE_MANAGEMENT + MENUITEM "Cookie Management(Profile)", IDM_SCENARIO_COOKIE_MANAGEMENT_PROFILE + POPUP "Extensions Management" + BEGIN + MENUITEM "Install Default Extensions", IDM_SCENARIO_EXTENSIONS_MANAGEMENT_INSTALL_DEFAULT + MENUITEM "Offload Default Extensions", IDM_SCENARIO_EXTENSIONS_MANAGEMENT_OFFLOAD_DEFAULT + END + POPUP "WebResourceRequested" + BEGIN + MENUITEM "Custom scheme WebResourceRequested CORS", IDM_SCENARIO_CUSTOM_SCHEME + MENUITEM "Navigate to custom scheme via WebResourceRequested", IDM_SCENARIO_CUSTOM_SCHEME_NAVIGATE + MENUITEM "Service worker WebResourceRequested", IDM_SCENARIO_SERVICE_WORKER_WRR + MENUITEM "Shared worker WebResourceRequested", IDM_SCENARIO_SHARED_WORKER + END + MENUITEM "WebRTC UDP Port Configuration", IDM_SCENARIO_WEBRTC_UDP_PORT_CONFIGURATION POPUP "Custom Download Experience" BEGIN MENUITEM "Use Deferred Download Dialog", IDM_SCENARIO_USE_DEFERRED_DOWNLOAD @@ -239,6 +289,16 @@ BEGIN MENUITEM "Host Objects", IDM_SCENARIO_ADD_HOST_OBJECT MENUITEM "IFrame Device Permission", IDM_SCENARIO_IFRAME_DEVICE_PERMISSION MENUITEM "NavigateWithWebResourceRequest", IDM_SCENARIO_NAVIGATEWITHWEBRESOURCEREQUEST + MENUITEM "NotificationReceived", IDM_SCENARIO_NOTIFICATION + MENUITEM "Permission Management", IDM_PERMISSION_MANAGEMENT + POPUP "Print" + BEGIN + MENUITEM "Browser Print Preview", IDM_SCENARIO_BROWSER_PRINT_PREVIEW + MENUITEM "System Print", IDM_SCENARIO_SYSTEM_PRINT + MENUITEM "Print to default printer", IDM_SCENARIO_PRINT_TO_DEFAULT_PRINTER + MENUITEM "Print to printer", IDM_SCENARIO_PRINT_TO_PRINTER + MENUITEM "Print to Pdf Stream", IDM_SCENARIO_PRINT_TO_PDF_STREAM + END POPUP "Script Debugging" BEGIN MENUITEM "JavaScript Local File", IDM_SCENARIO_JAVA_SCRIPT @@ -246,11 +306,63 @@ BEGIN MENUITEM "JavaScript Virtual File", IDM_SCENARIO_JAVA_SCRIPT_VIRTUAL MENUITEM "TypeScript Virtual File", IDM_SCENARIO_TYPE_SCRIPT_VIRTUAL END + MENUITEM "Non-Client Region Support", IDM_SCENARIO_NON_CLIENT_REGION_SUPPORT + MENUITEM "Shared Buffer", IDM_SCENARIO_SHARED_BUFFER MENUITEM "Testing Focus", IDM_SCENARIO_TESTING_FOCUS MENUITEM "Virtual Host Mapping With Service Worker", IDM_SCENARIO_VIRTUAL_HOST_MAPPING MENUITEM "Virtual Host Mapping For Pop Up Window", IDM_SCENARIO_VIRTUAL_HOST_MAPPING_POP_UP_WINDOW MENUITEM "Web Messaging", IDM_SCENARIO_POST_WEB_MESSAGE MENUITEM "WebView Event Monitor", IDM_SCENARIO_WEB_VIEW_EVENT_MONITOR + MENUITEM "WebView Window Controls Overlay", IDM_SCENARIO_WINDOW_CONTROLS_OVERLAY + + MENUITEM "Dropped file path", IDM_SCENARIO_DROPPED_FILE_PATH + POPUP "Save As" + BEGIN + MENUITEM "Toggle Silent Save As", IDM_SCENARIO_SAVE_AS_TOGGLE_SILENT + MENUITEM "Programmatic Save As", IDM_SCENARIO_SAVE_AS_PROGRAMMATIC + END + MENUITEM "Accelerator Key Pressed", IDM_SCENARIO_ACCELERATOR_KEY_PRESSED + MENUITEM "Throttling Control", IDM_SCENARIO_THROTTLING_CONTROL + MENUITEM "Screen Capture", IDM_SCENARIO_SCREEN_CAPTURE + MENUITEM "File Type Policy", IDM_SCENARIO_FILE_TYPE_POLICY + POPUP "Service Worker" + BEGIN + MENUITEM "Listen to new Service Worker Registrations", IDM_SCENARIO_SERVICE_WORKER_REGISTRATION_REQUESTED + MENUITEM "Get Service Worker Registrations", IDM_SCENARIO_GET_SERVICE_WORKER_REGISTRATIONS + MENUITEM "Get Service Worker Registrations for the Scope", IDM_SCENARIO_GET_SERVICE_WORKER_REGISTERED_FOR_SCOPE + MENUITEM "Web Messaging", IDM_SCENARIO_SERVICE_WORKER_POST_MESSAGE + MENUITEM "Toggle Service Worker JS APIs", IDM_TOGGLE_SERVICE_WORKER_JS_API_SETTING + END + POPUP "Dedicated Worker" + BEGIN + MENUITEM "Listen to new Dedicated Worker Creations", IDM_SCENARIO_DEDICATED_WORKER + MENUITEM "Web Messaging", IDM_SCENARIO_DEDICATED_WORKER_POST_MESSAGE + END + POPUP "Shared Worker" + BEGIN + MENUITEM "Listen to new Shared Worker Creations", IDM_SCENARIO_SHARED_WORKER_MANAGER + MENUITEM "Get Shared Workers", IDM_SCENARIO_GET_SHARED_WORKERS + END + MENUITEM "Drag Drop Override", IDM_SCENARIO_DRAG_DROP_OVERRIDE + POPUP "Start Find" + BEGIN + MENUITEM "Start Find on Page Dialog", IDM_START_FIND + MENUITEM "Get Match Count", IDM_GET_MATCHES + MENUITEM "Get Active Match Index", IDM_GET_ACTIVE_MATCH_INDEX + MENUITEM "Stop Find on Page Dialog", IDM_STOP_FIND + MENUITEM "Change Find Term", IDC_FIND_TERM + MENUITEM "Toggle Highlight", IDC_SHOULD_HIGHLIGHT_ALL_MATCHES + MENUITEM "Toggle Case Sensitivity", IDC_IS_CASE_SENSITIVE + MENUITEM "Toggle Suppress Default Find Dialog", IDC_SUPPRESS_DEFAULT_FIND_DIALOG + MENUITEM "Toggle Should Match Word", IDC_SHOULD_MATCH_WHOLE_WORD + END + POPUP "Sensitivity Label" + BEGIN + MENUITEM "Set PIRM Allowlist", IDM_SCENARIO_PIRM_SET_ALLOWLIST + MENUITEM "Check PIRM Availability", IDM_SCENARIO_PIRM_CHECK_AVAILABILITY + MENUITEM "Start Sensitivity Label Test", IDM_SCENARIO_SENSITIVITY_LABEL_START_TEST + MENUITEM "Toggle Event Listener On/Off", IDM_SCENARIO_SENSITIVITY_LABEL_TOGGLE_EVENTS + END END POPUP "&Audio" BEGIN @@ -299,7 +411,7 @@ BEGIN EDITTEXT IDC_EDIT_INPUT,14,55,281,69,ES_MULTILINE | ES_AUTOHSCROLL DEFPUSHBUTTON "OK",IDOK,198,130,50,14 PUSHBUTTON "Cancel",IDCANCEL,252,130,50,14 - EDITTEXT IDC_EDIT_DESCRIPTION,14,18,281,33,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY + EDITTEXT IDC_EDIT_DESCRIPTION,14,18,281,33,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | ES_AUTOVSCROLL | WS_VSCROLL END IDD_CERTIFICATE_DIALOG DIALOGEX 0, 0, 375, 175 @@ -326,9 +438,46 @@ BEGIN EDITTEXT IDC_EDIT_PROFILE,62,18,96,18,ES_AUTOHSCROLL LTEXT "Download path:",IDC_STATIC,25,40,36,18 EDITTEXT IDC_EDIT_DOWNLOAD_PATH,62,42,96,18,ES_AUTOHSCROLL - CONTROL " InPrivate",IDC_CHECK_INPRIVATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,61,74,16 + CONTROL " InPrivate",IDC_CHECK_INPRIVATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,84,74,16 LTEXT "Only allow alphabet characters (a-z, A-Z), digit characters (0-9) and '#', '@', '$', '(', ')', '+', '-', '_', '~', '.', ' ' (space).",IDC_STATIC,160,14,138,37 + LTEXT "Locale Region:",IDC_STATIC,25,61,36,18 + EDITTEXT IDC_EDIT_LOCALE,62,63,96,18,ES_AUTOHSCROLL + CONTROL " UseOSRegion",IDC_CHECK_USE_OS_REGION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,106,74,16 END + +IDD_SET_PERMISSION DIALOGEX 0, 0, 200, 130 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,15,110,50,14 + PUSHBUTTON "Cancel",IDCANCEL,75,110,50,14 + GROUPBOX "Set Permission",IDC_STATIC,7,3,190,100 + LTEXT "Origin:",IDC_STATIC,25,22,36,12 + EDITTEXT IDC_EDIT_PERMISSION_ORIGIN,62,22,105,12,ES_AUTOHSCROLL + LTEXT "Permission Kind:",IDC_STATIC,25,40,36,18 + COMBOBOX IDC_PERMISSION_KIND,62,42,105,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Permission State:",IDC_STATIC,25,61,36,18 + COMBOBOX IDC_PERMISSION_STATE,62,62,105,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +END + +IDD_SAVE_CONTENT_AS DIALOGEX 0, 0, 300, 180 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Save As Silent Demo" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK", IDOK, 25, 160, 50, 15 + PUSHBUTTON "Cancel", IDCANCEL, 225, 160, 50, 15 + GROUPBOX "Full path", IDC_STATIC, 10, 5, 280, 75 + LTEXT "Directory:", IDC_STATIC, 15, 20, 36, 12 + EDITTEXT IDC_EDIT_SAVE_AS_DIRECTORY, 15, 30, 265, 15, ES_AUTOHSCROLL + LTEXT "Filename:", IDC_STATIC, 15, 45, 36, 12 + EDITTEXT IDC_EDIT_SAVE_AS_FILENAME, 15, 55, 265, 15, ES_AUTOHSCROLL + CONTROL "Allow Replace Old File", IDC_CHECK_SAVE_AS_ALLOW_REPLACE, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 20, 90, 150, 15 + LTEXT "Save As Type Selection:", IDC_STATIC, 20, 110, 100, 15 + COMBOBOX IDC_SAVE_AS_KIND, 120, 110, 100, 50, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +END + ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO diff --git a/SampleApps/WebView2APISample/WebView2APISample.vcxproj b/SampleApps/WebView2APISample/WebView2APISample.vcxproj index f8c160f1..346a2deb 100644 --- a/SampleApps/WebView2APISample/WebView2APISample.vcxproj +++ b/SampleApps/WebView2APISample/WebView2APISample.vcxproj @@ -1,552 +1,546 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - Debug - ARM64 - - - Release - ARM64 - - - Win7 Debug - ARM64 - - - Win7 Debug - Win32 - - - Win7 Debug - x64 - - - Win7 Release - ARM64 - - - Win7 Release - Win32 - - - Win7 Release - x64 - - - - 15.0 - {4F0CEEF3-12B3-425E-9BB0-105200411592} - Win32Proj - 10.0 - - - - Application - true - v142 - Unicode - - - Application - true - v142 - Unicode - - - Application - false - v142 - Unicode - - - Application - false - v142 - Unicode - - - Application - true - v142 - Unicode - - - Application - true - v142 - Unicode - - - Application - false - v142 - Unicode - - - Application - false - v142 - Unicode - - - Application - true - v142 - Unicode - - - Application - true - v142 - Unicode - - - Application - false - v142 - Unicode - - - Application - false - v142 - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - $(ProjectDir)$(Configuration)\$(Platform)\ - $(Platform)\$(Configuration)\ - $(ProjectName) - - - true - $(ProjectDir)$(Configuration)\$(Platform)\ - $(Platform)\$(Configuration)\ - $(ProjectName)_Win7 - - - true - $(ProjectDir)$(Configuration)\$(Platform)\ - $(Platform)\$(Configuration)\ - - - true - $(ProjectDir)$(Configuration)\$(Platform)\ - $(Platform)\$(Configuration)\ - $(ProjectName)_Win7 - - - $(ProjectDir)$(Configuration)\$(Platform)\ - $(ProjectName) - - - $(ProjectDir)$(Configuration)\$(Platform)\ - $(ProjectName)_Win7 - - - $(ProjectDir)$(Configuration)\$(Platform)\ - - - $(ProjectDir)$(Configuration)\$(Platform)\ - $(ProjectName)_Win7 - - - $(ProjectDir)$(Configuration)\$(Platform)\ - $(ProjectName) - - - $(ProjectDir)$(Configuration)\$(Platform)\ - $(ProjectName)_Win7 - - - $(ProjectDir)$(Configuration)\$(Platform)\ - - - $(ProjectDir)$(Configuration)\$(Platform)\ - $(ProjectName)_Win7 - - - - USE_WEBVIEW2_WIN10;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) - MultiThreadedDebug - Level3 - ProgramDatabase - Disabled - stdcpp17 - - - MachineX86 - true - Windows - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;%(AdditionalDependencies) - onecoreuap.lib %(AdditionalOptions) - false - false - - - - - WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) - MultiThreadedDebug - Level3 - ProgramDatabase - Disabled - stdcpp17 - - - MachineX86 - true - Windows - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;%(AdditionalDependencies) - onecoreuap.lib %(AdditionalOptions) - - - - - USE_WEBVIEW2_WIN10;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) - MultiThreaded - Level3 - ProgramDatabase - stdcpp17 - - - MachineX86 - true - Windows - false - false - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;%(AdditionalDependencies) - onecoreuap.lib %(AdditionalOptions) - - - - - WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) - MultiThreaded - Level3 - ProgramDatabase - stdcpp17 - - - MachineX86 - true - Windows - true - true - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;%(AdditionalDependencies) - onecoreuap.lib %(AdditionalOptions) - - - - - MultiThreadedDebug - stdcpp17 - USE_WEBVIEW2_WIN10;_UNICODE;UNICODE;%(PreprocessorDefinitions) - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;%(AdditionalDependencies) - onecoreuap.lib %(AdditionalOptions) - - - - - MultiThreadedDebug - stdcpp17 - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;%(AdditionalDependencies) - onecoreuap.lib %(AdditionalOptions) - - - - - MultiThreaded - stdcpp17 - USE_WEBVIEW2_WIN10;_UNICODE;UNICODE;%(PreprocessorDefinitions) - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;%(AdditionalDependencies) - - - onecoreuap.lib %(AdditionalOptions) - - - - - MultiThreaded - stdcpp17 - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;%(AdditionalDependencies) - - - onecoreuap.lib %(AdditionalOptions) - - - - - MultiThreadedDebug - stdcpp17 - USE_WEBVIEW2_WIN10;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;%(AdditionalDependencies) - onecoreuap.lib %(AdditionalOptions) - - - - - MultiThreadedDebug - stdcpp17 - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;%(AdditionalDependencies) - onecoreuap.lib %(AdditionalOptions) - - - - - MultiThreaded - stdcpp17 - USE_WEBVIEW2_WIN10;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;%(AdditionalDependencies) - onecoreuap.lib %(AdditionalOptions) - - - - - MultiThreaded - stdcpp17 - - - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;%(AdditionalDependencies) - onecoreuap.lib %(AdditionalOptions) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - Create - Create - Create - Create - Create - Create - - - - - - - - - - - - - - - - - $(OutDir)\assets - - - $(OutDir)\assets - - - $(OutDir)\assets - - - $(OutDir)\assets - - - - $(OutDir)\assets - - - $(OutDir)\assets - - - $(OutDir)\assets - - - $(OutDir)\assets - - - $(OutDir)\assets - - - $(OutDir)\assets - - - $(OutDir)\assets - - - $(OutDir)\assets - - - $(OutDir)\assets - - - $(OutDir)\assets - - - $(OutDir)\assets - - - $(OutDir)\assets - - - $(OutDir)\assets - - - $(OutDir)\assets - - - - - - - - - - - - - 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}. - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + Debug + ARM64 + + + Release + ARM64 + + + + 15.0 + {4F0CEEF3-12B3-425E-9BB0-105200411592} + Win32Proj + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)$(Configuration)\$(Platform)\ + $(Platform)\$(Configuration)\ + $(ProjectName) + + + true + $(ProjectDir)$(Configuration)\$(Platform)\ + $(Platform)\$(Configuration)\ + + + $(ProjectDir)$(Configuration)\$(Platform)\ + $(ProjectName) + + + $(ProjectDir)$(Configuration)\$(Platform)\ + + + $(ProjectDir)$(Configuration)\$(Platform)\ + $(ProjectName) + + + $(ProjectDir)$(Configuration)\$(Platform)\ + + + + USE_WEBVIEW2_WIN10;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreadedDebug + Level3 + ProgramDatabase + Disabled + stdcpp17 + true + + + MachineX86 + true + Windows + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;Gdiplus.lib;%(AdditionalDependencies) + onecoreuap.lib %(AdditionalOptions) + false + false + + + + + USE_WEBVIEW2_WIN10;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + Level3 + ProgramDatabase + stdcpp17 + true + + + MachineX86 + true + Windows + false + false + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;Gdiplus.lib;%(AdditionalDependencies) + onecoreuap.lib %(AdditionalOptions) + + + + + MultiThreadedDebug + stdcpp17 + USE_WEBVIEW2_WIN10;_UNICODE;UNICODE;%(PreprocessorDefinitions) + true + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;Gdiplus.lib;%(AdditionalDependencies) + onecoreuap.lib %(AdditionalOptions) + + + + + MultiThreaded + stdcpp17 + USE_WEBVIEW2_WIN10;_UNICODE;UNICODE;%(PreprocessorDefinitions) + true + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;Gdiplus.lib;%(AdditionalDependencies) + + + onecoreuap.lib %(AdditionalOptions) + + + + + MultiThreadedDebug + stdcpp17 + USE_WEBVIEW2_WIN10;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + true + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;Gdiplus.lib;%(AdditionalDependencies) + onecoreuap.lib %(AdditionalOptions) + + + + + MultiThreaded + stdcpp17 + USE_WEBVIEW2_WIN10;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions) + true + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;shlwapi.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;Gdiplus.lib;%(AdditionalDependencies) + onecoreuap.lib %(AdditionalOptions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + + + + + + + + + + + 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}. + + + + + diff --git a/SampleApps/WebView2APISample/WebView2APISample.vcxproj.filters b/SampleApps/WebView2APISample/WebView2APISample.vcxproj.filters index 311aa759..4a6e5982 100644 --- a/SampleApps/WebView2APISample/WebView2APISample.vcxproj.filters +++ b/SampleApps/WebView2APISample/WebView2APISample.vcxproj.filters @@ -1,274 +1,327 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav - - - {83ecc4d0-229e-46e9-9d96-6a1aa28be262} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Source Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - - - - - - - - - - - - - - - - - - - - - Resource Files - - - - - - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - - - Source Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {83ecc4d0-229e-46e9-9d96-6a1aa28be262} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Source Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + + + + + + + + + + + + + + + + + + + + Resource Files + + + + + + + + + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + + + Source Files + + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/AppStartPage.html b/SampleApps/WebView2APISample/assets/AppStartPage.html index 357d4ad2..067b0d59 100644 --- a/SampleApps/WebView2APISample/assets/AppStartPage.html +++ b/SampleApps/WebView2APISample/assets/AppStartPage.html @@ -1,156 +1,213 @@  - + + Microsoft Edge WebView2 - -
-

Microsoft Edge WebView2

-
- -
-
-
-
SDK build
...
-
Runtime version
...
-
App path
...
-
Runtime path
...
-
-
-
- -
-
-

Issues

-
- New issue -
+ +
+
+
Microsoft Edge WebView2
+ Welcome to the WebView2 API sample app! + +
+
+ WebView2 logo +
- -
-
-

Documentation

-
- WebView2 documentation -
-
- -
-
-

SDK releases

-
    -
-
-
- - - -
-
-

Release Notes

- -
+
+
+

SDK Information

+
+
SDK build
+
...
+
Runtime version
+
...
+
App path
+
...
+
Runtime path
+
...
+
+
+ +
+

GitHub Issues

+
+ + +
+ + + View Community Discussions + + +

Documentation

+
+ + +
+
+ + + +
+

Downloads

+ +
+ +
+

Release Notes

+ +
- + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/AppStartPage.js b/SampleApps/WebView2APISample/assets/AppStartPage.js index ff5b7a23..fe8fb0f8 100644 --- a/SampleApps/WebView2APISample/assets/AppStartPage.js +++ b/SampleApps/WebView2APISample/assets/AppStartPage.js @@ -1,56 +1,62 @@ (async function () { async function uriToObject(uri) { - const responseFromFetch = await fetch(uri); - const responseAsText = await responseFromFetch.text(); - const response = JSON.parse(responseAsText); - return response; + const responseFromFetch = await fetch(uri); + const responseAsText = await responseFromFetch.text(); + const response = JSON.parse(responseAsText); + return response; } function parseQuery(query) { - if (query.startsWith("?")) { - query = query.substring(1); - } - - return query. - split("&"). - map(encodedNameValueStr => encodedNameValueStr.split("=")). - reduce((resultObject, encodedNameValueArr) => { - const nameValueArr = encodedNameValueArr.map(decodeURIComponent); - resultObject[nameValueArr[0]] = nameValueArr[1]; - return resultObject; - }, {}); + if (query.startsWith("?")) { + query = query.substring(1); + } + + return query. + split("&"). + map(encodedNameValueStr => encodedNameValueStr.split("=")). + reduce((resultObject, encodedNameValueArr) => { + const nameValueArr = encodedNameValueArr.map(decodeURIComponent); + resultObject[nameValueArr[0]] = nameValueArr[1]; + return resultObject; + }, {}); } const sdkReleasesNode = document.getElementById("sdkReleases"); + if (sdkReleasesNode) { - const nugetInfoUri = "https://azuresearch-usnc.nuget.org/query?q=PackageID%3aMicrosoft.Web.WebView2&prerelease=true&semVerLevel=2.0.0"; - const nugetInfo = await uriToObject(nugetInfoUri); - - let versions = nugetInfo.data[0].versions; - versions.reverse(); - versions.forEach(version => { - const versionText = version.version; - const aNode = document.createElement("a"); - aNode.href = "https://www.nuget.org/packages/Microsoft.Web.WebView2/" + versionText; - aNode.textContent = "WebView2 SDK " + versionText; - - const itemNode = document.createElement("li"); - itemNode.appendChild(aNode); - - sdkReleasesNode.appendChild(itemNode); - }); + + const nugetInfoUri = "https://azuresearch-usnc.nuget.org/query?q=PackageID%3aMicrosoft.Web.WebView2&prerelease=true&semVerLevel=2.0.0"; + const nugetInfo = await uriToObject(nugetInfoUri); + + let versions = nugetInfo.data[0].versions; + + versions.reverse(); + + versions = versions.slice(0, 5); + + versions.forEach(version => { + const versionText = version.version; + const aNode = document.createElement("a"); + aNode.href = "https://www.nuget.org/packages/Microsoft.Web.WebView2/" + versionText; + aNode.textContent = "WebView2 SDK " + versionText; + + const itemNode = document.createElement("li"); + itemNode.appendChild(aNode); + + sdkReleasesNode.appendChild(itemNode); + }); } const query = parseQuery(location.search); const fillIds = ["sdkBuild", "runtimeVersion", "appPath", "runtimePath"]; fillIds.forEach(id => { - let content = query[id]; - if (content) { - const maxContentLength = 100; - if (content.length > maxContentLength) { - content = "..." + content.substring(content.length - maxContentLength); + let content = query[id]; + if (content) { + const maxContentLength = 100; + if (content.length > maxContentLength) { + content = "..." + content.substring(content.length - maxContentLength); + } + document.getElementById(id).textContent = content; } - document.getElementById(id).textContent = content; - } }) })(); \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/DemoWorker.js b/SampleApps/WebView2APISample/assets/DemoWorker.js new file mode 100644 index 00000000..e9c6a3e3 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/DemoWorker.js @@ -0,0 +1,8 @@ +onconnect = function (e) { + var port = e.ports[0]; + + port.onmessage = function (e) { + var workerResult = 'Local script result: ' + e.data[0] + " * " + e.data[1] + " = " + (e.data[0] * e.data[1]); + port.postMessage(workerResult); + } +} diff --git a/SampleApps/WebView2APISample/assets/LandingPageForFindDemo.html b/SampleApps/WebView2APISample/assets/LandingPageForFindDemo.html new file mode 100644 index 00000000..121420bf --- /dev/null +++ b/SampleApps/WebView2APISample/assets/LandingPageForFindDemo.html @@ -0,0 +1,70 @@ + + + + + Demo: Programmatic Find API + + + + +
+

Programmatic Find API Demo

+
+ +

Introduction

+

Welcome to this demo showcasing the capabilities of the Programmatic Find API with WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 WebView2 . We have designed this feature to make it easier for developers to programmatically access and utilize WebView2's finding capabilities.

+ +

Why Programmatic Find API?

+

Programmatic Find API offers a way to embed WebView2's finding functionality directly into your applications. This enhances the overall user experience by allowing for customized behavior and extended functionalities.

+ +

Features

+
    +
  • Programmatic Access
  • +
  • Automated Testing Support
  • +
  • Real-time Results with WebView2
  • +
  • Enhanced Customization
  • +
+ +

Use Cases

+

Some common use cases include text highlighting, real-time search features, and quality assurance testing. This ensures that applications built with WebView2 can offer a more dynamic and interactive experience.

+ +

Technical Aspects

+

The API is designed to be platform-agnostic, allowing developers to implement WebView2-based functionalities across a variety of platforms. It is also built to be backward-compatible, ensuring a smooth transition for applications relying on older versions of WebView2.

+ +

Conclusion

+

We hope this demo helps you understand the advantages of using the Programmatic Find API in your WebView2-based applications. The aim is to make your development process smoother while enhancing the user experience.

+ +

FAQs

+
    +
  1. Is this feature limited to any specific programming languages?
  2. +
  3. How can I customize the search experience in WebView2?
  4. +
  5. What platforms currently support this WebView2 feature?
  6. +
+ +
+

For more information, please visit the official WebView2 documentation. https://learn.microsoft.com/en-us/microsoft-edge/webview2/?form=MA13LH

+
+ + + diff --git a/SampleApps/WebView2APISample/assets/ScenarioAcceleratorKeyPressed.html b/SampleApps/WebView2APISample/assets/ScenarioAcceleratorKeyPressed.html new file mode 100644 index 00000000..1b848b88 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioAcceleratorKeyPressed.html @@ -0,0 +1,24 @@ + + + + ScenarioAcceleratorKeyPressed + + + + +

Disable all Browser Accelerator keys but F7 remains enabled

+ + + +

Enable all Browser Accelerator keys but Ctrl + P remains disabled

+ + + + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/ScenarioAddHostObject.html b/SampleApps/WebView2APISample/assets/ScenarioAddHostObject.html index 52602cf8..be89318d 100644 --- a/SampleApps/WebView2APISample/assets/ScenarioAddHostObject.html +++ b/SampleApps/WebView2APISample/assets/ScenarioAddHostObject.html @@ -1,164 +1,221 @@ + - AddHostObjectToScript Sample + AddHostObjectToScript Sample + -

AddHostObjectToScript Sample

-

The following buttons interact with the chrome.webview.hostObjects.sample object. Open DevTools console to try running whatever code you like on this object.

-

Get Property

- - -
- - - -
- -

Set Property

- - -
- - - -
- - - -
- -

Indexed Property

- - -
- - - -
- -

Invoke Method

- - -
- - - -
- -

Invoke Callback

- - -
- -

Date Objects

- - -
- - -
- - - - +

AddHostObjectToScript Sample

+

The following buttons interact with the chrome.webview.hostObjects.sample object. Open DevTools + console to try running whatever code you like on this object.

+

Get Property

+ + +
+ + + +
+ +

Set Property

+ + +
+ + + +
+ + + +
+ +

Indexed Property

+ + +
+ + + +
+ +

Invoke Method

+ + +
+ + + +
+ +

Invoke Callback

+ + +
+ +

Date Objects

+ + +
+ + +
+ + + +
+

IFrame

+
+ + + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/ScenarioCustomScheme.html b/SampleApps/WebView2APISample/assets/ScenarioCustomScheme.html new file mode 100644 index 00000000..910c46fe --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioCustomScheme.html @@ -0,0 +1,18 @@ + + + + Handling custom schemes + + +
These resources are loaded via a URL with custom scheme that has an authority component:
+ + +
+ +

+ +

+ +
+ + diff --git a/SampleApps/WebView2APISample/assets/ScenarioCustomScheme.json b/SampleApps/WebView2APISample/assets/ScenarioCustomScheme.json new file mode 100644 index 00000000..9279d19d --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioCustomScheme.json @@ -0,0 +1 @@ +{ "success": true } \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/ScenarioDedicatedWorkerPostMessage.html b/SampleApps/WebView2APISample/assets/ScenarioDedicatedWorkerPostMessage.html new file mode 100644 index 00000000..6f2a664d --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioDedicatedWorkerPostMessage.html @@ -0,0 +1,43 @@ + + + + + ScenarioDedicatedWorkerPostMessage + + + + +
+

DedicatedWorker PostMessage Sample Page

+

This page demonstrates basic interaction between the host app and dedicated workers + by means of Web Messages.

+
+ +

Posting and receiving messages

+

Messages can be posted from the host app to the dedicated worker on this document using + the APIs ICoreWebView2DedicatedWorker::PostWebMessageAsJson and + ICoreWebView2DedicatedWorker::PostWebMessageAsString. +

+ +

Messages can be posted from the dedicated worker to the host app using + self.chrome.webview.postMessage. The host app can receive messages by + registering an event handler with + ICoreWebView2DedicatedWorker::add_WebMessageReceived. +

+ +

How to use the sample?

+

This document creates a dedicated worker that listens for messages from the host app in + the form of a command (ADD, SUB, MUL, DIV) and two numbers (first and second). It + performs the specified arithmetic operation and responds with the result." +

+

When the dedicated worker is created, a dialog will be opened to enter a message. Enter a + JSON string with a command and two numbers to receive a response from the worker. Ex: + {"command":"ADD","first":2,"second":3} will send a reply back with 5. +

+ + + + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/ScenarioDragDrop.html b/SampleApps/WebView2APISample/assets/ScenarioDragDrop.html new file mode 100644 index 00000000..a6ea7673 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioDragDrop.html @@ -0,0 +1,67 @@ + + + + ScenarioDOMContentLoaded + + + +
+
+ + +
+
+

+
+
+ +
+
+ + + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/ScenarioDragDropOverride.html b/SampleApps/WebView2APISample/assets/ScenarioDragDropOverride.html new file mode 100644 index 00000000..383c6afc --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioDragDropOverride.html @@ -0,0 +1,108 @@ + + + + + Scenario Drag Drop Override + + + + +

Scenario Drag Drop Override

+

+ This scenario demonstrates the ability to override drag drop behavior using the DragStarting Event. + Apps that handle the DragStarting event will be notified when drag is starting in the WebView2 and + can employ their own drag drop logic to override WebView2's. In the sample app, the override drag + experience will look no different from the default drag experience. By default, this webpage will use + the WebView2 default drag drop. +

+
+
+
+
+
+ + + +
+ + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/ScenarioFileSystemHandleShare.html b/SampleApps/WebView2APISample/assets/ScenarioFileSystemHandleShare.html new file mode 100644 index 00000000..2e776bd6 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioFileSystemHandleShare.html @@ -0,0 +1,94 @@ + + + + + + + + +

File System Explorer

+ +
+
    +
    + + + + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/ScenarioNonClientRegionSupport.html b/SampleApps/WebView2APISample/assets/ScenarioNonClientRegionSupport.html new file mode 100644 index 00000000..95aa7a58 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioNonClientRegionSupport.html @@ -0,0 +1,86 @@ + + + + ScenarioNonClientRegionSupport + + + +

    Non-Client Region Support

    +
    +

    Draggable Region

    +
    +

    + Note: This site will always have non-client region support enabled. + Upon navigating away from this site, non-client region support will be disabled. +

    + +

    Interactive Elements

    +

    + This shows how app-region drag can work with interactive elements +

    + + +

    Click counter: 0

    + + + + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/ScenarioNotificationReceived.html b/SampleApps/WebView2APISample/assets/ScenarioNotificationReceived.html new file mode 100644 index 00000000..4e9eff6b --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioNotificationReceived.html @@ -0,0 +1,83 @@ + + + + ScenarioNotificationReceived + + +

    Notification Test Page

    + + +

    Notification log

    +
    + + + diff --git a/SampleApps/WebView2APISample/assets/ScenarioPermissionManagement.html b/SampleApps/WebView2APISample/assets/ScenarioPermissionManagement.html new file mode 100644 index 00000000..ff4944a4 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioPermissionManagement.html @@ -0,0 +1,39 @@ + + + + ScenarioPermissionManagement + + +

    Permission Manager

    +

    All Permissions

    +
      + + + + diff --git a/SampleApps/WebView2APISample/assets/ScenarioScreenCapture.html b/SampleApps/WebView2APISample/assets/ScenarioScreenCapture.html new file mode 100644 index 00000000..f094b526 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioScreenCapture.html @@ -0,0 +1,43 @@ + + + + ScenarioScreenCapture + + +

      ScenarioScreenCapture Sample Page

      +

      Screen Capture Test From Main Frame

      + + +
      + + + + + + + diff --git a/SampleApps/WebView2APISample/assets/ScenarioScreenCaptureIFrame1.html b/SampleApps/WebView2APISample/assets/ScenarioScreenCaptureIFrame1.html new file mode 100644 index 00000000..6d6ce82f --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioScreenCaptureIFrame1.html @@ -0,0 +1,32 @@ + + + + ScenarioScreenCaptureIFrame1 + + +

      Screen Capture Test From Top Level IFrame1

      + + +
      + + + + diff --git a/SampleApps/WebView2APISample/assets/ScenarioScreenCaptureIFrame2.html b/SampleApps/WebView2APISample/assets/ScenarioScreenCaptureIFrame2.html new file mode 100644 index 00000000..0d901e5a --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioScreenCaptureIFrame2.html @@ -0,0 +1,32 @@ + + + + ScenarioScreenCaptureIFrame2 + + +

      Screen Capture Test From Top Level IFrame2

      + + +
      + + + + diff --git a/SampleApps/WebView2APISample/assets/ScenarioSensitivityLabelChanged.html b/SampleApps/WebView2APISample/assets/ScenarioSensitivityLabelChanged.html new file mode 100644 index 00000000..60c5eb04 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioSensitivityLabelChanged.html @@ -0,0 +1,72 @@ + + + + + Sensitivity Label API Sample + + + +
      +

      Sensitivity Label API Sample

      + + +
      +

      About This Sample

      +

      This sample demonstrates how to use the PageInteractionRestrictionManager API to add and remove sensitivity labels, which triggers the SensitivityInfoChanged event in WebView2.

      +
      + + +
      +

      API Status

      +

      Checking PageInteractionRestrictionManager availability...

      +
      + + +
      +

      Add Sensitivity Label

      + + + + + + + +
      + + +
      +

      Remove Sensitivity Label

      + + + + +
      + + +
      +

      Last Operation Status

      +

      +
      + + +
      +

      API Usage

      +
      +// Add a sensitivity label
      +const labelManager = await navigator.pageInteractionRestrictionManager.requestLabelManager();
      +const label = await labelManager.addLabel('MicrosoftSensitivityLabel', {
      +    label: 'your-label-guid',
      +    organization: 'your-org-guid'
      +});
      +
      +// Remove a sensitivity label
      +await label.remove();
      +            
      +
      +
      + + + + diff --git a/SampleApps/WebView2APISample/assets/ScenarioSensitivityLabelChanged.js b/SampleApps/WebView2APISample/assets/ScenarioSensitivityLabelChanged.js new file mode 100644 index 00000000..3b1beca8 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioSensitivityLabelChanged.js @@ -0,0 +1,164 @@ +// Sensitivity Label API Sample +// This sample demonstrates how to use the PageInteractionRestrictionManager API +// to add and remove sensitivity labels in WebView2 + +// Element ID constants +const ELEMENT_IDS = { + OUTPUT: 'output', + LABEL_ID: 'labelId', + ORG_ID: 'orgId', + LABEL_SELECT: 'labelSelect', + PIRM_STATUS: 'pirmStatus', + PIRM_STATUS_TEXT: 'pirmStatusText' +}; + +let labelMap = new Map(); // Store label objects for removal + +function log(message, is_error = false) { + const output = document.getElementById(ELEMENT_IDS.OUTPUT); + + // Simply update the text content and color + output.textContent = message; + output.style.color = is_error ? 'red' : ''; + + console.log(message); +} + +async function addLabel() { + const labelId = document.getElementById(ELEMENT_IDS.LABEL_ID).value.trim(); + const orgId = document.getElementById(ELEMENT_IDS.ORG_ID).value.trim(); + + if (!labelId || !orgId) { + log('Error: Please enter both Label ID and Organization ID', true /* is_error */); + return; + } + + if (labelMap.has(labelId)) { + log(`Error: Label ${labelId} already exists`, true /* is_error */); + return; + } + + try { + log(`Adding sensitivity label: ${labelId}`); + + // Request label manager from PageInteractionRestrictionManager API + const labelManager = await navigator.pageInteractionRestrictionManager.requestLabelManager(); + + // Add the sensitivity label + const label = await labelManager.addLabel('MicrosoftSensitivityLabel', { + label: labelId, + organization: orgId + }); + + // Store label object for removal later + labelMap.set(labelId, label); + + log(`Success: Added sensitivity label ${labelId}`); + addLabelToDropdown(labelId); + clearInputs(); + + } catch (error) { + log(`Error adding label: ${error.message}`, true /* is_error */); + } +} + +async function removeLabel() { + const selectedLabelId = document.getElementById(ELEMENT_IDS.LABEL_SELECT).value; + + const labelObject = labelMap.get(selectedLabelId); + if (!labelObject) { + log('Error: Label object not found', true /* is_error */); + return; + } + + try { + log(`Removing sensitivity label: ${selectedLabelId}`); + + // Remove the sensitivity label + await labelObject.remove(); + + // Remove from our map + labelMap.delete(selectedLabelId); + + log(`Success: Removed sensitivity label ${selectedLabelId}`); + removeLabelFromDropdown(selectedLabelId); + + } catch (error) { + log(`Error removing label: ${error.message}`, true /* is_error */); + } +} + +function addLabelToDropdown(labelId) { + const select = document.getElementById(ELEMENT_IDS.LABEL_SELECT); + + // If this is the first label, clear the "No labels available" option + if (select.options.length === 1 && select.options[0].value === '') { + select.options[0].textContent = 'Select a label to remove'; + } + + // Add the newly added label + const option = document.createElement('option'); + option.value = labelId; + option.textContent = labelId; + + select.appendChild(option); +} + +function removeLabelFromDropdown(labelId) { + const select = document.getElementById(ELEMENT_IDS.LABEL_SELECT); + const options = select.options; + + for (let i = 0; i < options.length; i++) { + if (options[i].value === labelId) { + select.removeChild(options[i]); + break; + } + } + + // If no labels left, add "No labels available" option + if (select.options.length === 1 && select.options[0].value === '') { + select.options[0].textContent = 'No labels available'; + } +} + +function clearInputs() { + document.getElementById(ELEMENT_IDS.LABEL_ID).value = ''; + document.getElementById(ELEMENT_IDS.ORG_ID).value = ''; +} + +function checkPirmAvailability() { + const statusBox = document.getElementById(ELEMENT_IDS.PIRM_STATUS); + const statusText = document.getElementById(ELEMENT_IDS.PIRM_STATUS_TEXT); + + try { + const isAvailable = typeof navigator.pageInteractionRestrictionManager !== 'undefined' && + navigator.pageInteractionRestrictionManager !== null; + + if (isAvailable) { + statusBox.className = 'status-box available'; + statusText.textContent = '✅ PageInteractionRestrictionManager API is available and ready to use!'; + log('PIRM API available'); + } else { + statusBox.className = 'status-box unavailable'; + statusText.textContent = '❌ PageInteractionRestrictionManager API is not available. Please check if the feature is enabled and the URL is added to the allowlist.'; + log('PIRM API not available'); + } + } catch (error) { + statusBox.className = 'status-box unavailable'; + statusText.textContent = '❌ Error checking API availability: ' + error.message; + log('Error checking PIRM availability: ' + error.message, true /* is_error */); + } +} + +// Initialize with sample values +document.addEventListener('DOMContentLoaded', function() { + // Set initial status + const statusBox = document.getElementById(ELEMENT_IDS.PIRM_STATUS); + statusBox.className = 'status-box checking'; + + document.getElementById(ELEMENT_IDS.LABEL_ID).value = '12345678-1234-1234-1234-123456789abc'; + document.getElementById(ELEMENT_IDS.ORG_ID).value = '87654321-4321-4321-4321-cba987654321'; + + log('Sensitivity Label API sample loaded'); + checkPirmAvailability(); +}); diff --git a/SampleApps/WebView2APISample/assets/ScenarioServiceWorkerSyncRegistrationManager.html b/SampleApps/WebView2APISample/assets/ScenarioServiceWorkerSyncRegistrationManager.html new file mode 100644 index 00000000..00aa0959 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioServiceWorkerSyncRegistrationManager.html @@ -0,0 +1,151 @@ + + + + ScenarioServiceWorkerSyncRegistrationManager + + + +

      Periodic Background Sync Example

      +

      Registrations

      +

      +
      + + + +
      + +
      + + +
      + +
      + + +
      + +
      + +
      +
      + +

      Background Sync Example

      +

      Registrations

      +

      +
      + + +
      + +
      + + +
      +
      + +
      + + + + diff --git a/SampleApps/WebView2APISample/assets/ScenarioServiceWorkerSyncRegistrationManagerServiceWorker.js b/SampleApps/WebView2APISample/assets/ScenarioServiceWorkerSyncRegistrationManagerServiceWorker.js new file mode 100644 index 00000000..4e5fbb2c --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioServiceWorkerSyncRegistrationManagerServiceWorker.js @@ -0,0 +1,12 @@ +function fetchAndCacheLatestNews() { + console.log("Fetched news from a server"); + } + + self.addEventListener("periodicsync", (event) => { + console.log("Periodic Sync Task Tag: " + event.tag + " executed"); + event.waitUntil(fetchAndCacheLatestNews()); + }); + + self.addEventListener("sync", (event) => { + console.log("Background Sync Task Tag: " + event.tag + " executed"); + }); \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/ScenarioSharedBuffer.html b/SampleApps/WebView2APISample/assets/ScenarioSharedBuffer.html new file mode 100644 index 00000000..f1c941f6 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioSharedBuffer.html @@ -0,0 +1,123 @@ + + + + ScenarioSharedBuffer + + + + + +

      Shared Buffer Data

      +
      +
      +
      +
      +
      +
      +
      + +
      + + + + diff --git a/SampleApps/WebView2APISample/assets/ScenarioThrottlingControl.html b/SampleApps/WebView2APISample/assets/ScenarioThrottlingControl.html new file mode 100644 index 00000000..70345bf2 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioThrottlingControl.html @@ -0,0 +1,15 @@ + + + Throttling Control + + + + +

      main

      +
      + + +
      + + + diff --git a/SampleApps/WebView2APISample/assets/ScenarioThrottlingControl.js b/SampleApps/WebView2APISample/assets/ScenarioThrottlingControl.js new file mode 100644 index 00000000..36440131 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioThrottlingControl.js @@ -0,0 +1,77 @@ +// target number of iterations +const limitIterations = false; +const iterations = 20; + +// steps per iteration +const steps = 80; +const target = steps + 1; + +// global state +let iteration = 0; +let counter = 0; +let first = performance.now(); +let timerId = undefined; + +const frameId = document.querySelector('meta[name="frame-title"]').content; +const logger = (frameId == 'main') ? window.open('/ScenarioThrottlingControlMonitor.html') : window.parent; + +const timerCallback = () => { + if (++counter == 1) { + first = performance.now(); + } + + // compute average timer delay only after target steps + if (counter == target) { + let end = performance.now(); + let avg = (end - first) / steps; + onIterationCompleted(avg); + } +} + +function reportAverageDelay(delay) { + console.log(`[${frameId}] avg: ${delay} ms`); + let message = { + "frameId": frameId, + "delayAvg": delay + }; + logger.postMessage(message); +} + +function onIterationCompleted(delayAvg) { + counter = 0; + + if (++iteration == iterations && limitIterations) { + clearInterval(timerId); + timerId = undefined; + } + + reportAverageDelay(delayAvg); +} + +document.addEventListener("visibilitychange", () => { + let message = { + "frameId": frameId, + "visibilityUpdate": document.visibilityState + }; + logger.postMessage(message); +}); + +window.addEventListener('message', (event) => { + console.log(`[${frameId}] got message: ${event.data}`); + + if (event.data == 'init') { + // init timer/state + counter = 0; + start = performance.now(); + timerId = setInterval(timerCallback, 0); + + // fwd to embedded frames + if (frameId == 'main') { + document.getElementById('trusted').contentWindow.postMessage(event.data); + document.getElementById('untrusted').contentWindow.postMessage(event.data); + } + } else if (frameId == 'main') { + // log from embedded frame, fwd to popup + logger.postMessage(event.data); + } +}); diff --git a/SampleApps/WebView2APISample/assets/ScenarioThrottlingControl1PP.html b/SampleApps/WebView2APISample/assets/ScenarioThrottlingControl1PP.html new file mode 100644 index 00000000..029a30d9 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioThrottlingControl1PP.html @@ -0,0 +1,11 @@ + + + 1PP Frame + + + + +

      trusted

      + + + diff --git a/SampleApps/WebView2APISample/assets/ScenarioThrottlingControl3PP.html b/SampleApps/WebView2APISample/assets/ScenarioThrottlingControl3PP.html new file mode 100644 index 00000000..8b311bc8 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioThrottlingControl3PP.html @@ -0,0 +1,11 @@ + + + 3PP Frame + + + + +

      untrusted

      + + + diff --git a/SampleApps/WebView2APISample/assets/ScenarioThrottlingControlMonitor.html b/SampleApps/WebView2APISample/assets/ScenarioThrottlingControlMonitor.html new file mode 100644 index 00000000..912d840c --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioThrottlingControlMonitor.html @@ -0,0 +1,71 @@ + + + Throttling Control + + + +

      Throttling Control

      + + +
      +
      + page state: + foreground +
      + +
      + + +
      +
      + + + +
      + +
      + + + +
      + +
      + + + +
      +
      +
      + +
      + Scenarios +
      + + +
      +
      + + +
      +
      +
      + + +
      + + +
      +
      +
      + + +
      +
      + + +
      +
      + + + + diff --git a/SampleApps/WebView2APISample/assets/ScenarioThrottlingControlMonitor.js b/SampleApps/WebView2APISample/assets/ScenarioThrottlingControlMonitor.js new file mode 100644 index 00000000..8d833d20 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioThrottlingControlMonitor.js @@ -0,0 +1,70 @@ +let counters = { + 'main': 0, + 'trusted': 0, + 'untrusted': 0 +}; + +function logLine (target, content) { + let output = document.getElementById(`output-${target}`); + let line = `${counters[`${target}`]++}`; + output.textContent += `${line.padStart(3, ' ')} | ${content}\n`; + + output.scrollTop = output.scrollHeight; +} + +window.addEventListener('message', (event) => { + console.log(event.data); + + let frameId = event.data.frameId; + + if (event.data.visibilityUpdate) { + let visibility = event.data.visibilityUpdate; + logLine(frameId, `[visibility: ${visibility}]`); + document.getElementById('page-state').textContent = visibility == 'hidden' ? 'background' : 'foreground'; + } else { + // reporting delay + let delayText = event.data.delayAvg.toFixed(2); + logLine(frameId, `${delayText} ms`); + } +}); + +function toggleVisibility() { + let message = { + command: 'toggle-visibility', + }; + + chrome.webview.postMessage(message); +} + +function setTimerInterval(priority) { + let interval = document.getElementById(`interval-${priority}`).value; + if (interval === '' || isNaN(interval)) { + console.log('invalid value'); + return; + } + + let message = { + command: 'set-interval', + params: { + priority: priority, + intervalMs: interval + } + }; + + console.log(message); + chrome.webview.postMessage(message); +} + +function triggerScenario(label) { + let message = { + command: 'scenario', + params: { + label: label + } + }; + + chrome.webview.postMessage(message); +} + +// notify target so it can start timers +window.opener.postMessage('init'); diff --git a/SampleApps/WebView2APISample/assets/ScenarioTypeScriptDebugIndex.ts b/SampleApps/WebView2APISample/assets/ScenarioTypeScriptDebugIndex.ts index 11dedc16..ef9adbff 100644 --- a/SampleApps/WebView2APISample/assets/ScenarioTypeScriptDebugIndex.ts +++ b/SampleApps/WebView2APISample/assets/ScenarioTypeScriptDebugIndex.ts @@ -1,7 +1,7 @@ function onHeaderClick() { console.log("onHeaderClick+"); const header = document.getElementById('header'); - document.getElementById('HeaderSpace').innerHTML = header.innerHTML; + document.getElementById('HeaderSpace').textContent = header.textContent; console.log("onHeaderClick-"); } diff --git a/SampleApps/WebView2APISample/assets/ScenarioWebMessage.html b/SampleApps/WebView2APISample/assets/ScenarioWebMessage.html index 4108e8c0..f93064ac 100644 --- a/SampleApps/WebView2APISample/assets/ScenarioWebMessage.html +++ b/SampleApps/WebView2APISample/assets/ScenarioWebMessage.html @@ -47,7 +47,7 @@ description = "page"; } else { class_value = "ICoreWebView2Frame"; - menu_item = "IFrame Post Message JSON"; + menu_item = "Post Message JSON IFrame"; description = "iframe"; } document.getElementById("class1").innerHTML = class_value; diff --git a/SampleApps/WebView2APISample/assets/ScenarioWebrtcUdpPortConfiguration.html b/SampleApps/WebView2APISample/assets/ScenarioWebrtcUdpPortConfiguration.html new file mode 100644 index 00000000..3de546b0 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioWebrtcUdpPortConfiguration.html @@ -0,0 +1,371 @@ + + + + + + WebRTC UDP Port Range Test + + + +

      WebRTC UDP Port Range Test

      + +
      +
      + + +
      + + + +
      + +
      +

      Statistics

      +
      +
      +
      0
      +
      Total Candidates
      +
      +
      +
      0
      +
      Host Candidates
      +
      +
      +
      0
      +
      Server Reflexive
      +
      +
      +
      0
      +
      Relay Candidates
      +
      +
      +
      + +
      +
      +

      ICE Candidates

      + + + + + + + + + + + + + + +
      TypeProtocolAddressPortFoundationPriorityFull Candidate
      +
      +
      + + + + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/ScenarioWindowControlsOverlay.html b/SampleApps/WebView2APISample/assets/ScenarioWindowControlsOverlay.html new file mode 100644 index 00000000..dfc14e67 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioWindowControlsOverlay.html @@ -0,0 +1,11 @@ + + + + + + Webview2 Window Controls Overlay + + +

      Window Controls overlay

      + + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/SecnarioFileTypePolicy.html b/SampleApps/WebView2APISample/assets/SecnarioFileTypePolicy.html new file mode 100644 index 00000000..4f0c519d --- /dev/null +++ b/SampleApps/WebView2APISample/assets/SecnarioFileTypePolicy.html @@ -0,0 +1,73 @@ + + + + ScenarioFileTypePolicy + + + +

      File Type Policy API Demo Page

      +

      Two customized example rules in this demo:

      +

      1. Smoothly save *.eml file without file extension warning

      +

      2. Intentionally block save *.iso file

      +

      3. Block or bypass *.exe file based on configuration

      +

      4. Block or bypass *.exe file based on popup response

      +

      + +

      +

      + +

      +

      + +

      +

      File Type Policy API for Save File

      +

      + Please enter a file extension: + +

      +
      +
      +

      File Type Policy API for download

      + +
      + +
      +
      + +
      + Download exe file +
      + Download emlx file + + + diff --git a/SampleApps/WebView2APISample/assets/dedicated_worker.js b/SampleApps/WebView2APISample/assets/dedicated_worker.js new file mode 100644 index 00000000..d7ef8e48 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/dedicated_worker.js @@ -0,0 +1,42 @@ +//! [chromeWebView] +self.chrome.webview.addEventListener('message', (e) => { + const data = e.data; + e.source.postMessage('Received msg :' + JSON.stringify(data)); + if (!data.hasOwnProperty('first') || !data.hasOwnProperty('second') || + !data.hasOwnProperty('command')) { + return; + } + + const first = data.first; + const second = data.second; + switch (data.command) { + case 'ADD': { + result = first + second; + break; + } + case 'SUB': { + result = first - second; + break; + } + case 'MUL': { + result = first * second; + break; + } + case 'DIV': { + if (second === 0) { + result = 'Error: Division by zero'; + break; + } + + result = first / second; + break; + } + default: { + result = 'Failed to process the command'; + } + } + + // Notify the app about the result. + self.chrome.webview.postMessage('Result = ' + result.toString()); +}); +//! [chromeWebView] diff --git a/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/devtools.html b/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/devtools.html new file mode 100644 index 00000000..e9b52a7f --- /dev/null +++ b/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/devtools.html @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/manifest.json b/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/manifest.json new file mode 100644 index 00000000..bfca89dc --- /dev/null +++ b/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/manifest.json @@ -0,0 +1,9 @@ +{ + "manifest_version": 2, + "name": "Example Developer Tools", + "version": "0.1", + "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArRkuE54mFLpFQWdzxe4KM9HeO4RqaoQPyi2cq1bfEVC0KkK6pRJhzRF5HtJ6i9QB/oZz2DJB+b4PfLbebJJPq9CmFc9UyEWVj7+WtdHVi+hvK9Iihyfnha3HhXIAH75WSo99u+Y1Zjo+XcoeLbDr93t/wZ6TePAzCosOJ4uzKqtzV+O5J6RaquutqOaN5Qm0tcvfRmqPxprGI1IeIIuS1UZvEsYbgHJ8uj1h3SfC3tHvi8qPpzW6ktgtrdrUtNLMnPg5Mu8WkV/9M/0y+mA3RBRnXeUo8l1uxXRCvpPQX8554SaCmg9Foow0jcXiv+1Lzv+Rwq4AT+Fb8hUeDPB/PQIDAQAB", + "description": "Example developer tools extension", + "devtools_page": "devtools.html", + "minimum_chrome_version": "10.0" +} \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/panel.html b/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/panel.html new file mode 100644 index 00000000..8ab46361 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/panel.html @@ -0,0 +1,7 @@ + + + + +

      This is an example devtools extension

      + + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/panel.js b/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/panel.js new file mode 100644 index 00000000..0a6304e8 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/panel.js @@ -0,0 +1 @@ +chrome.devtools.panels.create('Example', null, 'panel.html', null); \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/sw_scope/cached_by_sw_install.jpg b/SampleApps/WebView2APISample/assets/sw_scope/cached_by_sw_install.jpg new file mode 100644 index 00000000..b93f30f0 Binary files /dev/null and b/SampleApps/WebView2APISample/assets/sw_scope/cached_by_sw_install.jpg differ diff --git a/SampleApps/WebView2APISample/assets/sw_scope/index.html b/SampleApps/WebView2APISample/assets/sw_scope/index.html new file mode 100644 index 00000000..b3580d09 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/sw_scope/index.html @@ -0,0 +1,61 @@ + + + + VirtualHostMappingForServiceWorker + + + +

      Start to register sw.js

      + +

      Fetch via virtual host

      +

      Click the fetch button to get "./txt_from_local_asset", which will be fulfilled by SW + fetching a kServiceWorkerSubResource via virtual host mapping.

      +

      + + +

      Fetch from service worker cache

      +

      Click the fetch button to get "./image_from_cache", the image cached previously by SW's install handler + will be served.

      +

      +
      + +

      Fetch from network

      +

      Click the fetch button to get an image from external network, without involving cache and virtual host mapping.

      +

      +
      + + diff --git a/SampleApps/WebView2APISample/assets/sw_scope/simple.txt b/SampleApps/WebView2APISample/assets/sw_scope/simple.txt new file mode 100644 index 00000000..e49c48e4 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/sw_scope/simple.txt @@ -0,0 +1 @@ +Simple text file under assets\sw_scope \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/sw_scope/sw.js b/SampleApps/WebView2APISample/assets/sw_scope/sw.js new file mode 100644 index 00000000..8df6d32f --- /dev/null +++ b/SampleApps/WebView2APISample/assets/sw_scope/sw.js @@ -0,0 +1,30 @@ +'use strict'; + +const CACHE_NAME = 'sw_cache'; +const CACHE_LIST = [ + 'cached_by_sw_install.jpg' +]; + +self.addEventListener('install', event => { + console.log('sw_scope/sw.js handles install event'); + event.waitUntil(caches.open(CACHE_NAME) + .then(cache => cache.addAll(CACHE_LIST)) + .then(self.skipWaiting()) + ); +}); + +self.addEventListener('activate', event => { + console.log('sw_scope/sw.js handles activate event'); + event.waitUntil(clients.claim()); +}); + +self.addEventListener('fetch', event => { + console.log('sw_scope/sw.js handles fetch event for', event.request.url); + if (event.request.url.indexOf('txt_from_local_asset') != -1) { + event.respondWith(fetch('./simple.txt')); + } else if (event.request.url.indexOf('image_from_cache') != -1) { + event.respondWith(caches.match('./cached_by_sw_install.jpg')); + } else { + event.respondWith(fetch(event.request)); + } +}); \ No newline at end of file diff --git a/SampleApps/WebView2APISample/documentation/Testing-Instructions.md b/SampleApps/WebView2APISample/documentation/Testing-Instructions.md index a246fe3b..0f3b4160 100644 --- a/SampleApps/WebView2APISample/documentation/Testing-Instructions.md +++ b/SampleApps/WebView2APISample/documentation/Testing-Instructions.md @@ -4,85 +4,121 @@ These are instructions for manually testing all the features of the WebView2 API ## Table Of Contents -* [Getting started](#Getting-started) - * [Install a NuGet package Locally in VS](#Install-a-NuGet-package-Locally-in-VS) -* [UI Entries](#ui-entries) - * [File](#File) - * [Save Screenshot](#Save-Screenshot) - * [Get Document Title](#Get-Document-Title) - * [Get Browser Version After Creation](#Get-Browser-Version-After-Creation) - * [Get Browser Version Before Creation](#Get-Browser-Version-After-Creation) - * [Exit](#Exit) - * [Script](#Script) - * [Inject Script](#Inject-Script) - * [Post Message String](#Post-Message-String) - * [Post Message JSON](#Post-Message-JSON) - * [Add Initialize Script](#addremove-initialize-script) - * [Remove Initialize Script](#addremove-initialize-script) - * [Subscribe to CDP event & Call CDP method](#subscribe-to-cdp-event--call-cdp-method) - * [Open DevTools Window](#Open-DevTools-Window) - * [Window](#Window) - * [Close WebView](#Close-WebView) - * [Create WebView](#Create-WebView) - * [Create New Window](#Create-New-Window) - * [Create New Thread](#Create-New-Thread) - * [Process](#Process) - * [Browser Process Info](#Browser-Process-Info) - * [Crash Browser Process](#Crash-Browser-Process) - * [Unresponsive Browser Process](#Unresponsive-Browser-Process) - * [Setting](#Setting) - * [Blocked Domains](#Blocked-Domains) - * [Set User Agent](#Set-User-Agent) - * [Toggle JavaScript](#Toggle-JavaScript) - * [Toggle Web Messaging](#Toggle-Web-Messaging) - * [Toggle Fullscreen allowed](#Toggle-Fullscreen-allowed) - * [Toggle Status Bar enabled](#Toggle-Status-Bar-enabled) - * [Toggle DevTools enabled](#Toggle-DevTools-enabled) - * [Toggle ZoomControl enabled](#Toggle-ZoomControl-enabled) - * [Toggle Client Certificate Requested](#Toggle-Client-Certificate-Requested) - * [Toggle Pinch Zoom enabled](#Toggle-Pinch-Zoom-enabled) - * [Toggle Block images](#Toggle-Block-images) - * [JavaScript Dialogs](#JavaScript-Dialogs) - * [Toggle context menus enabled](#Toggle-context-menus-enabled) - * [Toggle builtin error page enabled](#Toggle-builtin-error-page-enabled) - * [Toggle general autofill enabled](#Toggle-general-autofill-enabled) - * [Toggle password autosave enabled](#Toggle-password-autosave-enabled) - * [Toggle browser accelerator keys enabled](#Toggle-browser-accelerator-keys-enabled) - * [Toggle Swipe Navigation enabled](#Toggle-Swipe-Navigation-enabled) - * [Toggle Hidden PDF toolbar items](#Toggle-hide-PDF-toolbar-items) - * [Toggle Allow External Drop](#Toggle-Allow-External-Drop) - * [View](#View) - * [Toggle Visibility](#Toggle-Visibility) - * [WebView Bounds Reference](#WebView-Bounds-Reference) - * [WebView Area](#WebView-Area) - * [WebView Zoom](#WebView-Zoom) - * [WebView Scale](#WebView-Scale) - * [Set Focus](#Set-Focus) - * [Tab In](#Tab-In) - * [Reverse Tab In](#Reverse-Tab-In) - * [Toggle Tab Handling](#Toggle-Tab-Handling) - * [Scenario](#Scenario) - * [Web Messaging](#Web-Messaging) - * [Host Objects](#Host-Objects) - * [Script Debugging](#Script-Debugging) - * [Cookie Management](#Cookie-Management) - * [NavigateWithWebResourceRequest](#NavigateWithWebResourceRequest) - * [Client Certificate Requested](#ClientCertificateRequested) - * [Clear Browsing Data](#ClearBrowsingData) - * [Single sign on](#SingleSignOn) - * [IFrame Device Permission](#IFrame-Device-Permission) - * [Help](#Help) - * [About ...](#about-) - * [Miscellaneous](#Miscellaneous) - * [Accelerator Key Support](#Accelerator-Key-Support) - * [Language](#Language) - * [Saving Password](#Saving-Password) - * [Open Link in New Window From PDF](#Open-Link-in-New-Window-from-PDF) - * [WebView Does Not Crash](#WebView-Does-Not-Crash) +- [WebView2 API Testing Instructions](#webview2-api-testing-instructions) + - [Table Of Contents](#table-of-contents) + - [Getting started](#getting-started) + - [Install a NuGet package Locally in VS](#install-a-nuget-package-locally-in-vs) + - [UI Entries](#ui-entries) + - [File](#file) + - [Save Screenshot](#save-screenshot) + - [Get Document Title](#get-document-title) + - [Get Browser Version After Creation](#get-browser-version-after-creation) + - [Get Browser Version Before Creation](#get-browser-version-before-creation) + - [Exit](#exit) + - [Script](#script) + - [Inject Script](#inject-script) + - [Inject Script With Result](#inject-script-with-result) + - [Post Message string](#post-message-string) + - [Post Message JSON](#post-message-json) + - [Add/Remove Initialize Script](#addremove-initialize-script) + - [Subscribe to CDP event \& Call CDP method](#subscribe-to-cdp-event--call-cdp-method) + - [Open DevTools Window](#open-devtools-window) + - [Window](#window) + - [Close WebView](#close-webview) + - [Create WebView](#create-webview) + - [Create New Window](#create-new-window) + - [Create New Window With Options](#create-new-window-with-options) + - [Create New Thread](#create-new-thread) + - [Process](#process) + - [Browser Process Info](#browser-process-info) + - [Crash Browser Process](#crash-browser-process) + - [Unresponsive Browser Process](#unresponsive-browser-process) + - [Settings](#settings) + - [Blocked Domains](#blocked-domains) + - [Set User Agent](#set-user-agent) + - [Toggle JavaScript](#toggle-javascript) + - [Toggle Web Messaging](#toggle-web-messaging) + - [Toggle Fullscreen allowed](#toggle-fullscreen-allowed) + - [Toggle Status Bar enabled](#toggle-status-bar-enabled) + - [Toggle DevTools enabled](#toggle-devtools-enabled) + - [Toggle ZoomControl enabled](#toggle-zoomcontrol-enabled) + - [Toggle Pinch Zoom enabled](#toggle-pinch-zoom-enabled) + - [Toggle Client Certificate Requested](#toggle-client-certificate-requested) + - [Toggle Block images](#toggle-block-images) + - [JavaScript Dialogs](#javascript-dialogs) + - [Toggle context menus enabled](#toggle-context-menus-enabled) + - [Toggle builtin error page enabled](#toggle-builtin-error-page-enabled) + - [Toggle general autofill enabled](#toggle-general-autofill-enabled) + - [Toggle password autosave enabled](#toggle-password-autosave-enabled) + - [Toggle profile general autofill enabled](#toggle-profile-general-autofill-enabled) + - [Toggle profile password autosave enabled](#toggle-profile-password-autosave-enabled) + - [Toggle browser accelerator keys enabled](#toggle-browser-accelerator-keys-enabled) + - [Toggle Swipe Navigation enabled](#toggle-swipe-navigation-enabled) + - [Toggle SmartScreen enabled](#toggle-smartscreen-enabled) + - [Toggle hide PDF toolbar items](#toggle-hide-pdf-toolbar-items) + - [Toggle Allow External Drop](#toggle-allow-external-drop) + - [Toggle Server Certificate Error](#toggle-server-certificate-error) + - [Toggle Launching External URI Scheme](#toggle-launching-external-uri-scheme) + - [View](#view) + - [Toggle Visibility](#toggle-visibility) + - [WebView Bounds Reference](#webview-bounds-reference) + - [Bounds A](#bounds-a) + - [Bounds B](#bounds-b) + - [Bounds C](#bounds-c) + - [Bounds D](#bounds-d) + - [WebView Area](#webview-area) + - [WebView Zoom](#webview-zoom) + - [WebView Scale](#webview-scale) + - [Set Focus](#set-focus) + - [Tab In](#tab-in) + - [ReverseTab In](#reversetab-in) + - [Toggle Tab Handling](#toggle-tab-handling) + - [WebView DefaultBackgroundColor](#webview-defaultbackgroundcolor) + - [Scenario](#scenario) + - [Web Messaging](#web-messaging) + - [Host Objects](#host-objects) + - [DOM Content Loaded](#dom-content-loaded) + - [Script Debugging](#script-debugging) + - [\[VSCode\] Debugging Setup](#vscode-debugging-setup) + - [\[VSCode\] Single WebView JavaScript Debugging](#vscode-single-webview-javascript-debugging) + - [\[VSCode\] Single WebView TypeScript Debugging](#vscode-single-webview-typescript-debugging) + - [\[VSCode\] Single WebView JavaScript Debugging Using Attach](#vscode-single-webview-javascript-debugging-using-attach) + - [\[VSCode\] Single WebView TypeScript Debugging Using Attach](#vscode-single-webview-typescript-debugging-using-attach) + - [\[VS\] Single WebView JavaScript Debugging (Debugger For Microsoft Edge)](#vs-single-webview-javascript-debugging-debugger-for-microsoft-edge) + - [\[VS\] Single WebView TypeScript Debugging (Debugger For Microsoft Edge)](#vs-single-webview-typescript-debugging-debugger-for-microsoft-edge) + - [Cookie Management](#cookie-management) + - [Cookie Management(Profile)](#cookie-managementprofile) + - [NavigateWithWebResourceRequest](#navigatewithwebresourcerequest) + - [ClientCertificateRequested](#clientcertificaterequested) + - [SingleSignOn](#singlesignon) + - [Clear Browsing Data](#clear-browsing-data) + - [Print](#print) + - [IFrame-Device-Permission](#iframe-device-permission) + - [Accelerator Key Pressed IsBrowserAcceleratorKeyEnabled](#accelerator-key-pressed-is-browser-accelerator-key-enabled) + - [Help](#help) + - [About](#about) + - [Dialogs](#dialogs) + - [Download Dialog](#download-dialog) + - [Find Dialog](#find-dialog) + - [Dragging](#dragging) + - [Draggable Regions](#draggable-regions) + - [Interactive Dragging](#interactive-dragging) + - [Drag and Drop](#drag-and-drop) + - [Hosting Modes](#hosting-modes) + - [Windowed Hosting](#windowed-hosting) + - [Visual Hosting](#visual-hosting) + - [Miscellaneous](#miscellaneous) + - [Accelerator Key Support](#accelerator-key-support) + - [Language](#language) + - [Saving Password](#saving-password) + - [Ctrl Cick a form with post method](#ctrl-cick-a-form-with-post-method) + - [Open Link in New Window from PDF](#open-link-in-new-window-from-pdf) + - [WebView Does Not Crash](#webview-does-not-crash) + - [HTTPS upgrades disabled for API navigations](#https-upgrades-disabled-for-api-navigations) ## Getting started -* Install the [latest Edge Canary Channel](https://www.microsoftedgeinsider.com/download) +- Install the [latest Edge Canary Channel](https://www.microsoftedgeinsider.com/download) ### Install a NuGet package Locally in VS @@ -161,24 +197,41 @@ Test that prompts the user for some script to run in the WebView 4. Click `Cancel` 5. Repeat steps 2-3 6. Type `confirm("Confirm?")` in the text input box and click `OK` -7. Expected: www.bing.com says popup that says `Confirm?` +7. Expected: says popup that says `Confirm?` 8. Click `OK` inside the Confirm Box 9. Expected: dialog closed 10. Expected: ExecuteScript Result popup that says `true` 11. Click OK inside the popup dialog 12. Expected: dialog closed +#### Inject Script With Result + +Test that prompts the user for some script to run in the WebView, and get the error reason when the execution fails + +1. Launch the sample app. +2. Go to `Script -> Inject Script With Result` +3. Expected: Text Input Dialog that prompts the user for JavaScript code to execute in the current top level document rendered in the WebView +4. Click `Cancel` +5. Repeat steps 2-3 +6. Type `"abc"` in the text input box and click `OK` +7. Expected: ExecuteScriptWithResult Json Result popup that says `"abc"` +8. Click OK inside the popup dialog +9. Expected: dialog closed +10. Expected: ExecuteScriptWithResult String Result popup that says `abc` +11. Click OK inside the popup dialog +12. Expected: dialog closed + #### Post Message string Test that prompts the user for some string web message to the top level document -1. See [Web Messaging](#Web-Messaging) +1. See [Web Messaging](#web-messaging) #### Post Message JSON Test that prompts the user for some JSON web message to the top level document -1. See [Web Messaging](#Web-Messaging) +1. See [Web Messaging](#web-messaging) #### Add/Remove Initialize Script @@ -266,6 +319,21 @@ Test that creates new window 2. Go to `Window -> Create New Window` 3. Expected: A new app window opened on the same thread +### Create New Window With Options + +Test that creates new window with options + +1. Launch the sample app. +2. Go to `Window -> Create New Window With Option`. +3. Type in profile name and uncheck InPrivate, then click `OK`. +4. Expected: A new app window opened with profile name in its title bar. +5. In sample app, repeat step 2. +6. Type in a different profile name as typed in step 3 and check InPrivate, then click OK. +7. Expected: A new app window opened with the different profile name in its title bar. +8. In sample app, repeat step 2. +9. Type in the same profile name as typed in step 3 but check InPrivate, then click OK. +10. Expected: A new window opened with the same profile name in its title bar and the app icon should be different that can indicate it's in private mode. + #### Create New Thread Test that opens a new app window on a new thread @@ -324,11 +392,11 @@ _It includes foo.com and bar.org by default_ 2. Load 3. Go to `Settings -> Blocked Domains` 4. Expected: Text Input Dialog that prompts the user for a list of blocked domains -5. Add www.bing.com to the list of blocked domains and click `OK` +5. Add to the list of blocked domains and click `OK` 6. Load 7. Expected: Navigation to fails 8. Repeat steps 3-4 -9. Remove www.bing.com from the list of blocked domains and click `OK` +9. Remove from the list of blocked domains and click `OK` 10. Repeat step 6 11. Expected: Navigation to completes @@ -650,6 +718,86 @@ Test that enables/disables password autosave 28. Repeat step 9. 29. Expected: There is not an additional drop down box that has been added. +### Toggle profile general autofill enabled + +Test that enables/disables profile general autofill +_General autofill is enabled by default._ + +1. Launch the sample app. +2. Go to `Window -> Create New Window With Option`. +3. Type in profile name and uncheck InPrivate, then click `OK`. +4. Expected: A new app window opened with profile name in its title bar, we call this window as window1. +5. In sample app, repeat step 2. +6. Type in the same profile name as typed in step 3 and uncheck InPrivate, then click OK. +7. Expected: A new app window opened with profile name in its title bar, we call this window as window2. +8. In sample app, repeat step 2. +9. Type in the same profile name as typed in step 3 but check InPrivate, then click OK. +10. Expected: A new window opened with the same profile name in its title bar and the app icon should be different that can indicate it's in private mode, we call this window as window3. +11. In all windows(1-3) navigate to (Use this third party site to verify). +12. In window1 enter in any test information into the Profile Autofill section and click `Submit`. +13. In window1 navigate to . +14. In all windows(1-3) click on the Name field. +15. Expected: A drop down box with the saved profile information is shown. +16. In all windows(1-3) click on the box. +17. Expected: The profile information is autofilled. +18. In window1 go to `Settings -> Toggle Profile General Autofill`. +19. Expected: Message box that says `General autofill will be disabled immediately in all WebView2 with the same profile.`. +20. Click `OK` inside the popup dialog. +21. In all windows(1-3) click on the Name field. +22. Expected: No drop down box appears. +23. Repeat step 12-14. +24. Expected: No drop down box appears. +25. In window1 go to `Settings -> Toggle Profile General Autofill`. +26. Expected: Message box that says `General autofill will be enabled immediately in all WebView2 with the same profile.`. +27. Click `OK` inside the popup dialog. +28. In all windows(1-3) click on the Name field. +15. Expected: A drop down box with the original saved profile information from step 12 is shown. +16. In all windows(1-3) click on the box. +17. Expected: The profile information is autofilled. + +### Toggle profile password autosave enabled + +Test that enables/disables password autosave + _Password autosave is disabled by default._ + +1. Launch the sample app. +2. Go to `Settings -> Toggle Profile General Autofill`. +3. Expected: Message Box that says `General autofill will be disabled immediately in all WebView2 with the same profile.`. +4. Go to `Window -> Create New Window With Option`. +5. Type in profile name and uncheck InPrivate, then click `OK`. +6. Expected: A new app window opened with profile name in its title bar, we call this window as window1. +7. In sample app, repeat step 2. +8. Type in the same profile name as typed in step 3 and uncheck InPrivate, then click OK. +9. Expected: A new app window opened with profile name in its title bar, we call this window as window2. +10. In sample app, repeat step 2. +11. Type in the same profile name as typed in step 3 but check InPrivate, then click OK. +12. Expected: A new window opened with the same profile name in its title bar and the app icon should be different that can indicate it's in private mode, we call this window as window3. +13. In all windows(1-3) navigate to (Use this third party site to verify). +14. In window1 enter in any test information into the Username/Password section and click `Submit`. +15. Expected: The window1 navigates to and no save password prompt is shown. +16. In window1, navigate to . +17. In all windows(1-3) click on the username field. +18. Expected: No drop down box appears. (note: if password information has previously been saved when the password autosave has been enabled, a drop down box will appear.) +19. In window1, go to `Settings -> Toogle Profile Password Autosave`. +20. Expected: Message Box that says `Password autosave will be enabled after the next navigation in all WebView2 with the same profile.`. +21. Click `OK` inside the popup dialog. +22. In window1 enter in any test information into the Username/Password section and click `Submit`. +23. Expected: The app navigates to and a save password prompt will popup. +24. Click `Save`. +25. In all windows(1-3) navigate to . +26. Expected: In window1 see the username and password information is auto-populated. +27. In all windows(1-3) click on the username field. +28. Expected: A drop down box with the saved password information is shown. +29. In window1 go to `Settings -> Toggle Profile Password Autosave`. +30. Expected: Message Box that says `Password autosave will be disabled after the next navigation in all WebView2 with the same profile.`. +31. Click `OK` inside the popup dialog. +32. In window1 delete the information from the username and password fields and enter in new test information and click submit. +33. Expected: No save password prompt is shown. +34. In window1 navigate to . +35. Expected: Only the information entered from step 22 is auto-populated. +36. In all windows(1-3) click on the username field. +37. Expected: There is not an additional drop down box that has been added. + ### Toggle browser accelerator keys enabled Test that enabled/disables browser accelerator keys @@ -690,7 +838,35 @@ _Swipe left/right to navigate is enabled by default._ 1. Click `OK` inside the popup dialog and click `Reload` 1. Verify that swipe to navigate works again. +#### Toggle SmartScreen enabled + +Test that enables/disables SmartScreen + +1. Launch the sample app +1. Navigate to +1. Expected: The SmartScreen pop-up window will appear +1. Go to `Settings -> Toggle Profile Smart Screen` +1. Expected: Message Box that says `SmartScreen is disable after the next navigation.` +1. Refresh the page +1. Expected: The popup will no longer appear +1. Go to `Window -> Create New Window` +1. Expected:A new window will be created +1. Navigate both windows to +1. Expected: The SmartScreen pop-up window will appear in both windows +1. In the second window, go to `Settings -> Toggle Profile Smart Screen` +1. Expected: Message Box that says `SmartScreen is disable after the next navigation.` +1. Refresh the pages of both windows. +1. Expected: The pop-up window of SmartScreen will not appear on both windows +1. In the second window,go to `Settings -> Toggle Profile Smart Screen` +1. Expected: Message Box that says `SmartScreen is enable after the next navigation.` +1. Refresh the page +1. Expected: The SmartScreen pop-up window will appear in both windows +1. Close the second window +1. First window navigate to +1. Expected: The popup will no longer appear + #### Toggle hide PDF toolbar items + Test that hide/show PDF save button and print button. 1. Launch the sample app @@ -717,6 +893,42 @@ Test that enables or disables dragging and dropping files into webview. 1. Drag and drop the file into the sample app again 1. Expected: A new window with this text file opened is launched +#### Toggle Server Certificate Error + +Test that turns off TLS error page. + +1. Launch the sample app. +1. Navigate to . +1. Expected: WebView2 displays SSL error page to the user. +1. Go to `Settings -> Server Certificate Error -> Toogle Server Certificate Error Support`. +1. Expected: Message Box that says `Custom server certificate error support been enabled`. +1. Click `OK` inside the popup dialog. +1. Refresh the page. +1. Expected: Web page is loaded without any errors. +1. Go to `Settings -> Server Certificate Error -> Toogle Server Certificate Error Support`. +1. Expected: Message Box that says `Custom server certificate error support been disbaled`. +1. Go to `Settings -> Server Certificate Error -> Clear Server Certificate Error Actions`. +1. Expected: Message Box that says `Clear server certificate error actions are succeeded.` +1. Refresh the page. +1. Expected: WebView2 displays SSL error page to the user. + +#### Toggle Launching External URI Scheme + +1. Launch the sample app. +1. Navigate to . +1. Expected: Default dialog is displayed. +1. Select `OK` inside the dialog. +1. Expected: Calculator application is launched. +1. Go to `Settings -> Toggle Launching External URI Scheme`. +1. Expected: Message Box that says `Launching Exteranl URI Scheme support has been enabled`. +1. Click `OK` inside the popup dialog. +1. Repeat step 2. +1. Expected: No default dialog is displayed and the calculator application is launched. +1. Go to `Settings -> Toggle Launching External URI Scheme`. +1. Expected: Message Box that says `Launching Exteranl URI Scheme support has been disabled`. +1. Repeat step 2. +1. Expected: Default dialog is displayed. + ### View #### Toggle Visibility @@ -733,9 +945,9 @@ Test that makes WebView visible/invisible Notes: -* Top is always 32 (or some non-zero value) to account for sample app UI such as menu bar and address bar -* WebView height is (Bottom - Top) -* WebView width is equal to Right +- Top is always 32 (or some non-zero value) to account for sample app UI such as menu bar and address bar +- WebView height is (Bottom - Top) +- WebView width is equal to Right ##### Bounds A @@ -753,7 +965,7 @@ Top: 32 Right: 712 Bottom: 366 -or, height/width should be 0.5x of [Bounds A](#bounds-A) +or, height/width should be 0.5x of [Bounds A](#bounds-a) ##### Bounds C @@ -762,7 +974,7 @@ Top: 32 Right: 1006 Bottom: 504 -or, height/width should be ~0.707x of [Bounds A](#bounds-A) +or, height/width should be ~0.707x of [Bounds A](#bounds-a) ##### Bounds D @@ -771,7 +983,7 @@ Top: 32 Right: 1509 Bottom: 740 -or, height/width should be ~1.06x of [Bounds A](#bounds-A) +or, height/width should be ~1.06x of [Bounds A](#bounds-a) #### WebView Area @@ -779,13 +991,13 @@ Test that resizes WebView window _Updates the bounds of the WebView window to resize_ 1. Launch the sample app. -1. Go to `View -> WebView Area -> Get WebView Bounds`. Note the current bounds. (See [Bounds A](#Bounds-A)) +1. Go to `View -> WebView Area -> Get WebView Bounds`. Note the current bounds. (See [Bounds A](#bounds-a)) 1. Go to `View -> WebView Area -> 25%` 1. Go to `View -> WebView Area -> Get WebView Bounds`. -1. Expected: WebView size ratio is 25% of bounds in step 2 and WebView was resized. (See [Bounds B](#Bounds-B)) +1. Expected: WebView size ratio is 25% of bounds in step 2 and WebView was resized. (See [Bounds B](#bounds-b)) 1. Go to `View -> WebView Area -> 50%` 1. Go to `View -> WebView Area -> Get WebView Bounds`. -1. Expected: WebView size ratio to 50% of bounds in step 2 and WebView was resized. (See [Bounds C](#Bounds-C)) +1. Expected: WebView size ratio to 50% of bounds in step 2 and WebView was resized. (See [Bounds C](#bounds-c)) 1. Go to `View -> WebView Area -> 100%` 1. Go to `View -> WebView Area -> Get WebView Bounds`. 1. Expected: WebView size matches bounds in step 2 and WebView was resized. @@ -820,10 +1032,10 @@ getting larger or smaller without the layout of the page changing._ 1. Launch the sample app. 1. Go to `View -> WebView Area -> 50%` -1. Go to `View -> WebView Area -> Get WebView Bounds`. Note the current bounds. (See [Bounds C](#Bounds-C)) +1. Go to `View -> WebView Area -> Get WebView Bounds`. Note the current bounds. (See [Bounds C](#bounds-c)) 1. Go to `View -> WebView Scale -> 1.5x` 1. Go to `View -> WebView Area -> Get WebView Bounds` -1. Expected: WebView size is 1.5x larger than bounds in step 2 - current WebView height is 1.5x larger than height in step 2 and current WebView width is 1.5x larger than width in step 2. (See [Bounds D](#Bounds-D)) +1. Expected: WebView size is 1.5x larger than bounds in step 2 - current WebView height is 1.5x larger than height in step 2 and current WebView width is 1.5x larger than width in step 2. (See [Bounds D](#bounds-d)) 1. Go to `View -> WebView Zoom -> Get WebView Zoom` 1. Expected: WebView zoom factor is set to 1.5x 1. Expected: WebView renders at the new size/zoom (looks larger) without the @@ -926,9 +1138,7 @@ Test that verifies `DOMContentLoaded` event is raised after the DOM is loaded wh ##### [VSCode] Debugging Setup -1. Open VSCode, go to `View -> Extensions` and install the two debuggers: - 1. [Debugger For Microsoft Edge](https://github.com/microsoft/vscode-edge-debug2) - ![old-debugging-tool](screenshots/old-script-debugging-tool.png) +1. Open VSCode, go to `View -> Extensions` and install the debugger: 1. [JavaScript Debugger Nightly](https://github.com/microsoft/vscode-js-debug) ![new-debugging-tool](screenshots/new-script-debugging-tool.png) 1. Go to `File -> Open Folder` and open `WebView2APISample/` (where `.vscode/` lives) @@ -938,7 +1148,7 @@ Test that verifies `DOMContentLoaded` event is raised after the DOM is loaded wh ##### [VSCode] Single WebView JavaScript Debugging -Test Single WebView JavaScript Debugging with **both** [Debugger For Microsoft Edge](https://github.com/microsoft/vscode-edge-debug2) and [JavaScript Debugger Nightly](https://github.com/microsoft/vscode-js-debug) in VSCode +Test Single WebView JavaScript Debugging with **both** [Visual Studio Code's built-in debugger for Microsoft Edge](https://code.visualstudio.com/docs/nodejs/browser-debugging) and [JavaScript Debugger Nightly](https://github.com/microsoft/vscode-js-debug) in VSCode 1. Follow [Debugging Setup](#vscode-debugging-setup) 1. Go to Debug tab via `View -> Run` @@ -952,7 +1162,7 @@ Test Single WebView JavaScript Debugging with **both** [Debugger For Microsoft E ##### [VSCode] Single WebView TypeScript Debugging -Test Single WebView TypeScript Debugging with **both** [Debugger For Microsoft Edge](https://github.com/microsoft/vscode-edge-debug2) and [JavaScript Debugger Nightly](https://github.com/microsoft/vscode-js-debug) in VSCode +Test Single WebView TypeScript Debugging with **both** [Visual Studio Code's built-in debugger for Microsoft Edge](https://code.visualstudio.com/docs/nodejs/browser-debugging) and [JavaScript Debugger Nightly](https://github.com/microsoft/vscode-js-debug) in VSCode 1. Follow [Debugging Setup](#vscode-debugging-setup) 1. Go to Debug tab via `View -> Run` @@ -967,7 +1177,7 @@ Test Single WebView TypeScript Debugging with **both** [Debugger For Microsoft E ##### [VSCode] Single WebView JavaScript Debugging Using Attach -Test Single WebView Script Debugging with **both** [Debugger For Microsoft Edge](https://github.com/microsoft/vscode-edge-debug2) and [JavaScript Debugger Nightly](https://github.com/microsoft/vscode-js-debug) in VSCode +Test Single WebView Script Debugging with **both** [Visual Studio Code's built-in debugger for Microsoft Edge](https://code.visualstudio.com/docs/nodejs/browser-debugging) and [JavaScript Debugger Nightly](https://github.com/microsoft/vscode-js-debug) in VSCode 1. Add a new REGKEY `*=--remote-debugging-port=9222` under `Computer\HKEY_CURRENT_USER\Software\Policies\Microsoft\Edge\WebView2\AdditionalBrowserArguments` ![step 1](screenshots/script-debugging-reg-key.png) @@ -984,7 +1194,7 @@ Test Single WebView Script Debugging with **both** [Debugger For Microsoft Edge] ##### [VSCode] Single WebView TypeScript Debugging Using Attach -Test Single WebView Script Debugging with **both** [Debugger For Microsoft Edge](https://github.com/microsoft/vscode-edge-debug2) and [JavaScript Debugger Nightly](https://github.com/microsoft/vscode-js-debug) in VSCode +Test Single WebView Script Debugging with **both** [Visual Studio Code's built-in debugger for Microsoft Edge](https://code.visualstudio.com/docs/nodejs/browser-debugging) and [JavaScript Debugger Nightly](https://github.com/microsoft/vscode-js-debug) in VSCode 1. Add a new REGKEY `*=--remote-debugging-port=9222` under `Computer\HKEY_CURRENT_USER\Software\Policies\Microsoft\Edge\WebView2\AdditionalBrowserArguments` ![step 1](screenshots/script-debugging-reg-key.png) @@ -999,9 +1209,9 @@ Test Single WebView Script Debugging with **both** [Debugger For Microsoft Edge] 1. Expect debugger to hit the breakpoint and pause the page 1. Delete the REGKEY after testing -##### [VS] Single WebView JavaScript Debugging (Old Tool: Debugger For Microsoft Edge) +##### [VS] Single WebView JavaScript Debugging (Debugger For Microsoft Edge) -Test Single WebView JavaScript Debugging with old debugging tool: [Debugger For Microsoft Edge in VS](https://github.com/microsoft/vscode-edge-debug2) +Test Single WebView JavaScript Debugging: 1. Open VS Installer, and make sure `JavaScript Diagnostics` is installed for C++ Development Kit. ![step 1](screenshots/vs-javascript-diagnostics.png) @@ -1013,9 +1223,9 @@ Test Single WebView JavaScript Debugging with old debugging tool: [Debugger For 6. Go to `Scenario -> Script Debugging -> JavaScript` 7. Expect debugger to hit the breakpoint and pause the page -##### [VS] Single WebView TypeScript Debugging (Old Tool: Debugger For Microsoft Edge) +##### [VS] Single WebView TypeScript Debugging (Debugger For Microsoft Edge) -Test Single WebView JavaScript Debugging with old debugging tool: [Debugger For Microsoft Edge in VS](https://github.com/microsoft/vscode-edge-debug2) +Test Single WebView JavaScript Debugging: 1. Open VS Installer, and make sure `JavaScript Diagnostics` is installed for C++ Development Kit. ![step 1](screenshots/vs-javascript-diagnostics.png) @@ -1036,6 +1246,14 @@ Test that demonstrates cookie management related APIs usage such as `GetCookies` 2. Go to **Scenario** > **Cookie Management** 3. Follow the instructions on the page +#### Cookie Management(Profile) + +Test that demonstrates cookie management related APIs using cookie manager got from profile. + +1. Launch the sample app +2. Go to **Scenario** > **Cookie Management(Profile)** +3. Follow the instructions on the page + #### NavigateWithWebResourceRequest 1. Launch sample app. @@ -1049,7 +1267,7 @@ Test that demonstrates cookie management related APIs usage such as `GetCookies` 1. Close sample app if it is open and re-launch. 2. Go to `Scenario -> Client Certificate Requested -> Use Deferred Custom Client Certificate Selection Dialog`. 3. Expected: Message Box that says `Custom Client Certificate selection dialog will be used next when WebView2 is making a request to an HTTP server that needs a client certificate.` -4. Follow steps 8-19 from [Toggle Client Certificate Requested](#Toggle-Client-Certificate-Requested) if client certificate is not installed, otherwise skip this. +4. Follow steps 8-19 from [Toggle Client Certificate Requested](#toggle-client-certificate-requested) if client certificate is not installed, otherwise skip this. 5. Navigate to . 6. Expected: A custom dialog box with title `Select a certificate for authentication` and certificate/s in the list box. 7. Select a certificate from the list. @@ -1063,6 +1281,7 @@ Test that demonstrates cookie management related APIs usage such as `GetCookies` 14. Expected: Dialog box is closed and server responds with 400 Bad Request (No required SSL Certificate was sent). #### SingleSignOn + 1. Set environment variable WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS=--enable-features=msSingleSignOnOSForPrimaryAccountIsShared 2. Launch sample app 3. Go to `Scenario -> WebView Event Monitor` @@ -1107,6 +1326,25 @@ Test that demonstrates the clear browsing data API. 31. Click on the Name field. 32. Expected: A drop down box with the saved profile information is shown. +#### Print + +Test that demonstrates the ShowPrintUI and Print API. + +1. Launch the sample app. +2. Go to **Scenario** > **Print** > **Browser Print Preview**. +3. Verify that browser print preview dialog is displayed. +4. Click cancel. +5. Go to **Scenario** > **Print** > **System Print**. +6. Verify that system print dialog is displayed. +7. Click cancel. +8. Go to **Scenario** > **Print** > **Print to printer**. +9. On the opened dialog box enter `Microsoft Print to PDF` as the printer name and click OK. +10. Confirm file dialog is displayed. +11. Save the PDF file to a location on the machine. +12. Open and confirm that the sample app home page is printed as PDF without any background graphics. +13. Go to **Scenario** > **Print** > **Print to default printer**. +14. Repeat steps 10-12. + #### IFrame-Device-Permission Test that demonstrates the frame Permission Requested API. @@ -1120,9 +1358,18 @@ Test that demonstrates the frame Permission Requested API. 7. Click `Location Test` for the main frame. 8. Expected: The CoreWebView2Frame permission requests opens a message box to ask user whether they want to accept or deny. +#### Accelerator Key Pressed IsBrowserAcceleratorKeyEnabled +Test that app can allow/block specific browser accelerator keys when `IsBrowserAcceleratorKeyEnabled` settings is set to `FALSE`/`TRUE`. +1. Launch the sample app. +1. Go to `Scenario -> Accelerator Key Pressed`. F7 is expected to always be enabled and Ctr + P is always disabled in this scenario. +1. Click on `Disable all Browser Accelerator`, close pop up dialog, then reload the page. +1. Expected: All browser accelerator keys are disabled, but F7 works. +1. Click on `Enable all Browser Accelerator`, close pop up dialog, then reload the page. +1. Expected: All browser accelerator keys are now enabled, but Ctrl + P will not work. + ### Help -#### About ... +#### About Test that gets `About …` @@ -1132,6 +1379,162 @@ Test that gets `About …` 4. Click `OK` inside the popup dialog 5. Expected: dialog closed +### Dialogs + +Test that various dialogs work as expected. Uses two windows because some crashes are only caught if the app is still running. + +#### Download Dialog + +1. Launch the sample app. +2. Go to `Window -> Create New Thread`. +3. Expected: A new app window is opened. +4. Navigate to . +5. Scroll down to `App Rep Demos` section and click on `Known Good Program` to download. +6. Expected: Download dialog appears. +7. Minimize app window with download dialog. +8. Restore app window with download dialog. +9. Close download dialog using `X` button. +10. Expected: Download dialog is closed. +11. Repeat step 5 to start another download. +12. Close app window with download dialog open. +13. Expected: App window and download dialog are closed. + +#### Find Dialog + +1. Launch the sample app. +2. Go to `Window -> Create New Thread`. +3. Expected: A new app window is opened. +4. Launch find dialog on new window with `Ctrl-F`. +5. Close new window. +6. Expected: New window and find dialog are closed. + +### Dragging + +#### Draggable Regions + +Test that draggable regions work on WebView2. + +1. Enable Draggable Regions by adding the feature flag `msWebView2EnableDraggableRegions` to `put_AdditionalBrowserArguments` args in `AppWindow::InitializeWebView`. +1. Build and launch the sample app. +1. Select `Script > Inject Script` and paste this code into the text box: + + ```javascript + document.getElementsByClassName('header')[0].style.appRegion = "drag"; + document.getElementsByClassName('center')[0].style.appRegion = "no-drag"; + document.getElementsByClassName('header')[0].style.width = "99%"; + setTimeout(1, function() { document.getElementsByClassName('header')[0].style.width = "100%";}); + ``` + +NOTE: this code briefly changes the size of the 'Microsoft Edge WebView2' header +element on the webpage. This is to trigger a reflow of the document. Without +this the `appRegion` changes would not take place until some document element was resized + +1. Click and drag over the text of 'Microsoft Edge WebView2' header element +1. Expected: Cursor changes to I-bar, text highlights if applicable, sample app + does not drag. Note: may drag if click and drag point is too far from the + text. +1. For following instructions, click in the box, not the text of the 'Microsoft + Edge WebView2' header element. +1. Click and drag 'Microsoft Edge WebView2' element. +1. Expected: Entire sample app should drag +1. Double click on the 'Microsoft Edge WebView2' element. +1. Expected: Sample app should maximize +1. Double click on the 'Microsoft Edge WebView2' element again. +1. Expected: Sample app should restore to previous size +1. Right click on 'Microsoft Edge WebView2' element. +1. Expected: Title bar context menu (non-WebView) should appear +1. Select `maximize` +1. Expected: Sample app will maximize +1. Right click 'Microsoft Edge WebView2' element and select `restore` +1. Expected: Sample app will restore. + +#### Interactive Dragging Enabled By Default + +Test that interactive dragging is enabled by default on Webview2. + +1. Click Scenario > Non-Client Region Support. +1. Look under the Heading "Interactive Elements". +1. Hover the mouse on the textarea and button. +1. Expected: Cursor should be arrow, the element border should turn red and + increase in size. +1. Drag on text area and button. +1. Expected: The entire app should drag. +1. Click into text area. +1. Expected: Cursor changes to I-bar. +1. Type text into textarea then try to select/highlight it +1. Expected: Text should highlight and the entire app should not drag +1. Click button. +1. Expected: The click counter should increment. + +#### Interactive Dragging Opt-out + +Test that the interactive dragging opt-out switch works on Webview2. + +1. run the app with the flag + --edge-webview-disable-interactive-dragging +1. Click Scenario > Non-Client Region Support. +1. Look under the Heading "Interactive Elements". +1. Hover the mouse on the textarea and button. +1. Expected: Cursor should be arrow, the element border should + stay the same. +1. Drag on text area and button. +1. Expected: The entire app should drag. +1. Click into text area. +1. Expected: Cursor remains the same. +1. Click button. +1. Expected: The click counter should not increment. + +#### Drag and Drop + +Test that Drag and Drop is supported in WebView2 using both hosting modes. + +1. Launch the sample app. +1. Select text "Runtime version". +1. Click, hold, and drag the selected text to the Query text box. +1. Release mouse over text box to drop text. +1. Expected: "Runtime version" text is inserted into Query text box. +1. Go to `Window -> Close WebView.` +1. Go to `Window -> WebView Creation Mode -> Visual - DComp.` +1. Go to `Window -> Create WebView.` +1. Select text "Runtime version". +1. Click, hold, and drag the selected text to the Query text box. +1. Release mouse over text box to drop text. +1. Expected: "Runtime version" text is inserted into Query text box. +1. Go to `Window -> Close WebView.` +1. Expected: App does not crash. + +### Hosting Modes + +#### Windowed Hosting + +The majority of the tests in this document are tested using Windowed/HWND hosting, which is the default. +We don't need other specific tests for Windowed Hosting. + +#### Visual Hosting + +Verify that basic hosting functionality continues to work when hosted using visuals. + +1. Launch the sample app. +1. Go to `Window -> Close WebView`. +1. Go to `Window -> WebView Creation Mode -> Visual - DComp`. +1. Go to `Window -> Create WebView`. +1. Move mouse to the Query text box in the webpage. +1. Expected: Cursor should change from a pointer to I-beam text cursor. +1. Click in Query text box. +1. Expected: Focus moves to the text box and insertion caret shows up in the text box. +1. Type "Hello world" in the Query text box. +1. Expected: Text shows up in text box. +1. Press `Windows + period` on the keyboard. +1. Expected: Emoji picker popup appears, positioned to the bottom right of the insertion point. +1. Click on any emoji to insert it. +1. Expected: Chosen emoji is inserted in the text box. +1. Close the emoji picker. +1. Drag the window to a new location on screen. +1. Repeat steps 5 - 15. +1. Expected: Webpage moves to new location. +1. Expected: Cursor changes from hovering and clicking text box are in the new location. +1. Expected: Emoji picker is in the new location. + ### Miscellaneous #### Accelerator Key Support @@ -1141,11 +1544,11 @@ Verify that accelerator key routing works 1. Launch the sample app. 2. Put focus inside the webpage. 3. For each of the following accelerator keys, press it while the webview is focused, and verify that the expected result happens. - * `CTRL-S`: The save screenshot dialog opens. Press cancel to close it. - * `CTRL-N`: A new app window opens. - * `CTRL-T`: A new app window opens. - * `CTRL-W`: The webview inside the current app window closes. - * `CTRL-Q`: The current app window closes. + - `CTRL-S`: The save screenshot dialog opens. Press cancel to close it. + - `CTRL-N`: A new app window opens. + - `CTRL-T`: A new app window opens. + - `CTRL-W`: The webview inside the current app window closes. + - `CTRL-Q`: The current app window closes. #### Language @@ -1169,7 +1572,7 @@ Verify that we don't offer saving password. 1. Launch the sample app. 2. Load , ignore any iframe navigation failure messages during the test. -3. Type in some test email and password, like test@example.com and 12345678 in Email and Password field on the right part of the page. +3. Type in some test email and password, like and 12345678 in Email and Password field on the right part of the page. 4. Click `Submit` button, the page should show the inputted values. 5. Make sure that there is no browser prompt for saving password with strings like `Microsoft Edge will save and fill your password for this site next time`. 6. Reload the page, ignore any iframe navigation failure messages during the test. @@ -1177,18 +1580,31 @@ Verify that we don't offer saving password. 8. Set focus on Email input, verify that we can choose to auto fill with previously typed in value. 9. Set focus on Password input, verify that there is no auto fill option showing up. +#### Ctrl Cick a form with post method + +Verify that we correctly pass request to the new opened window when submit form with post method through ctrl click. + +1. Launch the sample app. +2. Load , ignore any iframe navigation failure messages during the test. +3. Remove `target="_blank"` from the line `
      `. +4. Click `Run` button on the left part of the page. +5. Type in some test first name and last name, like first_name and last_name in First name and Last name on the right part of the page. +6. Press the Ctrl key, hold it and click `Submit` button in the meanwhile, then it should pop up a new window. +7. Verify that the text bar in the new opened window shows the first name and last name you typed in step 5, like `fname=first_name&lname=last_name`. + #### Open Link in New Window from PDF Verify that the `NewWindowRequested` event is fired when opening a link in new window from PDF. 1. Launch the sample app. -2. Load . +2. Navigate to . 3. Go to `Scenario -> WebView Event Monitor` to begin tracking events. -4. Scroll to the second page of the PDF and right click on the first link to open the context menu. +4. Right click on the link in the PDF to open the context menu. 5. Click on 'Open link in new window'. 6. Expected: Event Monitor displays `NewWindowRequested`. #### WebView Does Not Crash + Test that there is no crash in WebView processes for some of the error prone scenarios. 1. Launch the sample app. @@ -1201,3 +1617,10 @@ Test that there is no crash in WebView processes for some of the error prone sce 1. Close the WebView in first app window by `Window -> Close WebView`. 1. Expected: The WebView in first app window does not render the start page anymore, while no browser process failure message box is observed for the newly created app window. 1. Wait for 1 minute, expect no browser process failure message box is observed for the newly created app window. + +#### HTTPS upgrades disabled for API navigations + +1. Launch the sample app. +2. Navigate to `http://privacy-test-pages.site/privacy-protections/https-upgrades/` +3. Expected: Observe that the page loads on http and does not try to redirect to https + and go into a redirect loop. diff --git a/SampleApps/WebView2APISample/documentation/screenshots/old-script-debugging-tool.png b/SampleApps/WebView2APISample/documentation/screenshots/old-script-debugging-tool.png deleted file mode 100644 index 6e0f98b5..00000000 Binary files a/SampleApps/WebView2APISample/documentation/screenshots/old-script-debugging-tool.png and /dev/null differ diff --git a/SampleApps/WebView2APISample/documentation/screenshots/sample-app-layout-diagram.png b/SampleApps/WebView2APISample/documentation/screenshots/sample-app-layout-diagram.png deleted file mode 100644 index 5f2566bc..00000000 Binary files a/SampleApps/WebView2APISample/documentation/screenshots/sample-app-layout-diagram.png and /dev/null differ diff --git a/SampleApps/WebView2APISample/documentation/screenshots/sample-app-screenshot.png b/SampleApps/WebView2APISample/documentation/screenshots/sample-app-screenshot.png index c891df6d..6d32a13e 100644 Binary files a/SampleApps/WebView2APISample/documentation/screenshots/sample-app-screenshot.png and b/SampleApps/WebView2APISample/documentation/screenshots/sample-app-screenshot.png differ diff --git a/SampleApps/WebView2APISample/documentation/screenshots/sample-app-webmessaging-screenshot.png b/SampleApps/WebView2APISample/documentation/screenshots/sample-app-webmessaging-screenshot.png deleted file mode 100644 index 88f1ac14..00000000 Binary files a/SampleApps/WebView2APISample/documentation/screenshots/sample-app-webmessaging-screenshot.png and /dev/null differ diff --git a/SampleApps/WebView2APISample/packages.config b/SampleApps/WebView2APISample/packages.config index 3eaed8f0..2943f33f 100644 --- a/SampleApps/WebView2APISample/packages.config +++ b/SampleApps/WebView2APISample/packages.config @@ -1,5 +1,5 @@ - - - - + + + + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/resource.h b/SampleApps/WebView2APISample/resource.h index f8c0e75f..1da97a5b 100644 --- a/SampleApps/WebView2APISample/resource.h +++ b/SampleApps/WebView2APISample/resource.h @@ -9,7 +9,7 @@ #define IDM_ABOUT 104 #define IDM_EXIT 105 #define IDI_WEBVIEW2APISAMPLE 107 -#define IDI_SMALL 108 +//#define IDI_SMALL 108 - UNUSED #define IDC_WEBVIEW2APISAMPLE 109 #define IDC_WEBVIEW2APISAMPLEHOST 110 #define IDM_ZOOM_05 111 @@ -44,9 +44,7 @@ #define IDM_TOGGLE_TAB_HANDLING 155 #define ID_SETTINGS_STATUS_BAR_ENABLED 156 #define ID_SETTINGS_DEV_TOOLS_ENABLED 157 -#define IDM_USE_DEFAULT_SCRIPT_DIALOGS 158 -#define IDM_USE_CUSTOM_SCRIPT_DIALOGS 159 -#define IDM_USE_DEFERRED_SCRIPT_DIALOGS 160 +#define IDM_TOGGLE_DEFAULT_SCRIPT_DIALOGS 158 #define IDM_GET_DOCUMENT_TITLE 161 #define IDM_TRANSFORM_NONE 163 #define IDM_TRANSFORM_ROTATE_30DEG 165 @@ -68,12 +66,6 @@ #define IDM_GET_WEBVIEW_ZOOM 190 #define IDM_CRASH_RENDER_PROCESS 191 #define IDM_SET_LANGUAGE 192 -#define IDM_CREATION_MODE_WINDOWED 193 -#define IDM_CREATION_MODE_VISUAL_DCOMP 194 -#define IDM_CREATION_MODE_TARGET_DCOMP 195 -#ifdef USE_WEBVIEW2_WIN10 -#define IDM_CREATION_MODE_VISUAL_WINCOMP 196 -#endif #define IDM_SCENARIO_JAVA_SCRIPT 199 #define IDM_SCENARIO_TYPE_SCRIPT 200 #define IDM_TOGGLE_AAD_SSO 201 @@ -117,8 +109,27 @@ #define IDC_EDIT_DOWNLOAD_PATH 242 #define IDM_CALL_CDP_METHOD_FOR_SESSION 243 #define IDM_COLLECT_HEAP_MEMORY_VIA_CDP 244 +#define IDM_INJECT_SCRIPT_WITH_RESULT 245 +#define IDM_TOGGLE_CUSTOM_CRASH_REPORTING 246 +#define IDM_GET_FAILURE_REPORT_FOLDER 247 +#define IDM_TOGGLE_TRACKING_PREVENTION 251 +#define IDM_TRACKING_PREVENTION_LEVEL_NONE 252 +#define IDM_TRACKING_PREVENTION_LEVEL_BASIC 253 +#define IDM_TRACKING_PREVENTION_LEVEL_BALANCED 254 +#define IDM_TRACKING_PREVENTION_LEVEL_STRICT 255 +#define IDD_SET_PERMISSION 256 +#define IDC_EDIT_PERMISSION_ORIGIN 257 +#define IDC_PERMISSION_KIND 258 +#define IDC_PERMISSION_STATE 259 +#define IDD_SAVE_CONTENT_AS 260 +#define IDC_EDIT_SAVE_AS_DIRECTORY 261 +#define IDC_EDIT_SAVE_AS_FILENAME 262 +#define IDC_CHECK_SAVE_AS_ALLOW_REPLACE 263 +#define IDC_SAVE_AS_KIND 264 +#define IDM_ENHANCED_SECURITY_MODE_LEVEL_OFF 265 +#define IDM_ENHANCED_SECURITY_MODE_LEVEL_STRICT 266 #define IDM_TOGGLE_TOPMOST_WINDOW 300 - +#define IDM_PROCESS_EXTENDED_INFO 301 #define IDE_ADDRESSBAR 1000 #define IDE_ADDRESSBAR_GO 1001 #define IDE_BACK 1002 @@ -154,6 +165,63 @@ #define IDM_SCENARIO_VIRTUAL_HOST_MAPPING 2017 #define IDM_SCENARIO_VIRTUAL_HOST_MAPPING_POP_UP_WINDOW 2018 #define IDM_SCENARIO_IFRAME_DEVICE_PERMISSION 2019 +#define IDM_SCENARIO_COOKIE_MANAGEMENT_PROFILE 2020 +#define IDM_ADD_EXTENSION 2024 +#define IDM_REMOVE_EXTENSION 2025 +#define IDM_DISABLE_EXTENSION 2026 +#define IDM_SCENARIO_EXTENSIONS_MANAGEMENT_INSTALL_DEFAULT 2027 +#define IDM_SCENARIO_EXTENSIONS_MANAGEMENT_OFFLOAD_DEFAULT 2028 +#define IDM_SCENARIO_CUSTOM_SCHEME 2021 +#define IDM_SCENARIO_CUSTOM_SCHEME_NAVIGATE 2022 +#define IDM_SCENARIO_SHARED_WORKER 2023 +#define IDM_SCENARIO_BROWSER_PRINT_PREVIEW 2029 +#define IDM_SCENARIO_SYSTEM_PRINT 2030 +#define IDM_SCENARIO_PRINT_TO_DEFAULT_PRINTER 2031 +#define IDM_SCENARIO_PRINT_TO_PRINTER 2032 +#define IDM_SCENARIO_PRINT_TO_PDF_STREAM 2033 +#define IDM_SCENARIO_SHARED_BUFFER 2034 +#define IDM_SCENARIO_DROPPED_FILE_PATH 2035 +#define IDM_PERMISSION_MANAGEMENT 2036 +#define IDM_SCENARIO_CLEAR_CUSTOM_DATA_PARTITION 2037 +#define IDM_SCENARIO_NON_CLIENT_REGION_SUPPORT 2038 +#define IDM_SCENARIO_NOTIFICATION 2039 +#define IDM_SCENARIO_SAVE_AS_TOGGLE_SILENT 2040 +#define IDM_SCENARIO_SAVE_AS_PROGRAMMATIC 2041 +#define IDM_SCENARIO_ACCELERATOR_KEY_PRESSED 2042 +#define IDM_START_FIND 2043 +#define IDM_STOP_FIND 2044 +#define IDM_FIND_NEXT 2045 +#define IDM_FIND_PREVIOUS 2046 +#define IDM_GET_MATCHES 2047 +#define IDM_GET_ACTIVE_MATCH_INDEX 2048 +#define IDM_SCENARIO_FILE_TYPE_POLICY 2049 +#define IDM_SCENARIO_SERVICE_WORKER_REGISTRATION_REQUESTED 2050 +#define IDM_SCENARIO_DEDICATED_WORKER 2051 +#define IDM_SCENARIO_SHARED_WORKER_MANAGER 2052 +#define IDM_SCENARIO_GET_SERVICE_WORKER_REGISTRATIONS 2053 +#define IDM_SCENARIO_GET_SERVICE_WORKER_REGISTERED_FOR_SCOPE 2054 +#define IDM_SCENARIO_GET_SHARED_WORKERS 2055 +#define IDM_SCENARIO_WINDOW_CONTROLS_OVERLAY 2057 +#define IDM_SCENARIO_DRAG_DROP_OVERRIDE 2058 +#define IDC_FIND_TERM 2059 +#define IDC_IS_CASE_SENSITIVE 2060 +#define IDC_SHOULD_MATCH_WHOLE_WORD 2061 +#define IDC_SHOULD_HIGHLIGHT_ALL_MATCHES 2062 +#define IDC_SUPPRESS_DEFAULT_FIND_DIALOG 2063 +#define IDM_SCENARIO_SENSITIVITY_LABEL_START_TEST 2064 +#define IDM_SCENARIO_SENSITIVITY_LABEL_TOGGLE_EVENTS 2065 +#define IDM_SCENARIO_PIRM_SET_ALLOWLIST 2066 +#define IDM_SCENARIO_PIRM_CHECK_AVAILABILITY 2067 +#define IDM_SCENARIO_SERVICE_WORKER_WRR 2068 +#define IDM_CREATION_MODE_WINDOWED 3000 +#define IDM_CREATION_MODE_VISUAL_DCOMP 3001 +#define IDM_CREATION_MODE_TARGET_DCOMP 3002 +#define IDM_CREATION_MODE_VISUAL_WINCOMP 3003 +#define IDM_CREATION_MODE_HOST_INPUT_PROCESSING 3006 +#define IDM_SCENARIO_DEDICATED_WORKER_POST_MESSAGE 3009 +#define IDM_SCENARIO_SERVICE_WORKER_POST_MESSAGE 3010 +#define IDM_SCENARIO_WEBRTC_UDP_PORT_CONFIGURATION 3011 +#define IDM_TOGGLE_SERVICE_WORKER_JS_API_SETTING 3012 #define ID_BLOCKEDSITES 32773 #define ID_SETTINGS_NAVIGATETOSTRING 32774 #define ID_ADD_INITIALIZE_SCRIPT 32775 @@ -171,9 +239,28 @@ #define ID_SETTINGS_PINCH_ZOOM_ENABLED 32787 #define ID_SETTINGS_SWIPE_NAVIGATION_ENABLED 32788 #define ID_TOGGLE_CLIENT_CERTIFICATE_REQUESTED 32789 -#define ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS 32790 #define ID_TOGGLE_CUSTOM_CONTEXT_MENU 32791 #define ID_TOGGLE_ALLOW_EXTERNAL_DROP 32792 +#define ID_SETTINGS_TOGGLE_POST_STATUS_BAR_ACTIVITY 32793 +#define ID_SETTINGS_TOGGLE_POST_FAVICON_CHANGED 32794 +#define ID_SETTINGS_PROFILE_GENERAL_AUTOFILL_ENABLED 32795 +#define ID_SETTINGS_PROFILE_PASSWORD_AUTOSAVE_ENABLED 32796 +#define ID_TOGGLE_CUSTOM_SERVER_CERTIFICATE_SUPPORT 32797 +#define ID_CLEAR_SERVER_CERTIFICATE_ERROR_ACTIONS 32798 +#define ID_SETTINGS_SMART_SCREEN_ENABLED 32799 +#define ID_SETTINGS_PROFILE_DELETE 32800 +#define IDC_EDIT_LOCALE 32801 +#define ID_TOGGLE_LAUNCHING_EXTERNAL_URI_SCHEME_ENABLED 32802 +#define IDC_CHECK_USE_OS_REGION 32803 +#define ID_CUSTOM_DATA_PARTITION 32804 +#define ID_SETTINGS_NON_CLIENT_REGION_SUPPORT_ENABLED 32805 +#define ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_NONE 32853 +#define ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_LEFT 32854 +#define ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_CENTER 32855 +#define ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_RIGHT 32856 +#define ID_SETTINGS_TOGGLE_HIDE_PDF_TOOLBAR_ITEMS_ALL 32857 +#define IDM_SCENARIO_THROTTLING_CONTROL 32807 +#define IDM_SCENARIO_SCREEN_CAPTURE 32809 #define IDC_STATIC -1 // Next default values for new objects // @@ -181,7 +268,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NO_MFC 1 #define _APS_NEXT_RESOURCE_VALUE 245 -#define _APS_NEXT_COMMAND_VALUE 32795 +#define _APS_NEXT_COMMAND_VALUE 32858 #define _APS_NEXT_CONTROL_VALUE 1015 #define _APS_NEXT_SYMED_VALUE 110 #endif diff --git a/SampleApps/WebView2APISample/stdafx.h b/SampleApps/WebView2APISample/stdafx.h index 4c6bb77e..4509b7a4 100644 --- a/SampleApps/WebView2APISample/stdafx.h +++ b/SampleApps/WebView2APISample/stdafx.h @@ -17,5 +17,5 @@ #include #include -#include "webview2experimental.h" +#include "WebView2Experimental.h" #include "WebView2ExperimentalEnvironmentOptions.h" diff --git a/SampleApps/WebView2APISample/targetver.h b/SampleApps/WebView2APISample/targetver.h index 1048c990..6870b268 100644 --- a/SampleApps/WebView2APISample/targetver.h +++ b/SampleApps/WebView2APISample/targetver.h @@ -4,10 +4,10 @@ #pragma once -// Including SDKDDKVer.h defines the highest available Windows platform. +// Including sdkddkver.h defines the highest available Windows platform. // If you wish to build your application for a previous Windows platform, // include WinSDKVer.h and set the _WIN32_WINNT macro to the platform you wish -// to support before including SDKDDKVer.h. +// to support before including sdkddkver.h. -#include +#include diff --git a/SampleApps/WebView2SampleWinComp/CompositionHost.cpp b/SampleApps/WebView2SampleWinComp/CompositionHost.cpp index ea544059..bf9de36a 100644 --- a/SampleApps/WebView2SampleWinComp/CompositionHost.cpp +++ b/SampleApps/WebView2SampleWinComp/CompositionHost.cpp @@ -4,6 +4,7 @@ #include "pch.h" +#include #include "CheckFailure.h" #include "CompositionHost.h" #include diff --git a/SampleApps/WebView2SampleWinComp/README.md b/SampleApps/WebView2SampleWinComp/README.md index 8eecbdf7..3f7ade34 100644 --- a/SampleApps/WebView2SampleWinComp/README.md +++ b/SampleApps/WebView2SampleWinComp/README.md @@ -1,34 +1,26 @@ -# WebView2 Sample WinComp - -This is a hybrid application built with the [Microsoft Edge WebView2](https://aka.ms/webview2) control. - -![Sample App Snapshot](./screenshots/WinComp-Sample-App-Screenshot.png) - -The WebView2SampleWinComp is an example of an application that embeds a WebView within a Win32 native application. It is built as a Win32 [Visual Studio 2019](https://visualstudio.microsoft.com/vs/) project and makes use of both C++ and HTML/CSS/JavaScript in the WebView2 environment. It also uses [Windows Runtime Composition APIs](https://docs.microsoft.com/uwp/api/windows.ui.composition?view=winrt-19041) (also called the Visual layer) to take avantage of the latest Windows 10 UI features and create better look, feel, and functionality in C++ Win32 applications. - -The API Sample showcases a selection of WebView2's event handlers and API methods that allow a native Win32 application to directly interact with a WebView and vice versa. - -If this is your first time using WebView, we recommend first following the [Getting Started](https://docs.microsoft.com/microsoft-edge/webview2/gettingstarted/win32) guide, which goes over how to create a WebView2 and walks through some basic WebView2 functionality. - -To learn more specifics about events and API Handlers in WebView2, you can refer to the [WebView2 Reference Documentation](https://docs.microsoft.com/microsoft-edge/webview2/webview2-api-reference). - -## Prerequisites - -- [Microsoft Edge (Chromium)](https://www.microsoftedgeinsider.com/download/) installed on a supported OS. Currently we recommend the latest version of the Edge Canary channel. -- [Visual Studio](https://visualstudio.microsoft.com/vs/) with C++ support installed. -- Latest pre-release version of our [WebView2 SDK](https://aka.ms/webviewnuget), which is included in this project. - -## Build the WebView2 Sample WinComp - -Clone the repository and open the solution in Visual Studio. WebView2 is already included as a NuGet package* in this project. - -- Clone this repository -- Open the solution in Visual Studio 2019** -- Set the target you want to build (Debug/Release, x86/x64/ARM64) -- Build the project file: _WebView2SampleWinComp.vcxproj_ - -That's it! Everything should be ready to just launch the app. - -*You can get the WebView2 NugetPackage through the Visual Studio NuGet Package Manager. - -**You can also use Visual Studio 2017 by changing the project's Platform Toolset in Project Properties/Configuration properties/General/Platform Toolset. You might also need to change the Windows SDK to the latest version available to you. +--- +description: "Demonstrates the features and usage patterns of WebView2 in a Win32 app with Visual layer composition." +extendedZipContent: + - + path: SharedContent + target: SharedContent + - + path: LICENSE + target: LICENSE +languages: + - cpp +page_type: sample +products: + - microsoft-edge +urlFragment: WebView2SampleWinComp +--- +# Win32 sample app with Visual Composition + + +This sample, **WebView2SampleWinComp**, embeds a WebView within a Win32 native application. This sample uses Windows Runtime Composition APIs (also called the Visual layer) to take advantage of the latest Windows 10 UI features and create better look, feel, and functionality in C++ Win32 applications. + +This sample is built as a Win32 Visual Studio 2019 project. It uses C++ and HTML/CSS/JavaScript in the WebView2 environment. + +To use this sample, see [Win32 sample app with Visual Composition](https://learn.microsoft.com/microsoft-edge/webview2/samples/webview2samplewincomp). + +![The WebView2SampleWinComp sample app running](screenshots/wincomp-sample-app-running.png) diff --git a/SampleApps/WebView2SampleWinComp/WebView2SampleWinComp.vcxproj b/SampleApps/WebView2SampleWinComp/WebView2SampleWinComp.vcxproj index 73c4fb8f..4ee9c6ca 100644 --- a/SampleApps/WebView2SampleWinComp/WebView2SampleWinComp.vcxproj +++ b/SampleApps/WebView2SampleWinComp/WebView2SampleWinComp.vcxproj @@ -23,7 +23,7 @@ Win32Proj {abac8d87-c87b-455c-8340-0a9b0cd9a206} WebView2SampleWinComp - 10.0.18362.0 + 10.0 diff --git a/SampleApps/WebView2SampleWinComp/screenshots/WinComp-Sample-App-Screenshot.png b/SampleApps/WebView2SampleWinComp/screenshots/wincomp-sample-app-running.png similarity index 100% rename from SampleApps/WebView2SampleWinComp/screenshots/WinComp-Sample-App-Screenshot.png rename to SampleApps/WebView2SampleWinComp/screenshots/wincomp-sample-app-running.png diff --git a/SampleApps/WebView2Samples.sln b/SampleApps/WebView2Samples.sln index 6badb64f..9ff80692 100644 --- a/SampleApps/WebView2Samples.sln +++ b/SampleApps/WebView2Samples.sln @@ -27,14 +27,6 @@ Global Release|ARM64 = Release|ARM64 Release|x64 = Release|x64 Release|x86 = Release|x86 - Win7 Debug|Any CPU = Win7 Debug|Any CPU - Win7 Debug|ARM64 = Win7 Debug|ARM64 - Win7 Debug|x64 = Win7 Debug|x64 - Win7 Debug|x86 = Win7 Debug|x86 - Win7 Release|Any CPU = Win7 Release|Any CPU - Win7 Release|ARM64 = Win7 Release|ARM64 - Win7 Release|x64 = Win7 Release|x64 - Win7 Release|x86 = Win7 Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {4F0CEEF3-12B3-425E-9BB0-105200411592}.Debug|Any CPU.ActiveCfg = Debug|Win32 @@ -51,20 +43,6 @@ Global {4F0CEEF3-12B3-425E-9BB0-105200411592}.Release|x64.Build.0 = Release|x64 {4F0CEEF3-12B3-425E-9BB0-105200411592}.Release|x86.ActiveCfg = Release|Win32 {4F0CEEF3-12B3-425E-9BB0-105200411592}.Release|x86.Build.0 = Release|Win32 - {4F0CEEF3-12B3-425E-9BB0-105200411592}.Win7 Debug|Any CPU.ActiveCfg = Win7 Debug|Win32 - {4F0CEEF3-12B3-425E-9BB0-105200411592}.Win7 Debug|ARM64.ActiveCfg = Win7 Debug|ARM64 - {4F0CEEF3-12B3-425E-9BB0-105200411592}.Win7 Debug|ARM64.Build.0 = Win7 Debug|ARM64 - {4F0CEEF3-12B3-425E-9BB0-105200411592}.Win7 Debug|x64.ActiveCfg = Win7 Debug|x64 - {4F0CEEF3-12B3-425E-9BB0-105200411592}.Win7 Debug|x64.Build.0 = Win7 Debug|x64 - {4F0CEEF3-12B3-425E-9BB0-105200411592}.Win7 Debug|x86.ActiveCfg = Win7 Debug|Win32 - {4F0CEEF3-12B3-425E-9BB0-105200411592}.Win7 Debug|x86.Build.0 = Win7 Debug|Win32 - {4F0CEEF3-12B3-425E-9BB0-105200411592}.Win7 Release|Any CPU.ActiveCfg = Win7 Release|Win32 - {4F0CEEF3-12B3-425E-9BB0-105200411592}.Win7 Release|ARM64.ActiveCfg = Win7 Release|ARM64 - {4F0CEEF3-12B3-425E-9BB0-105200411592}.Win7 Release|ARM64.Build.0 = Win7 Release|ARM64 - {4F0CEEF3-12B3-425E-9BB0-105200411592}.Win7 Release|x64.ActiveCfg = Win7 Release|x64 - {4F0CEEF3-12B3-425E-9BB0-105200411592}.Win7 Release|x64.Build.0 = Win7 Release|x64 - {4F0CEEF3-12B3-425E-9BB0-105200411592}.Win7 Release|x86.ActiveCfg = Win7 Release|Win32 - {4F0CEEF3-12B3-425E-9BB0-105200411592}.Win7 Release|x86.Build.0 = Win7 Release|Win32 {59031776-19E7-442A-92DC-39165BD2DA0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {59031776-19E7-442A-92DC-39165BD2DA0A}.Debug|Any CPU.Build.0 = Debug|Any CPU {59031776-19E7-442A-92DC-39165BD2DA0A}.Debug|ARM64.ActiveCfg = Debug|Any CPU @@ -81,22 +59,6 @@ Global {59031776-19E7-442A-92DC-39165BD2DA0A}.Release|x64.Build.0 = Release|Any CPU {59031776-19E7-442A-92DC-39165BD2DA0A}.Release|x86.ActiveCfg = Release|Any CPU {59031776-19E7-442A-92DC-39165BD2DA0A}.Release|x86.Build.0 = Release|Any CPU - {59031776-19E7-442A-92DC-39165BD2DA0A}.Win7 Debug|Any CPU.ActiveCfg = Win7 Debug|Any CPU - {59031776-19E7-442A-92DC-39165BD2DA0A}.Win7 Debug|Any CPU.Build.0 = Win7 Debug|Any CPU - {59031776-19E7-442A-92DC-39165BD2DA0A}.Win7 Debug|ARM64.ActiveCfg = Win7 Debug|Any CPU - {59031776-19E7-442A-92DC-39165BD2DA0A}.Win7 Debug|ARM64.Build.0 = Win7 Debug|Any CPU - {59031776-19E7-442A-92DC-39165BD2DA0A}.Win7 Debug|x64.ActiveCfg = Win7 Debug|Any CPU - {59031776-19E7-442A-92DC-39165BD2DA0A}.Win7 Debug|x64.Build.0 = Win7 Debug|Any CPU - {59031776-19E7-442A-92DC-39165BD2DA0A}.Win7 Debug|x86.ActiveCfg = Win7 Debug|Any CPU - {59031776-19E7-442A-92DC-39165BD2DA0A}.Win7 Debug|x86.Build.0 = Win7 Debug|Any CPU - {59031776-19E7-442A-92DC-39165BD2DA0A}.Win7 Release|Any CPU.ActiveCfg = Win7 Release|Any CPU - {59031776-19E7-442A-92DC-39165BD2DA0A}.Win7 Release|Any CPU.Build.0 = Win7 Release|Any CPU - {59031776-19E7-442A-92DC-39165BD2DA0A}.Win7 Release|ARM64.ActiveCfg = Win7 Release|Any CPU - {59031776-19E7-442A-92DC-39165BD2DA0A}.Win7 Release|ARM64.Build.0 = Win7 Release|Any CPU - {59031776-19E7-442A-92DC-39165BD2DA0A}.Win7 Release|x64.ActiveCfg = Win7 Release|Any CPU - {59031776-19E7-442A-92DC-39165BD2DA0A}.Win7 Release|x64.Build.0 = Win7 Release|Any CPU - {59031776-19E7-442A-92DC-39165BD2DA0A}.Win7 Release|x86.ActiveCfg = Win7 Release|Any CPU - {59031776-19E7-442A-92DC-39165BD2DA0A}.Win7 Release|x86.Build.0 = Win7 Release|Any CPU {68762FAD-5D35-4D53-B15B-36B521C4494E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {68762FAD-5D35-4D53-B15B-36B521C4494E}.Debug|Any CPU.Build.0 = Debug|Any CPU {68762FAD-5D35-4D53-B15B-36B521C4494E}.Debug|ARM64.ActiveCfg = Debug|Any CPU @@ -113,22 +75,6 @@ Global {68762FAD-5D35-4D53-B15B-36B521C4494E}.Release|x64.Build.0 = Release|Any CPU {68762FAD-5D35-4D53-B15B-36B521C4494E}.Release|x86.ActiveCfg = Release|Any CPU {68762FAD-5D35-4D53-B15B-36B521C4494E}.Release|x86.Build.0 = Release|Any CPU - {68762FAD-5D35-4D53-B15B-36B521C4494E}.Win7 Debug|Any CPU.ActiveCfg = Win7 Debug|Any CPU - {68762FAD-5D35-4D53-B15B-36B521C4494E}.Win7 Debug|Any CPU.Build.0 = Win7 Debug|Any CPU - {68762FAD-5D35-4D53-B15B-36B521C4494E}.Win7 Debug|ARM64.ActiveCfg = Win7 Debug|Any CPU - {68762FAD-5D35-4D53-B15B-36B521C4494E}.Win7 Debug|ARM64.Build.0 = Win7 Debug|Any CPU - {68762FAD-5D35-4D53-B15B-36B521C4494E}.Win7 Debug|x64.ActiveCfg = Win7 Debug|Any CPU - {68762FAD-5D35-4D53-B15B-36B521C4494E}.Win7 Debug|x64.Build.0 = Win7 Debug|Any CPU - {68762FAD-5D35-4D53-B15B-36B521C4494E}.Win7 Debug|x86.ActiveCfg = Win7 Debug|Any CPU - {68762FAD-5D35-4D53-B15B-36B521C4494E}.Win7 Debug|x86.Build.0 = Win7 Debug|Any CPU - {68762FAD-5D35-4D53-B15B-36B521C4494E}.Win7 Release|Any CPU.ActiveCfg = Win7 Release|Any CPU - {68762FAD-5D35-4D53-B15B-36B521C4494E}.Win7 Release|Any CPU.Build.0 = Win7 Release|Any CPU - {68762FAD-5D35-4D53-B15B-36B521C4494E}.Win7 Release|ARM64.ActiveCfg = Win7 Release|Any CPU - {68762FAD-5D35-4D53-B15B-36B521C4494E}.Win7 Release|ARM64.Build.0 = Win7 Release|Any CPU - {68762FAD-5D35-4D53-B15B-36B521C4494E}.Win7 Release|x64.ActiveCfg = Win7 Release|Any CPU - {68762FAD-5D35-4D53-B15B-36B521C4494E}.Win7 Release|x64.Build.0 = Win7 Release|Any CPU - {68762FAD-5D35-4D53-B15B-36B521C4494E}.Win7 Release|x86.ActiveCfg = Win7 Release|Any CPU - {68762FAD-5D35-4D53-B15B-36B521C4494E}.Win7 Release|x86.Build.0 = Win7 Release|Any CPU {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Debug|Any CPU.ActiveCfg = Debug|x86 {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Debug|ARM64.ActiveCfg = Debug|x86 {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Debug|x64.ActiveCfg = Debug|x86 @@ -139,22 +85,6 @@ Global {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Release|x64.ActiveCfg = Release|x86 {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Release|x86.ActiveCfg = Release|x86 {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Release|x86.Build.0 = Release|x86 - {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Win7 Debug|Any CPU.ActiveCfg = Debug|x86 - {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Win7 Debug|Any CPU.Build.0 = Debug|x86 - {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Win7 Debug|ARM64.ActiveCfg = Debug|x86 - {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Win7 Debug|ARM64.Build.0 = Debug|x86 - {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Win7 Debug|x64.ActiveCfg = Debug|x86 - {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Win7 Debug|x64.Build.0 = Debug|x86 - {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Win7 Debug|x86.ActiveCfg = Debug|x86 - {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Win7 Debug|x86.Build.0 = Debug|x86 - {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Win7 Release|Any CPU.ActiveCfg = Release|x86 - {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Win7 Release|Any CPU.Build.0 = Release|x86 - {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Win7 Release|ARM64.ActiveCfg = Release|x86 - {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Win7 Release|ARM64.Build.0 = Release|x86 - {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Win7 Release|x64.ActiveCfg = Release|x86 - {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Win7 Release|x64.Build.0 = Release|x86 - {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Win7 Release|x86.ActiveCfg = Release|x86 - {3494E3E2-CB03-4283-B8F8-E1158CDBAF3F}.Win7 Release|x86.Build.0 = Release|x86 {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Debug|Any CPU.ActiveCfg = Debug|x86 {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Debug|ARM64.ActiveCfg = Debug|x86 {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Debug|x64.ActiveCfg = Debug|x86 @@ -165,22 +95,6 @@ Global {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Release|x64.ActiveCfg = Release|x86 {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Release|x86.ActiveCfg = Release|x86 {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Release|x86.Build.0 = Release|x86 - {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Win7 Debug|Any CPU.ActiveCfg = Debug|x86 - {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Win7 Debug|Any CPU.Build.0 = Debug|x86 - {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Win7 Debug|ARM64.ActiveCfg = Debug|x86 - {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Win7 Debug|ARM64.Build.0 = Debug|x86 - {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Win7 Debug|x64.ActiveCfg = Debug|x86 - {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Win7 Debug|x64.Build.0 = Debug|x86 - {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Win7 Debug|x86.ActiveCfg = Debug|x86 - {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Win7 Debug|x86.Build.0 = Debug|x86 - {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Win7 Release|Any CPU.ActiveCfg = Release|x86 - {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Win7 Release|Any CPU.Build.0 = Release|x86 - {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Win7 Release|ARM64.ActiveCfg = Release|x86 - {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Win7 Release|ARM64.Build.0 = Release|x86 - {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Win7 Release|x64.ActiveCfg = Release|x86 - {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Win7 Release|x64.Build.0 = Release|x86 - {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Win7 Release|x86.ActiveCfg = Release|x86 - {352113BF-FB17-4FD4-A47B-7D1013BFB8AE}.Win7 Release|x86.Build.0 = Release|x86 {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Debug|Any CPU.Build.0 = Debug|Any CPU {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Debug|ARM64.ActiveCfg = Debug|Any CPU @@ -197,22 +111,6 @@ Global {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Release|x64.Build.0 = Release|Any CPU {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Release|x86.ActiveCfg = Release|Any CPU {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Release|x86.Build.0 = Release|Any CPU - {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Win7 Debug|Any CPU.ActiveCfg = Debug|Any CPU - {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Win7 Debug|Any CPU.Build.0 = Debug|Any CPU - {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Win7 Debug|ARM64.ActiveCfg = Debug|Any CPU - {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Win7 Debug|ARM64.Build.0 = Debug|Any CPU - {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Win7 Debug|x64.ActiveCfg = Debug|Any CPU - {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Win7 Debug|x64.Build.0 = Debug|Any CPU - {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Win7 Debug|x86.ActiveCfg = Debug|Any CPU - {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Win7 Debug|x86.Build.0 = Debug|Any CPU - {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Win7 Release|Any CPU.ActiveCfg = Release|Any CPU - {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Win7 Release|Any CPU.Build.0 = Release|Any CPU - {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Win7 Release|ARM64.ActiveCfg = Release|Any CPU - {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Win7 Release|ARM64.Build.0 = Release|Any CPU - {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Win7 Release|x64.ActiveCfg = Release|Any CPU - {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Win7 Release|x64.Build.0 = Release|Any CPU - {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Win7 Release|x86.ActiveCfg = Release|Any CPU - {33C09167-E167-42FB-AECA-5BF6C24C3C40}.Win7 Release|x86.Build.0 = Release|Any CPU {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Debug|Any CPU.ActiveCfg = Debug|Win32 {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Debug|ARM64.ActiveCfg = Debug|Win32 {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Debug|x64.ActiveCfg = Debug|x64 @@ -225,22 +123,6 @@ Global {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Release|x64.Build.0 = Release|x64 {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Release|x86.ActiveCfg = Release|Win32 {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Release|x86.Build.0 = Release|Win32 - {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Win7 Debug|Any CPU.ActiveCfg = Debug|Win32 - {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Win7 Debug|Any CPU.Build.0 = Debug|Win32 - {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Win7 Debug|ARM64.ActiveCfg = Debug|Win32 - {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Win7 Debug|ARM64.Build.0 = Debug|Win32 - {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Win7 Debug|x64.ActiveCfg = Debug|x64 - {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Win7 Debug|x64.Build.0 = Debug|x64 - {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Win7 Debug|x86.ActiveCfg = Debug|Win32 - {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Win7 Debug|x86.Build.0 = Debug|Win32 - {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Win7 Release|Any CPU.ActiveCfg = Debug|Win32 - {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Win7 Release|Any CPU.Build.0 = Debug|Win32 - {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Win7 Release|ARM64.ActiveCfg = Debug|Win32 - {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Win7 Release|ARM64.Build.0 = Debug|Win32 - {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Win7 Release|x64.ActiveCfg = Release|x64 - {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Win7 Release|x64.Build.0 = Release|x64 - {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Win7 Release|x86.ActiveCfg = Release|Win32 - {ABAC8D87-C87B-455C-8340-0A9B0CD9A206}.Win7 Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SampleApps/WebView2WindowsFormsBrowser/BridgeAddRemoteObject.cs b/SampleApps/WebView2WindowsFormsBrowser/BridgeAddRemoteObject.cs new file mode 100644 index 00000000..307ed34a --- /dev/null +++ b/SampleApps/WebView2WindowsFormsBrowser/BridgeAddRemoteObject.cs @@ -0,0 +1,115 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +using System.Runtime.InteropServices; +using System.Collections.Generic; +using System.Reflection; +using System; +using System.Threading.Tasks; + +namespace WebView2WindowsFormsBrowser +{ + // BridgeAddRemoteObject is a .NET object that implements IDispatch and works with AddRemoteObject. + // See the AddRemoteObjectCmdExecute method that demonstrates how to use it from JavaScript. +#pragma warning disable CS0618 + // The.NET version of CoreWebView2.AddHostObjectToScript currently relies on the host object + // implementing IDispatch and so uses the deprecated ClassInterfaceType.AutoDual feature of.NET. + // This may change in the future, please see https://github.com/MicrosoftEdge/WebView2Feedback/issues/517 for more information + [ClassInterface(ClassInterfaceType.AutoDual)] +#pragma warning restore CS0618 + [ComVisible(true)] + public class AnotherRemoteObject + { + + // Sample property. + public string Prop { get; set; } = "AnotherRemoteObject.Prop"; + } + +#pragma warning disable CS0618 + [ClassInterface(ClassInterfaceType.AutoDual)] +#pragma warning restore CS0618 + [ComVisible(true)] + public class BridgeAddRemoteObject + { + // Sample function that takes a parameter. + public string Func(string param) + { + return "BridgeAddRemoteObject.Func(" + param + ")"; + } + + public async Task FuncAsync(int msDelay) + { + if (msDelay > 0) + { + await Task.Delay(msDelay); + } + return $"BridgeAddRemoteObject.FuncAsync({msDelay})"; + } + + public async Task FuncAsyncTaskVoid(int msDelay) + { + await Task.Delay(msDelay); + } + + // Sample function that takes no parameters. + public string Func2() + { + return "BridgeAddRemoteObject.Func2()"; + } + + public async Task Func2Async() + { + await Task.Delay(500); + return "BridgeAddRemoteObject.Func2Async()"; + } + + public async Task Func2AsyncTaskVoid() + { + await Task.Delay(500); + } + + // Get type of an object. + public string GetObjectType(object obj) + { + return obj.GetType().Name; + } + + public async Task GetObjectTypeAsync(object obj) + { + await Task.Delay(500); + return GetObjectType(obj); + } + + // Sample property. + public string Prop { get; set; } = "BridgeAddRemoteObject.Prop"; + + public DateTime DateProp { get; set; } = DateTime.UtcNow; + + public AnotherRemoteObject AnotherObject { get; set; } = new AnotherRemoteObject(); + + // Sample indexed property. + [System.Runtime.CompilerServices.IndexerName("Items")] + public string this[int index] + { + get { return m_dictionary[index]; } + set { m_dictionary[index] = value; } + } + private Dictionary m_dictionary = new Dictionary(); + + public void InvokeEvent() + { + TestEvent0?.Invoke(); + TestEvent1?.Invoke("param1"); + TestEvent2?.Invoke("param1", DateTime.UtcNow); + } +#pragma warning disable CS0067 + public delegate void TestEvent0Delegate(); + public event TestEvent0Delegate TestEvent0; + public delegate void TestEvent1Delegate(String param1); + public event TestEvent1Delegate TestEvent1; + public delegate void TestEvent2Delegate(String param1, DateTime param2); + public event TestEvent2Delegate TestEvent2; +#pragma warning restore CS0067 + } +} diff --git a/SampleApps/WebView2WindowsFormsBrowser/BrowserForm.Designer.cs b/SampleApps/WebView2WindowsFormsBrowser/BrowserForm.Designer.cs index 00486f69..cf403323 100644 --- a/SampleApps/WebView2WindowsFormsBrowser/BrowserForm.Designer.cs +++ b/SampleApps/WebView2WindowsFormsBrowser/BrowserForm.Designer.cs @@ -3,6 +3,7 @@ // found in the LICENSE file. using System; +using Microsoft.Web.WebView2.Core; namespace WebView2WindowsFormsBrowser { @@ -42,10 +43,20 @@ private void InitializeComponent() this.btnGo = new System.Windows.Forms.Button(); this.txtUrl = new System.Windows.Forms.TextBox(); this.menuStrip1 = new System.Windows.Forms.MenuStrip(); + this.windowToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.closeWebViewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.createWebViewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.createNewWindowToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.createNewWindowWithOptionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.createNewThreadToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.controlToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.acceleratorKeysEnabledToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.viewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.scriptToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.zoomToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.clearBrowsingDataStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.clientCertificateRequestedStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.cookieManagementStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.xToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.xToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); this.xToolStripMenuItem2 = new System.Windows.Forms.ToolStripMenuItem(); @@ -53,9 +64,63 @@ private void InitializeComponent() this.backgroundColorMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.blueBackgroundColorMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.redBackgroundColorMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.whiteBackgroundColorMeuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.whiteBackgroundColorMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.taskManagerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.methodCDPToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.transparentBackgroundColorMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.webViewLogoBitmap = new System.Drawing.Bitmap(@"assets\EdgeWebView2-80.jpg"); + this.allowExternalDropMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.setUsersAgentMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.getDocumentTitleMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.exitMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.getUserDataFolderMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.printToPDFMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.portraitMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.landscapeMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toggleVisibilityMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.serverCertificateErrorMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toggleCustomServerCertificateSupportMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.clearServerCertificateErrorActionsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toggleDefaultScriptDialogsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.scenarioToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.addRemoteObjectMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.domContentLoadedMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.navigateWithWebResourceRequestMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.webMessageMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.processToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.showBrowserProcessInfoMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.crashBrowserProcessMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.crashRendererProcessMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.showPerformanceInfoMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.audioToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toggleMuteStateMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.blockedDomainsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.injectScriptMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.injectScriptIntoFrameMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.addInitializeScriptMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.removeInitializeScriptMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.AuthenticationMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.ClearAllDOMStorageMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.ClearAllProfileMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.ClearAllSiteMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.ClearAutofillMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.ClearBrowsingHistoryMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.ClearCookiesMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.ClearDiskCacheMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.ClearDownloadHistoryMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.CustomClientCertificateSelectionMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.DeferredCustomCertificateDialogMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.GetCookiesMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.AddOrUpdateCookieMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.DeleteCookiesMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.DeleteAllCookiesMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.postMessageStringMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.postMessageJsonMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.postMessageStringIframeMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.postMessageJsonIframeMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.webViewLogoBitmap = new System.Drawing.Bitmap(@"assets\AppStartPageBackground.png"); this.webView2Control = new Microsoft.Web.WebView2.WinForms.WebView2(); this.menuStrip1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.webView2Control)).BeginInit(); @@ -103,7 +168,7 @@ private void InitializeComponent() this.btnRefresh.Name = "btnRefresh"; this.btnRefresh.Size = new System.Drawing.Size(150, 44); this.btnRefresh.TabIndex = 2; - this.btnRefresh.Text = "Refresh"; + this.btnRefresh.Text = "Reload"; this.btnRefresh.UseVisualStyleBackColor = true; this.btnRefresh.Click += new System.EventHandler(this.BtnRefresh_Click); // @@ -114,7 +179,7 @@ private void InitializeComponent() this.btnStop.Name = "btnStop"; this.btnStop.Size = new System.Drawing.Size(150, 44); this.btnStop.TabIndex = 3; - this.btnStop.Text = "Stop"; + this.btnStop.Text = "Cancel"; this.btnStop.UseVisualStyleBackColor = true; // // btnGo @@ -141,38 +206,255 @@ private void InitializeComponent() // this.menuStrip1.ImageScalingSize = new System.Drawing.Size(32, 32); this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.fileToolStripMenuItem, + this.processToolStripMenuItem, + this.windowToolStripMenuItem, this.controlToolStripMenuItem, - this.viewToolStripMenuItem}); + this.viewToolStripMenuItem, + this.scriptToolStripMenuItem, + this.scenarioToolStripMenuItem, + this.audioToolStripMenuItem, + this.helpToolStripMenuItem}); this.menuStrip1.Location = new System.Drawing.Point(0, 0); this.menuStrip1.Name = "menuStrip1"; this.menuStrip1.Size = new System.Drawing.Size(1580, 42); this.menuStrip1.TabIndex = 7; this.menuStrip1.Text = "menuStrip1"; // + // fileToolStripMenuItem + // + this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.printToPDFMenuItem,this.getDocumentTitleMenuItem,this.getUserDataFolderMenuItem,this.exitMenuItem}); + this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; + this.fileToolStripMenuItem.Size = new System.Drawing.Size(72, 38); + this.fileToolStripMenuItem.Text = "File"; + // + // getDocumentTitleMenuItem + // + this.getDocumentTitleMenuItem.Name = "getDocumentTitleMenuItem"; + this.getDocumentTitleMenuItem.Size = new System.Drawing.Size(359, 44); + this.getDocumentTitleMenuItem.Text = "Get Document Title"; + this.getDocumentTitleMenuItem.Click += new System.EventHandler(this.getDocumentTitleMenuItem_Click); + // + // exitMenuItem + // + this.exitMenuItem.Name = "exitMenuItem"; + this.exitMenuItem.Size = new System.Drawing.Size(359, 44); + this.exitMenuItem.Text = "Exit"; + this.exitMenuItem.Click += new System.EventHandler(this.exitMenuItem_Click); + // + // getUserDataFolderMenuItem + // + this.getUserDataFolderMenuItem.Name = "getUserDataFolderMenuItem"; + this.getUserDataFolderMenuItem.Size = new System.Drawing.Size(359, 44); + this.getUserDataFolderMenuItem.Text = "Get User Data Folder"; + this.getUserDataFolderMenuItem.Click += new System.EventHandler(this.getUserDataFolderMenuItem_Click); + // + // printToPDFMenuItem + // + this.printToPDFMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.portraitMenuItem, this.landscapeMenuItem}); + this.printToPDFMenuItem.Name = "printToPDFMenuItem"; + this.printToPDFMenuItem.Size = new System.Drawing.Size(359, 44); + this.printToPDFMenuItem.Text = "Print to PDF"; + // + // portraitMenuItem + // + this.portraitMenuItem.Name = "portraitMenuItem"; + this.portraitMenuItem.Size = new System.Drawing.Size(359, 44); + this.portraitMenuItem.Text = "Portrait"; + this.portraitMenuItem.Click += new System.EventHandler(this.portraitMenuItem_Click); + // + // landscapeMenuItem + // + this.landscapeMenuItem.Name = "landscapeMenuItem"; + this.landscapeMenuItem.Size = new System.Drawing.Size(359, 44); + this.landscapeMenuItem.Text = "Landscape"; + this.landscapeMenuItem.Click += new System.EventHandler(this.landscapeMenuItem_Click); + // + // windowToolStripMenuItem + // + this.windowToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.closeWebViewToolStripMenuItem, + this.createWebViewToolStripMenuItem, + this.createNewWindowToolStripMenuItem, + this.createNewWindowWithOptionsToolStripMenuItem, + this.createNewThreadToolStripMenuItem}); + this.windowToolStripMenuItem.Name = "windowToolStripMenuItem"; + this.windowToolStripMenuItem.Size = new System.Drawing.Size(72, 38); + this.windowToolStripMenuItem.Text = "Window"; + // + // closeWebViewToolStripMenuItem + // + this.closeWebViewToolStripMenuItem.Name = "closeWebViewToolStripMenuItem"; + this.closeWebViewToolStripMenuItem.Size = new System.Drawing.Size(359, 44); + this.closeWebViewToolStripMenuItem.Text = "Close WebView"; + this.closeWebViewToolStripMenuItem.Click += new System.EventHandler(this.closeWebViewToolStripMenuItem_Click); + // + // createWebViewToolStripMenuItem + // + this.createWebViewToolStripMenuItem.Name = "createWebViewToolStripMenuItem"; + this.createWebViewToolStripMenuItem.Size = new System.Drawing.Size(359, 44); + this.createWebViewToolStripMenuItem.Text = "Create WebView"; + this.createWebViewToolStripMenuItem.Click += new System.EventHandler(this.createWebViewToolStripMenuItem_Click); + // + // createNewWindowToolStripMenuItem + // + this.createNewWindowToolStripMenuItem.Name = "createNewWindowToolStripMenuItem"; + this.createNewWindowToolStripMenuItem.Size = new System.Drawing.Size(359, 44); + this.createNewWindowToolStripMenuItem.Text = "Create New Window"; + this.createNewWindowToolStripMenuItem.Click += new System.EventHandler(this.createNewWindowToolStripMenuItem_Click); + // + // createNewWindowWithOptionsToolStripMenuItem + // + this.createNewWindowWithOptionsToolStripMenuItem.Name = "createNewWindowWithOptionsToolStripMenuItem"; + this.createNewWindowWithOptionsToolStripMenuItem.Size = new System.Drawing.Size(359, 44); + this.createNewWindowWithOptionsToolStripMenuItem.Text = "Create New Window With Options"; + this.createNewWindowWithOptionsToolStripMenuItem.Click += new System.EventHandler(this.createNewWindowWithOptionsToolStripMenuItem_Click); + // + // createNewThreadToolStripMenuItem + // + this.createNewThreadToolStripMenuItem.Name = "createNewThreadToolStripMenuItem"; + this.createNewThreadToolStripMenuItem.Size = new System.Drawing.Size(359, 44); + this.createNewThreadToolStripMenuItem.Text = "Create New Thread"; + this.createNewThreadToolStripMenuItem.Click += new System.EventHandler(this.createNewThreadToolStripMenuItem_Click); + // // controlToolStripMenuItem // this.controlToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.acceleratorKeysEnabledToolStripMenuItem}); + this.acceleratorKeysEnabledToolStripMenuItem, + this.allowExternalDropMenuItem, + this.serverCertificateErrorMenuItem, + this.setUsersAgentMenuItem, + this.toggleDefaultScriptDialogsMenuItem}); this.controlToolStripMenuItem.Name = "controlToolStripMenuItem"; this.controlToolStripMenuItem.Size = new System.Drawing.Size(72, 38); - this.controlToolStripMenuItem.Text = "Control"; + this.controlToolStripMenuItem.Text = "Settings"; // - // zoomToolStripMenuItem + // acceleratorKeysEnabledToolStripMenuItem // this.acceleratorKeysEnabledToolStripMenuItem.Name = "acceleratorKeysEnabledToolStripMenuItem"; this.acceleratorKeysEnabledToolStripMenuItem.Size = new System.Drawing.Size(359, 44); - this.acceleratorKeysEnabledToolStripMenuItem.Text = "AcceleratorKeys Enabled"; + this.acceleratorKeysEnabledToolStripMenuItem.Text = "Toggle AcceleratorKeys"; this.acceleratorKeysEnabledToolStripMenuItem.Checked = true; this.acceleratorKeysEnabledToolStripMenuItem.CheckOnClick = true; + this.acceleratorKeysEnabledToolStripMenuItem.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; + // + // allowExternalDropMenuItem + // + this.allowExternalDropMenuItem.Name = "allowExternalDropMenuItem"; + this.allowExternalDropMenuItem.Size = new System.Drawing.Size(359, 44); + this.allowExternalDropMenuItem.Text = "Toggle AllowExternalDrop"; + this.allowExternalDropMenuItem.Checked = true; + this.allowExternalDropMenuItem.CheckOnClick = true; + this.allowExternalDropMenuItem.Click += new System.EventHandler(this.allowExternalDropMenuItem_Click); + this.allowExternalDropMenuItem.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; + // + // serverCertificateErrorMenuItem + // + this.serverCertificateErrorMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toggleCustomServerCertificateSupportMenuItem, + this.clearServerCertificateErrorActionsMenuItem}); + this.serverCertificateErrorMenuItem.Name = "serverCertificateErrorMenuItem"; + this.serverCertificateErrorMenuItem.Size = new System.Drawing.Size(359, 44); + this.serverCertificateErrorMenuItem.Text = "Server Certificate Error"; + // + // setUsersAgentMenuItem + // + this.setUsersAgentMenuItem.Name = "setUsersAgentMenuItem"; + this.setUsersAgentMenuItem.Size = new System.Drawing.Size(359, 44); + this.setUsersAgentMenuItem.Text = "Set Users Agent"; + this.setUsersAgentMenuItem.Click += new System.EventHandler(this.setUsersAgentMenuItem_Click); + // + // toggleCustomServerCertificateSupportMenuItem + // + this.toggleCustomServerCertificateSupportMenuItem.Name = "toggleCustomServerCertificateSupportMenuItem"; + this.toggleCustomServerCertificateSupportMenuItem.Size = new System.Drawing.Size(359, 44); + this.toggleCustomServerCertificateSupportMenuItem.Text = "Toggle Custom Server Certificate Support"; + this.toggleCustomServerCertificateSupportMenuItem.Click += new System.EventHandler(this.toggleCustomServerCertificateSupportMenuItem_Click); + this.toggleCustomServerCertificateSupportMenuItem.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; + // + // clearServerCertificateErrorActionsMenuItem + // + this.clearServerCertificateErrorActionsMenuItem.Name = "clearServerCertificateErrorActionsMenuItem"; + this.clearServerCertificateErrorActionsMenuItem.Size = new System.Drawing.Size(359, 44); + this.clearServerCertificateErrorActionsMenuItem.Text = "Clear Server Certificate Error Actions"; + this.clearServerCertificateErrorActionsMenuItem.Click += new System.EventHandler(this.clearServerCertificateErrorActionsMenuItem_Click); + // + // toggleDefaultScriptDialogsMenuItem + // + this.toggleDefaultScriptDialogsMenuItem.Name = "toggleDefaultScriptDialogsMenuItem"; + this.toggleDefaultScriptDialogsMenuItem.Size = new System.Drawing.Size(359, 44); + this.toggleDefaultScriptDialogsMenuItem.Text = "Toggle Default Script Dialogs"; + this.toggleDefaultScriptDialogsMenuItem.Click += new System.EventHandler(this.toggleDefaultScriptDialogsMenuItem_Click); + this.toggleDefaultScriptDialogsMenuItem.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; + // + // blockedDomainsMenuItem + // + this.blockedDomainsMenuItem.Name = "blockedDomainsMenuItem"; + this.blockedDomainsMenuItem.Size = new System.Drawing.Size(359, 44); + this.blockedDomainsMenuItem.Text = "Blocked Domains"; + this.blockedDomainsMenuItem.Click += new System.EventHandler(this.blockedDomainsMenuItem_Click); // // viewToolStripMenuItem // this.viewToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.zoomToolStripMenuItem, this.backgroundColorMenuItem}); + this.toggleVisibilityMenuItem, this.zoomToolStripMenuItem, this.backgroundColorMenuItem}); this.viewToolStripMenuItem.Name = "viewToolStripMenuItem"; this.viewToolStripMenuItem.Size = new System.Drawing.Size(86, 38); this.viewToolStripMenuItem.Text = "View"; // + // scriptToolStripMenuItem + // + this.scriptToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.injectScriptMenuItem, + this.injectScriptIntoFrameMenuItem, + this.methodCDPToolStripMenuItem, + this.taskManagerToolStripMenuItem, + this.postMessageStringMenuItem, + this.postMessageJsonMenuItem, + this.postMessageStringIframeMenuItem, + this.postMessageJsonIframeMenuItem, + this.addInitializeScriptMenuItem, + this.removeInitializeScriptMenuItem}); + this.scriptToolStripMenuItem.Name = "scriptToolStripMenuItem"; + this.scriptToolStripMenuItem.Size = new System.Drawing.Size(86, 38); + this.scriptToolStripMenuItem.Text = "Script"; + // + // clearBrowsingDataStripMenuItem + // + this.clearBrowsingDataStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.ClearAllDOMStorageMenuItem, this.ClearAllProfileMenuItem, this.ClearAllSiteMenuItem, this.ClearAutofillMenuItem, this.ClearBrowsingHistoryMenuItem, this.ClearCookiesMenuItem, this.ClearDiskCacheMenuItem, this.ClearDownloadHistoryMenuItem}); + this.clearBrowsingDataStripMenuItem.Name = "clearBrowsingDataStripMenuItem"; + this.clearBrowsingDataStripMenuItem.Size = new System.Drawing.Size(86, 38); + this.clearBrowsingDataStripMenuItem.Text = "Clear Browsing Data"; + // + // clientCertificateRequestedStripMenuItem + // + this.clientCertificateRequestedStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.CustomClientCertificateSelectionMenuItem, this.DeferredCustomCertificateDialogMenuItem}); + this.clientCertificateRequestedStripMenuItem.Name = "clientCertificateRequestedStripMenuItem"; + this.clientCertificateRequestedStripMenuItem.Size = new System.Drawing.Size(86, 38); + this.clientCertificateRequestedStripMenuItem.Text = "Client Certificate Request"; + // + // cookieManagementStripMenuItem + // + this.cookieManagementStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.GetCookiesMenuItem, this.AddOrUpdateCookieMenuItem, this.DeleteCookiesMenuItem, this.DeleteAllCookiesMenuItem}); + this.cookieManagementStripMenuItem.Name = "cookieManagementStripMenuItem"; + this.cookieManagementStripMenuItem.Size = new System.Drawing.Size(86, 38); + this.cookieManagementStripMenuItem.Text = "Cookie Management"; + // + // toggleVisibilityMenuItem + // + this.toggleVisibilityMenuItem.Name = "toggleVisibilityMenuItem"; + this.toggleVisibilityMenuItem.Size = new System.Drawing.Size(359, 44); + this.toggleVisibilityMenuItem.Text = "Toggle Visibility"; + this.toggleVisibilityMenuItem.Checked = true; + this.toggleVisibilityMenuItem.CheckOnClick = true; + this.toggleVisibilityMenuItem.Click += new System.EventHandler(this.toggleVisibilityMenuItem_Click); + this.toggleVisibilityMenuItem.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; + // // zoomToolStripMenuItem // this.zoomToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -215,7 +497,7 @@ private void InitializeComponent() // backgroundColorToolStripMenuItem // this.backgroundColorMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.whiteBackgroundColorMeuItem, + this.whiteBackgroundColorMenuItem, this.redBackgroundColorMenuItem, this.blueBackgroundColorMenuItem, this.transparentBackgroundColorMenuItem}); @@ -225,10 +507,10 @@ private void InitializeComponent() // // whiteBackgroundColorMenuItem // - this.whiteBackgroundColorMeuItem.Name = "whiteBackgroundColorMenuItem"; - this.whiteBackgroundColorMeuItem.Size = new System.Drawing.Size(359, 44); - this.whiteBackgroundColorMeuItem.Text = "White"; - this.whiteBackgroundColorMeuItem.Click += new System.EventHandler(this.backgroundColorMenuItem_Click); + this.whiteBackgroundColorMenuItem.Name = "whiteBackgroundColorMenuItem"; + this.whiteBackgroundColorMenuItem.Size = new System.Drawing.Size(359, 44); + this.whiteBackgroundColorMenuItem.Text = "White"; + this.whiteBackgroundColorMenuItem.Click += new System.EventHandler(this.backgroundColorMenuItem_Click); // // redBackgroundColorMenuItem // @@ -244,19 +526,314 @@ private void InitializeComponent() this.blueBackgroundColorMenuItem.Text = "Blue"; this.blueBackgroundColorMenuItem.Click += new System.EventHandler(this.backgroundColorMenuItem_Click); // + // methodCDPToolStripMenuItem + // + this.methodCDPToolStripMenuItem.Name = "methodCDPToolStripMenuItem"; + this.methodCDPToolStripMenuItem.Size = new System.Drawing.Size(359, 44); + this.methodCDPToolStripMenuItem.Text = "Call CDP Method"; + this.methodCDPToolStripMenuItem.Click += new System.EventHandler(this.methodCDPToolStripMenuItem_Click); + // + // taskManagerToolStripMenuItem + // + this.taskManagerToolStripMenuItem.Name = "methodCDPToolStripMenuItem"; + this.taskManagerToolStripMenuItem.Size = new System.Drawing.Size(359, 44); + this.taskManagerToolStripMenuItem.Text = "Open Task Manager"; + this.taskManagerToolStripMenuItem.Click += new System.EventHandler(this.taskManagerToolStripMenuItem_Click); + // + // injectScriptMenuItem + // + this.injectScriptMenuItem.Name = "injectScriptMenuItem"; + this.injectScriptMenuItem.Size = new System.Drawing.Size(359, 44); + this.injectScriptMenuItem.Text = "Inject Script"; + this.injectScriptMenuItem.Click += new System.EventHandler(this.injectScriptMenuItem_Click); + // + // injectScriptIntoFrameMenuItem + // + this.injectScriptIntoFrameMenuItem.Name = "injectScriptIntoFrameMenuItem"; + this.injectScriptIntoFrameMenuItem.Size = new System.Drawing.Size(359, 44); + this.injectScriptIntoFrameMenuItem.Text = "Inject Script Into Frame"; + this.injectScriptIntoFrameMenuItem.Click += new System.EventHandler(this.injectScriptIntoFrameMenuItem_Click); + // + // addInitializeScriptMenuItem + // + this.addInitializeScriptMenuItem.Name = "addInitializeScriptMenuItem"; + this.addInitializeScriptMenuItem.Size = new System.Drawing.Size(359, 44); + this.addInitializeScriptMenuItem.Text = "Add Initialize Script"; + this.addInitializeScriptMenuItem.Click += new System.EventHandler(this.addInitializeScriptMenuItem_Click); + // + // removeInitializeScriptMenuItem + // + this.removeInitializeScriptMenuItem.Name = "removeInitializeScriptMenuItem"; + this.removeInitializeScriptMenuItem.Size = new System.Drawing.Size(359, 44); + this.removeInitializeScriptMenuItem.Text = "Remove Initialize Script"; + this.removeInitializeScriptMenuItem.Click += new System.EventHandler(this.removeInitializeScriptMenuItem_Click); + // + // postMessageStringMenuItem + // + this.postMessageStringMenuItem.Name = "postMessageStringMenuItem"; + this.postMessageStringMenuItem.Size = new System.Drawing.Size(359, 44); + this.postMessageStringMenuItem.Text = "Post Message String"; + this.postMessageStringMenuItem.Click += new System.EventHandler(this.postMessageStringMenuItem_Click); + // + // postMessageJsonMenuItem + // + this.postMessageJsonMenuItem.Name = "postMessageJsonMenuItem"; + this.postMessageJsonMenuItem.Size = new System.Drawing.Size(359, 44); + this.postMessageJsonMenuItem.Text = "Post Message JSON"; + this.postMessageJsonMenuItem.Click += new System.EventHandler(this.postMessageJsonMenuItem_Click); + // + // postMessageStringIframeMenuItem + // + this.postMessageStringIframeMenuItem.Name = "postMessageStringIframeMenuItem"; + this.postMessageStringIframeMenuItem.Size = new System.Drawing.Size(359, 44); + this.postMessageStringIframeMenuItem.Text = "Post Message String Iframe"; + this.postMessageStringIframeMenuItem.Click += new System.EventHandler(this.postMessageStringIframeMenuItem_Click); + // + // postMessageJsonIframeMenuItem + // + this.postMessageJsonIframeMenuItem.Name = "postMessageJsonIframeMenuItem"; + this.postMessageJsonIframeMenuItem.Size = new System.Drawing.Size(359, 44); + this.postMessageJsonIframeMenuItem.Text = "Post Message JSON Iframe"; + this.postMessageJsonIframeMenuItem.Click += new System.EventHandler(this.postMessageJsonIframeMenuItem_Click); + // // transparentBackgroundColorMenuItem // this.transparentBackgroundColorMenuItem.Name = "transparentBackgroundColorMenuItem"; this.transparentBackgroundColorMenuItem.Size = new System.Drawing.Size(359, 44); this.transparentBackgroundColorMenuItem.Text = "Transparent"; this.transparentBackgroundColorMenuItem.Click += new System.EventHandler(this.backgroundColorMenuItem_Click); + // + // scenarioToolStripMenuItem + // + this.scenarioToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripMenuItem[] { + this.AuthenticationMenuItem, + this.clearBrowsingDataStripMenuItem, + this.clientCertificateRequestedStripMenuItem, + this.cookieManagementStripMenuItem, + this.addRemoteObjectMenuItem, + this.domContentLoadedMenuItem, + this.navigateWithWebResourceRequestMenuItem, + this.webMessageMenuItem }); + this.scenarioToolStripMenuItem.Name = "scenarioToolStripMenuItem"; + this.scenarioToolStripMenuItem.Size = new System.Drawing.Size(72, 38); + this.scenarioToolStripMenuItem.Text = "Scenario"; + // + // addRemoteObjectMenuItem + // + this.addRemoteObjectMenuItem.Name = "addRemoteObjectMenuItem"; + this.addRemoteObjectMenuItem.Size = new System.Drawing.Size(359, 44); + this.addRemoteObjectMenuItem.Text = "Add Remote Object"; + this.addRemoteObjectMenuItem.Click += new System.EventHandler(this.addRemoteObjectMenuItem_Click); + // + // domContentLoadedMenuItem + // + this.domContentLoadedMenuItem.Name = "domContentLoadedMenuItem"; + this.domContentLoadedMenuItem.Size = new System.Drawing.Size(359, 44); + this.domContentLoadedMenuItem.Text = "DOM Content Loaded"; + this.domContentLoadedMenuItem.Click += new System.EventHandler(this.domContentLoadedMenuItem_Click); + // + // navigateWithWebResourceRequestMenuItem + // + this.navigateWithWebResourceRequestMenuItem.Name = "navigateWithWebResourceRequestMenuItem"; + this.navigateWithWebResourceRequestMenuItem.Size = new System.Drawing.Size(359, 44); + this.navigateWithWebResourceRequestMenuItem.Text = "Navigate with WebResourceRequest"; + this.navigateWithWebResourceRequestMenuItem.Click += new System.EventHandler(this.navigateWithWebResourceRequestMenuItem_Click); + // + // webMessageMenuItem + // + this.webMessageMenuItem.Name = "webMessageMenuItem"; + this.webMessageMenuItem.Size = new System.Drawing.Size(359, 44); + this.webMessageMenuItem.Text = "Web Message"; + this.webMessageMenuItem.Click += new System.EventHandler(this.webMessageMenuItem_Click); + // + // processToolStripMenuItem + // + this.processToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.showBrowserProcessInfoMenuItem, + this.crashBrowserProcessMenuItem, + this.crashRendererProcessMenuItem, + this.showPerformanceInfoMenuItem}); + this.processToolStripMenuItem.Name = "processToolStripMenuItem"; + this.processToolStripMenuItem.Size = new System.Drawing.Size(72, 38); + this.processToolStripMenuItem.Text = "Process"; + // + // showBrowserProcessInfoMenuItem + // + this.showBrowserProcessInfoMenuItem.Name = "showBrowserProcessInfoMenuItem"; + this.showBrowserProcessInfoMenuItem.Size = new System.Drawing.Size(359, 44); + this.showBrowserProcessInfoMenuItem.Text = "Show Browser Process Info"; + this.showBrowserProcessInfoMenuItem.Click += new System.EventHandler(this.showBrowserProcessInfoMenuItem_Click); + // + // crashBrowserProcessMenuItem + // + this.crashBrowserProcessMenuItem.Name = "crashBrowserProcessMenuItem"; + this.crashBrowserProcessMenuItem.Size = new System.Drawing.Size(359, 44); + this.crashBrowserProcessMenuItem.Text = "Crash Browser Process"; + this.crashBrowserProcessMenuItem.Click += new System.EventHandler(this.crashBrowserProcessMenuItem_Click); + // + // crashRendererProcessMenuItem + // + this.crashRendererProcessMenuItem.Name = "crashRendererProcessMenuItem"; + this.crashRendererProcessMenuItem.Size = new System.Drawing.Size(359, 44); + this.crashRendererProcessMenuItem.Text = "Crash Renderer Process"; + this.crashRendererProcessMenuItem.Click += new System.EventHandler(this.crashRendererProcessMenuItem_Click); + // + // showPerformanceInfoMenuItem + // + this.showPerformanceInfoMenuItem.Name = "showPerformanceInfoMenuItem"; + this.showPerformanceInfoMenuItem.Size = new System.Drawing.Size(359, 44); + this.showPerformanceInfoMenuItem.Text = "Show Performance Info"; + this.showPerformanceInfoMenuItem.Click += new System.EventHandler(this.showPerformanceInfoMenuItem_Click); + // + // audioToolStripMenuItem + // + this.audioToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripMenuItem[] { + this.toggleMuteStateMenuItem }); + this.audioToolStripMenuItem.Name = "audioToolStripMenuItem"; + this.audioToolStripMenuItem.Size = new System.Drawing.Size(72, 38); + this.audioToolStripMenuItem.Text = "Audio"; + // + // toggleMuteStateStripMenuItem + // + this.toggleMuteStateMenuItem.Name = "toggleMuteStateMenuItem"; + this.toggleMuteStateMenuItem.Size = new System.Drawing.Size(359, 44); + this.toggleMuteStateMenuItem.Text = "Toggle Mute State"; + this.toggleMuteStateMenuItem.Click += new System.EventHandler(this.toggleMuteStateMenuItem_Click); + this.toggleMuteStateMenuItem.Checked = true; + this.toggleMuteStateMenuItem.CheckOnClick = true; + this.toggleMuteStateMenuItem.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; + // + // helpToolStripMenuItem + // + this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.aboutToolStripMenuItem }); + this.helpToolStripMenuItem.Name = "helpToolStripMenuItem"; + this.helpToolStripMenuItem.Size = new System.Drawing.Size(72, 38); + this.helpToolStripMenuItem.Text = "Help"; + // + // aboutToolStripMenuItem + // + this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem"; + this.aboutToolStripMenuItem.Size = new System.Drawing.Size(359, 44); + this.aboutToolStripMenuItem.Text = "About"; + this.aboutToolStripMenuItem.Click += new System.EventHandler(this.aboutToolStripMenuItem_Click); + // + // AuthenticationMenuItem + // + this.AuthenticationMenuItem.Name = "AuthenticationMenuItem"; + this.AuthenticationMenuItem.Size = new System.Drawing.Size(359, 44); + this.AuthenticationMenuItem.Text = "Authentication"; + this.AuthenticationMenuItem.Click += new System.EventHandler(this.AuthenticationMenuItem_Click); + // + // ClearAllDOMStorageMenuItem + // + this.ClearAllDOMStorageMenuItem.Name = "ClearAllDOMStorageMenuItem"; + this.ClearAllDOMStorageMenuItem.Size = new System.Drawing.Size(359, 44); + this.ClearAllDOMStorageMenuItem.Text = "All DOM Storage"; + this.ClearAllDOMStorageMenuItem.Click += new System.EventHandler((sender, e) => ClearBrowsingData(sender, e, CoreWebView2BrowsingDataKinds.AllDomStorage)); + // + // ClearAllProfileMenuItem + // + this.ClearAllProfileMenuItem.Name = "ClearAllProfileMenuItem"; + this.ClearAllProfileMenuItem.Size = new System.Drawing.Size(359, 44); + this.ClearAllProfileMenuItem.Text = "All Profile"; + this.ClearAllProfileMenuItem.Click += new System.EventHandler((sender, e) => ClearBrowsingData(sender, e, CoreWebView2BrowsingDataKinds.AllProfile)); + // + // ClearAllSiteMenuItem + // + this.ClearAllSiteMenuItem.Name = "ClearAllSiteMenuItem"; + this.ClearAllSiteMenuItem.Size = new System.Drawing.Size(359, 44); + this.ClearAllSiteMenuItem.Text = "All Site"; + this.ClearAllSiteMenuItem.Click += new System.EventHandler((sender, e) => ClearBrowsingData(sender, e, CoreWebView2BrowsingDataKinds.AllSite)); + // + // ClearAutofillMenuItem + // + this.ClearAutofillMenuItem.Name = "ClearAutofillMenuItem"; + this.ClearAutofillMenuItem.Size = new System.Drawing.Size(359, 44); + this.ClearAutofillMenuItem.Text = "Autofill"; + this.ClearAutofillMenuItem.Click += new System.EventHandler((sender, e) => ClearBrowsingData(sender, e, (CoreWebView2BrowsingDataKinds)(CoreWebView2BrowsingDataKinds.GeneralAutofill | CoreWebView2BrowsingDataKinds.PasswordAutosave))); + // + // ClearBrowsingHistoryMenuItem + // + this.ClearBrowsingHistoryMenuItem.Name = "ClearBrowsingHistoryMenuItem"; + this.ClearBrowsingHistoryMenuItem.Size = new System.Drawing.Size(359, 44); + this.ClearBrowsingHistoryMenuItem.Text = "Browsing History"; + this.ClearBrowsingHistoryMenuItem.Click += new System.EventHandler((sender, e) => ClearBrowsingData(sender, e, CoreWebView2BrowsingDataKinds.BrowsingHistory)); + // + // ClearCookiesMenuItem + // + this.ClearCookiesMenuItem.Name = "ClearCookiesMenuItem"; + this.ClearCookiesMenuItem.Size = new System.Drawing.Size(359, 44); + this.ClearCookiesMenuItem.Text = "Cookies"; + this.ClearCookiesMenuItem.Click += new System.EventHandler((sender, e) => ClearBrowsingData(sender, e, CoreWebView2BrowsingDataKinds.Cookies)); + // + // ClearDiskCacheMenuItem + // + this.ClearDiskCacheMenuItem.Name = "ClearDiskCacheMenuItem"; + this.ClearDiskCacheMenuItem.Size = new System.Drawing.Size(359, 44); + this.ClearDiskCacheMenuItem.Text = "Disk Cache"; + this.ClearDiskCacheMenuItem.Click += new System.EventHandler((sender, e) => ClearBrowsingData(sender, e, CoreWebView2BrowsingDataKinds.DiskCache)); + // + // ClearDownloadHistoryMenuItem + // + this.ClearDownloadHistoryMenuItem.Name = "ClearDownloadHistoryMenuItem"; + this.ClearDownloadHistoryMenuItem.Size = new System.Drawing.Size(359, 44); + this.ClearDownloadHistoryMenuItem.Text = "Download History"; + this.ClearDownloadHistoryMenuItem.Click += new System.EventHandler((sender, e) => ClearBrowsingData(sender, e, CoreWebView2BrowsingDataKinds.DownloadHistory)); + // + // CustomClientCertificateSelectionMenuItem + // + this.CustomClientCertificateSelectionMenuItem.Name = "CustomClientCertificateSelectionMenuItem"; + this.CustomClientCertificateSelectionMenuItem.Size = new System.Drawing.Size(359, 44); + this.CustomClientCertificateSelectionMenuItem.Text = "Custom Client Certificate Selection"; + this.CustomClientCertificateSelectionMenuItem.Click += new System.EventHandler(this.CustomClientCertificateSelectionMenuItem_Click); + // + // DeferredCustomCertificateDialogMenuItem + // + this.DeferredCustomCertificateDialogMenuItem.Name = "DeferredCustomCertificateDialogMenuItem"; + this.DeferredCustomCertificateDialogMenuItem.Size = new System.Drawing.Size(359, 44); + this.DeferredCustomCertificateDialogMenuItem.Text = "Deferred Custom Client Certificate Selection Dialog"; + this.DeferredCustomCertificateDialogMenuItem.Click += new System.EventHandler(this.DeferredCustomCertificateDialogMenuItem_Click); + // + // GetCookiesMenuItem + // + this.GetCookiesMenuItem.Name = "GetCookiesMenuItem"; + this.GetCookiesMenuItem.Size = new System.Drawing.Size(359, 44); + this.GetCookiesMenuItem.Text = "Get Cookies"; + this.GetCookiesMenuItem.Click += new System.EventHandler((sender, e) => GetCookiesMenuItem_Click(sender, e, txtUrl.Text)); + // + // AddOrUpdateCookieMenuItem + // + this.AddOrUpdateCookieMenuItem.Name = "AddOrUpdateCookieMenuItem"; + this.AddOrUpdateCookieMenuItem.Size = new System.Drawing.Size(359, 44); + this.AddOrUpdateCookieMenuItem.Text = "Add Or Update Cookie"; + this.AddOrUpdateCookieMenuItem.Click += new System.EventHandler((sender, e) => AddOrUpdateCookieMenuItem_Click(sender, e, new Uri(txtUrl.Text).Host)); + // + // DeleteCookiesMenuItem + // + this.DeleteCookiesMenuItem.Name = "DeleteCookiesMenuItem"; + this.DeleteCookiesMenuItem.Size = new System.Drawing.Size(359, 44); + this.DeleteCookiesMenuItem.Text = "Delete Cookie"; + this.DeleteCookiesMenuItem.Click += new System.EventHandler((sender, e) => DeleteCookiesMenuItem_Click(sender, e, new Uri(txtUrl.Text).Host)); + // + // DeleteAllCookiesMenuItem + // + this.DeleteAllCookiesMenuItem.Name = "DeleteAllCookiesMenuItem"; + this.DeleteAllCookiesMenuItem.Size = new System.Drawing.Size(359, 44); + this.DeleteAllCookiesMenuItem.Text = "Delete All Cookies"; + this.DeleteAllCookiesMenuItem.Click += new System.EventHandler(this.DeleteAllCookiesMenuItem_Click); + // // webView2Control // this.webView2Control.Location = new System.Drawing.Point(0, 96); this.webView2Control.Name = "webView2Control"; this.webView2Control.Size = new System.Drawing.Size(788, 410); + + this.webView2Control.CreationProperties = this.CreationProperties; + this.webView2Control.Source = new Uri("https://www.bing.com/"); + this.webView2Control.DefaultBackgroundColor = System.Drawing.Color.Transparent; this.webView2Control.TabIndex = 7; // // BrowserForm @@ -287,6 +864,7 @@ private void InitializeComponent() this.PerformLayout(); } #endregion + private System.Windows.Forms.Button btnEvents; private System.Windows.Forms.Button btnBack; private System.Windows.Forms.Button btnForward; @@ -297,18 +875,83 @@ private void InitializeComponent() private System.Drawing.Bitmap webViewLogoBitmap; private Microsoft.Web.WebView2.WinForms.WebView2 webView2Control; private System.Windows.Forms.MenuStrip menuStrip1; + private System.Windows.Forms.ToolStripMenuItem windowToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem closeWebViewToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem createWebViewToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem createNewWindowToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem createNewWindowWithOptionsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem createNewThreadToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem controlToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem acceleratorKeysEnabledToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem viewToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem zoomToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem clearBrowsingDataStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem clientCertificateRequestedStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem cookieManagementStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem scriptToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem xToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem xToolStripMenuItem1; private System.Windows.Forms.ToolStripMenuItem xToolStripMenuItem2; private System.Windows.Forms.ToolStripMenuItem xToolStripMenuItem3; private System.Windows.Forms.ToolStripMenuItem backgroundColorMenuItem; - private System.Windows.Forms.ToolStripMenuItem whiteBackgroundColorMeuItem; + private System.Windows.Forms.ToolStripMenuItem whiteBackgroundColorMenuItem; private System.Windows.Forms.ToolStripMenuItem redBackgroundColorMenuItem; private System.Windows.Forms.ToolStripMenuItem blueBackgroundColorMenuItem; + private System.Windows.Forms.ToolStripMenuItem taskManagerToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem methodCDPToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem transparentBackgroundColorMenuItem; + private System.Windows.Forms.ToolStripMenuItem allowExternalDropMenuItem; + private System.Windows.Forms.ToolStripMenuItem setUsersAgentMenuItem; + private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem getDocumentTitleMenuItem; + private System.Windows.Forms.ToolStripMenuItem exitMenuItem; + private System.Windows.Forms.ToolStripMenuItem getUserDataFolderMenuItem; + private System.Windows.Forms.ToolStripMenuItem printToPDFMenuItem; + private System.Windows.Forms.ToolStripMenuItem portraitMenuItem; + private System.Windows.Forms.ToolStripMenuItem landscapeMenuItem; + private System.Windows.Forms.ToolStripMenuItem toggleVisibilityMenuItem; + private System.Windows.Forms.ToolStripMenuItem serverCertificateErrorMenuItem; + private System.Windows.Forms.ToolStripMenuItem toggleCustomServerCertificateSupportMenuItem; + private System.Windows.Forms.ToolStripMenuItem clearServerCertificateErrorActionsMenuItem; + private System.Windows.Forms.ToolStripMenuItem toggleDefaultScriptDialogsMenuItem; + private System.Windows.Forms.ToolStripMenuItem scenarioToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem addRemoteObjectMenuItem; + private System.Windows.Forms.ToolStripMenuItem domContentLoadedMenuItem; + private System.Windows.Forms.ToolStripMenuItem navigateWithWebResourceRequestMenuItem; + private System.Windows.Forms.ToolStripMenuItem webMessageMenuItem; + private System.Windows.Forms.ToolStripMenuItem processToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem showBrowserProcessInfoMenuItem; + private System.Windows.Forms.ToolStripMenuItem crashBrowserProcessMenuItem; + private System.Windows.Forms.ToolStripMenuItem crashRendererProcessMenuItem; + private System.Windows.Forms.ToolStripMenuItem showPerformanceInfoMenuItem; + private System.Windows.Forms.ToolStripMenuItem audioToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem toggleMuteStateMenuItem; + private System.Windows.Forms.ToolStripMenuItem helpToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem aboutToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem blockedDomainsMenuItem; + private System.Windows.Forms.ToolStripMenuItem injectScriptMenuItem; + private System.Windows.Forms.ToolStripMenuItem injectScriptIntoFrameMenuItem; + private System.Windows.Forms.ToolStripMenuItem addInitializeScriptMenuItem; + private System.Windows.Forms.ToolStripMenuItem removeInitializeScriptMenuItem; + private System.Windows.Forms.ToolStripMenuItem AuthenticationMenuItem; + private System.Windows.Forms.ToolStripMenuItem ClearAllDOMStorageMenuItem; + private System.Windows.Forms.ToolStripMenuItem ClearAllProfileMenuItem; + private System.Windows.Forms.ToolStripMenuItem ClearAllSiteMenuItem; + private System.Windows.Forms.ToolStripMenuItem ClearAutofillMenuItem; + private System.Windows.Forms.ToolStripMenuItem ClearBrowsingHistoryMenuItem; + private System.Windows.Forms.ToolStripMenuItem ClearCookiesMenuItem; + private System.Windows.Forms.ToolStripMenuItem ClearDiskCacheMenuItem; + private System.Windows.Forms.ToolStripMenuItem ClearDownloadHistoryMenuItem; + private System.Windows.Forms.ToolStripMenuItem CustomClientCertificateSelectionMenuItem; + private System.Windows.Forms.ToolStripMenuItem DeferredCustomCertificateDialogMenuItem; + private System.Windows.Forms.ToolStripMenuItem GetCookiesMenuItem; + private System.Windows.Forms.ToolStripMenuItem AddOrUpdateCookieMenuItem; + private System.Windows.Forms.ToolStripMenuItem DeleteCookiesMenuItem; + private System.Windows.Forms.ToolStripMenuItem DeleteAllCookiesMenuItem; + private System.Windows.Forms.ToolStripMenuItem postMessageStringMenuItem; + private System.Windows.Forms.ToolStripMenuItem postMessageJsonMenuItem; + private System.Windows.Forms.ToolStripMenuItem postMessageStringIframeMenuItem; + private System.Windows.Forms.ToolStripMenuItem postMessageJsonIframeMenuItem; + } } diff --git a/SampleApps/WebView2WindowsFormsBrowser/BrowserForm.cs b/SampleApps/WebView2WindowsFormsBrowser/BrowserForm.cs index 91a78540..68368ee7 100644 --- a/SampleApps/WebView2WindowsFormsBrowser/BrowserForm.cs +++ b/SampleApps/WebView2WindowsFormsBrowser/BrowserForm.cs @@ -3,194 +3,1488 @@ // found in the LICENSE file. using System; +using System.Collections.Generic; +using System.Diagnostics; using System.Drawing; +using System.Threading; +using System.Text; +using System.IO; using System.Windows.Forms; using Microsoft.Web.WebView2.Core; +using Microsoft.Web.WebView2.WinForms; +using System.Linq; +using System.ComponentModel; namespace WebView2WindowsFormsBrowser { - public partial class BrowserForm : Form + public partial class BrowserForm : Form + { + private CoreWebView2CreationProperties _creationProperties = null; + public CoreWebView2CreationProperties CreationProperties { - public BrowserForm() + get + { + if (_creationProperties == null) { - InitializeComponent(); - AttachControlEventHandlers(this.webView2Control); - HandleResize(); + _creationProperties = new Microsoft.Web.WebView2.WinForms.CoreWebView2CreationProperties(); } + return _creationProperties; + } + set + { + _creationProperties = value; + } + } + + public BrowserForm() + { + InitializeComponent(); + AttachControlEventHandlers(this.webView2Control); + HandleResize(); + } + + public BrowserForm(CoreWebView2CreationProperties creationProperties = null) + { + this.CreationProperties = creationProperties; + InitializeComponent(); + AttachControlEventHandlers(this.webView2Control); + HandleResize(); + } + + private void UpdateTitleWithEvent(string message) + { + string currentDocumentTitle = this.webView2Control?.CoreWebView2?.DocumentTitle ?? "Uninitialized"; + this.Text = currentDocumentTitle + " (" + message + ")"; + } - private void UpdateTitleWithEvent(string message) + CoreWebView2Environment _webViewEnvironment; + CoreWebView2Environment WebViewEnvironment + { + get + { + if (_webViewEnvironment == null && webView2Control?.CoreWebView2 != null) { - string currentDocumentTitle = this.webView2Control?.CoreWebView2?.DocumentTitle ?? "Uninitialized"; - this.Text = currentDocumentTitle + " (" + message + ")"; + _webViewEnvironment = webView2Control.CoreWebView2.Environment; } + return _webViewEnvironment; + } + } - #region Event Handlers - private void WebView2Control_NavigationStarting(object sender, CoreWebView2NavigationStartingEventArgs e) + CoreWebView2Settings _webViewSettings; + CoreWebView2Settings WebViewSettings + { + get + { + if (_webViewSettings == null && webView2Control?.CoreWebView2 != null) { - UpdateTitleWithEvent("NavigationStarting"); + _webViewSettings = webView2Control.CoreWebView2.Settings; } + return _webViewSettings; + } + } - private void WebView2Control_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e) + string _lastInitializeScriptId; + + List _webViewFrames = new List(); + void WebView_HandleIFrames(object sender, CoreWebView2FrameCreatedEventArgs args) { - UpdateTitleWithEvent("NavigationCompleted"); + _webViewFrames.Add(args.Frame); + args.Frame.Destroyed += WebViewFrames_DestoryedNestedIFrames; } - private void WebView2Control_SourceChanged(object sender, CoreWebView2SourceChangedEventArgs e) + void WebViewFrames_DestoryedNestedIFrames(object sender, object args) { - txtUrl.Text = webView2Control.Source.AbsoluteUri; + try + { + var frameToRemove = _webViewFrames.SingleOrDefault(r => r.IsDestroyed() == 1); + if (frameToRemove != null) + _webViewFrames.Remove(frameToRemove); + } + catch (InvalidOperationException ex) + { + MessageBox.Show(ex.Message); + } } - private void WebView2Control_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e) + string WebViewFrames_ToString() { - if (!e.IsSuccess) + string result = ""; + for (var i = 0; i < _webViewFrames.Count; i++) { - MessageBox.Show($"WebView2 creation failed with exception = {e.InitializationException}"); - UpdateTitleWithEvent("CoreWebView2InitializationCompleted failed"); - return; + if (i > 0) result += "; "; + result += i.ToString() + " " + + (String.IsNullOrEmpty(_webViewFrames[i].Name) ? "" : _webViewFrames[i].Name); } + return String.IsNullOrEmpty(result) ? "no iframes available." : result; + } + + #region Event Handlers + // Enable (or disable) buttons when webview2 is init (or disposed). Similar to the CanExecute feature of WPF. + private void UpdateButtons(bool isEnabled) + { + this.btnEvents.Enabled = isEnabled; + this.btnBack.Enabled = isEnabled && webView2Control != null && webView2Control.CanGoBack; + this.btnForward.Enabled = isEnabled && webView2Control != null && webView2Control.CanGoForward; + this.btnRefresh.Enabled = isEnabled; + this.btnGo.Enabled = isEnabled; + this.closeWebViewToolStripMenuItem.Enabled = isEnabled; + this.allowExternalDropMenuItem.Enabled = isEnabled; + this.xToolStripMenuItem.Enabled = isEnabled; + this.xToolStripMenuItem1.Enabled = isEnabled; + this.xToolStripMenuItem2.Enabled = isEnabled; + this.xToolStripMenuItem3.Enabled = isEnabled; + this.whiteBackgroundColorMenuItem.Enabled = isEnabled; + this.redBackgroundColorMenuItem.Enabled = isEnabled; + this.blueBackgroundColorMenuItem.Enabled = isEnabled; + this.transparentBackgroundColorMenuItem.Enabled = isEnabled; + } + + private void EnableButtons() + { + UpdateButtons(true); + } + + private void DisableButtons(object sender, EventArgs e) + { + UpdateButtons(false); + } + + private void WebView2Control_NavigationStarting(object sender, CoreWebView2NavigationStartingEventArgs e) + { + UpdateTitleWithEvent("NavigationStarting"); + } + + private void WebView2Control_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e) + { + UpdateTitleWithEvent("NavigationCompleted"); + } + + private void WebView2Control_SourceChanged(object sender, CoreWebView2SourceChangedEventArgs e) + { + txtUrl.Text = webView2Control.Source.AbsoluteUri; + } + + private void WebView2Control_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e) + { + if (!e.IsSuccess) + { + MessageBox.Show($"WebView2 creation failed with exception = {e.InitializationException}"); + UpdateTitleWithEvent("CoreWebView2InitializationCompleted failed"); + return; + } + + // Setup host resource mapping for local files + this.webView2Control.CoreWebView2.SetVirtualHostNameToFolderMapping("appassets.example", "assets", CoreWebView2HostResourceAccessKind.DenyCors); + this.webView2Control.Source = new Uri(GetStartPageUri(this.webView2Control.CoreWebView2)); + + this.webView2Control.CoreWebView2.SourceChanged += CoreWebView2_SourceChanged; + this.webView2Control.CoreWebView2.HistoryChanged += CoreWebView2_HistoryChanged; + this.webView2Control.CoreWebView2.DocumentTitleChanged += CoreWebView2_DocumentTitleChanged; + this.webView2Control.CoreWebView2.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.Image, CoreWebView2WebResourceRequestSourceKinds.Document); + this.webView2Control.CoreWebView2.ProcessFailed += CoreWebView2_ProcessFailed; + this.webView2Control.CoreWebView2.FrameCreated += WebView_HandleIFrames; + + UpdateTitleWithEvent("CoreWebView2InitializationCompleted succeeded"); + EnableButtons(); + } - this.webView2Control.CoreWebView2.SourceChanged += CoreWebView2_SourceChanged; - this.webView2Control.CoreWebView2.HistoryChanged += CoreWebView2_HistoryChanged; - this.webView2Control.CoreWebView2.DocumentTitleChanged += CoreWebView2_DocumentTitleChanged; - this.webView2Control.CoreWebView2.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.Image); - UpdateTitleWithEvent("CoreWebView2InitializationCompleted succeeded"); + void AttachControlEventHandlers(Microsoft.Web.WebView2.WinForms.WebView2 control) + { + control.CoreWebView2InitializationCompleted += WebView2Control_CoreWebView2InitializationCompleted; + control.NavigationStarting += WebView2Control_NavigationStarting; + control.NavigationCompleted += WebView2Control_NavigationCompleted; + control.SourceChanged += WebView2Control_SourceChanged; + control.KeyDown += WebView2Control_KeyDown; + control.KeyUp += WebView2Control_KeyUp; + control.Disposed += DisableButtons; + } + + private void WebView2Control_KeyUp(object sender, KeyEventArgs e) + { + UpdateTitleWithEvent($"KeyUp key={e.KeyCode}"); + if (!this.acceleratorKeysEnabledToolStripMenuItem.Checked) + e.Handled = true; + } + + private void WebView2Control_KeyDown(object sender, KeyEventArgs e) + { + UpdateTitleWithEvent($"KeyDown key={e.KeyCode}"); + if (!this.acceleratorKeysEnabledToolStripMenuItem.Checked) + e.Handled = true; + } + + private void CoreWebView2_HistoryChanged(object sender, object e) + { + // No explicit check for webView2Control initialization because the events can only start + // firing after the CoreWebView2 and its events exist for us to subscribe. + btnBack.Enabled = webView2Control.CoreWebView2.CanGoBack; + btnForward.Enabled = webView2Control.CoreWebView2.CanGoForward; + UpdateTitleWithEvent("HistoryChanged"); + } + + private void CoreWebView2_SourceChanged(object sender, CoreWebView2SourceChangedEventArgs e) + { + this.txtUrl.Text = this.webView2Control.Source.AbsoluteUri; + UpdateTitleWithEvent("SourceChanged"); + } + + private void CoreWebView2_DocumentTitleChanged(object sender, object e) + { + this.Text = this.webView2Control.CoreWebView2.DocumentTitle; + UpdateTitleWithEvent("DocumentTitleChanged"); + } + #endregion + + #region UI event handlers + private void BtnRefresh_Click(object sender, EventArgs e) + { + webView2Control.Reload(); + } + + private void BtnGo_Click(object sender, EventArgs e) + { + var rawUrl = txtUrl.Text; + Uri uri = null; + + if (Uri.IsWellFormedUriString(rawUrl, UriKind.Absolute)) + { + uri = new Uri(rawUrl); + } + else if (!rawUrl.Contains(" ") && rawUrl.Contains(".")) + { + // An invalid URI contains a dot and no spaces, try tacking http:// on the front. + uri = new Uri("http://" + rawUrl); + } + else + { + // Otherwise treat it as a web search. + uri = new Uri("https://bing.com/search?q=" + + String.Join("+", Uri.EscapeDataString(rawUrl).Split(new string[] { "%20" }, StringSplitOptions.RemoveEmptyEntries))); + } + + webView2Control.Source = uri; + if (ShouldBlockUri()) + { + webView2Control.CoreWebView2.NavigateToString("You've attempted to navigate to a domain in the blocked sites list. Press back to return to the previous page."); + } + } + + + private void btnBack_Click(object sender, EventArgs e) + { + webView2Control.GoBack(); + } + + private void btnEvents_Click(object sender, EventArgs e) + { + (new EventMonitor(this.webView2Control)).Show(this); + } + + private void btnForward_Click(object sender, EventArgs e) + { + webView2Control.GoForward(); + } + + private void Form_Resize(object sender, EventArgs e) + { + HandleResize(); + } + + private void closeWebViewToolStripMenuItem_Click(object sender, EventArgs e) + { + this.Controls.Remove(webView2Control); + webView2Control.Dispose(); + } + + private void createWebViewToolStripMenuItem_Click(object sender, EventArgs e) + { + void EnsureProcessIsClose(uint pid) { + try + { + var process = Process.GetProcessById((int)pid); + process.Kill(); } + catch (ArgumentException) + { + // Process already exited. + } + } + if (this.webView2Control.CoreWebView2 != null) + { + var processId = this.webView2Control.CoreWebView2.BrowserProcessId; + this.Controls.Remove(this.webView2Control); + this.webView2Control.Dispose(); + EnsureProcessIsClose(processId); + } + this.webView2Control = GetReplacementControl(false); + // Set background transparent + this.webView2Control.DefaultBackgroundColor = System.Drawing.Color.Transparent; + this.Controls.Add(this.webView2Control); + HandleResize(); + } + + private void createNewWindowToolStripMenuItem_Click(object sender, EventArgs e) + { + new BrowserForm().Show(); + } + + private void createNewWindowWithOptionsToolStripMenuItem_Click(object sender, EventArgs e) + { + var dialog = new NewWindowOptionsDialog(); + if (dialog.ShowDialog() == DialogResult.OK) + { + new BrowserForm(dialog.CreationProperties).Show(); + } + } + + private void ThreadProc(CoreWebView2CreationProperties creationProperties) + { + try + { + var creationProps = new CoreWebView2CreationProperties(); + // The CoreWebView2CreationProperties object cannot be assigned directly, because its member _task will also be assigned. + creationProps.BrowserExecutableFolder = creationProperties.BrowserExecutableFolder; + creationProps.UserDataFolder = creationProperties.UserDataFolder; + creationProps.Language = creationProperties.Language; + creationProps.AdditionalBrowserArguments = creationProperties.AdditionalBrowserArguments; + creationProps.ProfileName = creationProperties.ProfileName; + creationProps.IsInPrivateModeEnabled = creationProperties.IsInPrivateModeEnabled; + var tempForm = new BrowserForm(creationProps); + tempForm.Show(); + // Run the message pump + Application.Run(); + } + catch (Exception exception) + { + MessageBox.Show("Create New Thread Failed: " + exception.Message, "Create New Thread"); + } + } - void AttachControlEventHandlers(Microsoft.Web.WebView2.WinForms.WebView2 control) { - control.CoreWebView2InitializationCompleted += WebView2Control_CoreWebView2InitializationCompleted; - control.NavigationStarting += WebView2Control_NavigationStarting; - control.NavigationCompleted += WebView2Control_NavigationCompleted; - control.SourceChanged += WebView2Control_SourceChanged; - control.KeyDown += WebView2Control_KeyDown; - control.KeyUp += WebView2Control_KeyUp; + private void createNewThreadToolStripMenuItem_Click(object sender, EventArgs e) + { + Thread newFormThread = new Thread(() => + { + ThreadProc(webView2Control.CreationProperties); + }); + newFormThread.SetApartmentState(ApartmentState.STA); + newFormThread.IsBackground = false; + newFormThread.Start(); + } + + private void xToolStripMenuItem05_Click(object sender, EventArgs e) + { + this.webView2Control.ZoomFactor = 0.5; + } + + private void xToolStripMenuItem1_Click(object sender, EventArgs e) + { + this.webView2Control.ZoomFactor = 1.0; + } + + private void xToolStripMenuItem2_Click(object sender, EventArgs e) + { + this.webView2Control.ZoomFactor = 2.0; + } + + private void xToolStripMenuItem3_Click(object sender, EventArgs e) + { + MessageBox.Show($"Zoom factor: {this.webView2Control.ZoomFactor}", "WebView Zoom factor"); + } + + private void backgroundColorMenuItem_Click(object sender, EventArgs e) + { + var menuItem = (ToolStripMenuItem)sender; + Color backgroundColor = Color.FromName(menuItem.Text); + this.webView2Control.DefaultBackgroundColor = backgroundColor; + } + + private void taskManagerToolStripMenuItem_Click(object sender, EventArgs e) + { + try + { + this.webView2Control.CoreWebView2.OpenTaskManagerWindow(); + } + catch (Exception ex) + { + MessageBox.Show(this, ex.ToString(), "Open Task Manager Window failed"); + } + } + + private async void methodCDPToolStripMenuItem_Click(object sender, EventArgs e) + { + TextInputDialog dialog = new TextInputDialog( + title: "Call CDP Method", + description: "Enter the CDP method name to call, followed by a space,\r\n" + + "followed by the parameters in JSON format.", + defaultInput: "Runtime.evaluate {\"expression\":\"alert(\\\"test\\\")\"}" + ); + if (dialog.ShowDialog() == DialogResult.OK) + { + string[] words = dialog.inputBox().Trim().Split(' '); + if (words.Length == 1 && words[0] == "") + { + MessageBox.Show(this, "Invalid argument:" + dialog.inputBox(), "CDP Method call failed"); + return; } + string methodName = words[0]; + string methodParams = (words.Length == 2 ? words[1] : "{}"); - private void WebView2Control_KeyUp(object sender, KeyEventArgs e) + try + { + string cdpResult = await this.webView2Control.CoreWebView2.CallDevToolsProtocolMethodAsync(methodName, methodParams); + MessageBox.Show(this, cdpResult, "CDP method call successfully"); + } + catch (Exception ex) { - UpdateTitleWithEvent($"AcceleratorKeyUp key={e.KeyCode}"); - if (!this.acceleratorKeysEnabledToolStripMenuItem.Checked) - e.Handled = true; + MessageBox.Show(this, ex.ToString(), "CDP method call failed"); } + } + } - private void WebView2Control_KeyDown(object sender, KeyEventArgs e) + private void allowExternalDropMenuItem_Click(object sender, EventArgs e) + { + this.webView2Control.AllowExternalDrop = this.allowExternalDropMenuItem.Checked; + } + + private void setUsersAgentMenuItem_Click(object sender, EventArgs e) + { + var dialog = new TextInputDialog( + title: "SetUserAgent", + description: "Enter UserAgent"); + if (dialog.ShowDialog() == DialogResult.OK) + { + // + WebViewSettings.UserAgent = dialog.inputBox(); + // + } + } + + private void getDocumentTitleMenuItem_Click(object sender, EventArgs e) + { + MessageBox.Show(webView2Control.CoreWebView2.DocumentTitle, "Document Title"); + } + + private bool _isPrintToPdfInProgress = false; + private async void portraitMenuItem_Click(object sender, EventArgs e) + { + if (_isPrintToPdfInProgress) + { + MessageBox.Show(this, "Print to PDF in progress", "Print To PDF"); + return; + } + try + { + // + SaveFileDialog saveFileDialog = new SaveFileDialog(); + saveFileDialog.InitialDirectory = "C:\\"; + saveFileDialog.Filter = "Pdf Files|*.pdf"; + if (saveFileDialog.ShowDialog() == DialogResult.OK) { - UpdateTitleWithEvent($"AcceleratorKeyDown key={e.KeyCode}"); - if (!this.acceleratorKeysEnabledToolStripMenuItem.Checked) - e.Handled = true; + _isPrintToPdfInProgress = true; + bool isSuccessful = await webView2Control.CoreWebView2.PrintToPdfAsync( + saveFileDialog.FileName); + _isPrintToPdfInProgress = false; + string message = (isSuccessful) ? + "Print to PDF succeeded" : "Print to PDF failed"; + MessageBox.Show(this, message, "Print To PDF Completed"); } + // + } + catch (NotImplementedException exception) + { + MessageBox.Show(this, "Print to PDF Failed: " + exception.Message, + "Print to PDF"); + } + } - private void CoreWebView2_HistoryChanged(object sender, object e) + private async void landscapeMenuItem_Click(object sender, EventArgs e) + { + { + if (_isPrintToPdfInProgress) { - // No explicit check for webView2Control initialization because the events can only start - // firing after the CoreWebView2 and its events exist for us to subscribe. - btnBack.Enabled = webView2Control.CoreWebView2.CanGoBack; - btnForward.Enabled = webView2Control.CoreWebView2.CanGoForward; - UpdateTitleWithEvent("HistoryChanged"); + MessageBox.Show(this, "Print to PDF in progress", "Print To PDF"); + return; } + try + { + // + CoreWebView2PrintSettings printSettings = WebViewEnvironment.CreatePrintSettings(); + printSettings.Orientation = CoreWebView2PrintOrientation.Landscape; + SaveFileDialog saveFileDialog = new SaveFileDialog(); + saveFileDialog.InitialDirectory = "C:\\"; + saveFileDialog.Filter = "Pdf Files|*.pdf"; + if (saveFileDialog.ShowDialog() == DialogResult.OK) + { + _isPrintToPdfInProgress = true; + bool isSuccessful = await webView2Control.CoreWebView2.PrintToPdfAsync( + saveFileDialog.FileName, printSettings); + _isPrintToPdfInProgress = false; + string message = (isSuccessful) ? + "Print to PDF succeeded" : "Print to PDF failed"; + MessageBox.Show(this, message, "Print To PDF Completed"); + } + // + } + catch (NotImplementedException exception) + { + MessageBox.Show(this, "Print to PDF Failed: " + exception.Message, + "Print to PDF"); + } + } + } - private void CoreWebView2_SourceChanged(object sender, CoreWebView2SourceChangedEventArgs e) + private void exitMenuItem_Click(object sender, EventArgs e) + { + if (_isPrintToPdfInProgress) + { + var selection = MessageBox.Show( + "Print to PDF in progress. Continue closing?", + "Print to PDF", MessageBoxButtons.YesNo); + if (selection == DialogResult.No) { - this.txtUrl.Text = this.webView2Control.Source.AbsoluteUri; - UpdateTitleWithEvent("SourceChanged"); + return; + } + } + this.Close(); + } + + private void getUserDataFolderMenuItem_Click(object sender, EventArgs e) + { + try + { + MessageBox.Show(WebViewEnvironment.UserDataFolder, "User Data Folder"); + } + catch (Exception exception) + { + MessageBox.Show(this, "Get User Data Folder Failed: " + exception.Message, "User Data Folder"); + } + } + + private void toggleVisibilityMenuItem_Click(object sender, EventArgs e) + { + this.webView2Control.Visible = this.toggleVisibilityMenuItem.Checked; + } + + private void toggleCustomServerCertificateSupportMenuItem_Click(object sender, EventArgs e) + { + ToggleCustomServerCertificateSupport(); + } + + private void clearServerCertificateErrorActionsMenuItem_Click(object sender, EventArgs e) + { + ClearServerCertificateErrorActions(); + } + + private void toggleDefaultScriptDialogsMenuItem_Click(object sender, EventArgs e) + { + + WebViewSettings.AreDefaultScriptDialogsEnabled = !WebViewSettings.AreDefaultScriptDialogsEnabled; + + MessageBox.Show("Default script dialogs will be " + (WebViewSettings.AreDefaultScriptDialogsEnabled ? "enabled" : "disabled"), "after the next navigation."); + } + + private void addRemoteObjectMenuItem_Click(object sender, EventArgs e) + { + try + { + this.webView2Control.CoreWebView2.AddHostObjectToScript("bridge", new BridgeAddRemoteObject()); + } + catch (NotSupportedException exception) + { + MessageBox.Show("CoreWebView2.AddRemoteObject failed: " + exception.Message); + } + + this.webView2Control.CoreWebView2.FrameCreated += (s, args) => + { + if (args.Frame.Name.Equals("iframe_name")) + { + try + { + string[] origins = new string[] { "https://appassets.example" }; + args.Frame.AddHostObjectToScript("bridge", new BridgeAddRemoteObject(), origins); + } + catch (NotSupportedException exception) + { + MessageBox.Show("Frame.AddHostObjectToScript failed: " + exception.Message); + } + } + args.Frame.NameChanged += (nameChangedSender, nameChangedArgs) => + { + CoreWebView2Frame frame = (CoreWebView2Frame)nameChangedSender; + MessageBox.Show("Frame.NameChanged: " + frame.Name); + }; + args.Frame.Destroyed += (frameDestroyedSender, frameDestroyedArgs) => + { + // Handle frame destroyed + }; + }; + + this.webView2Control.CoreWebView2.SetVirtualHostNameToFolderMapping( + "appassets.example", "assets", CoreWebView2HostResourceAccessKind.DenyCors); + this.webView2Control.Source = new Uri("https://appassets.example/hostObject.html"); } - private void CoreWebView2_DocumentTitleChanged(object sender, object e) + // + private void domContentLoadedMenuItem_Click(object sender, EventArgs e) { - this.Text = this.webView2Control.CoreWebView2.DocumentTitle; - UpdateTitleWithEvent("DocumentTitleChanged"); + this.webView2Control.CoreWebView2.DOMContentLoaded += WebView_DOMContentLoaded; + this.webView2Control.CoreWebView2.FrameCreated += WebView_FrameCreatedDOMContentLoaded; + this.webView2Control.NavigateToString(@"" + + "

      DOMContentLoaded sample page

      " + + "

      The content to the iframe and below will be added after DOM content is loaded

      " + + "