From da13015bb1a9a924fd0bcd5c51149aa9f301a8b8 Mon Sep 17 00:00:00 2001 From: Anthony Chen Date: Thu, 24 Sep 2026 17:43:36 -0700 Subject: [PATCH 1/2] Normalize tracked text files to LF Co-authored-by: Copilot App --- README.md | 252 +- SUPPORT.md | 14 +- samples/Accelerometer/CS/Accelerometer.csproj | 308 +- samples/Accelerometer/CS/Accelerometer.sln | 80 +- samples/Accelerometer/CS/App.xaml | 18 +- samples/Accelerometer/CS/App.xaml.cs | 202 +- samples/Accelerometer/CS/MainPage.xaml | 46 +- samples/Accelerometer/CS/MainPage.xaml.cs | 538 +-- samples/Accelerometer/CS/Package.appxmanifest | 100 +- .../CS/Properties/AssemblyInfo.cs | 56 +- .../CS/Properties/Default.rd.xml | 60 +- samples/Accelerometer/CS/README.md | 572 +-- samples/Accelerometer/README.md | 572 +-- samples/AppServiceBlinky/CPP/BlinkyClient.sln | 80 +- .../CPP/BlinkyClient/BlinkyClient.vcxproj | 466 +-- .../CPP/BlinkyClient/Package.appxmanifest | 112 +- .../CPP/BlinkyClient/StartupTask.cpp | 168 +- .../CPP/BlinkyClient/StartupTask.h | 40 +- .../AppServiceBlinky/CPP/BlinkyClient/pch.cpp | 12 +- .../AppServiceBlinky/CPP/BlinkyClient/pch.h | 20 +- .../AppServiceBlinky/CPP/BlinkyService.sln | 80 +- .../CPP/BlinkyService/BlinkyService.vcxproj | 468 +-- .../BlinkyService/BlinkyServiceProvider.cpp | 198 +- .../CPP/BlinkyService/BlinkyServiceProvider.h | 42 +- .../CPP/BlinkyService/Package.appxmanifest | 108 +- .../CPP/BlinkyService/pch.cpp | 12 +- .../AppServiceBlinky/CPP/BlinkyService/pch.h | 20 +- samples/AppServiceBlinky/CPP/README.md | 448 +-- samples/AppServiceBlinky/CS/BlinkyClient.sln | 80 +- .../CS/BlinkyClient/BlinkyClient.csproj | 262 +- .../CS/BlinkyClient/Package.appxmanifest | 112 +- .../BlinkyClient/Properties/AssemblyInfo.cs | 56 +- .../CS/BlinkyClient/Properties/Default.rd.xml | 60 +- .../CS/BlinkyClient/StartupTask.cs | 148 +- samples/AppServiceBlinky/CS/BlinkyService.sln | 80 +- .../CS/BlinkyService/BlinkyService.csproj | 262 +- .../CS/BlinkyService/Package.appxmanifest | 76 +- .../BlinkyService/Properties/AssemblyInfo.cs | 56 +- .../BlinkyService/Properties/Default.rd.xml | 60 +- .../CS/BlinkyService/StartupTask.cs | 224 +- samples/AppServiceBlinky/CS/README.md | 448 +-- samples/AppServiceBlinky/README.md | 448 +-- .../CS/NotepadClientBackgroundApplication.sln | 80 +- .../NotepadClientBackgroundApplication.csproj | 262 +- .../Package.appxmanifest | 112 +- .../Properties/AssemblyInfo.cs | 56 +- .../Properties/Default.rd.xml | 60 +- .../StartupTask.cs | 162 +- .../CS/NotepadService.sln | 80 +- .../CS/NotepadService/Notepad.cs | 164 +- .../CS/NotepadService/NotepadService.csproj | 264 +- .../CS/NotepadService/Package.appxmanifest | 78 +- .../NotepadService/Properties/AssemblyInfo.cs | 56 +- .../NotepadService/Properties/Default.rd.xml | 60 +- .../CS/NotepadService/StartupTask.cs | 218 +- .../CS/NotepadServiceClientApp.sln | 80 +- .../CS/NotepadServiceClientApp/App.xaml | 16 +- .../CS/NotepadServiceClientApp/App.xaml.cs | 216 +- .../ApplicationInsights.config | 6 +- .../CS/NotepadServiceClientApp/MainPage.xaml | 42 +- .../NotepadServiceClientApp/MainPage.xaml.cs | 204 +- .../NotepadServiceClientApp.csproj | 314 +- .../Package.appxmanifest | 98 +- .../Properties/AssemblyInfo.cs | 56 +- .../Properties/Default.rd.xml | 60 +- samples/AppServiceSharedNotepad/CS/README.md | 634 ++-- samples/AppServiceSharedNotepad/README.md | 634 ++-- samples/CustomDeviceAccessor/CPP/App.xaml | 18 +- samples/CustomDeviceAccessor/CPP/App.xaml.cpp | 242 +- samples/CustomDeviceAccessor/CPP/App.xaml.h | 58 +- .../CPP/CustomDeviceAccessorUWP.filters | 112 +- .../CPP/CustomDeviceAccessorUWP.sln | 80 +- .../CPP/CustomDeviceAccessorUWP.vcxproj | 396 +- .../CustomDeviceAccessor/CPP/MainPage.xaml | 28 +- .../CPP/MainPage.xaml.cpp | 172 +- .../CustomDeviceAccessor/CPP/MainPage.xaml.h | 46 +- .../CPP/Package.appxmanifest | 56 +- samples/CustomDeviceAccessor/CPP/README.md | 540 +-- samples/CustomDeviceAccessor/CPP/pch.cpp | 16 +- samples/CustomDeviceAccessor/CPP/pch.h | 74 +- samples/CustomDeviceAccessor/README.md | 586 +-- samples/DMMocKPortal/App.config | 42 +- samples/DMMocKPortal/App.xaml | 142 +- samples/DMMocKPortal/App.xaml.cs | 40 +- samples/DMMocKPortal/DMConstants.cs | 24 +- samples/DMMocKPortal/DMMockPortal.csproj | 484 +-- samples/DMMocKPortal/DMMockPortal.sln | 62 +- samples/DMMocKPortal/DeploymentControl.xaml | 416 +-- .../DMMocKPortal/DeploymentControl.xaml.cs | 930 ++--- .../DMMocKPortal/DeploymentListControl.xaml | 116 +- .../DeploymentListControl.xaml.cs | 566 +-- samples/DMMocKPortal/DeviceListControl.xaml | 110 +- .../DMMocKPortal/DeviceListControl.xaml.cs | 264 +- samples/DMMocKPortal/DeviceTwinControl.xaml | 396 +- .../DMMocKPortal/DeviceTwinControl.xaml.cs | 438 +-- samples/DMMocKPortal/DevicesQuery.cs | 232 +- .../DMMocKPortal/Dialogs/SamplesDialog.xaml | 328 +- .../Dialogs/SamplesDialog.xaml.cs | 42 +- samples/DMMocKPortal/IotHubManager.cs | 268 +- samples/DMMocKPortal/JsonTemplates.cs | 100 +- samples/DMMocKPortal/MainWindow.xaml | 82 +- samples/DMMocKPortal/MainWindow.xaml.cs | 130 +- .../DMMocKPortal/Properties/AssemblyInfo.cs | 116 +- .../Properties/Resources.Designer.cs | 142 +- .../DMMocKPortal/Properties/Resources.resx | 232 +- .../Properties/Settings.Designer.cs | 60 +- .../DMMocKPortal/Properties/Settings.settings | 12 +- .../ApplicationListControl.xaml | 38 +- .../ApplicationListControl.xaml.cs | 62 +- .../PropertyControls/AzureStorageControl.xaml | 46 +- .../AzureStorageControl.xaml.cs | 62 +- .../PropertyControls/RebootInfoControl.xaml | 46 +- .../RebootInfoControl.xaml.cs | 62 +- .../WindowsUpdateControl.xaml | 56 +- .../WindowsUpdateControl.xaml.cs | 62 +- samples/DMMocKPortal/TabControl.xaml | 82 +- samples/DMMocKPortal/packages.config | 36 +- samples/DMMocKPortal/readme.md | 232 +- .../windows_telemetry_x64_v1.json.txt | 12 +- samples/DeviceIOContoller/CPP/README.md | 548 +-- samples/DeviceIOContoller/README.md | 564 +-- .../DualOperator/DualOperator.csproj.user | 20 +- .../DualOperator/OperatorManager.resx | 118 +- .../DualOperator/ScanOperator.resx | 118 +- samples/DualOperator/README.md | 234 +- samples/DualOperator/TestApp/Form1.resx | 118 +- .../DualOperator/TestApp/TestApp.csproj.user | 16 +- .../Properties/Default.rd.xml | 60 +- samples/ExternalProcessLauncher/CS/README.md | 412 +-- samples/ExternalProcessLauncher/README.md | 412 +-- .../CS/FlowVolume/Properties/Default.rd.xml | 60 +- samples/FlowVolume/CS/README.md | 222 +- samples/FlowVolume/README.md | 222 +- .../CPP/README.md | 338 +- .../Properties/Default.rd.xml | 60 +- .../MyForegroundApp/Properties/Default.rd.xml | 60 +- .../CS/README.md | 338 +- .../ForegroundAppWithBackgroundApp/README.md | 336 +- samples/GPIOKmdfDemo/LICENSE.txt | 42 +- samples/GPIOKmdfDemo/asl/dragon.asl | 114 +- samples/GPIOKmdfDemo/asl/gpiokmdfdemo.asl | 110 +- samples/GPIOKmdfDemo/asl/rpi2.asl | 112 +- samples/GPIOKmdfDemo/readme.md | 90 +- samples/GPIOOneWire/CPP/ReadMe.md | 414 +-- samples/GPIOOneWire/CPP/schematic.sch | 816 ++--- samples/GPIOOneWire/ReadMe.md | 414 +-- samples/HIDInjector/README.md | 100 +- .../driver/CreateDriverPackage.cmd | 34 +- .../HIDInjector/driver/HidDriver.arm.pkg.xml | 42 +- .../Hello Blinky/CS/Properties/Default.rd.xml | 60 +- samples/Hello Blinky/CS/README.md | 372 +- samples/Hello Blinky/Cpp/README.md | 372 +- samples/Hello Blinky/README.md | 372 +- samples/HelloBlinkyBackground/CPP/README.md | 252 +- .../CS/Properties/Default.rd.xml | 60 +- samples/HelloBlinkyBackground/CS/README.md | 252 +- samples/HelloBlinkyBackground/README.md | 252 +- .../VB/BlinkyHeadlessVB.vbproj | 362 +- .../VB/My Project/AssemblyInfo.vb | 60 +- .../VB/My Project/Default.rd.xml | 60 +- samples/HelloBlinkyBackground/VB/README.md | 252 +- .../HelloBlinkyBackground/VB/StartupTask.vb | 120 +- .../I2CCompass/CS/Properties/Default.rd.xml | 60 +- samples/I2CCompass/README.md | 118 +- samples/I2CPortExpander/CS/README.md | 1198 +++--- samples/I2CPortExpander/README.md | 1198 +++--- samples/IoTEnterpriseDefault/CS/README.md | 334 +- .../Properties/SmartDisplay.Contracts.rd.xml | 66 +- .../Properties/SmartDisplay.Features.rd.xml | 66 +- .../Strings/en-US/Resources.resw | 276 +- .../Properties/SmartDisplay.Utils.rd.xml | 66 +- .../Assets/Messages/LogDescription.txt | 2 +- .../CS/SmartDisplay/Properties/Default.rd.xml | 60 +- .../SmartDisplay/Strings/de-DE/Resources.resw | 3018 +++++++-------- .../SmartDisplay/Strings/en-US/Resources.resw | 3264 ++++++++--------- .../SmartDisplay/Strings/es-ES/Resources.resw | 3018 +++++++-------- .../SmartDisplay/Strings/fr-FR/Resources.resw | 3018 +++++++-------- .../SmartDisplay/Strings/it-IT/Resources.resw | 3018 +++++++-------- .../SmartDisplay/Strings/ja-JP/Resources.resw | 3018 +++++++-------- .../CS/SmartDisplay/Strings/ko/Resources.resw | 3018 +++++++-------- .../SmartDisplay/Strings/pt-BR/Resources.resw | 3018 +++++++-------- .../SmartDisplay/Strings/ru-RU/Resources.resw | 3018 +++++++-------- .../SmartDisplay/Strings/zh-TW/Resources.resw | 3018 +++++++-------- .../Strings/zh-hans/Resources.resw | 3018 +++++++-------- samples/IoTEnterpriseDefault/README.md | 334 +- samples/IoTHubClients/CS/Assets/test | 2 +- .../CS/Properties/Default.rd.xml | 62 +- samples/IoTHubClients/CS/README.md | 152 +- samples/IoTHubClients/README.md | 152 +- samples/MemoryStatus/README.md | 336 +- samples/MemoryStatus/cpp/README.md | 336 +- samples/NTServiceRpc/README.md | 86 +- samples/NTServiceRpc/cpp/README.md | 86 +- .../cpp/Service/Interface/RpcInterface.acf | 34 +- samples/NTServiceRpc/cpp/docs/ACL.md | 156 +- samples/NTServiceRpc/cpp/docs/Client.md | 38 +- samples/NTServiceRpc/cpp/docs/IoT.md | 18 +- samples/NTServiceRpc/cpp/docs/Server.md | 64 +- .../CS/Properties/Default.rd.xml | 60 +- samples/Potentiometer/CS/README.md | 558 +-- samples/Potentiometer/README.md | 556 +-- samples/PushButtton/CS/README.md | 356 +- samples/PushButtton/README.md | 356 +- .../Mfrc522Lib/Properties/Mfrc522Lib.rd.xml | 66 +- .../Properties/PiezoBuzzerLib.rd.xml | 66 +- samples/RFIDForIoT/CS/README.md | 166 +- .../CS/RFIDForIoT/Properties/Default.rd.xml | 60 +- samples/RFIDForIoT/README.md | 190 +- samples/RGBLED/CS/Properties/Default.rd.xml | 60 +- samples/RGBLED/CS/README.md | 516 +-- samples/RGBLED/README.md | 518 +-- samples/RemoveOnIoTEnterpriseS.ps1 | 580 +-- samples/SPIDisplay/CS/README.md | 908 ++--- .../CS/SPIDisplay/Properties/Default.rd.xml | 60 +- samples/SPIDisplay/README.md | 908 ++--- .../SerialNumber/CS/Properties/Default.rd.xml | 60 +- samples/SerialNumber/CS/README.md | 154 +- samples/SerialNumber/README.md | 148 +- samples/SerialUART/CPP/README.md | 904 ++--- .../SerialUART/CS/Properties/Default.rd.xml | 60 +- samples/SerialUART/CS/README.md | 924 ++--- samples/SerialUART/README.md | 838 ++--- samples/ShellLauncher/README.md | 58 +- .../SampleBridgeWmiScripts/README.md | 80 +- .../ShellLauncherBridgeWmiHelpers.ps1 | 66 +- .../ShellLauncher/SampleConfigXmls/README.md | 106 +- .../ShellLauncherAutoLogonUwp.xml | 42 +- .../ShellLauncherAzureADMultiUser.xml | 60 +- .../ShellLauncherConfiguration_Demo.syncml | 98 +- .../ShellLauncherDefaultOnlyUwp.xml | 22 +- .../SampleConfigXmls/ShellLauncherSid.xml | 46 +- .../AnotherUwpApp/Properties/Default.rd.xml | 60 +- .../ShellLauncherV2/AnotherUwpApp/README.md | 30 +- .../Properties/Default.rd.xml | 60 +- .../ShellLauncherV2DemoUwp/README.md | 44 +- .../ShellLauncherV2DemoWin32/App.config | 10 +- .../Properties/Resources.resx | 232 +- .../Properties/Settings.settings | 12 +- .../ShellLauncherV2DemoWin32/README.md | 44 +- .../README.md | 34 +- .../ShellLauncherV2DemoWin32Installer.vdproj | 1512 ++++---- .../CS/ApplicationInsights.config | 4 +- .../CS/Properties/Default.rd.xml | 60 +- samples/SpeechTranslator/CS/README.md | 164 +- samples/SpeechTranslator/README.md | 164 +- .../CS/Properties/Default.rd.xml | 60 +- samples/TempForceSensor/CS/README.md | 442 +-- samples/TempForceSensor/README.md | 466 +-- .../CS/Properties/Default.rd.xml | 60 +- samples/VideoCaptureSample/CS/README.md | 416 +-- samples/VideoCaptureSample/README.md | 416 +-- .../Cpp/README.md | 84 +- .../VirtualMicrophoneArrayDriver/README.md | 84 +- .../WebcamApp/CS/Properties/Default.rd.xml | 60 +- samples/WebcamApp/CS/README.md | 664 ++-- samples/WebcamApp/README.md | 664 ++-- .../CS/Properties/Default.rd.xml | 60 +- samples/WifiConnector/CS/README.md | 736 ++-- samples/WifiConnector/README.md | 736 ++-- 259 files changed, 42816 insertions(+), 42816 deletions(-) diff --git a/README.md b/README.md index ed383d94d..b80b5ff89 100644 --- a/README.md +++ b/README.md @@ -1,126 +1,126 @@ - - - ██╗ ██╗ ██╗ ███╗ ██╗ ██████╗ █████╗ ██╗ ██╗ ██████╗   ██╗ ████████╗ - ██║ ██╗ ██║ ██║ ████╗ ██║ ██╔══██╗ ██╔══██╗ ██║ ██╗ ██║ ██╔════╝   ██║ ╚══██╔══╝ - ╚██╗████╗██╔╝ ██║ ██╔██╗██║ ██║ ██║ ██║ ██║ ╚██╗████╗██╔╝ ╚█████╗    ██║ █████╗ ██║ - ████╔═████║ ██║ ██║╚████║ ██║ ██║ ██║ ██║ ████╔═████║ ╚═══██╗  ██║ ██╔══██║ ██║ - ╚██╔╝ ╚██╔╝ ██║ ██║ ╚███║ ██████╔╝ ╚█████╔╝ ╚██╔╝ ╚██╔╝ ██████╔╝   ██║ ╚█████╔╝ ██║ -   ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══╝ ╚═════╝ ╚════╝ ╚═╝ ╚═╝ ╚═════╝    ╚═╝ ╚════╝ ╚═╝ - -# Windows Internet of Things (IoT) Samples - -This repo contains samples that demonstrate usage patterns for Microsoft's Windows 10 IoT. These code samples were created with templates available in Visual Studio and are designed, but not limited to, run on devices using Windows IoT Enterprise. - -> **Note:** If you are unfamiliar with Git and GitHub, you can download the entire collection as a -> [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. - -## Windows 10 IoT development -These samples require Visual Studio and the Windows Software Development Kit (SDK) for Windows 10. - - [Get a free copy of Visual Studio Community Edition with support for building Universal Windows Platform apps](http://go.microsoft.com/fwlink/p/?LinkID=280676) - -Additionally, to stay on top of the latest updates to Windows and the development tools, become a Windows Insider by joining the Windows Insider Program. - - [Become a Windows Insider](https://insider.windows.com/) - - ## Using the samples - -The easiest way to use these samples without using Git is to download the zip file containing the current version (using the following link or by clicking the "Download ZIP" button on the repo page). You can then unzip the entire archive and use the samples in Visual Studio. - - [Download the samples ZIP](../../archive/master.zip) - - **Notes:** - * Before you unzip the archive, right-click it, select **Properties**, and then select **Unblock**. - * Be sure to unzip the entire archive, and not just individual samples. The samples all depend on the SharedContent folder in the archive. - * In Visual Studio, the platform target defaults to ARM, so be sure to change that to x64 or x86 if you want to test on a non-ARM device. - -The samples use Linked files in Visual Studio to reduce duplication of common files, including sample template files and image assets. These common files are stored in the SharedContent folder at the root of the repository and are referred to in the project files using links. - -**Reminder:** If you unzip individual samples, they will not build due to references to other portions of the ZIP file that were not unzipped. You must unzip the entire archive if you intend to build the samples. - -For more info about the programming models, platforms, languages, and APIs demonstrated in these samples, please refer to the guidance, tutorials, and reference topics provided in the Windows 10 documentation available in the [Windows Developer Center](http://go.microsoft.com/fwlink/p/?LinkID=532421). These samples are provided as-is in order to indicate or demonstrate the functionality of the programming models and feature APIs for Windows. - -## Contributing -These samples are direct from the feature teams and we welcome your input on issues and suggestions for new samples. If you would like to see new coverage or have feedback, please consider contributing. You can edit the existing content, add new content, or simply create new issues. We’ll take a look at your suggestions and will work together to incorporate them into the docs. - -This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. - -**Note**: -* When contributing, make sure you are contributing from the **develop** branch and not the master branch. Your contribution will not be accepted if your PR is coming from the master branch. - -When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. - -This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments. - - -## See also - -For additional Windows samples, see: -* [Windows on GitHub](http://microsoft.github.io/windows/) -* [Windows IoT Core](https://github.com/microsoft/Windows-iotcore-samples/tree/develop/Samples) -* [Azure IoT Edge for Linux on Windows (EFLOW)](https://github.com/Azure/iotedge-eflow) -* [.NET IoT Libraries](https://github.com/dotnet/iot) - -## Samples by category - -### Azure IoT Edge - -| Name | Description | -|----------------|------------------| -| [interop-textmsg-consoleapp](https://aka.ms/WinIoTSamples-interop-textmsg-consoleapp) | Basic interop sample demonstrating text messaging between a Windows console app and an Edge module. | -| [interop-customvision-textmsg-uwpapp](https://aka.ms/WinIoTSamples-interop-customvision-textmsg-uwpapp) |

Two more advanced interop samples which demonstrate bidirectional communication between a Windows application and an Edge module.

| - -### Windows 10 IoT Enterprise - -| Name | Description | -|----------------|------------------| -| [Accelerometer](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/Accelerometer) | Sample app that reads data over either I2C or SPI from an attached ADXL345 accelerometer | -| [AppServiceBlinky](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/AppServiceBlinky) | Two part sample. 1. Create a simple Blinky app service and connect a LED to your Windows IoT Enterprise device (Up-Board). 2. Create a simple app service client that blinks the LED | -| [AppServiceSharedNotepad](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/AppServiceSharedNotepad) | This app creates a simple notepad app service, and two simple app service clients. One app will write to the notepad service and the other one reads from the notepad service. | -| [CustomDeviceAccessor](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/CustomDeviceAccessor) | This sample shows how to access devices from UWP applications using familiar win32 APIs like CreateFile(), ReadFile(), WriteFile(), and DeviceIOControl(). | -| [DMMockPortal](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/DMMocKPortal) | This sample shows what an operator's flow might look like when it comes to updating devices in bulk or individually. | -| [DeviceIOContoller](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/DeviceIOContoller) | This sample shows how to access devices from UWP applications using familiar win32 APIs like CreateFile(), ReadFile(), WriteFile(), and DeviceIoControl(). | -| [DualOperator](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/DualOperator) | This sample demonstrates Dual Operator demonstrates routing input from 2 physical keyboards to specific applications. | -| [ExternalProcessLauncher](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/ExternalProcessLauncher) | We'll learn how to launch an external process (exe) from a Universal Windows Platform (UWP) app using Windows.System.ProcessLauncher API. | -| [FlowVolume](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/FlowVolume) | This sample show how to launch an external process (exe) from a Universal Windows Platform (UWP) app using Windows.System.ProcessLauncher API. | -| [ForegroundAppWithBackgroundApp](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/ForegroundAppWithBackgroundApp) | This sample will showcase how to create a foreground application with a background application. | -| [GPIOKmdfDemo](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/GPIOKmdfDemo) | This sample will demonstrate how to deploy a GPIO Kernel driver to a Windows 10 IoT Device. | -| [GPIOOneWire](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/GPIOOneWire) | This sample shows how to read a temperature and humidity sensor from a Universal Windows Application. | -| [HIDInjector](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/HIDInjector) | This sample will allow you to deploy a driver to perform low level injection of touch, keyboard and mouse events. | -| [Hello Blinky](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/Hello%20Blinky) | This sample is a simple blinking LED app. | -| [HelloBlinkyBackground](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/HelloBlinkyBackground) | This sample showcases how to set up and use a background service. | -| [I2CCompass](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/I2CCompass) | This sample uses I2C on Windows IoT Enterprise to communicate with an magnetometer device.| -| [I2CPortExpander](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/I2CPortExpander) | This sample app uses the port expander to read the status of a tactile switch and control an LED. | -| [IoTEnterpriseDefault](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/IoTEnterpriseDefault) | This sample app provides an overview of the various features that can be enabled in Windows 10 IoT Enterprise. | -| [IoTHubClients](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/IoTHubClients) | This sample demonstrates how to connect to IoT Hub, send telemetry, and monitor and respond to device twin state changes. | -| [MemoryStatus](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/MemoryStatus) | This sample is intended to show how to create a console application that can be used to query the memory usage on your Windows 10 IoT Enterprise device. | -| [NTServiceRpc](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/NTServiceRpc) | This sample demonstrates the use of a NT service with an UWP app. | -| [Potentiometer](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/Potentiometer) | This sample shows how to connect a rotary potentiometer and LED to a Windows IoT Enterprise compatible board. | -| [PushButtton](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/PushButtton) | This sample shows how to use a push button to control an LED. | -| [RFIDForIoT](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/RFIDForIoT) | This sample demonstrates how to read an RFID tag and beep the buzzer when the card scans. | -| [RGBLED](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/RGBLED) | This sample demonstrates how a tri-color LED will blink and cycle through red, blue and green. | -| [SPIDisplay](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/SPIDisplay) | This sample interfaces a SPI based OLED display to a Windows 10 IoT Enterprise device. | -| [SerialNumber](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/SerialNumber) | This sample demonstrates how to get the device serial number. | -| [SerialUART](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/SerialUART) | This sample creates an app that allows communication between a PC and an IoT device over a serial interface. | -| [ShellLauncher](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/ShellLauncher) | This is a UWP app sample for Shell Launcher V2, see how to configure UWP app for Shell Launcher V2 in the samples. | -| [SpeechTranslator](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/SpeechTranslator) | This sample will translate speech to different languages. | -| [TempForceSensor](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/TempForceSensor) | This sample showcases how to use a temperature and force sensor. | -| [VideoCaptureSample](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/VideoCaptureSample) | This sample initializes a video capture device, record video to a file, preview video feed, and playback the recorded video. | -| [VirtualMicrophoneArrayDriver](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/VirtualMicrophoneArrayDriver) | This sample illustrates how to construct a virtual microphone array at runtime using monoaural audio devices present on the system. | -| [WebcamApp](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/WebcamApp) | This sample will initialize a webcam, take pictures, and record video and audio. | -| [WifiConnector](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/WifiConnector) | This sample will find and connect to WiFi networks using a Universal Windows Platform (UWP) app that makes use of the Windows.Devices.WiFi.WiFiAdapter API. | - - -#### Bus Tools -| Name | Description | -|----------------|------------------| -| [GPIOTestTool](https://github.com/microsoft/Windows-IoT-Samples/tree/master/BusTools) | Utility to manipulate GPIO pins from the command line. Demonstrates how to use the GPIO WinRT APIs from standard C++ with WRL. | -| [I2CTestTool](https://github.com/microsoft/Windows-IoT-Samples/tree/master/BusTools) | Utility to read and write I2C devices from the command line. Shows how to use C++/CX in console applications. | -| [MinComm (UART)](https://github.com/microsoft/Windows-IoT-Samples/tree/master/BusTools) | Demonstrates how to use UART. | -| [PWMTestTool](https://github.com/microsoft/Windows-IoT-Samples/tree/master/BusTools) | Utility to read and write PWM devices from the command line. Shows how to use C++/CX in console applications. | -| [SPITestTool](https://github.com/microsoft/Windows-IoT-Samples/tree/master/BusTools) | Utility to read and write SPI devices from the command line. | + + + ██╗ ██╗ ██╗ ███╗ ██╗ ██████╗ █████╗ ██╗ ██╗ ██████╗   ██╗ ████████╗ + ██║ ██╗ ██║ ██║ ████╗ ██║ ██╔══██╗ ██╔══██╗ ██║ ██╗ ██║ ██╔════╝   ██║ ╚══██╔══╝ + ╚██╗████╗██╔╝ ██║ ██╔██╗██║ ██║ ██║ ██║ ██║ ╚██╗████╗██╔╝ ╚█████╗    ██║ █████╗ ██║ + ████╔═████║ ██║ ██║╚████║ ██║ ██║ ██║ ██║ ████╔═████║ ╚═══██╗  ██║ ██╔══██║ ██║ + ╚██╔╝ ╚██╔╝ ██║ ██║ ╚███║ ██████╔╝ ╚█████╔╝ ╚██╔╝ ╚██╔╝ ██████╔╝   ██║ ╚█████╔╝ ██║ +   ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══╝ ╚═════╝ ╚════╝ ╚═╝ ╚═╝ ╚═════╝    ╚═╝ ╚════╝ ╚═╝ + +# Windows Internet of Things (IoT) Samples + +This repo contains samples that demonstrate usage patterns for Microsoft's Windows 10 IoT. These code samples were created with templates available in Visual Studio and are designed, but not limited to, run on devices using Windows IoT Enterprise. + +> **Note:** If you are unfamiliar with Git and GitHub, you can download the entire collection as a +> [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. + +## Windows 10 IoT development +These samples require Visual Studio and the Windows Software Development Kit (SDK) for Windows 10. + + [Get a free copy of Visual Studio Community Edition with support for building Universal Windows Platform apps](http://go.microsoft.com/fwlink/p/?LinkID=280676) + +Additionally, to stay on top of the latest updates to Windows and the development tools, become a Windows Insider by joining the Windows Insider Program. + + [Become a Windows Insider](https://insider.windows.com/) + + ## Using the samples + +The easiest way to use these samples without using Git is to download the zip file containing the current version (using the following link or by clicking the "Download ZIP" button on the repo page). You can then unzip the entire archive and use the samples in Visual Studio. + + [Download the samples ZIP](../../archive/master.zip) + + **Notes:** + * Before you unzip the archive, right-click it, select **Properties**, and then select **Unblock**. + * Be sure to unzip the entire archive, and not just individual samples. The samples all depend on the SharedContent folder in the archive. + * In Visual Studio, the platform target defaults to ARM, so be sure to change that to x64 or x86 if you want to test on a non-ARM device. + +The samples use Linked files in Visual Studio to reduce duplication of common files, including sample template files and image assets. These common files are stored in the SharedContent folder at the root of the repository and are referred to in the project files using links. + +**Reminder:** If you unzip individual samples, they will not build due to references to other portions of the ZIP file that were not unzipped. You must unzip the entire archive if you intend to build the samples. + +For more info about the programming models, platforms, languages, and APIs demonstrated in these samples, please refer to the guidance, tutorials, and reference topics provided in the Windows 10 documentation available in the [Windows Developer Center](http://go.microsoft.com/fwlink/p/?LinkID=532421). These samples are provided as-is in order to indicate or demonstrate the functionality of the programming models and feature APIs for Windows. + +## Contributing +These samples are direct from the feature teams and we welcome your input on issues and suggestions for new samples. If you would like to see new coverage or have feedback, please consider contributing. You can edit the existing content, add new content, or simply create new issues. We’ll take a look at your suggestions and will work together to incorporate them into the docs. + +This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. + +**Note**: +* When contributing, make sure you are contributing from the **develop** branch and not the master branch. Your contribution will not be accepted if your PR is coming from the master branch. + +When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments. + + +## See also + +For additional Windows samples, see: +* [Windows on GitHub](http://microsoft.github.io/windows/) +* [Windows IoT Core](https://github.com/microsoft/Windows-iotcore-samples/tree/develop/Samples) +* [Azure IoT Edge for Linux on Windows (EFLOW)](https://github.com/Azure/iotedge-eflow) +* [.NET IoT Libraries](https://github.com/dotnet/iot) + +## Samples by category + +### Azure IoT Edge + +| Name | Description | +|----------------|------------------| +| [interop-textmsg-consoleapp](https://aka.ms/WinIoTSamples-interop-textmsg-consoleapp) | Basic interop sample demonstrating text messaging between a Windows console app and an Edge module. | +| [interop-customvision-textmsg-uwpapp](https://aka.ms/WinIoTSamples-interop-customvision-textmsg-uwpapp) |

Two more advanced interop samples which demonstrate bidirectional communication between a Windows application and an Edge module.

| + +### Windows 10 IoT Enterprise + +| Name | Description | +|----------------|------------------| +| [Accelerometer](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/Accelerometer) | Sample app that reads data over either I2C or SPI from an attached ADXL345 accelerometer | +| [AppServiceBlinky](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/AppServiceBlinky) | Two part sample. 1. Create a simple Blinky app service and connect a LED to your Windows IoT Enterprise device (Up-Board). 2. Create a simple app service client that blinks the LED | +| [AppServiceSharedNotepad](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/AppServiceSharedNotepad) | This app creates a simple notepad app service, and two simple app service clients. One app will write to the notepad service and the other one reads from the notepad service. | +| [CustomDeviceAccessor](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/CustomDeviceAccessor) | This sample shows how to access devices from UWP applications using familiar win32 APIs like CreateFile(), ReadFile(), WriteFile(), and DeviceIOControl(). | +| [DMMockPortal](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/DMMocKPortal) | This sample shows what an operator's flow might look like when it comes to updating devices in bulk or individually. | +| [DeviceIOContoller](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/DeviceIOContoller) | This sample shows how to access devices from UWP applications using familiar win32 APIs like CreateFile(), ReadFile(), WriteFile(), and DeviceIoControl(). | +| [DualOperator](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/DualOperator) | This sample demonstrates Dual Operator demonstrates routing input from 2 physical keyboards to specific applications. | +| [ExternalProcessLauncher](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/ExternalProcessLauncher) | We'll learn how to launch an external process (exe) from a Universal Windows Platform (UWP) app using Windows.System.ProcessLauncher API. | +| [FlowVolume](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/FlowVolume) | This sample show how to launch an external process (exe) from a Universal Windows Platform (UWP) app using Windows.System.ProcessLauncher API. | +| [ForegroundAppWithBackgroundApp](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/ForegroundAppWithBackgroundApp) | This sample will showcase how to create a foreground application with a background application. | +| [GPIOKmdfDemo](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/GPIOKmdfDemo) | This sample will demonstrate how to deploy a GPIO Kernel driver to a Windows 10 IoT Device. | +| [GPIOOneWire](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/GPIOOneWire) | This sample shows how to read a temperature and humidity sensor from a Universal Windows Application. | +| [HIDInjector](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/HIDInjector) | This sample will allow you to deploy a driver to perform low level injection of touch, keyboard and mouse events. | +| [Hello Blinky](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/Hello%20Blinky) | This sample is a simple blinking LED app. | +| [HelloBlinkyBackground](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/HelloBlinkyBackground) | This sample showcases how to set up and use a background service. | +| [I2CCompass](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/I2CCompass) | This sample uses I2C on Windows IoT Enterprise to communicate with an magnetometer device.| +| [I2CPortExpander](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/I2CPortExpander) | This sample app uses the port expander to read the status of a tactile switch and control an LED. | +| [IoTEnterpriseDefault](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/IoTEnterpriseDefault) | This sample app provides an overview of the various features that can be enabled in Windows 10 IoT Enterprise. | +| [IoTHubClients](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/IoTHubClients) | This sample demonstrates how to connect to IoT Hub, send telemetry, and monitor and respond to device twin state changes. | +| [MemoryStatus](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/MemoryStatus) | This sample is intended to show how to create a console application that can be used to query the memory usage on your Windows 10 IoT Enterprise device. | +| [NTServiceRpc](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/NTServiceRpc) | This sample demonstrates the use of a NT service with an UWP app. | +| [Potentiometer](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/Potentiometer) | This sample shows how to connect a rotary potentiometer and LED to a Windows IoT Enterprise compatible board. | +| [PushButtton](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/PushButtton) | This sample shows how to use a push button to control an LED. | +| [RFIDForIoT](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/RFIDForIoT) | This sample demonstrates how to read an RFID tag and beep the buzzer when the card scans. | +| [RGBLED](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/RGBLED) | This sample demonstrates how a tri-color LED will blink and cycle through red, blue and green. | +| [SPIDisplay](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/SPIDisplay) | This sample interfaces a SPI based OLED display to a Windows 10 IoT Enterprise device. | +| [SerialNumber](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/SerialNumber) | This sample demonstrates how to get the device serial number. | +| [SerialUART](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/SerialUART) | This sample creates an app that allows communication between a PC and an IoT device over a serial interface. | +| [ShellLauncher](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/ShellLauncher) | This is a UWP app sample for Shell Launcher V2, see how to configure UWP app for Shell Launcher V2 in the samples. | +| [SpeechTranslator](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/SpeechTranslator) | This sample will translate speech to different languages. | +| [TempForceSensor](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/TempForceSensor) | This sample showcases how to use a temperature and force sensor. | +| [VideoCaptureSample](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/VideoCaptureSample) | This sample initializes a video capture device, record video to a file, preview video feed, and playback the recorded video. | +| [VirtualMicrophoneArrayDriver](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/VirtualMicrophoneArrayDriver) | This sample illustrates how to construct a virtual microphone array at runtime using monoaural audio devices present on the system. | +| [WebcamApp](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/WebcamApp) | This sample will initialize a webcam, take pictures, and record video and audio. | +| [WifiConnector](https://github.com/microsoft/Windows-IoT-Samples/tree/master/samples/WifiConnector) | This sample will find and connect to WiFi networks using a Universal Windows Platform (UWP) app that makes use of the Windows.Devices.WiFi.WiFiAdapter API. | + + +#### Bus Tools +| Name | Description | +|----------------|------------------| +| [GPIOTestTool](https://github.com/microsoft/Windows-IoT-Samples/tree/master/BusTools) | Utility to manipulate GPIO pins from the command line. Demonstrates how to use the GPIO WinRT APIs from standard C++ with WRL. | +| [I2CTestTool](https://github.com/microsoft/Windows-IoT-Samples/tree/master/BusTools) | Utility to read and write I2C devices from the command line. Shows how to use C++/CX in console applications. | +| [MinComm (UART)](https://github.com/microsoft/Windows-IoT-Samples/tree/master/BusTools) | Demonstrates how to use UART. | +| [PWMTestTool](https://github.com/microsoft/Windows-IoT-Samples/tree/master/BusTools) | Utility to read and write PWM devices from the command line. Shows how to use C++/CX in console applications. | +| [SPITestTool](https://github.com/microsoft/Windows-IoT-Samples/tree/master/BusTools) | Utility to read and write SPI devices from the command line. | diff --git a/SUPPORT.md b/SUPPORT.md index 978e778a3..c80e40ae0 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -1,7 +1,7 @@ -# Support - -## How to file issues and get help - -This project uses GitHub Issues to track bugs and feature requests. Please search the existing -issues before filing new issues to avoid duplicates. For new issues, file your bug or -feature request as a new Issue. +# Support + +## How to file issues and get help + +This project uses GitHub Issues to track bugs and feature requests. Please search the existing +issues before filing new issues to avoid duplicates. For new issues, file your bug or +feature request as a new Issue. diff --git a/samples/Accelerometer/CS/Accelerometer.csproj b/samples/Accelerometer/CS/Accelerometer.csproj index b1d41e7fe..d76b10d2e 100644 --- a/samples/Accelerometer/CS/Accelerometer.csproj +++ b/samples/Accelerometer/CS/Accelerometer.csproj @@ -1,154 +1,154 @@ - - - - - Debug - x86 - {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A} - AppContainerExe - Properties - Accelerometer - Accelerometer - en-US - UAP - 10.0.19041.0 - 10.0.15063.0 - 14 - true - 512 - {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Accelerometer_TemporaryKey.pfx - - - win10-arm;win10-arm-aot;win10-x86;win10-x86-aot;win10-x64;win10-x64-aot - False - SHA256 - True - True - Always - x64 - 0 - - - true - bin\ARM\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - ARM - false - prompt - true - - - bin\ARM\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - ARM - false - prompt - true - true - - - true - bin\x64\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - x64 - false - prompt - true - - - bin\x64\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - x64 - false - prompt - true - true - - - true - bin\x86\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - x86 - false - prompt - true - - - bin\x86\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - x86 - false - prompt - true - true - - - - App.xaml - - - MainPage.xaml - - - - - - Designer - - - - - - - - - - - - - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - - - - - - 5.0.0 - - - - 14.0 - - - - + + + + + Debug + x86 + {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A} + AppContainerExe + Properties + Accelerometer + Accelerometer + en-US + UAP + 10.0.19041.0 + 10.0.15063.0 + 14 + true + 512 + {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Accelerometer_TemporaryKey.pfx + + + win10-arm;win10-arm-aot;win10-x86;win10-x86-aot;win10-x64;win10-x64-aot + False + SHA256 + True + True + Always + x64 + 0 + + + true + bin\ARM\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + ARM + false + prompt + true + + + bin\ARM\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + ARM + false + prompt + true + true + + + true + bin\x64\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + x64 + false + prompt + true + + + bin\x64\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + x64 + false + prompt + true + true + + + true + bin\x86\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + x86 + false + prompt + true + + + bin\x86\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + x86 + false + prompt + true + true + + + + App.xaml + + + MainPage.xaml + + + + + + Designer + + + + + + + + + + + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + + + + + + 5.0.0 + + + + 14.0 + + + + diff --git a/samples/Accelerometer/CS/Accelerometer.sln b/samples/Accelerometer/CS/Accelerometer.sln index 265450b13..386b663f2 100644 --- a/samples/Accelerometer/CS/Accelerometer.sln +++ b/samples/Accelerometer/CS/Accelerometer.sln @@ -1,40 +1,40 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Accelerometer", "Accelerometer.csproj", "{1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}" -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 - {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Debug|ARM.ActiveCfg = Debug|ARM - {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Debug|ARM.Build.0 = Debug|ARM - {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Debug|ARM.Deploy.0 = Debug|ARM - {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Debug|x64.ActiveCfg = Debug|x64 - {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Debug|x64.Build.0 = Debug|x64 - {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Debug|x64.Deploy.0 = Debug|x64 - {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Debug|x86.ActiveCfg = Debug|x86 - {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Debug|x86.Build.0 = Debug|x86 - {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Debug|x86.Deploy.0 = Debug|x86 - {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Release|ARM.ActiveCfg = Release|ARM - {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Release|ARM.Build.0 = Release|ARM - {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Release|ARM.Deploy.0 = Release|ARM - {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Release|x64.ActiveCfg = Release|x64 - {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Release|x64.Build.0 = Release|x64 - {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Release|x64.Deploy.0 = Release|x64 - {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Release|x86.ActiveCfg = Release|x86 - {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Release|x86.Build.0 = Release|x86 - {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Release|x86.Deploy.0 = Release|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Accelerometer", "Accelerometer.csproj", "{1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}" +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 + {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Debug|ARM.ActiveCfg = Debug|ARM + {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Debug|ARM.Build.0 = Debug|ARM + {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Debug|ARM.Deploy.0 = Debug|ARM + {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Debug|x64.ActiveCfg = Debug|x64 + {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Debug|x64.Build.0 = Debug|x64 + {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Debug|x64.Deploy.0 = Debug|x64 + {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Debug|x86.ActiveCfg = Debug|x86 + {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Debug|x86.Build.0 = Debug|x86 + {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Debug|x86.Deploy.0 = Debug|x86 + {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Release|ARM.ActiveCfg = Release|ARM + {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Release|ARM.Build.0 = Release|ARM + {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Release|ARM.Deploy.0 = Release|ARM + {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Release|x64.ActiveCfg = Release|x64 + {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Release|x64.Build.0 = Release|x64 + {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Release|x64.Deploy.0 = Release|x64 + {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Release|x86.ActiveCfg = Release|x86 + {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Release|x86.Build.0 = Release|x86 + {1778F7E9-CD4F-45AC-8EB8-DA9AF005D84A}.Release|x86.Deploy.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/Accelerometer/CS/App.xaml b/samples/Accelerometer/CS/App.xaml index a457cd481..325afe283 100644 --- a/samples/Accelerometer/CS/App.xaml +++ b/samples/Accelerometer/CS/App.xaml @@ -1,9 +1,9 @@ - - - - - + + + + + diff --git a/samples/Accelerometer/CS/App.xaml.cs b/samples/Accelerometer/CS/App.xaml.cs index f3a3dccf7..d8c57c440 100644 --- a/samples/Accelerometer/CS/App.xaml.cs +++ b/samples/Accelerometer/CS/App.xaml.cs @@ -1,101 +1,101 @@ -// Copyright (c) Microsoft. All rights reserved. - -using System; -using Windows.ApplicationModel; -using Windows.ApplicationModel.Activation; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Navigation; - -// The Blank Application template is documented at http://go.microsoft.com/fwlink/?LinkId=402347&clcid=0x409 - -namespace Accelerometer -{ - /// - /// Provides application-specific behavior to supplement the default Application class. - /// - sealed partial class App : Application - { - /// - /// Initializes the singleton application object. This is the first line of authored code - /// executed, and as such is the logical equivalent of main() or WinMain(). - /// - public App() - { - this.InitializeComponent(); - this.Suspending += OnSuspending; - } - - /// - /// Invoked when the application is launched normally by the end user. Other entry points - /// will be used such as when the application is launched to open a specific file. - /// - /// Details about the launch request and process. - protected override void OnLaunched(LaunchActivatedEventArgs e) - { - -#if DEBUG - if (System.Diagnostics.Debugger.IsAttached) - { - this.DebugSettings.EnableFrameRateCounter = true; - } -#endif - - Frame rootFrame = Window.Current.Content as Frame; - - // Do not repeat app initialization when the Window already has content, - // just ensure that the window is active - if (rootFrame == null) - { - // Create a Frame to act as the navigation context and navigate to the first page - rootFrame = new Frame(); - // Set the default language - rootFrame.Language = Windows.Globalization.ApplicationLanguages.Languages[0]; - - rootFrame.NavigationFailed += OnNavigationFailed; - - if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) - { - //TODO: Load state from previously suspended application - } - - // Place the frame in the current Window - Window.Current.Content = rootFrame; - } - - if (rootFrame.Content == null) - { - // When the navigation stack isn't restored navigate to the first page, - // configuring the new page by passing required information as a navigation - // parameter - rootFrame.Navigate(typeof(MainPage), e.Arguments); - } - // Ensure the current window is active - Window.Current.Activate(); - } - - /// - /// Invoked when Navigation to a certain page fails - /// - /// The Frame which failed navigation - /// Details about the navigation failure - void OnNavigationFailed(object sender, NavigationFailedEventArgs e) - { - throw new Exception("Failed to load Page " + e.SourcePageType.FullName); - } - - /// - /// Invoked when application execution is being suspended. Application state is saved - /// without knowing whether the application will be terminated or resumed with the contents - /// of memory still intact. - /// - /// The source of the suspend request. - /// Details about the suspend request. - private void OnSuspending(object sender, SuspendingEventArgs e) - { - var deferral = e.SuspendingOperation.GetDeferral(); - //TODO: Save application state and stop any background activity - deferral.Complete(); - } - } -} +// Copyright (c) Microsoft. All rights reserved. + +using System; +using Windows.ApplicationModel; +using Windows.ApplicationModel.Activation; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; + +// The Blank Application template is documented at http://go.microsoft.com/fwlink/?LinkId=402347&clcid=0x409 + +namespace Accelerometer +{ + /// + /// Provides application-specific behavior to supplement the default Application class. + /// + sealed partial class App : Application + { + /// + /// Initializes the singleton application object. This is the first line of authored code + /// executed, and as such is the logical equivalent of main() or WinMain(). + /// + public App() + { + this.InitializeComponent(); + this.Suspending += OnSuspending; + } + + /// + /// Invoked when the application is launched normally by the end user. Other entry points + /// will be used such as when the application is launched to open a specific file. + /// + /// Details about the launch request and process. + protected override void OnLaunched(LaunchActivatedEventArgs e) + { + +#if DEBUG + if (System.Diagnostics.Debugger.IsAttached) + { + this.DebugSettings.EnableFrameRateCounter = true; + } +#endif + + Frame rootFrame = Window.Current.Content as Frame; + + // Do not repeat app initialization when the Window already has content, + // just ensure that the window is active + if (rootFrame == null) + { + // Create a Frame to act as the navigation context and navigate to the first page + rootFrame = new Frame(); + // Set the default language + rootFrame.Language = Windows.Globalization.ApplicationLanguages.Languages[0]; + + rootFrame.NavigationFailed += OnNavigationFailed; + + if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) + { + //TODO: Load state from previously suspended application + } + + // Place the frame in the current Window + Window.Current.Content = rootFrame; + } + + if (rootFrame.Content == null) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + rootFrame.Navigate(typeof(MainPage), e.Arguments); + } + // Ensure the current window is active + Window.Current.Activate(); + } + + /// + /// Invoked when Navigation to a certain page fails + /// + /// The Frame which failed navigation + /// Details about the navigation failure + void OnNavigationFailed(object sender, NavigationFailedEventArgs e) + { + throw new Exception("Failed to load Page " + e.SourcePageType.FullName); + } + + /// + /// Invoked when application execution is being suspended. Application state is saved + /// without knowing whether the application will be terminated or resumed with the contents + /// of memory still intact. + /// + /// The source of the suspend request. + /// Details about the suspend request. + private void OnSuspending(object sender, SuspendingEventArgs e) + { + var deferral = e.SuspendingOperation.GetDeferral(); + //TODO: Save application state and stop any background activity + deferral.Complete(); + } + } +} diff --git a/samples/Accelerometer/CS/MainPage.xaml b/samples/Accelerometer/CS/MainPage.xaml index f504414f1..6bd4a5f82 100644 --- a/samples/Accelerometer/CS/MainPage.xaml +++ b/samples/Accelerometer/CS/MainPage.xaml @@ -1,23 +1,23 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/samples/Accelerometer/CS/MainPage.xaml.cs b/samples/Accelerometer/CS/MainPage.xaml.cs index b19fea176..5455e13e7 100644 --- a/samples/Accelerometer/CS/MainPage.xaml.cs +++ b/samples/Accelerometer/CS/MainPage.xaml.cs @@ -1,269 +1,269 @@ -// Copyright (c) Microsoft. All rights reserved. - -using System; -using System.Threading; -using Windows.UI.Xaml.Controls; -using Windows.Devices.Enumeration; -using Windows.Devices.I2c; -using Windows.Devices.Spi; - -namespace Accelerometer -{ - struct Acceleration - { - public double X; - public double Y; - public double Z; - }; - - enum Protocol { NONE, SPI, I2C}; - - /// - /// Sample app that reads data over either I2C or SPI from an attached ADXL345 accelerometer - /// - public sealed partial class MainPage : Page - { - /* Important! Change this to either Protocol.I2C or Protocol.SPI based on how your accelerometer is wired */ - private Protocol HW_PROTOCOL = Protocol.NONE; - - private const byte ACCEL_REG_POWER_CONTROL = 0x2D; /* Address of the Power Control register */ - private const byte ACCEL_REG_DATA_FORMAT = 0x31; /* Address of the Data Format register */ - private const byte ACCEL_REG_X = 0x32; /* Address of the X Axis data register */ - private const byte ACCEL_REG_Y = 0x34; /* Address of the Y Axis data register */ - private const byte ACCEL_REG_Z = 0x36; /* Address of the Z Axis data register */ - - private const byte ACCEL_I2C_ADDR = 0x53; /* 7-bit I2C address of the ADXL345 with SDO pulled low */ - - private const byte SPI_CHIP_SELECT_LINE = 0; /* Chip select line to use */ - private const byte ACCEL_SPI_RW_BIT = 0x80; /* Bit used in SPI transactions to indicate read/write */ - private const byte ACCEL_SPI_MB_BIT = 0x40; /* Bit used to indicate multi-byte SPI transactions */ - - private I2cDevice I2CAccel; - private SpiDevice SPIAccel; - private Timer periodicTimer; - - public MainPage() - { - this.InitializeComponent(); - - /* Register for the unloaded event so we can clean up upon exit */ - Unloaded += MainPage_Unloaded; - - /* Initialize the I2C bus, accelerometer, and timer */ - InitAccel(); - } - - private void InitAccel() - { - /* Initialize the protocol and accelerometer */ - switch (HW_PROTOCOL) - { - case Protocol.SPI: - InitSPIAccel(); - break; - case Protocol.I2C: - InitI2CAccel(); - break; - case Protocol.NONE: - Text_Status.Text = "Please change the HW_PROTOCOL variable to either I2C or SPI"; - break; - default: - break; - } - } - - /* Initialization for I2C accelerometer */ - private async void InitI2CAccel() - { - var settings = new I2cConnectionSettings(ACCEL_I2C_ADDR); - settings.BusSpeed = I2cBusSpeed.FastMode; /* 400KHz bus speed */ - - var controller = await Windows.Devices.I2c.I2cController.GetDefaultAsync(); - I2CAccel = controller.GetDevice(settings); /* Create an I2cDevice with our selected bus controller and I2C settings */ - - /* - * Initialize the accelerometer: - * - * For this device, we create 2-byte write buffers: - * The first byte is the register address we want to write to. - * The second byte is the contents that we want to write to the register. - */ - byte[] WriteBuf_DataFormat = new byte[] { ACCEL_REG_DATA_FORMAT, 0x01 }; /* 0x01 sets range to +- 4Gs */ - byte[] WriteBuf_PowerControl = new byte[] { ACCEL_REG_POWER_CONTROL, 0x08 }; /* 0x08 puts the accelerometer into measurement mode */ - - /* Write the register settings */ - try - { - I2CAccel.Write(WriteBuf_DataFormat); - I2CAccel.Write(WriteBuf_PowerControl); - } - /* If the write fails display the error and stop running */ - catch (Exception ex) - { - Text_Status.Text = "Failed to communicate with device: " + ex.Message; - return; - } - - /* Now that everything is initialized, create a timer so we read data every 100mS */ - periodicTimer = new Timer(this.TimerCallback, null, 0, 100); - } - - /* Initialization for SPI accelerometer */ - private async void InitSPIAccel() - { - try { - var settings = new SpiConnectionSettings(SPI_CHIP_SELECT_LINE); - settings.ClockFrequency = 5000000; /* 5MHz is the rated speed of the ADXL345 accelerometer */ - settings.Mode = SpiMode.Mode3; /* The accelerometer expects an idle-high clock polarity, we use Mode3 - * to set the clock polarity and phase to: CPOL = 1, CPHA = 1 - */ - - string aqs = SpiDevice.GetDeviceSelector(); /* Get a selector string that will return all SPI controllers on the system */ - var dis = await DeviceInformation.FindAllAsync(aqs); /* Find the SPI bus controller devices with our selector string */ - SPIAccel = await SpiDevice.FromIdAsync(dis[0].Id, settings); /* Create an SpiDevice with our bus controller and SPI settings */ - if (SPIAccel == null) - { - Text_Status.Text = string.Format( - "SPI Controller {0} is currently in use by " + - "another application. Please ensure that no other applications are using SPI.", - dis[0].Id); - return; - } - } - catch (Exception ex) - { - Text_Status.Text = "SPI Initialization failed. Exception: " + ex.Message; - return; - } - - /* - * Initialize the accelerometer: - * - * For this device, we create 2-byte write buffers: - * The first byte is the register address we want to write to. - * The second byte is the contents that we want to write to the register. - */ - byte[] WriteBuf_DataFormat = new byte[] { ACCEL_REG_DATA_FORMAT, 0x01 }; /* 0x01 sets range to +- 4Gs */ - byte[] WriteBuf_PowerControl = new byte[] { ACCEL_REG_POWER_CONTROL, 0x08 }; /* 0x08 puts the accelerometer into measurement mode */ - - /* Write the register settings */ - try - { - SPIAccel.Write(WriteBuf_DataFormat); - SPIAccel.Write(WriteBuf_PowerControl); - } - /* If the write fails display the error and stop running */ - catch (Exception ex) - { - Text_Status.Text = "Failed to communicate with device: " + ex.Message; - return; - } - - /* Now that everything is initialized, create a timer so we read data every 100mS */ - periodicTimer = new Timer(this.TimerCallback, null, 0, 100); - } - - private void MainPage_Unloaded(object sender, object args) - { - /* Cleanup */ - switch (HW_PROTOCOL) - { - case Protocol.SPI: - SPIAccel.Dispose(); - break; - case Protocol.I2C: - I2CAccel.Dispose(); - break; - default: - break; - } - } - - private void TimerCallback(object state) - { - string xText, yText, zText; - string statusText; - - /* Read and format accelerometer data */ - try - { - Acceleration accel = ReadAccel(); - xText = String.Format("X Axis: {0:F3}G", accel.X); - yText = String.Format("Y Axis: {0:F3}G", accel.Y); - zText = String.Format("Z Axis: {0:F3}G", accel.Z); - statusText = "Status: Running"; - } - catch (Exception ex) - { - xText = "X Axis: Error"; - yText = "Y Axis: Error"; - zText = "Z Axis: Error"; - statusText = "Failed to read from Accelerometer: " + ex.Message; - } - - /* UI updates must be invoked on the UI thread */ - var task = this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => - { - Text_X_Axis.Text = xText; - Text_Y_Axis.Text = yText; - Text_Z_Axis.Text = zText; - Text_Status.Text = statusText; - }); - } - - private Acceleration ReadAccel() - { - const int ACCEL_RES = 1024; /* The ADXL345 has 10 bit resolution giving 1024 unique values */ - const int ACCEL_DYN_RANGE_G = 8; /* The ADXL345 had a total dynamic range of 8G, since we're configuring it to +-4G */ - const int UNITS_PER_G = ACCEL_RES / ACCEL_DYN_RANGE_G; /* Ratio of raw int values to G units */ - - byte[] ReadBuf; - byte[] RegAddrBuf; - - /* - * Read from the accelerometer - * We first write the address of the X-Axis register, then read all 3 axes into ReadBuf - */ - switch (HW_PROTOCOL) - { - case Protocol.SPI: - ReadBuf = new byte[6 + 1]; /* Read buffer of size 6 bytes (2 bytes * 3 axes) + 1 byte padding */ - RegAddrBuf = new byte[1 + 6]; /* Register address buffer of size 1 byte + 6 bytes padding */ - /* Register address we want to read from with read and multi-byte bit set */ - RegAddrBuf[0] = ACCEL_REG_X | ACCEL_SPI_RW_BIT | ACCEL_SPI_MB_BIT ; - SPIAccel.TransferFullDuplex(RegAddrBuf, ReadBuf); - Array.Copy(ReadBuf, 1, ReadBuf, 0, 6); /* Discard first dummy byte from read */ - break; - case Protocol.I2C: - ReadBuf = new byte[6]; /* We read 6 bytes sequentially to get all 3 two-byte axes */ - RegAddrBuf = new byte[] { ACCEL_REG_X }; /* Register address we want to read from */ - I2CAccel.WriteRead(RegAddrBuf, ReadBuf); - break; - default: /* Code should never get here */ - ReadBuf = new byte[6]; - break; - } - - /* Check the endianness of the system and flip the bytes if necessary */ - if (!BitConverter.IsLittleEndian) - { - Array.Reverse(ReadBuf, 0, 2); - Array.Reverse(ReadBuf, 2, 2); - Array.Reverse(ReadBuf, 4, 2); - } - - /* In order to get the raw 16-bit data values, we need to concatenate two 8-bit bytes for each axis */ - short AccelerationRawX = BitConverter.ToInt16(ReadBuf, 0); - short AccelerationRawY = BitConverter.ToInt16(ReadBuf, 2); - short AccelerationRawZ = BitConverter.ToInt16(ReadBuf, 4); - - /* Convert raw values to G's */ - Acceleration accel; - accel.X = (double)AccelerationRawX / UNITS_PER_G; - accel.Y = (double)AccelerationRawY / UNITS_PER_G; - accel.Z = (double)AccelerationRawZ / UNITS_PER_G; - - return accel; - } - } -} +// Copyright (c) Microsoft. All rights reserved. + +using System; +using System.Threading; +using Windows.UI.Xaml.Controls; +using Windows.Devices.Enumeration; +using Windows.Devices.I2c; +using Windows.Devices.Spi; + +namespace Accelerometer +{ + struct Acceleration + { + public double X; + public double Y; + public double Z; + }; + + enum Protocol { NONE, SPI, I2C}; + + /// + /// Sample app that reads data over either I2C or SPI from an attached ADXL345 accelerometer + /// + public sealed partial class MainPage : Page + { + /* Important! Change this to either Protocol.I2C or Protocol.SPI based on how your accelerometer is wired */ + private Protocol HW_PROTOCOL = Protocol.NONE; + + private const byte ACCEL_REG_POWER_CONTROL = 0x2D; /* Address of the Power Control register */ + private const byte ACCEL_REG_DATA_FORMAT = 0x31; /* Address of the Data Format register */ + private const byte ACCEL_REG_X = 0x32; /* Address of the X Axis data register */ + private const byte ACCEL_REG_Y = 0x34; /* Address of the Y Axis data register */ + private const byte ACCEL_REG_Z = 0x36; /* Address of the Z Axis data register */ + + private const byte ACCEL_I2C_ADDR = 0x53; /* 7-bit I2C address of the ADXL345 with SDO pulled low */ + + private const byte SPI_CHIP_SELECT_LINE = 0; /* Chip select line to use */ + private const byte ACCEL_SPI_RW_BIT = 0x80; /* Bit used in SPI transactions to indicate read/write */ + private const byte ACCEL_SPI_MB_BIT = 0x40; /* Bit used to indicate multi-byte SPI transactions */ + + private I2cDevice I2CAccel; + private SpiDevice SPIAccel; + private Timer periodicTimer; + + public MainPage() + { + this.InitializeComponent(); + + /* Register for the unloaded event so we can clean up upon exit */ + Unloaded += MainPage_Unloaded; + + /* Initialize the I2C bus, accelerometer, and timer */ + InitAccel(); + } + + private void InitAccel() + { + /* Initialize the protocol and accelerometer */ + switch (HW_PROTOCOL) + { + case Protocol.SPI: + InitSPIAccel(); + break; + case Protocol.I2C: + InitI2CAccel(); + break; + case Protocol.NONE: + Text_Status.Text = "Please change the HW_PROTOCOL variable to either I2C or SPI"; + break; + default: + break; + } + } + + /* Initialization for I2C accelerometer */ + private async void InitI2CAccel() + { + var settings = new I2cConnectionSettings(ACCEL_I2C_ADDR); + settings.BusSpeed = I2cBusSpeed.FastMode; /* 400KHz bus speed */ + + var controller = await Windows.Devices.I2c.I2cController.GetDefaultAsync(); + I2CAccel = controller.GetDevice(settings); /* Create an I2cDevice with our selected bus controller and I2C settings */ + + /* + * Initialize the accelerometer: + * + * For this device, we create 2-byte write buffers: + * The first byte is the register address we want to write to. + * The second byte is the contents that we want to write to the register. + */ + byte[] WriteBuf_DataFormat = new byte[] { ACCEL_REG_DATA_FORMAT, 0x01 }; /* 0x01 sets range to +- 4Gs */ + byte[] WriteBuf_PowerControl = new byte[] { ACCEL_REG_POWER_CONTROL, 0x08 }; /* 0x08 puts the accelerometer into measurement mode */ + + /* Write the register settings */ + try + { + I2CAccel.Write(WriteBuf_DataFormat); + I2CAccel.Write(WriteBuf_PowerControl); + } + /* If the write fails display the error and stop running */ + catch (Exception ex) + { + Text_Status.Text = "Failed to communicate with device: " + ex.Message; + return; + } + + /* Now that everything is initialized, create a timer so we read data every 100mS */ + periodicTimer = new Timer(this.TimerCallback, null, 0, 100); + } + + /* Initialization for SPI accelerometer */ + private async void InitSPIAccel() + { + try { + var settings = new SpiConnectionSettings(SPI_CHIP_SELECT_LINE); + settings.ClockFrequency = 5000000; /* 5MHz is the rated speed of the ADXL345 accelerometer */ + settings.Mode = SpiMode.Mode3; /* The accelerometer expects an idle-high clock polarity, we use Mode3 + * to set the clock polarity and phase to: CPOL = 1, CPHA = 1 + */ + + string aqs = SpiDevice.GetDeviceSelector(); /* Get a selector string that will return all SPI controllers on the system */ + var dis = await DeviceInformation.FindAllAsync(aqs); /* Find the SPI bus controller devices with our selector string */ + SPIAccel = await SpiDevice.FromIdAsync(dis[0].Id, settings); /* Create an SpiDevice with our bus controller and SPI settings */ + if (SPIAccel == null) + { + Text_Status.Text = string.Format( + "SPI Controller {0} is currently in use by " + + "another application. Please ensure that no other applications are using SPI.", + dis[0].Id); + return; + } + } + catch (Exception ex) + { + Text_Status.Text = "SPI Initialization failed. Exception: " + ex.Message; + return; + } + + /* + * Initialize the accelerometer: + * + * For this device, we create 2-byte write buffers: + * The first byte is the register address we want to write to. + * The second byte is the contents that we want to write to the register. + */ + byte[] WriteBuf_DataFormat = new byte[] { ACCEL_REG_DATA_FORMAT, 0x01 }; /* 0x01 sets range to +- 4Gs */ + byte[] WriteBuf_PowerControl = new byte[] { ACCEL_REG_POWER_CONTROL, 0x08 }; /* 0x08 puts the accelerometer into measurement mode */ + + /* Write the register settings */ + try + { + SPIAccel.Write(WriteBuf_DataFormat); + SPIAccel.Write(WriteBuf_PowerControl); + } + /* If the write fails display the error and stop running */ + catch (Exception ex) + { + Text_Status.Text = "Failed to communicate with device: " + ex.Message; + return; + } + + /* Now that everything is initialized, create a timer so we read data every 100mS */ + periodicTimer = new Timer(this.TimerCallback, null, 0, 100); + } + + private void MainPage_Unloaded(object sender, object args) + { + /* Cleanup */ + switch (HW_PROTOCOL) + { + case Protocol.SPI: + SPIAccel.Dispose(); + break; + case Protocol.I2C: + I2CAccel.Dispose(); + break; + default: + break; + } + } + + private void TimerCallback(object state) + { + string xText, yText, zText; + string statusText; + + /* Read and format accelerometer data */ + try + { + Acceleration accel = ReadAccel(); + xText = String.Format("X Axis: {0:F3}G", accel.X); + yText = String.Format("Y Axis: {0:F3}G", accel.Y); + zText = String.Format("Z Axis: {0:F3}G", accel.Z); + statusText = "Status: Running"; + } + catch (Exception ex) + { + xText = "X Axis: Error"; + yText = "Y Axis: Error"; + zText = "Z Axis: Error"; + statusText = "Failed to read from Accelerometer: " + ex.Message; + } + + /* UI updates must be invoked on the UI thread */ + var task = this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => + { + Text_X_Axis.Text = xText; + Text_Y_Axis.Text = yText; + Text_Z_Axis.Text = zText; + Text_Status.Text = statusText; + }); + } + + private Acceleration ReadAccel() + { + const int ACCEL_RES = 1024; /* The ADXL345 has 10 bit resolution giving 1024 unique values */ + const int ACCEL_DYN_RANGE_G = 8; /* The ADXL345 had a total dynamic range of 8G, since we're configuring it to +-4G */ + const int UNITS_PER_G = ACCEL_RES / ACCEL_DYN_RANGE_G; /* Ratio of raw int values to G units */ + + byte[] ReadBuf; + byte[] RegAddrBuf; + + /* + * Read from the accelerometer + * We first write the address of the X-Axis register, then read all 3 axes into ReadBuf + */ + switch (HW_PROTOCOL) + { + case Protocol.SPI: + ReadBuf = new byte[6 + 1]; /* Read buffer of size 6 bytes (2 bytes * 3 axes) + 1 byte padding */ + RegAddrBuf = new byte[1 + 6]; /* Register address buffer of size 1 byte + 6 bytes padding */ + /* Register address we want to read from with read and multi-byte bit set */ + RegAddrBuf[0] = ACCEL_REG_X | ACCEL_SPI_RW_BIT | ACCEL_SPI_MB_BIT ; + SPIAccel.TransferFullDuplex(RegAddrBuf, ReadBuf); + Array.Copy(ReadBuf, 1, ReadBuf, 0, 6); /* Discard first dummy byte from read */ + break; + case Protocol.I2C: + ReadBuf = new byte[6]; /* We read 6 bytes sequentially to get all 3 two-byte axes */ + RegAddrBuf = new byte[] { ACCEL_REG_X }; /* Register address we want to read from */ + I2CAccel.WriteRead(RegAddrBuf, ReadBuf); + break; + default: /* Code should never get here */ + ReadBuf = new byte[6]; + break; + } + + /* Check the endianness of the system and flip the bytes if necessary */ + if (!BitConverter.IsLittleEndian) + { + Array.Reverse(ReadBuf, 0, 2); + Array.Reverse(ReadBuf, 2, 2); + Array.Reverse(ReadBuf, 4, 2); + } + + /* In order to get the raw 16-bit data values, we need to concatenate two 8-bit bytes for each axis */ + short AccelerationRawX = BitConverter.ToInt16(ReadBuf, 0); + short AccelerationRawY = BitConverter.ToInt16(ReadBuf, 2); + short AccelerationRawZ = BitConverter.ToInt16(ReadBuf, 4); + + /* Convert raw values to G's */ + Acceleration accel; + accel.X = (double)AccelerationRawX / UNITS_PER_G; + accel.Y = (double)AccelerationRawY / UNITS_PER_G; + accel.Z = (double)AccelerationRawZ / UNITS_PER_G; + + return accel; + } + } +} diff --git a/samples/Accelerometer/CS/Package.appxmanifest b/samples/Accelerometer/CS/Package.appxmanifest index 8bdab3091..2a375e7b0 100644 --- a/samples/Accelerometer/CS/Package.appxmanifest +++ b/samples/Accelerometer/CS/Package.appxmanifest @@ -1,50 +1,50 @@ - - - - - - - - - - Accelerometer - MSFT - Assets\StoreLogo.png - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + Accelerometer + MSFT + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/Accelerometer/CS/Properties/AssemblyInfo.cs b/samples/Accelerometer/CS/Properties/AssemblyInfo.cs index 1c2232752..9fb2efbda 100644 --- a/samples/Accelerometer/CS/Properties/AssemblyInfo.cs +++ b/samples/Accelerometer/CS/Properties/AssemblyInfo.cs @@ -1,29 +1,29 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Accelerometer")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Accelerometer")] -[assembly: AssemblyCopyright("Copyright © 2015")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Accelerometer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Accelerometer")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] [assembly: ComVisible(false)] \ No newline at end of file diff --git a/samples/Accelerometer/CS/Properties/Default.rd.xml b/samples/Accelerometer/CS/Properties/Default.rd.xml index 461bc4c13..80a960ce3 100644 --- a/samples/Accelerometer/CS/Properties/Default.rd.xml +++ b/samples/Accelerometer/CS/Properties/Default.rd.xml @@ -1,31 +1,31 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Accelerometer/CS/README.md b/samples/Accelerometer/CS/README.md index 327742d21..bd256ef2a 100644 --- a/samples/Accelerometer/CS/README.md +++ b/samples/Accelerometer/CS/README.md @@ -1,286 +1,286 @@ ---- -page_type: sample -urlFragment: accelerometer -languages: - - csharp -products: - - Windows 10 - - Windows IoT - - Windows 10 IoT Enterprise -description: Create a simple app with an SPI accelerometer build with Windows 10 IoT Enterprise. ---- - -# SPI Accelerometer - -We'll connect an SPI accelerometer to your UP Board and create a simple app to read data from it. -We'll walk you through step-by-step, so no background knowledge of SPI is needed. However, if you're curious, SparkFun provides a great [tutorial on SPI](https://learn.sparkfun.com/tutorials/serial-peripheral-interface-spi). - -### Load the project in Visual Studio - -You can find the source code for this sample by downloading a zip of all of our samples. Make a copy of the folder on your disk and open the project from Visual Studio 2019. - -### Connect the SPI Accelerometer to your device - -You'll need a few components: - -* an [ADXL345 accelerometer board from Sparkfun](https://www.sparkfun.com/products/9836) with pin headers soldered on - -* a breadboard and a couple of male-to-female connector wires - -![Electrical Components](../../../Resources/components1.png) - -#### UP Board -If you have UP Board, we need to hook up power, ground, and the SPI lines to the accelerometer. - See the [UP Board pin mapping page](../../../Resources/PinMappingsUpBoard.png) for more details on the UP Board IO pins. - -**Note: Make sure to power off the UP Board when connecting your circuit. This is good practice to reduce the chance of an accidental short circuit during construction.** - -The ADXL345 breakout board has 8 IO pins, connect them as follows: - -1. **GND:** Connect to ground on the UP Board (Pin 6) -2. **VCC:** Connect to 3.3V on the UP Board (Pin 1) -3. **CS:** Connect to SPI0 CS0 on the UP Board (Pin 24). This is the chip-select line for the SPI bus. -4. **INT1:** Leave unconnected, we're not using this pin -5. **INT2:** Leave unconnected, we're not using this pin -6. **SDO:** Connect to SPI0 MISO on the UP Board (Pin 21) -7. **SDA:** Connect to SPI0 MOSI on the UP Board (Pin 19) -8. **SCL:** Connect to SPI0 SCLK on the UP Board (Pin 23). This is the clock line for the SPI bus. - -Here are the connections shown on a breadboard: - -![Breadboard connections](../../../Resources/breadboard_assembled_upboard1.png) - -Here are the schematics: - -![Accelerometer schematics](../../../Resources/schematics_upboard.png) - -### Deploy the app - - Click the Start button to search for the app by name, and then launch it. - -When everything is set up, power your device back on, and open up the sample app in Visual Studio. Open the file **MainPage.xaml.cs** and change the following line from **Protocol.NONE** to **Protocol.SPI**: - -```csharp -public sealed partial class MainPage : Page -{ - /* Important! Change this to either Protocol.I2C or Protocol.SPI based on how your accelerometer is wired */ - private Protocol HW_PROTOCOL = Protocol.SPI; - // ... -} -``` - -### [Generate an app package](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#generate-an-app-package) - -### [Install your app package using an install script](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#install-your-app-package-using-an-install-script) - -### BIOS Settings for UP Board -If you are using UP Board, you have to setup the BIOS SPI configuration. - -1. Once you power on the UP board, select the **Del** or **F7** key on your keyboard to enter the BIOS setting. - -1. Navigate to **Boot** > **OS Image ID** tab, and select **Windows 10 IoT Core**. - -1. Navigate to the **Advance** tab and select the **Hat Configuration** and select "LPSS SPISupport" as "Enabled". - -1. For more information, please review the [UP Board Firmware Settings](https://www.annabooks.com/Articles/Articles_IoT10/Windows-10-IoT-UP-Board-BIOS-RHPROXY-Rev1.3.pdf). - -### Run the app -The SPIAccelerometer app will deploy and start, and you should see accelerometer data show up on screen. -If you have your accelerometer flat on a surface, the Z axis should read close to 1.000G, while X and Y are close to 0.000G. The values will fluctuate a little even if the device is standing still. -This is normal and is due to minute vibrations and electrical noise. If you tilt or shake the sensor, you should see the values change in response. Note that this sample configures the device in 4G mode, so you wont be able to see G readings higher than 4Gs. - -![SPI Accelerometer running](../../../Resources/spiaccelerometer_screenshot.png) - -Congratulations! You've connected an SPI accelerometer. - -### Let's look at the code -The code in this sample performs two main tasks: - -1. First the code initializes the SPI bus and the accelerometer - -2. Secondly, we read from the accelerometer at defined intervals and update the display - -Let's start by digging into the initializations. - -### Initialize the SPI bus -To use the accelerometer, we need to initialize the SPI bus first. Here is the C# code. - -```csharp -using Windows.Devices.Enumeration; -using Windows.Devices.Spi; - -/* Initialization for SPI accelerometer */ -private async void InitSPIAccel() -{ - try { - var settings = new SpiConnectionSettings(SPI_CHIP_SELECT_LINE); - settings.ClockFrequency = 5000000; /* 5MHz is the rated speed of the ADXL345 accelerometer */ - settings.Mode = SpiMode.Mode3; /* The accelerometer expects an idle-high clock polarity, we use Mode3 - * to set the clock polarity and phase to: CPOL = 1, CPHA = 1 - */ - - string aqs = SpiDevice.GetDeviceSelector(); /* Get a selector string that will return all SPI controllers on the system */ - var dis = await DeviceInformation.FindAllAsync(aqs); /* Find the SPI bus controller devices with our selector string */ - SPIAccel = await SpiDevice.FromIdAsync(dis[0].Id, settings); /* Create an SpiDevice with our bus controller and SPI settings */ - if (SPIAccel == null) - { - Text_Status.Text = string.Format( - "SPI Controller {0} is currently in use by " + - "another application. Please ensure that no other applications are using SPI.", - dis[0].Id); - return; - } - } - - // ... -} -``` - -Here's an overview of what's happening: - -* First, we create an **SpiConnectionSettings** object and set the clock speed, clock polarity, and chip-select line. - -* Next, we get the selector strings for all SPI controllers on the device, and use that find all the SPI bus controllers on the system. - -* Finally, we create a new **SpiDevice** from the first SPI controller on the system (**dis[0]**) and check that it's available for use. - -### Initialize the accelerometer - -Now that we have the **SpiDevice** accelerometer instance, we're done with the SPI bus initialization. We can now write data over SPI to start up the accelerometer. We do this with the **Write()** function. -For this particular accelerometer, there are two internal registers we need to configure before we can start using the device: The data format register, and the power control register. - -1. We first write a 0x01 to the data format register. This configures the device range into +-4G mode. If you consult the [datasheet](https://www.sparkfun.com/datasheets/Sensors/Accelerometer/ADXL345.pdf){:target="_blank"}, you'll see that the device can be configured in a variety of measurement modes ranging from 2G to 16G. -Higher G settings provide you with greater range at the expense of reduced resolution. We choose 4G as a reasonable trade off between the two. - -2. We write a 0x08 to the power control register, which wakes the device from standby and starts measuring acceleration. Again, the [datasheet](https://www.sparkfun.com/datasheets/Sensors/Accelerometer/ADXL345.pdf){:target="_blank"} contains additional information about the device settings and capabilities. - -```csharp -private async void InitSPIAccel() -{ - // ... - - /* - * Initialize the accelerometer: - * - * For this device, we create 2-byte write buffers: - * The first byte is the register address we want to write to. - * The second byte is the contents that we want to write to the register. - */ - byte[] WriteBuf_DataFormat = new byte[] { ACCEL_REG_DATA_FORMAT, 0x01 }; /* 0x01 sets range to +- 4Gs */ - byte[] WriteBuf_PowerControl = new byte[] { ACCEL_REG_POWER_CONTROL, 0x08 }; /* 0x08 puts the accelerometer into measurement mode */ - - /* Write the register settings */ - try - { - SPIAccel.Write(WriteBuf_DataFormat); - SPIAccel.Write(WriteBuf_PowerControl); - } - /* If the write fails display the error and stop running */ - catch (Exception ex) - { - Text_Status.Text = "Failed to communicate with device: " + ex.Message; - return; - } - - // ... -} -``` - -### Timer code -After all the initializations are complete, we start a timer to read from the accelerometer periodically. Here is how you set up the timer to trigger every 100mS. -```csharp -private async void InitSPIAccel() -{ - // ... - - /* Now that everything is initialized, create a timer so we read data every 100mS */ - periodicTimer = new Timer(this.TimerCallback, null, 0, 100); - - // ... -} - -private void TimerCallback(object state) -{ - string xText, yText, zText; - string statusText; - - /* Read and format accelerometer data */ - try - { - Acceleration accel = ReadAccel(); - xText = String.Format("X Axis: {0:F3}G", accel.X); - yText = String.Format("Y Axis: {0:F3}G", accel.Y); - zText = String.Format("Z Axis: {0:F3}G", accel.Z); - statusText = "Status: Running"; - } - - // ... -} -``` - -### Read data from the accelerometer -With the SPI bus and accelerometer initialized, we can start reading data from the accelerometer. Our **ReadAccel()** function gets called every 100mS by the timer: - -```csharp -private Acceleration ReadAccel() -{ - const int ACCEL_RES = 1024; /* The ADXL345 has 10 bit resolution giving 1024 unique values */ - const int ACCEL_DYN_RANGE_G = 8; /* The ADXL345 had a total dynamic range of 8G, since we're configuring it to +-4G */ - const int UNITS_PER_G = ACCEL_RES / ACCEL_DYN_RANGE_G; /* Ratio of raw int values to G units */ - - byte[] ReadBuf; - byte[] RegAddrBuf; - - /* - * Read from the accelerometer - * We first write the address of the X-Axis register, then read all 3 axes into ReadBuf - */ - switch (HW_PROTOCOL) - { - case Protocol.SPI: - ReadBuf = new byte[6 + 1]; /* Read buffer of size 6 bytes (2 bytes * 3 axes) + 1 byte padding */ - RegAddrBuf = new byte[1 + 6]; /* Register address buffer of size 1 byte + 6 bytes padding */ - /* Register address we want to read from with read and multi-byte bit set */ - RegAddrBuf[0] = ACCEL_REG_X | ACCEL_SPI_RW_BIT | ACCEL_SPI_MB_BIT ; - SPIAccel.TransferFullDuplex(RegAddrBuf, ReadBuf); - Array.Copy(ReadBuf, 1, ReadBuf, 0, 6); /* Discard first dummy byte from read */ - break; - case Protocol.I2C: - // ... - default: /* Code should never get here */ - // ... - } - - // ... - - /* In order to get the raw 16-bit data values, we need to concatenate two 8-bit bytes for each axis */ - short AccelerationRawX = BitConverter.ToInt16(ReadBuf, 0); - short AccelerationRawY = BitConverter.ToInt16(ReadBuf, 2); - short AccelerationRawZ = BitConverter.ToInt16(ReadBuf, 4); - - /* Convert raw values to G's */ - Acceleration accel; - accel.X = (double)AccelerationRawX / UNITS_PER_G; - accel.Y = (double)AccelerationRawY / UNITS_PER_G; - accel.Z = (double)AccelerationRawZ / UNITS_PER_G; - - return accel; -} -``` -Here's how this works: - -* We begin by reading data from the accelerometer with the **TransferFullDuplex()** function. This function performs a SPI write and SPI read simultaneously in the same transaction. - -* The initial write specifies the register address we want to read from (which in this case is the X-Axis data register). This write ensures that a subsequent read will start from this register address. -We provide the function with a one-byte byte array representing the register address we want to write (plus padding bytes). We also set the read and multi-byte bits so that the accelerometer knows we're reading multiple bytes. - -* Next we provide the function with a read buffer of size 6 so we read 6 bytes over SPI (plus padding bytes). Since this device supports multi-byte reads, -**and** the X, Y, and Z data registers are next to each other, reading 6 bytes give us all of our data in one go. This ensures acceleration values don't change between reads as well. - -* We get back 6 bytes of data from our read. These represent the data in the X, Y, and Z data registers respectively. -We separate out the data into their respective axes and concatenate the bytes using **BitConverter.ToInt16()**. - -* The raw data is formatted as a 16-bit integer, which contains 10-bit data from the accelerometer. It can take on values ranging from -512 to 511. A reading of -512 corresponds to -4G while 511 is +4G. - To convert this to G units, we divide by the ratio of full-scale range (8G) to the resolution (1024) - -* Now that we have the G unit values, we can display the data on screen. This process is repeated every 100mS so the information is constantly updated. +--- +page_type: sample +urlFragment: accelerometer +languages: + - csharp +products: + - Windows 10 + - Windows IoT + - Windows 10 IoT Enterprise +description: Create a simple app with an SPI accelerometer build with Windows 10 IoT Enterprise. +--- + +# SPI Accelerometer + +We'll connect an SPI accelerometer to your UP Board and create a simple app to read data from it. +We'll walk you through step-by-step, so no background knowledge of SPI is needed. However, if you're curious, SparkFun provides a great [tutorial on SPI](https://learn.sparkfun.com/tutorials/serial-peripheral-interface-spi). + +### Load the project in Visual Studio + +You can find the source code for this sample by downloading a zip of all of our samples. Make a copy of the folder on your disk and open the project from Visual Studio 2019. + +### Connect the SPI Accelerometer to your device + +You'll need a few components: + +* an [ADXL345 accelerometer board from Sparkfun](https://www.sparkfun.com/products/9836) with pin headers soldered on + +* a breadboard and a couple of male-to-female connector wires + +![Electrical Components](../../../Resources/components1.png) + +#### UP Board +If you have UP Board, we need to hook up power, ground, and the SPI lines to the accelerometer. + See the [UP Board pin mapping page](../../../Resources/PinMappingsUpBoard.png) for more details on the UP Board IO pins. + +**Note: Make sure to power off the UP Board when connecting your circuit. This is good practice to reduce the chance of an accidental short circuit during construction.** + +The ADXL345 breakout board has 8 IO pins, connect them as follows: + +1. **GND:** Connect to ground on the UP Board (Pin 6) +2. **VCC:** Connect to 3.3V on the UP Board (Pin 1) +3. **CS:** Connect to SPI0 CS0 on the UP Board (Pin 24). This is the chip-select line for the SPI bus. +4. **INT1:** Leave unconnected, we're not using this pin +5. **INT2:** Leave unconnected, we're not using this pin +6. **SDO:** Connect to SPI0 MISO on the UP Board (Pin 21) +7. **SDA:** Connect to SPI0 MOSI on the UP Board (Pin 19) +8. **SCL:** Connect to SPI0 SCLK on the UP Board (Pin 23). This is the clock line for the SPI bus. + +Here are the connections shown on a breadboard: + +![Breadboard connections](../../../Resources/breadboard_assembled_upboard1.png) + +Here are the schematics: + +![Accelerometer schematics](../../../Resources/schematics_upboard.png) + +### Deploy the app + + Click the Start button to search for the app by name, and then launch it. + +When everything is set up, power your device back on, and open up the sample app in Visual Studio. Open the file **MainPage.xaml.cs** and change the following line from **Protocol.NONE** to **Protocol.SPI**: + +```csharp +public sealed partial class MainPage : Page +{ + /* Important! Change this to either Protocol.I2C or Protocol.SPI based on how your accelerometer is wired */ + private Protocol HW_PROTOCOL = Protocol.SPI; + // ... +} +``` + +### [Generate an app package](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#generate-an-app-package) + +### [Install your app package using an install script](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#install-your-app-package-using-an-install-script) + +### BIOS Settings for UP Board +If you are using UP Board, you have to setup the BIOS SPI configuration. + +1. Once you power on the UP board, select the **Del** or **F7** key on your keyboard to enter the BIOS setting. + +1. Navigate to **Boot** > **OS Image ID** tab, and select **Windows 10 IoT Core**. + +1. Navigate to the **Advance** tab and select the **Hat Configuration** and select "LPSS SPISupport" as "Enabled". + +1. For more information, please review the [UP Board Firmware Settings](https://www.annabooks.com/Articles/Articles_IoT10/Windows-10-IoT-UP-Board-BIOS-RHPROXY-Rev1.3.pdf). + +### Run the app +The SPIAccelerometer app will deploy and start, and you should see accelerometer data show up on screen. +If you have your accelerometer flat on a surface, the Z axis should read close to 1.000G, while X and Y are close to 0.000G. The values will fluctuate a little even if the device is standing still. +This is normal and is due to minute vibrations and electrical noise. If you tilt or shake the sensor, you should see the values change in response. Note that this sample configures the device in 4G mode, so you wont be able to see G readings higher than 4Gs. + +![SPI Accelerometer running](../../../Resources/spiaccelerometer_screenshot.png) + +Congratulations! You've connected an SPI accelerometer. + +### Let's look at the code +The code in this sample performs two main tasks: + +1. First the code initializes the SPI bus and the accelerometer + +2. Secondly, we read from the accelerometer at defined intervals and update the display + +Let's start by digging into the initializations. + +### Initialize the SPI bus +To use the accelerometer, we need to initialize the SPI bus first. Here is the C# code. + +```csharp +using Windows.Devices.Enumeration; +using Windows.Devices.Spi; + +/* Initialization for SPI accelerometer */ +private async void InitSPIAccel() +{ + try { + var settings = new SpiConnectionSettings(SPI_CHIP_SELECT_LINE); + settings.ClockFrequency = 5000000; /* 5MHz is the rated speed of the ADXL345 accelerometer */ + settings.Mode = SpiMode.Mode3; /* The accelerometer expects an idle-high clock polarity, we use Mode3 + * to set the clock polarity and phase to: CPOL = 1, CPHA = 1 + */ + + string aqs = SpiDevice.GetDeviceSelector(); /* Get a selector string that will return all SPI controllers on the system */ + var dis = await DeviceInformation.FindAllAsync(aqs); /* Find the SPI bus controller devices with our selector string */ + SPIAccel = await SpiDevice.FromIdAsync(dis[0].Id, settings); /* Create an SpiDevice with our bus controller and SPI settings */ + if (SPIAccel == null) + { + Text_Status.Text = string.Format( + "SPI Controller {0} is currently in use by " + + "another application. Please ensure that no other applications are using SPI.", + dis[0].Id); + return; + } + } + + // ... +} +``` + +Here's an overview of what's happening: + +* First, we create an **SpiConnectionSettings** object and set the clock speed, clock polarity, and chip-select line. + +* Next, we get the selector strings for all SPI controllers on the device, and use that find all the SPI bus controllers on the system. + +* Finally, we create a new **SpiDevice** from the first SPI controller on the system (**dis[0]**) and check that it's available for use. + +### Initialize the accelerometer + +Now that we have the **SpiDevice** accelerometer instance, we're done with the SPI bus initialization. We can now write data over SPI to start up the accelerometer. We do this with the **Write()** function. +For this particular accelerometer, there are two internal registers we need to configure before we can start using the device: The data format register, and the power control register. + +1. We first write a 0x01 to the data format register. This configures the device range into +-4G mode. If you consult the [datasheet](https://www.sparkfun.com/datasheets/Sensors/Accelerometer/ADXL345.pdf){:target="_blank"}, you'll see that the device can be configured in a variety of measurement modes ranging from 2G to 16G. +Higher G settings provide you with greater range at the expense of reduced resolution. We choose 4G as a reasonable trade off between the two. + +2. We write a 0x08 to the power control register, which wakes the device from standby and starts measuring acceleration. Again, the [datasheet](https://www.sparkfun.com/datasheets/Sensors/Accelerometer/ADXL345.pdf){:target="_blank"} contains additional information about the device settings and capabilities. + +```csharp +private async void InitSPIAccel() +{ + // ... + + /* + * Initialize the accelerometer: + * + * For this device, we create 2-byte write buffers: + * The first byte is the register address we want to write to. + * The second byte is the contents that we want to write to the register. + */ + byte[] WriteBuf_DataFormat = new byte[] { ACCEL_REG_DATA_FORMAT, 0x01 }; /* 0x01 sets range to +- 4Gs */ + byte[] WriteBuf_PowerControl = new byte[] { ACCEL_REG_POWER_CONTROL, 0x08 }; /* 0x08 puts the accelerometer into measurement mode */ + + /* Write the register settings */ + try + { + SPIAccel.Write(WriteBuf_DataFormat); + SPIAccel.Write(WriteBuf_PowerControl); + } + /* If the write fails display the error and stop running */ + catch (Exception ex) + { + Text_Status.Text = "Failed to communicate with device: " + ex.Message; + return; + } + + // ... +} +``` + +### Timer code +After all the initializations are complete, we start a timer to read from the accelerometer periodically. Here is how you set up the timer to trigger every 100mS. +```csharp +private async void InitSPIAccel() +{ + // ... + + /* Now that everything is initialized, create a timer so we read data every 100mS */ + periodicTimer = new Timer(this.TimerCallback, null, 0, 100); + + // ... +} + +private void TimerCallback(object state) +{ + string xText, yText, zText; + string statusText; + + /* Read and format accelerometer data */ + try + { + Acceleration accel = ReadAccel(); + xText = String.Format("X Axis: {0:F3}G", accel.X); + yText = String.Format("Y Axis: {0:F3}G", accel.Y); + zText = String.Format("Z Axis: {0:F3}G", accel.Z); + statusText = "Status: Running"; + } + + // ... +} +``` + +### Read data from the accelerometer +With the SPI bus and accelerometer initialized, we can start reading data from the accelerometer. Our **ReadAccel()** function gets called every 100mS by the timer: + +```csharp +private Acceleration ReadAccel() +{ + const int ACCEL_RES = 1024; /* The ADXL345 has 10 bit resolution giving 1024 unique values */ + const int ACCEL_DYN_RANGE_G = 8; /* The ADXL345 had a total dynamic range of 8G, since we're configuring it to +-4G */ + const int UNITS_PER_G = ACCEL_RES / ACCEL_DYN_RANGE_G; /* Ratio of raw int values to G units */ + + byte[] ReadBuf; + byte[] RegAddrBuf; + + /* + * Read from the accelerometer + * We first write the address of the X-Axis register, then read all 3 axes into ReadBuf + */ + switch (HW_PROTOCOL) + { + case Protocol.SPI: + ReadBuf = new byte[6 + 1]; /* Read buffer of size 6 bytes (2 bytes * 3 axes) + 1 byte padding */ + RegAddrBuf = new byte[1 + 6]; /* Register address buffer of size 1 byte + 6 bytes padding */ + /* Register address we want to read from with read and multi-byte bit set */ + RegAddrBuf[0] = ACCEL_REG_X | ACCEL_SPI_RW_BIT | ACCEL_SPI_MB_BIT ; + SPIAccel.TransferFullDuplex(RegAddrBuf, ReadBuf); + Array.Copy(ReadBuf, 1, ReadBuf, 0, 6); /* Discard first dummy byte from read */ + break; + case Protocol.I2C: + // ... + default: /* Code should never get here */ + // ... + } + + // ... + + /* In order to get the raw 16-bit data values, we need to concatenate two 8-bit bytes for each axis */ + short AccelerationRawX = BitConverter.ToInt16(ReadBuf, 0); + short AccelerationRawY = BitConverter.ToInt16(ReadBuf, 2); + short AccelerationRawZ = BitConverter.ToInt16(ReadBuf, 4); + + /* Convert raw values to G's */ + Acceleration accel; + accel.X = (double)AccelerationRawX / UNITS_PER_G; + accel.Y = (double)AccelerationRawY / UNITS_PER_G; + accel.Z = (double)AccelerationRawZ / UNITS_PER_G; + + return accel; +} +``` +Here's how this works: + +* We begin by reading data from the accelerometer with the **TransferFullDuplex()** function. This function performs a SPI write and SPI read simultaneously in the same transaction. + +* The initial write specifies the register address we want to read from (which in this case is the X-Axis data register). This write ensures that a subsequent read will start from this register address. +We provide the function with a one-byte byte array representing the register address we want to write (plus padding bytes). We also set the read and multi-byte bits so that the accelerometer knows we're reading multiple bytes. + +* Next we provide the function with a read buffer of size 6 so we read 6 bytes over SPI (plus padding bytes). Since this device supports multi-byte reads, +**and** the X, Y, and Z data registers are next to each other, reading 6 bytes give us all of our data in one go. This ensures acceleration values don't change between reads as well. + +* We get back 6 bytes of data from our read. These represent the data in the X, Y, and Z data registers respectively. +We separate out the data into their respective axes and concatenate the bytes using **BitConverter.ToInt16()**. + +* The raw data is formatted as a 16-bit integer, which contains 10-bit data from the accelerometer. It can take on values ranging from -512 to 511. A reading of -512 corresponds to -4G while 511 is +4G. + To convert this to G units, we divide by the ratio of full-scale range (8G) to the resolution (1024) + +* Now that we have the G unit values, we can display the data on screen. This process is repeated every 100mS so the information is constantly updated. diff --git a/samples/Accelerometer/README.md b/samples/Accelerometer/README.md index b30db3597..e8cc1e068 100644 --- a/samples/Accelerometer/README.md +++ b/samples/Accelerometer/README.md @@ -1,286 +1,286 @@ ---- -page_type: sample -urlFragment: accelerometer -languages: - - csharp -products: - - Windows 10 - - Windows IoT - - Windows 10 IoT Enterprise -description: Create a simple app with an SPI accelerometer build with Windows 10 IoT Enterprise. ---- - -# SPI Accelerometer - -We'll connect an SPI accelerometer to your UP Board and create a simple app to read data from it. -We'll walk you through step-by-step, so no background knowledge of SPI is needed. However, if you're curious, SparkFun provides a great [tutorial on SPI](https://learn.sparkfun.com/tutorials/serial-peripheral-interface-spi). - -### Load the project in Visual Studio - -You can find the source code for this sample by downloading a zip of all of our samples. Make a copy of the folder on your disk and open the project from Visual Studio 2019. - -### Connect the SPI Accelerometer to your device - -You'll need a few components: - -* an [ADXL345 accelerometer board from Sparkfun](https://www.sparkfun.com/products/9836) with pin headers soldered on - -* a breadboard and a couple of male-to-female connector wires - -![Electrical Components](../../Resources/components1.png) - -#### UP Board -If you have UP Board, we need to hook up power, ground, and the SPI lines to the accelerometer. - See the [UP Board pin mapping page](../../Resources/PinMappingsUpBoard.png) for more details on the UP Board IO pins. - -**Note: Make sure to power off the UP Board when connecting your circuit. This is good practice to reduce the chance of an accidental short circuit during construction.** - -The ADXL345 breakout board has 8 IO pins, connect them as follows: - -1. **GND:** Connect to ground on the UP Board (Pin 6) -2. **VCC:** Connect to 3.3V on the UP Board (Pin 1) -3. **CS:** Connect to SPI0 CS0 on the UP Board (Pin 24). This is the chip-select line for the SPI bus. -4. **INT1:** Leave unconnected, we're not using this pin -5. **INT2:** Leave unconnected, we're not using this pin -6. **SDO:** Connect to SPI0 MISO on the UP Board (Pin 21) -7. **SDA:** Connect to SPI0 MOSI on the UP Board (Pin 19) -8. **SCL:** Connect to SPI0 SCLK on the UP Board (Pin 23). This is the clock line for the SPI bus. - -Here are the connections shown on a breadboard: - -![Breadboard connections](../../Resources/breadboard_assembled_upboard1.png) - -Here are the schematics: - -![Accelerometer schematics](../../Resources/schematics_upboard.png) - -### Deploy the app - - Click the Start button to search for the app by name, and then launch it. - -When everything is set up, power your device back on, and open up the sample app in Visual Studio. Open the file **MainPage.xaml.cs** and change the following line from **Protocol.NONE** to **Protocol.SPI**: - -```csharp -public sealed partial class MainPage : Page -{ - /* Important! Change this to either Protocol.I2C or Protocol.SPI based on how your accelerometer is wired */ - private Protocol HW_PROTOCOL = Protocol.SPI; - // ... -} -``` - -### [Generate an app package](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#generate-an-app-package) - -### [Install your app package using an install script](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#install-your-app-package-using-an-install-script) - -### BIOS Settings for UP Board -If you are using UP Board, you have to setup the BIOS SPI configuration. - -1. Once you power on the UP board, select the **Del** or **F7** key on your keyboard to enter the BIOS setting. - -1. Navigate to **Boot** > **OS Image ID** tab, and select **Windows 10 IoT Core**. - -1. Navigate to the **Advance** tab and select the **Hat Configuration** and select "LPSS SPISupport" as "Enabled". - -1. For more information, please review the [UP Board Firmware Settings](https://www.annabooks.com/Articles/Articles_IoT10/Windows-10-IoT-UP-Board-BIOS-RHPROXY-Rev1.3.pdf). - -### Run the app -The SPIAccelerometer app will deploy and start, and you should see accelerometer data show up on screen. -If you have your accelerometer flat on a surface, the Z axis should read close to 1.000G, while X and Y are close to 0.000G. The values will fluctuate a little even if the device is standing still. -This is normal and is due to minute vibrations and electrical noise. If you tilt or shake the sensor, you should see the values change in response. Note that this sample configures the device in 4G mode, so you wont be able to see G readings higher than 4Gs. - -![SPI Accelerometer running](../../Resources/spiaccelerometer_screenshot.png) - -Congratulations! You've connected an SPI accelerometer. - -### Let's look at the code -The code in this sample performs two main tasks: - -1. First the code initializes the SPI bus and the accelerometer - -2. Secondly, we read from the accelerometer at defined intervals and update the display - -Let's start by digging into the initializations. - -### Initialize the SPI bus -To use the accelerometer, we need to initialize the SPI bus first. Here is the C# code. - -```csharp -using Windows.Devices.Enumeration; -using Windows.Devices.Spi; - -/* Initialization for SPI accelerometer */ -private async void InitSPIAccel() -{ - try { - var settings = new SpiConnectionSettings(SPI_CHIP_SELECT_LINE); - settings.ClockFrequency = 5000000; /* 5MHz is the rated speed of the ADXL345 accelerometer */ - settings.Mode = SpiMode.Mode3; /* The accelerometer expects an idle-high clock polarity, we use Mode3 - * to set the clock polarity and phase to: CPOL = 1, CPHA = 1 - */ - - string aqs = SpiDevice.GetDeviceSelector(); /* Get a selector string that will return all SPI controllers on the system */ - var dis = await DeviceInformation.FindAllAsync(aqs); /* Find the SPI bus controller devices with our selector string */ - SPIAccel = await SpiDevice.FromIdAsync(dis[0].Id, settings); /* Create an SpiDevice with our bus controller and SPI settings */ - if (SPIAccel == null) - { - Text_Status.Text = string.Format( - "SPI Controller {0} is currently in use by " + - "another application. Please ensure that no other applications are using SPI.", - dis[0].Id); - return; - } - } - - // ... -} -``` - -Here's an overview of what's happening: - -* First, we create an **SpiConnectionSettings** object and set the clock speed, clock polarity, and chip-select line. - -* Next, we get the selector strings for all SPI controllers on the device, and use that find all the SPI bus controllers on the system. - -* Finally, we create a new **SpiDevice** from the first SPI controller on the system (**dis[0]**) and check that it's available for use. - -### Initialize the accelerometer - -Now that we have the **SpiDevice** accelerometer instance, we're done with the SPI bus initialization. We can now write data over SPI to start up the accelerometer. We do this with the **Write()** function. -For this particular accelerometer, there are two internal registers we need to configure before we can start using the device: The data format register, and the power control register. - -1. We first write a 0x01 to the data format register. This configures the device range into +-4G mode. If you consult the [datasheet](https://www.sparkfun.com/datasheets/Sensors/Accelerometer/ADXL345.pdf){:target="_blank"}, you'll see that the device can be configured in a variety of measurement modes ranging from 2G to 16G. -Higher G settings provide you with greater range at the expense of reduced resolution. We choose 4G as a reasonable trade off between the two. - -2. We write a 0x08 to the power control register, which wakes the device from standby and starts measuring acceleration. Again, the [datasheet](https://www.sparkfun.com/datasheets/Sensors/Accelerometer/ADXL345.pdf){:target="_blank"} contains additional information about the device settings and capabilities. - -```csharp -private async void InitSPIAccel() -{ - // ... - - /* - * Initialize the accelerometer: - * - * For this device, we create 2-byte write buffers: - * The first byte is the register address we want to write to. - * The second byte is the contents that we want to write to the register. - */ - byte[] WriteBuf_DataFormat = new byte[] { ACCEL_REG_DATA_FORMAT, 0x01 }; /* 0x01 sets range to +- 4Gs */ - byte[] WriteBuf_PowerControl = new byte[] { ACCEL_REG_POWER_CONTROL, 0x08 }; /* 0x08 puts the accelerometer into measurement mode */ - - /* Write the register settings */ - try - { - SPIAccel.Write(WriteBuf_DataFormat); - SPIAccel.Write(WriteBuf_PowerControl); - } - /* If the write fails display the error and stop running */ - catch (Exception ex) - { - Text_Status.Text = "Failed to communicate with device: " + ex.Message; - return; - } - - // ... -} -``` - -### Timer code -After all the initializations are complete, we start a timer to read from the accelerometer periodically. Here is how you set up the timer to trigger every 100mS. -```csharp -private async void InitSPIAccel() -{ - // ... - - /* Now that everything is initialized, create a timer so we read data every 100mS */ - periodicTimer = new Timer(this.TimerCallback, null, 0, 100); - - // ... -} - -private void TimerCallback(object state) -{ - string xText, yText, zText; - string statusText; - - /* Read and format accelerometer data */ - try - { - Acceleration accel = ReadAccel(); - xText = String.Format("X Axis: {0:F3}G", accel.X); - yText = String.Format("Y Axis: {0:F3}G", accel.Y); - zText = String.Format("Z Axis: {0:F3}G", accel.Z); - statusText = "Status: Running"; - } - - // ... -} -``` - -### Read data from the accelerometer -With the SPI bus and accelerometer initialized, we can start reading data from the accelerometer. Our **ReadAccel()** function gets called every 100mS by the timer: - -```csharp -private Acceleration ReadAccel() -{ - const int ACCEL_RES = 1024; /* The ADXL345 has 10 bit resolution giving 1024 unique values */ - const int ACCEL_DYN_RANGE_G = 8; /* The ADXL345 had a total dynamic range of 8G, since we're configuring it to +-4G */ - const int UNITS_PER_G = ACCEL_RES / ACCEL_DYN_RANGE_G; /* Ratio of raw int values to G units */ - - byte[] ReadBuf; - byte[] RegAddrBuf; - - /* - * Read from the accelerometer - * We first write the address of the X-Axis register, then read all 3 axes into ReadBuf - */ - switch (HW_PROTOCOL) - { - case Protocol.SPI: - ReadBuf = new byte[6 + 1]; /* Read buffer of size 6 bytes (2 bytes * 3 axes) + 1 byte padding */ - RegAddrBuf = new byte[1 + 6]; /* Register address buffer of size 1 byte + 6 bytes padding */ - /* Register address we want to read from with read and multi-byte bit set */ - RegAddrBuf[0] = ACCEL_REG_X | ACCEL_SPI_RW_BIT | ACCEL_SPI_MB_BIT ; - SPIAccel.TransferFullDuplex(RegAddrBuf, ReadBuf); - Array.Copy(ReadBuf, 1, ReadBuf, 0, 6); /* Discard first dummy byte from read */ - break; - case Protocol.I2C: - // ... - default: /* Code should never get here */ - // ... - } - - // ... - - /* In order to get the raw 16-bit data values, we need to concatenate two 8-bit bytes for each axis */ - short AccelerationRawX = BitConverter.ToInt16(ReadBuf, 0); - short AccelerationRawY = BitConverter.ToInt16(ReadBuf, 2); - short AccelerationRawZ = BitConverter.ToInt16(ReadBuf, 4); - - /* Convert raw values to G's */ - Acceleration accel; - accel.X = (double)AccelerationRawX / UNITS_PER_G; - accel.Y = (double)AccelerationRawY / UNITS_PER_G; - accel.Z = (double)AccelerationRawZ / UNITS_PER_G; - - return accel; -} -``` -Here's how this works: - -* We begin by reading data from the accelerometer with the **TransferFullDuplex()** function. This function performs a SPI write and SPI read simultaneously in the same transaction. - -* The initial write specifies the register address we want to read from (which in this case is the X-Axis data register). This write ensures that a subsequent read will start from this register address. -We provide the function with a one-byte byte array representing the register address we want to write (plus padding bytes). We also set the read and multi-byte bits so that the accelerometer knows we're reading multiple bytes. - -* Next we provide the function with a read buffer of size 6 so we read 6 bytes over SPI (plus padding bytes). Since this device supports multi-byte reads, -**and** the X, Y, and Z data registers are next to each other, reading 6 bytes give us all of our data in one go. This ensures acceleration values don't change between reads as well. - -* We get back 6 bytes of data from our read. These represent the data in the X, Y, and Z data registers respectively. -We separate out the data into their respective axes and concatenate the bytes using **BitConverter.ToInt16()**. - -* The raw data is formatted as a 16-bit integer, which contains 10-bit data from the accelerometer. It can take on values ranging from -512 to 511. A reading of -512 corresponds to -4G while 511 is +4G. - To convert this to G units, we divide by the ratio of full-scale range (8G) to the resolution (1024) - -* Now that we have the G unit values, we can display the data on screen. This process is repeated every 100mS so the information is constantly updated. +--- +page_type: sample +urlFragment: accelerometer +languages: + - csharp +products: + - Windows 10 + - Windows IoT + - Windows 10 IoT Enterprise +description: Create a simple app with an SPI accelerometer build with Windows 10 IoT Enterprise. +--- + +# SPI Accelerometer + +We'll connect an SPI accelerometer to your UP Board and create a simple app to read data from it. +We'll walk you through step-by-step, so no background knowledge of SPI is needed. However, if you're curious, SparkFun provides a great [tutorial on SPI](https://learn.sparkfun.com/tutorials/serial-peripheral-interface-spi). + +### Load the project in Visual Studio + +You can find the source code for this sample by downloading a zip of all of our samples. Make a copy of the folder on your disk and open the project from Visual Studio 2019. + +### Connect the SPI Accelerometer to your device + +You'll need a few components: + +* an [ADXL345 accelerometer board from Sparkfun](https://www.sparkfun.com/products/9836) with pin headers soldered on + +* a breadboard and a couple of male-to-female connector wires + +![Electrical Components](../../Resources/components1.png) + +#### UP Board +If you have UP Board, we need to hook up power, ground, and the SPI lines to the accelerometer. + See the [UP Board pin mapping page](../../Resources/PinMappingsUpBoard.png) for more details on the UP Board IO pins. + +**Note: Make sure to power off the UP Board when connecting your circuit. This is good practice to reduce the chance of an accidental short circuit during construction.** + +The ADXL345 breakout board has 8 IO pins, connect them as follows: + +1. **GND:** Connect to ground on the UP Board (Pin 6) +2. **VCC:** Connect to 3.3V on the UP Board (Pin 1) +3. **CS:** Connect to SPI0 CS0 on the UP Board (Pin 24). This is the chip-select line for the SPI bus. +4. **INT1:** Leave unconnected, we're not using this pin +5. **INT2:** Leave unconnected, we're not using this pin +6. **SDO:** Connect to SPI0 MISO on the UP Board (Pin 21) +7. **SDA:** Connect to SPI0 MOSI on the UP Board (Pin 19) +8. **SCL:** Connect to SPI0 SCLK on the UP Board (Pin 23). This is the clock line for the SPI bus. + +Here are the connections shown on a breadboard: + +![Breadboard connections](../../Resources/breadboard_assembled_upboard1.png) + +Here are the schematics: + +![Accelerometer schematics](../../Resources/schematics_upboard.png) + +### Deploy the app + + Click the Start button to search for the app by name, and then launch it. + +When everything is set up, power your device back on, and open up the sample app in Visual Studio. Open the file **MainPage.xaml.cs** and change the following line from **Protocol.NONE** to **Protocol.SPI**: + +```csharp +public sealed partial class MainPage : Page +{ + /* Important! Change this to either Protocol.I2C or Protocol.SPI based on how your accelerometer is wired */ + private Protocol HW_PROTOCOL = Protocol.SPI; + // ... +} +``` + +### [Generate an app package](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#generate-an-app-package) + +### [Install your app package using an install script](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#install-your-app-package-using-an-install-script) + +### BIOS Settings for UP Board +If you are using UP Board, you have to setup the BIOS SPI configuration. + +1. Once you power on the UP board, select the **Del** or **F7** key on your keyboard to enter the BIOS setting. + +1. Navigate to **Boot** > **OS Image ID** tab, and select **Windows 10 IoT Core**. + +1. Navigate to the **Advance** tab and select the **Hat Configuration** and select "LPSS SPISupport" as "Enabled". + +1. For more information, please review the [UP Board Firmware Settings](https://www.annabooks.com/Articles/Articles_IoT10/Windows-10-IoT-UP-Board-BIOS-RHPROXY-Rev1.3.pdf). + +### Run the app +The SPIAccelerometer app will deploy and start, and you should see accelerometer data show up on screen. +If you have your accelerometer flat on a surface, the Z axis should read close to 1.000G, while X and Y are close to 0.000G. The values will fluctuate a little even if the device is standing still. +This is normal and is due to minute vibrations and electrical noise. If you tilt or shake the sensor, you should see the values change in response. Note that this sample configures the device in 4G mode, so you wont be able to see G readings higher than 4Gs. + +![SPI Accelerometer running](../../Resources/spiaccelerometer_screenshot.png) + +Congratulations! You've connected an SPI accelerometer. + +### Let's look at the code +The code in this sample performs two main tasks: + +1. First the code initializes the SPI bus and the accelerometer + +2. Secondly, we read from the accelerometer at defined intervals and update the display + +Let's start by digging into the initializations. + +### Initialize the SPI bus +To use the accelerometer, we need to initialize the SPI bus first. Here is the C# code. + +```csharp +using Windows.Devices.Enumeration; +using Windows.Devices.Spi; + +/* Initialization for SPI accelerometer */ +private async void InitSPIAccel() +{ + try { + var settings = new SpiConnectionSettings(SPI_CHIP_SELECT_LINE); + settings.ClockFrequency = 5000000; /* 5MHz is the rated speed of the ADXL345 accelerometer */ + settings.Mode = SpiMode.Mode3; /* The accelerometer expects an idle-high clock polarity, we use Mode3 + * to set the clock polarity and phase to: CPOL = 1, CPHA = 1 + */ + + string aqs = SpiDevice.GetDeviceSelector(); /* Get a selector string that will return all SPI controllers on the system */ + var dis = await DeviceInformation.FindAllAsync(aqs); /* Find the SPI bus controller devices with our selector string */ + SPIAccel = await SpiDevice.FromIdAsync(dis[0].Id, settings); /* Create an SpiDevice with our bus controller and SPI settings */ + if (SPIAccel == null) + { + Text_Status.Text = string.Format( + "SPI Controller {0} is currently in use by " + + "another application. Please ensure that no other applications are using SPI.", + dis[0].Id); + return; + } + } + + // ... +} +``` + +Here's an overview of what's happening: + +* First, we create an **SpiConnectionSettings** object and set the clock speed, clock polarity, and chip-select line. + +* Next, we get the selector strings for all SPI controllers on the device, and use that find all the SPI bus controllers on the system. + +* Finally, we create a new **SpiDevice** from the first SPI controller on the system (**dis[0]**) and check that it's available for use. + +### Initialize the accelerometer + +Now that we have the **SpiDevice** accelerometer instance, we're done with the SPI bus initialization. We can now write data over SPI to start up the accelerometer. We do this with the **Write()** function. +For this particular accelerometer, there are two internal registers we need to configure before we can start using the device: The data format register, and the power control register. + +1. We first write a 0x01 to the data format register. This configures the device range into +-4G mode. If you consult the [datasheet](https://www.sparkfun.com/datasheets/Sensors/Accelerometer/ADXL345.pdf){:target="_blank"}, you'll see that the device can be configured in a variety of measurement modes ranging from 2G to 16G. +Higher G settings provide you with greater range at the expense of reduced resolution. We choose 4G as a reasonable trade off between the two. + +2. We write a 0x08 to the power control register, which wakes the device from standby and starts measuring acceleration. Again, the [datasheet](https://www.sparkfun.com/datasheets/Sensors/Accelerometer/ADXL345.pdf){:target="_blank"} contains additional information about the device settings and capabilities. + +```csharp +private async void InitSPIAccel() +{ + // ... + + /* + * Initialize the accelerometer: + * + * For this device, we create 2-byte write buffers: + * The first byte is the register address we want to write to. + * The second byte is the contents that we want to write to the register. + */ + byte[] WriteBuf_DataFormat = new byte[] { ACCEL_REG_DATA_FORMAT, 0x01 }; /* 0x01 sets range to +- 4Gs */ + byte[] WriteBuf_PowerControl = new byte[] { ACCEL_REG_POWER_CONTROL, 0x08 }; /* 0x08 puts the accelerometer into measurement mode */ + + /* Write the register settings */ + try + { + SPIAccel.Write(WriteBuf_DataFormat); + SPIAccel.Write(WriteBuf_PowerControl); + } + /* If the write fails display the error and stop running */ + catch (Exception ex) + { + Text_Status.Text = "Failed to communicate with device: " + ex.Message; + return; + } + + // ... +} +``` + +### Timer code +After all the initializations are complete, we start a timer to read from the accelerometer periodically. Here is how you set up the timer to trigger every 100mS. +```csharp +private async void InitSPIAccel() +{ + // ... + + /* Now that everything is initialized, create a timer so we read data every 100mS */ + periodicTimer = new Timer(this.TimerCallback, null, 0, 100); + + // ... +} + +private void TimerCallback(object state) +{ + string xText, yText, zText; + string statusText; + + /* Read and format accelerometer data */ + try + { + Acceleration accel = ReadAccel(); + xText = String.Format("X Axis: {0:F3}G", accel.X); + yText = String.Format("Y Axis: {0:F3}G", accel.Y); + zText = String.Format("Z Axis: {0:F3}G", accel.Z); + statusText = "Status: Running"; + } + + // ... +} +``` + +### Read data from the accelerometer +With the SPI bus and accelerometer initialized, we can start reading data from the accelerometer. Our **ReadAccel()** function gets called every 100mS by the timer: + +```csharp +private Acceleration ReadAccel() +{ + const int ACCEL_RES = 1024; /* The ADXL345 has 10 bit resolution giving 1024 unique values */ + const int ACCEL_DYN_RANGE_G = 8; /* The ADXL345 had a total dynamic range of 8G, since we're configuring it to +-4G */ + const int UNITS_PER_G = ACCEL_RES / ACCEL_DYN_RANGE_G; /* Ratio of raw int values to G units */ + + byte[] ReadBuf; + byte[] RegAddrBuf; + + /* + * Read from the accelerometer + * We first write the address of the X-Axis register, then read all 3 axes into ReadBuf + */ + switch (HW_PROTOCOL) + { + case Protocol.SPI: + ReadBuf = new byte[6 + 1]; /* Read buffer of size 6 bytes (2 bytes * 3 axes) + 1 byte padding */ + RegAddrBuf = new byte[1 + 6]; /* Register address buffer of size 1 byte + 6 bytes padding */ + /* Register address we want to read from with read and multi-byte bit set */ + RegAddrBuf[0] = ACCEL_REG_X | ACCEL_SPI_RW_BIT | ACCEL_SPI_MB_BIT ; + SPIAccel.TransferFullDuplex(RegAddrBuf, ReadBuf); + Array.Copy(ReadBuf, 1, ReadBuf, 0, 6); /* Discard first dummy byte from read */ + break; + case Protocol.I2C: + // ... + default: /* Code should never get here */ + // ... + } + + // ... + + /* In order to get the raw 16-bit data values, we need to concatenate two 8-bit bytes for each axis */ + short AccelerationRawX = BitConverter.ToInt16(ReadBuf, 0); + short AccelerationRawY = BitConverter.ToInt16(ReadBuf, 2); + short AccelerationRawZ = BitConverter.ToInt16(ReadBuf, 4); + + /* Convert raw values to G's */ + Acceleration accel; + accel.X = (double)AccelerationRawX / UNITS_PER_G; + accel.Y = (double)AccelerationRawY / UNITS_PER_G; + accel.Z = (double)AccelerationRawZ / UNITS_PER_G; + + return accel; +} +``` +Here's how this works: + +* We begin by reading data from the accelerometer with the **TransferFullDuplex()** function. This function performs a SPI write and SPI read simultaneously in the same transaction. + +* The initial write specifies the register address we want to read from (which in this case is the X-Axis data register). This write ensures that a subsequent read will start from this register address. +We provide the function with a one-byte byte array representing the register address we want to write (plus padding bytes). We also set the read and multi-byte bits so that the accelerometer knows we're reading multiple bytes. + +* Next we provide the function with a read buffer of size 6 so we read 6 bytes over SPI (plus padding bytes). Since this device supports multi-byte reads, +**and** the X, Y, and Z data registers are next to each other, reading 6 bytes give us all of our data in one go. This ensures acceleration values don't change between reads as well. + +* We get back 6 bytes of data from our read. These represent the data in the X, Y, and Z data registers respectively. +We separate out the data into their respective axes and concatenate the bytes using **BitConverter.ToInt16()**. + +* The raw data is formatted as a 16-bit integer, which contains 10-bit data from the accelerometer. It can take on values ranging from -512 to 511. A reading of -512 corresponds to -4G while 511 is +4G. + To convert this to G units, we divide by the ratio of full-scale range (8G) to the resolution (1024) + +* Now that we have the G unit values, we can display the data on screen. This process is repeated every 100mS so the information is constantly updated. diff --git a/samples/AppServiceBlinky/CPP/BlinkyClient.sln b/samples/AppServiceBlinky/CPP/BlinkyClient.sln index bc61a1a79..7393f136b 100644 --- a/samples/AppServiceBlinky/CPP/BlinkyClient.sln +++ b/samples/AppServiceBlinky/CPP/BlinkyClient.sln @@ -1,40 +1,40 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26403.7 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlinkyClient", "BlinkyClient\BlinkyClient.vcxproj", "{74CD8FFB-29E6-43FE-8423-81B22DC46A36}" -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 - {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Debug|ARM.ActiveCfg = Debug|ARM - {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Debug|ARM.Build.0 = Debug|ARM - {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Debug|ARM.Deploy.0 = Debug|ARM - {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Debug|x64.ActiveCfg = Debug|x64 - {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Debug|x64.Build.0 = Debug|x64 - {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Debug|x64.Deploy.0 = Debug|x64 - {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Debug|x86.ActiveCfg = Debug|Win32 - {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Debug|x86.Build.0 = Debug|Win32 - {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Debug|x86.Deploy.0 = Debug|Win32 - {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Release|ARM.ActiveCfg = Release|ARM - {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Release|ARM.Build.0 = Release|ARM - {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Release|ARM.Deploy.0 = Release|ARM - {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Release|x64.ActiveCfg = Release|x64 - {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Release|x64.Build.0 = Release|x64 - {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Release|x64.Deploy.0 = Release|x64 - {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Release|x86.ActiveCfg = Release|Win32 - {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Release|x86.Build.0 = Release|Win32 - {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Release|x86.Deploy.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26403.7 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlinkyClient", "BlinkyClient\BlinkyClient.vcxproj", "{74CD8FFB-29E6-43FE-8423-81B22DC46A36}" +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 + {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Debug|ARM.ActiveCfg = Debug|ARM + {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Debug|ARM.Build.0 = Debug|ARM + {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Debug|ARM.Deploy.0 = Debug|ARM + {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Debug|x64.ActiveCfg = Debug|x64 + {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Debug|x64.Build.0 = Debug|x64 + {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Debug|x64.Deploy.0 = Debug|x64 + {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Debug|x86.ActiveCfg = Debug|Win32 + {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Debug|x86.Build.0 = Debug|Win32 + {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Debug|x86.Deploy.0 = Debug|Win32 + {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Release|ARM.ActiveCfg = Release|ARM + {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Release|ARM.Build.0 = Release|ARM + {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Release|ARM.Deploy.0 = Release|ARM + {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Release|x64.ActiveCfg = Release|x64 + {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Release|x64.Build.0 = Release|x64 + {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Release|x64.Deploy.0 = Release|x64 + {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Release|x86.ActiveCfg = Release|Win32 + {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Release|x86.Build.0 = Release|Win32 + {74CD8FFB-29E6-43FE-8423-81B22DC46A36}.Release|x86.Deploy.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/AppServiceBlinky/CPP/BlinkyClient/BlinkyClient.vcxproj b/samples/AppServiceBlinky/CPP/BlinkyClient/BlinkyClient.vcxproj index 595a244d1..3711cc621 100644 --- a/samples/AppServiceBlinky/CPP/BlinkyClient/BlinkyClient.vcxproj +++ b/samples/AppServiceBlinky/CPP/BlinkyClient/BlinkyClient.vcxproj @@ -1,233 +1,233 @@ - - - - {74cd8ffb-29e6-43fe-8423-81b22dc46a36} - BlinkyClient - en-US - 15.0 - true - Windows Store - 10.0.19041.0 - 10.0.15063.0 - 10.0 - true - true - true - true - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - DynamicLibrary - true - v141 - - - DynamicLibrary - true - v142 - - - DynamicLibrary - true - v142 - - - DynamicLibrary - false - true - v141 - true - - - DynamicLibrary - false - true - v142 - true - - - DynamicLibrary - false - true - v142 - true - - - - - - - - - - - - - - - - - - - - - - - - - BlinkyClient_TemporaryKey.pfx - - - - Use - _WINRT_DLL;%(PreprocessorDefinitions) - pch.h - $(IntDir)pch.pch - $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - 28204 - - - Console - runtimeobject.lib;%(AdditionalDependencies) - - - - - Use - _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) - pch.h - $(IntDir)pch.pch - $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - 28204 - - - Console - runtimeobject.lib;%(AdditionalDependencies) - false - false - - - - - Use - _WINRT_DLL;%(PreprocessorDefinitions) - pch.h - $(IntDir)pch.pch - $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - 28204 - - - Console - runtimeobject.lib;%(AdditionalDependencies) - false - - - - - Use - _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) - pch.h - $(IntDir)pch.pch - $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - 28204 - - - Console - runtimeobject.lib;%(AdditionalDependencies) - false - - - - - Use - _WINRT_DLL;%(PreprocessorDefinitions) - pch.h - $(IntDir)pch.pch - $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - 28204 - - - Console - runtimeobject.lib;%(AdditionalDependencies) - false - - - - - Use - _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) - pch.h - $(IntDir)pch.pch - $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - 28204 - - - Console - runtimeobject.lib;%(AdditionalDependencies) - false - - - - - Designer - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - + + + + {74cd8ffb-29e6-43fe-8423-81b22dc46a36} + BlinkyClient + en-US + 15.0 + true + Windows Store + 10.0.19041.0 + 10.0.15063.0 + 10.0 + true + true + true + true + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + DynamicLibrary + true + v141 + + + DynamicLibrary + true + v142 + + + DynamicLibrary + true + v142 + + + DynamicLibrary + false + true + v141 + true + + + DynamicLibrary + false + true + v142 + true + + + DynamicLibrary + false + true + v142 + true + + + + + + + + + + + + + + + + + + + + + + + + + BlinkyClient_TemporaryKey.pfx + + + + Use + _WINRT_DLL;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + + + Console + runtimeobject.lib;%(AdditionalDependencies) + + + + + Use + _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + + + Console + runtimeobject.lib;%(AdditionalDependencies) + false + false + + + + + Use + _WINRT_DLL;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + + + Console + runtimeobject.lib;%(AdditionalDependencies) + false + + + + + Use + _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + + + Console + runtimeobject.lib;%(AdditionalDependencies) + false + + + + + Use + _WINRT_DLL;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + + + Console + runtimeobject.lib;%(AdditionalDependencies) + false + + + + + Use + _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + + + Console + runtimeobject.lib;%(AdditionalDependencies) + false + + + + + Designer + + + + + + + + + + + + + + + + + Create + Create + Create + Create + Create + Create + + + + + + + diff --git a/samples/AppServiceBlinky/CPP/BlinkyClient/Package.appxmanifest b/samples/AppServiceBlinky/CPP/BlinkyClient/Package.appxmanifest index 93df43b04..9daa35bf3 100644 --- a/samples/AppServiceBlinky/CPP/BlinkyClient/Package.appxmanifest +++ b/samples/AppServiceBlinky/CPP/BlinkyClient/Package.appxmanifest @@ -1,56 +1,56 @@ - - - - - - - - - - BlinkyClient - msft - Assets\StoreLogo.png - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + BlinkyClient + msft + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/AppServiceBlinky/CPP/BlinkyClient/StartupTask.cpp b/samples/AppServiceBlinky/CPP/BlinkyClient/StartupTask.cpp index 9e5c0cfac..04f872a2d 100644 --- a/samples/AppServiceBlinky/CPP/BlinkyClient/StartupTask.cpp +++ b/samples/AppServiceBlinky/CPP/BlinkyClient/StartupTask.cpp @@ -1,85 +1,85 @@ -#include "pch.h" -#include "StartupTask.h" - -using namespace BlinkyClient; - -using namespace Platform; -using namespace Windows::ApplicationModel::Background; -using namespace Windows::ApplicationModel::AppService; -using namespace Windows::Foundation; -using namespace Windows::Foundation::Collections; -using namespace Windows::System::Threading; -using namespace Windows::Devices::Gpio; - -// The Background Application template is documented at http://go.microsoft.com/fwlink/?LinkID=533884&clcid=0x409 - -void StartupTask::Run(IBackgroundTaskInstance^ taskInstance) -{ - serviceDeferral = taskInstance->GetDeferral(); - - serviceConnection = ref new AppServiceConnection(); - serviceConnection->PackageFamilyName = L"BlinkyService-uwp_2yx4q2bk84nj4"; - serviceConnection->AppServiceName = L"BlinkyService"; - - auto connectTask = Concurrency::create_task(serviceConnection->OpenAsync()); - connectTask.then([this](AppServiceConnectionStatus connectStatus) - { - if (AppServiceConnectionStatus::Success == connectStatus) - { - auto message = ref new ValueSet(); - command = L"SetLedStateOn"; - message->Insert(L"SetLedState", command); - message->Insert(L"PinNumber", 5); - auto messageTask = Concurrency::create_task(serviceConnection->SendMessageAsync(message)); - - messageTask.then([this](AppServiceResponse ^appServiceResponse) - { - if ((appServiceResponse->Status == AppServiceResponseStatus::Success) && - (appServiceResponse->Message != nullptr) && - (appServiceResponse->Message->HasKey(L"Response"))) - { - auto response = appServiceResponse->Message->Lookup(L"Response"); - String^ responseMessage = safe_cast(response); - if (String::operator==(responseMessage, L"Success")) - { - TimerElapsedHandler ^handler = ref new TimerElapsedHandler( - [this](ThreadPoolTimer ^timer) - { - RequestBlinkService(); - }); - - TimeSpan interval; - interval.Duration = 500 * 1000 * 10; - timer = ThreadPoolTimer::CreatePeriodicTimer(handler, interval); - } - } - }); - } - else - { - serviceDeferral->Complete(); - } - }); -} - -void StartupTask::RequestBlinkService() -{ - command = String::operator==(command, L"SetLedStateOn") ? L"SetLedStateOff" : L"SetLedStateOn"; - auto message = ref new ValueSet(); - message->Insert(L"SetLedState", command); - message->Insert(L"PinNumber", 5); - auto messageTask = Concurrency::create_task(serviceConnection->SendMessageAsync(message)); -} - -void BlinkyClient::StartupTask::OnCanceled(Windows::ApplicationModel::Background::IBackgroundTaskInstance ^sender, Windows::ApplicationModel::Background::BackgroundTaskCancellationReason reason) -{ - if (serviceDeferral != nullptr) - { - serviceDeferral->Complete(); - } - - if (serviceConnection != nullptr) - { - serviceConnection = nullptr; - } +#include "pch.h" +#include "StartupTask.h" + +using namespace BlinkyClient; + +using namespace Platform; +using namespace Windows::ApplicationModel::Background; +using namespace Windows::ApplicationModel::AppService; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::System::Threading; +using namespace Windows::Devices::Gpio; + +// The Background Application template is documented at http://go.microsoft.com/fwlink/?LinkID=533884&clcid=0x409 + +void StartupTask::Run(IBackgroundTaskInstance^ taskInstance) +{ + serviceDeferral = taskInstance->GetDeferral(); + + serviceConnection = ref new AppServiceConnection(); + serviceConnection->PackageFamilyName = L"BlinkyService-uwp_2yx4q2bk84nj4"; + serviceConnection->AppServiceName = L"BlinkyService"; + + auto connectTask = Concurrency::create_task(serviceConnection->OpenAsync()); + connectTask.then([this](AppServiceConnectionStatus connectStatus) + { + if (AppServiceConnectionStatus::Success == connectStatus) + { + auto message = ref new ValueSet(); + command = L"SetLedStateOn"; + message->Insert(L"SetLedState", command); + message->Insert(L"PinNumber", 5); + auto messageTask = Concurrency::create_task(serviceConnection->SendMessageAsync(message)); + + messageTask.then([this](AppServiceResponse ^appServiceResponse) + { + if ((appServiceResponse->Status == AppServiceResponseStatus::Success) && + (appServiceResponse->Message != nullptr) && + (appServiceResponse->Message->HasKey(L"Response"))) + { + auto response = appServiceResponse->Message->Lookup(L"Response"); + String^ responseMessage = safe_cast(response); + if (String::operator==(responseMessage, L"Success")) + { + TimerElapsedHandler ^handler = ref new TimerElapsedHandler( + [this](ThreadPoolTimer ^timer) + { + RequestBlinkService(); + }); + + TimeSpan interval; + interval.Duration = 500 * 1000 * 10; + timer = ThreadPoolTimer::CreatePeriodicTimer(handler, interval); + } + } + }); + } + else + { + serviceDeferral->Complete(); + } + }); +} + +void StartupTask::RequestBlinkService() +{ + command = String::operator==(command, L"SetLedStateOn") ? L"SetLedStateOff" : L"SetLedStateOn"; + auto message = ref new ValueSet(); + message->Insert(L"SetLedState", command); + message->Insert(L"PinNumber", 5); + auto messageTask = Concurrency::create_task(serviceConnection->SendMessageAsync(message)); +} + +void BlinkyClient::StartupTask::OnCanceled(Windows::ApplicationModel::Background::IBackgroundTaskInstance ^sender, Windows::ApplicationModel::Background::BackgroundTaskCancellationReason reason) +{ + if (serviceDeferral != nullptr) + { + serviceDeferral->Complete(); + } + + if (serviceConnection != nullptr) + { + serviceConnection = nullptr; + } } \ No newline at end of file diff --git a/samples/AppServiceBlinky/CPP/BlinkyClient/StartupTask.h b/samples/AppServiceBlinky/CPP/BlinkyClient/StartupTask.h index 06e6e5a55..3ed49be35 100644 --- a/samples/AppServiceBlinky/CPP/BlinkyClient/StartupTask.h +++ b/samples/AppServiceBlinky/CPP/BlinkyClient/StartupTask.h @@ -1,20 +1,20 @@ -#pragma once - -#include "pch.h" - -namespace BlinkyClient -{ - [Windows::Foundation::Metadata::WebHostHidden] - public ref class StartupTask sealed : public Windows::ApplicationModel::Background::IBackgroundTask - { - public: - virtual void Run(Windows::ApplicationModel::Background::IBackgroundTaskInstance^ taskInstance); - private: - void OnCanceled(Windows::ApplicationModel::Background::IBackgroundTaskInstance ^sender, Windows::ApplicationModel::Background::BackgroundTaskCancellationReason reason); - Platform::Agile serviceDeferral; - Windows::ApplicationModel::AppService::AppServiceConnection ^serviceConnection; - Windows::System::Threading::ThreadPoolTimer ^timer; - Platform::String ^command; - void RequestBlinkService(); - }; -} +#pragma once + +#include "pch.h" + +namespace BlinkyClient +{ + [Windows::Foundation::Metadata::WebHostHidden] + public ref class StartupTask sealed : public Windows::ApplicationModel::Background::IBackgroundTask + { + public: + virtual void Run(Windows::ApplicationModel::Background::IBackgroundTaskInstance^ taskInstance); + private: + void OnCanceled(Windows::ApplicationModel::Background::IBackgroundTaskInstance ^sender, Windows::ApplicationModel::Background::BackgroundTaskCancellationReason reason); + Platform::Agile serviceDeferral; + Windows::ApplicationModel::AppService::AppServiceConnection ^serviceConnection; + Windows::System::Threading::ThreadPoolTimer ^timer; + Platform::String ^command; + void RequestBlinkService(); + }; +} diff --git a/samples/AppServiceBlinky/CPP/BlinkyClient/pch.cpp b/samples/AppServiceBlinky/CPP/BlinkyClient/pch.cpp index ef288d82a..97b544ec1 100644 --- a/samples/AppServiceBlinky/CPP/BlinkyClient/pch.cpp +++ b/samples/AppServiceBlinky/CPP/BlinkyClient/pch.cpp @@ -1,6 +1,6 @@ -// -// pch.cpp -// Include the standard header and generate the precompiled header. -// - -#include "pch.h" +// +// pch.cpp +// Include the standard header and generate the precompiled header. +// + +#include "pch.h" diff --git a/samples/AppServiceBlinky/CPP/BlinkyClient/pch.h b/samples/AppServiceBlinky/CPP/BlinkyClient/pch.h index 3fb712067..f32d6802b 100644 --- a/samples/AppServiceBlinky/CPP/BlinkyClient/pch.h +++ b/samples/AppServiceBlinky/CPP/BlinkyClient/pch.h @@ -1,10 +1,10 @@ -// -// pch.h -// Header for standard system include files. -// - -#pragma once - -#include -#include -#include +// +// pch.h +// Header for standard system include files. +// + +#pragma once + +#include +#include +#include diff --git a/samples/AppServiceBlinky/CPP/BlinkyService.sln b/samples/AppServiceBlinky/CPP/BlinkyService.sln index 6bcbe9296..61c0d5bb7 100644 --- a/samples/AppServiceBlinky/CPP/BlinkyService.sln +++ b/samples/AppServiceBlinky/CPP/BlinkyService.sln @@ -1,40 +1,40 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26403.7 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlinkyService", "BlinkyService\BlinkyService.vcxproj", "{88B91F3D-AD2F-4002-909C-11A2026E4CE8}" -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 - {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Debug|ARM.ActiveCfg = Debug|ARM - {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Debug|ARM.Build.0 = Debug|ARM - {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Debug|ARM.Deploy.0 = Debug|ARM - {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Debug|x64.ActiveCfg = Debug|x64 - {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Debug|x64.Build.0 = Debug|x64 - {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Debug|x64.Deploy.0 = Debug|x64 - {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Debug|x86.ActiveCfg = Debug|Win32 - {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Debug|x86.Build.0 = Debug|Win32 - {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Debug|x86.Deploy.0 = Debug|Win32 - {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Release|ARM.ActiveCfg = Release|ARM - {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Release|ARM.Build.0 = Release|ARM - {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Release|ARM.Deploy.0 = Release|ARM - {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Release|x64.ActiveCfg = Release|x64 - {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Release|x64.Build.0 = Release|x64 - {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Release|x64.Deploy.0 = Release|x64 - {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Release|x86.ActiveCfg = Release|Win32 - {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Release|x86.Build.0 = Release|Win32 - {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Release|x86.Deploy.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26403.7 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlinkyService", "BlinkyService\BlinkyService.vcxproj", "{88B91F3D-AD2F-4002-909C-11A2026E4CE8}" +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 + {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Debug|ARM.ActiveCfg = Debug|ARM + {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Debug|ARM.Build.0 = Debug|ARM + {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Debug|ARM.Deploy.0 = Debug|ARM + {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Debug|x64.ActiveCfg = Debug|x64 + {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Debug|x64.Build.0 = Debug|x64 + {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Debug|x64.Deploy.0 = Debug|x64 + {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Debug|x86.ActiveCfg = Debug|Win32 + {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Debug|x86.Build.0 = Debug|Win32 + {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Debug|x86.Deploy.0 = Debug|Win32 + {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Release|ARM.ActiveCfg = Release|ARM + {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Release|ARM.Build.0 = Release|ARM + {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Release|ARM.Deploy.0 = Release|ARM + {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Release|x64.ActiveCfg = Release|x64 + {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Release|x64.Build.0 = Release|x64 + {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Release|x64.Deploy.0 = Release|x64 + {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Release|x86.ActiveCfg = Release|Win32 + {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Release|x86.Build.0 = Release|Win32 + {88B91F3D-AD2F-4002-909C-11A2026E4CE8}.Release|x86.Deploy.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/AppServiceBlinky/CPP/BlinkyService/BlinkyService.vcxproj b/samples/AppServiceBlinky/CPP/BlinkyService/BlinkyService.vcxproj index 86492807b..5ac67d76d 100644 --- a/samples/AppServiceBlinky/CPP/BlinkyService/BlinkyService.vcxproj +++ b/samples/AppServiceBlinky/CPP/BlinkyService/BlinkyService.vcxproj @@ -1,234 +1,234 @@ - - - - {88b91f3d-ad2f-4002-909c-11a2026e4ce8} - BlinkyService - en-US - 15.0 - true - Windows Store - 10.0.19041.0 - 10.0.15063.0 - 10.0 - true - true - true - true - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - DynamicLibrary - true - v141 - - - DynamicLibrary - true - v142 - - - DynamicLibrary - true - v142 - - - DynamicLibrary - false - true - v141 - true - - - DynamicLibrary - false - true - v142 - true - - - DynamicLibrary - false - true - v142 - true - - - - - - - - - - - - - - - - - - - - - - - - - - BlinkyService_TemporaryKey.pfx - - - - Use - _WINRT_DLL;%(PreprocessorDefinitions) - pch.h - $(IntDir)pch.pch - $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - 28204 - - - Console - runtimeobject.lib;%(AdditionalDependencies) - - - - - Use - _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) - pch.h - $(IntDir)pch.pch - $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - 28204 - - - Console - runtimeobject.lib;%(AdditionalDependencies) - false - false - - - - - Use - _WINRT_DLL;%(PreprocessorDefinitions) - pch.h - $(IntDir)pch.pch - $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - 28204 - - - Console - runtimeobject.lib;%(AdditionalDependencies) - false - - - - - Use - _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) - pch.h - $(IntDir)pch.pch - $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - 28204 - - - Console - runtimeobject.lib;%(AdditionalDependencies) - false - - - - - Use - _WINRT_DLL;%(PreprocessorDefinitions) - pch.h - $(IntDir)pch.pch - $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - 28204 - - - Console - runtimeobject.lib;%(AdditionalDependencies) - false - - - - - Use - _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) - pch.h - $(IntDir)pch.pch - $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - 28204 - - - Console - runtimeobject.lib;%(AdditionalDependencies) - false - - - - - Designer - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - - - - - - - + + + + {88b91f3d-ad2f-4002-909c-11a2026e4ce8} + BlinkyService + en-US + 15.0 + true + Windows Store + 10.0.19041.0 + 10.0.15063.0 + 10.0 + true + true + true + true + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + DynamicLibrary + true + v141 + + + DynamicLibrary + true + v142 + + + DynamicLibrary + true + v142 + + + DynamicLibrary + false + true + v141 + true + + + DynamicLibrary + false + true + v142 + true + + + DynamicLibrary + false + true + v142 + true + + + + + + + + + + + + + + + + + + + + + + + + + + BlinkyService_TemporaryKey.pfx + + + + Use + _WINRT_DLL;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + + + Console + runtimeobject.lib;%(AdditionalDependencies) + + + + + Use + _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + + + Console + runtimeobject.lib;%(AdditionalDependencies) + false + false + + + + + Use + _WINRT_DLL;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + + + Console + runtimeobject.lib;%(AdditionalDependencies) + false + + + + + Use + _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + + + Console + runtimeobject.lib;%(AdditionalDependencies) + false + + + + + Use + _WINRT_DLL;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + + + Console + runtimeobject.lib;%(AdditionalDependencies) + false + + + + + Use + _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + + + Console + runtimeobject.lib;%(AdditionalDependencies) + false + + + + + Designer + + + + + + + + + + + + + + + + + Create + Create + Create + Create + Create + Create + + + + + + + diff --git a/samples/AppServiceBlinky/CPP/BlinkyService/BlinkyServiceProvider.cpp b/samples/AppServiceBlinky/CPP/BlinkyService/BlinkyServiceProvider.cpp index b70625c14..8bf8d1124 100644 --- a/samples/AppServiceBlinky/CPP/BlinkyService/BlinkyServiceProvider.cpp +++ b/samples/AppServiceBlinky/CPP/BlinkyService/BlinkyServiceProvider.cpp @@ -1,99 +1,99 @@ -#include "pch.h" -#include "BlinkyServiceProvider.h" - -using namespace BlinkyService; - -using namespace Platform; -using namespace Windows::ApplicationModel::AppService; -using namespace Windows::ApplicationModel::Background; -using namespace Windows::Devices::Gpio; -using namespace Windows::Foundation::Collections; - -void BlinkyServiceProvider::Run(IBackgroundTaskInstance^ taskInstance) -{ - serviceDeferral = taskInstance->GetDeferral(); - - taskInstance->Canceled += ref new Windows::ApplicationModel::Background::BackgroundTaskCanceledEventHandler(this, &BlinkyService::BlinkyServiceProvider::OnCanceled); - - auto appServiceTrigger = dynamic_cast(taskInstance->TriggerDetails); - - if (appServiceTrigger != nullptr) - { - if (String::operator==(appServiceTrigger->Name, L"BlinkyService")) - { - controller = GpioController::GetDefault(); - serviceConnection = appServiceTrigger->AppServiceConnection; - serviceConnection->RequestReceived += ref new Windows::Foundation::TypedEventHandler(this, &BlinkyService::BlinkyServiceProvider::OnRequestReceived); - } - else - { - serviceDeferral->Complete(); - } - } -} - -void BlinkyService::BlinkyServiceProvider::OnCanceled(Windows::ApplicationModel::Background::IBackgroundTaskInstance ^sender, Windows::ApplicationModel::Background::BackgroundTaskCancellationReason reason) -{ - if (serviceDeferral != nullptr) - { - serviceDeferral->Complete(); - } -} - -void BlinkyService::BlinkyServiceProvider::OnRequestReceived(Windows::ApplicationModel::AppService::AppServiceConnection ^sender, Windows::ApplicationModel::AppService::AppServiceRequestReceivedEventArgs ^args) -{ - auto messageDeferral = args->GetDeferral(); - - auto responseMessage = ref new ValueSet(); - - if (args->Request->Message != nullptr) - { - if ((args->Request->Message->HasKey(L"SetLedState")) && (args->Request->Message->HasKey(L"PinNumber"))) - { - try - { - auto commandObject = args->Request->Message->Lookup(L"SetLedState"); - String^ command = safe_cast(commandObject); - auto pinNumberObject = args->Request->Message->Lookup(L"PinNumber"); - int pinNumber = safe_cast(pinNumberObject); - auto pin = controller->OpenPin(pinNumber); - pin->SetDriveMode(GpioPinDriveMode::Output); - - if (String::operator==(command, L"SetLedStateOn")) - { - pin->Write(GpioPinValue::High); - responseMessage->Insert(L"Response", L"Success"); - } - else if (String::operator==(command, L"SetLedStateOff")) - { - pin->Write(GpioPinValue::Low); - responseMessage->Insert(L"Response", L"Success"); - } - else - { - responseMessage->Insert(L"Response", L"Request Failed:Invalid SetLedState parameter value."); - } - } - catch (InvalidCastException^ ic) - { - responseMessage->Insert(L"Response", L"Request Failed:Invalid cast exception occurred."); - } - catch (Exception^ e) - { - responseMessage->Insert(L"Response", L"Request Failed:Unknown exception occurred."); - } - } - else - { - responseMessage->Insert(L"Response", L"Request Failed:Invalid request."); - } - } - else - { - responseMessage->Insert(L"Response", L"Failed: Request message is empty."); - } - - args->Request->SendResponseAsync(responseMessage); - - messageDeferral->Complete(); -} +#include "pch.h" +#include "BlinkyServiceProvider.h" + +using namespace BlinkyService; + +using namespace Platform; +using namespace Windows::ApplicationModel::AppService; +using namespace Windows::ApplicationModel::Background; +using namespace Windows::Devices::Gpio; +using namespace Windows::Foundation::Collections; + +void BlinkyServiceProvider::Run(IBackgroundTaskInstance^ taskInstance) +{ + serviceDeferral = taskInstance->GetDeferral(); + + taskInstance->Canceled += ref new Windows::ApplicationModel::Background::BackgroundTaskCanceledEventHandler(this, &BlinkyService::BlinkyServiceProvider::OnCanceled); + + auto appServiceTrigger = dynamic_cast(taskInstance->TriggerDetails); + + if (appServiceTrigger != nullptr) + { + if (String::operator==(appServiceTrigger->Name, L"BlinkyService")) + { + controller = GpioController::GetDefault(); + serviceConnection = appServiceTrigger->AppServiceConnection; + serviceConnection->RequestReceived += ref new Windows::Foundation::TypedEventHandler(this, &BlinkyService::BlinkyServiceProvider::OnRequestReceived); + } + else + { + serviceDeferral->Complete(); + } + } +} + +void BlinkyService::BlinkyServiceProvider::OnCanceled(Windows::ApplicationModel::Background::IBackgroundTaskInstance ^sender, Windows::ApplicationModel::Background::BackgroundTaskCancellationReason reason) +{ + if (serviceDeferral != nullptr) + { + serviceDeferral->Complete(); + } +} + +void BlinkyService::BlinkyServiceProvider::OnRequestReceived(Windows::ApplicationModel::AppService::AppServiceConnection ^sender, Windows::ApplicationModel::AppService::AppServiceRequestReceivedEventArgs ^args) +{ + auto messageDeferral = args->GetDeferral(); + + auto responseMessage = ref new ValueSet(); + + if (args->Request->Message != nullptr) + { + if ((args->Request->Message->HasKey(L"SetLedState")) && (args->Request->Message->HasKey(L"PinNumber"))) + { + try + { + auto commandObject = args->Request->Message->Lookup(L"SetLedState"); + String^ command = safe_cast(commandObject); + auto pinNumberObject = args->Request->Message->Lookup(L"PinNumber"); + int pinNumber = safe_cast(pinNumberObject); + auto pin = controller->OpenPin(pinNumber); + pin->SetDriveMode(GpioPinDriveMode::Output); + + if (String::operator==(command, L"SetLedStateOn")) + { + pin->Write(GpioPinValue::High); + responseMessage->Insert(L"Response", L"Success"); + } + else if (String::operator==(command, L"SetLedStateOff")) + { + pin->Write(GpioPinValue::Low); + responseMessage->Insert(L"Response", L"Success"); + } + else + { + responseMessage->Insert(L"Response", L"Request Failed:Invalid SetLedState parameter value."); + } + } + catch (InvalidCastException^ ic) + { + responseMessage->Insert(L"Response", L"Request Failed:Invalid cast exception occurred."); + } + catch (Exception^ e) + { + responseMessage->Insert(L"Response", L"Request Failed:Unknown exception occurred."); + } + } + else + { + responseMessage->Insert(L"Response", L"Request Failed:Invalid request."); + } + } + else + { + responseMessage->Insert(L"Response", L"Failed: Request message is empty."); + } + + args->Request->SendResponseAsync(responseMessage); + + messageDeferral->Complete(); +} diff --git a/samples/AppServiceBlinky/CPP/BlinkyService/BlinkyServiceProvider.h b/samples/AppServiceBlinky/CPP/BlinkyService/BlinkyServiceProvider.h index 0e7dc05f8..a0a9130f6 100644 --- a/samples/AppServiceBlinky/CPP/BlinkyService/BlinkyServiceProvider.h +++ b/samples/AppServiceBlinky/CPP/BlinkyService/BlinkyServiceProvider.h @@ -1,21 +1,21 @@ -#pragma once - -#include "pch.h" - -namespace BlinkyService -{ - [Windows::Foundation::Metadata::WebHostHidden] - public ref class BlinkyServiceProvider sealed : public Windows::ApplicationModel::Background::IBackgroundTask - { - public: - virtual void Run(Windows::ApplicationModel::Background::IBackgroundTaskInstance^ taskInstance); - private: - Platform::Agile serviceDeferral; - Windows::ApplicationModel::AppService::AppServiceConnection ^serviceConnection; - - Windows::Devices::Gpio::GpioController ^controller; - - void OnCanceled(Windows::ApplicationModel::Background::IBackgroundTaskInstance ^sender, Windows::ApplicationModel::Background::BackgroundTaskCancellationReason reason); - void OnRequestReceived(Windows::ApplicationModel::AppService::AppServiceConnection ^sender, Windows::ApplicationModel::AppService::AppServiceRequestReceivedEventArgs ^args); - }; -} +#pragma once + +#include "pch.h" + +namespace BlinkyService +{ + [Windows::Foundation::Metadata::WebHostHidden] + public ref class BlinkyServiceProvider sealed : public Windows::ApplicationModel::Background::IBackgroundTask + { + public: + virtual void Run(Windows::ApplicationModel::Background::IBackgroundTaskInstance^ taskInstance); + private: + Platform::Agile serviceDeferral; + Windows::ApplicationModel::AppService::AppServiceConnection ^serviceConnection; + + Windows::Devices::Gpio::GpioController ^controller; + + void OnCanceled(Windows::ApplicationModel::Background::IBackgroundTaskInstance ^sender, Windows::ApplicationModel::Background::BackgroundTaskCancellationReason reason); + void OnRequestReceived(Windows::ApplicationModel::AppService::AppServiceConnection ^sender, Windows::ApplicationModel::AppService::AppServiceRequestReceivedEventArgs ^args); + }; +} diff --git a/samples/AppServiceBlinky/CPP/BlinkyService/Package.appxmanifest b/samples/AppServiceBlinky/CPP/BlinkyService/Package.appxmanifest index a77a6857c..7feb382d6 100644 --- a/samples/AppServiceBlinky/CPP/BlinkyService/Package.appxmanifest +++ b/samples/AppServiceBlinky/CPP/BlinkyService/Package.appxmanifest @@ -1,54 +1,54 @@ - - - - - - - - - - BlinkyService - msft - Assets\StoreLogo.png - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + BlinkyService + msft + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/AppServiceBlinky/CPP/BlinkyService/pch.cpp b/samples/AppServiceBlinky/CPP/BlinkyService/pch.cpp index ef288d82a..97b544ec1 100644 --- a/samples/AppServiceBlinky/CPP/BlinkyService/pch.cpp +++ b/samples/AppServiceBlinky/CPP/BlinkyService/pch.cpp @@ -1,6 +1,6 @@ -// -// pch.cpp -// Include the standard header and generate the precompiled header. -// - -#include "pch.h" +// +// pch.cpp +// Include the standard header and generate the precompiled header. +// + +#include "pch.h" diff --git a/samples/AppServiceBlinky/CPP/BlinkyService/pch.h b/samples/AppServiceBlinky/CPP/BlinkyService/pch.h index 3fb712067..f32d6802b 100644 --- a/samples/AppServiceBlinky/CPP/BlinkyService/pch.h +++ b/samples/AppServiceBlinky/CPP/BlinkyService/pch.h @@ -1,10 +1,10 @@ -// -// pch.h -// Header for standard system include files. -// - -#pragma once - -#include -#include -#include +// +// pch.h +// Header for standard system include files. +// + +#pragma once + +#include +#include +#include diff --git a/samples/AppServiceBlinky/CPP/README.md b/samples/AppServiceBlinky/CPP/README.md index 8f3de8bc6..96b165869 100644 --- a/samples/AppServiceBlinky/CPP/README.md +++ b/samples/AppServiceBlinky/CPP/README.md @@ -1,224 +1,224 @@ ---- -page_type: sample -urlFragment: appservice-blinky -languages: - - csharp - - cpp -products: - - Windows 10 - - Windows IoT - - Windows 10 IoT Enterprise -description: Create a simple Blinky app service and connect a LED to your Windows IoT Enterprise device. ---- - -# Using an app service to blink an LED -We’ll create a simple Blinky [app service](https://docs.microsoft.com/en-us/windows/uwp/launch-resume/how-to-create-and-consume-an-app-service) and connect a LED to your Windows IoT Enterprise device (Up-Board). We'll also create a simple app service client that blinks the LED. Be aware that the GPIO APIs are only available on the board, so this sample cannot run on your desktop. - -## Set up your hardware -___ -The hardware setup for this sample is the same as the Blinky sample. -Note that the app will not run successfully if it cannot find any available GPIO ports. - -## Load the projects in Visual Studio -___ - -* You can find the source code for this sample by downloading a zip of all of our samples in Windows 10 IoT Enterprise folder and navigating to the `samples-develop\AppServiceBlinky`. -* Make a copy of the folder on your disk and open the projects from Visual Studio. -* BlinkyService.sln implements the app service and must be started first. -* BlinkyClient.sln implements the app service client. -* Verify that the value of connection.PackageFamilyName in StartupTask.cs and MainPage.xaml.cs matches the value output in the output window by BlinkyService. -* If it does not have any value output, you will get the value by marking the breakpoint in debug mode for #StartupTask.cs at System.Diagnostics.Debug.WriteLine("Service closed. Status=" + args.Status.ToString()). - -## Deploy your app - -* * * - -With the application open in Visual Studio 2019, set the architecture in the toolbar dropdown. If you’re building for UP Board, select `x64`. - -### [Generate an app package](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#generate-an-app-package) - -### [Install your app package using an install script](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#install-your-app-package-using-an-install-script) - -### BIOS Settings for UP Board -If you are using an UP Board, you have to setup the BIOS GPIO configuration. - -1. Once you power on the UP board, select the **Del** or **F7** key on your keyboard to enter the BIOS setting. - -1. Navigate to **Boot** > **OS Image ID** tab, and select **Windows 10 IoT Core**. - -1. Navigate to the **Advance** tab and select the **Hat Configuration** and select **GPIO Configuration in Pin Order**. - -1. Configure the Pins you are using in the sample as **INPUT** or **OUTPUT**. - -1. For more information, please review the [UP Board Firmware Settings](https://www.annabooks.com/Articles/Articles_IoT10/Windows-10-IoT-UP-Board-BIOS-RHPROXY-Rev1.3.pdf). - -1. Click the Start button to search for the app by name, and then launch it. - -## Let's look at the code -___ -The code is in 2 projects BlinkyService and BlinkyClient. First we'll look at BlinkyService. - -## Adding an app service -___ -To add an appservice to our background application first we need to open appxmanifest.xml in a text editor and add an extension with Category="windows.AppService" - -```XML - - - - - - - - - - -``` - -Next we'll add a check in the StartupTask::Run method to see if the application is being started as an appservice - -```csharp -//Check to determine whether this activation was caused by an incoming app service connection -var appServiceTrigger = taskInstance.TriggerDetails as AppServiceTriggerDetails; -if (appServiceTrigger != null) -{ - //Verify that the app service connection is requesting the "BlinkyService" that this class provides - if (appServiceTrigger.Name.Equals("BlinkyService")) - { - //Store the connection and subscribe to the "RequestRecieved" event to be notified when clients send messages - connection = appServiceTrigger.AppServiceConnection; - connection.RequestReceived += Connection_RequestReceived; - } - else - { - deferral.Complete(); - } -} -``` - -At the beginning of BlinkyService's StartupTask::Run get the deferral object and set up a Canceled event handler to clean up the deferral on exit. - -```csharp -deferral = taskInstance.GetDeferral(); -taskInstance.Canceled += TaskInstance_Canceled; -``` - -When the Canceled event handler is called Complete the deferral for this instance of the app service if one exists. If the deferral is not completed then the app service process will be killed by the operating system even if other clients still have connections open to the app service. - -```csharp -private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) -{ - if (deferral != null) - { - deferral.Complete(); - deferral = null; - } -} -``` - -Finally we need to handle service requests: - -```csharp -private void Connection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) -{ - var messageDeferral = args.GetDeferral(); - - //The message is provided as a ValueSet (IDictionary + + + + + + + + + +``` + +Next we'll add a check in the StartupTask::Run method to see if the application is being started as an appservice + +```csharp +//Check to determine whether this activation was caused by an incoming app service connection +var appServiceTrigger = taskInstance.TriggerDetails as AppServiceTriggerDetails; +if (appServiceTrigger != null) +{ + //Verify that the app service connection is requesting the "BlinkyService" that this class provides + if (appServiceTrigger.Name.Equals("BlinkyService")) + { + //Store the connection and subscribe to the "RequestRecieved" event to be notified when clients send messages + connection = appServiceTrigger.AppServiceConnection; + connection.RequestReceived += Connection_RequestReceived; + } + else + { + deferral.Complete(); + } +} +``` + +At the beginning of BlinkyService's StartupTask::Run get the deferral object and set up a Canceled event handler to clean up the deferral on exit. + +```csharp +deferral = taskInstance.GetDeferral(); +taskInstance.Canceled += TaskInstance_Canceled; +``` + +When the Canceled event handler is called Complete the deferral for this instance of the app service if one exists. If the deferral is not completed then the app service process will be killed by the operating system even if other clients still have connections open to the app service. + +```csharp +private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) +{ + if (deferral != null) + { + deferral.Complete(); + deferral = null; + } +} +``` + +Finally we need to handle service requests: + +```csharp +private void Connection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) +{ + var messageDeferral = args.GetDeferral(); + + //The message is provided as a ValueSet (IDictionary - - - - Debug - x86 - {44e17c65-15ac-49b2-a8b9-3da936561bcc} - winmdobj - Properties - BlinkyClient - BlinkyClient - en-US - UAP - 10.0.19041.0 - 10.0.15063.0 - 14 - true - 512 - {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - false - BlinkyClient_TemporaryKey.pfx - true - true - win10-arm;win10-arm-aot;win10-x86;win10-x86-aot;win10-x64;win10-x64-aot - - - true - bin\ARM\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - ARM - false - prompt - true - - - bin\ARM\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - ARM - false - prompt - true - true - - - true - bin\x64\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - x64 - false - prompt - true - - - bin\x64\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - x64 - false - prompt - true - true - - - true - bin\x86\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - x86 - false - prompt - true - - - bin\x86\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - x86 - false - prompt - true - true - - - - - - - - Designer - - - - - - - - - - - - - - - - 5.0.0 - - - - 14.0 - - - - + + + + + Debug + x86 + {44e17c65-15ac-49b2-a8b9-3da936561bcc} + winmdobj + Properties + BlinkyClient + BlinkyClient + en-US + UAP + 10.0.19041.0 + 10.0.15063.0 + 14 + true + 512 + {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + false + BlinkyClient_TemporaryKey.pfx + true + true + win10-arm;win10-arm-aot;win10-x86;win10-x86-aot;win10-x64;win10-x64-aot + + + true + bin\ARM\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + ARM + false + prompt + true + + + bin\ARM\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + ARM + false + prompt + true + true + + + true + bin\x64\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + x64 + false + prompt + true + + + bin\x64\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + x64 + false + prompt + true + true + + + true + bin\x86\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + x86 + false + prompt + true + + + bin\x86\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + x86 + false + prompt + true + true + + + + + + + + Designer + + + + + + + + + + + + + + + + 5.0.0 + + + + 14.0 + + + + diff --git a/samples/AppServiceBlinky/CS/BlinkyClient/Package.appxmanifest b/samples/AppServiceBlinky/CS/BlinkyClient/Package.appxmanifest index 33288ff75..89d37e2e4 100644 --- a/samples/AppServiceBlinky/CS/BlinkyClient/Package.appxmanifest +++ b/samples/AppServiceBlinky/CS/BlinkyClient/Package.appxmanifest @@ -1,56 +1,56 @@ - - - - - - - - - - BlinkyClient - Microsoft - Assets\StoreLogo.png - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + BlinkyClient + Microsoft + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/AppServiceBlinky/CS/BlinkyClient/Properties/AssemblyInfo.cs b/samples/AppServiceBlinky/CS/BlinkyClient/Properties/AssemblyInfo.cs index fd1d7d95f..2cc91a33b 100644 --- a/samples/AppServiceBlinky/CS/BlinkyClient/Properties/AssemblyInfo.cs +++ b/samples/AppServiceBlinky/CS/BlinkyClient/Properties/AssemblyInfo.cs @@ -1,29 +1,29 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("BlinkyClient")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("BlinkyClient")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("BlinkyClient")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("BlinkyClient")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] [assembly: ComVisible(false)] \ No newline at end of file diff --git a/samples/AppServiceBlinky/CS/BlinkyClient/Properties/Default.rd.xml b/samples/AppServiceBlinky/CS/BlinkyClient/Properties/Default.rd.xml index 461bc4c13..80a960ce3 100644 --- a/samples/AppServiceBlinky/CS/BlinkyClient/Properties/Default.rd.xml +++ b/samples/AppServiceBlinky/CS/BlinkyClient/Properties/Default.rd.xml @@ -1,31 +1,31 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/AppServiceBlinky/CS/BlinkyClient/StartupTask.cs b/samples/AppServiceBlinky/CS/BlinkyClient/StartupTask.cs index 5115ce860..32f837015 100644 --- a/samples/AppServiceBlinky/CS/BlinkyClient/StartupTask.cs +++ b/samples/AppServiceBlinky/CS/BlinkyClient/StartupTask.cs @@ -1,74 +1,74 @@ -// Copyright (c) Microsoft. All rights reserved. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Net.Http; -using Windows.ApplicationModel.Background; -using Windows.ApplicationModel.AppService; -using Windows.Foundation.Collections; -using Windows.System.Threading; - - -// The Background Application template is documented at http://go.microsoft.com/fwlink/?LinkID=533884&clcid=0x409 - -namespace BlinkyClient -{ - public sealed class StartupTask : IBackgroundTask - { - - AppServiceConnection connection; - BackgroundTaskDeferral deferral; - ThreadPoolTimer timer; - string requestedPinValue; - - - public async void Run(IBackgroundTaskInstance taskInstance) - { - deferral = taskInstance.GetDeferral(); - - - //Connect to the "BlinkyService" implemented in the "BlinkyService" solution - connection = new AppServiceConnection(); - connection.AppServiceName = "BlinkyService"; - connection.PackageFamilyName = "BlinkyService-uwp_2yx4q2bk84nj4"; - AppServiceConnectionStatus status = await connection.OpenAsync(); - - if (status != AppServiceConnectionStatus.Success) - { - deferral.Complete(); - return; - } - - //Send a message with the name "requestedPinValue" and the value "High" - //These work like loosely typed input parameters to a method - requestedPinValue = "High"; - var message = new ValueSet(); - message["requestedPinValue"] = requestedPinValue; - AppServiceResponse response = await connection.SendMessageAsync(message); - - //If the message was successful, start a timer to send alternating requestedPinValues to blink the LED - if (response.Status == AppServiceResponseStatus.Success) - { - timer = ThreadPoolTimer.CreatePeriodicTimer(this.Tick, TimeSpan.FromMilliseconds(500)); - } - - } - - private async void Tick(ThreadPoolTimer timer) - { - if (requestedPinValue.Equals("High")) - { - requestedPinValue = "Low"; - } - else - { - requestedPinValue = "High"; - } - var message = new ValueSet(); - message["requestedPinValue"] = requestedPinValue; - await connection.SendMessageAsync(message); - } - } -} +// Copyright (c) Microsoft. All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Http; +using Windows.ApplicationModel.Background; +using Windows.ApplicationModel.AppService; +using Windows.Foundation.Collections; +using Windows.System.Threading; + + +// The Background Application template is documented at http://go.microsoft.com/fwlink/?LinkID=533884&clcid=0x409 + +namespace BlinkyClient +{ + public sealed class StartupTask : IBackgroundTask + { + + AppServiceConnection connection; + BackgroundTaskDeferral deferral; + ThreadPoolTimer timer; + string requestedPinValue; + + + public async void Run(IBackgroundTaskInstance taskInstance) + { + deferral = taskInstance.GetDeferral(); + + + //Connect to the "BlinkyService" implemented in the "BlinkyService" solution + connection = new AppServiceConnection(); + connection.AppServiceName = "BlinkyService"; + connection.PackageFamilyName = "BlinkyService-uwp_2yx4q2bk84nj4"; + AppServiceConnectionStatus status = await connection.OpenAsync(); + + if (status != AppServiceConnectionStatus.Success) + { + deferral.Complete(); + return; + } + + //Send a message with the name "requestedPinValue" and the value "High" + //These work like loosely typed input parameters to a method + requestedPinValue = "High"; + var message = new ValueSet(); + message["requestedPinValue"] = requestedPinValue; + AppServiceResponse response = await connection.SendMessageAsync(message); + + //If the message was successful, start a timer to send alternating requestedPinValues to blink the LED + if (response.Status == AppServiceResponseStatus.Success) + { + timer = ThreadPoolTimer.CreatePeriodicTimer(this.Tick, TimeSpan.FromMilliseconds(500)); + } + + } + + private async void Tick(ThreadPoolTimer timer) + { + if (requestedPinValue.Equals("High")) + { + requestedPinValue = "Low"; + } + else + { + requestedPinValue = "High"; + } + var message = new ValueSet(); + message["requestedPinValue"] = requestedPinValue; + await connection.SendMessageAsync(message); + } + } +} diff --git a/samples/AppServiceBlinky/CS/BlinkyService.sln b/samples/AppServiceBlinky/CS/BlinkyService.sln index bbef05c5f..0a1f17764 100644 --- a/samples/AppServiceBlinky/CS/BlinkyService.sln +++ b/samples/AppServiceBlinky/CS/BlinkyService.sln @@ -1,40 +1,40 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlinkyService", "BlinkyService\BlinkyService.csproj", "{A939FEA0-B875-4654-8366-3BA23ADA12D1}" -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 - {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Debug|ARM.ActiveCfg = Debug|ARM - {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Debug|ARM.Build.0 = Debug|ARM - {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Debug|ARM.Deploy.0 = Debug|ARM - {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Debug|x64.ActiveCfg = Debug|x64 - {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Debug|x64.Build.0 = Debug|x64 - {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Debug|x64.Deploy.0 = Debug|x64 - {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Debug|x86.ActiveCfg = Debug|x86 - {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Debug|x86.Build.0 = Debug|x86 - {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Debug|x86.Deploy.0 = Debug|x86 - {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Release|ARM.ActiveCfg = Release|ARM - {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Release|ARM.Build.0 = Release|ARM - {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Release|ARM.Deploy.0 = Release|ARM - {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Release|x64.ActiveCfg = Release|x64 - {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Release|x64.Build.0 = Release|x64 - {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Release|x64.Deploy.0 = Release|x64 - {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Release|x86.ActiveCfg = Release|x86 - {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Release|x86.Build.0 = Release|x86 - {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Release|x86.Deploy.0 = Release|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.24720.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlinkyService", "BlinkyService\BlinkyService.csproj", "{A939FEA0-B875-4654-8366-3BA23ADA12D1}" +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 + {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Debug|ARM.ActiveCfg = Debug|ARM + {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Debug|ARM.Build.0 = Debug|ARM + {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Debug|ARM.Deploy.0 = Debug|ARM + {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Debug|x64.ActiveCfg = Debug|x64 + {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Debug|x64.Build.0 = Debug|x64 + {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Debug|x64.Deploy.0 = Debug|x64 + {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Debug|x86.ActiveCfg = Debug|x86 + {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Debug|x86.Build.0 = Debug|x86 + {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Debug|x86.Deploy.0 = Debug|x86 + {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Release|ARM.ActiveCfg = Release|ARM + {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Release|ARM.Build.0 = Release|ARM + {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Release|ARM.Deploy.0 = Release|ARM + {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Release|x64.ActiveCfg = Release|x64 + {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Release|x64.Build.0 = Release|x64 + {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Release|x64.Deploy.0 = Release|x64 + {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Release|x86.ActiveCfg = Release|x86 + {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Release|x86.Build.0 = Release|x86 + {A939FEA0-B875-4654-8366-3BA23ADA12D1}.Release|x86.Deploy.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/AppServiceBlinky/CS/BlinkyService/BlinkyService.csproj b/samples/AppServiceBlinky/CS/BlinkyService/BlinkyService.csproj index 9b6a19451..c03120c3f 100644 --- a/samples/AppServiceBlinky/CS/BlinkyService/BlinkyService.csproj +++ b/samples/AppServiceBlinky/CS/BlinkyService/BlinkyService.csproj @@ -1,131 +1,131 @@ - - - - - Debug - x86 - {A939FEA0-B875-4654-8366-3BA23ADA12D1} - winmdobj - Properties - BlinkyService - BlinkyService - en-US - UAP - 10.0.19041.0 - 10.0.15063.0 - 14 - true - 512 - {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - false - BlinkyService_TemporaryKey.pfx - true - true - win10-arm;win10-arm-aot;win10-x86;win10-x86-aot;win10-x64;win10-x64-aot - - - true - bin\ARM\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - ARM - false - prompt - true - - - bin\ARM\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - ARM - false - prompt - true - true - - - true - bin\x64\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - x64 - false - prompt - true - - - bin\x64\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - x64 - false - prompt - true - true - - - true - bin\x86\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - x86 - false - prompt - true - - - bin\x86\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - x86 - false - prompt - true - true - - - - - - - - Designer - - - - - - - - - - - - - - - - 5.0.0 - - - - 14.0 - - - - + + + + + Debug + x86 + {A939FEA0-B875-4654-8366-3BA23ADA12D1} + winmdobj + Properties + BlinkyService + BlinkyService + en-US + UAP + 10.0.19041.0 + 10.0.15063.0 + 14 + true + 512 + {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + false + BlinkyService_TemporaryKey.pfx + true + true + win10-arm;win10-arm-aot;win10-x86;win10-x86-aot;win10-x64;win10-x64-aot + + + true + bin\ARM\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + ARM + false + prompt + true + + + bin\ARM\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + ARM + false + prompt + true + true + + + true + bin\x64\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + x64 + false + prompt + true + + + bin\x64\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + x64 + false + prompt + true + true + + + true + bin\x86\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + x86 + false + prompt + true + + + bin\x86\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + x86 + false + prompt + true + true + + + + + + + + Designer + + + + + + + + + + + + + + + + 5.0.0 + + + + 14.0 + + + + diff --git a/samples/AppServiceBlinky/CS/BlinkyService/Package.appxmanifest b/samples/AppServiceBlinky/CS/BlinkyService/Package.appxmanifest index 2dfca96a6..ba46d4876 100644 --- a/samples/AppServiceBlinky/CS/BlinkyService/Package.appxmanifest +++ b/samples/AppServiceBlinky/CS/BlinkyService/Package.appxmanifest @@ -1,39 +1,39 @@ - - - - - - BlinkyService - Microsoft - Assets\StoreLogo.png - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + BlinkyService + Microsoft + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/AppServiceBlinky/CS/BlinkyService/Properties/AssemblyInfo.cs b/samples/AppServiceBlinky/CS/BlinkyService/Properties/AssemblyInfo.cs index 46f4af7f7..639c0b571 100644 --- a/samples/AppServiceBlinky/CS/BlinkyService/Properties/AssemblyInfo.cs +++ b/samples/AppServiceBlinky/CS/BlinkyService/Properties/AssemblyInfo.cs @@ -1,29 +1,29 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("BlinkyService")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("BlinkyService")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("BlinkyService")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("BlinkyService")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] [assembly: ComVisible(false)] \ No newline at end of file diff --git a/samples/AppServiceBlinky/CS/BlinkyService/Properties/Default.rd.xml b/samples/AppServiceBlinky/CS/BlinkyService/Properties/Default.rd.xml index 461bc4c13..80a960ce3 100644 --- a/samples/AppServiceBlinky/CS/BlinkyService/Properties/Default.rd.xml +++ b/samples/AppServiceBlinky/CS/BlinkyService/Properties/Default.rd.xml @@ -1,31 +1,31 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/AppServiceBlinky/CS/BlinkyService/StartupTask.cs b/samples/AppServiceBlinky/CS/BlinkyService/StartupTask.cs index 274e444dd..d7ed08876 100644 --- a/samples/AppServiceBlinky/CS/BlinkyService/StartupTask.cs +++ b/samples/AppServiceBlinky/CS/BlinkyService/StartupTask.cs @@ -1,112 +1,112 @@ -// Copyright (c) Microsoft. All rights reserved. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Net.Http; -using Windows.ApplicationModel.Background; -using Windows.ApplicationModel.AppService; -using Windows.Foundation.Collections; -using Windows.Devices.Gpio; - - -// The Background Application template is documented at http://go.microsoft.com/fwlink/?LinkID=533884&clcid=0x409 - -namespace BlinkyService -{ - public sealed class StartupTask : IBackgroundTask - { - //Gpio Pin and Controller are shared between all connections. - private static GpioPin pin; - private static GpioController controller; - - //Each client gets it's own connection - BackgroundTaskDeferral deferral; - AppServiceConnection connection; - - public async void Run(IBackgroundTaskInstance taskInstance) - { - deferral = taskInstance.GetDeferral(); - taskInstance.Canceled += TaskInstance_Canceled; - - //Print out the FamilyName - //This string is needed to connect from a client - System.Diagnostics.Debug.WriteLine(Windows.ApplicationModel.Package.Current.Id.FamilyName); - - - //If this is the first time this background task is activated, init the gpio controller and pin - if (pin == null && controller == null) - { - controller = await GpioController.GetDefaultAsync(); - pin = controller.OpenPin(5); - pin.SetDriveMode(GpioPinDriveMode.Output); - } - - //Check to determine whether this activation was caused by an incoming app service connection - var appServiceTrigger = taskInstance.TriggerDetails as AppServiceTriggerDetails; - if (appServiceTrigger != null) - { - //Verify that the app service connection is requesting the "BlinkyService" that this class provides - if (appServiceTrigger.Name.Equals("BlinkyService")) - { - //Store the connection and subscribe to the "RequestRecieved" event to be notified when clients send messages - connection = appServiceTrigger.AppServiceConnection; - connection.RequestReceived += Connection_RequestReceived; - } - else - { - deferral.Complete(); - } - - } - - } - - private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) - { - if (deferral != null) - { - deferral.Complete(); - deferral = null; - } - } - - private void Connection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) - { - var messageDeferral = args.GetDeferral(); - - //The message is provided as a ValueSet (IDictionary - - - - - - - - - -``` - -Next we'll add a check in the StartupTask::Run method to see if the application is being started as an appservice - -```csharp -//Check to determine whether this activation was caused by an incoming app service connection -var appServiceTrigger = taskInstance.TriggerDetails as AppServiceTriggerDetails; -if (appServiceTrigger != null) -{ - //Verify that the app service connection is requesting the "BlinkyService" that this class provides - if (appServiceTrigger.Name.Equals("BlinkyService")) - { - //Store the connection and subscribe to the "RequestRecieved" event to be notified when clients send messages - connection = appServiceTrigger.AppServiceConnection; - connection.RequestReceived += Connection_RequestReceived; - } - else - { - deferral.Complete(); - } -} -``` - -At the beginning of BlinkyService's StartupTask::Run get the deferral object and set up a Canceled event handler to clean up the deferral on exit. - -```csharp -deferral = taskInstance.GetDeferral(); -taskInstance.Canceled += TaskInstance_Canceled; -``` - -When the Canceled event handler is called Complete the deferral for this instance of the app service if one exists. If the deferral is not completed then the app service process will be killed by the operating system even if other clients still have connections open to the app service. - -```csharp -private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) -{ - if (deferral != null) - { - deferral.Complete(); - deferral = null; - } -} -``` - -Finally we need to handle service requests: - -```csharp -private void Connection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) -{ - var messageDeferral = args.GetDeferral(); - - //The message is provided as a ValueSet (IDictionary + + + + + + + + + +``` + +Next we'll add a check in the StartupTask::Run method to see if the application is being started as an appservice + +```csharp +//Check to determine whether this activation was caused by an incoming app service connection +var appServiceTrigger = taskInstance.TriggerDetails as AppServiceTriggerDetails; +if (appServiceTrigger != null) +{ + //Verify that the app service connection is requesting the "BlinkyService" that this class provides + if (appServiceTrigger.Name.Equals("BlinkyService")) + { + //Store the connection and subscribe to the "RequestRecieved" event to be notified when clients send messages + connection = appServiceTrigger.AppServiceConnection; + connection.RequestReceived += Connection_RequestReceived; + } + else + { + deferral.Complete(); + } +} +``` + +At the beginning of BlinkyService's StartupTask::Run get the deferral object and set up a Canceled event handler to clean up the deferral on exit. + +```csharp +deferral = taskInstance.GetDeferral(); +taskInstance.Canceled += TaskInstance_Canceled; +``` + +When the Canceled event handler is called Complete the deferral for this instance of the app service if one exists. If the deferral is not completed then the app service process will be killed by the operating system even if other clients still have connections open to the app service. + +```csharp +private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) +{ + if (deferral != null) + { + deferral.Complete(); + deferral = null; + } +} +``` + +Finally we need to handle service requests: + +```csharp +private void Connection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) +{ + var messageDeferral = args.GetDeferral(); + + //The message is provided as a ValueSet (IDictionary - - - - - - - - - -``` - -Next we'll add a check in the StartupTask::Run method to see if the application is being started as an appservice - -```csharp -//Check to determine whether this activation was caused by an incoming app service connection -var appServiceTrigger = taskInstance.TriggerDetails as AppServiceTriggerDetails; -if (appServiceTrigger != null) -{ - //Verify that the app service connection is requesting the "BlinkyService" that this class provides - if (appServiceTrigger.Name.Equals("BlinkyService")) - { - //Store the connection and subscribe to the "RequestRecieved" event to be notified when clients send messages - connection = appServiceTrigger.AppServiceConnection; - connection.RequestReceived += Connection_RequestReceived; - } - else - { - deferral.Complete(); - } -} -``` - -At the beginning of BlinkyService's StartupTask::Run get the deferral object and set up a Canceled event handler to clean up the deferral on exit. - -```csharp -deferral = taskInstance.GetDeferral(); -taskInstance.Canceled += TaskInstance_Canceled; -``` - -When the Canceled event handler is called Complete the deferral for this instance of the app service if one exists. If the deferral is not completed then the app service process will be killed by the operating system even if other clients still have connections open to the app service. - -```csharp -private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) -{ - if (deferral != null) - { - deferral.Complete(); - deferral = null; - } -} -``` - -Finally we need to handle service requests: - -```csharp -private void Connection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) -{ - var messageDeferral = args.GetDeferral(); - - //The message is provided as a ValueSet (IDictionary + + + + + + + + + +``` + +Next we'll add a check in the StartupTask::Run method to see if the application is being started as an appservice + +```csharp +//Check to determine whether this activation was caused by an incoming app service connection +var appServiceTrigger = taskInstance.TriggerDetails as AppServiceTriggerDetails; +if (appServiceTrigger != null) +{ + //Verify that the app service connection is requesting the "BlinkyService" that this class provides + if (appServiceTrigger.Name.Equals("BlinkyService")) + { + //Store the connection and subscribe to the "RequestRecieved" event to be notified when clients send messages + connection = appServiceTrigger.AppServiceConnection; + connection.RequestReceived += Connection_RequestReceived; + } + else + { + deferral.Complete(); + } +} +``` + +At the beginning of BlinkyService's StartupTask::Run get the deferral object and set up a Canceled event handler to clean up the deferral on exit. + +```csharp +deferral = taskInstance.GetDeferral(); +taskInstance.Canceled += TaskInstance_Canceled; +``` + +When the Canceled event handler is called Complete the deferral for this instance of the app service if one exists. If the deferral is not completed then the app service process will be killed by the operating system even if other clients still have connections open to the app service. + +```csharp +private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) +{ + if (deferral != null) + { + deferral.Complete(); + deferral = null; + } +} +``` + +Finally we need to handle service requests: + +```csharp +private void Connection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) +{ + var messageDeferral = args.GetDeferral(); + + //The message is provided as a ValueSet (IDictionary - - - - Debug - x86 - {90830ed9-f52a-41aa-bc4c-3d9973d57d51} - winmdobj - Properties - NotepadClientBackgroundApplication - NotepadClientBackgroundApplication - en-US - UAP - 10.0.19041.0 - 10.0.15063.0 - 14 - true - 512 - {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - false - NotepadClientBackgroundApplication_TemporaryKey.pfx - true - true - win10-arm;win10-arm-aot;win10-x86;win10-x86-aot;win10-x64;win10-x64-aot - - - true - bin\ARM\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - ARM - false - prompt - true - - - bin\ARM\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - ARM - false - prompt - true - true - - - true - bin\x64\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - x64 - false - prompt - true - - - bin\x64\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - x64 - false - prompt - true - true - - - true - bin\x86\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - x86 - false - prompt - true - - - bin\x86\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - x86 - false - prompt - true - true - - - - - - - - Designer - - - - - - - - - - - - - - - - 5.0.0 - - - - 14.0 - - - - + + + + + Debug + x86 + {90830ed9-f52a-41aa-bc4c-3d9973d57d51} + winmdobj + Properties + NotepadClientBackgroundApplication + NotepadClientBackgroundApplication + en-US + UAP + 10.0.19041.0 + 10.0.15063.0 + 14 + true + 512 + {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + false + NotepadClientBackgroundApplication_TemporaryKey.pfx + true + true + win10-arm;win10-arm-aot;win10-x86;win10-x86-aot;win10-x64;win10-x64-aot + + + true + bin\ARM\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + ARM + false + prompt + true + + + bin\ARM\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + ARM + false + prompt + true + true + + + true + bin\x64\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + x64 + false + prompt + true + + + bin\x64\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + x64 + false + prompt + true + true + + + true + bin\x86\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + x86 + false + prompt + true + + + bin\x86\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + x86 + false + prompt + true + true + + + + + + + + Designer + + + + + + + + + + + + + + + + 5.0.0 + + + + 14.0 + + + + diff --git a/samples/AppServiceSharedNotepad/CS/NotepadClientBackgroundApplication/Package.appxmanifest b/samples/AppServiceSharedNotepad/CS/NotepadClientBackgroundApplication/Package.appxmanifest index 5007e7f95..1b8a507c9 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadClientBackgroundApplication/Package.appxmanifest +++ b/samples/AppServiceSharedNotepad/CS/NotepadClientBackgroundApplication/Package.appxmanifest @@ -1,56 +1,56 @@ - - - - - - - - - - NotepadClientBackgroundApplication - Microsoft - Assets\StoreLogo.png - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + NotepadClientBackgroundApplication + Microsoft + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/AppServiceSharedNotepad/CS/NotepadClientBackgroundApplication/Properties/AssemblyInfo.cs b/samples/AppServiceSharedNotepad/CS/NotepadClientBackgroundApplication/Properties/AssemblyInfo.cs index ea9a165e3..914b49db7 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadClientBackgroundApplication/Properties/AssemblyInfo.cs +++ b/samples/AppServiceSharedNotepad/CS/NotepadClientBackgroundApplication/Properties/AssemblyInfo.cs @@ -1,29 +1,29 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("NotepadClientBackgroundApplication")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("NotepadClientBackgroundApplication")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NotepadClientBackgroundApplication")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("NotepadClientBackgroundApplication")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] [assembly: ComVisible(false)] \ No newline at end of file diff --git a/samples/AppServiceSharedNotepad/CS/NotepadClientBackgroundApplication/Properties/Default.rd.xml b/samples/AppServiceSharedNotepad/CS/NotepadClientBackgroundApplication/Properties/Default.rd.xml index 461bc4c13..80a960ce3 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadClientBackgroundApplication/Properties/Default.rd.xml +++ b/samples/AppServiceSharedNotepad/CS/NotepadClientBackgroundApplication/Properties/Default.rd.xml @@ -1,31 +1,31 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/AppServiceSharedNotepad/CS/NotepadClientBackgroundApplication/StartupTask.cs b/samples/AppServiceSharedNotepad/CS/NotepadClientBackgroundApplication/StartupTask.cs index 48d38111c..ac7666d33 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadClientBackgroundApplication/StartupTask.cs +++ b/samples/AppServiceSharedNotepad/CS/NotepadClientBackgroundApplication/StartupTask.cs @@ -1,81 +1,81 @@ -// Copyright (c) Microsoft. All rights reserved. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Net.Http; -using Windows.ApplicationModel.Background; -using Windows.ApplicationModel.AppService; -using Windows.Foundation.Collections; -using Windows.System.Threading; - -// The Background Application template is documented at http://go.microsoft.com/fwlink/?LinkID=533884&clcid=0x409 - -namespace NotepadClientBackgroundApplication -{ - public sealed class StartupTask : IBackgroundTask - { - AppServiceConnection connection; - BackgroundTaskDeferral deferral; - ThreadPoolTimer timer; - int count = 1; - - //For a detailed introduction to AppServices on IoT, see the "AppServiceBlinky" sample - //This app connects to the service and pushes messages every 30 seconds. - public async void Run(IBackgroundTaskInstance taskInstance) - { - deferral = taskInstance.GetDeferral(); - taskInstance.Canceled += TaskInstance_Canceled; - - connection = new AppServiceConnection(); - connection.AppServiceName = "NotepadService"; - connection.PackageFamilyName = "NotepadService-uwp_2yx4q2bk84nj4"; - AppServiceConnectionStatus status = await connection.OpenAsync(); - if (status != AppServiceConnectionStatus.Success) - { - return; - } - - var message = new ValueSet(); - - //Send a message with an operation type of "postNote" and the desired "newNote" - //Then, if successful, start a timer and send a new message periodically - message.Add("operation", "postNote"); - message.Add("newNote", "Hello, this is my first note. I will add another one every 30 seconds"); - AppServiceResponse response = await connection.SendMessageAsync(message); - if (response.Status == AppServiceResponseStatus.Success) - { - var result = response.Message["Result"].ToString(); - timer = ThreadPoolTimer.CreatePeriodicTimer(this.Tick, TimeSpan.FromSeconds(30)); - System.Diagnostics.Debug.WriteLine(result); - } - - - } - - private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) - { - if (deferral != null) - { - deferral.Complete(); - deferral = null; - } - } - - public async void Tick(ThreadPoolTimer sender) - { - count++; - var message = new ValueSet(); - message.Add("operation", "postNote"); - message.Add("newNote", "Here is new note #" + count.ToString()); - AppServiceResponse response = await connection.SendMessageAsync(message); - if (response.Status == AppServiceResponseStatus.Success) - { - var result = response.Message["Result"].ToString(); - System.Diagnostics.Debug.WriteLine(result); - - } - } - } -} +// Copyright (c) Microsoft. All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Http; +using Windows.ApplicationModel.Background; +using Windows.ApplicationModel.AppService; +using Windows.Foundation.Collections; +using Windows.System.Threading; + +// The Background Application template is documented at http://go.microsoft.com/fwlink/?LinkID=533884&clcid=0x409 + +namespace NotepadClientBackgroundApplication +{ + public sealed class StartupTask : IBackgroundTask + { + AppServiceConnection connection; + BackgroundTaskDeferral deferral; + ThreadPoolTimer timer; + int count = 1; + + //For a detailed introduction to AppServices on IoT, see the "AppServiceBlinky" sample + //This app connects to the service and pushes messages every 30 seconds. + public async void Run(IBackgroundTaskInstance taskInstance) + { + deferral = taskInstance.GetDeferral(); + taskInstance.Canceled += TaskInstance_Canceled; + + connection = new AppServiceConnection(); + connection.AppServiceName = "NotepadService"; + connection.PackageFamilyName = "NotepadService-uwp_2yx4q2bk84nj4"; + AppServiceConnectionStatus status = await connection.OpenAsync(); + if (status != AppServiceConnectionStatus.Success) + { + return; + } + + var message = new ValueSet(); + + //Send a message with an operation type of "postNote" and the desired "newNote" + //Then, if successful, start a timer and send a new message periodically + message.Add("operation", "postNote"); + message.Add("newNote", "Hello, this is my first note. I will add another one every 30 seconds"); + AppServiceResponse response = await connection.SendMessageAsync(message); + if (response.Status == AppServiceResponseStatus.Success) + { + var result = response.Message["Result"].ToString(); + timer = ThreadPoolTimer.CreatePeriodicTimer(this.Tick, TimeSpan.FromSeconds(30)); + System.Diagnostics.Debug.WriteLine(result); + } + + + } + + private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) + { + if (deferral != null) + { + deferral.Complete(); + deferral = null; + } + } + + public async void Tick(ThreadPoolTimer sender) + { + count++; + var message = new ValueSet(); + message.Add("operation", "postNote"); + message.Add("newNote", "Here is new note #" + count.ToString()); + AppServiceResponse response = await connection.SendMessageAsync(message); + if (response.Status == AppServiceResponseStatus.Success) + { + var result = response.Message["Result"].ToString(); + System.Diagnostics.Debug.WriteLine(result); + + } + } + } +} diff --git a/samples/AppServiceSharedNotepad/CS/NotepadService.sln b/samples/AppServiceSharedNotepad/CS/NotepadService.sln index 955e69d88..825a30ea8 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadService.sln +++ b/samples/AppServiceSharedNotepad/CS/NotepadService.sln @@ -1,40 +1,40 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NotepadService", "NotepadService\NotepadService.csproj", "{F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}" -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 - {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Debug|ARM.ActiveCfg = Debug|ARM - {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Debug|ARM.Build.0 = Debug|ARM - {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Debug|ARM.Deploy.0 = Debug|ARM - {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Debug|x64.ActiveCfg = Debug|x64 - {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Debug|x64.Build.0 = Debug|x64 - {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Debug|x64.Deploy.0 = Debug|x64 - {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Debug|x86.ActiveCfg = Debug|x86 - {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Debug|x86.Build.0 = Debug|x86 - {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Debug|x86.Deploy.0 = Debug|x86 - {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Release|ARM.ActiveCfg = Release|ARM - {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Release|ARM.Build.0 = Release|ARM - {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Release|ARM.Deploy.0 = Release|ARM - {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Release|x64.ActiveCfg = Release|x64 - {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Release|x64.Build.0 = Release|x64 - {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Release|x64.Deploy.0 = Release|x64 - {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Release|x86.ActiveCfg = Release|x86 - {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Release|x86.Build.0 = Release|x86 - {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Release|x86.Deploy.0 = Release|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.24720.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NotepadService", "NotepadService\NotepadService.csproj", "{F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}" +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 + {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Debug|ARM.ActiveCfg = Debug|ARM + {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Debug|ARM.Build.0 = Debug|ARM + {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Debug|ARM.Deploy.0 = Debug|ARM + {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Debug|x64.ActiveCfg = Debug|x64 + {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Debug|x64.Build.0 = Debug|x64 + {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Debug|x64.Deploy.0 = Debug|x64 + {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Debug|x86.ActiveCfg = Debug|x86 + {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Debug|x86.Build.0 = Debug|x86 + {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Debug|x86.Deploy.0 = Debug|x86 + {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Release|ARM.ActiveCfg = Release|ARM + {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Release|ARM.Build.0 = Release|ARM + {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Release|ARM.Deploy.0 = Release|ARM + {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Release|x64.ActiveCfg = Release|x64 + {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Release|x64.Build.0 = Release|x64 + {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Release|x64.Deploy.0 = Release|x64 + {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Release|x86.ActiveCfg = Release|x86 + {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Release|x86.Build.0 = Release|x86 + {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D}.Release|x86.Deploy.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/AppServiceSharedNotepad/CS/NotepadService/Notepad.cs b/samples/AppServiceSharedNotepad/CS/NotepadService/Notepad.cs index d179a8c02..fac82c4ef 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadService/Notepad.cs +++ b/samples/AppServiceSharedNotepad/CS/NotepadService/Notepad.cs @@ -1,82 +1,82 @@ -// Copyright (c) Microsoft. All rights reserved. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Windows.Devices.Gpio; - -namespace NotepadService -{ - internal class Notepad - { - List notes; - bool newNotes; - GpioPin newNotesPin; - - public Notepad() - { - notes = new List(); - newNotes = false; - } - - public async Task InitGpioPin() - { - var controller = await GpioController.GetDefaultAsync(); - newNotesPin = controller.OpenPin(5); - newNotesPin.Write(GpioPinValue.Low); - newNotesPin.SetDriveMode(GpioPinDriveMode.Output); - } - - public async Task AddNote(string note) - { - if (newNotesPin == null) - { - await InitGpioPin(); - } - notes.Add(note); - NewNotesAvailable = true; - if (NoteAdded != null) - { - NoteAdded.Invoke(this,new EventArgs()); - } - } - - public bool NewNotesAvailable - { - get - { - return newNotes; - } - set - { - bool changed = value != newNotes; - newNotes = value; - if (newNotes) - { - newNotesPin.Write(GpioPinValue.High); - } - else - { - newNotesPin.Write(GpioPinValue.Low); - } - if (changed && NewNoteStateChanged!= null) - { - NewNoteStateChanged.Invoke(this, new EventArgs()); - } - - } - } - - - public List GetNotes() - { - NewNotesAvailable = false; - return notes; - } - - public event EventHandler NoteAdded; - public event EventHandler NewNoteStateChanged; - } -} +// Copyright (c) Microsoft. All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.Devices.Gpio; + +namespace NotepadService +{ + internal class Notepad + { + List notes; + bool newNotes; + GpioPin newNotesPin; + + public Notepad() + { + notes = new List(); + newNotes = false; + } + + public async Task InitGpioPin() + { + var controller = await GpioController.GetDefaultAsync(); + newNotesPin = controller.OpenPin(5); + newNotesPin.Write(GpioPinValue.Low); + newNotesPin.SetDriveMode(GpioPinDriveMode.Output); + } + + public async Task AddNote(string note) + { + if (newNotesPin == null) + { + await InitGpioPin(); + } + notes.Add(note); + NewNotesAvailable = true; + if (NoteAdded != null) + { + NoteAdded.Invoke(this,new EventArgs()); + } + } + + public bool NewNotesAvailable + { + get + { + return newNotes; + } + set + { + bool changed = value != newNotes; + newNotes = value; + if (newNotes) + { + newNotesPin.Write(GpioPinValue.High); + } + else + { + newNotesPin.Write(GpioPinValue.Low); + } + if (changed && NewNoteStateChanged!= null) + { + NewNoteStateChanged.Invoke(this, new EventArgs()); + } + + } + } + + + public List GetNotes() + { + NewNotesAvailable = false; + return notes; + } + + public event EventHandler NoteAdded; + public event EventHandler NewNoteStateChanged; + } +} diff --git a/samples/AppServiceSharedNotepad/CS/NotepadService/NotepadService.csproj b/samples/AppServiceSharedNotepad/CS/NotepadService/NotepadService.csproj index 9f70f15a0..16cd5fba7 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadService/NotepadService.csproj +++ b/samples/AppServiceSharedNotepad/CS/NotepadService/NotepadService.csproj @@ -1,132 +1,132 @@ - - - - - Debug - x86 - {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D} - winmdobj - Properties - NotepadService - NotepadService - en-US - UAP - 10.0.19041.0 - 10.0.15063.0 - 14 - true - 512 - {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - false - NotepadService_TemporaryKey.pfx - true - true - win10-arm;win10-arm-aot;win10-x86;win10-x86-aot;win10-x64;win10-x64-aot - - - true - bin\ARM\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - ARM - false - prompt - true - - - bin\ARM\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - ARM - false - prompt - true - true - - - true - bin\x64\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - x64 - false - prompt - true - - - bin\x64\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - x64 - false - prompt - true - true - - - true - bin\x86\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - x86 - false - prompt - true - - - bin\x86\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - x86 - false - prompt - true - true - - - - - - - - - Designer - - - - - - - - - - - - - - - - 5.0.0 - - - - 14.0 - - - - + + + + + Debug + x86 + {F91C6FE1-FDE9-4C49-8501-6FC8B3366A8D} + winmdobj + Properties + NotepadService + NotepadService + en-US + UAP + 10.0.19041.0 + 10.0.15063.0 + 14 + true + 512 + {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + false + NotepadService_TemporaryKey.pfx + true + true + win10-arm;win10-arm-aot;win10-x86;win10-x86-aot;win10-x64;win10-x64-aot + + + true + bin\ARM\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + ARM + false + prompt + true + + + bin\ARM\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + ARM + false + prompt + true + true + + + true + bin\x64\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + x64 + false + prompt + true + + + bin\x64\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + x64 + false + prompt + true + true + + + true + bin\x86\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + x86 + false + prompt + true + + + bin\x86\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + x86 + false + prompt + true + true + + + + + + + + + Designer + + + + + + + + + + + + + + + + 5.0.0 + + + + 14.0 + + + + diff --git a/samples/AppServiceSharedNotepad/CS/NotepadService/Package.appxmanifest b/samples/AppServiceSharedNotepad/CS/NotepadService/Package.appxmanifest index 7f47ba9b2..54af52c25 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadService/Package.appxmanifest +++ b/samples/AppServiceSharedNotepad/CS/NotepadService/Package.appxmanifest @@ -1,40 +1,40 @@ - - - - - - NotepadService - Microsoft - Assets\StoreLogo.png - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + NotepadService + Microsoft + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/AppServiceSharedNotepad/CS/NotepadService/Properties/AssemblyInfo.cs b/samples/AppServiceSharedNotepad/CS/NotepadService/Properties/AssemblyInfo.cs index 666a21ccd..9195139e0 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadService/Properties/AssemblyInfo.cs +++ b/samples/AppServiceSharedNotepad/CS/NotepadService/Properties/AssemblyInfo.cs @@ -1,29 +1,29 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("NotepadService")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("NotepadService")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NotepadService")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("NotepadService")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] [assembly: ComVisible(false)] \ No newline at end of file diff --git a/samples/AppServiceSharedNotepad/CS/NotepadService/Properties/Default.rd.xml b/samples/AppServiceSharedNotepad/CS/NotepadService/Properties/Default.rd.xml index 461bc4c13..80a960ce3 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadService/Properties/Default.rd.xml +++ b/samples/AppServiceSharedNotepad/CS/NotepadService/Properties/Default.rd.xml @@ -1,31 +1,31 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/AppServiceSharedNotepad/CS/NotepadService/StartupTask.cs b/samples/AppServiceSharedNotepad/CS/NotepadService/StartupTask.cs index 80988f606..a9dff427e 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadService/StartupTask.cs +++ b/samples/AppServiceSharedNotepad/CS/NotepadService/StartupTask.cs @@ -1,109 +1,109 @@ -// Copyright (c) Microsoft. All rights reserved. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Net.Http; -using Windows.ApplicationModel.Background; -using Windows.ApplicationModel.AppService; -using Windows.Foundation.Collections; - -// The Background Application template is documented at http://go.microsoft.com/fwlink/?LinkID=533884&clcid=0x409 - -namespace NotepadService -{ - // See the "AppServiceBlinky" sample for a basic introduction to AppServices for IoT devices - // Each connection causes a new instance to be spun up in the same process - public sealed class StartupTask : IBackgroundTask - { - // Notepad is static to allow a single instance to be shared among all connections - private static Notepad notePad; - BackgroundTaskDeferral serviceDeferral; - AppServiceConnection appServiceConnection; - - public void Run(IBackgroundTaskInstance taskInstance) - { - - serviceDeferral = taskInstance.GetDeferral(); - taskInstance.Canceled += TaskInstance_Canceled; - - System.Diagnostics.Debug.WriteLine(Windows.ApplicationModel.Package.Current.Id.FamilyName); - - if (notePad == null) - { - notePad = new Notepad(); - } - - - var appServiceTrigger = taskInstance.TriggerDetails as AppServiceTriggerDetails; - - if (appServiceTrigger != null) - { - if (appServiceTrigger.Name.Equals("NotepadService")) - { - appServiceConnection = appServiceTrigger.AppServiceConnection; - appServiceConnection.RequestReceived += AppServiceConnection_RequestReceived; - appServiceConnection.ServiceClosed += AppServiceConnection_ServiceClosed; - notePad.NoteAdded += NotePad_NoteAdded; - } - else - { - serviceDeferral.Complete(); - } - } - } - - private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) - { - if (serviceDeferral != null) - { - serviceDeferral.Complete(); - serviceDeferral = null; - } - } - - private void AppServiceConnection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args) - { - System.Diagnostics.Debug.WriteLine("Service closed. Status=" + args.Status.ToString()); - } - - // Every time the underlying notepad gets a new note, send a message back to the client indicating that a new message is available - private async void NotePad_NoteAdded(object sender, EventArgs e) - { - ValueSet message = new ValueSet(); - message.Add("operation", "newMessagesAdded"); - await appServiceConnection.SendMessageAsync(message); - } - - // This AppService supports recieving two types of request: "postNote" and "getMessages" - // When a note is sent from the clients the service will pass it to the shared notepad - // and send a confirmation response to the client - // When the client requests messages the repsonse will contain a string[] of all the messages on the notepad - private async void AppServiceConnection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) - { - var messageDefferal = args.GetDeferral(); - var message = args.Request.Message; - string operation = (string)message["operation"]; - if (operation.Equals("postNote")) - { - await notePad.AddNote((message["newNote"].ToString())); - ValueSet returnMessage = new ValueSet(); - returnMessage.Add("Result", "Note Added"); - var responseStatus = await args.Request.SendResponseAsync(returnMessage); - System.Diagnostics.Debug.WriteLine("New note posted: " + message["newNote"].ToString()); - } - else if (operation.Equals("getMessages")) - { - var notes = notePad.GetNotes(); - ValueSet returnMessage = new ValueSet(); - returnMessage.Add("notes", notes.ToArray()); - var responseStatus = await args.Request.SendResponseAsync(returnMessage); - } - - messageDefferal.Complete(); - } - } - - -} +// Copyright (c) Microsoft. All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Http; +using Windows.ApplicationModel.Background; +using Windows.ApplicationModel.AppService; +using Windows.Foundation.Collections; + +// The Background Application template is documented at http://go.microsoft.com/fwlink/?LinkID=533884&clcid=0x409 + +namespace NotepadService +{ + // See the "AppServiceBlinky" sample for a basic introduction to AppServices for IoT devices + // Each connection causes a new instance to be spun up in the same process + public sealed class StartupTask : IBackgroundTask + { + // Notepad is static to allow a single instance to be shared among all connections + private static Notepad notePad; + BackgroundTaskDeferral serviceDeferral; + AppServiceConnection appServiceConnection; + + public void Run(IBackgroundTaskInstance taskInstance) + { + + serviceDeferral = taskInstance.GetDeferral(); + taskInstance.Canceled += TaskInstance_Canceled; + + System.Diagnostics.Debug.WriteLine(Windows.ApplicationModel.Package.Current.Id.FamilyName); + + if (notePad == null) + { + notePad = new Notepad(); + } + + + var appServiceTrigger = taskInstance.TriggerDetails as AppServiceTriggerDetails; + + if (appServiceTrigger != null) + { + if (appServiceTrigger.Name.Equals("NotepadService")) + { + appServiceConnection = appServiceTrigger.AppServiceConnection; + appServiceConnection.RequestReceived += AppServiceConnection_RequestReceived; + appServiceConnection.ServiceClosed += AppServiceConnection_ServiceClosed; + notePad.NoteAdded += NotePad_NoteAdded; + } + else + { + serviceDeferral.Complete(); + } + } + } + + private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) + { + if (serviceDeferral != null) + { + serviceDeferral.Complete(); + serviceDeferral = null; + } + } + + private void AppServiceConnection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args) + { + System.Diagnostics.Debug.WriteLine("Service closed. Status=" + args.Status.ToString()); + } + + // Every time the underlying notepad gets a new note, send a message back to the client indicating that a new message is available + private async void NotePad_NoteAdded(object sender, EventArgs e) + { + ValueSet message = new ValueSet(); + message.Add("operation", "newMessagesAdded"); + await appServiceConnection.SendMessageAsync(message); + } + + // This AppService supports recieving two types of request: "postNote" and "getMessages" + // When a note is sent from the clients the service will pass it to the shared notepad + // and send a confirmation response to the client + // When the client requests messages the repsonse will contain a string[] of all the messages on the notepad + private async void AppServiceConnection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) + { + var messageDefferal = args.GetDeferral(); + var message = args.Request.Message; + string operation = (string)message["operation"]; + if (operation.Equals("postNote")) + { + await notePad.AddNote((message["newNote"].ToString())); + ValueSet returnMessage = new ValueSet(); + returnMessage.Add("Result", "Note Added"); + var responseStatus = await args.Request.SendResponseAsync(returnMessage); + System.Diagnostics.Debug.WriteLine("New note posted: " + message["newNote"].ToString()); + } + else if (operation.Equals("getMessages")) + { + var notes = notePad.GetNotes(); + ValueSet returnMessage = new ValueSet(); + returnMessage.Add("notes", notes.ToArray()); + var responseStatus = await args.Request.SendResponseAsync(returnMessage); + } + + messageDefferal.Complete(); + } + } + + +} diff --git a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp.sln b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp.sln index 0acdeee72..8b4a3b9ce 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp.sln +++ b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp.sln @@ -1,40 +1,40 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NotepadServiceClientApp", "NotepadServiceClientApp\NotepadServiceClientApp.csproj", "{5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}" -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 - {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Debug|ARM.ActiveCfg = Debug|ARM - {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Debug|ARM.Build.0 = Debug|ARM - {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Debug|ARM.Deploy.0 = Debug|ARM - {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Debug|x64.ActiveCfg = Debug|x64 - {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Debug|x64.Build.0 = Debug|x64 - {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Debug|x64.Deploy.0 = Debug|x64 - {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Debug|x86.ActiveCfg = Debug|x86 - {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Debug|x86.Build.0 = Debug|x86 - {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Debug|x86.Deploy.0 = Debug|x86 - {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Release|ARM.ActiveCfg = Release|ARM - {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Release|ARM.Build.0 = Release|ARM - {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Release|ARM.Deploy.0 = Release|ARM - {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Release|x64.ActiveCfg = Release|x64 - {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Release|x64.Build.0 = Release|x64 - {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Release|x64.Deploy.0 = Release|x64 - {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Release|x86.ActiveCfg = Release|x86 - {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Release|x86.Build.0 = Release|x86 - {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Release|x86.Deploy.0 = Release|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.24720.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NotepadServiceClientApp", "NotepadServiceClientApp\NotepadServiceClientApp.csproj", "{5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}" +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 + {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Debug|ARM.ActiveCfg = Debug|ARM + {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Debug|ARM.Build.0 = Debug|ARM + {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Debug|ARM.Deploy.0 = Debug|ARM + {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Debug|x64.ActiveCfg = Debug|x64 + {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Debug|x64.Build.0 = Debug|x64 + {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Debug|x64.Deploy.0 = Debug|x64 + {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Debug|x86.ActiveCfg = Debug|x86 + {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Debug|x86.Build.0 = Debug|x86 + {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Debug|x86.Deploy.0 = Debug|x86 + {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Release|ARM.ActiveCfg = Release|ARM + {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Release|ARM.Build.0 = Release|ARM + {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Release|ARM.Deploy.0 = Release|ARM + {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Release|x64.ActiveCfg = Release|x64 + {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Release|x64.Build.0 = Release|x64 + {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Release|x64.Deploy.0 = Release|x64 + {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Release|x86.ActiveCfg = Release|x86 + {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Release|x86.Build.0 = Release|x86 + {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28}.Release|x86.Deploy.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/App.xaml b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/App.xaml index 0d39a4430..481d958d3 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/App.xaml +++ b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/App.xaml @@ -1,8 +1,8 @@ - - - + + + diff --git a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/App.xaml.cs b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/App.xaml.cs index c24b9fdac..9eab5e760 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/App.xaml.cs +++ b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/App.xaml.cs @@ -1,108 +1,108 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices.WindowsRuntime; -using Windows.ApplicationModel; -using Windows.ApplicationModel.Activation; -using Windows.Foundation; -using Windows.Foundation.Collections; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Controls.Primitives; -using Windows.UI.Xaml.Data; -using Windows.UI.Xaml.Input; -using Windows.UI.Xaml.Media; -using Windows.UI.Xaml.Navigation; - -namespace NotepadServiceClientApp -{ - /// - /// Provides application-specific behavior to supplement the default Application class. - /// - sealed partial class App : Application - { - /// - /// Initializes the singleton application object. This is the first line of authored code - /// executed, and as such is the logical equivalent of main() or WinMain(). - /// - public App() - { - Microsoft.ApplicationInsights.WindowsAppInitializer.InitializeAsync( - Microsoft.ApplicationInsights.WindowsCollectors.Metadata | - Microsoft.ApplicationInsights.WindowsCollectors.Session); - this.InitializeComponent(); - this.Suspending += OnSuspending; - } - - /// - /// Invoked when the application is launched normally by the end user. Other entry points - /// will be used such as when the application is launched to open a specific file. - /// - /// Details about the launch request and process. - protected override void OnLaunched(LaunchActivatedEventArgs e) - { - -#if DEBUG - if (System.Diagnostics.Debugger.IsAttached) - { - this.DebugSettings.EnableFrameRateCounter = true; - } -#endif - - Frame rootFrame = Window.Current.Content as Frame; - - // Do not repeat app initialization when the Window already has content, - // just ensure that the window is active - if (rootFrame == null) - { - // Create a Frame to act as the navigation context and navigate to the first page - rootFrame = new Frame(); - - rootFrame.NavigationFailed += OnNavigationFailed; - - if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) - { - //TODO: Load state from previously suspended application - } - - // Place the frame in the current Window - Window.Current.Content = rootFrame; - } - - if (rootFrame.Content == null) - { - // When the navigation stack isn't restored navigate to the first page, - // configuring the new page by passing required information as a navigation - // parameter - rootFrame.Navigate(typeof(MainPage), e.Arguments); - } - // Ensure the current window is active - Window.Current.Activate(); - } - - /// - /// Invoked when Navigation to a certain page fails - /// - /// The Frame which failed navigation - /// Details about the navigation failure - void OnNavigationFailed(object sender, NavigationFailedEventArgs e) - { - throw new Exception("Failed to load Page " + e.SourcePageType.FullName); - } - - /// - /// Invoked when application execution is being suspended. Application state is saved - /// without knowing whether the application will be terminated or resumed with the contents - /// of memory still intact. - /// - /// The source of the suspend request. - /// Details about the suspend request. - private void OnSuspending(object sender, SuspendingEventArgs e) - { - var deferral = e.SuspendingOperation.GetDeferral(); - //TODO: Save application state and stop any background activity - deferral.Complete(); - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.ApplicationModel; +using Windows.ApplicationModel.Activation; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Navigation; + +namespace NotepadServiceClientApp +{ + /// + /// Provides application-specific behavior to supplement the default Application class. + /// + sealed partial class App : Application + { + /// + /// Initializes the singleton application object. This is the first line of authored code + /// executed, and as such is the logical equivalent of main() or WinMain(). + /// + public App() + { + Microsoft.ApplicationInsights.WindowsAppInitializer.InitializeAsync( + Microsoft.ApplicationInsights.WindowsCollectors.Metadata | + Microsoft.ApplicationInsights.WindowsCollectors.Session); + this.InitializeComponent(); + this.Suspending += OnSuspending; + } + + /// + /// Invoked when the application is launched normally by the end user. Other entry points + /// will be used such as when the application is launched to open a specific file. + /// + /// Details about the launch request and process. + protected override void OnLaunched(LaunchActivatedEventArgs e) + { + +#if DEBUG + if (System.Diagnostics.Debugger.IsAttached) + { + this.DebugSettings.EnableFrameRateCounter = true; + } +#endif + + Frame rootFrame = Window.Current.Content as Frame; + + // Do not repeat app initialization when the Window already has content, + // just ensure that the window is active + if (rootFrame == null) + { + // Create a Frame to act as the navigation context and navigate to the first page + rootFrame = new Frame(); + + rootFrame.NavigationFailed += OnNavigationFailed; + + if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) + { + //TODO: Load state from previously suspended application + } + + // Place the frame in the current Window + Window.Current.Content = rootFrame; + } + + if (rootFrame.Content == null) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + rootFrame.Navigate(typeof(MainPage), e.Arguments); + } + // Ensure the current window is active + Window.Current.Activate(); + } + + /// + /// Invoked when Navigation to a certain page fails + /// + /// The Frame which failed navigation + /// Details about the navigation failure + void OnNavigationFailed(object sender, NavigationFailedEventArgs e) + { + throw new Exception("Failed to load Page " + e.SourcePageType.FullName); + } + + /// + /// Invoked when application execution is being suspended. Application state is saved + /// without knowing whether the application will be terminated or resumed with the contents + /// of memory still intact. + /// + /// The source of the suspend request. + /// Details about the suspend request. + private void OnSuspending(object sender, SuspendingEventArgs e) + { + var deferral = e.SuspendingOperation.GetDeferral(); + //TODO: Save application state and stop any background activity + deferral.Complete(); + } + } +} diff --git a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/ApplicationInsights.config b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/ApplicationInsights.config index 399f3c4e9..cb2a232da 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/ApplicationInsights.config +++ b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/ApplicationInsights.config @@ -1,3 +1,3 @@ - - - + + + diff --git a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/MainPage.xaml b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/MainPage.xaml index 2b48551e9..f6d940a9c 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/MainPage.xaml +++ b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/MainPage.xaml @@ -1,21 +1,21 @@ - - - - - Messages - - - - - - - - - + + + + + Messages + + + + + + + + + diff --git a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/MainPage.xaml.cs b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/MainPage.xaml.cs index 48fafc0d8..8ba14b812 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/MainPage.xaml.cs +++ b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/MainPage.xaml.cs @@ -1,102 +1,102 @@ -// Copyright (c) Microsoft. All rights reserved. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices.WindowsRuntime; -using Windows.Foundation; -using Windows.Foundation.Collections; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Controls.Primitives; -using Windows.UI.Xaml.Data; -using Windows.UI.Xaml.Input; -using Windows.UI.Xaml.Media; -using Windows.UI.Xaml.Navigation; -using Windows.ApplicationModel.Background; -using Windows.ApplicationModel.AppService; -using Windows.UI.Core; - -// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 - -namespace NotepadServiceClientApp -{ - /// - /// An empty page that can be used on its own or navigated to within a Frame. - /// - public sealed partial class MainPage : Page - { - - AppServiceConnection connection; - public MainPage() - { - this.InitializeComponent(); - this.Loaded += MainPage_Loaded; - } - - - //For more details about basic AppServices, see the "AppServiceBlinky" sample - //This app allows the user to request messages from the NotepadService - //The "GetNewMessagesButton" is only enabled when there are new messages with the service - private async void MainPage_Loaded(object sender, RoutedEventArgs e) - { - GetNewMessagesButton.IsEnabled = false; - connection = new AppServiceConnection(); - connection.AppServiceName = "NotepadService"; - connection.PackageFamilyName = "NotepadService-uwp_2yx4q2bk84nj4"; - AppServiceConnectionStatus status = await connection.OpenAsync(); - if (status != AppServiceConnectionStatus.Success) - { - Messages.Text = "Could not connnect to Notepad Service"; - } - else - { - connection.RequestReceived += Connection_RequestReceived; - GetNewMessagesButton.Click += GetNewMessagesButton_Click; - } - - } - - - //When the user requests new messages, send a request to the server and print them out - private async void GetNewMessagesButton_Click(object sender, RoutedEventArgs e) - { - var message = new ValueSet(); - message.Add("operation", "getMessages"); - var result = await connection.SendMessageAsync(message); - if (result.Status == AppServiceResponseStatus.Success) - { - var response = result.Message; - string[] notes = (string[])response["notes"]; - foreach (string note in notes) - { - Messages.Text += note + "\n"; - } - } - else - { - Messages.Text = "Could not connect to Notepad service"; - } - GetNewMessagesButton.IsEnabled = false; - - } - - //When the service notifies us of new messages, enable the button to allow the user to request messages - private async void Connection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) - { - ValueSet message = args.Request.Message; - if (message["operation"].Equals("newMessagesAdded")) - { - //Incoming messages come in on a background thread and so you need to go through the dispatcher to modify the button on the UI thread - var dispatcher = GetNewMessagesButton.Dispatcher; - await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => - { - GetNewMessagesButton.IsEnabled = true; - }); - - } - - } - } -} +// Copyright (c) Microsoft. All rights reserved. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Navigation; +using Windows.ApplicationModel.Background; +using Windows.ApplicationModel.AppService; +using Windows.UI.Core; + +// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 + +namespace NotepadServiceClientApp +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class MainPage : Page + { + + AppServiceConnection connection; + public MainPage() + { + this.InitializeComponent(); + this.Loaded += MainPage_Loaded; + } + + + //For more details about basic AppServices, see the "AppServiceBlinky" sample + //This app allows the user to request messages from the NotepadService + //The "GetNewMessagesButton" is only enabled when there are new messages with the service + private async void MainPage_Loaded(object sender, RoutedEventArgs e) + { + GetNewMessagesButton.IsEnabled = false; + connection = new AppServiceConnection(); + connection.AppServiceName = "NotepadService"; + connection.PackageFamilyName = "NotepadService-uwp_2yx4q2bk84nj4"; + AppServiceConnectionStatus status = await connection.OpenAsync(); + if (status != AppServiceConnectionStatus.Success) + { + Messages.Text = "Could not connnect to Notepad Service"; + } + else + { + connection.RequestReceived += Connection_RequestReceived; + GetNewMessagesButton.Click += GetNewMessagesButton_Click; + } + + } + + + //When the user requests new messages, send a request to the server and print them out + private async void GetNewMessagesButton_Click(object sender, RoutedEventArgs e) + { + var message = new ValueSet(); + message.Add("operation", "getMessages"); + var result = await connection.SendMessageAsync(message); + if (result.Status == AppServiceResponseStatus.Success) + { + var response = result.Message; + string[] notes = (string[])response["notes"]; + foreach (string note in notes) + { + Messages.Text += note + "\n"; + } + } + else + { + Messages.Text = "Could not connect to Notepad service"; + } + GetNewMessagesButton.IsEnabled = false; + + } + + //When the service notifies us of new messages, enable the button to allow the user to request messages + private async void Connection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) + { + ValueSet message = args.Request.Message; + if (message["operation"].Equals("newMessagesAdded")) + { + //Incoming messages come in on a background thread and so you need to go through the dispatcher to modify the button on the UI thread + var dispatcher = GetNewMessagesButton.Dispatcher; + await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => + { + GetNewMessagesButton.IsEnabled = true; + }); + + } + + } + } +} diff --git a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/NotepadServiceClientApp.csproj b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/NotepadServiceClientApp.csproj index 74d183119..bc083dbfd 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/NotepadServiceClientApp.csproj +++ b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/NotepadServiceClientApp.csproj @@ -1,157 +1,157 @@ - - - - - Debug - x86 - {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28} - AppContainerExe - Properties - NotepadServiceClientApp - NotepadServiceClientApp - en-US - UAP - 10.0.19041.0 - 10.0.15063.0 - 14 - 512 - {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - NotepadServiceClientApp_TemporaryKey.pfx - win10-arm;win10-arm-aot;win10-x86;win10-x86-aot;win10-x64;win10-x64-aot - - - true - bin\x86\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - x86 - false - prompt - true - - - bin\x86\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - x86 - false - prompt - true - true - - - true - bin\ARM\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - ARM - false - prompt - true - - - bin\ARM\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - ARM - false - prompt - true - true - - - true - bin\x64\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - x64 - false - prompt - true - - - bin\x64\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - x64 - false - prompt - true - true - - - - - PreserveNewest - - - - - App.xaml - - - MainPage.xaml - - - - - - Designer - - - - - - - - - - - - - - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - - - 1.0.0 - - - 1.0.0 - - - 1.0.0 - - - 5.0.0 - - - - 14.0 - - - - + + + + + Debug + x86 + {5BE6AA83-D1FA-40EB-B062-0BEA3AEC0A28} + AppContainerExe + Properties + NotepadServiceClientApp + NotepadServiceClientApp + en-US + UAP + 10.0.19041.0 + 10.0.15063.0 + 14 + 512 + {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + NotepadServiceClientApp_TemporaryKey.pfx + win10-arm;win10-arm-aot;win10-x86;win10-x86-aot;win10-x64;win10-x64-aot + + + true + bin\x86\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + x86 + false + prompt + true + + + bin\x86\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + x86 + false + prompt + true + true + + + true + bin\ARM\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + ARM + false + prompt + true + + + bin\ARM\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + ARM + false + prompt + true + true + + + true + bin\x64\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + x64 + false + prompt + true + + + bin\x64\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + x64 + false + prompt + true + true + + + + + PreserveNewest + + + + + App.xaml + + + MainPage.xaml + + + + + + Designer + + + + + + + + + + + + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + + + 1.0.0 + + + 1.0.0 + + + 1.0.0 + + + 5.0.0 + + + + 14.0 + + + + diff --git a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/Package.appxmanifest b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/Package.appxmanifest index 11392c841..3b89f453b 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/Package.appxmanifest +++ b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/Package.appxmanifest @@ -1,49 +1,49 @@ - - - - - - - - - - NotepadServiceClientApp - Microsoft - Assets\StoreLogo.png - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + NotepadServiceClientApp + Microsoft + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/Properties/AssemblyInfo.cs b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/Properties/AssemblyInfo.cs index da44e19a0..6fabaad54 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/Properties/AssemblyInfo.cs +++ b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/Properties/AssemblyInfo.cs @@ -1,29 +1,29 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("NotepadServiceClientApp")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("NotepadServiceClientApp")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NotepadServiceClientApp")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("NotepadServiceClientApp")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] [assembly: ComVisible(false)] \ No newline at end of file diff --git a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/Properties/Default.rd.xml b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/Properties/Default.rd.xml index 461bc4c13..80a960ce3 100644 --- a/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/Properties/Default.rd.xml +++ b/samples/AppServiceSharedNotepad/CS/NotepadServiceClientApp/Properties/Default.rd.xml @@ -1,31 +1,31 @@ - - - - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/AppServiceSharedNotepad/CS/README.md b/samples/AppServiceSharedNotepad/CS/README.md index cb0a42f38..1793df4ab 100644 --- a/samples/AppServiceSharedNotepad/CS/README.md +++ b/samples/AppServiceSharedNotepad/CS/README.md @@ -1,317 +1,317 @@ ---- -page_type: sample -urlFragment: appservice-sharednotepad -languages: - - csharp -products: - - Windows 10 - - Windows IoT - - Windows 10 IoT Enterprise -description: Create a simple notepad app service as well as two simple app service clients for Windows 10 IoT Enterprise. ---- - -# Using an app service with multiple clients - -We’ll create a simple notepad [app service](https://docs.microsoft.com/en-us/windows/uwp/launch-resume/how-to-create-and-consume-an-app-service). We'll also create two simple app service clients. One that writes to the notepad service and one that reads from the notepad service. - -## Step 1: Load the projects in Visual Studio -___ - -* You can find the source code for this sample by downloading a zip of all of our samples in Windows 10 IoT Enterprise folder and navigating to the `samples-develop\AppServiceBlinky`. -* Make a copy of the folder on your disk and open the projects from Visual Studio. -* NotepadService.sln implements the app service and must be started first. -* NotepadClientBackgroundApplication.sln implements a client that writes messages to the app service. -* NotepadServiceClientApp.sln implements a window that retrieves messages from the client and displays them. -* Make a copy of the folder on your disk and open the projects from Visual Studio. -* NotepadService.sln implements the app service and must be started first. -* NotepadClientBackgroundApplication.sln implements the app service client. - -## Step 2: Deploy your app - -* * * - -With the application open in Visual Studio 2019, set the architecture in the toolbar dropdown. If you’re building for UP Board, select `x64`. - -When everything is set up, you should be able to press F5 from each instance of Visual Studio. - -The NotepadService app will deploy and start on the Windows IoT device, and you should see the package family name printed the debug output window on Visual Studio. - -Before pressing F5 for NotepadClientBackgroundApplication and NotepadServiceClientApp projects verify that the value of connection.PackageFamilyName in StartupTask.cs and MainPage.xaml.cs matches the value output in the output window by NotepadService. - -If it does not have any value output, you will get the value by marking the breakpoint in debug mode for -StartupTask.cs at System.Diagnostics.Debug.WriteLine("Service closed. Status=" + args.Status.ToString()). - -Next start NotepadServiceClientApp and then NotepadServiceClientApp. - -### [Generate an app package](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#generate-an-app-package) - -### [Install your app package using an install script](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#install-your-app-package-using-an-install-script) - -When you run the client app you should see - -![No messages yet](../../../Resources/AppServiceSharedNotepad-NoMessages.jpg) - -After a 30 seconds or so the text in the button should change to black from gray. Clicking the button will show the messages from the clipboard service. - -![Message from clipboard service](../../../Resources/AppServiceSharedNotepad-Messages.jpg) - -## Let's look at the code -___ -The code is in 3 projects NotepadService, NotepadClientBackgroundApplication and NotepadServiceClientApp. First we'll look at NotepadService. - -## Adding an app service -___ -To add an appservice to our background application first we need to open appxmanifest.xml in a text editor and add an extension with Category="windows.AppService" - -``` xml - - - - - - - - - - - -``` - -Next we'll add a check in the StartupTask::Run method to see if the application is being started as an appservice - -```csharp -//Check to determine whether this activation was caused by an incoming app service connection -var appServiceTrigger = taskInstance.TriggerDetails as AppServiceTriggerDetails; -if (appServiceTrigger != null) -{ - if (appServiceTrigger.Name.Equals("NotepadService")) - { - appServiceConnection = appServiceTrigger.AppServiceConnection; - appServiceConnection.RequestReceived += AppServiceConnection_RequestReceived; - appServiceConnection.ServiceClosed += AppServiceConnection_ServiceClosed; - notePad.NoteAdded += NotePad_NoteAdded; - } - else - { - serviceDeferral.Complete(); - } -} -``` - -At the beginning of NotepadService's StartupTask::Run get the deferral object and set up a Canceled event handler to clean up the deferral on exit. - -```csharp -serviceDeferral = taskInstance.GetDeferral(); -taskInstance.Canceled += TaskInstance_Canceled; -``` - -When the Canceled event handler is called Complete the deferral for this instance of the app service if one exists. If the deferral is not completed then the app service process will be killed by the operating system even if other clients still have connections open to the app service. - -```csharp -private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) -{ - if (deferral != null) - { - deferral.Complete(); - deferral = null; - } -} -``` - -Finally we need to handle service requests: - -```csharp -// This AppService supports recieving two types of request: "postNote" and "getMessages" -// When a note is sent from the clients the service will pass it to the shared notepad -// and send a confirmation response to the client. -// When the client requests messages the repsonse will contain a string[] of all the messages on the notepad -private async void AppServiceConnection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) -{ - var messageDefferal = args.GetDeferral(); - var message = args.Request.Message; - string operation = (string)message["operation"]; - if (operation.Equals("postNote")) - { - await notePad.AddNote((message["newNote"].ToString())); - ValueSet returnMessage = new ValueSet(); - returnMessage.Add("Result", "Note Added"); - var responseStatus = await args.Request.SendResponseAsync(returnMessage); - System.Diagnostics.Debug.WriteLine("New note posted: " + message["newNote"].ToString()); - } - else if (operation.Equals("getMessages")) - { - var notes = notePad.GetNotes(); - ValueSet returnMessage = new ValueSet(); - returnMessage.Add("notes", notes.ToArray()); - var responseStatus = await args.Request.SendResponseAsync(returnMessage); - } - - messageDefferal.Complete(); -} -``` - -## Writing messages in NotepadClientBackgroundApplication -___ -When the client starts it opens a connection to the client. The string assigned to connection.PackageFamilyName uniquely identifies the service we want to connect to. - -```csharp -AppServiceConnection connection; -BackgroundTaskDeferral deferral; -ThreadPoolTimer timer; -string requestedPinValue; - -public async void Run(IBackgroundTaskInstance taskInstance) -{ - deferral = taskInstance.GetDeferral(); - taskInstance.Canceled += TaskInstance_Canceled; - - connection = new AppServiceConnection(); - connection.AppServiceName = "NotepadService"; - connection.PackageFamilyName = "NotepadService-uwp_2yx4q2bk84nj4"; - AppServiceConnectionStatus status = await connection.OpenAsync(); - if (status != AppServiceConnectionStatus.Success) - { - return; - } - - var message = new ValueSet(); - - //Send a message with an operation type of "postNote" and the desired "newNote" - //Then, if successful, start a timer and send a new message periodically - message.Add("operation", "postNote"); - message.Add("newNote", "Hello, this is my first note. I will add another one every 30 seconds"); - AppServiceResponse response = await connection.SendMessageAsync(message); - if (response.Status == AppServiceResponseStatus.Success) - { - var result = response.Message["Result"].ToString(); - timer = ThreadPoolTimer.CreatePeriodicTimer(this.Tick, TimeSpan.FromSeconds(30)); - System.Diagnostics.Debug.WriteLine(result); - } -} - -private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) -{ - if (deferral != null) - { - deferral.Complete(); - deferral = null; - } -} -``` - -If everything connects without an error then the timer callback will post a new note every 30 seconds. - -```csharp -public async void Tick(ThreadPoolTimer sender) -{ - count++; - var message = new ValueSet(); - message.Add("operation", "postNote"); - message.Add("newNote", "Here is new note #" + count.ToString()); - AppServiceResponse response = await connection.SendMessageAsync(message); - if (response.Status == AppServiceResponseStatus.Success) - { - var result = response.Message["Result"].ToString(); - System.Diagnostics.Debug.WriteLine(result); - } -} -``` - -## Receiving new message notificiations and showing messages in NotepadServiceClient -___ -In the NotepadServiceClient application add a TextBlock named **Messages** to contain the messages from the NotepadService. -Also, add a button called **GetNewMessagesButton** to get messages from NotepadServiceClient and store them in the **Messages** TextBlock. - -``` xml - - - Messages - - - - - - -``` - -In the **MainPage** constructor add an event handler for the **Loaded** event. In the **Loaded** event handler connect to the **NotepadService** app service. - -```csharp -AppServiceConnection connection; - -public MainPage() -{ - this.InitializeComponent(); - this.Loaded += MainPage_Loaded; -} - - -//For more details about basic AppServices, see the "AppServiceBlinky" sample -//This app allows the user to request messages from the NotepadService -//The "GetNewMessagesButton" is only enabled when there are new messages with the service -private async void MainPage_Loaded(object sender, RoutedEventArgs e) -{ - GetNewMessagesButton.IsEnabled = false; - connection = new AppServiceConnection(); - connection.AppServiceName = "NotepadService"; - connection.PackageFamilyName = "NotepadService-uwp_2yx4q2bk84nj4"; - AppServiceConnectionStatus status = await connection.OpenAsync(); - if (status != AppServiceConnectionStatus.Success) - { - Messages.Text = "Could not connnect to Notepad Service"; - } - else - { - connection.RequestReceived += Connection_RequestReceived; - GetNewMessagesButton.Click += GetNewMessagesButton_Click; - } - -} -``` - -When the NotepadService receives a new message it will call the connection's **RequestReceived** event handler to notify the client application. When a new message is received enable **GetNewMessagesButton**. - -```csharp -//When the service notifies us of new messages, enable the button to allow the user to request messages -private async void Connection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) -{ - ValueSet message = args.Request.Message; - if (message["operation"].Equals("newMessagesAdded")) - { - //Incoming messages come in on a background thread and so you need to go through the dispatcher to modify the button on the UI thread - var dispatcher = GetNewMessagesButton.Dispatcher; - await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => - { - GetNewMessagesButton.IsEnabled = true; - }); - - } - -} -``` - -When the **GetNewMessagesButton** is clicked request the message from **NotepadService** and display them in the **Messages** TextBlock. - -```csharp -//When the user requests new messages, send a request to the server and print them out -private async void GetNewMessagesButton_Click(object sender, RoutedEventArgs e) -{ - var message = new ValueSet(); - message.Add("operation", "getMessages"); - var result = await connection.SendMessageAsync(message); - if (result.Status == AppServiceResponseStatus.Success) - { - var response = result.Message; - string[] notes = (string[])response["notes"]; - foreach (string note in notes) - { - Messages.Text += note + "\n"; - } - } - else - { - Messages.Text = "Could not connect to Notepad service"; - } - GetNewMessagesButton.IsEnabled = false; -} -``` +--- +page_type: sample +urlFragment: appservice-sharednotepad +languages: + - csharp +products: + - Windows 10 + - Windows IoT + - Windows 10 IoT Enterprise +description: Create a simple notepad app service as well as two simple app service clients for Windows 10 IoT Enterprise. +--- + +# Using an app service with multiple clients + +We’ll create a simple notepad [app service](https://docs.microsoft.com/en-us/windows/uwp/launch-resume/how-to-create-and-consume-an-app-service). We'll also create two simple app service clients. One that writes to the notepad service and one that reads from the notepad service. + +## Step 1: Load the projects in Visual Studio +___ + +* You can find the source code for this sample by downloading a zip of all of our samples in Windows 10 IoT Enterprise folder and navigating to the `samples-develop\AppServiceBlinky`. +* Make a copy of the folder on your disk and open the projects from Visual Studio. +* NotepadService.sln implements the app service and must be started first. +* NotepadClientBackgroundApplication.sln implements a client that writes messages to the app service. +* NotepadServiceClientApp.sln implements a window that retrieves messages from the client and displays them. +* Make a copy of the folder on your disk and open the projects from Visual Studio. +* NotepadService.sln implements the app service and must be started first. +* NotepadClientBackgroundApplication.sln implements the app service client. + +## Step 2: Deploy your app + +* * * + +With the application open in Visual Studio 2019, set the architecture in the toolbar dropdown. If you’re building for UP Board, select `x64`. + +When everything is set up, you should be able to press F5 from each instance of Visual Studio. + +The NotepadService app will deploy and start on the Windows IoT device, and you should see the package family name printed the debug output window on Visual Studio. + +Before pressing F5 for NotepadClientBackgroundApplication and NotepadServiceClientApp projects verify that the value of connection.PackageFamilyName in StartupTask.cs and MainPage.xaml.cs matches the value output in the output window by NotepadService. + +If it does not have any value output, you will get the value by marking the breakpoint in debug mode for +StartupTask.cs at System.Diagnostics.Debug.WriteLine("Service closed. Status=" + args.Status.ToString()). + +Next start NotepadServiceClientApp and then NotepadServiceClientApp. + +### [Generate an app package](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#generate-an-app-package) + +### [Install your app package using an install script](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#install-your-app-package-using-an-install-script) + +When you run the client app you should see + +![No messages yet](../../../Resources/AppServiceSharedNotepad-NoMessages.jpg) + +After a 30 seconds or so the text in the button should change to black from gray. Clicking the button will show the messages from the clipboard service. + +![Message from clipboard service](../../../Resources/AppServiceSharedNotepad-Messages.jpg) + +## Let's look at the code +___ +The code is in 3 projects NotepadService, NotepadClientBackgroundApplication and NotepadServiceClientApp. First we'll look at NotepadService. + +## Adding an app service +___ +To add an appservice to our background application first we need to open appxmanifest.xml in a text editor and add an extension with Category="windows.AppService" + +``` xml + + + + + + + + + + + +``` + +Next we'll add a check in the StartupTask::Run method to see if the application is being started as an appservice + +```csharp +//Check to determine whether this activation was caused by an incoming app service connection +var appServiceTrigger = taskInstance.TriggerDetails as AppServiceTriggerDetails; +if (appServiceTrigger != null) +{ + if (appServiceTrigger.Name.Equals("NotepadService")) + { + appServiceConnection = appServiceTrigger.AppServiceConnection; + appServiceConnection.RequestReceived += AppServiceConnection_RequestReceived; + appServiceConnection.ServiceClosed += AppServiceConnection_ServiceClosed; + notePad.NoteAdded += NotePad_NoteAdded; + } + else + { + serviceDeferral.Complete(); + } +} +``` + +At the beginning of NotepadService's StartupTask::Run get the deferral object and set up a Canceled event handler to clean up the deferral on exit. + +```csharp +serviceDeferral = taskInstance.GetDeferral(); +taskInstance.Canceled += TaskInstance_Canceled; +``` + +When the Canceled event handler is called Complete the deferral for this instance of the app service if one exists. If the deferral is not completed then the app service process will be killed by the operating system even if other clients still have connections open to the app service. + +```csharp +private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) +{ + if (deferral != null) + { + deferral.Complete(); + deferral = null; + } +} +``` + +Finally we need to handle service requests: + +```csharp +// This AppService supports recieving two types of request: "postNote" and "getMessages" +// When a note is sent from the clients the service will pass it to the shared notepad +// and send a confirmation response to the client. +// When the client requests messages the repsonse will contain a string[] of all the messages on the notepad +private async void AppServiceConnection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) +{ + var messageDefferal = args.GetDeferral(); + var message = args.Request.Message; + string operation = (string)message["operation"]; + if (operation.Equals("postNote")) + { + await notePad.AddNote((message["newNote"].ToString())); + ValueSet returnMessage = new ValueSet(); + returnMessage.Add("Result", "Note Added"); + var responseStatus = await args.Request.SendResponseAsync(returnMessage); + System.Diagnostics.Debug.WriteLine("New note posted: " + message["newNote"].ToString()); + } + else if (operation.Equals("getMessages")) + { + var notes = notePad.GetNotes(); + ValueSet returnMessage = new ValueSet(); + returnMessage.Add("notes", notes.ToArray()); + var responseStatus = await args.Request.SendResponseAsync(returnMessage); + } + + messageDefferal.Complete(); +} +``` + +## Writing messages in NotepadClientBackgroundApplication +___ +When the client starts it opens a connection to the client. The string assigned to connection.PackageFamilyName uniquely identifies the service we want to connect to. + +```csharp +AppServiceConnection connection; +BackgroundTaskDeferral deferral; +ThreadPoolTimer timer; +string requestedPinValue; + +public async void Run(IBackgroundTaskInstance taskInstance) +{ + deferral = taskInstance.GetDeferral(); + taskInstance.Canceled += TaskInstance_Canceled; + + connection = new AppServiceConnection(); + connection.AppServiceName = "NotepadService"; + connection.PackageFamilyName = "NotepadService-uwp_2yx4q2bk84nj4"; + AppServiceConnectionStatus status = await connection.OpenAsync(); + if (status != AppServiceConnectionStatus.Success) + { + return; + } + + var message = new ValueSet(); + + //Send a message with an operation type of "postNote" and the desired "newNote" + //Then, if successful, start a timer and send a new message periodically + message.Add("operation", "postNote"); + message.Add("newNote", "Hello, this is my first note. I will add another one every 30 seconds"); + AppServiceResponse response = await connection.SendMessageAsync(message); + if (response.Status == AppServiceResponseStatus.Success) + { + var result = response.Message["Result"].ToString(); + timer = ThreadPoolTimer.CreatePeriodicTimer(this.Tick, TimeSpan.FromSeconds(30)); + System.Diagnostics.Debug.WriteLine(result); + } +} + +private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) +{ + if (deferral != null) + { + deferral.Complete(); + deferral = null; + } +} +``` + +If everything connects without an error then the timer callback will post a new note every 30 seconds. + +```csharp +public async void Tick(ThreadPoolTimer sender) +{ + count++; + var message = new ValueSet(); + message.Add("operation", "postNote"); + message.Add("newNote", "Here is new note #" + count.ToString()); + AppServiceResponse response = await connection.SendMessageAsync(message); + if (response.Status == AppServiceResponseStatus.Success) + { + var result = response.Message["Result"].ToString(); + System.Diagnostics.Debug.WriteLine(result); + } +} +``` + +## Receiving new message notificiations and showing messages in NotepadServiceClient +___ +In the NotepadServiceClient application add a TextBlock named **Messages** to contain the messages from the NotepadService. +Also, add a button called **GetNewMessagesButton** to get messages from NotepadServiceClient and store them in the **Messages** TextBlock. + +``` xml + + + Messages + + + + + + +``` + +In the **MainPage** constructor add an event handler for the **Loaded** event. In the **Loaded** event handler connect to the **NotepadService** app service. + +```csharp +AppServiceConnection connection; + +public MainPage() +{ + this.InitializeComponent(); + this.Loaded += MainPage_Loaded; +} + + +//For more details about basic AppServices, see the "AppServiceBlinky" sample +//This app allows the user to request messages from the NotepadService +//The "GetNewMessagesButton" is only enabled when there are new messages with the service +private async void MainPage_Loaded(object sender, RoutedEventArgs e) +{ + GetNewMessagesButton.IsEnabled = false; + connection = new AppServiceConnection(); + connection.AppServiceName = "NotepadService"; + connection.PackageFamilyName = "NotepadService-uwp_2yx4q2bk84nj4"; + AppServiceConnectionStatus status = await connection.OpenAsync(); + if (status != AppServiceConnectionStatus.Success) + { + Messages.Text = "Could not connnect to Notepad Service"; + } + else + { + connection.RequestReceived += Connection_RequestReceived; + GetNewMessagesButton.Click += GetNewMessagesButton_Click; + } + +} +``` + +When the NotepadService receives a new message it will call the connection's **RequestReceived** event handler to notify the client application. When a new message is received enable **GetNewMessagesButton**. + +```csharp +//When the service notifies us of new messages, enable the button to allow the user to request messages +private async void Connection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) +{ + ValueSet message = args.Request.Message; + if (message["operation"].Equals("newMessagesAdded")) + { + //Incoming messages come in on a background thread and so you need to go through the dispatcher to modify the button on the UI thread + var dispatcher = GetNewMessagesButton.Dispatcher; + await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => + { + GetNewMessagesButton.IsEnabled = true; + }); + + } + +} +``` + +When the **GetNewMessagesButton** is clicked request the message from **NotepadService** and display them in the **Messages** TextBlock. + +```csharp +//When the user requests new messages, send a request to the server and print them out +private async void GetNewMessagesButton_Click(object sender, RoutedEventArgs e) +{ + var message = new ValueSet(); + message.Add("operation", "getMessages"); + var result = await connection.SendMessageAsync(message); + if (result.Status == AppServiceResponseStatus.Success) + { + var response = result.Message; + string[] notes = (string[])response["notes"]; + foreach (string note in notes) + { + Messages.Text += note + "\n"; + } + } + else + { + Messages.Text = "Could not connect to Notepad service"; + } + GetNewMessagesButton.IsEnabled = false; +} +``` diff --git a/samples/AppServiceSharedNotepad/README.md b/samples/AppServiceSharedNotepad/README.md index d12885114..eaae84a45 100644 --- a/samples/AppServiceSharedNotepad/README.md +++ b/samples/AppServiceSharedNotepad/README.md @@ -1,317 +1,317 @@ ---- -page_type: sample -urlFragment: appservice-sharednotepad -languages: - - csharp -products: - - Windows 10 - - Windows IoT - - Windows 10 IoT Enterprise -description: Create a simple notepad app service as well as two simple app service clients for Windows 10 IoT Enterprise. ---- - -# Using an app service with multiple clients - -We’ll create a simple notepad [app service](https://docs.microsoft.com/en-us/windows/uwp/launch-resume/how-to-create-and-consume-an-app-service). We'll also create two simple app service clients. One that writes to the notepad service and one that reads from the notepad service. - -## Step 1: Load the projects in Visual Studio -___ - -* You can find the source code for this sample by downloading a zip of all of our samples in Windows 10 IoT Enterprise folder and navigating to the `samples-develop\AppServiceBlinky`. -* Make a copy of the folder on your disk and open the projects from Visual Studio. -* NotepadService.sln implements the app service and must be started first. -* NotepadClientBackgroundApplication.sln implements a client that writes messages to the app service. -* NotepadServiceClientApp.sln implements a window that retrieves messages from the client and displays them. -* Make a copy of the folder on your disk and open the projects from Visual Studio. -* NotepadService.sln implements the app service and must be started first. -* NotepadClientBackgroundApplication.sln implements the app service client. - -## Step 2: Deploy your app - -* * * - -With the application open in Visual Studio 2019, set the architecture in the toolbar dropdown. If you’re building for UP Board, select `x64`. - -When everything is set up, you should be able to press F5 from each instance of Visual Studio. - -The NotepadService app will deploy and start on the Windows IoT device, and you should see the package family name printed the debug output window on Visual Studio. - -Before pressing F5 for NotepadClientBackgroundApplication and NotepadServiceClientApp projects verify that the value of connection.PackageFamilyName in StartupTask.cs and MainPage.xaml.cs matches the value output in the output window by NotepadService. - -If it does not have any value output, you will get the value by marking the breakpoint in debug mode for -StartupTask.cs at System.Diagnostics.Debug.WriteLine("Service closed. Status=" + args.Status.ToString()). - -Next start NotepadServiceClientApp and then NotepadServiceClientApp. - -### [Generate an app package](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#generate-an-app-package) - -### [Install your app package using an install script](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#install-your-app-package-using-an-install-script) - -When you run the client app you should see - -![No messages yet](../../Resources/AppServiceSharedNotepad-NoMessages.jpg) - -After a 30 seconds or so the text in the button should change to black from gray. Clicking the button will show the messages from the clipboard service. - -![Message from clipboard service](../../Resources/AppServiceSharedNotepad-Messages.jpg) - -## Let's look at the code -___ -The code is in 3 projects NotepadService, NotepadClientBackgroundApplication and NotepadServiceClientApp. First we'll look at NotepadService. - -## Adding an app service -___ -To add an appservice to our background application first we need to open appxmanifest.xml in a text editor and add an extension with Category="windows.AppService" - -``` xml - - - - - - - - - - - -``` - -Next we'll add a check in the StartupTask::Run method to see if the application is being started as an appservice - -```csharp -//Check to determine whether this activation was caused by an incoming app service connection -var appServiceTrigger = taskInstance.TriggerDetails as AppServiceTriggerDetails; -if (appServiceTrigger != null) -{ - if (appServiceTrigger.Name.Equals("NotepadService")) - { - appServiceConnection = appServiceTrigger.AppServiceConnection; - appServiceConnection.RequestReceived += AppServiceConnection_RequestReceived; - appServiceConnection.ServiceClosed += AppServiceConnection_ServiceClosed; - notePad.NoteAdded += NotePad_NoteAdded; - } - else - { - serviceDeferral.Complete(); - } -} -``` - -At the beginning of NotepadService's StartupTask::Run get the deferral object and set up a Canceled event handler to clean up the deferral on exit. - -```csharp -serviceDeferral = taskInstance.GetDeferral(); -taskInstance.Canceled += TaskInstance_Canceled; -``` - -When the Canceled event handler is called Complete the deferral for this instance of the app service if one exists. If the deferral is not completed then the app service process will be killed by the operating system even if other clients still have connections open to the app service. - -```csharp -private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) -{ - if (deferral != null) - { - deferral.Complete(); - deferral = null; - } -} -``` - -Finally we need to handle service requests: - -```csharp -// This AppService supports recieving two types of request: "postNote" and "getMessages" -// When a note is sent from the clients the service will pass it to the shared notepad -// and send a confirmation response to the client. -// When the client requests messages the repsonse will contain a string[] of all the messages on the notepad -private async void AppServiceConnection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) -{ - var messageDefferal = args.GetDeferral(); - var message = args.Request.Message; - string operation = (string)message["operation"]; - if (operation.Equals("postNote")) - { - await notePad.AddNote((message["newNote"].ToString())); - ValueSet returnMessage = new ValueSet(); - returnMessage.Add("Result", "Note Added"); - var responseStatus = await args.Request.SendResponseAsync(returnMessage); - System.Diagnostics.Debug.WriteLine("New note posted: " + message["newNote"].ToString()); - } - else if (operation.Equals("getMessages")) - { - var notes = notePad.GetNotes(); - ValueSet returnMessage = new ValueSet(); - returnMessage.Add("notes", notes.ToArray()); - var responseStatus = await args.Request.SendResponseAsync(returnMessage); - } - - messageDefferal.Complete(); -} -``` - -## Writing messages in NotepadClientBackgroundApplication -___ -When the client starts it opens a connection to the client. The string assigned to connection.PackageFamilyName uniquely identifies the service we want to connect to. - -```csharp -AppServiceConnection connection; -BackgroundTaskDeferral deferral; -ThreadPoolTimer timer; -string requestedPinValue; - -public async void Run(IBackgroundTaskInstance taskInstance) -{ - deferral = taskInstance.GetDeferral(); - taskInstance.Canceled += TaskInstance_Canceled; - - connection = new AppServiceConnection(); - connection.AppServiceName = "NotepadService"; - connection.PackageFamilyName = "NotepadService-uwp_2yx4q2bk84nj4"; - AppServiceConnectionStatus status = await connection.OpenAsync(); - if (status != AppServiceConnectionStatus.Success) - { - return; - } - - var message = new ValueSet(); - - //Send a message with an operation type of "postNote" and the desired "newNote" - //Then, if successful, start a timer and send a new message periodically - message.Add("operation", "postNote"); - message.Add("newNote", "Hello, this is my first note. I will add another one every 30 seconds"); - AppServiceResponse response = await connection.SendMessageAsync(message); - if (response.Status == AppServiceResponseStatus.Success) - { - var result = response.Message["Result"].ToString(); - timer = ThreadPoolTimer.CreatePeriodicTimer(this.Tick, TimeSpan.FromSeconds(30)); - System.Diagnostics.Debug.WriteLine(result); - } -} - -private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) -{ - if (deferral != null) - { - deferral.Complete(); - deferral = null; - } -} -``` - -If everything connects without an error then the timer callback will post a new note every 30 seconds. - -```csharp -public async void Tick(ThreadPoolTimer sender) -{ - count++; - var message = new ValueSet(); - message.Add("operation", "postNote"); - message.Add("newNote", "Here is new note #" + count.ToString()); - AppServiceResponse response = await connection.SendMessageAsync(message); - if (response.Status == AppServiceResponseStatus.Success) - { - var result = response.Message["Result"].ToString(); - System.Diagnostics.Debug.WriteLine(result); - } -} -``` - -## Receiving new message notificiations and showing messages in NotepadServiceClient -___ -In the NotepadServiceClient application add a TextBlock named **Messages** to contain the messages from the NotepadService. -Also, add a button called **GetNewMessagesButton** to get messages from NotepadServiceClient and store them in the **Messages** TextBlock. - -``` xml - - - Messages - - - - - - -``` - -In the **MainPage** constructor add an event handler for the **Loaded** event. In the **Loaded** event handler connect to the **NotepadService** app service. - -```csharp -AppServiceConnection connection; - -public MainPage() -{ - this.InitializeComponent(); - this.Loaded += MainPage_Loaded; -} - - -//For more details about basic AppServices, see the "AppServiceBlinky" sample -//This app allows the user to request messages from the NotepadService -//The "GetNewMessagesButton" is only enabled when there are new messages with the service -private async void MainPage_Loaded(object sender, RoutedEventArgs e) -{ - GetNewMessagesButton.IsEnabled = false; - connection = new AppServiceConnection(); - connection.AppServiceName = "NotepadService"; - connection.PackageFamilyName = "NotepadService-uwp_2yx4q2bk84nj4"; - AppServiceConnectionStatus status = await connection.OpenAsync(); - if (status != AppServiceConnectionStatus.Success) - { - Messages.Text = "Could not connnect to Notepad Service"; - } - else - { - connection.RequestReceived += Connection_RequestReceived; - GetNewMessagesButton.Click += GetNewMessagesButton_Click; - } - -} -``` - -When the NotepadService receives a new message it will call the connection's **RequestReceived** event handler to notify the client application. When a new message is received enable **GetNewMessagesButton**. - -```csharp -//When the service notifies us of new messages, enable the button to allow the user to request messages -private async void Connection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) -{ - ValueSet message = args.Request.Message; - if (message["operation"].Equals("newMessagesAdded")) - { - //Incoming messages come in on a background thread and so you need to go through the dispatcher to modify the button on the UI thread - var dispatcher = GetNewMessagesButton.Dispatcher; - await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => - { - GetNewMessagesButton.IsEnabled = true; - }); - - } - -} -``` - -When the **GetNewMessagesButton** is clicked request the message from **NotepadService** and display them in the **Messages** TextBlock. - -```csharp -//When the user requests new messages, send a request to the server and print them out -private async void GetNewMessagesButton_Click(object sender, RoutedEventArgs e) -{ - var message = new ValueSet(); - message.Add("operation", "getMessages"); - var result = await connection.SendMessageAsync(message); - if (result.Status == AppServiceResponseStatus.Success) - { - var response = result.Message; - string[] notes = (string[])response["notes"]; - foreach (string note in notes) - { - Messages.Text += note + "\n"; - } - } - else - { - Messages.Text = "Could not connect to Notepad service"; - } - GetNewMessagesButton.IsEnabled = false; -} -``` +--- +page_type: sample +urlFragment: appservice-sharednotepad +languages: + - csharp +products: + - Windows 10 + - Windows IoT + - Windows 10 IoT Enterprise +description: Create a simple notepad app service as well as two simple app service clients for Windows 10 IoT Enterprise. +--- + +# Using an app service with multiple clients + +We’ll create a simple notepad [app service](https://docs.microsoft.com/en-us/windows/uwp/launch-resume/how-to-create-and-consume-an-app-service). We'll also create two simple app service clients. One that writes to the notepad service and one that reads from the notepad service. + +## Step 1: Load the projects in Visual Studio +___ + +* You can find the source code for this sample by downloading a zip of all of our samples in Windows 10 IoT Enterprise folder and navigating to the `samples-develop\AppServiceBlinky`. +* Make a copy of the folder on your disk and open the projects from Visual Studio. +* NotepadService.sln implements the app service and must be started first. +* NotepadClientBackgroundApplication.sln implements a client that writes messages to the app service. +* NotepadServiceClientApp.sln implements a window that retrieves messages from the client and displays them. +* Make a copy of the folder on your disk and open the projects from Visual Studio. +* NotepadService.sln implements the app service and must be started first. +* NotepadClientBackgroundApplication.sln implements the app service client. + +## Step 2: Deploy your app + +* * * + +With the application open in Visual Studio 2019, set the architecture in the toolbar dropdown. If you’re building for UP Board, select `x64`. + +When everything is set up, you should be able to press F5 from each instance of Visual Studio. + +The NotepadService app will deploy and start on the Windows IoT device, and you should see the package family name printed the debug output window on Visual Studio. + +Before pressing F5 for NotepadClientBackgroundApplication and NotepadServiceClientApp projects verify that the value of connection.PackageFamilyName in StartupTask.cs and MainPage.xaml.cs matches the value output in the output window by NotepadService. + +If it does not have any value output, you will get the value by marking the breakpoint in debug mode for +StartupTask.cs at System.Diagnostics.Debug.WriteLine("Service closed. Status=" + args.Status.ToString()). + +Next start NotepadServiceClientApp and then NotepadServiceClientApp. + +### [Generate an app package](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#generate-an-app-package) + +### [Install your app package using an install script](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#install-your-app-package-using-an-install-script) + +When you run the client app you should see + +![No messages yet](../../Resources/AppServiceSharedNotepad-NoMessages.jpg) + +After a 30 seconds or so the text in the button should change to black from gray. Clicking the button will show the messages from the clipboard service. + +![Message from clipboard service](../../Resources/AppServiceSharedNotepad-Messages.jpg) + +## Let's look at the code +___ +The code is in 3 projects NotepadService, NotepadClientBackgroundApplication and NotepadServiceClientApp. First we'll look at NotepadService. + +## Adding an app service +___ +To add an appservice to our background application first we need to open appxmanifest.xml in a text editor and add an extension with Category="windows.AppService" + +``` xml + + + + + + + + + + + +``` + +Next we'll add a check in the StartupTask::Run method to see if the application is being started as an appservice + +```csharp +//Check to determine whether this activation was caused by an incoming app service connection +var appServiceTrigger = taskInstance.TriggerDetails as AppServiceTriggerDetails; +if (appServiceTrigger != null) +{ + if (appServiceTrigger.Name.Equals("NotepadService")) + { + appServiceConnection = appServiceTrigger.AppServiceConnection; + appServiceConnection.RequestReceived += AppServiceConnection_RequestReceived; + appServiceConnection.ServiceClosed += AppServiceConnection_ServiceClosed; + notePad.NoteAdded += NotePad_NoteAdded; + } + else + { + serviceDeferral.Complete(); + } +} +``` + +At the beginning of NotepadService's StartupTask::Run get the deferral object and set up a Canceled event handler to clean up the deferral on exit. + +```csharp +serviceDeferral = taskInstance.GetDeferral(); +taskInstance.Canceled += TaskInstance_Canceled; +``` + +When the Canceled event handler is called Complete the deferral for this instance of the app service if one exists. If the deferral is not completed then the app service process will be killed by the operating system even if other clients still have connections open to the app service. + +```csharp +private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) +{ + if (deferral != null) + { + deferral.Complete(); + deferral = null; + } +} +``` + +Finally we need to handle service requests: + +```csharp +// This AppService supports recieving two types of request: "postNote" and "getMessages" +// When a note is sent from the clients the service will pass it to the shared notepad +// and send a confirmation response to the client. +// When the client requests messages the repsonse will contain a string[] of all the messages on the notepad +private async void AppServiceConnection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) +{ + var messageDefferal = args.GetDeferral(); + var message = args.Request.Message; + string operation = (string)message["operation"]; + if (operation.Equals("postNote")) + { + await notePad.AddNote((message["newNote"].ToString())); + ValueSet returnMessage = new ValueSet(); + returnMessage.Add("Result", "Note Added"); + var responseStatus = await args.Request.SendResponseAsync(returnMessage); + System.Diagnostics.Debug.WriteLine("New note posted: " + message["newNote"].ToString()); + } + else if (operation.Equals("getMessages")) + { + var notes = notePad.GetNotes(); + ValueSet returnMessage = new ValueSet(); + returnMessage.Add("notes", notes.ToArray()); + var responseStatus = await args.Request.SendResponseAsync(returnMessage); + } + + messageDefferal.Complete(); +} +``` + +## Writing messages in NotepadClientBackgroundApplication +___ +When the client starts it opens a connection to the client. The string assigned to connection.PackageFamilyName uniquely identifies the service we want to connect to. + +```csharp +AppServiceConnection connection; +BackgroundTaskDeferral deferral; +ThreadPoolTimer timer; +string requestedPinValue; + +public async void Run(IBackgroundTaskInstance taskInstance) +{ + deferral = taskInstance.GetDeferral(); + taskInstance.Canceled += TaskInstance_Canceled; + + connection = new AppServiceConnection(); + connection.AppServiceName = "NotepadService"; + connection.PackageFamilyName = "NotepadService-uwp_2yx4q2bk84nj4"; + AppServiceConnectionStatus status = await connection.OpenAsync(); + if (status != AppServiceConnectionStatus.Success) + { + return; + } + + var message = new ValueSet(); + + //Send a message with an operation type of "postNote" and the desired "newNote" + //Then, if successful, start a timer and send a new message periodically + message.Add("operation", "postNote"); + message.Add("newNote", "Hello, this is my first note. I will add another one every 30 seconds"); + AppServiceResponse response = await connection.SendMessageAsync(message); + if (response.Status == AppServiceResponseStatus.Success) + { + var result = response.Message["Result"].ToString(); + timer = ThreadPoolTimer.CreatePeriodicTimer(this.Tick, TimeSpan.FromSeconds(30)); + System.Diagnostics.Debug.WriteLine(result); + } +} + +private void TaskInstance_Canceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) +{ + if (deferral != null) + { + deferral.Complete(); + deferral = null; + } +} +``` + +If everything connects without an error then the timer callback will post a new note every 30 seconds. + +```csharp +public async void Tick(ThreadPoolTimer sender) +{ + count++; + var message = new ValueSet(); + message.Add("operation", "postNote"); + message.Add("newNote", "Here is new note #" + count.ToString()); + AppServiceResponse response = await connection.SendMessageAsync(message); + if (response.Status == AppServiceResponseStatus.Success) + { + var result = response.Message["Result"].ToString(); + System.Diagnostics.Debug.WriteLine(result); + } +} +``` + +## Receiving new message notificiations and showing messages in NotepadServiceClient +___ +In the NotepadServiceClient application add a TextBlock named **Messages** to contain the messages from the NotepadService. +Also, add a button called **GetNewMessagesButton** to get messages from NotepadServiceClient and store them in the **Messages** TextBlock. + +``` xml + + + Messages + + + + + + +``` + +In the **MainPage** constructor add an event handler for the **Loaded** event. In the **Loaded** event handler connect to the **NotepadService** app service. + +```csharp +AppServiceConnection connection; + +public MainPage() +{ + this.InitializeComponent(); + this.Loaded += MainPage_Loaded; +} + + +//For more details about basic AppServices, see the "AppServiceBlinky" sample +//This app allows the user to request messages from the NotepadService +//The "GetNewMessagesButton" is only enabled when there are new messages with the service +private async void MainPage_Loaded(object sender, RoutedEventArgs e) +{ + GetNewMessagesButton.IsEnabled = false; + connection = new AppServiceConnection(); + connection.AppServiceName = "NotepadService"; + connection.PackageFamilyName = "NotepadService-uwp_2yx4q2bk84nj4"; + AppServiceConnectionStatus status = await connection.OpenAsync(); + if (status != AppServiceConnectionStatus.Success) + { + Messages.Text = "Could not connnect to Notepad Service"; + } + else + { + connection.RequestReceived += Connection_RequestReceived; + GetNewMessagesButton.Click += GetNewMessagesButton_Click; + } + +} +``` + +When the NotepadService receives a new message it will call the connection's **RequestReceived** event handler to notify the client application. When a new message is received enable **GetNewMessagesButton**. + +```csharp +//When the service notifies us of new messages, enable the button to allow the user to request messages +private async void Connection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) +{ + ValueSet message = args.Request.Message; + if (message["operation"].Equals("newMessagesAdded")) + { + //Incoming messages come in on a background thread and so you need to go through the dispatcher to modify the button on the UI thread + var dispatcher = GetNewMessagesButton.Dispatcher; + await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => + { + GetNewMessagesButton.IsEnabled = true; + }); + + } + +} +``` + +When the **GetNewMessagesButton** is clicked request the message from **NotepadService** and display them in the **Messages** TextBlock. + +```csharp +//When the user requests new messages, send a request to the server and print them out +private async void GetNewMessagesButton_Click(object sender, RoutedEventArgs e) +{ + var message = new ValueSet(); + message.Add("operation", "getMessages"); + var result = await connection.SendMessageAsync(message); + if (result.Status == AppServiceResponseStatus.Success) + { + var response = result.Message; + string[] notes = (string[])response["notes"]; + foreach (string note in notes) + { + Messages.Text += note + "\n"; + } + } + else + { + Messages.Text = "Could not connect to Notepad service"; + } + GetNewMessagesButton.IsEnabled = false; +} +``` diff --git a/samples/CustomDeviceAccessor/CPP/App.xaml b/samples/CustomDeviceAccessor/CPP/App.xaml index 8a11502b1..c248e2eac 100644 --- a/samples/CustomDeviceAccessor/CPP/App.xaml +++ b/samples/CustomDeviceAccessor/CPP/App.xaml @@ -1,9 +1,9 @@ - - - - + + + + diff --git a/samples/CustomDeviceAccessor/CPP/App.xaml.cpp b/samples/CustomDeviceAccessor/CPP/App.xaml.cpp index 83c660dcd..c432ee2f8 100644 --- a/samples/CustomDeviceAccessor/CPP/App.xaml.cpp +++ b/samples/CustomDeviceAccessor/CPP/App.xaml.cpp @@ -1,122 +1,122 @@ -// Copyright (c) Microsoft. All rights reserved. - -// -// App.xaml.cpp -// Implementation of the App class. -// - -#include "pch.h" -#include "MainPage.xaml.h" - -using namespace CustomDeviceAccessorUWP; - -using namespace Platform; -using namespace Windows::ApplicationModel; -using namespace Windows::ApplicationModel::Activation; -using namespace Windows::Foundation; -using namespace Windows::Foundation::Collections; -using namespace Windows::UI::Xaml; -using namespace Windows::UI::Xaml::Controls; -using namespace Windows::UI::Xaml::Controls::Primitives; -using namespace Windows::UI::Xaml::Data; -using namespace Windows::UI::Xaml::Input; -using namespace Windows::UI::Xaml::Interop; -using namespace Windows::UI::Xaml::Media; -using namespace Windows::UI::Xaml::Navigation; - -/// -/// Initializes the singleton application object. This is the first line of authored code -/// executed, and as such is the logical equivalent of main() or WinMain(). -/// -App::App() -{ - InitializeComponent(); - Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending); -} - -/// -/// Invoked when the application is launched normally by the end user. Other entry points -/// will be used such as when the application is launched to open a specific file. -/// -/// Details about the launch request and process. -void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ e) -{ - -#if _DEBUG - // Show graphics profiling information while debugging. - if (IsDebuggerPresent()) - { - // Display the current frame rate counters - DebugSettings->EnableFrameRateCounter = true; - } -#endif - - auto rootFrame = dynamic_cast(Window::Current->Content); - - // Do not repeat app initialization when the Window already has content, - // just ensure that the window is active - if (rootFrame == nullptr) - { - // Create a Frame to act as the navigation context and associate it with - // a SuspensionManager key - rootFrame = ref new Frame(); - - rootFrame->NavigationFailed += ref new Windows::UI::Xaml::Navigation::NavigationFailedEventHandler(this, &App::OnNavigationFailed); - - if (e->PreviousExecutionState == ApplicationExecutionState::Terminated) - { - // TODO: Restore the saved session state only when appropriate, scheduling the - // final launch steps after the restore is complete - - } - - if (rootFrame->Content == nullptr) - { - // When the navigation stack isn't restored navigate to the first page, - // configuring the new page by passing required information as a navigation - // parameter - rootFrame->Navigate(TypeName(MainPage::typeid), e->Arguments); - } - // Place the frame in the current Window - Window::Current->Content = rootFrame; - // Ensure the current window is active - Window::Current->Activate(); - } - else - { - if (rootFrame->Content == nullptr) - { - // When the navigation stack isn't restored navigate to the first page, - // configuring the new page by passing required information as a navigation - // parameter - rootFrame->Navigate(TypeName(MainPage::typeid), e->Arguments); - } - // Ensure the current window is active - Window::Current->Activate(); - } -} - -/// -/// Invoked when application execution is being suspended. Application state is saved -/// without knowing whether the application will be terminated or resumed with the contents -/// of memory still intact. -/// -/// The source of the suspend request. -/// Details about the suspend request. -void App::OnSuspending(Object^ sender, SuspendingEventArgs^ e) -{ - (void) sender; // Unused parameter - (void) e; // Unused parameter - - //TODO: Save application state and stop any background activity -} - -/// -/// Invoked when Navigation to a certain page fails -/// -/// The Frame which failed navigation -/// Details about the navigation failure -void App::OnNavigationFailed(Platform::Object ^sender, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs ^e) -{ - throw ref new FailureException("Failed to load Page " + e->SourcePageType.Name); +// Copyright (c) Microsoft. All rights reserved. + +// +// App.xaml.cpp +// Implementation of the App class. +// + +#include "pch.h" +#include "MainPage.xaml.h" + +using namespace CustomDeviceAccessorUWP; + +using namespace Platform; +using namespace Windows::ApplicationModel; +using namespace Windows::ApplicationModel::Activation; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Controls::Primitives; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Input; +using namespace Windows::UI::Xaml::Interop; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::UI::Xaml::Navigation; + +/// +/// Initializes the singleton application object. This is the first line of authored code +/// executed, and as such is the logical equivalent of main() or WinMain(). +/// +App::App() +{ + InitializeComponent(); + Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending); +} + +/// +/// Invoked when the application is launched normally by the end user. Other entry points +/// will be used such as when the application is launched to open a specific file. +/// +/// Details about the launch request and process. +void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ e) +{ + +#if _DEBUG + // Show graphics profiling information while debugging. + if (IsDebuggerPresent()) + { + // Display the current frame rate counters + DebugSettings->EnableFrameRateCounter = true; + } +#endif + + auto rootFrame = dynamic_cast(Window::Current->Content); + + // Do not repeat app initialization when the Window already has content, + // just ensure that the window is active + if (rootFrame == nullptr) + { + // Create a Frame to act as the navigation context and associate it with + // a SuspensionManager key + rootFrame = ref new Frame(); + + rootFrame->NavigationFailed += ref new Windows::UI::Xaml::Navigation::NavigationFailedEventHandler(this, &App::OnNavigationFailed); + + if (e->PreviousExecutionState == ApplicationExecutionState::Terminated) + { + // TODO: Restore the saved session state only when appropriate, scheduling the + // final launch steps after the restore is complete + + } + + if (rootFrame->Content == nullptr) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + rootFrame->Navigate(TypeName(MainPage::typeid), e->Arguments); + } + // Place the frame in the current Window + Window::Current->Content = rootFrame; + // Ensure the current window is active + Window::Current->Activate(); + } + else + { + if (rootFrame->Content == nullptr) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + rootFrame->Navigate(TypeName(MainPage::typeid), e->Arguments); + } + // Ensure the current window is active + Window::Current->Activate(); + } +} + +/// +/// Invoked when application execution is being suspended. Application state is saved +/// without knowing whether the application will be terminated or resumed with the contents +/// of memory still intact. +/// +/// The source of the suspend request. +/// Details about the suspend request. +void App::OnSuspending(Object^ sender, SuspendingEventArgs^ e) +{ + (void) sender; // Unused parameter + (void) e; // Unused parameter + + //TODO: Save application state and stop any background activity +} + +/// +/// Invoked when Navigation to a certain page fails +/// +/// The Frame which failed navigation +/// Details about the navigation failure +void App::OnNavigationFailed(Platform::Object ^sender, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs ^e) +{ + throw ref new FailureException("Failed to load Page " + e->SourcePageType.Name); } \ No newline at end of file diff --git a/samples/CustomDeviceAccessor/CPP/App.xaml.h b/samples/CustomDeviceAccessor/CPP/App.xaml.h index 45608fbb8..3b702589f 100644 --- a/samples/CustomDeviceAccessor/CPP/App.xaml.h +++ b/samples/CustomDeviceAccessor/CPP/App.xaml.h @@ -1,29 +1,29 @@ -// Copyright (c) Microsoft. All rights reserved. - -// -// App.xaml.h -// Declaration of the App class. -// - -#pragma once - -#include "App.g.h" - -namespace CustomDeviceAccessorUWP -{ - /// - /// Provides application-specific behavior to supplement the default Application class. - /// - ref class App sealed - { - protected: - virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ e) override; - - internal: - App(); - - private: - void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ e); - void OnNavigationFailed(Platform::Object ^sender, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs ^e); - }; -} +// Copyright (c) Microsoft. All rights reserved. + +// +// App.xaml.h +// Declaration of the App class. +// + +#pragma once + +#include "App.g.h" + +namespace CustomDeviceAccessorUWP +{ + /// + /// Provides application-specific behavior to supplement the default Application class. + /// + ref class App sealed + { + protected: + virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ e) override; + + internal: + App(); + + private: + void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ e); + void OnNavigationFailed(Platform::Object ^sender, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs ^e); + }; +} diff --git a/samples/CustomDeviceAccessor/CPP/CustomDeviceAccessorUWP.filters b/samples/CustomDeviceAccessor/CPP/CustomDeviceAccessorUWP.filters index 0c2310118..b36016a23 100644 --- a/samples/CustomDeviceAccessor/CPP/CustomDeviceAccessorUWP.filters +++ b/samples/CustomDeviceAccessor/CPP/CustomDeviceAccessorUWP.filters @@ -1,57 +1,57 @@ - - - - - 1dc1814a-c942-4468-9b4f-96008974d9e3 - - - 0b012d96-6fc7-42f2-9a9f-6da2642f1174 - bmp;fbx;gif;jpg;jpeg;tga;tiff;tif;png - - - - - - - - - - - - - - - - - - Assets - - - Assets - - - Assets - - - Assets - - - Assets - - - Assets - - - Assets - - - - - - - - - - - + + + + + 1dc1814a-c942-4468-9b4f-96008974d9e3 + + + 0b012d96-6fc7-42f2-9a9f-6da2642f1174 + 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/CustomDeviceAccessor/CPP/CustomDeviceAccessorUWP.sln b/samples/CustomDeviceAccessor/CPP/CustomDeviceAccessorUWP.sln index 3745d8ed0..909cb93d3 100644 --- a/samples/CustomDeviceAccessor/CPP/CustomDeviceAccessorUWP.sln +++ b/samples/CustomDeviceAccessor/CPP/CustomDeviceAccessorUWP.sln @@ -1,40 +1,40 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DeviceIoControlUwp", "CustomDeviceAccessorUWP.vcxproj", "{1DC1814A-C942-4468-9B4F-96008974D9E3}" -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 - {1DC1814A-C942-4468-9B4F-96008974D9E3}.Debug|ARM.ActiveCfg = Debug|ARM - {1DC1814A-C942-4468-9B4F-96008974D9E3}.Debug|ARM.Build.0 = Debug|ARM - {1DC1814A-C942-4468-9B4F-96008974D9E3}.Debug|ARM.Deploy.0 = Debug|ARM - {1DC1814A-C942-4468-9B4F-96008974D9E3}.Debug|x64.ActiveCfg = Debug|x64 - {1DC1814A-C942-4468-9B4F-96008974D9E3}.Debug|x64.Build.0 = Debug|x64 - {1DC1814A-C942-4468-9B4F-96008974D9E3}.Debug|x64.Deploy.0 = Debug|x64 - {1DC1814A-C942-4468-9B4F-96008974D9E3}.Debug|x86.ActiveCfg = Debug|Win32 - {1DC1814A-C942-4468-9B4F-96008974D9E3}.Debug|x86.Build.0 = Debug|Win32 - {1DC1814A-C942-4468-9B4F-96008974D9E3}.Debug|x86.Deploy.0 = Debug|Win32 - {1DC1814A-C942-4468-9B4F-96008974D9E3}.Release|ARM.ActiveCfg = Release|ARM - {1DC1814A-C942-4468-9B4F-96008974D9E3}.Release|ARM.Build.0 = Release|ARM - {1DC1814A-C942-4468-9B4F-96008974D9E3}.Release|ARM.Deploy.0 = Release|ARM - {1DC1814A-C942-4468-9B4F-96008974D9E3}.Release|x64.ActiveCfg = Release|x64 - {1DC1814A-C942-4468-9B4F-96008974D9E3}.Release|x64.Build.0 = Release|x64 - {1DC1814A-C942-4468-9B4F-96008974D9E3}.Release|x64.Deploy.0 = Release|x64 - {1DC1814A-C942-4468-9B4F-96008974D9E3}.Release|x86.ActiveCfg = Release|Win32 - {1DC1814A-C942-4468-9B4F-96008974D9E3}.Release|x86.Build.0 = Release|Win32 - {1DC1814A-C942-4468-9B4F-96008974D9E3}.Release|x86.Deploy.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.24720.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DeviceIoControlUwp", "CustomDeviceAccessorUWP.vcxproj", "{1DC1814A-C942-4468-9B4F-96008974D9E3}" +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 + {1DC1814A-C942-4468-9B4F-96008974D9E3}.Debug|ARM.ActiveCfg = Debug|ARM + {1DC1814A-C942-4468-9B4F-96008974D9E3}.Debug|ARM.Build.0 = Debug|ARM + {1DC1814A-C942-4468-9B4F-96008974D9E3}.Debug|ARM.Deploy.0 = Debug|ARM + {1DC1814A-C942-4468-9B4F-96008974D9E3}.Debug|x64.ActiveCfg = Debug|x64 + {1DC1814A-C942-4468-9B4F-96008974D9E3}.Debug|x64.Build.0 = Debug|x64 + {1DC1814A-C942-4468-9B4F-96008974D9E3}.Debug|x64.Deploy.0 = Debug|x64 + {1DC1814A-C942-4468-9B4F-96008974D9E3}.Debug|x86.ActiveCfg = Debug|Win32 + {1DC1814A-C942-4468-9B4F-96008974D9E3}.Debug|x86.Build.0 = Debug|Win32 + {1DC1814A-C942-4468-9B4F-96008974D9E3}.Debug|x86.Deploy.0 = Debug|Win32 + {1DC1814A-C942-4468-9B4F-96008974D9E3}.Release|ARM.ActiveCfg = Release|ARM + {1DC1814A-C942-4468-9B4F-96008974D9E3}.Release|ARM.Build.0 = Release|ARM + {1DC1814A-C942-4468-9B4F-96008974D9E3}.Release|ARM.Deploy.0 = Release|ARM + {1DC1814A-C942-4468-9B4F-96008974D9E3}.Release|x64.ActiveCfg = Release|x64 + {1DC1814A-C942-4468-9B4F-96008974D9E3}.Release|x64.Build.0 = Release|x64 + {1DC1814A-C942-4468-9B4F-96008974D9E3}.Release|x64.Deploy.0 = Release|x64 + {1DC1814A-C942-4468-9B4F-96008974D9E3}.Release|x86.ActiveCfg = Release|Win32 + {1DC1814A-C942-4468-9B4F-96008974D9E3}.Release|x86.Build.0 = Release|Win32 + {1DC1814A-C942-4468-9B4F-96008974D9E3}.Release|x86.Deploy.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/CustomDeviceAccessor/CPP/CustomDeviceAccessorUWP.vcxproj b/samples/CustomDeviceAccessor/CPP/CustomDeviceAccessorUWP.vcxproj index 8f90090bb..d2e3998cc 100644 --- a/samples/CustomDeviceAccessor/CPP/CustomDeviceAccessorUWP.vcxproj +++ b/samples/CustomDeviceAccessor/CPP/CustomDeviceAccessorUWP.vcxproj @@ -1,198 +1,198 @@ - - - - {1dc1814a-c942-4468-9b4f-96008974d9e3} - DeviceIoControlUwp - en-US - 14.0 - true - Windows Store - 10.0.19041.0 - 10.0.15063.0 - 10.0 - - <_NoWinAPIFamilyApp>true - CustomDeviceAccessorUWP - - - - - Debug - ARM - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - Win32 - - - Release - x64 - - - - Application - true - v141 - - - Application - true - v141 - - - Application - true - v142 - - - Application - false - true - v141 - true - - - Application - false - true - v141 - true - - - Application - false - true - v142 - true - - - - - - - - - - - - - - - - - - - - - - - - - CustomDeviceAccessorUWP_TemporaryKey.pfx - - - - - onecoreuap.lib;%(AdditionalDependencies) - - - - - /bigobj %(AdditionalOptions) - 4453;28204 - - - - - /bigobj %(AdditionalOptions) - 4453;28204 - - - - - /bigobj %(AdditionalOptions) - 4453;28204 - - - - - /bigobj %(AdditionalOptions) - 4453;28204 - - - - - /bigobj %(AdditionalOptions) - 4453;28204 - - - - - /bigobj %(AdditionalOptions) - 4453;28204 - - - - - - App.xaml - - - MainPage.xaml - - - - - Designer - - - Designer - - - - - Designer - - - - - - - - - - - - - - - App.xaml - - - MainPage.xaml - - - Create - Create - Create - Create - Create - Create - - - - - - + + + + {1dc1814a-c942-4468-9b4f-96008974d9e3} + DeviceIoControlUwp + en-US + 14.0 + true + Windows Store + 10.0.19041.0 + 10.0.15063.0 + 10.0 + + <_NoWinAPIFamilyApp>true + CustomDeviceAccessorUWP + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + Application + true + v141 + + + Application + true + v141 + + + Application + true + v142 + + + Application + false + true + v141 + true + + + Application + false + true + v141 + true + + + Application + false + true + v142 + true + + + + + + + + + + + + + + + + + + + + + + + + + CustomDeviceAccessorUWP_TemporaryKey.pfx + + + + + onecoreuap.lib;%(AdditionalDependencies) + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + + + + App.xaml + + + MainPage.xaml + + + + + Designer + + + Designer + + + + + Designer + + + + + + + + + + + + + + + App.xaml + + + MainPage.xaml + + + Create + Create + Create + Create + Create + Create + + + + + + diff --git a/samples/CustomDeviceAccessor/CPP/MainPage.xaml b/samples/CustomDeviceAccessor/CPP/MainPage.xaml index f5ad318ac..b50fc868a 100644 --- a/samples/CustomDeviceAccessor/CPP/MainPage.xaml +++ b/samples/CustomDeviceAccessor/CPP/MainPage.xaml @@ -1,14 +1,14 @@ - - - - - - - + + + + + + + diff --git a/samples/CustomDeviceAccessor/CPP/MainPage.xaml.cpp b/samples/CustomDeviceAccessor/CPP/MainPage.xaml.cpp index 7ecf513e7..40b7f2f54 100644 --- a/samples/CustomDeviceAccessor/CPP/MainPage.xaml.cpp +++ b/samples/CustomDeviceAccessor/CPP/MainPage.xaml.cpp @@ -1,86 +1,86 @@ -// Copyright (c) Microsoft. All rights reserved. - -// -// MainPage.xaml.cpp -// Implementation of the MainPage class. -// - -#include "pch.h" -#include "MainPage.xaml.h" - -using namespace CustomDeviceAccessorUWP; - -using namespace Platform; -using namespace Windows::Foundation; -using namespace Windows::Foundation::Collections; -using namespace Windows::UI::Xaml; -using namespace Windows::UI::Xaml::Controls; -using namespace Windows::UI::Xaml::Controls::Primitives; -using namespace Windows::UI::Xaml::Data; -using namespace Windows::UI::Xaml::Input; -using namespace Windows::UI::Xaml::Media; -using namespace Windows::UI::Xaml::Navigation; - -// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 - -void AccessComPort () -{ - using namespace Microsoft::WRL::Wrappers; - - // Open the COM port synchronously for simplicity. - // You'll almost always want to use FILE_FLAG_OVERLAPPED - // for COM ports. - FileHandle fileHandle(CreateFile( - L"\\\\.\\COM1", - GENERIC_READ | GENERIC_WRITE, - 0, - nullptr, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - nullptr)); - - if (!fileHandle.IsValid()) { - DWORD lastError = GetLastError(); - throw ref new Exception( // set a breakpoint here - HRESULT_FROM_WIN32(lastError), - L"Failed to open COM port."); - } - - // Set baud rate - SERIAL_BAUD_RATE inputBuffer = { 115200 }; - DWORD information; - if (!DeviceIoControl( - fileHandle.Get(), - IOCTL_SERIAL_SET_BAUD_RATE, - &inputBuffer, - sizeof(inputBuffer), - nullptr, - 0, - &information, - nullptr)) { - - throw ref new Exception( - HRESULT_FROM_WIN32(GetLastError()), - L"Failed to set baud rate."); - } - - // Write out a string over the serial port - const char message[] = "Hello serial!\n"; - if (!WriteFile( - fileHandle.Get(), - message, - sizeof(message), - &information, - nullptr)) { - - throw ref new Exception( - HRESULT_FROM_WIN32(GetLastError()), - L"Failed to write data to COM port."); - } -} - -MainPage::MainPage() -{ - InitializeComponent(); - AccessComPort(); -} +// Copyright (c) Microsoft. All rights reserved. + +// +// MainPage.xaml.cpp +// Implementation of the MainPage class. +// + +#include "pch.h" +#include "MainPage.xaml.h" + +using namespace CustomDeviceAccessorUWP; + +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Controls::Primitives; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Input; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::UI::Xaml::Navigation; + +// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 + +void AccessComPort () +{ + using namespace Microsoft::WRL::Wrappers; + + // Open the COM port synchronously for simplicity. + // You'll almost always want to use FILE_FLAG_OVERLAPPED + // for COM ports. + FileHandle fileHandle(CreateFile( + L"\\\\.\\COM1", + GENERIC_READ | GENERIC_WRITE, + 0, + nullptr, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + nullptr)); + + if (!fileHandle.IsValid()) { + DWORD lastError = GetLastError(); + throw ref new Exception( // set a breakpoint here + HRESULT_FROM_WIN32(lastError), + L"Failed to open COM port."); + } + + // Set baud rate + SERIAL_BAUD_RATE inputBuffer = { 115200 }; + DWORD information; + if (!DeviceIoControl( + fileHandle.Get(), + IOCTL_SERIAL_SET_BAUD_RATE, + &inputBuffer, + sizeof(inputBuffer), + nullptr, + 0, + &information, + nullptr)) { + + throw ref new Exception( + HRESULT_FROM_WIN32(GetLastError()), + L"Failed to set baud rate."); + } + + // Write out a string over the serial port + const char message[] = "Hello serial!\n"; + if (!WriteFile( + fileHandle.Get(), + message, + sizeof(message), + &information, + nullptr)) { + + throw ref new Exception( + HRESULT_FROM_WIN32(GetLastError()), + L"Failed to write data to COM port."); + } +} + +MainPage::MainPage() +{ + InitializeComponent(); + AccessComPort(); +} diff --git a/samples/CustomDeviceAccessor/CPP/MainPage.xaml.h b/samples/CustomDeviceAccessor/CPP/MainPage.xaml.h index 08a596bf3..e5b041217 100644 --- a/samples/CustomDeviceAccessor/CPP/MainPage.xaml.h +++ b/samples/CustomDeviceAccessor/CPP/MainPage.xaml.h @@ -1,23 +1,23 @@ -// Copyright (c) Microsoft. All rights reserved. - -// -// MainPage.xaml.h -// Declaration of the MainPage class. -// - -#pragma once - -#include "MainPage.g.h" - -namespace CustomDeviceAccessorUWP -{ - /// - /// An empty page that can be used on its own or navigated to within a Frame. - /// - public ref class MainPage sealed - { - public: - MainPage(); - - }; -} +// Copyright (c) Microsoft. All rights reserved. + +// +// MainPage.xaml.h +// Declaration of the MainPage class. +// + +#pragma once + +#include "MainPage.g.h" + +namespace CustomDeviceAccessorUWP +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public ref class MainPage sealed + { + public: + MainPage(); + + }; +} diff --git a/samples/CustomDeviceAccessor/CPP/Package.appxmanifest b/samples/CustomDeviceAccessor/CPP/Package.appxmanifest index 5b1c57cc9..94a4011fb 100644 --- a/samples/CustomDeviceAccessor/CPP/Package.appxmanifest +++ b/samples/CustomDeviceAccessor/CPP/Package.appxmanifest @@ -1,29 +1,29 @@ - - - - - - - CustomDeviceAccessorUWP - MSFT - Assets\StoreLogo.png - - - - - - - - - - - - - - - - - - - + + + + + + + CustomDeviceAccessorUWP + MSFT + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/CustomDeviceAccessor/CPP/README.md b/samples/CustomDeviceAccessor/CPP/README.md index 0e89d1294..b7991da20 100644 --- a/samples/CustomDeviceAccessor/CPP/README.md +++ b/samples/CustomDeviceAccessor/CPP/README.md @@ -1,270 +1,270 @@ ---- -page_type: sample -urlFragment: custom-device-accessor -languages: - - cpp -products: - - Windows 10 - - Windows IoT - - Windows 10 IoT Enterprise -description: This sample shows how to access devices from UWP applications using familiar win32 APIs like CreateFile(), ReadFile(), WriteFile(), and DeviceIoControl() with Windows 10 IoT Enterprise. ---- - -# Custom Device Accessor - -This sample shows how to access devices from UWP applications using familiar win32 APIs like CreateFile(), ReadFile(), WriteFile(), and DeviceIoControl(). Some reasons you may want to do this are: - - - You have existing code that uses CreateFile() - - You prefer the programming model of the win32 APIs to Windows.Devices.Custom - - Your application needs the performance of the win32 APIs - - You need to open the device synchronously, because the device driver requires it, or you need to leverage FastIO - -While you will be able to debug and deploy this app on devices you own by sideloading the application, you will not be able to upload an app that uses unsupported APIs to the Windows Store. - -The high level steps involved are: - - 1. Create a C++/CX UWP application - 2. Set an msbuild property named `_NoWinAPIFamilyApp` to `true` in the vcxproj file - 3. Use CreateFile/ReadFile/WriteFile/DeviceIoControl in your code - 4. Make the device accessible to appcontainer processes - -This walkthrough uses the COM port on UP Board as the example device. UP Board has 2 COM ports - one high-speed UARTs on the 40-pin header, and a conventional COM port controlled by serial.sys on a separate header. The oone high speed UARTs are already exposed to UWP applications, but the COM port is not. This walkthrough shows you how to access the COM port from UWP applications. - -## Exposing the COM port to usermode - -Before we can access the COM port, we need to add the `PortName` registry value under the device's hardware key so that serial.sys will create a device interface and symbolic link. On desktop flavors of Windows, this is handled by the ports class coinstaller (msports.dll), but since coinstallers are not supported on onecore-based editions, we need to add this reg key manually. - - Reg add "HKLM\SYSTEM\ControlSet001\Enum\ACPI\PNP0501\1\Device Parameters" /v PortName /t REG_SZ /d COM1 - Devcon restart acpi\pnp0501 - -If you now run `mincomm -list`, you should see ACPI\PNP0501\1 in the list of COM ports. Mincomm is available at [here](https://github.com/ms-iot/samples/tree/develop/MinComm). - -## Enabling access to desktop APIs in a C++/CX UWP Application - -Create a new project by going to File -> New -> Project -> Visual C++ -> Windows-> Universal -> Blank App (Universal Windows), and click OK. - -Open the .vcxproj file in a text editor and add the `<_NoWinAPIFamilyAPP>` element to the first PropertyGroup element: - -
-<PropertyGroup Label="Globals">
-    <ProjectGuid>...</ProjectGuid>
-    ...
-    <!-- Add the following property to make desktop APIs visible at compile time. -->
-    <_NoWinAPIFamilyApp>true</_NoWinAPIFamilyApp>
-</PropertyGroup>
-
- -When you define `_NoWinAPIFamilyApp`, it causes `WINAPI_FAMILY` to be left undefined, instead of defined to `WINAPI_FAMILY_APP`. If `WINAPI_FAMILY` is not defined, it will default to `WINAPI_FAMILY_DESKTOP_APP`, which makes desktop APIs visible at compile time. The `_NoWinAPIFamilyApp` property is referenced as follows by C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\Microsoft.Cpp.AppContainerApplication.props: - - %(PreprocessorDefinitions);WINAPI_FAMILY=WINAPI_FAMILY_APP - -For more information on API families, see winapifamily.h from the SDK. - -We also need to link against onecoreuap.lib, which exports all symbols available on OnecoreUAP-based editions. Add an `AdditionalDependencies` element containing onecoreuap.lib just after the PropertyGroup that contains the `PackageCertificateKeyFile` element. - -
-<PropertyGroup>
-    <PackageCertificateKeyFile>CustomDeviceAccessorUWP_TemporaryKey.pfx</PackageCertificateKeyFile>
-</PropertyGroup>
-<!-- Link against onecoreuap.lib so we can use CreateFile() and friends. -->
-<ItemDefinitionGroup>
-    <Link>
-        <AdditionalDependencies>onecoreuap.lib;%(AdditionalDependencies)</AdditionalDependencies>
-    </Link>
-</ItemDefinitionGroup>
-
- -## Use CreateFile/DeviceIoControl in your Application - -Add the following code to pch.h: - -``` C++ - - #include - #include - - // Undefine symbols to avoid collision with ntddser.h - #undef SERIAL_LSRMST_ESCAPE - #undef SERIAL_LSRMST_LSR_DATA - #undef SERIAL_LSRMST_LSR_NODATA - #undef SERIAL_LSRMST_MST - #undef SERIAL_IOC_FCR_FIFO_ENABLE - #undef SERIAL_IOC_FCR_RCVR_RESET - #undef SERIAL_IOC_FCR_XMIT_RESET - #undef SERIAL_IOC_FCR_DMA_MODE - #undef SERIAL_IOC_FCR_RES1 - #undef SERIAL_IOC_FCR_RES2 - #undef SERIAL_IOC_FCR_RCVR_TRIGGER_LSB - #undef SERIAL_IOC_FCR_RCVR_TRIGGER_MSB - #undef SERIAL_IOC_MCR_DTR - #undef SERIAL_IOC_MCR_RTS - #undef SERIAL_IOC_MCR_OUT1 - #undef SERIAL_IOC_MCR_OUT2 - #undef SERIAL_IOC_MCR_LOOP - - #include - #include - -``` - -Add the following code to Mainpage.xaml.cpp: - -``` C++ - void AccessComPort () - { - using namespace Microsoft::WRL::Wrappers; - - // Open the COM port synchronously for simplicity. - // You'll almost always want to use FILE_FLAG_OVERLAPPED - // for COM ports. - FileHandle fileHandle(CreateFile( - L"\\\\.\\COM1", - GENERIC_READ | GENERIC_WRITE, - 0, - nullptr, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL /*FILE_FLAG_OVERLAPPED*/, - nullptr)); - - if (!fileHandle.IsValid()) { - DWORD lastError = GetLastError(); - throw ref new Exception( // set a breakpoint here - HRESULT_FROM_WIN32(lastError), - L"Failed to open COM port."); - } - - DWORD information; - SERIAL_BAUD_RATE inputBuffer = { 115200 }; - if (!DeviceIoControl( - fileHandle.Get(), - IOCTL_SERIAL_SET_BAUD_RATE, - &inputBuffer, - sizeof(inputBuffer), - nullptr, - 0, - &information, - nullptr)) { - - throw ref new Exception( - HRESULT_FROM_WIN32(GetLastError()), - L"Failed to set baud rate."); - } - - const char message[] = "Hello serial!\n"; - if (!WriteFile( - fileHandle.Get(), - message, - sizeof(message), - &information, - nullptr)) { - - throw ref new Exception( - HRESULT_FROM_WIN32(GetLastError()), - L"Failed to write data to COM port."); - } - } -``` - -Add a call to `AccessComPort()` in the MainPage constructor: - -``` C++ - MainPage::MainPage() - { - InitializeComponent(); - AccessComPort(); - } -``` - -### Deploy your app - -* If you're building for [UP Board](https://up-board.org/up/specifications/), select `x64` as the architecture. -* Select **Local Machine** to point to IoT device and hit F5 to deploy to your device. -* Build the project, which should succeed because we made desktop APIs visible at compile time. -* Set a breakpoint on the `throw` statement after the file handle validity check, as indicated in the source code above. -* Debug the application on UP Board. The breakpoint should get hit. Inspect the `lastError` variable in the debugger, which should equal 5 (Access Denied). We need to set a proper security descriptor on the device object so it can be accessed by UWP applications. - -### [Generate an app package](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#generate-an-app-package) - -### [Install your app package using an install script](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#install-your-app-package-using-an-install-script) - -## Granting Access to AppContainer Processes - -Every device object in the system has an associated security descriptor. The security descriptor determines who has what access to a device object. Security descriptors have a binary representation which is used by the system to compute access to objects, and a human readable form called an SDDL string. Some examples of SDDL strings are: - - - - - - - - - - - - - - - - - - - - - - - - - -
SDDL StringDescriptionWdmsec.h constant
"D:P"Denies access to all, except other kernel-mode clients. SDDL_DEVOBJ_KERNEL_ONLY
"D:P(A;;GA;;;SY)"Denies access to all, except kernel mode code, and usermode clients running under the SYSTEM account.SDDL_DEVOBJ_SYS_ALL
"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GR;;;WD)"Grants full access to kernel mode clients and the SYSTEM account, grants read, write, execute to built-in Administrators, and grants read-only access to everyone else.SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_R
- -A number of common security descriptor strings are defined in wdmsec.h. - -To make a device accessible to UWP applications, you need to grant access to the All Application Packages security principle, which is represented by the SID string "AC". The following SDDL will grant GENERIC_ALL permissions to SYSTEM, built-in administrators, authenticated users, and appcontainer applications: - - "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;AU)(A;;GA;;;AC)" - -If you control the code of the driver you wish to access, you can programatically assign an SDDL string to a device object using the [IoCreateDeviceObjectSecure()](https://msdn.microsoft.com/en-us/library/windows/hardware/ff548407(v=vs.85).aspx) routine in WDM drivers, or the [WdfDeviceInitAssignSDDLString()](https://msdn.microsoft.com/en-us/library/windows/hardware/ff546035(v=vs.85).aspx) routine in WDF drivers. - -If you do not control the driver code for your device, you can override the SDDL for any device using the registry. If a registry value named "Security" is present in the hardware registry key for a device, the system will use the specified security descriptor instead of the one supplied by the driver. We will override the security descriptor for the COM port with one that grants access to all appcontainer applications. - -First, we need to convert the SDDL string to its binary representation. We can do this with [PowerShell](http://blogs.technet.com/b/heyscriptingguy/archive/2011/08/09/use-powershell-to-convert-sddl-to-binary-format.aspx). Open a PowerShell prompt and run the following commands: - -```csharp - $a = ([wmiclass]"Win32_SecurityDescriptorHelper").SDDLToBinarySD("D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;AU)(A;;GA;;;AC)").BinarySD | % { '{0:X}' -f $_ } - $a -join ',' -``` - -The output will be a long string of comma-separated numbers that we will paste into a registry file. Create a file named deviceac.reg with the following contents: - - Windows Registry Editor Version 5.00 - - [HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\ACPI\PNP0501\1] - "Security"=hex:1,0,4,90,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,2,0,60,0,4,0,0,0,0,0,14,0,0,0,0,10,1,1,0,0,0,0,0,5,12,0,0,0,0,0,18,0,0,0,0,10,1,2,0,0,0,0,0,5,20,0,0,0,20,2,0,0,0,0,14,0,0,0,0,10,1,1,0,0,0,0,0,5,B,0,0,0,0,0,18,0,0,0,0,10,1,2,0,0,0,0,0,F,2,0,0,0,1,0,0,0 - -Verify that the Security registry value was created by running: - - reg query HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\ACPI\PNP0501\1 /v Security - -If you don't see the Security value, something went wrong in the previous steps. If the Security value was created successfully, restart the device so the new security settings take effect: - - Devcon restart acpi\pnp0501 - -Now, debug the universal application again. The COM port should be opened successfully and the breakpoint above should not be hit. - -Congratulations, you have successfully opened a device and sent an IOCTL to it! - -## Granting Access to a Specific Application - -The security identifier "AC" identifies all application packages, and will grant all apps access to the device. If you want to grant access to a specific application only, you can replace "AC" in the SDDL above with the app-specific SID of the application you'd like to target. You can inspect the app-specific SID with [process explorer](https://technet.microsoft.com/en-us/sysinternals/bb896653). - -Launch the app and launch process explorer. Open the properties dialog box for the process in process explorer and go to the Security tab. There you will see all of the security identifiers associated with the process's token. The SID with the AppContainer flag set is the app-specific SID. - -![Process Explorer](../../../Resources/images/CustomDeviceAccessorUwp-AppContainerSid.png) - -You can replace "AC" with this SID in the above SDDL to generate an SDDL that grants access to that specific application only. For example, the following SDDL would grant access only to the application shown above: - - "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;AU)(A;;GA;;;S-1-15-3-2628158189-2540711686-3785793668-522787976-4226511596-526649915-1865015409)" - -SIDs are generated at application install time so can only be determined after the application has been installed on the target machine. - -For more information about app containers, see [Windows 8 App Container Security Notes - Part 1](http://recxltd.blogspot.com/2012/03/windows-8-app-container-security-notes.html). +--- +page_type: sample +urlFragment: custom-device-accessor +languages: + - cpp +products: + - Windows 10 + - Windows IoT + - Windows 10 IoT Enterprise +description: This sample shows how to access devices from UWP applications using familiar win32 APIs like CreateFile(), ReadFile(), WriteFile(), and DeviceIoControl() with Windows 10 IoT Enterprise. +--- + +# Custom Device Accessor + +This sample shows how to access devices from UWP applications using familiar win32 APIs like CreateFile(), ReadFile(), WriteFile(), and DeviceIoControl(). Some reasons you may want to do this are: + + - You have existing code that uses CreateFile() + - You prefer the programming model of the win32 APIs to Windows.Devices.Custom + - Your application needs the performance of the win32 APIs + - You need to open the device synchronously, because the device driver requires it, or you need to leverage FastIO + +While you will be able to debug and deploy this app on devices you own by sideloading the application, you will not be able to upload an app that uses unsupported APIs to the Windows Store. + +The high level steps involved are: + + 1. Create a C++/CX UWP application + 2. Set an msbuild property named `_NoWinAPIFamilyApp` to `true` in the vcxproj file + 3. Use CreateFile/ReadFile/WriteFile/DeviceIoControl in your code + 4. Make the device accessible to appcontainer processes + +This walkthrough uses the COM port on UP Board as the example device. UP Board has 2 COM ports - one high-speed UARTs on the 40-pin header, and a conventional COM port controlled by serial.sys on a separate header. The oone high speed UARTs are already exposed to UWP applications, but the COM port is not. This walkthrough shows you how to access the COM port from UWP applications. + +## Exposing the COM port to usermode + +Before we can access the COM port, we need to add the `PortName` registry value under the device's hardware key so that serial.sys will create a device interface and symbolic link. On desktop flavors of Windows, this is handled by the ports class coinstaller (msports.dll), but since coinstallers are not supported on onecore-based editions, we need to add this reg key manually. + + Reg add "HKLM\SYSTEM\ControlSet001\Enum\ACPI\PNP0501\1\Device Parameters" /v PortName /t REG_SZ /d COM1 + Devcon restart acpi\pnp0501 + +If you now run `mincomm -list`, you should see ACPI\PNP0501\1 in the list of COM ports. Mincomm is available at [here](https://github.com/ms-iot/samples/tree/develop/MinComm). + +## Enabling access to desktop APIs in a C++/CX UWP Application + +Create a new project by going to File -> New -> Project -> Visual C++ -> Windows-> Universal -> Blank App (Universal Windows), and click OK. + +Open the .vcxproj file in a text editor and add the `<_NoWinAPIFamilyAPP>` element to the first PropertyGroup element: + +
+<PropertyGroup Label="Globals">
+    <ProjectGuid>...</ProjectGuid>
+    ...
+    <!-- Add the following property to make desktop APIs visible at compile time. -->
+    <_NoWinAPIFamilyApp>true</_NoWinAPIFamilyApp>
+</PropertyGroup>
+
+ +When you define `_NoWinAPIFamilyApp`, it causes `WINAPI_FAMILY` to be left undefined, instead of defined to `WINAPI_FAMILY_APP`. If `WINAPI_FAMILY` is not defined, it will default to `WINAPI_FAMILY_DESKTOP_APP`, which makes desktop APIs visible at compile time. The `_NoWinAPIFamilyApp` property is referenced as follows by C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\Microsoft.Cpp.AppContainerApplication.props: + + %(PreprocessorDefinitions);WINAPI_FAMILY=WINAPI_FAMILY_APP + +For more information on API families, see winapifamily.h from the SDK. + +We also need to link against onecoreuap.lib, which exports all symbols available on OnecoreUAP-based editions. Add an `AdditionalDependencies` element containing onecoreuap.lib just after the PropertyGroup that contains the `PackageCertificateKeyFile` element. + +
+<PropertyGroup>
+    <PackageCertificateKeyFile>CustomDeviceAccessorUWP_TemporaryKey.pfx</PackageCertificateKeyFile>
+</PropertyGroup>
+<!-- Link against onecoreuap.lib so we can use CreateFile() and friends. -->
+<ItemDefinitionGroup>
+    <Link>
+        <AdditionalDependencies>onecoreuap.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+</ItemDefinitionGroup>
+
+ +## Use CreateFile/DeviceIoControl in your Application + +Add the following code to pch.h: + +``` C++ + + #include + #include + + // Undefine symbols to avoid collision with ntddser.h + #undef SERIAL_LSRMST_ESCAPE + #undef SERIAL_LSRMST_LSR_DATA + #undef SERIAL_LSRMST_LSR_NODATA + #undef SERIAL_LSRMST_MST + #undef SERIAL_IOC_FCR_FIFO_ENABLE + #undef SERIAL_IOC_FCR_RCVR_RESET + #undef SERIAL_IOC_FCR_XMIT_RESET + #undef SERIAL_IOC_FCR_DMA_MODE + #undef SERIAL_IOC_FCR_RES1 + #undef SERIAL_IOC_FCR_RES2 + #undef SERIAL_IOC_FCR_RCVR_TRIGGER_LSB + #undef SERIAL_IOC_FCR_RCVR_TRIGGER_MSB + #undef SERIAL_IOC_MCR_DTR + #undef SERIAL_IOC_MCR_RTS + #undef SERIAL_IOC_MCR_OUT1 + #undef SERIAL_IOC_MCR_OUT2 + #undef SERIAL_IOC_MCR_LOOP + + #include + #include + +``` + +Add the following code to Mainpage.xaml.cpp: + +``` C++ + void AccessComPort () + { + using namespace Microsoft::WRL::Wrappers; + + // Open the COM port synchronously for simplicity. + // You'll almost always want to use FILE_FLAG_OVERLAPPED + // for COM ports. + FileHandle fileHandle(CreateFile( + L"\\\\.\\COM1", + GENERIC_READ | GENERIC_WRITE, + 0, + nullptr, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL /*FILE_FLAG_OVERLAPPED*/, + nullptr)); + + if (!fileHandle.IsValid()) { + DWORD lastError = GetLastError(); + throw ref new Exception( // set a breakpoint here + HRESULT_FROM_WIN32(lastError), + L"Failed to open COM port."); + } + + DWORD information; + SERIAL_BAUD_RATE inputBuffer = { 115200 }; + if (!DeviceIoControl( + fileHandle.Get(), + IOCTL_SERIAL_SET_BAUD_RATE, + &inputBuffer, + sizeof(inputBuffer), + nullptr, + 0, + &information, + nullptr)) { + + throw ref new Exception( + HRESULT_FROM_WIN32(GetLastError()), + L"Failed to set baud rate."); + } + + const char message[] = "Hello serial!\n"; + if (!WriteFile( + fileHandle.Get(), + message, + sizeof(message), + &information, + nullptr)) { + + throw ref new Exception( + HRESULT_FROM_WIN32(GetLastError()), + L"Failed to write data to COM port."); + } + } +``` + +Add a call to `AccessComPort()` in the MainPage constructor: + +``` C++ + MainPage::MainPage() + { + InitializeComponent(); + AccessComPort(); + } +``` + +### Deploy your app + +* If you're building for [UP Board](https://up-board.org/up/specifications/), select `x64` as the architecture. +* Select **Local Machine** to point to IoT device and hit F5 to deploy to your device. +* Build the project, which should succeed because we made desktop APIs visible at compile time. +* Set a breakpoint on the `throw` statement after the file handle validity check, as indicated in the source code above. +* Debug the application on UP Board. The breakpoint should get hit. Inspect the `lastError` variable in the debugger, which should equal 5 (Access Denied). We need to set a proper security descriptor on the device object so it can be accessed by UWP applications. + +### [Generate an app package](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#generate-an-app-package) + +### [Install your app package using an install script](https://docs.microsoft.com/windows/msix/package/packaging-uwp-apps#install-your-app-package-using-an-install-script) + +## Granting Access to AppContainer Processes + +Every device object in the system has an associated security descriptor. The security descriptor determines who has what access to a device object. Security descriptors have a binary representation which is used by the system to compute access to objects, and a human readable form called an SDDL string. Some examples of SDDL strings are: + + + + + + + + + + + + + + + + + + + + + + + + + +
SDDL StringDescriptionWdmsec.h constant
"D:P"Denies access to all, except other kernel-mode clients. SDDL_DEVOBJ_KERNEL_ONLY
"D:P(A;;GA;;;SY)"Denies access to all, except kernel mode code, and usermode clients running under the SYSTEM account.SDDL_DEVOBJ_SYS_ALL
"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GR;;;WD)"Grants full access to kernel mode clients and the SYSTEM account, grants read, write, execute to built-in Administrators, and grants read-only access to everyone else.SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_R
+ +A number of common security descriptor strings are defined in wdmsec.h. + +To make a device accessible to UWP applications, you need to grant access to the All Application Packages security principle, which is represented by the SID string "AC". The following SDDL will grant GENERIC_ALL permissions to SYSTEM, built-in administrators, authenticated users, and appcontainer applications: + + "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;AU)(A;;GA;;;AC)" + +If you control the code of the driver you wish to access, you can programatically assign an SDDL string to a device object using the [IoCreateDeviceObjectSecure()](https://msdn.microsoft.com/en-us/library/windows/hardware/ff548407(v=vs.85).aspx) routine in WDM drivers, or the [WdfDeviceInitAssignSDDLString()](https://msdn.microsoft.com/en-us/library/windows/hardware/ff546035(v=vs.85).aspx) routine in WDF drivers. + +If you do not control the driver code for your device, you can override the SDDL for any device using the registry. If a registry value named "Security" is present in the hardware registry key for a device, the system will use the specified security descriptor instead of the one supplied by the driver. We will override the security descriptor for the COM port with one that grants access to all appcontainer applications. + +First, we need to convert the SDDL string to its binary representation. We can do this with [PowerShell](http://blogs.technet.com/b/heyscriptingguy/archive/2011/08/09/use-powershell-to-convert-sddl-to-binary-format.aspx). Open a PowerShell prompt and run the following commands: + +```csharp + $a = ([wmiclass]"Win32_SecurityDescriptorHelper").SDDLToBinarySD("D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;AU)(A;;GA;;;AC)").BinarySD | % { '{0:X}' -f $_ } + $a -join ',' +``` + +The output will be a long string of comma-separated numbers that we will paste into a registry file. Create a file named deviceac.reg with the following contents: + + Windows Registry Editor Version 5.00 + + [HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\ACPI\PNP0501\1] + "Security"=hex:1,0,4,90,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,2,0,60,0,4,0,0,0,0,0,14,0,0,0,0,10,1,1,0,0,0,0,0,5,12,0,0,0,0,0,18,0,0,0,0,10,1,2,0,0,0,0,0,5,20,0,0,0,20,2,0,0,0,0,14,0,0,0,0,10,1,1,0,0,0,0,0,5,B,0,0,0,0,0,18,0,0,0,0,10,1,2,0,0,0,0,0,F,2,0,0,0,1,0,0,0 + +Verify that the Security registry value was created by running: + + reg query HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\ACPI\PNP0501\1 /v Security + +If you don't see the Security value, something went wrong in the previous steps. If the Security value was created successfully, restart the device so the new security settings take effect: + + Devcon restart acpi\pnp0501 + +Now, debug the universal application again. The COM port should be opened successfully and the breakpoint above should not be hit. + +Congratulations, you have successfully opened a device and sent an IOCTL to it! + +## Granting Access to a Specific Application + +The security identifier "AC" identifies all application packages, and will grant all apps access to the device. If you want to grant access to a specific application only, you can replace "AC" in the SDDL above with the app-specific SID of the application you'd like to target. You can inspect the app-specific SID with [process explorer](https://technet.microsoft.com/en-us/sysinternals/bb896653). + +Launch the app and launch process explorer. Open the properties dialog box for the process in process explorer and go to the Security tab. There you will see all of the security identifiers associated with the process's token. The SID with the AppContainer flag set is the app-specific SID. + +![Process Explorer](../../../Resources/images/CustomDeviceAccessorUwp-AppContainerSid.png) + +You can replace "AC" with this SID in the above SDDL to generate an SDDL that grants access to that specific application only. For example, the following SDDL would grant access only to the application shown above: + + "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;AU)(A;;GA;;;S-1-15-3-2628158189-2540711686-3785793668-522787976-4226511596-526649915-1865015409)" + +SIDs are generated at application install time so can only be determined after the application has been installed on the target machine. + +For more information about app containers, see [Windows 8 App Container Security Notes - Part 1](http://recxltd.blogspot.com/2012/03/windows-8-app-container-security-notes.html). diff --git a/samples/CustomDeviceAccessor/CPP/pch.cpp b/samples/CustomDeviceAccessor/CPP/pch.cpp index b459044b7..dbd902d13 100644 --- a/samples/CustomDeviceAccessor/CPP/pch.cpp +++ b/samples/CustomDeviceAccessor/CPP/pch.cpp @@ -1,8 +1,8 @@ -// Copyright (c) Microsoft. All rights reserved. - -// -// pch.cpp -// Include the standard header and generate the precompiled header. -// - -#include "pch.h" +// Copyright (c) Microsoft. All rights reserved. + +// +// pch.cpp +// Include the standard header and generate the precompiled header. +// + +#include "pch.h" diff --git a/samples/CustomDeviceAccessor/CPP/pch.h b/samples/CustomDeviceAccessor/CPP/pch.h index 49b76a6cb..386a38ad8 100644 --- a/samples/CustomDeviceAccessor/CPP/pch.h +++ b/samples/CustomDeviceAccessor/CPP/pch.h @@ -1,37 +1,37 @@ -// Copyright (c) Microsoft. All rights reserved. - -// -// pch.h -// Header for standard system include files. -// - -#pragma once - -#include -#include -#include -#include - -// Undefine symbols to avoid collision with ntddser.h -#undef SERIAL_LSRMST_ESCAPE -#undef SERIAL_LSRMST_LSR_DATA -#undef SERIAL_LSRMST_LSR_NODATA -#undef SERIAL_LSRMST_MST -#undef SERIAL_IOC_FCR_FIFO_ENABLE -#undef SERIAL_IOC_FCR_RCVR_RESET -#undef SERIAL_IOC_FCR_XMIT_RESET -#undef SERIAL_IOC_FCR_DMA_MODE -#undef SERIAL_IOC_FCR_RES1 -#undef SERIAL_IOC_FCR_RES2 -#undef SERIAL_IOC_FCR_RCVR_TRIGGER_LSB -#undef SERIAL_IOC_FCR_RCVR_TRIGGER_MSB -#undef SERIAL_IOC_MCR_DTR -#undef SERIAL_IOC_MCR_RTS -#undef SERIAL_IOC_MCR_OUT1 -#undef SERIAL_IOC_MCR_OUT2 -#undef SERIAL_IOC_MCR_LOOP - -#include -#include - -#include "App.xaml.h" +// Copyright (c) Microsoft. All rights reserved. + +// +// pch.h +// Header for standard system include files. +// + +#pragma once + +#include +#include +#include +#include + +// Undefine symbols to avoid collision with ntddser.h +#undef SERIAL_LSRMST_ESCAPE +#undef SERIAL_LSRMST_LSR_DATA +#undef SERIAL_LSRMST_LSR_NODATA +#undef SERIAL_LSRMST_MST +#undef SERIAL_IOC_FCR_FIFO_ENABLE +#undef SERIAL_IOC_FCR_RCVR_RESET +#undef SERIAL_IOC_FCR_XMIT_RESET +#undef SERIAL_IOC_FCR_DMA_MODE +#undef SERIAL_IOC_FCR_RES1 +#undef SERIAL_IOC_FCR_RES2 +#undef SERIAL_IOC_FCR_RCVR_TRIGGER_LSB +#undef SERIAL_IOC_FCR_RCVR_TRIGGER_MSB +#undef SERIAL_IOC_MCR_DTR +#undef SERIAL_IOC_MCR_RTS +#undef SERIAL_IOC_MCR_OUT1 +#undef SERIAL_IOC_MCR_OUT2 +#undef SERIAL_IOC_MCR_LOOP + +#include +#include + +#include "App.xaml.h" diff --git a/samples/CustomDeviceAccessor/README.md b/samples/CustomDeviceAccessor/README.md index a2a685b43..48e0c7e0d 100644 --- a/samples/CustomDeviceAccessor/README.md +++ b/samples/CustomDeviceAccessor/README.md @@ -1,293 +1,293 @@ ---- -page_type: sample -urlFragment: custom-device-accessor -languages: - - cpp -products: - - windows - - windows-iot - - windows-10-iot-Enterprise -description: This sample shows how to access devices from UWP applications using familiar win32 APIs like CreateFile(), ReadFile(), WriteFile(), and DeviceIoControl() with Windows 10 IoT Enterprise. ---- - -# Custom Device Accessor - -This sample shows how to access devices from UWP applications using familiar win32 APIs like CreateFile(), ReadFile(), WriteFile(), and DeviceIoControl(). Some reasons you may want to do this are: - - - You have existing code that uses CreateFile() - - You prefer the programming model of the win32 APIs to Windows.Devices.Custom - - Your application needs the performance of the win32 APIs - - You need to open the device synchronously, because the device driver requires it, or you need to leverage FastIO - -While you will be able to debug and deploy this app on devices you own by sideloading the application, you will not be able to upload an app that uses unsupported APIs to the Windows Store. - -The high level steps involved are: - - 1. Create a C++/CX UWP application - 2. Set an msbuild property named `_NoWinAPIFamilyApp` to `true` in the vcxproj file - 3. Use CreateFile/ReadFile/WriteFile/DeviceIoControl in your code - 4. Make the device accessible to appcontainer processes - -This walkthrough uses the COM port on UP Board as the example device. UP Board has 2 COM ports - one high-speed UARTs on the 40-pin header, and a conventional COM port controlled by serial.sys on a separate header. The one high speed UARTs are already exposed to UWP applications, but the COM port is not. This walkthrough shows you how to access the COM port from UWP applications. - -## Exposing the COM port to usermode - -Before we can access the COM port, we need to add the `PortName` registry value under the device's hardware key so that serial.sys will create a device interface and symbolic link. On desktop flavors of Windows, this is handled by the ports class coinstaller (msports.dll), but since coinstallers are not supported on onecore-based editions, we need to add this reg key manually. - - Reg add "HKLM\SYSTEM\ControlSet001\Enum\ACPI\PNP0501\1\Device Parameters" /v PortName /t REG_SZ /d COM1 - Devcon restart acpi\pnp0501 - -If you now run `mincomm -list`, you should see ACPI\PNP0501\1 in the list of COM ports. Mincomm is available at [here](https://github.com/ms-iot/samples/tree/develop/MinComm). - -## Enabling access to desktop APIs in a C++/CX UWP Application - -Create a new project by going to File -> New -> Project -> Visual C++ -> Windows-> Universal -> Blank App (Universal Windows), and click OK. - -Open the .vcxproj file in a text editor and add the `<_NoWinAPIFamilyAPP>` element to the first PropertyGroup element: - -
-<PropertyGroup Label="Globals">
-    <ProjectGuid>...</ProjectGuid>
-    ...
-    <!-- Add the following property to make desktop APIs visible at compile time. -->
-    <_NoWinAPIFamilyApp>true</_NoWinAPIFamilyApp>
-</PropertyGroup>
-
- -When you define `_NoWinAPIFamilyApp`, it causes `WINAPI_FAMILY` to be left undefined, instead of defined to `WINAPI_FAMILY_APP`. If `WINAPI_FAMILY` is not defined, it will default to `WINAPI_FAMILY_DESKTOP_APP`, which makes desktop APIs visible at compile time. The `_NoWinAPIFamilyApp` property is referenced as follows by C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\Microsoft.Cpp.AppContainerApplication.props: - - %(PreprocessorDefinitions);WINAPI_FAMILY=WINAPI_FAMILY_APP - -For more information on API families, see winapifamily.h from the SDK. - -We also need to link against onecoreuap.lib, which exports all symbols available on OnecoreUAP-based editions. Add an `AdditionalDependencies` element containing onecoreuap.lib just after the PropertyGroup that contains the `PackageCertificateKeyFile` element. - -
-<PropertyGroup>
-    <PackageCertificateKeyFile>CustomDeviceAccessorUWP_TemporaryKey.pfx</PackageCertificateKeyFile>
-</PropertyGroup>
-<!-- Link against onecoreuap.lib so we can use CreateFile() and friends. -->
-<ItemDefinitionGroup>
-    <Link>
-        <AdditionalDependencies>onecoreuap.lib;%(AdditionalDependencies)</AdditionalDependencies>
-    </Link>
-</ItemDefinitionGroup>
-
- -## Use CreateFile/DeviceIoControl in your Application - -Add the following code to pch.h: - -``` C++ - - #include - #include - - // Undefine symbols to avoid collision with ntddser.h - #undef SERIAL_LSRMST_ESCAPE - #undef SERIAL_LSRMST_LSR_DATA - #undef SERIAL_LSRMST_LSR_NODATA - #undef SERIAL_LSRMST_MST - #undef SERIAL_IOC_FCR_FIFO_ENABLE - #undef SERIAL_IOC_FCR_RCVR_RESET - #undef SERIAL_IOC_FCR_XMIT_RESET - #undef SERIAL_IOC_FCR_DMA_MODE - #undef SERIAL_IOC_FCR_RES1 - #undef SERIAL_IOC_FCR_RES2 - #undef SERIAL_IOC_FCR_RCVR_TRIGGER_LSB - #undef SERIAL_IOC_FCR_RCVR_TRIGGER_MSB - #undef SERIAL_IOC_MCR_DTR - #undef SERIAL_IOC_MCR_RTS - #undef SERIAL_IOC_MCR_OUT1 - #undef SERIAL_IOC_MCR_OUT2 - #undef SERIAL_IOC_MCR_LOOP - - #include - #include - -``` - -Add the following code to Mainpage.xaml.cpp: - -``` C++ - void AccessComPort () - { - using namespace Microsoft::WRL::Wrappers; - - // Open the COM port synchronously for simplicity. - // You'll almost always want to use FILE_FLAG_OVERLAPPED - // for COM ports. - FileHandle fileHandle(CreateFile( - L"\\\\.\\COM1", - GENERIC_READ | GENERIC_WRITE, - 0, - nullptr, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL /*FILE_FLAG_OVERLAPPED*/, - nullptr)); - - if (!fileHandle.IsValid()) { - DWORD lastError = GetLastError(); - throw ref new Exception( // set a breakpoint here - HRESULT_FROM_WIN32(lastError), - L"Failed to open COM port."); - } - - DWORD information; - SERIAL_BAUD_RATE inputBuffer = { 115200 }; - if (!DeviceIoControl( - fileHandle.Get(), - IOCTL_SERIAL_SET_BAUD_RATE, - &inputBuffer, - sizeof(inputBuffer), - nullptr, - 0, - &information, - nullptr)) { - - throw ref new Exception( - HRESULT_FROM_WIN32(GetLastError()), - L"Failed to set baud rate."); - } - - const char message[] = "Hello serial!\n"; - if (!WriteFile( - fileHandle.Get(), - message, - sizeof(message), - &information, - nullptr)) { - - throw ref new Exception( - HRESULT_FROM_WIN32(GetLastError()), - L"Failed to write data to COM port."); - } - } -``` - -Add a call to `AccessComPort()` in the MainPage constructor: - -``` C++ - MainPage::MainPage() - { - InitializeComponent(); - AccessComPort(); - } -``` - -### Deploy your app - -* If you're building for UPBoard, select `x64` as the architecture. - -* Select **Local Machine** to point to IoT device and hit F5 to deploy to your device. - -* Build the project, which should succeed because we made desktop APIs visible at compile time. - -* Set a breakpoint on the `throw` statement after the file handle validity check, as indicated in the source code above. - -* Debug the application on UP Board. The breakpoint should get hit. Inspect the `lastError` variable in the debugger, which should equal 5 (Access Denied). We need to set a proper security descriptor on the device object so it can be accessed by UWP applications. - -### Generate an app package - -Steps to follow : - - * In Solution Explorer, open the solution for your application project. - * Right-click the project and choose Publish->Create App Packages (before Visual Studio 2019 version 16.3, the Publish menu is named Store). - * Select Sideloading in the first page of the wizard and then click Next. - * On the Select signing method page, select whether to skip packaging signing or select a certificate for signing. You can select a certificate from your local certificate store, select a certificate file, or create a new certificate. For an MSIX package to be installed on an end user's machine, it must be signed with a cert that is trusted on the machine. - * Complete the Select and configure packages page as described in the Create your app package upload file using Visual Studio section. - - If you need guidance click Link: [here](https://docs.microsoft.com/en-us/windows/msix/package/packaging-uwp-apps#generate-an-app-package). - -### Install your app package using an install script - -Steps to follow : - * Open the *_Test folder. - * Right-click on the Add-AppDevPackage.ps1 file. Choose Run with PowerShell and follow the prompts. - * When the app package has been installed, the PowerShell window displays this message: Your app was successfully installed. - - If you need guidance click Link: [here](https://docs.microsoft.com/en-us/windows/msix/package/packaging-uwp-apps#install-your-app-package-using-an-install-script). - - Click the Start button to search for the app by name, and then launch it. - -## Granting Access to AppContainer Processes - -Every device object in the system has an associated security descriptor. The security descriptor determines who has what access to a device object. Security descriptors have a binary representation which is used by the system to compute access to objects, and a human readable form called an SDDL string. Some examples of SDDL strings are: - - - - - - - - - - - - - - - - - - - - - - - - - -
SDDL StringDescriptionWdmsec.h constant
"D:P"Denies access to all, except other kernel-mode clients. SDDL_DEVOBJ_KERNEL_ONLY
"D:P(A;;GA;;;SY)"Denies access to all, except kernel mode code, and usermode clients running under the SYSTEM account.SDDL_DEVOBJ_SYS_ALL
"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GR;;;WD)"Grants full access to kernel mode clients and the SYSTEM account, grants read, write, execute to built-in Administrators, and grants read-only access to everyone else.SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_R
- -A number of common security descriptor strings are defined in wdmsec.h. - -To make a device accessible to UWP applications, you need to grant access to the All Application Packages security principle, which is represented by the SID string "AC". The following SDDL will grant GENERIC_ALL permissions to SYSTEM, built-in administrators, authenticated users, and appcontainer applications: - - "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;AU)(A;;GA;;;AC)" - -If you control the code of the driver you wish to access, you can programatically assign an SDDL string to a device object using the [IoCreateDeviceObjectSecure()](https://msdn.microsoft.com/en-us/library/windows/hardware/ff548407(v=vs.85).aspx) routine in WDM drivers, or the [WdfDeviceInitAssignSDDLString()](https://msdn.microsoft.com/en-us/library/windows/hardware/ff546035(v=vs.85).aspx) routine in WDF drivers. - -If you do not control the driver code for your device, you can override the SDDL for any device using the registry. If a registry value named "Security" is present in the hardware registry key for a device, the system will use the specified security descriptor instead of the one supplied by the driver. We will override the security descriptor for the COM port with one that grants access to all appcontainer applications. - -First, we need to convert the SDDL string to its binary representation. We can do this with [PowerShell](http://blogs.technet.com/b/heyscriptingguy/archive/2011/08/09/use-powershell-to-convert-sddl-to-binary-format.aspx). Open a PowerShell prompt and run the following commands: - -```csharp - $a = ([wmiclass]"Win32_SecurityDescriptorHelper").SDDLToBinarySD("D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;AU)(A;;GA;;;AC)").BinarySD | % { '{0:X}' -f $_ } - $a -join ',' -``` - -The output will be a long string of comma-separated numbers that we will paste into a registry file. Create a file named deviceac.reg with the following contents: - - Windows Registry Editor Version 5.00 - - [HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\ACPI\PNP0501\1] - "Security"=hex:1,0,4,90,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,2,0,60,0,4,0,0,0,0,0,14,0,0,0,0,10,1,1,0,0,0,0,0,5,12,0,0,0,0,0,18,0,0,0,0,10,1,2,0,0,0,0,0,5,20,0,0,0,20,2,0,0,0,0,14,0,0,0,0,10,1,1,0,0,0,0,0,5,B,0,0,0,0,0,18,0,0,0,0,10,1,2,0,0,0,0,0,F,2,0,0,0,1,0,0,0 - -Verify that the Security registry value was created by running: - - reg query HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\ACPI\PNP0501\1 /v Security - -If you don't see the Security value, something went wrong in the previous steps. If the Security value was created successfully, restart the device so the new security settings take effect: - - Devcon restart acpi\pnp0501 - -Now, debug the universal application again. The COM port should be opened successfully and the breakpoint above should not be hit. - -Congratulations, you have successfully opened a device and sent an IOCTL to it! - -## Granting Access to a Specific Application - -The security identifier "AC" identifies all application packages, and will grant all apps access to the device. If you want to grant access to a specific application only, you can replace "AC" in the SDDL above with the app-specific SID of the application you'd like to target. You can inspect the app-specific SID with [process explorer](https://technet.microsoft.com/en-us/sysinternals/bb896653). - -Launch the app and launch process explorer. Open the properties dialog box for the process in process explorer and go to the Security tab. There you will see all of the security identifiers associated with the process's token. The SID with the AppContainer flag set is the app-specific SID. - -![Process Explorer](../../Resources/images/CustomDeviceAccessorUwp-AppContainerSid.png) - -You can replace "AC" with this SID in the above SDDL to generate an SDDL that grants access to that specific application only. For example, the following SDDL would grant access only to the application shown above: - - "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;AU)(A;;GA;;;S-1-15-3-2628158189-2540711686-3785793668-522787976-4226511596-526649915-1865015409)" - -SIDs are generated at application install time so can only be determined after the application has been installed on the target machine. - -For more information about app containers, see [Windows 8 App Container Security Notes - Part 1](http://recxltd.blogspot.com/2012/03/windows-8-app-container-security-notes.html). +--- +page_type: sample +urlFragment: custom-device-accessor +languages: + - cpp +products: + - windows + - windows-iot + - windows-10-iot-Enterprise +description: This sample shows how to access devices from UWP applications using familiar win32 APIs like CreateFile(), ReadFile(), WriteFile(), and DeviceIoControl() with Windows 10 IoT Enterprise. +--- + +# Custom Device Accessor + +This sample shows how to access devices from UWP applications using familiar win32 APIs like CreateFile(), ReadFile(), WriteFile(), and DeviceIoControl(). Some reasons you may want to do this are: + + - You have existing code that uses CreateFile() + - You prefer the programming model of the win32 APIs to Windows.Devices.Custom + - Your application needs the performance of the win32 APIs + - You need to open the device synchronously, because the device driver requires it, or you need to leverage FastIO + +While you will be able to debug and deploy this app on devices you own by sideloading the application, you will not be able to upload an app that uses unsupported APIs to the Windows Store. + +The high level steps involved are: + + 1. Create a C++/CX UWP application + 2. Set an msbuild property named `_NoWinAPIFamilyApp` to `true` in the vcxproj file + 3. Use CreateFile/ReadFile/WriteFile/DeviceIoControl in your code + 4. Make the device accessible to appcontainer processes + +This walkthrough uses the COM port on UP Board as the example device. UP Board has 2 COM ports - one high-speed UARTs on the 40-pin header, and a conventional COM port controlled by serial.sys on a separate header. The one high speed UARTs are already exposed to UWP applications, but the COM port is not. This walkthrough shows you how to access the COM port from UWP applications. + +## Exposing the COM port to usermode + +Before we can access the COM port, we need to add the `PortName` registry value under the device's hardware key so that serial.sys will create a device interface and symbolic link. On desktop flavors of Windows, this is handled by the ports class coinstaller (msports.dll), but since coinstallers are not supported on onecore-based editions, we need to add this reg key manually. + + Reg add "HKLM\SYSTEM\ControlSet001\Enum\ACPI\PNP0501\1\Device Parameters" /v PortName /t REG_SZ /d COM1 + Devcon restart acpi\pnp0501 + +If you now run `mincomm -list`, you should see ACPI\PNP0501\1 in the list of COM ports. Mincomm is available at [here](https://github.com/ms-iot/samples/tree/develop/MinComm). + +## Enabling access to desktop APIs in a C++/CX UWP Application + +Create a new project by going to File -> New -> Project -> Visual C++ -> Windows-> Universal -> Blank App (Universal Windows), and click OK. + +Open the .vcxproj file in a text editor and add the `<_NoWinAPIFamilyAPP>` element to the first PropertyGroup element: + +
+<PropertyGroup Label="Globals">
+    <ProjectGuid>...</ProjectGuid>
+    ...
+    <!-- Add the following property to make desktop APIs visible at compile time. -->
+    <_NoWinAPIFamilyApp>true</_NoWinAPIFamilyApp>
+</PropertyGroup>
+
+ +When you define `_NoWinAPIFamilyApp`, it causes `WINAPI_FAMILY` to be left undefined, instead of defined to `WINAPI_FAMILY_APP`. If `WINAPI_FAMILY` is not defined, it will default to `WINAPI_FAMILY_DESKTOP_APP`, which makes desktop APIs visible at compile time. The `_NoWinAPIFamilyApp` property is referenced as follows by C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\Microsoft.Cpp.AppContainerApplication.props: + + %(PreprocessorDefinitions);WINAPI_FAMILY=WINAPI_FAMILY_APP + +For more information on API families, see winapifamily.h from the SDK. + +We also need to link against onecoreuap.lib, which exports all symbols available on OnecoreUAP-based editions. Add an `AdditionalDependencies` element containing onecoreuap.lib just after the PropertyGroup that contains the `PackageCertificateKeyFile` element. + +
+<PropertyGroup>
+    <PackageCertificateKeyFile>CustomDeviceAccessorUWP_TemporaryKey.pfx</PackageCertificateKeyFile>
+</PropertyGroup>
+<!-- Link against onecoreuap.lib so we can use CreateFile() and friends. -->
+<ItemDefinitionGroup>
+    <Link>
+        <AdditionalDependencies>onecoreuap.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+</ItemDefinitionGroup>
+
+ +## Use CreateFile/DeviceIoControl in your Application + +Add the following code to pch.h: + +``` C++ + + #include + #include + + // Undefine symbols to avoid collision with ntddser.h + #undef SERIAL_LSRMST_ESCAPE + #undef SERIAL_LSRMST_LSR_DATA + #undef SERIAL_LSRMST_LSR_NODATA + #undef SERIAL_LSRMST_MST + #undef SERIAL_IOC_FCR_FIFO_ENABLE + #undef SERIAL_IOC_FCR_RCVR_RESET + #undef SERIAL_IOC_FCR_XMIT_RESET + #undef SERIAL_IOC_FCR_DMA_MODE + #undef SERIAL_IOC_FCR_RES1 + #undef SERIAL_IOC_FCR_RES2 + #undef SERIAL_IOC_FCR_RCVR_TRIGGER_LSB + #undef SERIAL_IOC_FCR_RCVR_TRIGGER_MSB + #undef SERIAL_IOC_MCR_DTR + #undef SERIAL_IOC_MCR_RTS + #undef SERIAL_IOC_MCR_OUT1 + #undef SERIAL_IOC_MCR_OUT2 + #undef SERIAL_IOC_MCR_LOOP + + #include + #include + +``` + +Add the following code to Mainpage.xaml.cpp: + +``` C++ + void AccessComPort () + { + using namespace Microsoft::WRL::Wrappers; + + // Open the COM port synchronously for simplicity. + // You'll almost always want to use FILE_FLAG_OVERLAPPED + // for COM ports. + FileHandle fileHandle(CreateFile( + L"\\\\.\\COM1", + GENERIC_READ | GENERIC_WRITE, + 0, + nullptr, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL /*FILE_FLAG_OVERLAPPED*/, + nullptr)); + + if (!fileHandle.IsValid()) { + DWORD lastError = GetLastError(); + throw ref new Exception( // set a breakpoint here + HRESULT_FROM_WIN32(lastError), + L"Failed to open COM port."); + } + + DWORD information; + SERIAL_BAUD_RATE inputBuffer = { 115200 }; + if (!DeviceIoControl( + fileHandle.Get(), + IOCTL_SERIAL_SET_BAUD_RATE, + &inputBuffer, + sizeof(inputBuffer), + nullptr, + 0, + &information, + nullptr)) { + + throw ref new Exception( + HRESULT_FROM_WIN32(GetLastError()), + L"Failed to set baud rate."); + } + + const char message[] = "Hello serial!\n"; + if (!WriteFile( + fileHandle.Get(), + message, + sizeof(message), + &information, + nullptr)) { + + throw ref new Exception( + HRESULT_FROM_WIN32(GetLastError()), + L"Failed to write data to COM port."); + } + } +``` + +Add a call to `AccessComPort()` in the MainPage constructor: + +``` C++ + MainPage::MainPage() + { + InitializeComponent(); + AccessComPort(); + } +``` + +### Deploy your app + +* If you're building for UPBoard, select `x64` as the architecture. + +* Select **Local Machine** to point to IoT device and hit F5 to deploy to your device. + +* Build the project, which should succeed because we made desktop APIs visible at compile time. + +* Set a breakpoint on the `throw` statement after the file handle validity check, as indicated in the source code above. + +* Debug the application on UP Board. The breakpoint should get hit. Inspect the `lastError` variable in the debugger, which should equal 5 (Access Denied). We need to set a proper security descriptor on the device object so it can be accessed by UWP applications. + +### Generate an app package + +Steps to follow : + + * In Solution Explorer, open the solution for your application project. + * Right-click the project and choose Publish->Create App Packages (before Visual Studio 2019 version 16.3, the Publish menu is named Store). + * Select Sideloading in the first page of the wizard and then click Next. + * On the Select signing method page, select whether to skip packaging signing or select a certificate for signing. You can select a certificate from your local certificate store, select a certificate file, or create a new certificate. For an MSIX package to be installed on an end user's machine, it must be signed with a cert that is trusted on the machine. + * Complete the Select and configure packages page as described in the Create your app package upload file using Visual Studio section. + + If you need guidance click Link: [here](https://docs.microsoft.com/en-us/windows/msix/package/packaging-uwp-apps#generate-an-app-package). + +### Install your app package using an install script + +Steps to follow : + * Open the *_Test folder. + * Right-click on the Add-AppDevPackage.ps1 file. Choose Run with PowerShell and follow the prompts. + * When the app package has been installed, the PowerShell window displays this message: Your app was successfully installed. + + If you need guidance click Link: [here](https://docs.microsoft.com/en-us/windows/msix/package/packaging-uwp-apps#install-your-app-package-using-an-install-script). + + Click the Start button to search for the app by name, and then launch it. + +## Granting Access to AppContainer Processes + +Every device object in the system has an associated security descriptor. The security descriptor determines who has what access to a device object. Security descriptors have a binary representation which is used by the system to compute access to objects, and a human readable form called an SDDL string. Some examples of SDDL strings are: + + + + + + + + + + + + + + + + + + + + + + + + + +
SDDL StringDescriptionWdmsec.h constant
"D:P"Denies access to all, except other kernel-mode clients. SDDL_DEVOBJ_KERNEL_ONLY
"D:P(A;;GA;;;SY)"Denies access to all, except kernel mode code, and usermode clients running under the SYSTEM account.SDDL_DEVOBJ_SYS_ALL
"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GR;;;WD)"Grants full access to kernel mode clients and the SYSTEM account, grants read, write, execute to built-in Administrators, and grants read-only access to everyone else.SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_R
+ +A number of common security descriptor strings are defined in wdmsec.h. + +To make a device accessible to UWP applications, you need to grant access to the All Application Packages security principle, which is represented by the SID string "AC". The following SDDL will grant GENERIC_ALL permissions to SYSTEM, built-in administrators, authenticated users, and appcontainer applications: + + "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;AU)(A;;GA;;;AC)" + +If you control the code of the driver you wish to access, you can programatically assign an SDDL string to a device object using the [IoCreateDeviceObjectSecure()](https://msdn.microsoft.com/en-us/library/windows/hardware/ff548407(v=vs.85).aspx) routine in WDM drivers, or the [WdfDeviceInitAssignSDDLString()](https://msdn.microsoft.com/en-us/library/windows/hardware/ff546035(v=vs.85).aspx) routine in WDF drivers. + +If you do not control the driver code for your device, you can override the SDDL for any device using the registry. If a registry value named "Security" is present in the hardware registry key for a device, the system will use the specified security descriptor instead of the one supplied by the driver. We will override the security descriptor for the COM port with one that grants access to all appcontainer applications. + +First, we need to convert the SDDL string to its binary representation. We can do this with [PowerShell](http://blogs.technet.com/b/heyscriptingguy/archive/2011/08/09/use-powershell-to-convert-sddl-to-binary-format.aspx). Open a PowerShell prompt and run the following commands: + +```csharp + $a = ([wmiclass]"Win32_SecurityDescriptorHelper").SDDLToBinarySD("D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;AU)(A;;GA;;;AC)").BinarySD | % { '{0:X}' -f $_ } + $a -join ',' +``` + +The output will be a long string of comma-separated numbers that we will paste into a registry file. Create a file named deviceac.reg with the following contents: + + Windows Registry Editor Version 5.00 + + [HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\ACPI\PNP0501\1] + "Security"=hex:1,0,4,90,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,2,0,60,0,4,0,0,0,0,0,14,0,0,0,0,10,1,1,0,0,0,0,0,5,12,0,0,0,0,0,18,0,0,0,0,10,1,2,0,0,0,0,0,5,20,0,0,0,20,2,0,0,0,0,14,0,0,0,0,10,1,1,0,0,0,0,0,5,B,0,0,0,0,0,18,0,0,0,0,10,1,2,0,0,0,0,0,F,2,0,0,0,1,0,0,0 + +Verify that the Security registry value was created by running: + + reg query HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\ACPI\PNP0501\1 /v Security + +If you don't see the Security value, something went wrong in the previous steps. If the Security value was created successfully, restart the device so the new security settings take effect: + + Devcon restart acpi\pnp0501 + +Now, debug the universal application again. The COM port should be opened successfully and the breakpoint above should not be hit. + +Congratulations, you have successfully opened a device and sent an IOCTL to it! + +## Granting Access to a Specific Application + +The security identifier "AC" identifies all application packages, and will grant all apps access to the device. If you want to grant access to a specific application only, you can replace "AC" in the SDDL above with the app-specific SID of the application you'd like to target. You can inspect the app-specific SID with [process explorer](https://technet.microsoft.com/en-us/sysinternals/bb896653). + +Launch the app and launch process explorer. Open the properties dialog box for the process in process explorer and go to the Security tab. There you will see all of the security identifiers associated with the process's token. The SID with the AppContainer flag set is the app-specific SID. + +![Process Explorer](../../Resources/images/CustomDeviceAccessorUwp-AppContainerSid.png) + +You can replace "AC" with this SID in the above SDDL to generate an SDDL that grants access to that specific application only. For example, the following SDDL would grant access only to the application shown above: + + "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;AU)(A;;GA;;;S-1-15-3-2628158189-2540711686-3785793668-522787976-4226511596-526649915-1865015409)" + +SIDs are generated at application install time so can only be determined after the application has been installed on the target machine. + +For more information about app containers, see [Windows 8 App Container Security Notes - Part 1](http://recxltd.blogspot.com/2012/03/windows-8-app-container-security-notes.html). diff --git a/samples/DMMocKPortal/App.config b/samples/DMMocKPortal/App.config index 656760a59..bfa8a3866 100644 --- a/samples/DMMocKPortal/App.config +++ b/samples/DMMocKPortal/App.config @@ -1,22 +1,22 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/DMMocKPortal/App.xaml b/samples/DMMocKPortal/App.xaml index 67fa5b564..a8922095a 100644 --- a/samples/DMMocKPortal/App.xaml +++ b/samples/DMMocKPortal/App.xaml @@ -1,71 +1,71 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/samples/DMMocKPortal/App.xaml.cs b/samples/DMMocKPortal/App.xaml.cs index 3bd481aba..e0805efaa 100644 --- a/samples/DMMocKPortal/App.xaml.cs +++ b/samples/DMMocKPortal/App.xaml.cs @@ -1,20 +1,20 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Data; -using System.Linq; -using System.Threading.Tasks; -using System.Windows; - -namespace DMMockPortal -{ - /// - /// Interaction logic for App.xaml - /// - public partial class App : Application - { - } -} +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace DMMockPortal +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/samples/DMMocKPortal/DMConstants.cs b/samples/DMMocKPortal/DMConstants.cs index 11b211c5d..98b089f3c 100644 --- a/samples/DMMocKPortal/DMConstants.cs +++ b/samples/DMMocKPortal/DMConstants.cs @@ -1,12 +1,12 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -namespace DMMockPortal -{ - static class DMConstants - { - public static readonly string AllDevicesConfigName = "*All*"; - public static readonly string RegistryStore = "Software\\Microsoft\\DMMockPortal"; - public static readonly string RegistryConnectionString = "ConnectionString"; - } -} +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace DMMockPortal +{ + static class DMConstants + { + public static readonly string AllDevicesConfigName = "*All*"; + public static readonly string RegistryStore = "Software\\Microsoft\\DMMockPortal"; + public static readonly string RegistryConnectionString = "ConnectionString"; + } +} diff --git a/samples/DMMocKPortal/DMMockPortal.csproj b/samples/DMMocKPortal/DMMockPortal.csproj index d83de7bd0..7ffff6457 100644 --- a/samples/DMMocKPortal/DMMockPortal.csproj +++ b/samples/DMMocKPortal/DMMockPortal.csproj @@ -1,243 +1,243 @@ - - - - - Debug - AnyCPU - {7E332748-5155-49AA-89C4-C588C4724DFB} - WinExe - DMMockPortal - DMMockPortal - v4.6.1 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - true - - - x64 - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - true - bin\x64\Debug\ - DEBUG;TRACE - full - x64 - 7.3 - prompt - true - - - bin\x64\Release\ - TRACE - true - pdbonly - x64 - 7.3 - prompt - true - - - - packages\Microsoft.Azure.Amqp.2.4.13\lib\net45\Microsoft.Azure.Amqp.dll - - - packages\Microsoft.Azure.Devices.1.34.0\lib\net451\Microsoft.Azure.Devices.dll - - - packages\Microsoft.Azure.Devices.Shared.1.28.1\lib\net451\Microsoft.Azure.Devices.Shared.dll - - - packages\Microsoft.Owin.4.2.0\lib\net45\Microsoft.Owin.dll - - - packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll - - - ..\..\packages\Owin.1.0\lib\net40\Owin.dll - - - - - - - packages\Microsoft.AspNet.WebApi.Client.5.2.7\lib\net45\System.Net.Http.Formatting.dll - - - packages\System.Net.WebSockets.4.3.0\lib\net46\System.Net.WebSockets.dll - - - packages\System.Net.WebSockets.Client.4.3.2\lib\net46\System.Net.WebSockets.Client.dll - - - - packages\System.Runtime.Serialization.Primitives.4.3.0\lib\net46\System.Runtime.Serialization.Primitives.dll - - - packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net461\System.Security.Cryptography.Algorithms.dll - - - packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll - - - packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll - - - packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll - - - - packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll - - - - - - - - - - - 4.0 - - - - - - - - MSBuild:Compile - Designer - - - SamplesDialog.xaml - - - - DeploymentControl.xaml - - - DeploymentListControl.xaml - - - DeviceListControl.xaml - - - - DeviceTwinControl.xaml - - - - ApplicationListControl.xaml - - - AzureStorageControl.xaml - - - RebootInfoControl.xaml - - - WindowsUpdateControl.xaml - - - TabControl.xaml - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - App.xaml - Code - - - - MainWindow.xaml - Code - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - - - Code - - - True - True - Resources.resx - - - True - Settings.settings - True - - - ResXFileCodeGenerator - Resources.Designer.cs - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - - + + + + + Debug + AnyCPU + {7E332748-5155-49AA-89C4-C588C4724DFB} + WinExe + DMMockPortal + DMMockPortal + v4.6.1 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + + + x64 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + 7.3 + prompt + true + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + 7.3 + prompt + true + + + + packages\Microsoft.Azure.Amqp.2.4.13\lib\net45\Microsoft.Azure.Amqp.dll + + + packages\Microsoft.Azure.Devices.1.34.0\lib\net451\Microsoft.Azure.Devices.dll + + + packages\Microsoft.Azure.Devices.Shared.1.28.1\lib\net451\Microsoft.Azure.Devices.Shared.dll + + + packages\Microsoft.Owin.4.2.0\lib\net45\Microsoft.Owin.dll + + + packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll + + + ..\..\packages\Owin.1.0\lib\net40\Owin.dll + + + + + + + packages\Microsoft.AspNet.WebApi.Client.5.2.7\lib\net45\System.Net.Http.Formatting.dll + + + packages\System.Net.WebSockets.4.3.0\lib\net46\System.Net.WebSockets.dll + + + packages\System.Net.WebSockets.Client.4.3.2\lib\net46\System.Net.WebSockets.Client.dll + + + + packages\System.Runtime.Serialization.Primitives.4.3.0\lib\net46\System.Runtime.Serialization.Primitives.dll + + + packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net461\System.Security.Cryptography.Algorithms.dll + + + packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + + + packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + + + packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll + + + + packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll + + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + SamplesDialog.xaml + + + + DeploymentControl.xaml + + + DeploymentListControl.xaml + + + DeviceListControl.xaml + + + + DeviceTwinControl.xaml + + + + ApplicationListControl.xaml + + + AzureStorageControl.xaml + + + RebootInfoControl.xaml + + + WindowsUpdateControl.xaml + + + TabControl.xaml + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + + MainWindow.xaml + Code + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + \ No newline at end of file diff --git a/samples/DMMocKPortal/DMMockPortal.sln b/samples/DMMocKPortal/DMMockPortal.sln index 0fd4f1107..2fd9c4ab5 100644 --- a/samples/DMMocKPortal/DMMockPortal.sln +++ b/samples/DMMocKPortal/DMMockPortal.sln @@ -1,31 +1,31 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31313.79 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DMMockPortal", "DMMockPortal.csproj", "{7E332748-5155-49AA-89C4-C588C4724DFB}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {7E332748-5155-49AA-89C4-C588C4724DFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7E332748-5155-49AA-89C4-C588C4724DFB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7E332748-5155-49AA-89C4-C588C4724DFB}.Debug|x64.ActiveCfg = Debug|x64 - {7E332748-5155-49AA-89C4-C588C4724DFB}.Debug|x64.Build.0 = Debug|x64 - {7E332748-5155-49AA-89C4-C588C4724DFB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7E332748-5155-49AA-89C4-C588C4724DFB}.Release|Any CPU.Build.0 = Release|Any CPU - {7E332748-5155-49AA-89C4-C588C4724DFB}.Release|x64.ActiveCfg = Release|x64 - {7E332748-5155-49AA-89C4-C588C4724DFB}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {1945AE7F-2C9D-4743-9803-7D0C2BEC1889} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31313.79 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DMMockPortal", "DMMockPortal.csproj", "{7E332748-5155-49AA-89C4-C588C4724DFB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7E332748-5155-49AA-89C4-C588C4724DFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7E332748-5155-49AA-89C4-C588C4724DFB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7E332748-5155-49AA-89C4-C588C4724DFB}.Debug|x64.ActiveCfg = Debug|x64 + {7E332748-5155-49AA-89C4-C588C4724DFB}.Debug|x64.Build.0 = Debug|x64 + {7E332748-5155-49AA-89C4-C588C4724DFB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7E332748-5155-49AA-89C4-C588C4724DFB}.Release|Any CPU.Build.0 = Release|Any CPU + {7E332748-5155-49AA-89C4-C588C4724DFB}.Release|x64.ActiveCfg = Release|x64 + {7E332748-5155-49AA-89C4-C588C4724DFB}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1945AE7F-2C9D-4743-9803-7D0C2BEC1889} + EndGlobalSection +EndGlobal diff --git a/samples/DMMocKPortal/DeploymentControl.xaml b/samples/DMMocKPortal/DeploymentControl.xaml index 30dd44154..d3f56626b 100644 --- a/samples/DMMocKPortal/DeploymentControl.xaml +++ b/samples/DMMocKPortal/DeploymentControl.xaml @@ -1,208 +1,208 @@ - - - - - - - - - - - - - - - - - - - - - - -