diff --git a/.github/ISSUE_TEMPLATE/bug-in-sample.md b/.github/ISSUE_TEMPLATE/bug-in-sample.md
new file mode 100644
index 0000000000..ebe78110d9
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug-in-sample.md
@@ -0,0 +1,43 @@
+---
+name: Bug in sample
+about: Report a problem with a sample
+title: ''
+labels: bug
+assignees: ''
+
+---
+
+**Which sample are you reporting a bug in?**
+
+Example: ResizeAppView
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+Include links to specific lines of code where you think the bug is.
+(Click the line number, then click the "..." and select "Copy permalink.")
+If not sure, at least include a link to the scenario where the problem is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Configuration**
+
+* Language/architecture/flavor: (example: C++/WinRT x64 Debug)
+* Windows platform and build number: (example: Desktop build 18362.)
+
+* Visual Studio version: (example: 16.6.5; get this value from Help.About.)
+
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000000..58ed9bf109
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,8 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Bug in the OS
+ url: https://developer.microsoft.com/windows/support/
+ about: In Windows Dev Center, click "Forums & community" to see your options
+ - name: OS feature request
+ url: https://aka.ms/feedback-hub/support
+ about: Use Feedback Hub to request OS features
diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md
new file mode 100644
index 0000000000..81e8ef85ef
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature-request.md
@@ -0,0 +1,19 @@
+---
+name: Suggestion for sample
+about: Suggest a new sample or update to an existing sample
+title: ''
+labels: suggestion
+assignees: ''
+
+---
+
+**Which sample are you requesting a feature to be added to?**
+
+Example: ResizeAppView (or say "New sample" to suggest a new sample)
+
+Note that this is for suggesting a new sample or suggesting an update to an existing sample. To request features to be added to the operating system, use [Feedback Hub]( https://aka.ms/feedback-hub/support).
+
+**Describe the feature**
+A clear and concise description of the desired feature to be demonstrated by a sample.
+
+Example: Show how to use the MapElementsLayer class to organize elements into layers on the MapControl.
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000000..4d983495be
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,41 @@
+
+
+
+## Description
+
+Name of sample: (example: ResizeAppView, or proposed name of new sample)
+
+
+
+
+## Testing
+
+
+
+## Type of change
+
+- [ ] Bug fix
+- [ ] New feature
+- [ ] Porting to new language
+
+## Supported platforms
+Minimum OS version: (example: 18362)
+
+
+- [ ] All UWP platforms
+- [ ] Desktop
+- [ ] Holographic
+- [ ] IoT
+- [ ] Xbox
+- [ ] 10X
+
+## Supported languages
+
+
+
+
+- [ ] C#
+- [ ] C++/WinRT
+
+## Additional remarks
+
diff --git a/README.md b/README.md
index 838d92caab..822ede9c42 100644
--- a/README.md
+++ b/README.md
@@ -531,11 +531,12 @@ For additional Windows samples, see [Windows on GitHub](http://microsoft.github.
+ Capabilities
Custom capabilities
In-process component authoring
- In-process component authoring
+ In-process component authoring
Out-of-process component authoring
Version adaptive code
diff --git a/Samples/BarcodeScanner/README.md b/Samples/BarcodeScanner/README.md
index be9455ee3b..40c6079e99 100644
--- a/Samples/BarcodeScanner/README.md
+++ b/Samples/BarcodeScanner/README.md
@@ -5,6 +5,7 @@ languages:
- cpp
- cppcx
- vb
+- cppwinrt
products:
- windows
- windows-uwp
diff --git a/Samples/BarcodeScanner/cppwinrt/BarcodeScanner.sln b/Samples/BarcodeScanner/cppwinrt/BarcodeScanner.sln
new file mode 100644
index 0000000000..07c7b42ab4
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/BarcodeScanner.sln
@@ -0,0 +1,43 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30320.27
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BarcodeScanner", "BarcodeScanner.vcxproj", "{A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM = Release|ARM
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}.Debug|ARM.ActiveCfg = Debug|ARM
+ {A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}.Debug|ARM.Build.0 = Debug|ARM
+ {A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}.Debug|ARM.Deploy.0 = Debug|ARM
+ {A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}.Debug|x64.ActiveCfg = Debug|x64
+ {A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}.Debug|x64.Build.0 = Debug|x64
+ {A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}.Debug|x64.Deploy.0 = Debug|x64
+ {A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}.Debug|x86.ActiveCfg = Debug|Win32
+ {A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}.Debug|x86.Build.0 = Debug|Win32
+ {A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}.Debug|x86.Deploy.0 = Debug|Win32
+ {A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}.Release|ARM.ActiveCfg = Release|ARM
+ {A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}.Release|ARM.Build.0 = Release|ARM
+ {A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}.Release|ARM.Deploy.0 = Release|ARM
+ {A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}.Release|x64.ActiveCfg = Release|x64
+ {A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}.Release|x64.Build.0 = Release|x64
+ {A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}.Release|x64.Deploy.0 = Release|x64
+ {A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}.Release|x86.ActiveCfg = Release|Win32
+ {A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}.Release|x86.Build.0 = Release|Win32
+ {A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}.Release|x86.Deploy.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {F8F7BA01-CCD5-44F2-879D-3189E0598F3C}
+ EndGlobalSection
+EndGlobal
diff --git a/Samples/BarcodeScanner/cppwinrt/BarcodeScanner.vcxproj b/Samples/BarcodeScanner/cppwinrt/BarcodeScanner.vcxproj
new file mode 100644
index 0000000000..54adbc6d5b
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/BarcodeScanner.vcxproj
@@ -0,0 +1,235 @@
+
+
+
+
+ $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), LICENSE))\SharedContent
+
+
+ true
+ {A8DD75F9-CA19-4997-96CC-F6C28FD7D55B}
+ BarcodeScanner
+ SDKTemplate
+ en-US
+ 15.0
+ true
+ Windows Store
+ 10.0
+ 10.0.18362.0
+ 10.0.17763.0
+
+
+
+
+ Debug
+ ARM
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ ARM
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ Application
+ Unicode
+
+
+ true
+ true
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+ $(VC_IncludePath);$(UniversalCRT_IncludePath);$(WindowsSDK_IncludePath);$(SharedContentDir)\cppwinrt
+ true
+
+
+
+ Use
+ pch.h
+ $(IntDir)pch.pch
+ Level4
+ %(AdditionalOptions) /bigobj /await
+ 4453;28204
+
+
+
+
+ _DEBUG;%(PreprocessorDefinitions)
+
+
+
+
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+
+
+ $(SharedContentDir)\xaml\App.xaml
+
+
+ $(SharedContentDir)\xaml\MainPage.xaml
+
+
+
+
+
+
+ ..\shared\Scenario1_BasicFunctionality.xaml
+ Code
+
+
+
+ ..\shared\Scenario2_MultipleScanners.xaml
+ Code
+
+
+ Scenario3_ActiveSymbologies.xaml
+ Code
+
+
+ ..\shared\Scenario4_SymbologyAttributes.xaml
+ Code
+
+
+ ..\shared\Scenario5_DisplayingBarcodePreview.xaml
+ Code
+
+
+
+
+
+ Designer
+
+
+ Designer
+
+
+
+
+ Designer
+
+
+
+
+ Styles\Styles.xaml
+
+
+
+
+ $(SharedContentDir)\xaml\App.xaml
+
+
+ $(SharedContentDir)\xaml\MainPage.xaml
+
+
+ BarcodeScannerInfo.h
+
+
+ BindingHelpers.h
+
+
+ DataHelpers.h
+
+
+ SampleConfiguration.h
+
+
+ ..\shared\Scenario1_BasicFunctionality.xaml
+
+
+ Create
+ pch.h
+
+
+ Project.idl
+
+
+ ..\shared\Scenario2_MultipleScanners.xaml
+ Code
+
+
+ Scenario3_ActiveSymbologies.xaml
+ Code
+
+
+ ..\shared\Scenario4_SymbologyAttributes.xaml
+
+
+ ..\shared\Scenario5_DisplayingBarcodePreview.xaml
+ Code
+
+
+ SymbologyListEntry.h
+
+
+
+
+ $(SharedContentDir)\xaml\MainPage.xaml
+
+
+
+
+
+ Designer
+
+
+
+
+
+ Assets\microsoft-sdk.png
+
+
+ Assets\smallTile-sdk.png
+
+
+ Assets\splash-sdk.png
+
+
+ Assets\squareTile-sdk.png
+
+
+ Assets\storeLogo-sdk.png
+
+
+ Assets\tile-sdk.png
+
+
+ Assets\windows-sdk.png
+
+
+
+
+
+
+
+
+ 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}.
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/BarcodeScanner/cppwinrt/BarcodeScanner.vcxproj.filters b/Samples/BarcodeScanner/cppwinrt/BarcodeScanner.vcxproj.filters
new file mode 100644
index 0000000000..da382ed588
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/BarcodeScanner.vcxproj.filters
@@ -0,0 +1,74 @@
+
+
+
+
+ 4416d50a-7676-4d0a-9b2c-91ff70c6047f
+ bmp;fbx;gif;jpg;jpeg;tga;tiff;tif;png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/BarcodeScanner/cppwinrt/BarcodeScannerInfo.cpp b/Samples/BarcodeScanner/cppwinrt/BarcodeScannerInfo.cpp
new file mode 100644
index 0000000000..f5ef8d6c9f
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/BarcodeScannerInfo.cpp
@@ -0,0 +1,15 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "BarcodeScannerInfo.h"
+#include "BarcodeScannerInfo.g.cpp"
+
diff --git a/Samples/BarcodeScanner/cppwinrt/BarcodeScannerInfo.h b/Samples/BarcodeScanner/cppwinrt/BarcodeScannerInfo.h
new file mode 100644
index 0000000000..13ce82bf44
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/BarcodeScannerInfo.h
@@ -0,0 +1,47 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "BarcodeScannerInfo.g.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct BarcodeScannerInfo : BarcodeScannerInfoT
+ {
+ BarcodeScannerInfo(winrt::hstring const& deviceName, winrt::hstring const& deviceId) :
+ m_deviceName(deviceName),
+ m_deviceId(deviceId)
+ {
+ }
+
+ winrt::hstring Name() const
+ {
+ return m_deviceName;
+ }
+
+ winrt::hstring DeviceId() const
+ {
+ return m_deviceId;
+ }
+
+ private:
+ winrt::hstring m_deviceName;
+ winrt::hstring m_deviceId;
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct BarcodeScannerInfo : BarcodeScannerInfoT
+ {
+ };
+}
\ No newline at end of file
diff --git a/Samples/BarcodeScanner/cppwinrt/BindingHelpers.cpp b/Samples/BarcodeScanner/cppwinrt/BindingHelpers.cpp
new file mode 100644
index 0000000000..c2e8813691
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/BindingHelpers.cpp
@@ -0,0 +1,14 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "BindingHelpers.h"
+#include "BindingHelpers.g.cpp"
diff --git a/Samples/BarcodeScanner/cppwinrt/BindingHelpers.h b/Samples/BarcodeScanner/cppwinrt/BindingHelpers.h
new file mode 100644
index 0000000000..02926d7a33
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/BindingHelpers.h
@@ -0,0 +1,37 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "BindingHelpers.g.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct BindingHelpers
+ {
+ static bool Not(bool value)
+ {
+ return !value;
+ }
+
+ static winrt::Windows::UI::Xaml::Visibility CollapsedIf(bool value)
+ {
+ return value ? winrt::Windows::UI::Xaml::Visibility::Collapsed : winrt::Windows::UI::Xaml::Visibility::Visible;
+ }
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct BindingHelpers : BindingHelpersT
+ {
+ };
+}
diff --git a/Samples/BarcodeScanner/cppwinrt/DataHelpers.cpp b/Samples/BarcodeScanner/cppwinrt/DataHelpers.cpp
new file mode 100644
index 0000000000..384337b280
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/DataHelpers.cpp
@@ -0,0 +1,84 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include
+#include
+#include "DataHelpers.h"
+
+namespace winrt
+{
+ using namespace Windows::Storage::Streams;
+ using namespace Windows::Devices::PointOfService;
+}
+
+std::wstring GetDataString(winrt::IBuffer const& data)
+{
+ if (!data)
+ {
+ return L"No data";
+ }
+
+ // Just to show that we have the raw data, we'll print the value of the bytes.
+ // Arbitrarily limit the number of bytes printed so the UI isn't overloaded.
+ const unsigned int MAX_BYTES_TO_PRINT = 20;
+ unsigned int byteCount = (std::min)(data.Length(), MAX_BYTES_TO_PRINT);
+
+ std::wstringstream buffer;
+ buffer << std::setfill(L'0') << std::hex;
+ for (uint32_t value : winrt::array_view(data.data(), byteCount))
+ {
+ buffer << std::setw(2) << value << L" ";
+ }
+
+ if (byteCount < data.Length())
+ {
+ buffer << L"...";
+ }
+
+ return buffer.str();
+}
+
+winrt::hstring GetDataLabelString(winrt::IBuffer const& data, uint32_t scanDataType)
+{
+ // Only certain data types contain encoded text.
+ // To keep this simple, we'll just decode a few of them.
+ if (!data)
+ {
+ return L"No data";
+ }
+
+ if (scanDataType == winrt::BarcodeSymbologies::Upca() ||
+ scanDataType == winrt::BarcodeSymbologies::UpcaAdd2() ||
+ scanDataType == winrt::BarcodeSymbologies::UpcaAdd5() ||
+ scanDataType == winrt::BarcodeSymbologies::Upce() ||
+ scanDataType == winrt::BarcodeSymbologies::UpceAdd2() ||
+ scanDataType == winrt::BarcodeSymbologies::UpceAdd5() ||
+ scanDataType == winrt::BarcodeSymbologies::Ean8() ||
+ scanDataType == winrt::BarcodeSymbologies::TfStd() ||
+ scanDataType == winrt::BarcodeSymbologies::OcrA() ||
+ scanDataType == winrt::BarcodeSymbologies::OcrB())
+ {
+ // The UPC, EAN8, and 2 of 5 families encode the digits 0..9
+ // which are then sent to the app in a UTF8 string (like "01234")
+
+ // This is not an exhaustive list of symbologies that can be converted to a string
+
+ winrt::DataReader reader = winrt::DataReader::FromBuffer(data);
+ return reader.ReadString(data.Length());
+ }
+ else
+ {
+ // Some other symbologies (typically 2-D symbologies) contain binary data that
+ // should not be converted to text.
+ return hstring{ L"Decoded data unavailable. Raw label data: " + GetDataString(data) };
+ }
+}
diff --git a/Samples/BarcodeScanner/cppwinrt/DataHelpers.h b/Samples/BarcodeScanner/cppwinrt/DataHelpers.h
new file mode 100644
index 0000000000..b61310d91c
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/DataHelpers.h
@@ -0,0 +1,15 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+std::wstring GetDataString(winrt::Windows::Storage::Streams::IBuffer const& data);
+winrt::hstring GetDataLabelString(winrt::Windows::Storage::Streams::IBuffer const& data, uint32_t scanDataType);
diff --git a/Samples/BarcodeScanner/cppwinrt/Package.appxmanifest b/Samples/BarcodeScanner/cppwinrt/Package.appxmanifest
new file mode 100644
index 0000000000..ab8de83491
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/Package.appxmanifest
@@ -0,0 +1,45 @@
+
+
+
+
+
+ BarcodeScanner C++/WinRT Sample
+ Microsoft Corporation
+ Assets\storelogo-sdk.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/BarcodeScanner/cppwinrt/Project.idl b/Samples/BarcodeScanner/cppwinrt/Project.idl
new file mode 100644
index 0000000000..383210f007
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/Project.idl
@@ -0,0 +1,73 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+namespace SDKTemplate
+{
+ [default_interface]
+ runtimeclass Scenario1_BasicFunctionality : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario1_BasicFunctionality();
+ }
+
+ [default_interface]
+ runtimeclass Scenario2_MultipleScanners : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario2_MultipleScanners();
+ }
+
+ [default_interface]
+ runtimeclass Scenario3_ActiveSymbologies : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario3_ActiveSymbologies();
+ }
+
+ [Windows.UI.Xaml.Data.Bindable]
+ runtimeclass SymbologyListEntry
+ {
+ SymbologyListEntry(UInt32 symbologyId);
+ SymbologyListEntry(UInt32 symbologyId, Boolean symbologyEnabled);
+
+ UInt32 Id{ get; };
+ Boolean IsEnabled;
+ String Name{ get; };
+ }
+
+ [default_interface]
+ runtimeclass Scenario4_SymbologyAttributes : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario4_SymbologyAttributes();
+ }
+
+ runtimeclass Scenario5_DisplayingBarcodePreview :
+ Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged
+ {
+ Scenario5_DisplayingBarcodePreview();
+
+ Boolean IsScannerClaimed;
+ Boolean ScannerSupportsPreview;
+ Boolean IsPreviewing;
+ Boolean SoftwareTriggerStarted;
+ }
+
+ static runtimeclass BindingHelpers
+ {
+ static Windows.UI.Xaml.Visibility CollapsedIf(Boolean value);
+ static Boolean Not(Boolean value);
+ }
+
+ runtimeclass BarcodeScannerInfo
+ {
+ BarcodeScannerInfo(String name, String deviceId);
+
+ String Name{ get; };
+ String DeviceId{ get; };
+ }
+}
diff --git a/Samples/BarcodeScanner/cppwinrt/SampleConfiguration.cpp b/Samples/BarcodeScanner/cppwinrt/SampleConfiguration.cpp
new file mode 100644
index 0000000000..dc78e59dd1
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/SampleConfiguration.cpp
@@ -0,0 +1,33 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include
+#include "MainPage.h"
+#include "SampleConfiguration.h"
+
+using namespace winrt;
+using namespace winrt::Windows::Foundation::Collections;
+using namespace winrt::SDKTemplate;
+
+hstring implementation::MainPage::FEATURE_NAME()
+{
+ return L"Barcode Scanner";
+}
+
+IVector implementation::MainPage::scenariosInner = winrt::single_threaded_observable_vector(
+{
+ Scenario{ L"DataReceived event", xaml_typename() },
+ Scenario{ L"Release/Retain functionality", xaml_typename() },
+ Scenario{ L"Active Symbologies", xaml_typename() },
+ Scenario{ L"Symbology Attributes", xaml_typename() },
+ Scenario{ L"Displaying a Barcode Preview", xaml_typename() },
+});
diff --git a/Samples/BarcodeScanner/cppwinrt/SampleConfiguration.h b/Samples/BarcodeScanner/cppwinrt/SampleConfiguration.h
new file mode 100644
index 0000000000..93a2f26cbf
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/SampleConfiguration.h
@@ -0,0 +1,17 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+#include "pch.h"
+
+namespace winrt::SDKTemplate
+{
+}
diff --git a/Samples/BarcodeScanner/cppwinrt/Scenario1_BasicFunctionality.cpp b/Samples/BarcodeScanner/cppwinrt/Scenario1_BasicFunctionality.cpp
new file mode 100644
index 0000000000..e4e65b8db4
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/Scenario1_BasicFunctionality.cpp
@@ -0,0 +1,152 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include
+#include
+#include "Scenario1_BasicFunctionality.h"
+#include "Scenario1_BasicFunctionality.g.cpp"
+
+namespace winrt
+{
+ using namespace Windows::Foundation;
+ using namespace Windows::Devices;
+ using namespace Windows::Devices::Enumeration;
+ using namespace Windows::Devices::PointOfService;
+ using namespace Windows::UI::Xaml;
+ using namespace Windows::UI::Xaml::Navigation;
+}
+
+namespace winrt::SDKTemplate::implementation
+{
+ Scenario1_BasicFunctionality::Scenario1_BasicFunctionality()
+ {
+ InitializeComponent();
+ }
+
+ void Scenario1_BasicFunctionality::OnNavigatedTo(NavigationEventArgs const&)
+ {
+ ResetTheScenarioState();
+ }
+
+ void Scenario1_BasicFunctionality::OnNavigatedFrom(NavigationEventArgs const&)
+ {
+ ResetTheScenarioState();
+ }
+
+ void Scenario1_BasicFunctionality::ResetTheScenarioState()
+ {
+ if (m_claimedScanner)
+ {
+ // Detach the event handlers
+ m_claimedScanner.DataReceived(m_claimedScannerDataReceivedToken);
+ m_claimedScanner.ReleaseDeviceRequested(m_claimedScannerReleaseDeviceRequestedToken);
+ // Release the Barcode Scanner and set to null
+ m_claimedScanner = nullptr;
+ }
+
+ m_scanner = nullptr;
+
+ // Reset the UI if we are still the current page.
+ if (Frame().Content() == *this)
+ {
+ m_rootPage.NotifyUser(L"Click the start scanning button to begin.", NotifyType::StatusMessage);
+ ScenarioOutputScanData().Text(L"No data");
+ ScenarioOutputScanDataLabel().Text(L"No data");
+ ScenarioOutputScanDataType().Text(L"No data");
+
+ // reset the button state
+ ScenarioEndScanButton().IsEnabled(false);
+ ScenarioStartScanButton().IsEnabled(true);
+ }
+ }
+
+ fire_and_forget Scenario1_BasicFunctionality::ScenarioStartScanButton_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto lifetime = get_strong();
+ ScenarioStartScanButton().IsEnabled(false);
+
+ m_rootPage.NotifyUser(L"Acquiring barcode scanner object.", NotifyType::StatusMessage);
+
+ // Obtain the default barcode scanner.
+ m_scanner = co_await winrt::BarcodeScanner::GetDefaultAsync();
+ if (m_scanner)
+ {
+ // after successful creation, claim the scanner for exclusive use and enable it so that data reveived events are received.
+ m_claimedScanner = co_await m_scanner.ClaimScannerAsync();
+
+ if (m_claimedScanner)
+ {
+ // It is always a good idea to have a release device requested event handler. If this event is not handled, there are chances of another app can
+ // claim ownership of the barcode scanner.
+ m_claimedScannerReleaseDeviceRequestedToken = m_claimedScanner.ReleaseDeviceRequested({ get_weak(), &Scenario1_BasicFunctionality::claimedScanner_ReleaseDeviceRequested });
+
+ // after successfully claiming, attach the datareceived event handler.
+ m_claimedScannerDataReceivedToken = m_claimedScanner.DataReceived({ get_weak(), &Scenario1_BasicFunctionality::claimedScanner_DataReceived });
+
+ // Ask the API to decode the data by default. By setting this, API will decode the raw data from the barcode scanner and
+ // send the ScanDataLabel and ScanDataType in the DataReceived event
+ m_claimedScanner.IsDecodeDataEnabled(true);
+
+ // enable the scanner.
+ // The scanner must be enabled in order to receive the DataReceived event.
+ co_await m_claimedScanner.EnableAsync();
+
+ m_rootPage.NotifyUser(L"Ready to scan. Device ID: " + m_scanner.DeviceId(), NotifyType::StatusMessage);
+ ScenarioEndScanButton().IsEnabled(true);
+ }
+ else
+ {
+ m_rootPage.NotifyUser(L"Claim barcode scanner failed.", NotifyType::ErrorMessage);
+ ScenarioStartScanButton().IsEnabled(true);
+ }
+ }
+ else
+ {
+ m_rootPage.NotifyUser(L"Barcode scanner not found. Please connect a barcode scanner.", NotifyType::ErrorMessage);
+ ScenarioStartScanButton().IsEnabled(true);
+ }
+ }
+
+ ///
+ /// Event handler for the Release Device Requested event fired when barcode scanner receives Claim request from another application
+ ///
+ ///
+ /// Contains the ClamiedBarcodeScanner that is sending this request
+ void Scenario1_BasicFunctionality::claimedScanner_ReleaseDeviceRequested(IInspectable const&, ClaimedBarcodeScanner const& e)
+ {
+ // always retain the device
+ e.RetainDevice();
+
+ m_rootPage.NotifyUser(L"Event ReleaseDeviceRequested received. Retaining the barcode scanner.", NotifyType::StatusMessage);
+ }
+
+ ///
+ /// Event handler for the DataReceived event fired when a barcode is scanned by the barcode scanner
+ ///
+ ///
+ /// Contains the BarcodeScannerReport which contains the data obtained in the scan
+ fire_and_forget Scenario1_BasicFunctionality::claimedScanner_DataReceived(ClaimedBarcodeScanner const&, BarcodeScannerDataReceivedEventArgs args)
+ {
+ auto lifetime = get_strong();
+ co_await resume_foreground(Dispatcher());
+
+ // read the data from the buffer and convert to string.
+ ScenarioOutputScanDataLabel().Text(GetDataLabelString(args.Report().ScanDataLabel(), args.Report().ScanDataType()));
+ ScenarioOutputScanData().Text(GetDataString(args.Report().ScanData()));
+ ScenarioOutputScanDataType().Text(BarcodeSymbologies::GetName(args.Report().ScanDataType()));
+ }
+
+ void Scenario1_BasicFunctionality::ScenarioEndScanButton_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ ResetTheScenarioState();
+ }
+}
diff --git a/Samples/BarcodeScanner/cppwinrt/Scenario1_BasicFunctionality.h b/Samples/BarcodeScanner/cppwinrt/Scenario1_BasicFunctionality.h
new file mode 100644
index 0000000000..560b3560cf
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/Scenario1_BasicFunctionality.h
@@ -0,0 +1,47 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "Scenario1_BasicFunctionality.g.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario1_BasicFunctionality : Scenario1_BasicFunctionalityT
+ {
+ Scenario1_BasicFunctionality();
+
+ fire_and_forget ScenarioStartScanButton_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void ScenarioEndScanButton_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+
+ void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs const& e);
+ void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs const& e);
+ void claimedScanner_ReleaseDeviceRequested(Windows::Foundation::IInspectable const&, Windows::Devices::PointOfService::ClaimedBarcodeScanner const& e);
+ fire_and_forget claimedScanner_DataReceived(Windows::Devices::PointOfService::ClaimedBarcodeScanner const& sender, Windows::Devices::PointOfService::BarcodeScannerDataReceivedEventArgs args);
+
+ private:
+
+ void ResetTheScenarioState();
+
+ SDKTemplate::MainPage m_rootPage{ MainPage::Current() };
+ Windows::Devices::PointOfService::BarcodeScanner m_scanner{ nullptr };
+ Windows::Devices::PointOfService::ClaimedBarcodeScanner m_claimedScanner{ nullptr };
+ event_token m_claimedScannerDataReceivedToken;
+ event_token m_claimedScannerReleaseDeviceRequestedToken;
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario1_BasicFunctionality : Scenario1_BasicFunctionalityT
+ {
+ };
+}
diff --git a/Samples/BarcodeScanner/cppwinrt/Scenario2_MultipleScanners.cpp b/Samples/BarcodeScanner/cppwinrt/Scenario2_MultipleScanners.cpp
new file mode 100644
index 0000000000..25fad440a0
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/Scenario2_MultipleScanners.cpp
@@ -0,0 +1,477 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+
+#include "Scenario2_MultipleScanners.h"
+#include "Scenario2_MultipleScanners.g.cpp"
+
+namespace winrt
+{
+ using namespace Windows::Devices;
+ using namespace Windows::Devices::Enumeration;
+ using namespace Windows::Devices::PointOfService;
+ using namespace Windows::Foundation;
+ using namespace Windows::UI;
+ using namespace Windows::UI::Xaml;
+ using namespace Windows::UI::Xaml::Controls;
+ using namespace Windows::UI::Xaml::Media;
+ using namespace Windows::UI::Xaml::Navigation;
+}
+
+namespace winrt::SDKTemplate::implementation
+{
+
+ Scenario2_MultipleScanners::Scenario2_MultipleScanners()
+ {
+ InitializeComponent();
+ }
+
+ ///
+ /// Invoked when this page is no longer displayed.
+ ///
+ /// Event data that describes how this page was exited. The Parameter
+ /// property is typically used to configure the page.
+ void Scenario2_MultipleScanners::OnNavigatedFrom(NavigationEventArgs const&)
+ {
+ ResetTheScenarioState();
+ }
+
+ ///
+ /// Invoked when this page is about to be displayed in a Frame.
+ ///
+ /// Event data that describes how this page was reached. The Parameter
+ /// property is typically used to configure the page.
+ void Scenario2_MultipleScanners::OnNavigatedTo(NavigationEventArgs const&)
+ {
+ ResetTheScenarioState();
+ }
+
+ ///
+ /// This is the click handler for the 'ScenarioStartScanningInstance1' button. It initiates creation of scanner instance 1.
+ ///
+ fire_and_forget Scenario2_MultipleScanners::ButtonStartScanningInstance1_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto lifetime = get_strong();
+
+ //Get the handle to the default scanner
+ if (co_await CreateDefaultScannerObjectAsync(BarcodeScannerInstance::Instance1))
+ {
+ //Claim the scanner
+ if (co_await ClaimBarcodeScannerAsync(BarcodeScannerInstance::Instance1))
+ {
+ //add the event handlers
+ m_dev1ReleaseRequestedToken = m_claimedBarcodeScannerInstance1.ReleaseDeviceRequested({ get_weak(), &Scenario2_MultipleScanners::claimedBarcodeScannerInstance1_ReleaseDeviceRequested });
+ m_dev1DataReceivedToken = m_claimedBarcodeScannerInstance1.DataReceived({ get_weak(), &Scenario2_MultipleScanners::claimedBarcodeScannerInstance1_DataReceived });
+ m_claimedBarcodeScannerInstance1.IsDecodeDataEnabled(true);
+
+ //Enable the Scanner
+ if (co_await EnableBarcodeScannerAsync(BarcodeScannerInstance::Instance1))
+ {
+ //Set the UI state
+ ResetUI();
+ SetUI(BarcodeScannerInstance::Instance1);
+ }
+ }
+ else
+ {
+ if (m_barcodeScannerInstance1)
+ {
+ m_barcodeScannerInstance1.Close();
+ m_barcodeScannerInstance1 = nullptr;
+ }
+ }
+ }
+ }
+
+ ///
+ /// This method is called upon when a claim request is made on instance 1. If a retain request was placed on the device it rejects the new claim.
+ ///
+ fire_and_forget Scenario2_MultipleScanners::claimedBarcodeScannerInstance1_ReleaseDeviceRequested(IInspectable const&, ClaimedBarcodeScanner const&)
+ {
+ auto lifetime = get_strong();
+
+ co_await resume_foreground(Dispatcher());
+
+ //check if the instance wants to retain the device
+ if (Retain1().IsChecked().Value())
+ {
+ try
+ {
+ //Retain the device
+ m_claimedBarcodeScannerInstance1.RetainDevice();
+ }
+ catch (hresult_error const& exception)
+ {
+ m_rootPage.NotifyUser(L"Retain instance 1 failed: " + exception.message(), NotifyType::ErrorMessage);
+ }
+ }
+ //Release the device
+ else
+ {
+ m_claimedBarcodeScannerInstance1.Close();
+ m_claimedBarcodeScannerInstance1 = nullptr;
+
+ if (m_barcodeScannerInstance1)
+ {
+ m_barcodeScannerInstance1.Close();
+ m_barcodeScannerInstance1 = nullptr;
+ }
+ }
+ }
+
+ ///
+ /// This is the click handler for the 'ScenarioStartScanningInstance2' button. Initiates creation of scanner instance 2
+ ///
+ fire_and_forget Scenario2_MultipleScanners::ButtonStartScanningInstance2_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto lifetime = get_strong();
+
+ //Get the handle to the default scanner
+ if (co_await CreateDefaultScannerObjectAsync(BarcodeScannerInstance::Instance2))
+ {
+ //Claim the scanner
+ if (co_await ClaimBarcodeScannerAsync(BarcodeScannerInstance::Instance2))
+ {
+ //set the handlers
+ m_dev2ReleaseRequestedToken = m_claimedBarcodeScannerInstance2.ReleaseDeviceRequested({ get_weak(), &Scenario2_MultipleScanners::claimedBarcodeScannerInstance2_ReleaseDeviceRequested });
+ m_dev2DataReceivedToken = m_claimedBarcodeScannerInstance2.DataReceived({ get_weak(), &Scenario2_MultipleScanners::claimedBarcodeScannerInstance2_DataReceived });
+
+ //enable the scanner to decode the scanned data
+ m_claimedBarcodeScannerInstance2.IsDecodeDataEnabled(true);
+
+ //Enable the Scanner
+ if (co_await EnableBarcodeScannerAsync(BarcodeScannerInstance::Instance2))
+ {
+ //Set the UI state
+ ResetUI();
+ SetUI(BarcodeScannerInstance::Instance2);
+ }
+ }
+ else
+ {
+ if (m_barcodeScannerInstance2)
+ {
+ m_barcodeScannerInstance2.Close();
+ m_barcodeScannerInstance2 = nullptr;
+ }
+ }
+ }
+ }
+
+ ///
+ /// This method is called upon when a claim request is made on instance 2. If a retain request was placed on the device it rejects the new claim.
+ ///
+ fire_and_forget Scenario2_MultipleScanners::claimedBarcodeScannerInstance2_ReleaseDeviceRequested(IInspectable const&, ClaimedBarcodeScanner const&)
+ {
+ auto lifetime = get_strong();
+
+ co_await resume_foreground(Dispatcher());
+
+ //check if the instance wants to retain the device
+ if (Retain2().IsChecked().Value())
+ {
+ try
+ {
+ //Retain the device
+ m_claimedBarcodeScannerInstance2.RetainDevice();
+ }
+ catch (hresult_error const& exception)
+ {
+ m_rootPage.NotifyUser(L"Retain instance 2 failed: " + exception.message(), NotifyType::ErrorMessage);
+ }
+ }
+ //Release the device
+ else
+ {
+ m_claimedBarcodeScannerInstance2.Close();
+ m_claimedBarcodeScannerInstance2 = nullptr;
+
+ if (m_barcodeScannerInstance2)
+ {
+ m_barcodeScannerInstance2.Close();
+ m_barcodeScannerInstance2 = nullptr;
+ }
+ }
+ }
+
+ ///
+ /// This is the click handler for the 'ScenarioEndScanningInstance1' button.
+ /// Initiates the disposal of scanner instance 1.
+ ///
+ void Scenario2_MultipleScanners::ButtonEndScanningInstance1_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ if (m_claimedBarcodeScannerInstance1)
+ {
+ //remove the event handlers
+ m_claimedBarcodeScannerInstance1.ReleaseDeviceRequested(m_dev1ReleaseRequestedToken);
+ m_claimedBarcodeScannerInstance1.DataReceived(m_dev1DataReceivedToken);
+
+ //dispose the instance
+ m_claimedBarcodeScannerInstance1.Close();
+ m_claimedBarcodeScannerInstance1 = nullptr;
+ }
+
+ if (m_barcodeScannerInstance1)
+ {
+ m_barcodeScannerInstance1.Close();
+ m_barcodeScannerInstance1 = nullptr;
+ }
+
+ //reset the UI
+
+ ResetUI();
+
+ m_rootPage.NotifyUser(L"Click a start scanning button to begin.", NotifyType::StatusMessage);
+ }
+
+ ///
+ /// This is the click handler for the 'ScenarioEndScanningInstance2' button.
+ /// Initiates the disposal fo scanner instance 2.
+ ///
+ void Scenario2_MultipleScanners::ButtonEndScanningInstance2_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ if (m_claimedBarcodeScannerInstance2)
+ {
+ //remove the event handlers
+ m_claimedBarcodeScannerInstance2.ReleaseDeviceRequested(m_dev2ReleaseRequestedToken);
+ m_claimedBarcodeScannerInstance2.DataReceived(m_dev2DataReceivedToken);
+
+ //dispose the instance
+ m_claimedBarcodeScannerInstance2.Close();
+ m_claimedBarcodeScannerInstance2 = nullptr;
+ }
+
+ if (m_barcodeScannerInstance2)
+ {
+ m_barcodeScannerInstance2.Close();
+ m_barcodeScannerInstance2 = nullptr;
+ }
+
+ //reset the UI
+ ResetUI();
+
+ m_rootPage.NotifyUser(L"Click a start scanning button to begin.", NotifyType::StatusMessage);
+ }
+
+ ///
+ /// This method returns the first available Barcode Scanner. To enumerate and find a particular device use the device enumeration code.
+ ///
+ /// a boolean value based on whether it found a compatible scanner connected
+
+ IAsyncOperation Scenario2_MultipleScanners::CreateDefaultScannerObjectAsync(BarcodeScannerInstance instance)
+ {
+ auto lifetime = get_strong();
+
+ BarcodeScanner scanner = co_await BarcodeScanner::GetDefaultAsync();
+
+ if (!scanner)
+ {
+ m_rootPage.NotifyUser(L"Barcode scanner not found. Please connect a barcode scanner.", NotifyType::ErrorMessage);
+ co_return false;
+ }
+
+ switch (instance)
+ {
+ case BarcodeScannerInstance::Instance1:
+ m_barcodeScannerInstance1 = scanner;
+ break;
+ case BarcodeScannerInstance::Instance2:
+ m_barcodeScannerInstance2 = scanner;
+ break;
+ default:
+ co_return false;
+ }
+
+ co_return true;
+ }
+
+ ///
+ /// This method claims the connected scanner.
+ ///
+ /// a boolean based on whether it was able to claim the scanner.
+
+ IAsyncOperation Scenario2_MultipleScanners::ClaimBarcodeScannerAsync(BarcodeScannerInstance instance)
+ {
+ auto lifetime = get_strong();
+ bool claimAsyncStatus = false;
+ //select the instance to claim
+ switch (instance)
+ {
+ case BarcodeScannerInstance::Instance1:
+
+ m_claimedBarcodeScannerInstance1 = co_await m_barcodeScannerInstance1.ClaimScannerAsync();
+ if (!m_claimedBarcodeScannerInstance1)
+ m_rootPage.NotifyUser(L"Instance 1 claim barcode scanner failed.", NotifyType::ErrorMessage);
+ else
+ claimAsyncStatus = true;
+ break;
+
+ case BarcodeScannerInstance::Instance2:
+
+ m_claimedBarcodeScannerInstance2 = co_await m_barcodeScannerInstance2.ClaimScannerAsync();
+ if (!m_claimedBarcodeScannerInstance2)
+ m_rootPage.NotifyUser(L"Instance 2 claim barcode scanner failed.", NotifyType::ErrorMessage);
+ else
+ claimAsyncStatus = true;
+ break;
+
+ default:
+ co_return claimAsyncStatus;
+ }
+ co_return claimAsyncStatus;
+ }
+
+ ///
+ /// This method enables the connected scanner.
+ ///
+ /// a boolean based on whether it was able to enable the scanner.
+
+ IAsyncOperation Scenario2_MultipleScanners::EnableBarcodeScannerAsync(BarcodeScannerInstance instance)
+ {
+ auto lifetime = get_strong();
+ switch (instance)
+ {
+ case BarcodeScannerInstance::Instance1:
+ co_await m_claimedBarcodeScannerInstance1.EnableAsync();
+ m_rootPage.NotifyUser(L"Instance 1 ready to scan. Device ID: " + m_claimedBarcodeScannerInstance1.DeviceId(), NotifyType::StatusMessage);
+ break;
+ case BarcodeScannerInstance::Instance2:
+ co_await m_claimedBarcodeScannerInstance2.EnableAsync();
+ m_rootPage.NotifyUser(L"Instance 2 ready to scan. Device ID: " + m_claimedBarcodeScannerInstance2.DeviceId(), NotifyType::StatusMessage);
+ break;
+ default:
+ co_return false;
+ }
+ co_return true;
+ }
+
+ ///
+ /// Reset the Scenario state
+ ///
+
+ void Scenario2_MultipleScanners::ResetTheScenarioState()
+ {
+ if (m_claimedBarcodeScannerInstance1)
+ {
+ m_claimedBarcodeScannerInstance1.Close();
+ m_claimedBarcodeScannerInstance1 = nullptr;
+ }
+
+ if (m_barcodeScannerInstance1)
+ {
+ m_barcodeScannerInstance1.Close();
+ m_barcodeScannerInstance1 = nullptr;
+ }
+
+ if (m_claimedBarcodeScannerInstance2)
+ {
+ m_claimedBarcodeScannerInstance2.Close();
+ m_claimedBarcodeScannerInstance2 = nullptr;
+ }
+
+ if (m_barcodeScannerInstance2)
+ {
+ m_barcodeScannerInstance2.Close();
+ m_barcodeScannerInstance2 = nullptr;
+ }
+
+ ResetUI();
+ }
+
+ ///
+ /// Resets the display Elements to original state
+ ///
+
+ void Scenario2_MultipleScanners::ResetUI()
+ {
+ Instance1Border().BorderBrush(SolidColorBrush{ Colors::Gray() });
+ Instance2Border().BorderBrush(SolidColorBrush{ Colors::Gray() });
+
+ ScanDataType1().Text(L"No data");
+ ScanData1().Text(L"No data");
+ DataLabel1().Text(L"No data");
+ ScanDataType2().Text(L"No data");
+ ScanData2().Text(L"No data");
+ DataLabel2().Text(L"No data");
+
+ ScenarioStartScanningInstance1().IsEnabled(true);
+ ScenarioStartScanningInstance2().IsEnabled(true);
+ ScenarioEndScanningInstance1().IsEnabled(false);
+ ScenarioEndScanningInstance2().IsEnabled(false);
+ }
+
+ ///
+ /// Sets the UI elements to a state corresponding to the current active Instance.
+ ///
+ /// Corresponds to the current active instance
+
+ void Scenario2_MultipleScanners::SetUI(BarcodeScannerInstance instance)
+ {
+ Instance1Border().BorderBrush(SolidColorBrush{ Colors::Gray() });
+ Instance2Border().BorderBrush(SolidColorBrush{ Colors::Gray() });
+
+ switch (instance)
+ {
+ case BarcodeScannerInstance::Instance1:
+ ScenarioStartScanningInstance1().IsEnabled(false);
+ ScenarioStartScanningInstance2().IsEnabled(true);
+ ScenarioEndScanningInstance1().IsEnabled(true);
+ ScenarioEndScanningInstance2().IsEnabled(false);
+ Instance1Border().BorderBrush(SolidColorBrush{ Colors::DarkBlue() });
+ break;
+
+ case BarcodeScannerInstance::Instance2:
+ ScenarioStartScanningInstance1().IsEnabled(true);
+ ScenarioStartScanningInstance2().IsEnabled(false);
+ ScenarioEndScanningInstance1().IsEnabled(false);
+ ScenarioEndScanningInstance2().IsEnabled(true);
+ Instance2Border().BorderBrush(SolidColorBrush{ Colors::DarkBlue() });
+ break;
+ }
+ }
+
+ ///
+ /// This is an event handler for the claimed scanner Instance 1 when it scans and recieves data
+ ///
+ ///
+ ///
+
+ fire_and_forget Scenario2_MultipleScanners::claimedBarcodeScannerInstance1_DataReceived(ClaimedBarcodeScanner const&, BarcodeScannerDataReceivedEventArgs args)
+ {
+ auto lifetime = get_strong();
+ co_await resume_foreground(Dispatcher());
+
+ ScanDataType1().Text(BarcodeSymbologies::GetName(args.Report().ScanDataType()));
+ DataLabel1().Text(GetDataLabelString(args.Report().ScanDataLabel(), args.Report().ScanDataType()));
+ ScanData1().Text(GetDataString(args.Report().ScanData()));
+
+ m_rootPage.NotifyUser(L"Instance 1 received data from the barcode scanner.", NotifyType::StatusMessage);
+ }
+
+ ///
+ /// This is an event handler for the claimed scanner Instance 2 when it scans and recieves data
+ ///
+ ///
+ ///
+
+ fire_and_forget Scenario2_MultipleScanners::claimedBarcodeScannerInstance2_DataReceived(ClaimedBarcodeScanner const&, BarcodeScannerDataReceivedEventArgs args)
+ {
+ auto lifetime = get_strong();
+ co_await resume_foreground(Dispatcher());
+ ScanDataType2().Text(BarcodeSymbologies::GetName(args.Report().ScanDataType()));
+ DataLabel2().Text(GetDataLabelString(args.Report().ScanDataLabel(), args.Report().ScanDataType()));
+ ScanData2().Text(GetDataString(args.Report().ScanData()));
+
+ m_rootPage.NotifyUser(L"Instance 2 received data from the barcode scanner.", NotifyType::StatusMessage);
+ }
+
+}
\ No newline at end of file
diff --git a/Samples/BarcodeScanner/cppwinrt/Scenario2_MultipleScanners.h b/Samples/BarcodeScanner/cppwinrt/Scenario2_MultipleScanners.h
new file mode 100644
index 0000000000..ceaf264c5d
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/Scenario2_MultipleScanners.h
@@ -0,0 +1,74 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "Scenario2_MultipleScanners.g.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario2_MultipleScanners : Scenario2_MultipleScannersT
+ {
+ Scenario2_MultipleScanners();
+
+ void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs const& e);
+ void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs const& e);
+
+ fire_and_forget ButtonStartScanningInstance1_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+ fire_and_forget claimedBarcodeScannerInstance1_ReleaseDeviceRequested(Windows::Foundation::IInspectable const& sender, Windows::Devices::PointOfService::ClaimedBarcodeScanner const&);
+ fire_and_forget ButtonStartScanningInstance2_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const&);
+ fire_and_forget claimedBarcodeScannerInstance2_ReleaseDeviceRequested(Windows::Foundation::IInspectable const& sender, Windows::Devices::PointOfService::ClaimedBarcodeScanner const&);
+
+ void ButtonEndScanningInstance1_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+ void ButtonEndScanningInstance2_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+
+ private:
+ SDKTemplate::MainPage m_rootPage{ SDKTemplate::MainPage::Current() };
+
+ Windows::Devices::PointOfService::BarcodeScanner m_barcodeScannerInstance1{ nullptr };
+ Windows::Devices::PointOfService::BarcodeScanner m_barcodeScannerInstance2{ nullptr };
+ Windows::Devices::PointOfService::ClaimedBarcodeScanner m_claimedBarcodeScannerInstance1{ nullptr };
+ Windows::Devices::PointOfService::ClaimedBarcodeScanner m_claimedBarcodeScannerInstance2{ nullptr };
+ event_token m_dev1ReleaseRequestedToken;
+ event_token m_dev1DataReceivedToken;
+ event_token m_dev2ReleaseRequestedToken;
+ event_token m_dev2DataReceivedToken;
+
+ ///
+ /// Enumerator for current active Instance.
+ ///
+ enum class BarcodeScannerInstance
+ {
+ Instance1,
+ Instance2
+ };
+
+ Windows::Foundation::IAsyncOperation CreateDefaultScannerObjectAsync(BarcodeScannerInstance instance);
+ Windows::Foundation::IAsyncOperation ClaimBarcodeScannerAsync(BarcodeScannerInstance instance);
+ Windows::Foundation::IAsyncOperation EnableBarcodeScannerAsync(BarcodeScannerInstance instance);
+
+ void ResetTheScenarioState();
+ void ResetUI();
+
+ void SetUI(BarcodeScannerInstance instance);
+
+ fire_and_forget claimedBarcodeScannerInstance1_DataReceived(Windows::Devices::PointOfService::ClaimedBarcodeScanner const&, Windows::Devices::PointOfService::BarcodeScannerDataReceivedEventArgs args);
+ fire_and_forget claimedBarcodeScannerInstance2_DataReceived(Windows::Devices::PointOfService::ClaimedBarcodeScanner const&, Windows::Devices::PointOfService::BarcodeScannerDataReceivedEventArgs args);
+
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario2_MultipleScanners : Scenario2_MultipleScannersT
+ {
+ };
+}
diff --git a/Samples/BarcodeScanner/cppwinrt/Scenario3_ActiveSymbologies.cpp b/Samples/BarcodeScanner/cppwinrt/Scenario3_ActiveSymbologies.cpp
new file mode 100644
index 0000000000..0fb8d200e8
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/Scenario3_ActiveSymbologies.cpp
@@ -0,0 +1,205 @@
+#include "pch.h"
+#include "Scenario3_ActiveSymbologies.h"
+#include "Scenario3_ActiveSymbologies.g.cpp"
+
+namespace winrt
+{
+ using namespace Windows::Foundation;
+ using namespace Windows::Foundation::Collections;
+ using namespace Windows::Devices::PointOfService;
+ using namespace Windows::UI::Core;
+ using namespace Windows::UI::Xaml;
+ using namespace Windows::UI::Xaml::Data;
+ using namespace Windows::UI::Xaml::Controls;
+ using namespace Windows::UI::Xaml::Navigation;
+}
+
+namespace winrt::SDKTemplate::implementation
+{
+ Scenario3_ActiveSymbologies::Scenario3_ActiveSymbologies()
+ {
+ InitializeComponent();
+
+ m_listOfSymbologies = single_threaded_observable_vector();
+ SymbologyListSource().Source(m_listOfSymbologies);
+ }
+
+ ///
+ /// Invoked when this page is about to be displayed in a Frame.
+ ///
+ void Scenario3_ActiveSymbologies::OnNavigatedTo(NavigationEventArgs const&)
+ {
+ ResetTheScenarioState();
+ }
+
+ ///
+ /// Invoked when this page is no longer displayed.
+ ///
+ void Scenario3_ActiveSymbologies::OnNavigatedFrom(NavigationEventArgs const&)
+ {
+ ResetTheScenarioState();
+ }
+
+ ///
+ /// Event Handler for Start Scan Button Click.
+ /// Sets up the barcode scanner to be ready to receive the data events from the scan.
+ ///
+ fire_and_forget Scenario3_ActiveSymbologies::ScenarioStartScanButton_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto lifetime = get_strong();
+
+ ScenarioStartScanButton().IsEnabled(false);
+
+ m_rootPage.NotifyUser(L"Acquiring barcode scanner object.", NotifyType::StatusMessage);
+
+ // create the barcode scanner.
+ m_scanner = co_await BarcodeScanner::GetDefaultAsync();
+
+ if (m_scanner)
+ {
+ // Claim the scanner for exclusive use and enable it so raises DataReceived events.
+ m_claimedScanner = co_await m_scanner.ClaimScannerAsync();
+ if (m_claimedScanner)
+ {
+ // It is always a good idea to have a release device requested event handler.
+ // If this event is not handled, then another app can claim ownership of the barcode scanner.
+ m_scannerReleaseRequestedToken = m_claimedScanner.ReleaseDeviceRequested({ get_weak(), &Scenario3_ActiveSymbologies::claimedScanner_ReleaseDeviceRequested });
+
+ // after successfully claiming, attach the datareceived event handler.
+ m_scannerDataReceivedToken = m_claimedScanner.DataReceived({ get_weak(), &Scenario3_ActiveSymbologies::claimedScanner_DataReceived });
+
+ // Ask the platform to decode the data by default. When this is set, the platform
+ // will decode the raw data from the barcode scanner and include in the
+ // BarcodeScannerReport.ScanDataLabel and ScanDataType in the DataReceived event.
+ m_claimedScanner.IsDecodeDataEnabled(true);
+
+ // Enable the scanner so it raises DataReceived events.
+ // Do this after adding the DataReceived event handler.
+ co_await m_claimedScanner.EnableAsync();
+
+ // after successful claim, list supported symbologies
+ auto supportedSymbologies = co_await m_scanner.GetSupportedSymbologiesAsync();
+ for (uint32_t symbology : supportedSymbologies)
+ {
+ m_listOfSymbologies.Append(SymbologyListEntry{ symbology });
+ }
+
+ // reset the button state
+ ScenarioEndScanButton().IsEnabled(true);
+ SetActiveSymbologiesButton().IsEnabled(true);
+
+ m_rootPage.NotifyUser(L"Ready to scan. Device ID: " + m_claimedScanner.DeviceId(), NotifyType::StatusMessage);
+ }
+ else
+ {
+ m_scanner.Close();
+ m_scanner = nullptr;
+ ScenarioStartScanButton().IsEnabled(true);
+ m_rootPage.NotifyUser(L"Claim barcode scanner failed.", NotifyType::ErrorMessage);
+ }
+ }
+ else
+ {
+ ScenarioStartScanButton().IsEnabled(true);
+ m_rootPage.NotifyUser(L"Barcode scanner not found. Please connect a barcode scanner.", NotifyType::ErrorMessage);
+ }
+ }
+
+ ///
+ /// Event handler for the Release Device Requested event fired when barcode scanner receives Claim request from another application
+ ///
+ /// Contains the ClamiedBarcodeScanner that is sending this request
+ void Scenario3_ActiveSymbologies::claimedScanner_ReleaseDeviceRequested(IInspectable const&, ClaimedBarcodeScanner const& e)
+ {
+ // always retain the device
+ e.RetainDevice();
+ m_rootPage.NotifyUser(L"Event ReleaseDeviceRequested received. Retaining the barcode scanner.", NotifyType::StatusMessage);
+ }
+
+
+ ///
+ /// Event handler for the DataReceived event fired when a barcode is scanned by the barcode scanner
+ ///
+ /// Contains the BarcodeScannerDataReceivedEventArgs which contains the data obtained in the scan
+ fire_and_forget Scenario3_ActiveSymbologies::claimedScanner_DataReceived(ClaimedBarcodeScanner const&, BarcodeScannerDataReceivedEventArgs args)
+ {
+ auto lifetime = get_strong();
+
+ // need to update the UI data on the dispatcher thread.
+ // update the UI with the data received from the scan.
+ co_await resume_foreground(Dispatcher());
+
+ // read the data from the buffer and convert to string.
+ ScenarioOutputScanDataLabel().Text(GetDataLabelString(args.Report().ScanDataLabel(), args.Report().ScanDataType()));
+ ScenarioOutputScanData().Text(GetDataString(args.Report().ScanData()));
+ ScenarioOutputScanDataType().Text(BarcodeSymbologies::GetName(args.Report().ScanDataType()));
+ }
+
+ ///
+ /// Reset the Scenario state
+ ///
+ void Scenario3_ActiveSymbologies::ResetTheScenarioState()
+ {
+ if (m_claimedScanner)
+ {
+ // Detach the event handlers
+ m_claimedScanner.DataReceived(m_scannerDataReceivedToken);
+ m_claimedScanner.ReleaseDeviceRequested(m_scannerReleaseRequestedToken);
+
+ // Release the Barcode Scanner and set to nullptr
+ m_claimedScanner.Close();
+ m_claimedScanner = nullptr;
+ }
+
+ if (m_scanner)
+ {
+ m_scanner.Close();
+ m_scanner = nullptr;
+ }
+
+ // Reset the UI if we are still the current page.
+ if (Frame().Content() == *this)
+ {
+ m_rootPage.NotifyUser(L"Click the start scanning button to begin.", NotifyType::StatusMessage);
+ ScenarioOutputScanData().Text(L"No data");
+ ScenarioOutputScanDataLabel().Text(L"No data");
+ ScenarioOutputScanDataType().Text(L"No data");
+
+ // reset the button state
+ SetActiveSymbologiesButton().IsEnabled(false);
+ ScenarioEndScanButton().IsEnabled(false);
+ ScenarioStartScanButton().IsEnabled(true);
+
+ // reset symbology list
+ m_listOfSymbologies.Clear();
+ }
+ }
+
+ ///
+ /// Event handler for End Scan Button Click.
+ /// Releases the Barcode Scanner and resets the text in the UI
+ ///
+ void Scenario3_ActiveSymbologies::ScenarioEndScanButton_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ ResetTheScenarioState();
+ }
+
+ fire_and_forget Scenario3_ActiveSymbologies::SetActiveSymbologies_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto lifetime = get_strong();
+
+ if (m_claimedScanner)
+ {
+ std::vector symbologyList;
+ for (auto&& symbologyListEntry : m_listOfSymbologies)
+ {
+ if (symbologyListEntry.IsEnabled())
+ {
+ symbologyList.push_back(symbologyListEntry.Id());
+ }
+ }
+
+ co_await m_claimedScanner.SetActiveSymbologiesAsync(std::move(symbologyList));
+ }
+ }
+}
\ No newline at end of file
diff --git a/Samples/BarcodeScanner/cppwinrt/Scenario3_ActiveSymbologies.h b/Samples/BarcodeScanner/cppwinrt/Scenario3_ActiveSymbologies.h
new file mode 100644
index 0000000000..17d6c2e9b8
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/Scenario3_ActiveSymbologies.h
@@ -0,0 +1,51 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "Scenario3_ActiveSymbologies.g.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario3_ActiveSymbologies : Scenario3_ActiveSymbologiesT
+ {
+ Scenario3_ActiveSymbologies();
+
+ void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs const&);
+ void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs const&);
+
+ fire_and_forget ScenarioStartScanButton_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+ fire_and_forget SetActiveSymbologies_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+ void ScenarioEndScanButton_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+
+ private:
+ SDKTemplate::MainPage m_rootPage{ MainPage::Current() };
+ Windows::Devices::PointOfService::BarcodeScanner m_scanner{ nullptr };
+ Windows::Devices::PointOfService::ClaimedBarcodeScanner m_claimedScanner{ nullptr };
+
+ Windows::Foundation::Collections::IObservableVector m_listOfSymbologies{ nullptr };
+
+ event_token m_scannerReleaseRequestedToken;
+ event_token m_scannerDataReceivedToken;
+
+ void claimedScanner_ReleaseDeviceRequested(Windows::Foundation::IInspectable const&, Windows::Devices::PointOfService::ClaimedBarcodeScanner const& e);
+ fire_and_forget claimedScanner_DataReceived(Windows::Devices::PointOfService::ClaimedBarcodeScanner const&, Windows::Devices::PointOfService::BarcodeScannerDataReceivedEventArgs args);
+
+ void ResetTheScenarioState();
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario3_ActiveSymbologies : Scenario3_ActiveSymbologiesT
+ {
+ };
+}
diff --git a/Samples/BarcodeScanner/cppwinrt/Scenario3_ActiveSymbologies.xaml b/Samples/BarcodeScanner/cppwinrt/Scenario3_ActiveSymbologies.xaml
new file mode 100644
index 0000000000..46399c6d07
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/Scenario3_ActiveSymbologies.xaml
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Lists supported symbologies for the device to illustrate the use of setting active symbologiges functionality. Check or uncheck symbologies and tap "Set Active Symbologies" button to set active symbologies.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/BarcodeScanner/cppwinrt/Scenario4_SymbologyAttributes.cpp b/Samples/BarcodeScanner/cppwinrt/Scenario4_SymbologyAttributes.cpp
new file mode 100644
index 0000000000..ab4e6a2c59
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/Scenario4_SymbologyAttributes.cpp
@@ -0,0 +1,301 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "Scenario4_SymbologyAttributes.h"
+#include "Scenario4_SymbologyAttributes.g.cpp"
+
+namespace winrt
+{
+ using namespace Windows::Foundation;
+ using namespace Windows::Foundation::Collections;
+ using namespace Windows::Devices::PointOfService;
+ using namespace Windows::UI::Xaml;
+ using namespace Windows::UI::Xaml::Controls;
+ using namespace Windows::UI::Xaml::Data;
+ using namespace Windows::UI::Xaml::Navigation;
+}
+
+namespace winrt::SDKTemplate::implementation
+{
+ Scenario4_SymbologyAttributes::Scenario4_SymbologyAttributes()
+ {
+ InitializeComponent();
+
+ m_listOfSymbologies = single_threaded_observable_vector();
+ SymbologyListSource().Source(m_listOfSymbologies);
+ }
+
+ void Scenario4_SymbologyAttributes::OnNavigatedTo(NavigationEventArgs const&)
+ {
+ ResetTheScenarioState();
+ }
+
+ void Scenario4_SymbologyAttributes::OnNavigatedFrom(NavigationEventArgs const&)
+ {
+ ResetTheScenarioState();
+ }
+
+ ///
+ /// Event Handler for Start Scan Button Click.
+ /// Sets up the barcode scanner to be ready to receive the data events from the scan.
+ ///
+ fire_and_forget Scenario4_SymbologyAttributes::ScenarioStartScanButton_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto lifetime = get_strong();
+
+ ScenarioStartScanButton().IsEnabled(false);
+
+ m_rootPage.NotifyUser(L"Acquiring barcode scanner IInspectable const&.", NotifyType::StatusMessage);
+
+ // create the barcode scanner.
+ m_scanner = co_await BarcodeScanner::GetDefaultAsync();
+
+ if (m_scanner)
+ {
+ // claim the scanner for exclusive use and enable it so that data received events are received.
+ m_claimedScanner = co_await m_scanner.ClaimScannerAsync();
+ if (m_claimedScanner)
+ {
+ // It is always a good idea to have a release device requested event handler. If this event is not handled, there are chances of another app can
+ // claim ownership of the barcode scanner.
+ m_scannerReleaseRequestedToken = m_claimedScanner.ReleaseDeviceRequested(auto_revoke, { get_weak(), &Scenario4_SymbologyAttributes::claimedScanner_ReleaseDeviceRequested });
+
+ // after successfully claiming, attach the datareceived event handler.
+ m_scannerDataReceivedToken = m_claimedScanner.DataReceived(auto_revoke, { get_weak(), &Scenario4_SymbologyAttributes::claimedScanner_DataReceived });
+
+ // Ask the API to decode the data by default. By setting this, API will decode the raw data from the barcode scanner and
+ // send the ScanDataLabel and ScanDataType in the DataReceived event
+ m_claimedScanner.IsDecodeDataEnabled(true);
+
+ // enable the scanner.
+ // Note: If the scanner is not enabled (i.e. EnableAsync not called), attaching the event handler will not be any useful because the API will not fire the event
+ // if the claimedScanner has not been Enabled
+ co_await m_claimedScanner.EnableAsync();
+
+ // after successful claim, list supported symbologies
+ auto supportedSymbologies = co_await m_scanner.GetSupportedSymbologiesAsync();
+ for (uint32_t symbology : supportedSymbologies)
+ {
+ m_listOfSymbologies.Append(SymbologyListEntry{ symbology });
+ }
+
+ // reset the button state
+ ScenarioEndScanButton().IsEnabled(true);
+
+ m_rootPage.NotifyUser(L"Ready to scan. Device ID: " + m_claimedScanner.DeviceId(), NotifyType::StatusMessage);
+ }
+ else
+ {
+ m_scanner.Close();
+ m_scanner = nullptr;
+ ScenarioStartScanButton().IsEnabled(true);
+ m_rootPage.NotifyUser(L"Claim barcode scanner failed.", NotifyType::ErrorMessage);
+ }
+ }
+ else
+ {
+ ScenarioStartScanButton().IsEnabled(true);
+ m_rootPage.NotifyUser(L"Barcode scanner not found. Please connect a barcode scanner.", NotifyType::ErrorMessage);
+ }
+ }
+
+ ///
+ /// Event handler for the Release Device Requested event fired when barcode scanner receives Claim request from another application
+ ///
+ /// Contains the ClamiedBarcodeScanner that is sending this request
+ void Scenario4_SymbologyAttributes::claimedScanner_ReleaseDeviceRequested(IInspectable const&, ClaimedBarcodeScanner const& args)
+ {
+ // always retain the device
+ args.RetainDevice();
+ m_rootPage.NotifyUser(L"Event ReleaseDeviceRequested received. Retaining the barcode scanner.", NotifyType::StatusMessage);
+ }
+
+ ///
+ /// Event handler for the DataReceived event fired when a barcode is scanned by the barcode scanner
+ ///
+ /// Contains the BarcodeScannerReport which contains the data obtained in the scan
+ fire_and_forget Scenario4_SymbologyAttributes::claimedScanner_DataReceived(ClaimedBarcodeScanner const&, BarcodeScannerDataReceivedEventArgs args)
+ {
+ auto lifetime = get_strong();
+ co_await resume_foreground(Dispatcher());
+
+ // read the data from the buffer and convert to string.
+ ScenarioOutputScanDataLabel().Text(GetDataLabelString(args.Report().ScanDataLabel(), args.Report().ScanDataType()));
+ ScenarioOutputScanData().Text(GetDataString(args.Report().ScanData()));
+ ScenarioOutputScanDataType().Text(BarcodeSymbologies::GetName(args.Report().ScanDataType()));
+ }
+
+ ///
+ /// Reset the Scenario state
+ ///
+ void Scenario4_SymbologyAttributes::ResetTheScenarioState()
+ {
+ if (m_claimedScanner)
+ {
+ // Detach the event handlers
+ m_scannerDataReceivedToken.revoke();
+ m_scannerReleaseRequestedToken.revoke();
+ // Release the Barcode Scanner and set to nullptr
+ m_claimedScanner.Close();
+ m_claimedScanner = nullptr;
+ }
+
+ if (m_scanner)
+ {
+ m_scanner.Close();
+ m_scanner = nullptr;
+ }
+
+ m_symbologyAttributes = nullptr;
+
+ // Reset the UI if we are still the current page.
+ if (Frame().Content() == *this)
+ {
+ m_rootPage.NotifyUser(L"Click the start scanning button to begin.", NotifyType::StatusMessage);
+ ScenarioOutputScanData().Text(L"No data");
+ ScenarioOutputScanDataLabel().Text(L"No data");
+ ScenarioOutputScanDataType().Text(L"No data");
+
+ // reset the button state
+ ScenarioEndScanButton().IsEnabled(false);
+ ScenarioStartScanButton().IsEnabled(true);
+ SetSymbologyAttributesButton().IsEnabled(false);
+ EnableCheckDigit().IsEnabled(false);
+ TransmitCheckDigit().IsEnabled(false);
+ SetDecodeRangeLimits().IsEnabled(false);
+
+ // reset symbology list
+ m_listOfSymbologies.Clear();
+ }
+ }
+
+ ///
+ /// Event handler for End Scan Button Click.
+ /// Releases the Barcode Scanner and resets the text in the UI
+ ///
+ void Scenario4_SymbologyAttributes::ScenarioEndScanButton_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ // reset the scenario state
+ ResetTheScenarioState();
+ }
+
+ ///
+ /// Event handler for Symbology listbox selection changed.
+ /// Get symbology attributes and populate attribute UI components
+ ///
+ fire_and_forget Scenario4_SymbologyAttributes::SymbologySelection_Changed(IInspectable const&, SelectionChangedEventArgs const&)
+ {
+ auto lifetime = get_strong();
+
+ if (m_claimedScanner)
+ {
+ auto symbologyListEntry = SymbologyListBox().SelectedItem().as();
+ if (symbologyListEntry)
+ {
+ SetSymbologyAttributesButton().IsEnabled(false);
+ try
+ {
+ m_symbologyAttributes = co_await m_claimedScanner.GetSymbologyAttributesAsync(symbologyListEntry.Id());
+ }
+ catch (hresult_error const&)
+ {
+ m_symbologyAttributes = nullptr;
+ }
+
+ if (m_symbologyAttributes)
+ {
+ SetSymbologyAttributesButton().IsEnabled(true);
+
+ // initialize attributes UIs
+ EnableCheckDigit().IsEnabled(m_symbologyAttributes.IsCheckDigitValidationSupported());
+ EnableCheckDigit().IsChecked(m_symbologyAttributes.IsCheckDigitValidationEnabled());
+ TransmitCheckDigit().IsEnabled(m_symbologyAttributes.IsCheckDigitTransmissionSupported());
+ TransmitCheckDigit().IsChecked(m_symbologyAttributes.IsCheckDigitTransmissionEnabled());
+ SetDecodeRangeLimits().IsEnabled(m_symbologyAttributes.IsDecodeLengthSupported());
+ bool decodeLengthEnabled = (m_symbologyAttributes.DecodeLengthKind() == BarcodeSymbologyDecodeLengthKind::Range);
+ SetDecodeRangeLimits().IsChecked(decodeLengthEnabled);
+ if (decodeLengthEnabled)
+ {
+ MinimumDecodeLength().Value((std::min)(m_symbologyAttributes.DecodeLength1(), m_symbologyAttributes.DecodeLength2()));
+ MaximumDecodeLength().Value((std::max)(m_symbologyAttributes.DecodeLength1(), m_symbologyAttributes.DecodeLength2()));
+ }
+ }
+ else
+ {
+ m_rootPage.NotifyUser(L"Symbology attributes are not available.", NotifyType::ErrorMessage);
+ EnableCheckDigit().IsEnabled(false);
+ TransmitCheckDigit().IsEnabled(false);
+ SetDecodeRangeLimits().IsEnabled(false);
+ }
+ }
+ }
+ }
+
+ fire_and_forget Scenario4_SymbologyAttributes::SetSymbologyAttributes_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto lifetime = get_strong();
+
+ if (m_claimedScanner && m_symbologyAttributes)
+ {
+ // populate attributes
+ if (m_symbologyAttributes.IsCheckDigitValidationSupported())
+ {
+ m_symbologyAttributes.IsCheckDigitValidationEnabled(EnableCheckDigit().IsChecked().Value());
+ }
+ if (m_symbologyAttributes.IsCheckDigitTransmissionSupported())
+ {
+ m_symbologyAttributes.IsCheckDigitTransmissionEnabled(TransmitCheckDigit().IsChecked().Value());
+ }
+ if (m_symbologyAttributes.IsDecodeLengthSupported())
+ {
+ if (SetDecodeRangeLimits().IsChecked().Value())
+ {
+ m_symbologyAttributes.DecodeLengthKind(BarcodeSymbologyDecodeLengthKind::Range);
+ m_symbologyAttributes.DecodeLength1(static_cast(MinimumDecodeLength().Value()));
+ m_symbologyAttributes.DecodeLength2(static_cast(MaximumDecodeLength().Value()));
+ }
+ else
+ {
+ m_symbologyAttributes.DecodeLengthKind(BarcodeSymbologyDecodeLengthKind::AnyLength);
+ }
+ }
+
+ auto symbologyListEntry = SymbologyListBox().SelectedItem().as();
+ if (symbologyListEntry)
+ {
+ bool attributesSet = false;
+
+ try
+ {
+ attributesSet = co_await m_claimedScanner.SetSymbologyAttributesAsync(symbologyListEntry.Id(), m_symbologyAttributes);
+ }
+ catch (hresult_error const&)
+ {
+ // Scanner could not set the attributes.
+ }
+
+ if (attributesSet)
+ {
+ m_rootPage.NotifyUser(L"Attributes set for symbology '" + symbologyListEntry.Name() + L"'", NotifyType::StatusMessage);
+ }
+ else
+ {
+ m_rootPage.NotifyUser(L"Attributes could not be set for symbology '" + symbologyListEntry.Name() + L"'.", NotifyType::ErrorMessage);
+ }
+ }
+ else
+ {
+ m_rootPage.NotifyUser(L"Select a symbology from the list.", NotifyType::ErrorMessage);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Samples/BarcodeScanner/cppwinrt/Scenario4_SymbologyAttributes.h b/Samples/BarcodeScanner/cppwinrt/Scenario4_SymbologyAttributes.h
new file mode 100644
index 0000000000..4e820778aa
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/Scenario4_SymbologyAttributes.h
@@ -0,0 +1,53 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "Scenario4_SymbologyAttributes.g.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario4_SymbologyAttributes : Scenario4_SymbologyAttributesT
+ {
+ Scenario4_SymbologyAttributes();
+
+ void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs const&);
+ void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs const&);
+
+ fire_and_forget ScenarioStartScanButton_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+ void ScenarioEndScanButton_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+ fire_and_forget SymbologySelection_Changed(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::Controls::SelectionChangedEventArgs const&);
+ fire_and_forget SetSymbologyAttributes_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+
+ private:
+ SDKTemplate::MainPage m_rootPage{ MainPage::Current() };
+ Windows::Devices::PointOfService::BarcodeScanner m_scanner{ nullptr };
+ Windows::Devices::PointOfService::ClaimedBarcodeScanner m_claimedScanner{ nullptr };
+
+ Windows::Foundation::Collections::IObservableVector m_listOfSymbologies{ nullptr };
+ Windows::Devices::PointOfService::BarcodeSymbologyAttributes m_symbologyAttributes{ nullptr };
+ Windows::Devices::PointOfService::ClaimedBarcodeScanner::ReleaseDeviceRequested_revoker m_scannerReleaseRequestedToken;
+ Windows::Devices::PointOfService::ClaimedBarcodeScanner::DataReceived_revoker m_scannerDataReceivedToken;
+
+ void claimedScanner_ReleaseDeviceRequested(Windows::Foundation::IInspectable const&, Windows::Devices::PointOfService::ClaimedBarcodeScanner const& args);
+ fire_and_forget claimedScanner_DataReceived(Windows::Devices::PointOfService::ClaimedBarcodeScanner const&, Windows::Devices::PointOfService::BarcodeScannerDataReceivedEventArgs args);
+
+ void ResetTheScenarioState();
+
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario4_SymbologyAttributes : Scenario4_SymbologyAttributesT
+ {
+ };
+}
\ No newline at end of file
diff --git a/Samples/BarcodeScanner/cppwinrt/Scenario5_DisplayingBarcodePreview.cpp b/Samples/BarcodeScanner/cppwinrt/Scenario5_DisplayingBarcodePreview.cpp
new file mode 100644
index 0000000000..711425768b
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/Scenario5_DisplayingBarcodePreview.cpp
@@ -0,0 +1,453 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "Scenario5_DisplayingBarcodePreview.h"
+#include "Scenario5_DisplayingBarcodePreview.g.cpp"
+
+namespace winrt
+{
+ using namespace Windows::Foundation;
+ using namespace Windows::Foundation::Collections;
+ using namespace Windows::Devices;
+ using namespace Windows::Devices::Enumeration;
+ using namespace Windows::Devices::PointOfService;
+ using namespace Windows::Graphics::Display;
+ using namespace Windows::System::Display;
+ using namespace Windows::UI::Xaml;
+ using namespace Windows::UI::Xaml::Controls;
+ using namespace Windows::UI::Xaml::Data;
+ using namespace Windows::UI::Xaml::Navigation;
+ using namespace Windows::Media::Capture;
+}
+
+namespace winrt::SDKTemplate::implementation
+{
+ Scenario5_DisplayingBarcodePreview::Scenario5_DisplayingBarcodePreview()
+ {
+ InitializeComponent();
+
+ ScannerListSource().Source(m_barcodeScanners);
+ m_watcher = DeviceInformation::CreateWatcher(BarcodeScanner::GetDeviceSelector());
+ m_watcher.Added({ get_weak(), &Scenario5_DisplayingBarcodePreview::Watcher_Added });
+ m_watcher.Removed({ get_weak(), &Scenario5_DisplayingBarcodePreview::Watcher_Removed });
+ m_watcher.Updated({ get_weak(), &Scenario5_DisplayingBarcodePreview::Watcher_Updated });
+ m_watcher.Start();
+
+ DataContext(*this);
+ }
+
+ fire_and_forget Scenario5_DisplayingBarcodePreview::Watcher_Added(DeviceWatcher const& sender, DeviceInformation args)
+ {
+ auto lifetime = get_strong();
+ co_await Dispatcher();
+
+ m_barcodeScanners.Append({ args.Name(), args.Id() });
+
+ if (m_barcodeScanners.Size() == 1)
+ {
+ ScannerListBox().SelectedIndex(0);
+ }
+ }
+
+ fire_and_forget Scenario5_DisplayingBarcodePreview::Watcher_Removed(DeviceWatcher const&, DeviceInformationUpdate const&)
+ {
+ // We don't do anything here, but this event needs to be handled to enable realtime updates.
+ // See https://aka.ms/devicewatcher_added.
+ co_return;
+ }
+
+ fire_and_forget Scenario5_DisplayingBarcodePreview::Watcher_Updated(DeviceWatcher const&, DeviceInformationUpdate const&)
+ {
+ // We don't do anything here, but this event needs to be handled to enable realtime updates.
+ //See https://aka.ms/devicewatcher_added.
+ co_return;
+ }
+
+ fire_and_forget Scenario5_DisplayingBarcodePreview::OnNavigatedFrom(NavigationEventArgs const&)
+ {
+ auto lifetime = get_strong();
+
+ m_watcher.Stop();
+
+ if (m_isSelectionChanging)
+ {
+ isStopPending = true;
+ }
+ else
+ {
+ co_await CloseScannerResourcesAsync();
+ }
+ }
+
+ ///
+ /// Starts previewing the selected scanner's video feed and prevents the display from going to sleep.
+ ///
+ IAsyncAction Scenario5_DisplayingBarcodePreview::StartMediaCaptureAsync(hstring videoDeviceId)
+ {
+ auto lifetime = get_strong();
+ m_mediaCapture = MediaCapture();
+
+ // Register for a notification when something goes wrong
+ m_mediaCapture.Failed({ get_weak(), &Scenario5_DisplayingBarcodePreview::MediaCapture_Failed });
+
+ auto settings = MediaCaptureInitializationSettings();
+ settings.VideoDeviceId(videoDeviceId);
+ settings.StreamingCaptureMode(StreamingCaptureMode::Video);
+ settings.SharingMode(MediaCaptureSharingMode::SharedReadOnly);
+
+ // Initialize MediaCapture
+ bool captureInitialized = false;
+ try
+ {
+ co_await m_mediaCapture.InitializeAsync(settings);
+ captureInitialized = true;
+ }
+ catch (hresult_access_denied const&)
+ {
+ m_rootPage.NotifyUser(L"The app was denied access to the camera", NotifyType::ErrorMessage);
+ }
+ catch (hresult_error const& e)
+ {
+ m_rootPage.NotifyUser(L"Failed to initialize the camera: " + e.message(), NotifyType::ErrorMessage);
+ }
+
+ if (captureInitialized)
+ {
+ // Prevent the device from sleeping while the preview is running.
+ m_displayRequest.RequestActive();
+
+ PreviewControl().Source(m_mediaCapture);
+ co_await m_mediaCapture.StartPreviewAsync();
+ co_await SetPreviewRotationAsync(DisplayInformation::GetForCurrentView().CurrentOrientation());
+ IsPreviewing(true);
+ RaisePropertyChanged(L"IsPreviewing");
+ }
+ else
+ {
+ m_mediaCapture.Close();
+ m_mediaCapture = nullptr;
+ }
+ }
+
+ ///
+ /// Close the scanners and stop the preview.
+ ///
+ IAsyncAction Scenario5_DisplayingBarcodePreview::CloseScannerResourcesAsync()
+ {
+ auto lifetime = get_strong();
+ if (m_claimedScanner)
+ {
+ m_claimedScanner.Close();
+ m_claimedScanner = nullptr;
+ }
+
+ if (m_selectedScanner)
+ {
+ m_selectedScanner.Close();
+ m_selectedScanner = nullptr;
+ }
+
+ SoftwareTriggerStarted(false);
+ RaisePropertyChanged(L"SoftwareTriggerStarted");
+
+ if (!IsPreviewing())
+ {
+ co_return;
+ }
+
+ if (m_mediaCapture)
+ {
+ co_await m_mediaCapture.StopPreviewAsync();
+ m_mediaCapture.Close();
+ m_mediaCapture = nullptr;
+ }
+
+ if (m_displayRequest)
+ {
+ m_displayRequest.RequestRelease();
+ IsPreviewing(false);
+ RaisePropertyChanged(L"IsPreviewing");
+ }
+ }
+
+ ///
+ /// Set preview rotation and mirroring state to adjust for the orientation of the camera, and for embedded cameras, the rotation of the device.
+ ///
+ ///
+ ///
+ IAsyncAction Scenario5_DisplayingBarcodePreview::SetPreviewRotationAsync(DisplayOrientations displayOrientation)
+ {
+ auto lifetime = get_strong();
+ bool isExternalCamera;
+ bool isPreviewMirrored;
+
+ // Figure out where the camera is located to account for mirroring and later adjust rotation accordingly.
+ DeviceInformation cameraInformation = co_await DeviceInformation::CreateFromIdAsync(m_selectedScanner.VideoDeviceId());
+
+ if ((cameraInformation.EnclosureLocation() == nullptr) || (cameraInformation.EnclosureLocation().Panel() == Windows::Devices::Enumeration::Panel::Unknown))
+ {
+ isExternalCamera = true;
+ isPreviewMirrored = false;
+ }
+ else
+ {
+ isExternalCamera = false;
+ isPreviewMirrored = (cameraInformation.EnclosureLocation().Panel() == Windows::Devices::Enumeration::Panel::Front);
+ }
+
+ PreviewControl().FlowDirection(isPreviewMirrored ? FlowDirection::RightToLeft : FlowDirection::LeftToRight);
+
+ if (!isExternalCamera)
+ {
+ // Calculate which way and how far to rotate the preview.
+ int rotationDegrees = 0;
+ switch (displayOrientation)
+ {
+ case DisplayOrientations::Portrait:
+ rotationDegrees = 90;
+ break;
+ case DisplayOrientations::LandscapeFlipped:
+ rotationDegrees = 180;
+ break;
+ case DisplayOrientations::PortraitFlipped:
+ rotationDegrees = 270;
+ break;
+ case DisplayOrientations::Landscape:
+ default:
+ rotationDegrees = 0;
+ break;
+ }
+
+ // The rotation direction needs to be inverted if the preview is being mirrored.
+ if (isPreviewMirrored)
+ {
+ rotationDegrees = (360 - rotationDegrees) % 360;
+ }
+
+ // Add rotation metadata to the preview stream to make sure the aspect ratio / dimensions match when rendering and getting preview frames.
+ auto streamProperties = m_mediaCapture.VideoDeviceController().GetMediaStreamProperties(MediaStreamType::VideoPreview);
+ static constexpr guid rotationGuid(0xC380465D, 0x2271, 0x428C, { 0x9B, 0x83, 0xEC, 0xEA, 0x3B, 0x4A, 0x85, 0xC1 });
+ streamProperties.Properties().Insert(rotationGuid, box_value(rotationDegrees));
+ co_await m_mediaCapture.SetEncodingPropertiesAsync(MediaStreamType::VideoPreview, streamProperties, nullptr);
+ }
+ }
+
+ ///
+ /// Media capture failed, potentially due to the camera being unplugged.
+ ///
+ ///
+ ///
+ void Scenario5_DisplayingBarcodePreview::MediaCapture_Failed(MediaCapture const&, MediaCaptureFailedEventArgs const&)
+ {
+ m_rootPage.NotifyUser(L"Media capture failed. Make sure the camera is still connected.", NotifyType::ErrorMessage);
+ }
+
+ ///
+ /// Event Handler for Show Preview Button Click.
+ /// Displays the preview window for the selected barcode scanner.
+ ///
+ ///
+ ///
+ fire_and_forget Scenario5_DisplayingBarcodePreview::ShowPreviewButton_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto lifetime = get_strong();
+
+ if (m_claimedScanner)
+ {
+ co_await m_claimedScanner.ShowVideoPreviewAsync();
+ }
+ }
+
+ ///
+ /// Event Handler for Hide Preview Button Click.
+ /// Hides the preview window for the selected barcode scanner.
+ ///
+ ///
+ ///
+ void Scenario5_DisplayingBarcodePreview::HidePreviewButton_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ if (m_claimedScanner)
+ {
+ m_claimedScanner.HideVideoPreview();
+ }
+ }
+
+ ///
+ /// Event Handler for Start Software Trigger Button Click.
+ /// Starts scanning.
+ ///
+ ///
+ ///
+ fire_and_forget Scenario5_DisplayingBarcodePreview::StartSoftwareTriggerButton_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto lifetime = get_strong();
+
+ if (m_claimedScanner)
+ {
+ co_await m_claimedScanner.StartSoftwareTriggerAsync();
+
+ SoftwareTriggerStarted(true);
+ RaisePropertyChanged(L"SoftwareTriggerStarted");
+ }
+ }
+
+ ///
+ /// Event Handler for Stop Software Trigger Button Click.
+ /// Stops scanning.
+ ///
+ ///
+ ///
+ fire_and_forget Scenario5_DisplayingBarcodePreview::StopSoftwareTriggerButton_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto lifetime = get_strong();
+
+ if (m_claimedScanner)
+ {
+ co_await m_claimedScanner.StopSoftwareTriggerAsync();
+
+ SoftwareTriggerStarted(false);
+ RaisePropertyChanged(L"SoftwareTriggerStarted");
+ }
+ }
+
+ ///
+ /// Event Handler for Flip Preview Button Click.
+ /// Stops scanning.
+ ///
+ ///
+ ///
+ void Scenario5_DisplayingBarcodePreview::FlipPreview_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ if (PreviewControl().FlowDirection() == FlowDirection::LeftToRight)
+ {
+ PreviewControl().FlowDirection(FlowDirection::RightToLeft);
+ }
+ else
+ {
+ PreviewControl().FlowDirection(FlowDirection::LeftToRight);
+ }
+ }
+
+ ///
+ /// Event handler for scanner listbox selection changed
+ ///
+ ///
+ ///
+ fire_and_forget Scenario5_DisplayingBarcodePreview::ScannerSelection_Changed(IInspectable const& sender, SelectionChangedEventArgs const& args)
+ {
+ auto lifetime = get_strong();
+ auto selectedScannerInfo = args.AddedItems().GetAt(0).as();
+ auto deviceId = selectedScannerInfo.DeviceId();
+
+ if (m_isSelectionChanging)
+ {
+ m_pendingSelectionDeviceId = deviceId;
+ return;
+ }
+
+ do
+ {
+ co_await SelectScannerAsync(deviceId);
+
+ // Stop takes precedence over updating the selection.
+ if (isStopPending)
+ {
+ co_await CloseScannerResourcesAsync();
+ break;
+ }
+
+ deviceId = m_pendingSelectionDeviceId;
+ m_pendingSelectionDeviceId.clear();
+ } while (!deviceId.empty());
+ }
+
+ ///
+ /// Select the scanner specified by its device ID.
+ ///
+ ///
+ IAsyncAction Scenario5_DisplayingBarcodePreview::SelectScannerAsync(hstring scannerDeviceId)
+ {
+ auto lifetime = get_strong();
+ m_isSelectionChanging = true;
+
+ co_await CloseScannerResourcesAsync();
+
+ m_selectedScanner = co_await BarcodeScanner::FromIdAsync(scannerDeviceId);
+
+ if (m_selectedScanner)
+ {
+ m_claimedScanner = co_await m_selectedScanner.ClaimScannerAsync();
+ if (m_claimedScanner)
+ {
+ co_await m_claimedScanner.EnableAsync();
+ m_claimedScanner.Closed({ get_weak(), &Scenario5_DisplayingBarcodePreview::ClaimedScanner_Closed });
+ ScannerSupportsPreview(!m_selectedScanner.VideoDeviceId().empty());
+ RaisePropertyChanged(L"ScannerSupportsPreview");
+
+ m_claimedScanner.DataReceived({ get_weak(), &Scenario5_DisplayingBarcodePreview::ClaimedScanner_DataReceived });
+
+ if (ScannerSupportsPreview())
+ {
+ co_await StartMediaCaptureAsync(m_selectedScanner.VideoDeviceId());
+ }
+ }
+ else
+ {
+ m_rootPage.NotifyUser(L"Failed to claim the selected barcode scanner", NotifyType::ErrorMessage);
+ }
+
+ }
+ else
+ {
+ m_rootPage.NotifyUser(L"Failed to create a barcode scanner object", NotifyType::ErrorMessage);
+ }
+
+ IsScannerClaimed(m_claimedScanner != nullptr);
+ RaisePropertyChanged(L"IsScannerClaimed");
+
+ m_isSelectionChanging = false;
+ }
+
+ ///
+ /// Closed notification was received from the selected scanner.
+ ///
+ ///
+ ///
+ void Scenario5_DisplayingBarcodePreview::ClaimedScanner_Closed(ClaimedBarcodeScanner const&, ClaimedBarcodeScannerClosedEventArgs const&)
+ {
+ // Resources associated to the claimed barcode scanner can be cleaned up here
+ }
+
+ ///
+ /// Scan data was received from the selected scanner.
+ ///
+ ///
+ ///
+ fire_and_forget Scenario5_DisplayingBarcodePreview::ClaimedScanner_DataReceived(ClaimedBarcodeScanner const&, BarcodeScannerDataReceivedEventArgs args)
+ {
+ auto lifetime = get_strong();
+ co_await Dispatcher();
+ ScenarioOutputScanDataLabel().Text(GetDataLabelString(args.Report().ScanDataLabel(), args.Report().ScanDataType()));
+ ScenarioOutputScanData().Text(GetDataString(args.Report().ScanData()));
+ ScenarioOutputScanDataType().Text(BarcodeSymbologies::GetName(args.Report().ScanDataType()));
+ }
+
+ ///
+ /// Update listeners that a property was changed so that data bindings can be updated.
+ ///
+ ///
+ void Scenario5_DisplayingBarcodePreview::RaisePropertyChanged(hstring propertyName)
+ {
+ m_propertyChanged(*this, PropertyChangedEventArgs(propertyName));
+ }
+
+}
diff --git a/Samples/BarcodeScanner/cppwinrt/Scenario5_DisplayingBarcodePreview.h b/Samples/BarcodeScanner/cppwinrt/Scenario5_DisplayingBarcodePreview.h
new file mode 100644
index 0000000000..3155c1c7d3
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/Scenario5_DisplayingBarcodePreview.h
@@ -0,0 +1,119 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "Scenario5_DisplayingBarcodePreview.g.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario5_DisplayingBarcodePreview : Scenario5_DisplayingBarcodePreviewT
+ {
+ Scenario5_DisplayingBarcodePreview();
+
+ bool IsScannerClaimed()
+ {
+ return m_isScannerClaimed;
+ }
+ void IsScannerClaimed(bool claimed)
+ {
+ m_isScannerClaimed = claimed;
+ }
+
+ bool IsPreviewing()
+ {
+ return m_isPreviewing;
+ }
+ void IsPreviewing(bool isPreviewing)
+ {
+ m_isPreviewing = isPreviewing;
+ }
+
+ bool ScannerSupportsPreview()
+ {
+ return m_scannerSupportsPreview;
+ }
+ void ScannerSupportsPreview(bool supportsPreview)
+ {
+ m_scannerSupportsPreview = supportsPreview;
+ }
+
+ bool SoftwareTriggerStarted()
+ {
+ return m_softwareTriggerStarted;
+ }
+ void SoftwareTriggerStarted(bool started)
+ {
+ m_softwareTriggerStarted = started;
+ }
+
+ event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
+ {
+ return m_propertyChanged.add(handler);
+ }
+
+ void PropertyChanged(event_token const& token) noexcept
+ {
+ return m_propertyChanged.remove(token);
+ }
+
+ fire_and_forget Watcher_Added(Windows::Devices::Enumeration::DeviceWatcher const& sender, Windows::Devices::Enumeration::DeviceInformation args);
+ fire_and_forget Watcher_Updated(Windows::Devices::Enumeration::DeviceWatcher const& sender, Windows::Devices::Enumeration::DeviceInformationUpdate const& args);
+ fire_and_forget Watcher_Removed(Windows::Devices::Enumeration::DeviceWatcher const& sender, Windows::Devices::Enumeration::DeviceInformationUpdate const& args);
+
+ fire_and_forget OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs const& args);
+ fire_and_forget ScannerSelection_Changed(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs const& args);
+ void FlipPreview_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+ fire_and_forget ShowPreviewButton_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+ fire_and_forget StartSoftwareTriggerButton_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+ fire_and_forget StopSoftwareTriggerButton_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+ void HidePreviewButton_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+
+ private:
+ Windows::Foundation::IAsyncAction StartMediaCaptureAsync(hstring videoDeviceId);
+ Windows::Foundation::IAsyncAction CloseScannerResourcesAsync();
+ Windows::Foundation::IAsyncAction SetPreviewRotationAsync(Windows::Graphics::Display::DisplayOrientations displayOrientation);
+ void MediaCapture_Failed(Windows::Media::Capture::MediaCapture const& sender, Windows::Media::Capture::MediaCaptureFailedEventArgs const& errorEventArgs);
+ Windows::Foundation::IAsyncAction SelectScannerAsync(hstring scannerDeviceId);
+ void ClaimedScanner_Closed(Windows::Devices::PointOfService::ClaimedBarcodeScanner const& sender, Windows::Devices::PointOfService::ClaimedBarcodeScannerClosedEventArgs const& args);
+
+ fire_and_forget ClaimedScanner_DataReceived(Windows::Devices::PointOfService::ClaimedBarcodeScanner const&, Windows::Devices::PointOfService::BarcodeScannerDataReceivedEventArgs args);
+
+ void RaisePropertyChanged(hstring propertyName);
+
+ bool m_isScannerClaimed = false;
+ bool m_isPreviewing = false;
+ bool m_scannerSupportsPreview = false;
+ bool m_softwareTriggerStarted = false;
+
+ SDKTemplate::MainPage m_rootPage{ MainPage::Current() };
+ Windows::Foundation::Collections::IObservableVector m_barcodeScanners{ single_threaded_observable_vector() };
+ Windows::Devices::PointOfService::BarcodeScanner m_selectedScanner{ nullptr };
+ Windows::Devices::PointOfService::ClaimedBarcodeScanner m_claimedScanner{ nullptr };
+ Windows::Devices::Enumeration::DeviceWatcher m_watcher{ nullptr };
+
+ Windows::System::Display::DisplayRequest m_displayRequest;
+ Windows::Media::Capture::MediaCapture m_mediaCapture{ nullptr };
+
+ bool m_isSelectionChanging = false;
+ hstring m_pendingSelectionDeviceId;
+ bool isStopPending = false;
+
+ event m_propertyChanged;
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario5_DisplayingBarcodePreview : Scenario5_DisplayingBarcodePreviewT
+ {
+ };
+}
diff --git a/Samples/BarcodeScanner/cppwinrt/SymbologyListEntry.cpp b/Samples/BarcodeScanner/cppwinrt/SymbologyListEntry.cpp
new file mode 100644
index 0000000000..172051f686
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/SymbologyListEntry.cpp
@@ -0,0 +1,14 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "SymbologyListEntry.h"
+#include "SymbologyListEntry.g.cpp"
diff --git a/Samples/BarcodeScanner/cppwinrt/SymbologyListEntry.h b/Samples/BarcodeScanner/cppwinrt/SymbologyListEntry.h
new file mode 100644
index 0000000000..434ce09b82
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/SymbologyListEntry.h
@@ -0,0 +1,57 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "SymbologyListEntry.g.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct SymbologyListEntry : SymbologyListEntryT
+ {
+ SymbologyListEntry(uint32_t symbologyId, bool symbologyEnabled = true) :
+ m_id(symbologyId),
+ m_enabled(symbologyEnabled)
+ {
+ }
+
+ uint32_t Id()
+ {
+ return m_id;
+ }
+
+ bool IsEnabled()
+ {
+ return m_enabled;
+ }
+
+ void IsEnabled(bool enabled)
+ {
+ m_enabled = enabled;
+ }
+
+ winrt::hstring Name()
+ {
+ return winrt::Windows::Devices::PointOfService::BarcodeSymbologies::GetName(m_id);
+ }
+
+ private:
+ uint32_t m_id;
+ bool m_enabled;
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct SymbologyListEntry : SymbologyListEntryT
+ {
+ };
+}
\ No newline at end of file
diff --git a/Samples/BarcodeScanner/cppwinrt/packages.config b/Samples/BarcodeScanner/cppwinrt/packages.config
new file mode 100644
index 0000000000..68fd1b237d
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Samples/BarcodeScanner/cppwinrt/pch.cpp b/Samples/BarcodeScanner/cppwinrt/pch.cpp
new file mode 100644
index 0000000000..01484ff5aa
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/pch.cpp
@@ -0,0 +1,6 @@
+//
+// pch.cpp
+// Include the standard header and generate the precompiled header.
+//
+
+#include "pch.h"
diff --git a/Samples/BarcodeScanner/cppwinrt/pch.h b/Samples/BarcodeScanner/cppwinrt/pch.h
new file mode 100644
index 0000000000..480a2b9c8f
--- /dev/null
+++ b/Samples/BarcodeScanner/cppwinrt/pch.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include
+#include "winrt/Windows.Foundation.h"
+#include "winrt/Windows.Foundation.Collections.h"
+#include "winrt/Windows.ApplicationModel.Activation.h"
+#include "winrt/Windows.Storage.h"
+#include "winrt/Windows.Storage.Streams.h"
+#include "winrt/Windows.System.h"
+#include "winrt/Windows.System.Display.h"
+#include "winrt/Windows.UI.Core.h"
+#include "winrt/Windows.UI.Xaml.h"
+#include "winrt/Windows.UI.Xaml.Automation.Peers.h"
+#include "winrt/Windows.UI.Xaml.Controls.h"
+#include "winrt/Windows.UI.Xaml.Controls.Primitives.h"
+#include "winrt/Windows.UI.Xaml.Data.h"
+#include "winrt/Windows.UI.Xaml.Documents.h"
+#include "winrt/Windows.UI.Xaml.Interop.h"
+#include "winrt/Windows.UI.Xaml.Markup.h"
+#include "winrt/Windows.UI.Xaml.Media.h"
+#include "winrt/Windows.UI.Xaml.Navigation.h"
+#include "winrt/Windows.Devices.PointOfService.h"
+#include "winrt/Windows.Devices.Enumeration.h"
+#include "winrt/Windows.Devices.h"
+#include "winrt/Windows.Graphics.Display.h"
+#include "winrt/Windows.Media.h"
+#include "winrt/Windows.Media.Capture.h"
+#include "winrt/Windows.Media.Devices.h"
+#include "winrt/Windows.Media.MediaProperties.h"
+#include "DataHelpers.h"
+#include "BarcodeScannerInfo.h"
\ No newline at end of file
diff --git a/Samples/BarcodeScanner/cs/Scenario1_BasicFunctionality.xaml.cs b/Samples/BarcodeScanner/cs/Scenario1_BasicFunctionality.xaml.cs
index 9f78c52980..5b74e372f7 100644
--- a/Samples/BarcodeScanner/cs/Scenario1_BasicFunctionality.xaml.cs
+++ b/Samples/BarcodeScanner/cs/Scenario1_BasicFunctionality.xaml.cs
@@ -79,7 +79,7 @@ private async void ScenarioStartScanButton_Click(object sender, RoutedEventArgs
if (claimedScanner != null)
{
// It is always a good idea to have a release device requested event handler. If this event is not handled, there are chances of another app can
- // claim ownsership of the barcode scanner.
+ // claim ownership of the barcode scanner.
claimedScanner.ReleaseDeviceRequested += claimedScanner_ReleaseDeviceRequested;
// after successfully claiming, attach the datareceived event handler.
@@ -90,8 +90,7 @@ private async void ScenarioStartScanButton_Click(object sender, RoutedEventArgs
claimedScanner.IsDecodeDataEnabled = true;
// enable the scanner.
- // Note: If the scanner is not enabled (i.e. EnableAsync not called), attaching the event handler will not be any useful because the API will not fire the event
- // if the claimedScanner has not beed Enabled
+ // The scanner must be enabled in order to receive the DataReceived event.
await claimedScanner.EnableAsync();
rootPage.NotifyUser("Ready to scan. Device ID: " + claimedScanner.DeviceId, NotifyType.StatusMessage);
@@ -115,15 +114,12 @@ private async void ScenarioStartScanButton_Click(object sender, RoutedEventArgs
///
///
/// Contains the ClamiedBarcodeScanner that is sending this request
- async void claimedScanner_ReleaseDeviceRequested(object sender, ClaimedBarcodeScanner e)
+ void claimedScanner_ReleaseDeviceRequested(object sender, ClaimedBarcodeScanner e)
{
// always retain the device
e.RetainDevice();
- await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
- {
- rootPage.NotifyUser("Event ReleaseDeviceRequested received. Retaining the barcode scanner.", NotifyType.StatusMessage);
- });
+ rootPage.NotifyUser("Event ReleaseDeviceRequested received. Retaining the barcode scanner.", NotifyType.StatusMessage);
}
///
diff --git a/Samples/BarcodeScanner/cs/Scenario2_MultipleScanners.xaml.cs b/Samples/BarcodeScanner/cs/Scenario2_MultipleScanners.xaml.cs
index decfcc9fda..36a7d4a44a 100644
--- a/Samples/BarcodeScanner/cs/Scenario2_MultipleScanners.xaml.cs
+++ b/Samples/BarcodeScanner/cs/Scenario2_MultipleScanners.xaml.cs
@@ -117,7 +117,7 @@ private async void ButtonStartScanningInstance1_Click(object sender, RoutedEvent
///
async void claimedBarcodeScannerInstance1_ReleaseDeviceRequested(object sender, ClaimedBarcodeScanner e)
{
- await MainPage.Current.Dispatcher.RunAsync(
+ await Dispatcher.RunAsync(
Windows.UI.Core.CoreDispatcherPriority.Normal,
() =>
{
@@ -197,7 +197,7 @@ private async void ButtonStartScanningInstance2_Click(object sender, RoutedEvent
///
async void claimedBarcodeScannerInstance2_ReleaseDeviceRequested(object sender, ClaimedBarcodeScanner e)
{
- await MainPage.Current.Dispatcher.RunAsync(
+ await Dispatcher.RunAsync(
Windows.UI.Core.CoreDispatcherPriority.Normal,
() =>
{
@@ -211,7 +211,7 @@ await MainPage.Current.Dispatcher.RunAsync(
}
catch (Exception exception)
{
- rootPage.NotifyUser("Retain instance 1 failed: " + exception.Message, NotifyType.ErrorMessage);
+ rootPage.NotifyUser("Retain instance 2 failed: " + exception.Message, NotifyType.ErrorMessage);
}
}
//Release the device
@@ -437,7 +437,7 @@ private void ResetUI()
/// Sets the UI elements to a state corresponding to the current active Instance.
///
/// Corresponds to the current active instance
- private async void SetUI(BarcodeScannerInstance instance)
+ private void SetUI(BarcodeScannerInstance instance)
{
Instance1Border.BorderBrush = new SolidColorBrush(Colors.Gray);
Instance2Border.BorderBrush = new SolidColorBrush(Colors.Gray);
@@ -445,30 +445,19 @@ private async void SetUI(BarcodeScannerInstance instance)
switch (instance)
{
case BarcodeScannerInstance.Instance1:
- await rootPage.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
- () =>
- {
- ScenarioStartScanningInstance1.IsEnabled = false;
- ScenarioStartScanningInstance2.IsEnabled = true;
- ScenarioEndScanningInstance1.IsEnabled = true;
- ScenarioEndScanningInstance2.IsEnabled = false;
- Instance1Border.BorderBrush = new SolidColorBrush(Colors.DarkBlue);
- }
- );
-
+ ScenarioStartScanningInstance1.IsEnabled = false;
+ ScenarioStartScanningInstance2.IsEnabled = true;
+ ScenarioEndScanningInstance1.IsEnabled = true;
+ ScenarioEndScanningInstance2.IsEnabled = false;
+ Instance1Border.BorderBrush = new SolidColorBrush(Colors.DarkBlue);
break;
case BarcodeScannerInstance.Instance2:
- await rootPage.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
- () =>
- {
- ScenarioStartScanningInstance1.IsEnabled = true;
- ScenarioStartScanningInstance2.IsEnabled = false;
- ScenarioEndScanningInstance1.IsEnabled = false;
- ScenarioEndScanningInstance2.IsEnabled = true;
- Instance2Border.BorderBrush = new SolidColorBrush(Colors.DarkBlue);
- }
- );
+ ScenarioStartScanningInstance1.IsEnabled = true;
+ ScenarioStartScanningInstance2.IsEnabled = false;
+ ScenarioEndScanningInstance1.IsEnabled = false;
+ ScenarioEndScanningInstance2.IsEnabled = true;
+ Instance2Border.BorderBrush = new SolidColorBrush(Colors.DarkBlue);
break;
}
}
diff --git a/Samples/CameraStreamCoordinateMapper/cpp/Content/CameraCoordinateMapper.cpp b/Samples/CameraStreamCoordinateMapper/cpp/Content/CameraCoordinateMapper.cpp
index 1a74e85028..cc8cd33eaa 100644
--- a/Samples/CameraStreamCoordinateMapper/cpp/Content/CameraCoordinateMapper.cpp
+++ b/Samples/CameraStreamCoordinateMapper/cpp/Content/CameraCoordinateMapper.cpp
@@ -293,8 +293,15 @@ bool CameraCoordinateMapper::TryAcquireLatestFrameData() try {
if (depthToColorRef)
{
- m_rasterizeFrameBlob.depthToSource = depthToColorRef->Value;
- m_rasterizeFrameBlob.depthToTarget = depthToColorRef->Value;
+ static const float4x4 leftToRight = make_float4x4_scale(1, 1, -1);
+ static const float4x4 rightToLeft = leftToRight; // inverse is the same
+
+ // Camera coordinate systems are right-handed with -Z pointing forward out from the camera,
+ // but camera intrinsics are left-handed with +Z pointing forward out from the camera.
+ // Therefore we need to transform left-handed 3D coordinates from the intrinsics to right-handed
+ // and back again when applying the coordinate system transforms which expect right-handed coordinates.
+ m_rasterizeFrameBlob.depthToSource = leftToRight * depthToColorRef->Value * rightToLeft;
+ m_rasterizeFrameBlob.depthToTarget = leftToRight * depthToColorRef->Value * rightToLeft;
}
else
{
diff --git a/Samples/CameraStreamCorrelation/cpp/Scenario1_CorrelateStreams.xaml.cpp b/Samples/CameraStreamCorrelation/cpp/Scenario1_CorrelateStreams.xaml.cpp
index ad0c552bcd..2e12c4d504 100644
--- a/Samples/CameraStreamCorrelation/cpp/Scenario1_CorrelateStreams.xaml.cpp
+++ b/Samples/CameraStreamCorrelation/cpp/Scenario1_CorrelateStreams.xaml.cpp
@@ -410,7 +410,14 @@ void Scenario1_CorrelateStreams::FrameReader_FrameArrived(MediaFrameReader^ send
if (IBox^ boxedDepthToColorTransform = depthCoordinateSystem->TryGetTransformTo(colorCoordinateSystem))
{
- float4x4 depthToColorTransform = boxedDepthToColorTransform->Value;
+ static const float4x4 leftToRight = make_float4x4_scale(1, 1, -1);
+ static const float4x4 rightToLeft = leftToRight; // inverse is the same
+
+ // Camera coordinate systems are right-handed with -Z pointing forward out from the camera,
+ // but camera intrinsics are left-handed with +Z pointing forward out from the camera.
+ // Therefore we need to transform left-handed 3D coordinates from the intrinsics to right-handed
+ // and back again when applying the coordinate system transforms which expect right-handed coordinates.
+ float4x4 depthToColorTransform = leftToRight * boxedDepthToColorTransform->Value * rightToLeft;
skeletalFrameRenderer->Render(result->Frame, ref new CoordinateTransformationMethod(
[colorIntrinsics, depthToColorTransform, widthScale, heightScale](float3 point)
diff --git a/Samples/Capabilities/README.md b/Samples/Capabilities/README.md
new file mode 100644
index 0000000000..7a7cff9074
--- /dev/null
+++ b/Samples/Capabilities/README.md
@@ -0,0 +1,75 @@
+---
+page_type: sample
+languages:
+- csharp
+- cpp
+- cppwinrt
+products:
+- windows
+- windows-uwp
+urlFragment: Capability
+extendedZipContent:
+- path: SharedContent
+ target: SharedContent
+- path: LICENSE
+ target: LICENSE
+description: "Shows how to query and request declared capabilities."
+---
+
+
+
+# Capability sample
+
+Shows how to query and request declared capabilities.
+
+> **Note:** This sample is part of a large collection of UWP feature samples.
+> You can download this sample as a standalone ZIP file
+> [from docs.microsoft.com](https://docs.microsoft.com/samples/microsoft/windows-universal-samples/resizeappview/),
+> or you can download the entire collection as a single
+> [ZIP file](https://github.com/Microsoft/Windows-universal-samples/archive/master.zip), but be
+> sure to unzip everything to access shared dependencies. For more info on working with the ZIP file,
+> the samples collection, and GitHub, see [Get the UWP samples from GitHub](https://aka.ms/ovu2uq).
+> For more samples, see the [Samples portal](https://aka.ms/winsamples) on the Windows Dev Center.
+
+The sample shows the following techniques:
+
+- Checking whether a declared capability has been granted.
+- Responding when a capability is granted or denied.
+- Requesting multiple capabilities.
+
+**Note** The Windows universal samples require Visual Studio to build and Windows 10 to execute.
+
+To obtain information about Windows 10 development, go to the [Windows Dev Center](http://go.microsoft.com/fwlink/?LinkID=532421)
+
+To obtain information about Microsoft Visual Studio and the tools for developing Windows apps, go to [Visual Studio](http://go.microsoft.com/fwlink/?LinkID=532422)
+
+## Related topics
+
+### Reference
+
+[AppCapability class](https://docs.microsoft.com/uwp/api/Windows.Security.Authorization.AppCapabilityAccess.AppCapability]
+
+## System requirements
+
+* Windows 10 version 18362 or higher
+
+## Build the sample
+
+1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
+2. Start Microsoft Visual Studio and select **File** \> **Open** \> **Project/Solution**.
+3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language. Double-click the Visual Studio Solution (.sln) file.
+4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
+
+## Run the sample
+
+The next steps depend on whether you just want to deploy the sample or you want to both deploy and run it.
+
+### Deploying the sample
+
+- Select Build > Deploy Solution.
+
+### Deploying and running the sample
+
+- To debug the sample and then run it, press F5 or select Debug > Start Debugging. To run the sample without debugging, press Ctrl+F5 or select Debug > Start Without Debugging.
diff --git a/Samples/Capabilities/cppwinrt/Capabilities.sln b/Samples/Capabilities/cppwinrt/Capabilities.sln
new file mode 100644
index 0000000000..6428f13650
--- /dev/null
+++ b/Samples/Capabilities/cppwinrt/Capabilities.sln
@@ -0,0 +1,43 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30320.27
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Capabilities", "Capabilities.vcxproj", "{5619D0BF-06A8-53D5-A0C0-64CD917623D8}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM = Release|ARM
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {5619D0BF-06A8-53D5-A0C0-64CD917623D8}.Debug|ARM.ActiveCfg = Debug|ARM
+ {5619D0BF-06A8-53D5-A0C0-64CD917623D8}.Debug|ARM.Build.0 = Debug|ARM
+ {5619D0BF-06A8-53D5-A0C0-64CD917623D8}.Debug|ARM.Deploy.0 = Debug|ARM
+ {5619D0BF-06A8-53D5-A0C0-64CD917623D8}.Debug|x64.ActiveCfg = Debug|x64
+ {5619D0BF-06A8-53D5-A0C0-64CD917623D8}.Debug|x64.Build.0 = Debug|x64
+ {5619D0BF-06A8-53D5-A0C0-64CD917623D8}.Debug|x64.Deploy.0 = Debug|x64
+ {5619D0BF-06A8-53D5-A0C0-64CD917623D8}.Debug|x86.ActiveCfg = Debug|Win32
+ {5619D0BF-06A8-53D5-A0C0-64CD917623D8}.Debug|x86.Build.0 = Debug|Win32
+ {5619D0BF-06A8-53D5-A0C0-64CD917623D8}.Debug|x86.Deploy.0 = Debug|Win32
+ {5619D0BF-06A8-53D5-A0C0-64CD917623D8}.Release|ARM.ActiveCfg = Release|ARM
+ {5619D0BF-06A8-53D5-A0C0-64CD917623D8}.Release|ARM.Build.0 = Release|ARM
+ {5619D0BF-06A8-53D5-A0C0-64CD917623D8}.Release|ARM.Deploy.0 = Release|ARM
+ {5619D0BF-06A8-53D5-A0C0-64CD917623D8}.Release|x64.ActiveCfg = Release|x64
+ {5619D0BF-06A8-53D5-A0C0-64CD917623D8}.Release|x64.Build.0 = Release|x64
+ {5619D0BF-06A8-53D5-A0C0-64CD917623D8}.Release|x64.Deploy.0 = Release|x64
+ {5619D0BF-06A8-53D5-A0C0-64CD917623D8}.Release|x86.ActiveCfg = Release|Win32
+ {5619D0BF-06A8-53D5-A0C0-64CD917623D8}.Release|x86.Build.0 = Release|Win32
+ {5619D0BF-06A8-53D5-A0C0-64CD917623D8}.Release|x86.Deploy.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {CB13346E-02AA-4E25-BBC4-D57D894293B5}
+ EndGlobalSection
+EndGlobal
diff --git a/Samples/Capabilities/cppwinrt/Capabilities.vcxproj b/Samples/Capabilities/cppwinrt/Capabilities.vcxproj
new file mode 100644
index 0000000000..3300f03f4e
--- /dev/null
+++ b/Samples/Capabilities/cppwinrt/Capabilities.vcxproj
@@ -0,0 +1,188 @@
+
+
+
+
+ $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), LICENSE))\SharedContent
+
+
+ true
+ {5619D0BF-06A8-53D5-A0C0-64CD917623D8}
+ Capabilities
+ SDKTemplate
+ en-US
+ 15.0
+ true
+ Windows Store
+ 10.0
+ 10.0.18362.0
+ $(WindowsTargetPlatformVersion)
+
+
+
+
+ Debug
+ ARM
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ ARM
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ Application
+ Unicode
+
+
+ true
+ true
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+ $(VC_IncludePath);$(UniversalCRT_IncludePath);$(WindowsSDK_IncludePath);$(SharedContentDir)\cppwinrt
+ true
+
+
+
+ Use
+ pch.h
+ $(IntDir)pch.pch
+ Level4
+ %(AdditionalOptions) /bigobj
+ 4453;28204
+
+
+
+
+ _DEBUG;%(PreprocessorDefinitions)
+
+
+
+
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+
+
+ $(SharedContentDir)\xaml\App.xaml
+
+
+ $(SharedContentDir)\xaml\MainPage.xaml
+
+
+
+ ..\shared\Scenario1_Check.xaml
+
+
+ ..\shared\Scenario2_RequestMany.xaml
+
+
+
+
+
+ Designer
+
+
+ Designer
+
+
+
+
+ Styles\Styles.xaml
+
+
+
+
+ $(SharedContentDir)\xaml\App.xaml
+
+
+ $(SharedContentDir)\xaml\MainPage.xaml
+
+
+ SampleConfiguration.h
+
+
+ ..\shared\Scenario1_Check.xaml
+
+
+ ..\shared\Scenario2_RequestMany.xaml
+
+
+ Create
+ pch.h
+
+
+ Project.idl
+
+
+
+
+ $(SharedContentDir)\xaml\MainPage.xaml
+
+
+
+
+
+ Designer
+
+
+
+
+
+ Assets\microsoft-sdk.png
+
+
+ Assets\smallTile-sdk.png
+
+
+ Assets\splash-sdk.png
+
+
+ Assets\squareTile-sdk.png
+
+
+ Assets\storeLogo-sdk.png
+
+
+ Assets\tile-sdk.png
+
+
+ Assets\windows-sdk.png
+
+
+
+
+
+
+
+
+ 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}.
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/Capabilities/cppwinrt/Capabilities.vcxproj.filters b/Samples/Capabilities/cppwinrt/Capabilities.vcxproj.filters
new file mode 100644
index 0000000000..1e5e18c0e6
--- /dev/null
+++ b/Samples/Capabilities/cppwinrt/Capabilities.vcxproj.filters
@@ -0,0 +1,63 @@
+
+
+
+
+ 4416d50a-7676-4d0a-9b2c-91ff70c6047f
+ bmp;fbx;gif;jpg;jpeg;tga;tiff;tif;png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/Capabilities/cppwinrt/Package.appxmanifest b/Samples/Capabilities/cppwinrt/Package.appxmanifest
new file mode 100644
index 0000000000..264b6a996c
--- /dev/null
+++ b/Samples/Capabilities/cppwinrt/Package.appxmanifest
@@ -0,0 +1,43 @@
+
+
+
+
+
+ Capabilities C++/WinRT Sample
+ Microsoft Corporation
+ Assets\storelogo-sdk.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/Capabilities/cppwinrt/Project.idl b/Samples/Capabilities/cppwinrt/Project.idl
new file mode 100644
index 0000000000..e19da3aa85
--- /dev/null
+++ b/Samples/Capabilities/cppwinrt/Project.idl
@@ -0,0 +1,25 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+namespace SDKTemplate
+{
+ [default_interface]
+ runtimeclass Scenario1_Check : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario1_Check();
+ }
+
+ [default_interface]
+ runtimeclass Scenario2_RequestMany : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario2_RequestMany();
+ }
+}
diff --git a/Samples/Capabilities/cppwinrt/SampleConfiguration.cpp b/Samples/Capabilities/cppwinrt/SampleConfiguration.cpp
new file mode 100644
index 0000000000..d934c7e6cc
--- /dev/null
+++ b/Samples/Capabilities/cppwinrt/SampleConfiguration.cpp
@@ -0,0 +1,30 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include
+#include "MainPage.h"
+#include "SampleConfiguration.h"
+
+using namespace winrt;
+using namespace winrt::Windows::Foundation::Collections;
+using namespace winrt::SDKTemplate;
+
+hstring implementation::MainPage::FEATURE_NAME()
+{
+ return L"Capabilities C++/WinRT Sample";
+}
+
+IVector implementation::MainPage::scenariosInner = winrt::single_threaded_observable_vector(
+{
+ Scenario{ L"Check capability", xaml_typename() },
+ Scenario{ L"Request multiple capabilities", xaml_typename() },
+});
diff --git a/Samples/Capabilities/cppwinrt/SampleConfiguration.h b/Samples/Capabilities/cppwinrt/SampleConfiguration.h
new file mode 100644
index 0000000000..93a2f26cbf
--- /dev/null
+++ b/Samples/Capabilities/cppwinrt/SampleConfiguration.h
@@ -0,0 +1,17 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+#include "pch.h"
+
+namespace winrt::SDKTemplate
+{
+}
diff --git a/Samples/Capabilities/cppwinrt/Scenario1_Check.cpp b/Samples/Capabilities/cppwinrt/Scenario1_Check.cpp
new file mode 100644
index 0000000000..ebbf0ed3fb
--- /dev/null
+++ b/Samples/Capabilities/cppwinrt/Scenario1_Check.cpp
@@ -0,0 +1,168 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "Scenario1_Check.h"
+#include "Scenario1_Check.g.cpp"
+#include
+
+using namespace winrt;
+using namespace winrt::Windows::Devices::Geolocation;
+using namespace winrt::Windows::Foundation;
+using namespace winrt::Windows::Security::Authorization::AppCapabilityAccess;
+using namespace winrt::Windows::System;
+using namespace winrt::Windows::UI::Xaml;
+using namespace winrt::Windows::UI::Xaml::Navigation;
+
+namespace winrt::SDKTemplate::implementation
+{
+ Scenario1_Check::Scenario1_Check()
+ {
+ InitializeComponent();
+ }
+
+ void Scenario1_Check::OnNavigatedTo(NavigationEventArgs const&)
+ {
+ // Specify which capability we want to query/monitor.
+ locationCapability = AppCapability::Create(L"location");
+
+ // Register a handler to be called when access changes.
+ accessChangedToken = locationCapability.AccessChanged({ get_weak(), &Scenario1_Check::OnCapabilityAccessChanged });
+
+ // Update UI to match current access.
+ UpdateCapabilityStatus();
+ }
+
+ void Scenario1_Check::OnNavigatedFrom(NavigationEventArgs const&)
+ {
+ locationCapability.AccessChanged(accessChangedToken);
+ }
+
+ fire_and_forget Scenario1_Check::OnCapabilityAccessChanged(AppCapability const&, IInspectable const&)
+ {
+ auto lifetime = get_strong();
+ co_await resume_foreground(Dispatcher());
+ UpdateCapabilityStatus();
+ }
+
+ fire_and_forget Scenario1_Check::RequestAccessButton_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto lifetime = get_strong();
+
+ switch (locationCapability.CheckAccess())
+ {
+ case AppCapabilityAccessStatus::Allowed:
+ // Access was already granted.
+ // AccessChanged event will trigger a recalc.
+ break;
+
+ case AppCapabilityAccessStatus::UserPromptRequired:
+ // Request access directly for a better experience than going to Settings.
+ // This is equivalent to calling Geolocator::RequestAccessAsync().
+ if (co_await locationCapability.RequestAccessAsync() == AppCapabilityAccessStatus::Allowed)
+ {
+ // The user granted access.
+ // AccessChanged event will trigger a recalc.
+ }
+ break;
+
+ case AppCapabilityAccessStatus::DeniedByUser:
+ case AppCapabilityAccessStatus::DeniedBySystem:
+ default:
+ // Send user to Settings to obtain location permission
+ // or explain why access is denied.
+ co_await Launcher::LaunchUriAsync(Uri(L"ms-settings:privacy-location"));
+ break;
+
+ }
+ }
+
+ IAsyncAction Scenario1_Check::ShowLocationAsync()
+ {
+ auto lifetime = get_strong();
+
+ if (co_await Geolocator::RequestAccessAsync() == GeolocationAccessStatus::Allowed)
+ {
+ // Need try/catch because we can lose geolocator access at any time.
+ try
+ {
+ LocationTextBlock().Text(L"Calculating current location...");
+ Geolocator geolocator;
+ Geoposition pos = co_await geolocator.GetGeopositionAsync();
+ if (pos == nullptr)
+ {
+ LocationTextBlock().Text(L"Current location unknown.");
+ }
+ else
+ {
+ std::wostringstream output;
+ output << L"Approximate location is Latitude " << pos.Coordinate().Point().Position().Latitude <<
+ L", Longitude" << pos.Coordinate().Point().Position().Longitude;
+ LocationTextBlock().Text(output.str());
+ }
+ }
+ catch (hresult_access_denied const&)
+ {
+ // Lost access in the middle of the operation.
+ // AccessChanged event will trigger a recalc.
+ }
+ }
+ else
+ {
+ // Lost access before operation started.
+ // AccessChanged event will trigger a recalc.
+ }
+ }
+
+ fire_and_forget Scenario1_Check::UpdateCapabilityStatus()
+ {
+ auto lifetime = get_strong();
+
+ AppCapabilityAccessStatus status = locationCapability.CheckAccess();
+ if (status == AppCapabilityAccessStatus::Allowed)
+ {
+ LocationTextBlock().Visibility(Visibility::Visible);
+ RequestAccessButton().Visibility(Visibility::Collapsed);
+ co_await ShowLocationAsync();
+ }
+ else
+ {
+ LocationTextBlock().Visibility(Visibility::Collapsed);
+
+ switch (status)
+ {
+ case AppCapabilityAccessStatus::NotDeclaredByApp:
+ // The app neglected to declare the capability in its manifest.
+ // This is a developer error.
+ RequestAccessButton().Visibility(Visibility::Collapsed);
+ rootPage.NotifyUser(L"App misconfiguration error. Contact vendor for support.", NotifyType::ErrorMessage);
+ break;
+
+ default:
+ case AppCapabilityAccessStatus::DeniedBySystem:
+ // We can send the user to the Settings page to obtain access
+ // or at least explain why access is denied.
+ RequestAccessButton().Visibility(Visibility::Visible);
+ break;
+
+ case AppCapabilityAccessStatus::DeniedByUser:
+ // We can send the user to the Settings page to obtain access.
+ RequestAccessButton().Visibility(Visibility::Visible);
+ break;
+
+ case AppCapabilityAccessStatus::UserPromptRequired:
+ // We can prompt the user to give us access.
+ RequestAccessButton().Visibility(Visibility::Visible);
+ break;
+ }
+ }
+ }
+}
diff --git a/Samples/Capabilities/cppwinrt/Scenario1_Check.h b/Samples/Capabilities/cppwinrt/Scenario1_Check.h
new file mode 100644
index 0000000000..710edec22e
--- /dev/null
+++ b/Samples/Capabilities/cppwinrt/Scenario1_Check.h
@@ -0,0 +1,43 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "Scenario1_Check.g.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario1_Check : Scenario1_CheckT
+ {
+ Scenario1_Check();
+
+ void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs const&);
+ void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs const&);
+
+ fire_and_forget RequestAccessButton_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+
+ private:
+ SDKTemplate::MainPage rootPage{ MainPage::Current() };
+ Windows::Security::Authorization::AppCapabilityAccess::AppCapability locationCapability{ nullptr };
+ event_token accessChangedToken;
+
+ fire_and_forget OnCapabilityAccessChanged(Windows::Security::Authorization::AppCapabilityAccess::AppCapability const&, Windows::Foundation::IInspectable const&);
+ Windows::Foundation::IAsyncAction ShowLocationAsync();
+ fire_and_forget UpdateCapabilityStatus();
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario1_Check : Scenario1_CheckT
+ {
+ };
+}
diff --git a/Samples/Capabilities/cppwinrt/Scenario2_RequestMany.cpp b/Samples/Capabilities/cppwinrt/Scenario2_RequestMany.cpp
new file mode 100644
index 0000000000..4e5d754e3a
--- /dev/null
+++ b/Samples/Capabilities/cppwinrt/Scenario2_RequestMany.cpp
@@ -0,0 +1,62 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "Scenario2_RequestMany.h"
+#include "Scenario2_RequestMany.g.cpp"
+
+using namespace winrt;
+using namespace winrt::Windows::Foundation;
+using namespace winrt::Windows::Foundation::Collections;
+using namespace winrt::Windows::Security::Authorization::AppCapabilityAccess;
+using namespace winrt::Windows::UI::Xaml;
+
+namespace winrt::SDKTemplate::implementation
+{
+ Scenario2_RequestMany::Scenario2_RequestMany()
+ {
+ InitializeComponent();
+ }
+
+ fire_and_forget Scenario2_RequestMany::RequestAccessButton_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto lifetime = get_strong();
+
+ // This will prompt for any capabilities whose current status is UserPromptRequired.
+ IMapView result =
+ co_await AppCapability::RequestAccessForCapabilitiesAsync({ L"location", L"webcam" });
+ hstring locationMessage;
+ if (result.Lookup(L"location") == AppCapabilityAccessStatus::Allowed)
+ {
+ locationMessage = L"Location access is granted. ";
+ }
+ else
+ {
+ // We could inspect the specific status to provide better feedback,
+ // but for the purpose of this sample, we merely report whether access was granted
+ // and do not study the reason why.
+ locationMessage = L"Location access is not granted. ";
+ }
+ hstring webcamMessage;
+ if (result.Lookup(L"webcam") == AppCapabilityAccessStatus::Allowed)
+ {
+ webcamMessage = L"Webcam access is granted. ";
+ }
+ else
+ {
+ // We could inspect the specific status to provide better feedback,
+ // but for the purpose of this sample, we merely report whether access was granted
+ // and do not study the reason why.
+ webcamMessage = L"Webcam access is not granted. ";
+ }
+ rootPage.NotifyUser(locationMessage + webcamMessage, NotifyType::StatusMessage);
+ }
+}
diff --git a/Samples/Capabilities/cppwinrt/Scenario2_RequestMany.h b/Samples/Capabilities/cppwinrt/Scenario2_RequestMany.h
new file mode 100644
index 0000000000..f1037e3fba
--- /dev/null
+++ b/Samples/Capabilities/cppwinrt/Scenario2_RequestMany.h
@@ -0,0 +1,34 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "Scenario2_RequestMany.g.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario2_RequestMany : Scenario2_RequestManyT
+ {
+ Scenario2_RequestMany();
+
+ fire_and_forget RequestAccessButton_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+
+ private:
+ SDKTemplate::MainPage rootPage{ MainPage::Current() };
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario2_RequestMany : Scenario2_RequestManyT
+ {
+ };
+}
diff --git a/Samples/Capabilities/cppwinrt/packages.config b/Samples/Capabilities/cppwinrt/packages.config
new file mode 100644
index 0000000000..81f107b8bc
--- /dev/null
+++ b/Samples/Capabilities/cppwinrt/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Samples/Capabilities/cppwinrt/pch.cpp b/Samples/Capabilities/cppwinrt/pch.cpp
new file mode 100644
index 0000000000..01484ff5aa
--- /dev/null
+++ b/Samples/Capabilities/cppwinrt/pch.cpp
@@ -0,0 +1,6 @@
+//
+// pch.cpp
+// Include the standard header and generate the precompiled header.
+//
+
+#include "pch.h"
diff --git a/Samples/Capabilities/cppwinrt/pch.h b/Samples/Capabilities/cppwinrt/pch.h
new file mode 100644
index 0000000000..5ceba7e51a
--- /dev/null
+++ b/Samples/Capabilities/cppwinrt/pch.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include
+#include "winrt/Windows.Foundation.h"
+#include "winrt/Windows.Foundation.Collections.h"
+#include "winrt/Windows.ApplicationModel.Activation.h"
+#include "winrt/Windows.Devices.Geolocation.h"
+#include "winrt/Windows.Security.Authorization.AppCapabilityAccess.h"
+#include "winrt/Windows.System.h"
+#include "winrt/Windows.UI.Core.h"
+#include "winrt/Windows.UI.Xaml.h"
+#include "winrt/Windows.UI.Xaml.Automation.Peers.h"
+#include "winrt/Windows.UI.Xaml.Controls.h"
+#include "winrt/Windows.UI.Xaml.Controls.Primitives.h"
+#include "winrt/Windows.UI.Xaml.Documents.h"
+#include "winrt/Windows.UI.Xaml.Interop.h"
+#include "winrt/Windows.UI.Xaml.Markup.h"
+#include "winrt/Windows.UI.Xaml.Media.h"
+#include "winrt/Windows.UI.Xaml.Navigation.h"
diff --git a/Samples/Capabilities/cs/Capabilities.csproj b/Samples/Capabilities/cs/Capabilities.csproj
new file mode 100644
index 0000000000..978722dea8
--- /dev/null
+++ b/Samples/Capabilities/cs/Capabilities.csproj
@@ -0,0 +1,186 @@
+
+
+
+
+ $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), LICENSE))\SharedContent
+
+
+ Debug
+ {9E2A70C2-36E7-531C-83D0-29E2FCCF8916}
+ AppContainerExe
+ Properties
+ SDKTemplate
+ Capabilities
+ en-US
+ UAP
+ 10.0.18362.0
+ 10.0.18362.0
+ 14
+ true
+ 512
+ {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+
+
+ true
+ bin\ARM\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP
+ ;2008
+ full
+ ARM
+ false
+ prompt
+ true
+
+
+ bin\ARM\Release\
+ TRACE;NETFX_CORE;WINDOWS_UAP
+ true
+ ;2008
+ pdbonly
+ ARM
+ false
+ prompt
+ true
+ true
+
+
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP
+ ;2008
+ full
+ x64
+ false
+ prompt
+ true
+
+
+ bin\x64\Release\
+ TRACE;NETFX_CORE;WINDOWS_UAP
+ true
+ ;2008
+ pdbonly
+ x64
+ false
+ prompt
+ true
+ true
+
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP
+ ;2008
+ full
+ x86
+ false
+ prompt
+ true
+
+
+ bin\x86\Release\
+ TRACE;NETFX_CORE;WINDOWS_UAP
+ true
+ ;2008
+ pdbonly
+ x86
+ false
+ prompt
+ true
+ true
+
+
+
+ App.xaml.cs
+ App.xaml
+
+
+ MainPage.xaml.cs
+ MainPage.xaml
+
+
+ Properties\AssemblyInfo.cs
+
+
+
+ Scenario1_Check.xaml
+
+
+ Scenario2_RequestMany.xaml
+
+
+
+
+ Designer
+
+
+
+
+ App.xaml
+ MSBuild:Compile
+ Designer
+
+
+ MainPage.xaml
+ MSBuild:Compile
+ Designer
+
+
+ Scenario1_Check.xaml
+ MSBuild:Compile
+ Designer
+
+
+ Scenario2_RequestMany.xaml
+ MSBuild:Compile
+ Designer
+
+
+ Styles\Styles.xaml
+ MSBuild:Compile
+ Designer
+
+
+
+
+ Properties\Default.rd.xml
+
+
+ Assets\microsoft-sdk.png
+
+
+ Assets\smallTile-sdk.png
+
+
+ Assets\splash-sdk.png
+
+
+ Assets\squareTile-sdk.png
+
+
+ Assets\storeLogo-sdk.png
+
+
+ Assets\tile-sdk.png
+
+
+ Assets\windows-sdk.png
+
+
+
+
+ 5.0.0
+
+
+
+ 14.0
+
+
+
+
diff --git a/Samples/Capabilities/cs/Capabilities.sln b/Samples/Capabilities/cs/Capabilities.sln
new file mode 100644
index 0000000000..dc5ce9d03f
--- /dev/null
+++ b/Samples/Capabilities/cs/Capabilities.sln
@@ -0,0 +1,43 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30320.27
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Capabilities", "Capabilities.csproj", "{9E2A70C2-36E7-531C-83D0-29E2FCCF8916}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM = Release|ARM
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {9E2A70C2-36E7-531C-83D0-29E2FCCF8916}.Debug|ARM.ActiveCfg = Debug|ARM
+ {9E2A70C2-36E7-531C-83D0-29E2FCCF8916}.Debug|ARM.Build.0 = Debug|ARM
+ {9E2A70C2-36E7-531C-83D0-29E2FCCF8916}.Debug|ARM.Deploy.0 = Debug|ARM
+ {9E2A70C2-36E7-531C-83D0-29E2FCCF8916}.Debug|x64.ActiveCfg = Debug|x64
+ {9E2A70C2-36E7-531C-83D0-29E2FCCF8916}.Debug|x64.Build.0 = Debug|x64
+ {9E2A70C2-36E7-531C-83D0-29E2FCCF8916}.Debug|x64.Deploy.0 = Debug|x64
+ {9E2A70C2-36E7-531C-83D0-29E2FCCF8916}.Debug|x86.ActiveCfg = Debug|x86
+ {9E2A70C2-36E7-531C-83D0-29E2FCCF8916}.Debug|x86.Build.0 = Debug|x86
+ {9E2A70C2-36E7-531C-83D0-29E2FCCF8916}.Debug|x86.Deploy.0 = Debug|x86
+ {9E2A70C2-36E7-531C-83D0-29E2FCCF8916}.Release|ARM.ActiveCfg = Release|ARM
+ {9E2A70C2-36E7-531C-83D0-29E2FCCF8916}.Release|ARM.Build.0 = Release|ARM
+ {9E2A70C2-36E7-531C-83D0-29E2FCCF8916}.Release|ARM.Deploy.0 = Release|ARM
+ {9E2A70C2-36E7-531C-83D0-29E2FCCF8916}.Release|x64.ActiveCfg = Release|x64
+ {9E2A70C2-36E7-531C-83D0-29E2FCCF8916}.Release|x64.Build.0 = Release|x64
+ {9E2A70C2-36E7-531C-83D0-29E2FCCF8916}.Release|x64.Deploy.0 = Release|x64
+ {9E2A70C2-36E7-531C-83D0-29E2FCCF8916}.Release|x86.ActiveCfg = Release|x86
+ {9E2A70C2-36E7-531C-83D0-29E2FCCF8916}.Release|x86.Build.0 = Release|x86
+ {9E2A70C2-36E7-531C-83D0-29E2FCCF8916}.Release|x86.Deploy.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {694E262D-A0FE-4828-B5C2-DD2BA1FDD292}
+ EndGlobalSection
+EndGlobal
diff --git a/Samples/Capabilities/cs/Package.appxmanifest b/Samples/Capabilities/cs/Package.appxmanifest
new file mode 100644
index 0000000000..938d48b1b6
--- /dev/null
+++ b/Samples/Capabilities/cs/Package.appxmanifest
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+ Capabilities C# Sample
+ Microsoft Corporation
+ Assets\StoreLogo-sdk.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/Capabilities/cs/SampleConfiguration.cs b/Samples/Capabilities/cs/SampleConfiguration.cs
new file mode 100644
index 0000000000..ebc9262469
--- /dev/null
+++ b/Samples/Capabilities/cs/SampleConfiguration.cs
@@ -0,0 +1,34 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+using System;
+using System.Collections.Generic;
+using Windows.UI.Xaml.Controls;
+
+namespace SDKTemplate
+{
+ public partial class MainPage : Page
+ {
+ public const string FEATURE_NAME = "Capabilities";
+
+ List scenarios = new List
+ {
+ new Scenario() { Title="Check capability", ClassType=typeof(Scenario1_Check)},
+ new Scenario() { Title="Request multiple capabilities", ClassType=typeof(Scenario2_RequestMany)},
+ };
+ }
+
+ public class Scenario
+ {
+ public string Title { get; set; }
+ public Type ClassType { get; set; }
+ }
+}
diff --git a/Samples/Capabilities/cs/Scenario1_Check.xaml.cs b/Samples/Capabilities/cs/Scenario1_Check.xaml.cs
new file mode 100644
index 0000000000..e96e48344a
--- /dev/null
+++ b/Samples/Capabilities/cs/Scenario1_Check.xaml.cs
@@ -0,0 +1,164 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+using System;
+using System.Threading.Tasks;
+using Windows.Devices.Geolocation;
+using Windows.Foundation;
+using Windows.Security.Authorization.AppCapabilityAccess;
+using Windows.System;
+using Windows.UI.Core;
+using Windows.UI.ViewManagement;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Input;
+using Windows.UI.Xaml.Navigation;
+
+namespace SDKTemplate
+{
+ public sealed partial class Scenario1_Check : Page
+ {
+ private MainPage rootPage = MainPage.Current;
+ AppCapability locationCapability = null;
+
+ public Scenario1_Check()
+ {
+ this.InitializeComponent();
+ }
+
+ protected override void OnNavigatedTo(NavigationEventArgs e)
+ {
+ // Specify which capability we want to query/monitor.
+ locationCapability = AppCapability.Create("location");
+
+ // Register a handler to be called when access changes.
+ locationCapability.AccessChanged += OnCapabilityAccessChanged;
+
+ // Update UI to match current access.
+ UpdateCapabilityStatus();
+ }
+
+ protected override void OnNavigatedFrom(NavigationEventArgs e)
+ {
+ locationCapability.AccessChanged -= OnCapabilityAccessChanged;
+ }
+
+ async void OnCapabilityAccessChanged(AppCapability sender, object e)
+ {
+ await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => UpdateCapabilityStatus());
+ }
+
+ async void RequestAccessButton_Click(object sender, RoutedEventArgs e)
+ {
+ switch (locationCapability.CheckAccess())
+ {
+ case AppCapabilityAccessStatus.Allowed:
+ // Access was already granted.
+ // AccessChanged event will trigger a recalc.
+ break;
+
+ case AppCapabilityAccessStatus.UserPromptRequired:
+ // Request access directly for a better experience than going to Settings.
+ // This is equivalent to calling Geolocator::RequestAccessAsync().
+ if (await locationCapability.RequestAccessAsync() == AppCapabilityAccessStatus.Allowed)
+ {
+ // The user granted access.
+ // AccessChanged event will trigger a recalc.
+ }
+ break;
+
+ case AppCapabilityAccessStatus.DeniedByUser:
+ case AppCapabilityAccessStatus.DeniedBySystem:
+ default:
+ // Send user to Settings to obtain location permission
+ // or explain why access is denied.
+ await Launcher.LaunchUriAsync(new Uri("ms-settings:privacy-location"));
+ break;
+
+ }
+ }
+
+ async Task ShowLocationAsync()
+ {
+ if (await Geolocator.RequestAccessAsync() == GeolocationAccessStatus.Allowed)
+ {
+ // Need try/catch because we can lose geolocator access at any time.
+ try
+ {
+ LocationTextBlock.Text = "Calculating current location...";
+ Geolocator geolocator = new Geolocator();
+ Geoposition pos = await geolocator.GetGeopositionAsync();
+ if (pos == null)
+ {
+ LocationTextBlock.Text = "Current location unknown.";
+ }
+ else
+ {
+ LocationTextBlock.Text = $"Approximate location is Latitude {pos.Coordinate.Point.Position.Latitude:F}, Longitude {pos.Coordinate.Point.Position.Longitude:F}";
+ }
+
+ }
+ catch (Exception ex) when (ex.HResult == unchecked((int)0x80070005)) // E_ACCESSDENIED
+ {
+ // Lost access in the middle of the operation.
+ // AccessChanged event will trigger a recalc.
+ }
+ }
+ else
+ {
+ // Lost access before operation started.
+ // AccessChanged event will trigger a recalc.
+ }
+ }
+
+ async void UpdateCapabilityStatus()
+ {
+ AppCapabilityAccessStatus status = locationCapability.CheckAccess();
+ if (status == AppCapabilityAccessStatus.Allowed)
+ {
+ LocationTextBlock.Visibility = Visibility.Visible;
+ RequestAccessButton.Visibility = Visibility.Collapsed;
+ await ShowLocationAsync();
+ }
+ else
+ {
+ LocationTextBlock.Visibility = Visibility.Collapsed;
+
+ switch (status)
+ {
+ case AppCapabilityAccessStatus.NotDeclaredByApp:
+ // The app neglected to declare the capability in its manifest.
+ // This is a developer error.
+ RequestAccessButton.Visibility = Visibility.Collapsed;
+ rootPage.NotifyUser("App misconfiguration error. Contact vendor for support.", NotifyType.ErrorMessage);
+ break;
+
+ default:
+ case AppCapabilityAccessStatus.DeniedBySystem:
+ // We can send the user to the Settings page to obtain access
+ // or at least explain why access is denied.
+ RequestAccessButton.Visibility = Visibility.Visible;
+ break;
+
+ case AppCapabilityAccessStatus.DeniedByUser:
+ // We can send the user to the Settings page to obtain access.
+ RequestAccessButton.Visibility = Visibility.Visible;
+ break;
+
+ case AppCapabilityAccessStatus.UserPromptRequired:
+ // We can prompt the user to give us access.
+ RequestAccessButton.Visibility = Visibility.Visible;
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/Samples/Capabilities/cs/Scenario2_RequestMany.xaml.cs b/Samples/Capabilities/cs/Scenario2_RequestMany.xaml.cs
new file mode 100644
index 0000000000..a117c88b59
--- /dev/null
+++ b/Samples/Capabilities/cs/Scenario2_RequestMany.xaml.cs
@@ -0,0 +1,62 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+using System;
+using System.Collections.Generic;
+using Windows.Foundation;
+using Windows.Security.Authorization.AppCapabilityAccess;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+
+namespace SDKTemplate
+{
+ public sealed partial class Scenario2_RequestMany : Page
+ {
+ MainPage rootPage = MainPage.Current;
+
+ public Scenario2_RequestMany()
+ {
+ this.InitializeComponent();
+ }
+
+ async void RequestAccessButton_Click(object sender, RoutedEventArgs e)
+ {
+ // This will prompt for any capabilities whose current status is UserPromptRequired.
+ IReadOnlyDictionary result =
+ await AppCapability.RequestAccessForCapabilitiesAsync(new[] { "location", "webcam" });
+ string locationMessage;
+ if (result["location"] == AppCapabilityAccessStatus.Allowed)
+ {
+ locationMessage = "Location access is granted. ";
+ }
+ else
+ {
+ // We could inspect the specific status to provide better feedback,
+ // but for the purpose of this sample, we merely report whether access was granted
+ // and do not study the reason why.
+ locationMessage = "Location access is not granted. ";
+ }
+ string webcamMessage;
+ if (result["webcam"] == AppCapabilityAccessStatus.Allowed)
+ {
+ webcamMessage = "Webcam access is granted. ";
+ }
+ else
+ {
+ // We could inspect the specific status to provide better feedback,
+ // but for the purpose of this sample, we merely report whether access was granted
+ // and do not study the reason why.
+ webcamMessage = "Webcam access is not granted. ";
+ }
+ rootPage.NotifyUser(locationMessage + webcamMessage, NotifyType.StatusMessage);
+ }
+ }
+}
diff --git a/Samples/Capabilities/shared/Scenario1_Check.xaml b/Samples/Capabilities/shared/Scenario1_Check.xaml
new file mode 100644
index 0000000000..945613cecd
--- /dev/null
+++ b/Samples/Capabilities/shared/Scenario1_Check.xaml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+ Checking capabilities
+
+
+ An app can check whether a capability has already been granted.
+ This permits it to take advantage of granted capabilities
+ without triggering a prompt
+ if the capability has not yet been granted.
+
+
+
+ Click to enable location tracking
+
+
+
diff --git a/Samples/Capabilities/shared/Scenario2_RequestMany.xaml b/Samples/Capabilities/shared/Scenario2_RequestMany.xaml
new file mode 100644
index 0000000000..77b4db0d1a
--- /dev/null
+++ b/Samples/Capabilities/shared/Scenario2_RequestMany.xaml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+ Requesting capabilities
+
+
+ An app can request access to multiple capabilities at once.
+
+ Request access to both location and camera
+
+
diff --git a/Samples/HolographicTagAlong/cpp/Content/QuadRenderer.cpp b/Samples/HolographicTagAlong/cpp/Content/QuadRenderer.cpp
index bf162f4ef1..9fc661a2c8 100644
--- a/Samples/HolographicTagAlong/cpp/Content/QuadRenderer.cpp
+++ b/Samples/HolographicTagAlong/cpp/Content/QuadRenderer.cpp
@@ -80,20 +80,21 @@ void QuadRenderer::Update(const DX::StepTimer& timer)
const float oneOverDeltaTime = 1.f / deltaTime;
// Create a direction normal from the hologram's position to the origin of person space.
- // This is the z-axis rotation.
+ // This is the z-axis of our rotated coordinate system in unrotated space.
XMVECTOR facingNormal = XMVector3Normalize(-XMLoadFloat3(&m_position));
// Rotate the x-axis around the y-axis.
- // This is a 90-degree angle from the normal, in the xz-plane.
- // This is the x-axis rotation.
+ // This rotation is achieved by projecting the normal into the xz-plane.
+ // This is the x-axis of our rotated coordinate system in unrotated space.
XMVECTOR xAxisRotation = XMVector3Normalize(XMVectorSet(XMVectorGetZ(facingNormal), 0.f, -XMVectorGetX(facingNormal), 0.f));
// Create a third normal to satisfy the conditions of a rotation matrix.
- // The cross product of the other two normals is at a 90-degree angle to
- // both normals. (Normalize the cross product to avoid floating-point math
- // errors.)
- // Note how the cross product will never be a zero-matrix because the two normals
- // are always at a 90-degree angle from one another.
+ // The cross product of the other two normals is at a 90-degree angle to
+ // both normals. The cross product is normalized to avoid floating-point
+ // math errors.
+ // Note how the cross product will never be null because the two axis
+ // normals we generated above will always be at a 90-degree angle from
+ // one another.
XMVECTOR yAxisRotation = XMVector3Normalize(XMVector3Cross(facingNormal, xAxisRotation));
// Construct the 4x4 rotation matrix.
diff --git a/Samples/Logging/README.md b/Samples/Logging/README.md
index 5114c9ab0e..3b3cf21f86 100644
--- a/Samples/Logging/README.md
+++ b/Samples/Logging/README.md
@@ -4,6 +4,7 @@ languages:
- csharp
- cpp
- cppcx
+- cppwinrt
products:
- windows
- windows-uwp
diff --git a/Samples/Logging/cppwinrt/FileLoggingSessionScenario.cpp b/Samples/Logging/cppwinrt/FileLoggingSessionScenario.cpp
new file mode 100644
index 0000000000..2ff6b2bc80
--- /dev/null
+++ b/Samples/Logging/cppwinrt/FileLoggingSessionScenario.cpp
@@ -0,0 +1,399 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "FileLoggingSessionScenario.h"
+#include "LoggingScenarioHelpers.h"
+
+#define SCENARIO_PREFIX L"FileLoggingSessionScenario_"
+#define DEFAULT_SESSION_NAME SCENARIO_PREFIX L"Session"
+#define DEFAULT_CHANNEL_NAME SCENARIO_PREFIX L"Channel"
+#define OUR_SAMPLE_APP_LOG_FILE_FOLDER_NAME SCENARIO_PREFIX L"LogFiles"
+#define LOGGING_ENABLED_SETTING_KEY_NAME SCENARIO_PREFIX L"LoggingEnabled"
+#define LOGFILEGEN_BEFORE_SUSPEND_SETTING_KEY_NAME SCENARIO_PREFIX L"LogFileGeneratedBeforeSuspend"
+
+using namespace winrt;
+using namespace winrt::Windows::Foundation;
+using namespace winrt::Windows::Foundation::Diagnostics;
+using namespace winrt::Windows::Storage;
+using namespace winrt::SDKTemplate;
+
+FileLoggingSessionScenario::~FileLoggingSessionScenario()
+{
+}
+
+FileLoggingSessionScenario::FileLoggingSessionScenario()
+{
+ // Create the logging channel.
+ // When an app logs messages to a channel, the messges will go
+ // to any sessions which are consuming messages from the channel.
+ _channel = LoggingChannel(DEFAULT_CHANNEL_NAME);
+
+ // This sample listens to the channel's events so it can track
+ // information about the channel's enablement status.
+ _channel.LoggingEnabled({ this, &FileLoggingSessionScenario::OnChannelLoggingEnabled });
+
+ // Attach event handlers for Suspend/Resume.
+ Windows::UI::Xaml::Application app = Windows::UI::Xaml::Application::Current();
+ app.Suspending({ this, &FileLoggingSessionScenario::OnAppSuspending });
+ app.Resuming({ this, &FileLoggingSessionScenario::OnAppResuming });
+
+ // If the app is being launched (not resumed), the following call will
+ // activate logging if it had been active at the time of the last suspend.
+ ResumeLoggingIfApplicable();
+}
+
+// static
+FileLoggingSessionScenario&
+FileLoggingSessionScenario::Instance()
+{
+ static FileLoggingSessionScenario instance;
+ return instance;
+}
+
+event_token
+FileLoggingSessionScenario::StatusChanged(StatusChangedHandler const& handler)
+{
+ return _statusChanged.add(handler);
+}
+
+void
+FileLoggingSessionScenario::StatusChanged(event_token const& token) noexcept
+{
+ _statusChanged.remove(token);
+}
+
+bool
+FileLoggingSessionScenario::IsBusy() const noexcept
+{
+ return _isBusy != 0;
+}
+
+int
+FileLoggingSessionScenario::LogFileGeneratedCount() const noexcept
+{
+ return _logFileGeneratedCount;
+}
+
+bool
+FileLoggingSessionScenario::LoggingEnabled() const noexcept
+{
+ return _session != nullptr;
+}
+
+// Handle a request to toggle logging enable/disable status.
+IAsyncOperation
+FileLoggingSessionScenario::ToggleLoggingEnabledDisabledAsync()
+{
+ BusySetter busy(*this);
+
+ if (_session != nullptr)
+ {
+ // Save any final log file.
+ StorageFile finalLogFile = co_await CloseSessionSaveFinalLogFile();
+
+ // Cleanup the session and let the sample UI know of the new status.
+ _session.Close();
+ _session = nullptr;
+ _statusChanged(make(LoggingScenarioEventType::LogFileGeneratedAtDisable, finalLogFile == nullptr ? L"" : finalLogFile.Path()));
+ _settings.Insert(LOGGING_ENABLED_SETTING_KEY_NAME, box_value(false));
+ _statusChanged(make(LoggingScenarioEventType::LoggingEnabledDisabled, false));
+ co_return false;
+ }
+ else
+ {
+ // Enable logging and let the UI know of the new status.
+ StartLogging();
+ _settings.Insert(LOGGING_ENABLED_SETTING_KEY_NAME, box_value(true));
+ _statusChanged(make(LoggingScenarioEventType::LoggingEnabledDisabled, true));
+ co_return true;
+ }
+}
+
+// DoScenarioAsync creates a worker thread to simulate application activity.
+// In actual use, logging functions would be called from various parts of a
+// larger application. The purpose of the below concise function is to show
+// how logging works over periods of time when lots of messages are logged.
+// Primarily, it shows how log files are generated when each log file reaches
+// its maximum capacity. This function logs information in a loop
+// that exits after 3 log files have been generated. After each log file is
+// generated, the sample's UI is updated with the log file's name.
+IAsyncAction
+FileLoggingSessionScenario::DoScenarioAsync()
+{
+ // Tell the UI the scenario is busy working.
+ BusySetter busy(*this);
+
+ std::wstring messageToLog;
+
+ int messageIndex = 0; // Increments for each logging call.
+ int startFileCount = LogFileGeneratedCount();
+
+ const int NUMBER_OF_LOG_FILES_TO_GENERATE = 3;
+
+ // To demo logging, loop and log messages until 3 log files have been produced.
+ // Each time a new log is created, the FileLoggingSession will notify this sample
+ // via the FileLoggingSession::LogFileGenerated event.
+ // While not 3 files yet, execute the following code...
+ while (LogFileGeneratedCount() - startFileCount < NUMBER_OF_LOG_FILES_TO_GENERATE)
+ {
+ // Since the channel is added to the session at level Warning, the following
+ // message is logged because it is logged at level LoggingLevel.Critical.
+ messageToLog = L"Message=";
+ messageToLog += std::to_wstring(++messageIndex);
+ messageToLog +=
+ L": Lorem ipsum dolor sit amet, consectetur adipiscing elit.In ligula nisi, vehicula nec eleifend vel, rutrum non dolor.Vestibulum ante ipsum "
+ L"primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur elementum scelerisque accumsan. In hac habitasse platea dictumst.";
+ _channel.LogMessage(messageToLog, LoggingLevel::Critical);
+
+ // Since the channel is added to the session at level Warning, the following
+ // message is *not* logged because it is logged at LoggingLevel.Information.
+ messageToLog = L"Message=";
+ messageToLog += std::to_wstring(++messageIndex);
+ messageToLog +=
+ L": Lorem ipsum dolor sit amet, consectetur adipiscing elit.In ligula nisi, vehicula nec eleifend vel, rutrum non dolor.Vestibulum ante ipsum "
+ L"primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur elementum scelerisque accumsan. In hac habitasse platea dictumst.";
+ _channel.LogMessage(messageToLog, LoggingLevel::Information);
+
+ int value = 1000000; // one million, 7 digits, 4-bytes as an int, 14 bytes as a wide character string.
+ messageToLog = L"Value #";
+ messageToLog += std::to_wstring(++messageIndex);
+ messageToLog += L':';
+ messageToLog += std::to_wstring(value);
+ _channel.LogMessage(messageToLog, LoggingLevel::Critical); // 'value' is logged as 14 byte wide character string.
+ ++messageIndex;
+ _channel.LogValuePair(L"Value", value, LoggingLevel::Critical); // 'value' is logged as a 4-byte integer.
+
+ //
+ // Pause every once in a while to simulate application activity outside of logging.
+ //
+
+ if (messageIndex % 50 == 0)
+ {
+ co_await resume_after(std::chrono::milliseconds(5));
+ }
+ }
+}
+
+void
+FileLoggingSessionScenario::StartLogging()
+{
+ // If no session exists, create one.
+ // NOTE: There are use cases where an application
+ // may want to create only a channel for sessions outside
+ // of the application itself. See MSDN for details. This
+ // sample is the common scenario of an app logging events
+ // which it wants to place in its own log file, so it creates
+ // a session and channel as a pair. The channel is created
+ // during construction of this LoggingScenario class so
+ // it already exsits by the time this function is called.
+ if (_session == nullptr)
+ {
+ _session = FileLoggingSession(DEFAULT_SESSION_NAME);
+ _session.LogFileGenerated({ this, &FileLoggingSessionScenario::OnLogFileGenerated }); // event+=handler
+ }
+
+ // This sample adds the channel at level "warning" to
+ // demonstrated how messages logged at more verbose levels
+ // are ignored by the session.
+ _session.AddLoggingChannel(_channel, LoggingLevel::Warning);
+}
+
+// Prepare this scenario for suspend.
+IAsyncAction
+FileLoggingSessionScenario::PrepareToSuspendAsync()
+{
+ if (_session != nullptr)
+ {
+ _isPreparingForSuspend = true;
+
+ // Before suspend, save any final log file.
+ StorageFile finalLogFile = co_await CloseSessionSaveFinalLogFile();
+
+ // Cleanup the session.
+ _session.Close();
+ _session = nullptr;
+
+ // Save values used when the app is resumed or started later.
+ // Logging is enabled.
+ _settings.Insert(LOGGING_ENABLED_SETTING_KEY_NAME, box_value(true));
+
+ // If there's a final log file...
+ if (finalLogFile != nullptr)
+ {
+ // Save the log file name saved at suspend so the sample UI can be
+ // updated on resume with that information.
+ _settings.Insert(LOGFILEGEN_BEFORE_SUSPEND_SETTING_KEY_NAME, box_value(finalLogFile.Path()));
+ }
+ else
+ {
+ _settings.TryRemove(LOGFILEGEN_BEFORE_SUSPEND_SETTING_KEY_NAME);
+ }
+
+ _isPreparingForSuspend = false;
+ }
+ else
+ {
+ // Save values used when the app is resumed or started later.
+ // Logging is not enabled and no log file was saved.
+ _settings.Insert(LOGGING_ENABLED_SETTING_KEY_NAME, box_value(false));
+ _settings.TryRemove(LOGFILEGEN_BEFORE_SUSPEND_SETTING_KEY_NAME);
+ }
+}
+
+// This is called when the app is either resuming or starting.
+// It will enable logging if the app has never been started before
+// or if logging had been enabled the last time the app was running.
+void
+FileLoggingSessionScenario::ResumeLoggingIfApplicable()
+{
+ bool loggingEnabled = unbox_value_or(_settings.TryLookup(LOGGING_ENABLED_SETTING_KEY_NAME), true);
+ if (loggingEnabled)
+ {
+ StartLogging();
+ }
+
+ // When the sample suspends, it retains state as to whether or not it had
+ // generated a new log file at the last suspension. This allows any
+ // UI to be updated on resume to reflect that fact.
+ hstring pathOfLogFileGeneratedBeforeSuspend = unbox_value_or(_settings.TryLookup(LOGFILEGEN_BEFORE_SUSPEND_SETTING_KEY_NAME), L"");
+ if (!pathOfLogFileGeneratedBeforeSuspend.empty())
+ {
+ _statusChanged(make(LoggingScenarioEventType::LogFileGeneratedAtSuspend, pathOfLogFileGeneratedBeforeSuspend));
+ _settings.TryRemove(LOGFILEGEN_BEFORE_SUSPEND_SETTING_KEY_NAME);
+ }
+}
+
+IAsyncOperation
+FileLoggingSessionScenario::CloseSessionSaveFinalLogFile()
+{
+ // Tell the session to save its final log file.
+ StorageFile finalFileBeforeSuspend = co_await _session.CloseAndSaveToFileAsync();
+
+ if (finalFileBeforeSuspend != nullptr)
+ {
+ // A final log file was created.
+ // Move it to the sample-defined log folder.
+ // First, get create/open our sample-defined log folder.
+ StorageFolder ourSampleAppLogFolder =
+ co_await ApplicationData::Current().LocalFolder().CreateFolderAsync(
+ OUR_SAMPLE_APP_LOG_FILE_FOLDER_NAME,
+ CreationCollisionOption::OpenIfExists);
+
+ std::wstring logFileName;
+ logFileName += L"Log-";
+ logFileName += GetTimeStamp();
+ logFileName += L".etl";
+ co_await finalFileBeforeSuspend.MoveAsync(ourSampleAppLogFolder, logFileName, NameCollisionOption::FailIfExists);
+
+ std::wstring fullPath;
+ fullPath += ourSampleAppLogFolder.Path();
+ fullPath += L'\\';
+ fullPath += logFileName;
+
+ StorageFile movedFile = co_await StorageFile::GetFileFromPathAsync(hstring(fullPath));
+ return movedFile;
+ }
+
+ return nullptr;
+}
+
+void
+FileLoggingSessionScenario::OnChannelLoggingEnabled(
+ ILoggingChannel const& sender,
+ IInspectable const&)
+{
+ // This method is called when the channel is informing us of channel-related state changes.
+ // Save new channel state. These values can be used for advanced logging scenarios where,
+ // for example, it's desired to skip blocks of logging code if the channel is not being
+ // consumed by any sessions.
+ _isChannelEnabled = sender.Enabled();
+ _channelLoggingLevel = sender.Level();
+}
+
+// When the log file gets large, the system closes it and starts a new one.
+// The LogFileGenerated event is raised to give the app a chance to move
+// the recently-generated log file to a safe place. When the handler returns,
+// the FileLoggingSession may reuse the file name for a new log file.
+// This function moves the log file to an app-defined location.
+fire_and_forget
+FileLoggingSessionScenario::OnLogFileGenerated(
+ IFileLoggingSession const& sender,
+ LogFileGeneratedEventArgs const& args)
+{
+ ++_logFileGeneratedCount;
+
+ StorageFile generatedLogFile = args.File();
+
+ // Create the app-defined folder under the app's local folder.
+ // An app defines where/how it wants to store log files.
+ // This sample uses OUR_SAMPLE_APP_LOG_FILE_FOLDER_NAME under
+ // the app's local folder.
+ StorageFolder ourSampleAppLogFolder =
+ co_await ApplicationData::Current().LocalFolder().CreateFolderAsync(
+ OUR_SAMPLE_APP_LOG_FILE_FOLDER_NAME,
+ CreationCollisionOption::OpenIfExists);
+
+ std::wstring logFileName;
+ logFileName += L"Log-";
+ logFileName += GetTimeStamp();
+ logFileName += L".etl";
+
+ // Move the log file to our sample app's log folder.
+ co_await generatedLogFile.MoveAsync(ourSampleAppLogFolder, logFileName, NameCollisionOption::FailIfExists);
+
+ // Update the UI to show the new log file.
+ if (_isPreparingForSuspend == false)
+ {
+ hstring fullPath = ourSampleAppLogFolder.Path() + L"\\" + logFileName;
+ _statusChanged(make(LoggingScenarioEventType::LogFileGenerated, fullPath));
+ }
+}
+
+fire_and_forget
+FileLoggingSessionScenario::OnAppSuspending(
+ IInspectable const&,
+ Windows::ApplicationModel::SuspendingEventArgs const& e)
+{
+ // Get a deferral before performing any async operations
+ // to avoid suspension prior to LoggingScenario completing
+ // PrepareToSuspendAsync().
+ auto deferral = e.SuspendingOperation().GetDeferral();
+ co_await PrepareToSuspendAsync();
+ deferral.Complete();
+}
+
+void FileLoggingSessionScenario::OnAppResuming(
+ IInspectable const&,
+ IInspectable const&)
+{
+ // If logging was active at the last suspend,
+ // ResumeLoggingIfApplicable will re-activate
+ // logging.
+ ResumeLoggingIfApplicable();
+}
+
+FileLoggingSessionScenario::BusySetter::~BusySetter()
+{
+ if (0 == --_scenario._isBusy)
+ {
+ _scenario._statusChanged(make(LoggingScenarioEventType::BusyStatusChanged));
+ }
+}
+
+FileLoggingSessionScenario::BusySetter::BusySetter(FileLoggingSessionScenario& scenario)
+ : _scenario(scenario)
+{
+ if (1 == ++_scenario._isBusy)
+ {
+ _scenario._statusChanged(make(LoggingScenarioEventType::BusyStatusChanged));
+ }
+}
diff --git a/Samples/Logging/cppwinrt/FileLoggingSessionScenario.h b/Samples/Logging/cppwinrt/FileLoggingSessionScenario.h
new file mode 100644
index 0000000000..57931f8b52
--- /dev/null
+++ b/Samples/Logging/cppwinrt/FileLoggingSessionScenario.h
@@ -0,0 +1,104 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+#include "LoggingScenarioEventArgs.h"
+
+namespace winrt::SDKTemplate
+{
+ class FileLoggingSessionScenario
+ {
+ // This is a singleton, only created/destroyed by the Instance() method.
+ ~FileLoggingSessionScenario();
+ FileLoggingSessionScenario();
+
+ public:
+
+ static FileLoggingSessionScenario&
+ Instance();
+
+ event_token
+ StatusChanged(StatusChangedHandler const& handler);
+
+ void
+ StatusChanged(event_token const& token) noexcept;
+
+ bool
+ IsBusy() const noexcept;
+
+ int
+ LogFileGeneratedCount() const noexcept;
+
+ bool
+ LoggingEnabled() const noexcept;
+
+ Windows::Foundation::IAsyncOperation
+ ToggleLoggingEnabledDisabledAsync();
+
+ Windows::Foundation::IAsyncAction
+ DoScenarioAsync();
+
+ private:
+
+ void
+ StartLogging();
+
+ Windows::Foundation::IAsyncAction
+ PrepareToSuspendAsync();
+
+ void
+ ResumeLoggingIfApplicable();
+
+ Windows::Foundation::IAsyncOperation
+ CloseSessionSaveFinalLogFile();
+
+ void
+ OnChannelLoggingEnabled(
+ Windows::Foundation::Diagnostics::ILoggingChannel const& sender,
+ Windows::Foundation::IInspectable const& args);
+
+ fire_and_forget
+ OnLogFileGenerated(
+ Windows::Foundation::Diagnostics::IFileLoggingSession const& sender,
+ Windows::Foundation::Diagnostics::LogFileGeneratedEventArgs const& args);
+
+ fire_and_forget
+ OnAppSuspending(Windows::Foundation::IInspectable const& sender,
+ Windows::ApplicationModel::SuspendingEventArgs const& e);
+
+ void
+ OnAppResuming(Windows::Foundation::IInspectable const& sender,
+ Windows::Foundation::IInspectable const& args);
+
+ private:
+
+ struct BusySetter
+ {
+ ~BusySetter();
+ explicit BusySetter(FileLoggingSessionScenario& scenario);
+ FileLoggingSessionScenario& _scenario;
+ };
+
+ Windows::Foundation::Diagnostics::FileLoggingSession _session{ nullptr };
+ Windows::Foundation::Diagnostics::LoggingChannel _channel{ nullptr };
+
+ std::atomic _logFileGeneratedCount;
+ std::atomic _isBusy;
+ bool _isPreparingForSuspend = false;
+
+ bool _isChannelEnabled = false;
+ Windows::Foundation::Diagnostics::LoggingLevel _channelLoggingLevel{};
+
+ Windows::Foundation::Collections::IPropertySet _settings{ Windows::Storage::ApplicationData::Current().LocalSettings().Values() };
+
+ event _statusChanged;
+ };
+}
diff --git a/Samples/Logging/cppwinrt/Logging.sln b/Samples/Logging/cppwinrt/Logging.sln
new file mode 100644
index 0000000000..f958ec9f1f
--- /dev/null
+++ b/Samples/Logging/cppwinrt/Logging.sln
@@ -0,0 +1,43 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30320.27
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Logging", "Logging.vcxproj", "{39D38C25-25B2-4344-A60B-0B45EB32A2D5}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM = Release|ARM
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {39D38C25-25B2-4344-A60B-0B45EB32A2D5}.Debug|ARM.ActiveCfg = Debug|ARM
+ {39D38C25-25B2-4344-A60B-0B45EB32A2D5}.Debug|ARM.Build.0 = Debug|ARM
+ {39D38C25-25B2-4344-A60B-0B45EB32A2D5}.Debug|ARM.Deploy.0 = Debug|ARM
+ {39D38C25-25B2-4344-A60B-0B45EB32A2D5}.Debug|x64.ActiveCfg = Debug|x64
+ {39D38C25-25B2-4344-A60B-0B45EB32A2D5}.Debug|x64.Build.0 = Debug|x64
+ {39D38C25-25B2-4344-A60B-0B45EB32A2D5}.Debug|x64.Deploy.0 = Debug|x64
+ {39D38C25-25B2-4344-A60B-0B45EB32A2D5}.Debug|x86.ActiveCfg = Debug|Win32
+ {39D38C25-25B2-4344-A60B-0B45EB32A2D5}.Debug|x86.Build.0 = Debug|Win32
+ {39D38C25-25B2-4344-A60B-0B45EB32A2D5}.Debug|x86.Deploy.0 = Debug|Win32
+ {39D38C25-25B2-4344-A60B-0B45EB32A2D5}.Release|ARM.ActiveCfg = Release|ARM
+ {39D38C25-25B2-4344-A60B-0B45EB32A2D5}.Release|ARM.Build.0 = Release|ARM
+ {39D38C25-25B2-4344-A60B-0B45EB32A2D5}.Release|ARM.Deploy.0 = Release|ARM
+ {39D38C25-25B2-4344-A60B-0B45EB32A2D5}.Release|x64.ActiveCfg = Release|x64
+ {39D38C25-25B2-4344-A60B-0B45EB32A2D5}.Release|x64.Build.0 = Release|x64
+ {39D38C25-25B2-4344-A60B-0B45EB32A2D5}.Release|x64.Deploy.0 = Release|x64
+ {39D38C25-25B2-4344-A60B-0B45EB32A2D5}.Release|x86.ActiveCfg = Release|Win32
+ {39D38C25-25B2-4344-A60B-0B45EB32A2D5}.Release|x86.Build.0 = Release|Win32
+ {39D38C25-25B2-4344-A60B-0B45EB32A2D5}.Release|x86.Deploy.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {8B3EAE62-ABE2-4450-BDFD-0A35E56B141B}
+ EndGlobalSection
+EndGlobal
diff --git a/Samples/Logging/cppwinrt/Logging.vcxproj b/Samples/Logging/cppwinrt/Logging.vcxproj
new file mode 100644
index 0000000000..80e8ecc49c
--- /dev/null
+++ b/Samples/Logging/cppwinrt/Logging.vcxproj
@@ -0,0 +1,215 @@
+
+
+
+
+ $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), LICENSE))\SharedContent
+
+
+ true
+ {39D38C25-25B2-4344-A60B-0B45EB32A2D5}
+ Logging
+ SDKTemplate
+ en-US
+ 15.0
+ true
+ Windows Store
+ 10.0
+ 10.0.18362.0
+ $(WindowsTargetPlatformVersion)
+
+
+
+
+ Debug
+ ARM
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ ARM
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ Application
+ Unicode
+
+
+ true
+ true
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+ $(VC_IncludePath);$(UniversalCRT_IncludePath);$(WindowsSDK_IncludePath);$(SharedContentDir)\cppwinrt
+ true
+
+
+
+ Use
+ pch.h
+ $(IntDir)pch.pch
+ Level4
+ %(AdditionalOptions) /bigobj
+ 4453;28204
+
+
+
+
+ _DEBUG;%(PreprocessorDefinitions)
+
+
+
+
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+
+
+ $(SharedContentDir)\xaml\App.xaml
+
+
+ $(SharedContentDir)\xaml\MainPage.xaml
+
+
+
+
+
+
+
+
+ ..\shared\Scenario1.xaml
+ Code
+
+
+
+ ..\shared\Scenario2.xaml
+ Code
+
+
+ ..\shared\Scenario3.xaml
+ Code
+
+
+
+
+ Designer
+
+
+ Designer
+
+
+ Designer
+
+
+ Styles\Styles.xaml
+
+
+ Designer
+
+
+ Designer
+
+
+
+
+ $(SharedContentDir)\xaml\App.xaml
+
+
+ $(SharedContentDir)\xaml\MainPage.xaml
+
+
+
+
+
+ SampleConfiguration.h
+
+
+ ..\shared\Scenario1.xaml
+ Code
+
+
+ Create
+ pch.h
+
+
+ Project.idl
+
+
+ ..\shared\Scenario2.xaml
+ Code
+
+
+ ..\shared\Scenario3.xaml
+ Code
+
+
+
+
+ $(SharedContentDir)\xaml\MainPage.xaml
+
+
+
+
+
+ Designer
+
+
+
+
+
+ Assets\microsoft-sdk.png
+
+
+ Assets\smallTile-sdk.png
+
+
+ Assets\splash-sdk.png
+
+
+ Assets\squareTile-sdk.png
+
+
+ Assets\storeLogo-sdk.png
+
+
+ Assets\tile-sdk.png
+
+
+ Assets\windows-sdk.png
+
+
+
+
+
+
+
+
+ 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}.
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/Logging/cppwinrt/Logging.vcxproj.filters b/Samples/Logging/cppwinrt/Logging.vcxproj.filters
new file mode 100644
index 0000000000..5639c480fa
--- /dev/null
+++ b/Samples/Logging/cppwinrt/Logging.vcxproj.filters
@@ -0,0 +1,68 @@
+
+
+
+
+ 4416d50a-7676-4d0a-9b2c-91ff70c6047f
+ bmp;fbx;gif;jpg;jpeg;tga;tiff;tif;png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/Logging/cppwinrt/LoggingChannelScenario.cpp b/Samples/Logging/cppwinrt/LoggingChannelScenario.cpp
new file mode 100644
index 0000000000..45060feb41
--- /dev/null
+++ b/Samples/Logging/cppwinrt/LoggingChannelScenario.cpp
@@ -0,0 +1,316 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "LoggingChannelScenario.h"
+
+using namespace winrt;
+using namespace winrt::Windows::Foundation;
+using namespace winrt::Windows::Foundation::Diagnostics;
+using namespace winrt::SDKTemplate;
+
+///
+/// Construct a LoggingChannel with the Windows 8.1 constructor, then
+/// use the LoggingChannel for the scenario.
+/// See this sample's README for further discussion.
+///
+void
+LoggingChannelScenario::LogWithWin81Constructor()
+{
+ // The 1-parameter constructor creates a channel with Windows 8.1 semantics.
+ LoggingChannel channel(L"SampleProvider");
+ DemonstrateLogging(channel);
+}
+
+///
+/// Construct a LoggingChannel with the Windows 10 constructor, then
+/// use the LoggingChannel for the scenario. Also show the use cases
+/// for the two Windows 10 constructors.
+// See this sample's README for further discussion.
+///
+void
+LoggingChannelScenario::LogWithWin10Constructor()
+{
+ {
+ // The 2-parameter constructor creates a channel with Windows 10 semantics.
+ LoggingChannel channel(
+ L"SampleProvider",
+ nullptr); // null means use default options.
+
+ // The Id is generated by hashing the string "SampleProvider".
+ // channel.Id == eff1e128-4903-5093-096a-bdc29b38456f
+ DemonstrateLogging(channel);
+ }
+
+ /*
+ Demonstrate other (less-common) constructor scenarios:
+ */
+
+ {
+ // This creates a channel with Windows 10 semantics and declared
+ // membership in a provider group.
+ GUID g = { 0x2e0582f3,0xd1b6,0x516a,0x9d,0xe3,0x9f,0xd7,0x9e,0xf9,0x52,0xf8 };
+ LoggingChannel channel(
+ L"SampleProvider",
+ Windows::Foundation::Diagnostics::LoggingChannelOptions(g)); // Join a provider group
+ // The Id is generated by hashing the string "SampleProvider".
+ // channel.Id == eff1e128-4903-5093-096a-bdc29b38456f
+ }
+
+ {
+ // This creates a channel with Windows 10 semantics and a specific
+ // provider Id.
+ GUID g = { 0x2e0582f3,0xd1b6,0x516a,0x9d,0xe3,0x9f,0xd7,0x9e,0xf9,0x52,0xf8 };
+ LoggingChannel channel(
+ L"SampleProvider",
+ nullptr,
+ g);
+ // channel.Id == 2e0582f3-d1b6-516a-9de3-9fd79ef952f8
+ }
+}
+
+///
+/// This method demonstrates the LoggingChannel and LoggingActivity APIs.
+///
+///
+/// The channel to use for the demonstration. This channel may have been
+/// constructed using a Windows 8.1 constructor or a Windows 10 constructor.
+/// The same APIs are supported in both cases, but the ETL events will be
+/// formatted a bit differently depending on how the channel was constructed.
+///
+void
+LoggingChannelScenario::DemonstrateLogging(
+ LoggingChannel const& channel)
+{
+ // Whenever any ETW session changes the way it is listening to this
+ // channel, the LoggingEnable event is fired. For example, this might
+ // be called when a session begins listening, changes the level at
+ // which it is listening, or stops listening.
+ event_token loggingEnabledToken = channel.LoggingEnabled({ this, &LoggingChannelScenario::OnLoggingEnabled });
+
+ // Log simple string events
+ channel.LogMessage(L"Simple message"); // default level is Verbose
+ channel.LogMessage(L"Simple error", Windows::Foundation::Diagnostics::LoggingLevel::Error);
+
+ // Log simple string + integer events.
+ channel.LogValuePair(L"Simple message", 123); // default level is Verbose
+ channel.LogValuePair(L"Simple error", 456, LoggingLevel::Error);
+
+ // The channel.Name property returns the name that was used when the
+ // channel was constructed. When running in Windows 10 mode, the name
+ // is already set as the provider name, so no LoggingChannelName is
+ // automatically added to the event.
+ channel.LogMessage(channel.Name());
+
+ // The channel.Id property is new to Windows 10.
+ channel.LogMessage(to_hstring(channel.Id()));
+
+ // If you want to avoid the overhead of collecting data when nobody is
+ // listening to your channel, check the Enabled property before logging.
+ if (channel.Enabled())
+ {
+ channel.LogMessage(CollectExpensiveData());
+ }
+
+ // The IsEnabled() method is exactly the same as the Enabled property,
+ // except that it is a new Windows 10 API.
+ if (channel.IsEnabled())
+ {
+ channel.LogMessage(CollectExpensiveData());
+ }
+
+ // If you want to only collect data if somebody is listening at a specific
+ // level, you need to check both Enabled and Level. Note that the value of
+ // the Level is unspecified when Enabled is false.
+ if (channel.Enabled() && channel.Level() <= LoggingLevel::Warning)
+ {
+ channel.LogMessage(CollectExpensiveData(), LoggingLevel::Warning);
+ }
+
+ // The IsEnabled(LoggingLevel) method is a bit nicer than checking both
+ // Enabled and Level, but it is only available on Windows 10 or later.
+ if (channel.IsEnabled(LoggingLevel::Warning))
+ {
+ channel.LogMessage(CollectExpensiveData(), LoggingLevel::Warning);
+ }
+
+ // You can also use IsEnabled to check for keywords.
+ if (channel.IsEnabled(LoggingLevel::Information, 0x10))
+ {
+ channel.LogMessage(CollectExpensiveData(), LoggingLevel::Information);
+ }
+
+ // Use LoggingFields with the LogEvent method to write complex events.
+ Windows::Foundation::Diagnostics::LoggingFields fields;
+ fields.AddDouble(L"pi", 3.14159);
+ channel.LogEvent(
+ L"ComplexEvent",
+ fields,
+ LoggingLevel::Verbose,
+ LoggingOptions(0x10)); // Keywords = 0x10
+
+ // You can add any number of name-value pairs to a fields object, though
+ // you may encounter ETW limitations if you add too many. For example,
+ // ETW is limited to a maximum event size of 64KB, and the current
+ // TraceLogging decoder can handle no more than 128 fields.
+
+ // Performance optimization: You can reuse a LoggingFields object to
+ // avoid unnecessary allocations. Don't forget to call Clear()
+ // between uses, and don't try to share a LoggingFields object between
+ // threads.
+ DateTime now = clock::now();
+ fields.Clear();
+ fields.AddInt64(L"Date", clock::to_file_time(now).value, LoggingFieldFormat::FileTime);
+ channel.LogEvent(L"Now", fields);
+
+ fields.Clear();
+
+ // You can add a formatting hint to affect the way a value is decoded.
+ // Not all combinations are useful, and the hint may be ignored.
+ // For example, you can encode an MBCS string by writing a byte array
+ // with a String hint.
+ uint8_t abc123[] = { 65, 66, 67, 49, 50, 51 }; // "ABC123"
+ fields.AddUInt8Array(
+ L"AnsiString",
+ abc123,
+ LoggingFieldFormat::String);
+
+ // You can add "tag" bits to a field. These are user-defined bits that
+ // can be used to communicate with an event processing tool. For example,
+ // you might define a tag bit to indicate that a field contains private
+ // data that should not be displayed on-screen.
+ fields.AddString(L"Password", L"12345", LoggingFieldFormat::Default, 0x10);
+
+ // You can add a "structure" to an event. A structure is a name for a
+ // group of fields. Structures can nest. Call BeginStruct to add a level
+ // of nesting, and call EndStruct after the last field of the structure.
+ fields.BeginStruct(L"Nested");
+ fields.AddInt16(L"Nested-1", 1);
+ fields.AddInt16(L"Nested-2", 2);
+ fields.BeginStruct(L"Nested-Nested");
+ fields.AddInt16(L"Nested-Nested-3", 3);
+ fields.EndStruct();
+ fields.AddInt16(L"Nested-4", 4);
+ fields.EndStruct();
+
+ // Advanced scenarios: you can use a LoggingOptions object to control
+ // detailed event settings such as keywords, opcodes, and activity Ids.
+ // These have their normal ETW semantics. You can also set event tags,
+ // which are bit values that can be used to communicate with the event
+ // processor.
+ LoggingOptions options;
+ options.Keywords(0x123);
+ options.Tags(0x10);
+ channel.LogEvent(
+ L"VeryComplexEvent",
+ fields,
+ LoggingLevel::Information,
+ options);
+
+ // Windows 10 introduces the ILoggingTarget interface. LoggingChannel
+ // implements this interface. This interface allows components to accept
+ // a logger as an parameter.
+ DoSomething(channel);
+
+ /*
+ If a LoggingActivity is created using a LoggingActivity constructor,
+ it will use Windows 8.1 semantics:
+
+ - If an activity is destroyed (garbage-collected) without being closed
+ and the associated LoggingChannel is still open, the activity will
+ write a default Stop event.
+ - The default Stop event (written by the destructor or by the Close()
+ method) is encoded as a "simple" event.
+
+ The 8.1 semantics are deprecated because the automatic generation of
+ a Stop event at garbage-collection can be misleading. The Stop event
+ is intended to mark the a precise point at which an activity is
+ completed, while the garbage-collection of an abandoned activity is
+ inherently imprecise and unpredictable.
+
+ If a LoggingActivity is created using a StartActivity method, it will
+ use Windows 10 semantics:
+
+ - If an activity is destroyed (garbage-collected) without being closed,
+ there will be no Stop event for the activity.
+ - The default Stop event (written by the Close() method) is encoded as
+ a TraceLogging event with name "ActivityClosed".
+ */
+
+ {
+ // This activity is created with Windows 8.1 semantics.
+ LoggingActivity a1(L"Activity1", channel);
+
+ // The activity Start event is written by the LoggingActivity constructor.
+ // You would do your activity's work here.
+ // The activity Stop event is written when the activity is closed (disposed).
+
+ // The Windows 10 LoggingActivity adds new methods for writing events
+ // that are marked as associated with the activity.
+ a1.LogEvent(L"Activity event");
+
+ // LoggingActivity also implements the ILoggingTarget interface, so you can
+ // use either a channel or an activity as a logging target.
+ DoSomething(a1);
+
+ {
+ // The Windows 10 LoggingActivity adds new methods for creating nested activities.
+ // Note that nested activities are always created with Windows 10 semantics,
+ // even when nested under an activity that is using Windows 8.1 semantics.
+ LoggingActivity a2 = a1.StartActivity(L"Activity2");
+
+ // Nested task occurs here.
+
+ // The Windows 10 LoggingActivity allows you to customize the Stop event.
+ a2.StopActivity(L"Activity 2 stop");
+ }
+
+ // Because a1 is using Windows 8.1 semantics, it will write a Stop event when
+ // it goes out of scope.
+ }
+
+ {
+ // The Windows 10 StartActivity method creates a new activity, optionally with
+ // specified fields and characteristics.
+ // This activity is created with Windows 10 semantics.
+ LoggingActivity a3 = channel.StartActivity(L"Activity3");
+
+ // Because a3 is using Windows 10 semantics, if we did not call StopActivity(),
+ // there would be no Stop event (not even when the activity is garbage
+ // collected). To get a Stop event, be sure to stop, close, or dispose the
+ // activity.
+ a3.StopActivity(L"ActivityClosed");
+ }
+
+ // Unregister from the event.
+ channel.LoggingEnabled(loggingEnabledToken);
+}
+
+hstring
+LoggingChannelScenario::CollectExpensiveData()
+{
+ return L"ExpensiveData";
+}
+
+void
+LoggingChannelScenario::DoSomething(
+ ILoggingTarget const& logger)
+{
+ logger.LogEvent(L"Did something");
+}
+
+void
+LoggingChannelScenario::OnLoggingEnabled(
+ ILoggingChannel const&,
+ IInspectable const&)
+{
+ // Here, you could note a change in the level or keywords.
+}
diff --git a/Samples/Logging/cppwinrt/LoggingChannelScenario.h b/Samples/Logging/cppwinrt/LoggingChannelScenario.h
new file mode 100644
index 0000000000..5c8e1ee710
--- /dev/null
+++ b/Samples/Logging/cppwinrt/LoggingChannelScenario.h
@@ -0,0 +1,44 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+namespace winrt::SDKTemplate
+{
+ class LoggingChannelScenario
+ {
+ public:
+
+ void
+ LogWithWin81Constructor();
+
+ void
+ LogWithWin10Constructor();
+
+ private:
+
+ void
+ DemonstrateLogging(
+ Windows::Foundation::Diagnostics::LoggingChannel const& channel);
+
+ hstring
+ CollectExpensiveData();
+
+ void
+ DoSomething(
+ Windows::Foundation::Diagnostics::ILoggingTarget const& logger);
+
+ void
+ OnLoggingEnabled(
+ Windows::Foundation::Diagnostics::ILoggingChannel const& sender,
+ Windows::Foundation::IInspectable const& e);
+ };
+}
diff --git a/Samples/Logging/cppwinrt/LoggingScenarioEventArgs.h b/Samples/Logging/cppwinrt/LoggingScenarioEventArgs.h
new file mode 100644
index 0000000000..8ef10f400e
--- /dev/null
+++ b/Samples/Logging/cppwinrt/LoggingScenarioEventArgs.h
@@ -0,0 +1,40 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+#include "LoggingScenarioEventArgs.g.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct LoggingScenarioEventArgs : LoggingScenarioEventArgsT
+ {
+ // e.g. for BusyStatusChanged
+ LoggingScenarioEventArgs(LoggingScenarioEventType type)
+ : _type(type) {}
+
+ // e.g. for LogFileGenerated
+ LoggingScenarioEventArgs(LoggingScenarioEventType type, hstring const& logFileFullPath)
+ : _type(type), _logFileFullPath(logFileFullPath) {}
+
+ // e.g. for LoggingEnabledDisabled
+ LoggingScenarioEventArgs(LoggingScenarioEventType type, bool enabled)
+ : _type(type), _enabled(enabled) {}
+
+ LoggingScenarioEventType Type() const noexcept { return _type; }
+ bool Enabled() const noexcept { return _enabled; }
+ hstring LogFileFullPath() const noexcept { return _logFileFullPath; }
+
+ private:
+ LoggingScenarioEventType _type;
+ bool _enabled = false;
+ hstring _logFileFullPath;
+ };
+}
diff --git a/Samples/Logging/cppwinrt/LoggingScenarioHelpers.h b/Samples/Logging/cppwinrt/LoggingScenarioHelpers.h
new file mode 100644
index 0000000000..6d5dbaf7dc
--- /dev/null
+++ b/Samples/Logging/cppwinrt/LoggingScenarioHelpers.h
@@ -0,0 +1,82 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+namespace winrt::SDKTemplate
+{
+ // Create a time stamp to append to log file names so
+ // each file has a unique name. The format is:
+ // YYMMDD-hhmmssMMM
+ // where
+ // YY == year
+ // MM == month
+ // DD == day
+ // hh == hours
+ // mm == minutes
+ // ss == seconds
+ // MMM == milliseconds
+ inline std::wstring
+ GetTimeStamp()
+ {
+ std::wstring result;
+ SYSTEMTIME timeNow;
+ GetLocalTime(&timeNow);
+ result.resize(16);
+ swprintf_s(
+ &result[0],
+ result.size() + 1,
+ L"%02u%02u%02u-%02u%02u%02u%03u",
+ timeNow.wYear - 2000,
+ timeNow.wMonth,
+ timeNow.wDay,
+ timeNow.wHour,
+ timeNow.wMinute,
+ timeNow.wSecond,
+ timeNow.wMilliseconds);
+ return result;
+ }
+
+ inline Windows::UI::Xaml::Controls::ScrollViewer
+ FindScrollViewer(Windows::UI::Xaml::DependencyObject const& control)
+ {
+ if (control == nullptr)
+ {
+ return nullptr;
+ }
+
+ int childCount = Windows::UI::Xaml::Media::VisualTreeHelper::GetChildrenCount(control);
+ if (childCount <= 0)
+ {
+ return nullptr;
+ }
+
+ for (int childIndex = 0; childIndex < childCount; childIndex++)
+ {
+ Windows::UI::Xaml::DependencyObject childControl =
+ Windows::UI::Xaml::Media::VisualTreeHelper::GetChild(control, childIndex);
+ Windows::UI::Xaml::Controls::ScrollViewer viewer =
+ childControl.try_as();
+ if (viewer != nullptr)
+ {
+ return viewer;
+ }
+
+ viewer = FindScrollViewer(childControl);
+ if (viewer != nullptr)
+ {
+ return viewer;
+ }
+ }
+
+ return nullptr;
+ }
+}
diff --git a/Samples/Logging/cppwinrt/LoggingSessionScenario.cpp b/Samples/Logging/cppwinrt/LoggingSessionScenario.cpp
new file mode 100644
index 0000000000..d16e78b72c
--- /dev/null
+++ b/Samples/Logging/cppwinrt/LoggingSessionScenario.cpp
@@ -0,0 +1,338 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "LoggingSessionScenario.h"
+#include "LoggingScenarioHelpers.h"
+
+#define SCENARIO_PREFIX L"LoggingSessionScenario_"
+#define DEFAULT_SESSION_NAME SCENARIO_PREFIX L"Session"
+#define DEFAULT_CHANNEL_NAME SCENARIO_PREFIX L"Channel"
+#define OUR_SAMPLE_APP_LOG_FILE_FOLDER_NAME SCENARIO_PREFIX L"LogFiles"
+#define LOGGING_ENABLED_SETTING_KEY_NAME SCENARIO_PREFIX L"LoggingEnabled"
+
+using namespace winrt;
+using namespace winrt::Windows::ApplicationModel;
+using namespace winrt::Windows::Foundation;
+using namespace winrt::Windows::Foundation::Diagnostics;
+using namespace winrt::Windows::Storage;
+using namespace winrt::SDKTemplate;
+
+LoggingSessionScenario::~LoggingSessionScenario()
+{
+}
+
+LoggingSessionScenario::LoggingSessionScenario()
+{
+ // Create the logging channel.
+ // When an app logs messages to a channel, the messges will go
+ // to any sessions which are consuming messages from the channel.
+ _channel = LoggingChannel(DEFAULT_CHANNEL_NAME);
+
+ // This sample listens to the channel's events so it can track
+ // information about the channel's enablement status.
+ _channel.LoggingEnabled({ this, &LoggingSessionScenario::OnChannelLoggingEnabled });
+
+ // Attach event handlers for Suspend/Resume.
+ Windows::UI::Xaml::Application app = Windows::UI::Xaml::Application::Current();
+ app.Suspending({ this, &LoggingSessionScenario::OnAppSuspending });
+ app.Resuming({ this, &LoggingSessionScenario::OnAppResuming });
+
+ // If the app is being launched (not resumed), the following call will
+ // activate logging if it had been active at the time of the last suspend.
+ ResumeLoggingIfApplicable();
+}
+
+// static
+LoggingSessionScenario&
+LoggingSessionScenario::Instance()
+{
+ static LoggingSessionScenario instance;
+ return instance;
+}
+
+event_token
+LoggingSessionScenario::StatusChanged(StatusChangedHandler const& handler)
+{
+ return _statusChanged.add(handler);
+}
+
+void
+LoggingSessionScenario::StatusChanged(event_token const& token) noexcept
+{
+ _statusChanged.remove(token);
+}
+
+bool
+LoggingSessionScenario::IsBusy() const noexcept
+{
+ return _isBusy != 0;
+}
+
+int
+LoggingSessionScenario::LogFileGeneratedCount() const noexcept
+{
+ return _logFileGeneratedCount;
+}
+
+bool
+LoggingSessionScenario::LoggingEnabled() const noexcept
+{
+ return _session != nullptr;
+}
+
+bool
+LoggingSessionScenario::ToggleLoggingEnabledDisabled()
+{
+ BusySetter busy(*this);
+
+ if (_session != nullptr)
+ {
+ _session.Close();
+ _session = nullptr;
+ _settings.Insert(LOGGING_ENABLED_SETTING_KEY_NAME, box_value(false));
+ _statusChanged(make(LoggingScenarioEventType::LoggingEnabledDisabled, false));
+ return false;
+ }
+ else
+ {
+ StartLogging();
+ _settings.Insert(LOGGING_ENABLED_SETTING_KEY_NAME, box_value(true));
+ _statusChanged(make(LoggingScenarioEventType::LoggingEnabledDisabled, true));
+ return true;
+ }
+}
+
+IAsyncAction
+LoggingSessionScenario::DoScenarioAsync()
+{
+ BusySetter busy(*this);
+
+ std::wstring messageToLog;
+
+ int messageIndex = 0; // Increments for each logging call.
+ int lastDelayIndex = 0; // The messageIndex value at the last delay.
+ int lastAppErrorIndex = 0; // The messageIndex value at the last simulated error.
+ int startFileCount = LogFileGeneratedCount();
+
+ const int NUMBER_OF_LOG_FILES_TO_GENERATE = 3;
+
+ while (LogFileGeneratedCount() - startFileCount < NUMBER_OF_LOG_FILES_TO_GENERATE)
+ {
+ bool exceptionOccurred = false;
+ try
+ {
+ // Since the channel is added to the session at level Warning,
+ // the following is logged because it is logged at level LoggingLevel.Critical.
+ messageToLog = L"Message=";
+ messageToLog += std::to_wstring(++messageIndex);
+ messageToLog +=
+ L": Lorem ipsum dolor sit amet, consectetur adipiscing elit.In ligula nisi, vehicula nec eleifend vel, rutrum non dolor.Vestibulum ante ipsum "
+ L"primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur elementum scelerisque accumsan. In hac habitasse platea dictumst.";
+ _channel.LogMessage(messageToLog, LoggingLevel::Critical);
+
+ // Since the channel is added to the session at level Warning,
+ // the following is *not* logged because it is logged at LoggingLevel.Information.
+ messageToLog = L"Message=";
+ messageToLog += std::to_wstring(++messageIndex);
+ messageToLog +=
+ L": Lorem ipsum dolor sit amet, consectetur adipiscing elit.In ligula nisi, vehicula nec eleifend vel, rutrum non dolor.Vestibulum ante ipsum "
+ L"primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur elementum scelerisque accumsan. In hac habitasse platea dictumst.";
+ _channel.LogMessage(messageToLog, LoggingLevel::Information);
+
+ int value = 1000000; // one million, 7 digits, 4-bytes as an int, 14 bytes as a wide character string.
+ messageToLog = L"Value #";
+ messageToLog += std::to_wstring(++messageIndex);
+ messageToLog += L':';
+ messageToLog += std::to_wstring(value);
+ _channel.LogMessage(messageToLog, LoggingLevel::Critical); // 'value' is logged as 14 byte wide character string.
+ ++messageIndex;
+ _channel.LogValuePair(L"Value", value, LoggingLevel::Critical); // 'value' is logged as a 4-byte integer.
+
+ //
+ // Every once in a while, simulate an application error
+ // which causes the app to save the current snapshot
+ // of logging events in memory to a disk ETL file.
+ //
+
+ if (messageIndex - lastAppErrorIndex >= 25000)
+ {
+ lastAppErrorIndex = messageIndex;
+
+ // Before simulating an application error, demonstrate LoggingActivity.
+ // A LoggingActivity outputs a pair of begin and end messages to the channel.
+ // The first message is logged when the LoggingActivity is created. When
+ // exiting the scope of the LoggingActivity, the second message will be logged.
+ {
+ LoggingActivity activity(L"Add two numbers.", _channel,
+ LoggingLevel::Critical);
+ int oneNumber = 100;
+ int anotherNumber = 200;
+ int total = oneNumber + anotherNumber;
+ messageToLog = L"Message=";
+ messageToLog += std::to_wstring(++messageIndex);
+ messageToLog += L": The result of adding two numbers: ";
+ messageToLog += std::to_wstring(total);
+ _channel.LogMessage(messageToLog, LoggingLevel::Critical);
+ } // The LoggingActivity instance will log the end message at this scope exit.
+
+ // Simulate an application error.
+ throw std::exception("Some bad app error occurred.");
+ }
+
+ //
+ // Pause every once in a while to simulate application activity outside of logging.
+ //
+
+ if (messageIndex - lastDelayIndex >= 100)
+ {
+ lastDelayIndex = messageIndex;
+ co_await resume_after(std::chrono::milliseconds(5));
+ }
+ }
+ catch (std::exception const& e)
+ {
+ // Save in-memory logging buffer to a log file on error.
+
+ hstring what;
+ if (e.what() != nullptr)
+ {
+ what = to_hstring(e.what());
+ }
+ else
+ {
+ what = L"Unknown.";
+ }
+
+ // The session added the channel at level Warning. Log the message at
+ // level Error which is above (more critical than) Warning, which
+ // means it will actually get logged.
+ _channel.LogMessage(L"Exception occurred: " + what, LoggingLevel::Error);
+
+ // Since co_await is not supported within catch blocks, record the exception.
+ // After the catch block, we'll notice that an exception occurred and save the log.
+ exceptionOccurred = true;
+ }
+
+ if (exceptionOccurred)
+ {
+ // An exception occurred, so save the in-memory events to disk for analysis.
+
+ // Create the app-defined folder under the app's local folder.
+ // An app defines where/how it wants to store log files.
+ // This sample uses OUR_SAMPLE_APP_LOG_FILE_FOLDER_NAME under
+ // the app's local folder.
+ StorageFolder ourSampleAppLogFolder =
+ co_await ApplicationData::Current().LocalFolder().CreateFolderAsync(
+ OUR_SAMPLE_APP_LOG_FILE_FOLDER_NAME,
+ CreationCollisionOption::OpenIfExists);
+
+ // Create a new log file name.
+ std::wstring newLogFileName;
+ newLogFileName += L"Log-";
+ newLogFileName += GetTimeStamp();
+ newLogFileName += L".etl";
+
+ StorageFile logFile = co_await _session.SaveToFileAsync(ourSampleAppLogFolder, newLogFileName);
+ ++_logFileGeneratedCount;
+ _statusChanged(make(LoggingScenarioEventType::LogFileGenerated, logFile.Path()));
+ }
+ }
+}
+
+void
+LoggingSessionScenario::StartLogging()
+{
+ // If no session exists, create one.
+ // NOTE: There are use cases where an application
+ // may want to create only a channel for sessions outside
+ // of the application itself. See MSDN for details. This
+ // sample is the common scenario of an app logging events
+ // which it wants to place in its own log file, so it creates
+ // a session and channel as a pair. The channel is created
+ // during construction of this LoggingSessionScenario class so
+ // it already exists by the time this function is called.
+ if (_session == nullptr)
+ {
+ _session = LoggingSession(DEFAULT_SESSION_NAME);
+ }
+
+ // This sample adds the channel at level "warning" to
+ // demonstrate how messages logged at more verbose levels
+ // are ignored by the session.
+ _session.AddLoggingChannel(_channel, LoggingLevel::Warning);
+}
+
+void
+LoggingSessionScenario::PrepareToSuspend()
+{
+ _settings.Insert(LOGGING_ENABLED_SETTING_KEY_NAME, box_value(_session != nullptr));
+}
+
+void
+LoggingSessionScenario::ResumeLoggingIfApplicable()
+{
+ bool loggingEnabled = unbox_value_or(_settings.TryLookup(LOGGING_ENABLED_SETTING_KEY_NAME), true);
+ if (loggingEnabled)
+ {
+ StartLogging();
+ }
+}
+
+void
+LoggingSessionScenario::OnChannelLoggingEnabled(
+ ILoggingChannel const& sender,
+ IInspectable const&)
+{
+ // This method is called when the channel is informing us of channel-related state changes.
+ // Save new channel state. These values can be used for advanced logging scenarios where,
+ // for example, it's desired to skip blocks of logging code if the channel is not being
+ // consumed by any sessions.
+ _isChannelEnabled = sender.Enabled();
+ _channelLoggingLevel = sender.Level();
+}
+
+void
+LoggingSessionScenario::OnAppSuspending(
+ IInspectable const&,
+ SuspendingEventArgs const& e)
+{
+ auto deferral = e.SuspendingOperation().GetDeferral();
+ PrepareToSuspend();
+ deferral.Complete();
+}
+
+void
+LoggingSessionScenario::OnAppResuming(
+ IInspectable const&,
+ IInspectable const&)
+{
+ // If logging was active at the last suspend, ResumeLoggingIfApplicable
+ // will re-activate logging.
+ ResumeLoggingIfApplicable();
+}
+
+LoggingSessionScenario::BusySetter::~BusySetter()
+{
+ if (0 == --_scenario._isBusy)
+ {
+ _scenario._statusChanged(make(LoggingScenarioEventType::BusyStatusChanged));
+ }
+}
+
+LoggingSessionScenario::BusySetter::BusySetter(LoggingSessionScenario& scenario)
+ : _scenario(scenario)
+{
+ if (1 == ++_scenario._isBusy)
+ {
+ _scenario._statusChanged(make(LoggingScenarioEventType::BusyStatusChanged));
+ }
+}
diff --git a/Samples/Logging/cppwinrt/LoggingSessionScenario.h b/Samples/Logging/cppwinrt/LoggingSessionScenario.h
new file mode 100644
index 0000000000..af618a9a90
--- /dev/null
+++ b/Samples/Logging/cppwinrt/LoggingSessionScenario.h
@@ -0,0 +1,97 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+#include "LoggingScenarioEventArgs.h"
+
+namespace winrt::SDKTemplate
+{
+ class LoggingSessionScenario
+ {
+ // This is a singleton, only created/destroyed by the Instance() method.
+ ~LoggingSessionScenario();
+ LoggingSessionScenario();
+
+ public:
+
+ static LoggingSessionScenario&
+ Instance();
+
+ winrt::event_token
+ StatusChanged(StatusChangedHandler const& handler);
+
+ void
+ StatusChanged(winrt::event_token const& token) noexcept;
+
+ bool
+ IsBusy() const noexcept;
+
+ int
+ LogFileGeneratedCount() const noexcept;
+
+ bool
+ LoggingEnabled() const noexcept;
+
+ bool
+ ToggleLoggingEnabledDisabled();
+
+ Windows::Foundation::IAsyncAction
+ DoScenarioAsync();
+
+ private:
+
+ void
+ StartLogging();
+
+ void
+ PrepareToSuspend();
+
+ void
+ ResumeLoggingIfApplicable();
+
+ void
+ OnChannelLoggingEnabled(
+ Windows::Foundation::Diagnostics::ILoggingChannel const& sender,
+ Windows::Foundation::IInspectable const& args);
+
+ void
+ OnAppSuspending(
+ Windows::Foundation::IInspectable const& sender,
+ Windows::ApplicationModel::SuspendingEventArgs const& e);
+
+ void
+ OnAppResuming(
+ Windows::Foundation::IInspectable const& sender,
+ Windows::Foundation::IInspectable const& args);
+
+ private:
+
+ struct BusySetter
+ {
+ ~BusySetter();
+ explicit BusySetter(LoggingSessionScenario& scenario);
+ LoggingSessionScenario& _scenario;
+ };
+
+ Windows::Foundation::Diagnostics::LoggingSession _session{ nullptr };
+ Windows::Foundation::Diagnostics::LoggingChannel _channel{ nullptr };
+
+ std::atomic _logFileGeneratedCount;
+ std::atomic _isBusy;
+
+ bool _isChannelEnabled = false;
+ Windows::Foundation::Diagnostics::LoggingLevel _channelLoggingLevel{};
+
+ Windows::Foundation::Collections::IPropertySet _settings{ Windows::Storage::ApplicationData::Current().LocalSettings().Values() };
+
+ event _statusChanged;
+ };
+}
diff --git a/Samples/Logging/cppwinrt/Package.appxmanifest b/Samples/Logging/cppwinrt/Package.appxmanifest
new file mode 100644
index 0000000000..e39a581e71
--- /dev/null
+++ b/Samples/Logging/cppwinrt/Package.appxmanifest
@@ -0,0 +1,42 @@
+
+
+
+
+
+ Logging C++/WinRT Sample
+ Microsoft Corporation
+ Assets\storelogo-sdk.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/Logging/cppwinrt/Project.idl b/Samples/Logging/cppwinrt/Project.idl
new file mode 100644
index 0000000000..e7c6dedc69
--- /dev/null
+++ b/Samples/Logging/cppwinrt/Project.idl
@@ -0,0 +1,52 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+namespace SDKTemplate
+{
+ [default_interface]
+ runtimeclass Scenario1 : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario1();
+ }
+
+ [default_interface]
+ runtimeclass Scenario2 : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario2();
+ }
+
+ [default_interface]
+ runtimeclass Scenario3 : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario3();
+ }
+
+ // LoggingScenario tells the UI what's happening by
+ // using the following enums.
+ enum LoggingScenarioEventType
+ {
+ BusyStatusChanged,
+ LogFileGenerated,
+ LogFileGeneratedAtDisable,
+ LogFileGeneratedAtSuspend,
+ LoggingEnabledDisabled,
+ };
+
+ runtimeclass LoggingScenarioEventArgs
+ {
+ LoggingScenarioEventType Type{ get; };
+ Boolean Enabled{ get; };
+ String LogFileFullPath{ get; };
+ }
+
+ delegate void StatusChangedHandler(LoggingScenarioEventArgs e);
+
+}
diff --git a/Samples/Logging/cppwinrt/SampleConfiguration.cpp b/Samples/Logging/cppwinrt/SampleConfiguration.cpp
new file mode 100644
index 0000000000..7edaa6395b
--- /dev/null
+++ b/Samples/Logging/cppwinrt/SampleConfiguration.cpp
@@ -0,0 +1,32 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "SampleConfiguration.h"
+#include "MainPage.h"
+#include
+
+using namespace winrt;
+using namespace winrt::SDKTemplate::implementation;
+
+winrt::hstring
+MainPage::FEATURE_NAME()
+{
+ return L"Logging C++/WinRT Sample";
+}
+
+Windows::Foundation::Collections::IVector
+MainPage::scenariosInner = winrt::single_threaded_observable_vector(
+{
+ Scenario{ L"LoggingChannel", winrt::xaml_typename() },
+ Scenario{ L"LoggingSession", winrt::xaml_typename() },
+ Scenario{ L"FileLoggingSession", winrt::xaml_typename() },
+});
diff --git a/Samples/Logging/cppwinrt/SampleConfiguration.h b/Samples/Logging/cppwinrt/SampleConfiguration.h
new file mode 100644
index 0000000000..2c10b7e8b8
--- /dev/null
+++ b/Samples/Logging/cppwinrt/SampleConfiguration.h
@@ -0,0 +1,16 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+namespace winrt::SDKTemplate
+{
+}
diff --git a/Samples/Logging/cppwinrt/Scenario1.cpp b/Samples/Logging/cppwinrt/Scenario1.cpp
new file mode 100644
index 0000000000..61eb01be70
--- /dev/null
+++ b/Samples/Logging/cppwinrt/Scenario1.cpp
@@ -0,0 +1,35 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "Scenario1.h"
+#include "Scenario1.g.cpp"
+#include "LoggingChannelScenario.h"
+
+using namespace winrt;
+using namespace winrt::SDKTemplate::implementation;
+
+Scenario1::Scenario1()
+{
+ InitializeComponent();
+}
+
+void Scenario1::DoWin81Mode(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&)
+{
+ LoggingChannelScenario().LogWithWin81Constructor();
+ MainPage::Current().NotifyUser(L"Complete: Windows 8 mode", NotifyType::StatusMessage);
+}
+
+void Scenario1::DoWin10Mode(IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&)
+{
+ LoggingChannelScenario().LogWithWin10Constructor();
+ MainPage::Current().NotifyUser(L"Complete: Windows 10 mode", NotifyType::StatusMessage);
+}
diff --git a/Samples/Logging/cppwinrt/Scenario1.h b/Samples/Logging/cppwinrt/Scenario1.h
new file mode 100644
index 0000000000..2048b4df7e
--- /dev/null
+++ b/Samples/Logging/cppwinrt/Scenario1.h
@@ -0,0 +1,39 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "Scenario1.g.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario1 : Scenario1T
+ {
+ Scenario1();
+
+ void
+ DoWin81Mode(
+ Windows::Foundation::IInspectable const& sender,
+ Windows::UI::Xaml::RoutedEventArgs const& args);
+
+ void
+ DoWin10Mode(
+ Windows::Foundation::IInspectable const& sender,
+ Windows::UI::Xaml::RoutedEventArgs const& args);
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario1 : Scenario1T
+ {
+ };
+}
diff --git a/Samples/Logging/cppwinrt/Scenario2.cpp b/Samples/Logging/cppwinrt/Scenario2.cpp
new file mode 100644
index 0000000000..df29cb6506
--- /dev/null
+++ b/Samples/Logging/cppwinrt/Scenario2.cpp
@@ -0,0 +1,183 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "Scenario2.h"
+#include "Scenario2.g.cpp"
+#include "LoggingScenarioHelpers.h"
+
+using namespace winrt;
+using namespace winrt::Windows::Foundation;
+using namespace winrt::Windows::UI::Xaml;
+using namespace winrt::Windows::UI::Xaml::Controls;
+using namespace winrt::Windows::UI::Xaml::Navigation;
+using namespace winrt::SDKTemplate::implementation;
+
+Scenario2::Scenario2()
+{
+ InitializeComponent();
+}
+
+fire_and_forget
+Scenario2::DoScenario(IInspectable const&, RoutedEventArgs const&)
+{
+ MainPage::Current().NotifyUser(L"Scenario running...", NotifyType::StatusMessage);
+ DoScenarioButton().IsEnabled(false);
+
+ // Run the scenario asynchronously so the UI can update.
+ co_await resume_background();
+ co_await _instance.DoScenarioAsync();
+
+ // After the scenario completes, re-enable UI controls and display a message.
+ co_await resume_foreground(Dispatcher());
+ DoScenarioButton().IsEnabled(true);
+ MainPage::Current().NotifyUser(L"Scenario finished.", NotifyType::StatusMessage);
+}
+
+void
+Scenario2::EnableDisableLogging(IInspectable const&, RoutedEventArgs const&)
+{
+ if (_instance.LoggingEnabled())
+ {
+ MainPage::Current().NotifyUser(L"Disabling logging...", NotifyType::StatusMessage);
+ }
+ else
+ {
+ MainPage::Current().NotifyUser(L"Enabling logging...", NotifyType::StatusMessage);
+ }
+
+ _instance.ToggleLoggingEnabledDisabled();
+ UpdateControls();
+
+ if (_instance.LoggingEnabled())
+ {
+ MainPage::Current().NotifyUser(L"Logging enabled.", NotifyType::StatusMessage);
+ }
+ else
+ {
+ MainPage::Current().NotifyUser(L"Logging disabled.", NotifyType::StatusMessage);
+ }
+}
+
+void
+Scenario2::OnNavigatedTo(NavigationEventArgs const&)
+{
+ _statusChangedToken = _instance.StatusChanged({ this, &Scenario2::OnStatusChanged });
+ UpdateControls();
+}
+
+void
+Scenario2::OnNavigatedFrom(NavigationEventArgs const&)
+{
+ _instance.StatusChanged(_statusChangedToken);
+}
+
+void
+Scenario2::UpdateControls()
+{
+ if (_instance.LoggingEnabled())
+ {
+ InputTextBlock1().Text(
+ L"Logging is enabled. Click 'Disable Logging' to disable logging. With logging enabled, you can click 'Log Messages' to use the logging API to generate log files.");
+ EnableDisableLoggingButton().Content(box_value(L"Disable Logging"));
+
+ if (_instance.IsBusy())
+ {
+ EnableDisableLoggingButton().IsEnabled(false);
+ DoScenarioButton().IsEnabled(false);
+ }
+ else
+ {
+ EnableDisableLoggingButton().IsEnabled(true);
+ DoScenarioButton().IsEnabled(true);
+ }
+ }
+ else
+ {
+ InputTextBlock1().Text(
+ L"Logging is disabled. Click 'Enable Logging' to enable logging. After you enable logging you can click 'Log Messages' to use the logging API to generate log files.");
+ EnableDisableLoggingButton().Content(box_value(L"Enable Logging"));
+ DoScenarioButton().IsEnabled(false);
+ EnableDisableLoggingButton().IsEnabled(!_instance.IsBusy());
+ }
+}
+
+void
+Scenario2::AddMessage(LPCWSTR message)
+{
+ TextBox statusMessageList = StatusMessageList();
+ std::wstring statusText(statusMessageList.Text());
+ statusText += message;
+ statusText += L"\r\n";
+ statusMessageList.Text(statusText);
+ statusMessageList.Select(static_cast(statusText.size()), 0);
+
+ ScrollViewer viewer = FindScrollViewer(statusMessageList);
+ if (viewer != nullptr)
+ {
+ viewer.ChangeView(nullptr, statusMessageList.ActualHeight(), nullptr);
+ }
+}
+
+fire_and_forget
+Scenario2::OnStatusChanged(SDKTemplate::LoggingScenarioEventArgs args)
+{
+ // Switch to UI thread.
+ co_await resume_foreground(Dispatcher());
+
+ switch (args.Type())
+ {
+ case LoggingScenarioEventType::BusyStatusChanged:
+ UpdateControls();
+ break;
+
+ case LoggingScenarioEventType::LogFileGenerated:
+ {
+ hstring logFileFullPath = args.LogFileFullPath();
+ if (logFileFullPath.empty())
+ {
+ AddMessage(L"LogFileGenerated: none, nothing logged since saving the last file.");
+ }
+ else
+ {
+ // Add a message to the UI indicating a new log file was created.
+ std::wstring fullPath(logFileFullPath);
+ std::wstring directoryName;
+ std::wstring fileName;
+ std::size_t lastSlashPos = fullPath.find_last_of(L'\\');
+ if (lastSlashPos > 0 && lastSlashPos < fullPath.size() - 1)
+ {
+ directoryName = fullPath.substr(0, lastSlashPos);
+ fileName = fullPath.substr(lastSlashPos + 1, fullPath.size() - (lastSlashPos + 1));
+ }
+
+ ViewLogInfo().Text(
+ L"Log folder: \"" + directoryName + L"\"\r\n"
+ L"- To view with tracerpt: tracerpt.exe \"" + fullPath + L"\" -of XML -o LogFile.xml\r\n"
+ L"- To view with Windows Performance Toolkit (WPT):\n"
+ L" xperf -merge \"" + fullPath + "\" merged.etl\n"
+ L" wpa.exe merged.etl");
+ AddMessage((L"LogFileGenerated: " + fileName).c_str());
+ }
+ }
+ break;
+
+ case LoggingScenarioEventType::LoggingEnabledDisabled:
+ AddMessage(args.Enabled()
+ ? L"Logging has been enabled."
+ : L"Logging has been disabled.");
+ break;
+
+ default:
+ AddMessage(L"Unrecognized event.");
+ break;
+ }
+}
diff --git a/Samples/Logging/cppwinrt/Scenario2.h b/Samples/Logging/cppwinrt/Scenario2.h
new file mode 100644
index 0000000000..c76416fbc5
--- /dev/null
+++ b/Samples/Logging/cppwinrt/Scenario2.h
@@ -0,0 +1,62 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "Scenario2.g.h"
+#include "LoggingSessionScenario.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario2 : Scenario2T
+ {
+ Scenario2();
+
+ fire_and_forget
+ DoScenario(
+ Windows::Foundation::IInspectable const& sender,
+ Windows::UI::Xaml::RoutedEventArgs const& args);
+
+ void
+ EnableDisableLogging(
+ Windows::Foundation::IInspectable const& sender,
+ Windows::UI::Xaml::RoutedEventArgs const& args);
+
+ void
+ OnNavigatedTo(
+ Windows::UI::Xaml::Navigation::NavigationEventArgs const& args);
+
+ void
+ OnNavigatedFrom(
+ Windows::UI::Xaml::Navigation::NavigationEventArgs const& args);
+
+ private:
+
+ void
+ UpdateControls();
+
+ void
+ AddMessage(_In_ LPCWSTR message);
+
+ fire_and_forget
+ OnStatusChanged(SDKTemplate::LoggingScenarioEventArgs args);
+
+ LoggingSessionScenario& _instance = LoggingSessionScenario::Instance();
+ event_token _statusChangedToken;
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario2 : Scenario2T
+ {
+ };
+}
diff --git a/Samples/Logging/cppwinrt/Scenario3.cpp b/Samples/Logging/cppwinrt/Scenario3.cpp
new file mode 100644
index 0000000000..d9925d39ab
--- /dev/null
+++ b/Samples/Logging/cppwinrt/Scenario3.cpp
@@ -0,0 +1,204 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "Scenario3.h"
+#include "Scenario3.g.cpp"
+#include "LoggingScenarioHelpers.h"
+
+using namespace winrt;
+using namespace winrt::Windows::Foundation;
+using namespace winrt::Windows::UI::Xaml;
+using namespace winrt::Windows::UI::Xaml::Controls;
+using namespace winrt::Windows::UI::Xaml::Navigation;
+using namespace winrt::SDKTemplate::implementation;
+
+Scenario3::Scenario3()
+{
+ InitializeComponent();
+}
+
+fire_and_forget
+Scenario3::DoScenario(IInspectable const&, RoutedEventArgs const&)
+{
+ MainPage::Current().NotifyUser(L"Scenario running...", NotifyType::StatusMessage);
+ DoScenarioButton().IsEnabled(false);
+
+ // Run the scenario asynchronously so the UI can update.
+ co_await resume_background();
+ co_await _instance.DoScenarioAsync();
+
+ // After the scenario completes, re-enable UI controls and display a message.
+ co_await resume_foreground(Dispatcher());
+ DoScenarioButton().IsEnabled(true);
+ MainPage::Current().NotifyUser(L"Scenario finished.", NotifyType::StatusMessage);
+}
+
+fire_and_forget
+Scenario3::EnableDisableLogging(IInspectable const&, RoutedEventArgs const&)
+{
+ if (_instance.LoggingEnabled())
+ {
+ MainPage::Current().NotifyUser(L"Disabling logging...", NotifyType::StatusMessage);
+ }
+ else
+ {
+ MainPage::Current().NotifyUser(L"Enabling logging...", NotifyType::StatusMessage);
+ }
+
+ co_await _instance.ToggleLoggingEnabledDisabledAsync();
+
+ co_await resume_foreground(Dispatcher());
+
+ UpdateControls();
+
+ if (_instance.LoggingEnabled())
+ {
+ MainPage::Current().NotifyUser(L"Logging enabled.", NotifyType::StatusMessage);
+ }
+ else
+ {
+ MainPage::Current().NotifyUser(L"Logging disabled.", NotifyType::StatusMessage);
+ }
+}
+
+void
+Scenario3::OnNavigatedTo(NavigationEventArgs const&)
+{
+ _statusChangedToken = _instance.StatusChanged({ this, &Scenario3::OnStatusChanged });
+ UpdateControls();
+}
+
+void
+Scenario3::OnNavigatedFrom(NavigationEventArgs const&)
+{
+ _instance.StatusChanged(_statusChangedToken);
+ UpdateControls();
+}
+
+void
+Scenario3::UpdateControls()
+{
+ if (_instance.LoggingEnabled())
+ {
+ InputTextBlock1().Text(
+ L"Logging is enabled. Click 'Disable Logging' to disable logging. With logging enabled, you can click 'Log Messages' to use the logging API to generate log files.");
+ EnableDisableLoggingButton().Content(box_value(L"Disable Logging"));
+
+ if (_instance.IsBusy())
+ {
+ EnableDisableLoggingButton().IsEnabled(false);
+ DoScenarioButton().IsEnabled(false);
+ }
+ else
+ {
+ EnableDisableLoggingButton().IsEnabled(true);
+ DoScenarioButton().IsEnabled(true);
+ }
+ }
+ else
+ {
+ InputTextBlock1().Text(
+ L"Logging is disabled. Click 'Enable Logging' to enable logging. After you enable logging you can click 'Log Messages' to use the logging API to generate log files.");
+ EnableDisableLoggingButton().Content(box_value(L"Enable Logging"));
+ DoScenarioButton().IsEnabled(false);
+ EnableDisableLoggingButton().IsEnabled(!_instance.IsBusy());
+ }
+}
+
+void
+Scenario3::AddMessage(_In_ LPCWSTR message)
+{
+ TextBox statusMessageList = StatusMessageList();
+ std::wstring statusText(statusMessageList.Text());
+ statusText += message;
+ statusText += L"\r\n";
+ statusMessageList.Text(statusText);
+ statusMessageList.Select(static_cast(statusText.size()), 0);
+
+ ScrollViewer viewer = FindScrollViewer(statusMessageList);
+ if (viewer != nullptr)
+ {
+ viewer.ChangeView(nullptr, statusMessageList.ActualHeight(), nullptr);
+ }
+}
+
+void
+Scenario3::AddLogFileMessage(_In_ LPCWSTR message, _In_opt_ LPCWSTR logFileFullPath)
+{
+ std::wstring finalMessage = message;
+
+ if (logFileFullPath == nullptr || logFileFullPath[0] == 0)
+ {
+ finalMessage += L": none, nothing logged since saving the last file.";
+ }
+ else
+ {
+ // Add a message to the UI indicating a new log file was created.
+ std::wstring fullPath(logFileFullPath);
+ std::wstring directoryName;
+ std::wstring fileName;
+ std::size_t lastSlashPos = fullPath.find_last_of(L'\\');
+ if (lastSlashPos > 0 && lastSlashPos < fullPath.size() - 1)
+ {
+ directoryName = fullPath.substr(0, lastSlashPos);
+ fileName = fullPath.substr(lastSlashPos + 1, fullPath.size() - (lastSlashPos + 1));
+ }
+
+ ViewLogInfo().Text(
+ L"Log folder: \"" + directoryName + L"\"\r\n"
+ L"- To view with tracerpt: tracerpt.exe \"" + fullPath + L"\" -of XML -o LogFile.xml\r\n"
+ L"- To view with Windows Performance Toolkit (WPT):\n"
+ L" xperf -merge \"" + fullPath + "\" merged.etl\n"
+ L" wpa.exe merged.etl");
+
+ finalMessage += L": ";
+ finalMessage += fileName;
+ }
+
+ AddMessage(finalMessage.c_str());
+}
+
+fire_and_forget
+Scenario3::OnStatusChanged(SDKTemplate::LoggingScenarioEventArgs args)
+{
+ // Switch to UI thread.
+ co_await resume_foreground(Dispatcher());
+
+ switch (args.Type())
+ {
+ case LoggingScenarioEventType::BusyStatusChanged:
+ UpdateControls();
+ break;
+
+ case LoggingScenarioEventType::LogFileGenerated:
+ AddLogFileMessage(L"LogFileGenerated", args.LogFileFullPath().c_str());
+ break;
+
+ case LoggingScenarioEventType::LogFileGeneratedAtSuspend:
+ AddLogFileMessage(L"Log file at suspend", args.LogFileFullPath().c_str());
+ break;
+
+ case LoggingScenarioEventType::LogFileGeneratedAtDisable:
+ AddLogFileMessage(L"Log file at disable", args.LogFileFullPath().c_str());
+ break;
+
+ case LoggingScenarioEventType::LoggingEnabledDisabled:
+ AddMessage(args.Enabled()
+ ? L"Logging has been enabled."
+ : L"Logging has been disabled.");
+ break;
+
+ default:
+ AddMessage(L"Unrecognized event.");
+ break;
+ }
+}
diff --git a/Samples/Logging/cppwinrt/Scenario3.h b/Samples/Logging/cppwinrt/Scenario3.h
new file mode 100644
index 0000000000..eca2391438
--- /dev/null
+++ b/Samples/Logging/cppwinrt/Scenario3.h
@@ -0,0 +1,67 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "Scenario3.g.h"
+#include "FileLoggingSessionScenario.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario3 : Scenario3T
+ {
+ Scenario3();
+
+ fire_and_forget
+ DoScenario(
+ Windows::Foundation::IInspectable const& sender,
+ Windows::UI::Xaml::RoutedEventArgs const& args);
+
+ fire_and_forget
+ EnableDisableLogging(
+ Windows::Foundation::IInspectable const& sender,
+ Windows::UI::Xaml::RoutedEventArgs const& args);
+
+ void
+ OnNavigatedTo(
+ Windows::UI::Xaml::Navigation::NavigationEventArgs const& args);
+
+ void
+ OnNavigatedFrom(
+ Windows::UI::Xaml::Navigation::NavigationEventArgs const& args);
+
+ private:
+
+ void
+ UpdateControls();
+
+ void
+ AddMessage(_In_ LPCWSTR message);
+
+ void
+ AddLogFileMessage(
+ _In_ LPCWSTR message,
+ _In_opt_ LPCWSTR logFileFullPath);
+
+ fire_and_forget
+ OnStatusChanged(SDKTemplate::LoggingScenarioEventArgs args);
+
+ FileLoggingSessionScenario& _instance = FileLoggingSessionScenario::Instance();
+ event_token _statusChangedToken;
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario3 : Scenario3T
+ {
+ };
+}
diff --git a/Samples/Logging/cppwinrt/packages.config b/Samples/Logging/cppwinrt/packages.config
new file mode 100644
index 0000000000..68fd1b237d
--- /dev/null
+++ b/Samples/Logging/cppwinrt/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Samples/Logging/cppwinrt/pch.cpp b/Samples/Logging/cppwinrt/pch.cpp
new file mode 100644
index 0000000000..bcb5590be1
--- /dev/null
+++ b/Samples/Logging/cppwinrt/pch.cpp
@@ -0,0 +1 @@
+#include "pch.h"
diff --git a/Samples/Logging/cppwinrt/pch.h b/Samples/Logging/cppwinrt/pch.h
new file mode 100644
index 0000000000..3af35202e3
--- /dev/null
+++ b/Samples/Logging/cppwinrt/pch.h
@@ -0,0 +1,31 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include
+#include "winrt/Windows.Foundation.h"
+#include "winrt/Windows.Foundation.Collections.h"
+#include "winrt/Windows.Foundation.Diagnostics.h"
+#include "winrt/Windows.Storage.h"
+#include "winrt/Windows.ApplicationModel.Activation.h"
+#include "winrt/Windows.System.h"
+#include "winrt/Windows.UI.Core.h"
+#include "winrt/Windows.UI.Xaml.h"
+#include "winrt/Windows.UI.Xaml.Automation.Peers.h"
+#include "winrt/Windows.UI.Xaml.Controls.h"
+#include "winrt/Windows.UI.Xaml.Controls.Primitives.h"
+#include "winrt/Windows.UI.Xaml.Documents.h"
+#include "winrt/Windows.UI.Xaml.Interop.h"
+#include "winrt/Windows.UI.Xaml.Markup.h"
+#include "winrt/Windows.UI.Xaml.Media.h"
+#include "winrt/Windows.UI.Xaml.Navigation.h"
+#include
diff --git a/SharedContent/cs/DeviceHelpers.cs b/SharedContent/cs/DeviceHelpers.cs
index 34762e0307..1117478c0c 100644
--- a/SharedContent/cs/DeviceHelpers.cs
+++ b/SharedContent/cs/DeviceHelpers.cs
@@ -50,6 +50,18 @@ public static async Task GetFirstDeviceAsync(string selector, Func
+ {
+ // We don't do anything here, but this event needs to be handled to enable realtime updates.
+ // See https://aka.ms/devicewatcher_added.
+ };
+
+ watcher.Updated += (DeviceWatcher sender, DeviceInformationUpdate args) =>
+ {
+ // We don't do anything here, but this event needs to be handled to enable realtime updates.
+ // See https://aka.ms/devicewatcher_added.
+ };
+
watcher.Start();
// Wait for enumeration to complete or for a device to be found.