Windows 10 Version 1803 - July 2018 Update

This commit is contained in:
Raymond Chen 2018-07-18 17:00:05 -07:00
Родитель fe8567faf2 cff2a43164
Коммит 157c9eb612
97 изменённых файлов: 3762 добавлений и 937 удалений

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

@ -203,4 +203,4 @@ FakesAssemblies/
# Custom ignores
gallery.xml
project.lock.json
project.lock.json

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

@ -485,6 +485,7 @@ For additional Windows samples, see [Windows on GitHub](http://microsoft.github.
</tr>
<tr>
<td><a href="Samples/ExtendedExecution">Extended execution</a></td>
<td><a href="https://aka.ms/Kcrqst">Multi-instance apps</a></td>
<td><a href="Samples/BasicSuspension">Suspend and resume</a></td>
</tr>
</table>

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

@ -102,7 +102,11 @@ namespace SDKTemplate
// Start over with an empty collection.
KnownDevices.Clear();
// Start the watcher.
// Start the watcher. Active enumeration is limited to approximately 30 seconds.
// This limits power usage and reduces interference with other Bluetooth activities.
// To monitor for the presence of Bluetooth LE devices for an extended period,
// use the BluetoothLEAdvertisementWatcher runtime class. See the BluetoothAdvertisement
// sample for an example.
deviceWatcher.Start();
}

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

@ -65,7 +65,7 @@ Before you run this scenario, you must start the corresponding NT service.
* Build the NT service portion of the sample, which requires that the Windows SDK for Desktop C++ Apps be installed.
* Start the service from an elevated command prompt in one of two ways:
* Install it as a service: `rpcserver.exe -install`
* Install it as a service using `rpcserver.exe -install` and start it using `sc start hsaservice`.
* Run the service in console mode: `rpcserver.exe -console`
## Using a custom capability to access a custom device
@ -115,6 +115,37 @@ When they are full, the next write operation will wait until a message is read,
thereby freeing up a message buffer.
When they are empty, the next read operation will wait until a message is written.
## Raising Custom System Event Trigger
Demonstrates how to register background task with the CustomSystemEventTrigger type and
raise a custom system event when an OSR FX-2 device is connected to a system. The code to
raise the event is part of the OSR FX-2 driver. This enables custom devices/NT services to raise a custom system event which triggers a background task.
The code for the OSR USB FX-2 driver can be found in the
[Microsoft Windows-driver-samples repo](https://github.com/Microsoft/Windows-driver-samples/)
under
[usb/kmdf_fx2/driver](https://github.com/Microsoft/Windows-driver-samples/tree/master/usb/kmdf_fx2).
The driver must be built for Windows 10 version 1803 or higher in order to support
the custom system event trigger used by this sample.
## Firmware access
Declaring the restricted capability `smbios` allows apps to read the SMBIOS.
Call the
[GetSystemFirmwareTable](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724379(v=vs.85).aspx)
and
[EnumSystemFirmwareTables](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724259(v=vs.85).aspx)
functions with the 'RSMB' (Raw SMBIOS) table provider.
The following custom capabilities can be used for accessing UEFI variables:
- `microsoft.firmwareRead_cw5n1h2txyewy`: Read UEFI variables using [GetFirmwareEnvironmentVariable](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724325(v=vs.85).aspx)
- `microsoft.firmwareWrite_cw5n1h2txyewy`: Read/Write UEFI variables using [SetFirmwareEnvironmentVariable](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724934(v=vs.85).aspx)
UEFI access also requires the app to declare 'protectedApp' restricted capability and enable [INTEGRITYCHECK](https://docs.microsoft.com/en-us/cpp/build/reference/integritycheck-require-signature-check) for the project. This would trigger necessary store signing for protected apps during store submission. Currently the [INTEGRITYCHECK](https://docs.microsoft.com/en-us/cpp/build/reference/integritycheck-require-signature-check) can only be enabled on C++ projects properties.
UEFI variables can be accessed only when the app is being used by a user belonging to Administrators group.
**Note** The Windows universal samples require Visual Studio 2017 to build and Windows 10 to execute.
To obtain information about Windows 10 development, go to the [Windows Dev Center](http://go.microsoft.com/fwlink/?LinkID=532421)
@ -140,6 +171,7 @@ To obtain information about Microsoft Visual Studio and the tools for developing
* [How to use RPC callbacks](https://support.microsoft.com/kb/96781)
* [Custom Capabilities for Universal Windows Platform apps](https://msdn.microsoft.com/windows/hardware/drivers/devapps/custom-capabilities-for-universal-windows-platform-apps)
* [Hardware access for Universal Windows Platform apps](https://msdn.microsoft.com/windows/hardware/drivers/devapps/hardware-access-for-universal-windows-platform-apps)
## System requirements
**Client:** Windows 10 version 1703

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

@ -0,0 +1,19 @@
#pragma once
extern "C" {
#define MANUFACTURER_NAME_LENGTH_MAX 1024
__declspec(dllexport)
DWORD
GetManufacturerNameFromSmbios(
_Out_ wchar_t* ManufacturerName,
_In_ DWORD Size
);
__declspec(dllexport)
DWORD
GetSecureBootEnabledFromUefi(
_Out_ bool* SecureBootEnabled
);
}

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

@ -206,6 +206,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="FirmwareAccess.h" />
<ClInclude Include="RpcClient.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="RpcClientApi.h">
@ -234,6 +235,8 @@
<ClCompile Include="RpcClientApi.cpp">
<DeploymentContent>true</DeploymentContent>
</ClCompile>
<ClCompile Include="smbios.cpp" />
<ClCompile Include="uefi.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

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

@ -11,11 +11,14 @@
<ClCompile Include="pch.cpp" />
<ClCompile Include="RpcClientApi.cpp" />
<ClCompile Include="$(OutDir)\RpcInterface_c.c" />
<ClCompile Include="smbios.cpp" />
<ClCompile Include="uefi.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="RpcClient.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="RpcClientApi.h" />
<ClInclude Include="FirmwareAccess.h" />
</ItemGroup>
</Project>

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

@ -0,0 +1,303 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
#include "pch.h"
#include <intsafe.h>
#include <string>
#include "FirmwareAccess.h"
struct RawSMBIOSData
{
BYTE Used20CallingMethod;
BYTE SMBIOSMajorVersion;
BYTE SMBIOSMinorVersion;
BYTE DmiRevision;
DWORD Length;
BYTE SMBIOSTableData[ANYSIZE_ARRAY];
};
struct RawSMBIOSTable
{
BYTE Type;
BYTE Length;
WORD Handle;
};
struct RawSMBIOSSystemInfo : public RawSMBIOSTable
{
BYTE Manufacturer;
BYTE ProductName;
BYTE Version;
BYTE SerialNumber;
// Ver 2.1 beyond here
BYTE UUID[16];
BYTE Wakeup_Type;
// Ver 2.4 beyond here
BYTE SKUNumber;
BYTE Family;
};
DWORD
FindSmBiosTable(
_In_ const RawSMBIOSData* SMBIOSData,
_In_ BYTE Type,
_Out_ RawSMBIOSTable** SMBIOSTable
)
{
DWORD error = S_OK;
ULONG i = 0;
RawSMBIOSTable* smbiosTable = NULL;
bool properTermination = false;
*SMBIOSTable = NULL;
// Find SMBIOS Table
do
{
properTermination = false;
// Check that the table header fits in the buffer.
if (i + sizeof(RawSMBIOSTable) < SMBIOSData->Length)
{
if (SMBIOSData->SMBIOSTableData[i] == Type)
{
// Found table
smbiosTable = (RawSMBIOSTable*)&SMBIOSData->SMBIOSTableData[i];
}
// Set i to the end of the formated section.
i += SMBIOSData->SMBIOSTableData[i + 1];
// Look for the end of the struct that must be terminated by \0\0
while (i + 1 < SMBIOSData->Length)
{
if (0 == SMBIOSData->SMBIOSTableData[i] &&
0 == SMBIOSData->SMBIOSTableData[i + 1])
{
properTermination = true;
i += 2;
break;
}
++i;
}
}
}
while (properTermination && !smbiosTable);
if (properTermination) {
if (!smbiosTable) {
// The table was not found.
error = ERROR_FILE_NOT_FOUND;
}
}
else
{
// A table was not double null terminated within the buffer.
error = ERROR_INVALID_DATA;
}
if (ERROR_SUCCESS == error) {
*SMBIOSTable = smbiosTable;
}
return error;
}
DWORD
GetSmBiosString(
_In_ const RawSMBIOSTable* SmBiosTable,
_In_ BYTE StringIndex,
_Out_ PWSTR* ResultString
)
{
DWORD error = ERROR_SUCCESS;
PSTR currentString = NULL;
BYTE CurrentStringIndex = 1;
ULONG stringLen = 0;
ULONG bufferLen = 0;
HRESULT hr = S_OK;
*ResultString = NULL;
// 0 index implies the empty string
if (StringIndex <= 0)
{
goto exit;
}
currentString = (PSTR)(((BYTE*)SmBiosTable) + SmBiosTable->Length);
// find the string in the multisz string
while (*currentString)
{
if (CurrentStringIndex == StringIndex)
{
break;
}
++currentString;
if (!*currentString)
{
++currentString;
++CurrentStringIndex;
}
}
if (!*currentString)
{
// String was not found in the string table.
error = ERROR_INVALID_DATA;
goto exit;
}
// Convert the string to UNICODE
stringLen = MultiByteToWideChar(
CP_ACP,
MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
currentString,
-1,
NULL,
0);
if (0 == stringLen)
{
error = GetLastError();
goto exit;
}
// SMBIOS strings are limited to 64 characters
if (stringLen > 65)
{
error = ERROR_INVALID_DATA;
goto exit;
}
hr = ULongMult(stringLen, sizeof(WCHAR), &bufferLen);
if (hr != S_OK)
{
error = ERROR_INVALID_DATA;
goto exit;
}
*ResultString = (PWSTR) HeapAlloc(GetProcessHeap(), 0, bufferLen);
if (!*ResultString)
{
error = ERROR_OUTOFMEMORY;
goto exit;
}
stringLen = MultiByteToWideChar(
CP_ACP,
MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
currentString,
-1,
*ResultString,
stringLen);
if (0 == stringLen)
{
error = GetLastError();
}
exit:
if (error != ERROR_SUCCESS)
{
HeapFree(GetProcessHeap(), 0, *ResultString);
*ResultString = NULL;
}
return error;
}
DWORD
GetManufacturerNameFromSmbios(
_Out_ wchar_t* ManufacturerName,
_In_ DWORD Size
)
{
DWORD error = ERROR_SUCCESS;
DWORD smBiosDataSize = 0;
RawSMBIOSData* smBiosData = NULL;
DWORD bytesWritten = 0;
RawSMBIOSSystemInfo* systemInfo = NULL;
PWSTR manufacturerName = NULL;
if (ManufacturerName == NULL)
{
return E_INVALIDARG;
}
//
// Query size of SMBIOS data.
//
smBiosDataSize = GetSystemFirmwareTable('RSMB', 0, NULL, 0);
if (smBiosDataSize <= 0)
{
error = GetLastError();
goto exit;
}
//
// Allocate memory for the smbios table
//
smBiosData = (RawSMBIOSData*) HeapAlloc(GetProcessHeap(), 0, smBiosDataSize);
if (smBiosData == NULL)
{
error = ERROR_OUTOFMEMORY;
goto exit;
}
bytesWritten = GetSystemFirmwareTable('RSMB', 0, smBiosData, smBiosDataSize);
if (bytesWritten != smBiosDataSize)
{
error = ERROR_INVALID_DATA;
goto exit;
}
error = FindSmBiosTable(smBiosData, 1, (RawSMBIOSTable**)&systemInfo);
if (error != ERROR_SUCCESS)
{
goto exit;
}
error = GetSmBiosString(systemInfo, systemInfo->Manufacturer, &manufacturerName);
if (error != ERROR_SUCCESS)
{
goto exit;
}
if (manufacturerName != NULL)
{
if (Size < (DWORD) wcslen(manufacturerName))
{
error = ERROR_BUFFER_OVERFLOW;
goto exit;
}
wcscpy_s(ManufacturerName, Size, manufacturerName);
HeapFree(GetProcessHeap(), 0, manufacturerName);
}
else
{
error = E_UNEXPECTED;
}
exit:
if (smBiosData)
{
HeapFree(GetProcessHeap(), 0, smBiosData);
}
return error;
}

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

@ -0,0 +1,45 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
#include "pch.h"
#include "firmwareaccess.h"
#define EFI_GLOBAL_VAR_GUID L"{8BE4DF61-93CA-11D2-AA0D-00E098032B8C}"
DWORD
GetSecureBootEnabledFromUefi(
_Out_ bool* SecureBootEnabled
)
{
BYTE secureBootStatus;
DWORD bytesReturned;
DWORD error = ERROR_SUCCESS;
bytesReturned = GetFirmwareEnvironmentVariable(L"SecureBoot",
EFI_GLOBAL_VAR_GUID,
&secureBootStatus,
sizeof(BYTE));
if (bytesReturned <= 0)
{
error = GetLastError();
goto exit;
}
if (bytesReturned != sizeof(BYTE))
{
error = ERROR_INVALID_DATA;
goto exit;
}
*SecureBootEnabled = (secureBootStatus != 0);
exit:
return error;
}

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

@ -0,0 +1,38 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
using Windows.ApplicationModel.Background;
using Windows.Data.Xml.Dom;
using Windows.UI.Notifications;
namespace Osrusbfx2Task
{
public sealed class ConnectedTask : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
string xml = $@"<toast activationType='foreground'>
<visual>
<binding template='ToastGeneric'>
<text>CustomCapability Sample</text>
<text>Osrfx2usb device connected.</text>
</binding>
</visual>
</toast>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
var toast = new ToastNotification(doc);
ToastNotificationManager.CreateToastNotifier().Show(toast);
}
}
}

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

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{87655708-3F5C-5E82-B201-52F6DB1A8971}</ProjectGuid>
<OutputType>winmdobj</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Osrusbfx2Task</RootNamespace>
<AssemblyName>Osrusbfx2Task</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.17134.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.17134.0</TargetPlatformMinVersion>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<AllowCrossPlatformRetargeting>false</AllowCrossPlatformRetargeting>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<PlatformTarget>ARM</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\ARM\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
<PlatformTarget>ARM</PlatformTarget>
<OutputPath>bin\ARM\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<PlatformTarget>x64</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<ItemGroup>
<Compile Include="ConnectedTask.cs" />
<Compile Include="..\..\..\..\SharedContent\cs\AssemblyInfo.cs">
<Link>Properties\AssemblyInfo.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>5.4.0</Version>
</PackageReference>
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

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

@ -71,7 +71,7 @@ void InstallService(
schSCManager, // SCManager database
pszServiceName, // Name of service
pszDisplayName, // Name to display
SERVICE_QUERY_STATUS, // Desired access
SERVICE_QUERY_STATUS | SERVICE_START, // Desired access
SERVICE_WIN32_OWN_PROCESS, // Service type
dwStartType, // Service start type
SERVICE_ERROR_NORMAL, // Error control type
@ -91,6 +91,14 @@ void InstallService(
wprintf(L"%s is installed.\n", pszServiceName);
if (StartService(schService, 0, nullptr) == 0)
{
wprintf(L"StartService failed w/err 0x%08lx\n", GetLastError());
goto Cleanup;
}
wprintf(L"%s is started.\n", pszServiceName);
Cleanup:
// Centralized cleanup for all allocated resources.
if (schSCManager)
@ -105,7 +113,6 @@ Cleanup:
}
}
//
// FUNCTION: UninstallService
//

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

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<CustomCapabilityDescriptor xmlns="http://schemas.microsoft.com/appx/2016/sccd" xmlns:s="http://schemas.microsoft.com/appx/2016/sccd">
<CustomCapabilities>
<CustomCapability Name="microsoft.firmwareRead_cw5n1h2txyewy"></CustomCapability>
<CustomCapability Name="microsoft.hsaTestCustomCapability_q536wpkpf5cy2"></CustomCapability>
</CustomCapabilities>
<AuthorizedEntities>

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

@ -20,65 +20,61 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RpcClient", "..\Service\Cli
{B9574DFC-0906-5CE8-9A93-88FD96F9076F} = {B9574DFC-0906-5CE8-9A93-88FD96F9076F}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Osrusbfx2Task", "..\Service\Osrusbfx2Task\Osrusbfx2Task.csproj", "{28201DC4-0755-547C-99F5-0812FF7DCD85}"
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
{DBDDFB64-E433-5A05-BD84-15612E0C8937}.Debug|ARM.ActiveCfg = Debug|ARM
{DBDDFB64-E433-5A05-BD84-15612E0C8937}.Debug|ARM.Build.0 = Debug|ARM
{DBDDFB64-E433-5A05-BD84-15612E0C8937}.Debug|ARM.Deploy.0 = Debug|ARM
{DBDDFB64-E433-5A05-BD84-15612E0C8937}.Debug|x64.ActiveCfg = Debug|x64
{DBDDFB64-E433-5A05-BD84-15612E0C8937}.Debug|x64.Build.0 = Debug|x64
{DBDDFB64-E433-5A05-BD84-15612E0C8937}.Debug|x64.Deploy.0 = Debug|x64
{DBDDFB64-E433-5A05-BD84-15612E0C8937}.Debug|x86.ActiveCfg = Debug|Win32
{DBDDFB64-E433-5A05-BD84-15612E0C8937}.Debug|x86.Build.0 = Debug|Win32
{DBDDFB64-E433-5A05-BD84-15612E0C8937}.Debug|x86.Deploy.0 = Debug|Win32
{DBDDFB64-E433-5A05-BD84-15612E0C8937}.Release|ARM.ActiveCfg = Release|ARM
{DBDDFB64-E433-5A05-BD84-15612E0C8937}.Release|ARM.Build.0 = Release|ARM
{DBDDFB64-E433-5A05-BD84-15612E0C8937}.Release|ARM.Deploy.0 = Release|ARM
{DBDDFB64-E433-5A05-BD84-15612E0C8937}.Release|x64.ActiveCfg = Release|x64
{DBDDFB64-E433-5A05-BD84-15612E0C8937}.Release|x64.Build.0 = Release|x64
{DBDDFB64-E433-5A05-BD84-15612E0C8937}.Release|x64.Deploy.0 = Release|x64
{DBDDFB64-E433-5A05-BD84-15612E0C8937}.Release|x86.ActiveCfg = Release|Win32
{DBDDFB64-E433-5A05-BD84-15612E0C8937}.Release|x86.Build.0 = Release|Win32
{DBDDFB64-E433-5A05-BD84-15612E0C8937}.Release|x86.Deploy.0 = Release|Win32
{B9574DFC-0906-5CE8-9A93-88FD96F9076F}.Debug|ARM.ActiveCfg = Debug|ARM
{B9574DFC-0906-5CE8-9A93-88FD96F9076F}.Debug|x64.ActiveCfg = Debug|x64
{B9574DFC-0906-5CE8-9A93-88FD96F9076F}.Debug|x64.Build.0 = Debug|x64
{B9574DFC-0906-5CE8-9A93-88FD96F9076F}.Debug|x64.Deploy.0 = Debug|x64
{B9574DFC-0906-5CE8-9A93-88FD96F9076F}.Debug|x86.ActiveCfg = Debug|Win32
{B9574DFC-0906-5CE8-9A93-88FD96F9076F}.Debug|x86.Build.0 = Debug|Win32
{B9574DFC-0906-5CE8-9A93-88FD96F9076F}.Release|ARM.ActiveCfg = Release|ARM
{B9574DFC-0906-5CE8-9A93-88FD96F9076F}.Release|x64.ActiveCfg = Release|x64
{B9574DFC-0906-5CE8-9A93-88FD96F9076F}.Release|x64.Build.0 = Release|x64
{B9574DFC-0906-5CE8-9A93-88FD96F9076F}.Release|x86.ActiveCfg = Release|Win32
{B9574DFC-0906-5CE8-9A93-88FD96F9076F}.Release|x86.Build.0 = Release|Win32
{EA240EE5-06A0-54BD-AA79-CD5B9AADE097}.Debug|ARM.ActiveCfg = Debug|ARM
{EA240EE5-06A0-54BD-AA79-CD5B9AADE097}.Debug|x64.ActiveCfg = Debug|x64
{EA240EE5-06A0-54BD-AA79-CD5B9AADE097}.Debug|x64.Build.0 = Debug|x64
{EA240EE5-06A0-54BD-AA79-CD5B9AADE097}.Debug|x86.ActiveCfg = Debug|Win32
{EA240EE5-06A0-54BD-AA79-CD5B9AADE097}.Debug|x86.Build.0 = Debug|Win32
{EA240EE5-06A0-54BD-AA79-CD5B9AADE097}.Release|ARM.ActiveCfg = Release|ARM
{EA240EE5-06A0-54BD-AA79-CD5B9AADE097}.Release|x64.ActiveCfg = Release|x64
{EA240EE5-06A0-54BD-AA79-CD5B9AADE097}.Release|x64.Build.0 = Release|x64
{EA240EE5-06A0-54BD-AA79-CD5B9AADE097}.Release|x86.ActiveCfg = Release|Win32
{EA240EE5-06A0-54BD-AA79-CD5B9AADE097}.Release|x86.Build.0 = Release|Win32
{43579D6C-9BA2-505C-9FB3-7D74A71E6379}.Debug|ARM.ActiveCfg = Debug|ARM
{43579D6C-9BA2-505C-9FB3-7D74A71E6379}.Debug|x64.ActiveCfg = Debug|x64
{43579D6C-9BA2-505C-9FB3-7D74A71E6379}.Debug|x64.Build.0 = Debug|x64
{43579D6C-9BA2-505C-9FB3-7D74A71E6379}.Debug|x86.ActiveCfg = Debug|Win32
{43579D6C-9BA2-505C-9FB3-7D74A71E6379}.Debug|x86.Build.0 = Debug|Win32
{43579D6C-9BA2-505C-9FB3-7D74A71E6379}.Release|ARM.ActiveCfg = Release|ARM
{43579D6C-9BA2-505C-9FB3-7D74A71E6379}.Release|x64.ActiveCfg = Release|x64
{43579D6C-9BA2-505C-9FB3-7D74A71E6379}.Release|x64.Build.0 = Release|x64
{43579D6C-9BA2-505C-9FB3-7D74A71E6379}.Release|x86.ActiveCfg = Release|Win32
{43579D6C-9BA2-505C-9FB3-7D74A71E6379}.Release|x86.Build.0 = Release|Win32
{28201DC4-0755-547C-99F5-0812FF7DCD85}.Debug|x64.ActiveCfg = Debug|x64
{28201DC4-0755-547C-99F5-0812FF7DCD85}.Debug|x64.Build.0 = Debug|x64
{28201DC4-0755-547C-99F5-0812FF7DCD85}.Debug|x86.ActiveCfg = Debug|x86
{28201DC4-0755-547C-99F5-0812FF7DCD85}.Debug|x86.Build.0 = Debug|x86
{28201DC4-0755-547C-99F5-0812FF7DCD85}.Release|x64.ActiveCfg = Release|x64
{28201DC4-0755-547C-99F5-0812FF7DCD85}.Release|x64.Build.0 = Release|x64
{28201DC4-0755-547C-99F5-0812FF7DCD85}.Release|x86.ActiveCfg = Release|x86
{28201DC4-0755-547C-99F5-0812FF7DCD85}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

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

@ -198,6 +198,7 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="DeviceList.h" />
<ClInclude Include="FirmwareAccess.h" />
<ClInclude Include="Fx2Driver.h" />
<ClInclude Include="ServiceViewModel.h" />
<ClInclude Include="pch.h" />
@ -223,6 +224,12 @@
<ClInclude Include="Scenario5_DeviceReadWrite.xaml.h">
<DependentUpon>..\shared\Scenario5_DeviceReadWrite.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Scenario6_CustomTrigger.xaml.h">
<DependentUpon>..\shared\Scenario6_CustomTrigger.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Scenario7_FirmwareAccess.xaml.h">
<DependentUpon>..\shared\Scenario7_FirmwareAccess.xaml</DependentUpon>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="..\..\..\SharedContent\xaml\App.xaml">
@ -241,6 +248,8 @@
<Page Include="..\shared\Scenario3_DeviceIO.xaml" />
<Page Include="..\shared\Scenario4_DeviceEvents.xaml" />
<Page Include="..\shared\Scenario5_DeviceReadWrite.xaml" />
<Page Include="..\shared\Scenario6_CustomTrigger.xaml" />
<Page Include="..\shared\Scenario7_FirmwareAccess.xaml" />
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
@ -304,6 +313,12 @@
<ClCompile Include="Scenario5_DeviceReadWrite.xaml.cpp">
<DependentUpon>..\shared\Scenario5_DeviceReadWrite.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Scenario6_CustomTrigger.xaml.cpp">
<DependentUpon>..\shared\Scenario6_CustomTrigger.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Scenario7_FirmwareAccess.xaml.cpp">
<DependentUpon>..\shared\Scenario7_FirmwareAccess.xaml</DependentUpon>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="CustomCapability.SCCD">
@ -311,6 +326,9 @@
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Service\Osrusbfx2Task\Osrusbfx2Task.csproj">
<Project>{45611270-f6a1-4969-ab74-9a0e1f39111b}</Project>
</ProjectReference>
<ProjectReference Condition="'$(Platform)' == 'x86' Or '$(Platform)' == 'x64'" Include="..\Service\Client\RpcClient.vcxproj">
<Project>{86B5561E-46B3-5DDE-9121-423803DA2807}</Project>
<Name>RpcClient</Name>

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

@ -39,6 +39,8 @@
<ClCompile Include="ServiceViewModel.cpp">
<Filter>ViewModel</Filter>
</ClCompile>
<ClCompile Include="Scenario6_CustomTrigger.xaml.cpp" />
<ClCompile Include="Scenario7_FirmwareAccess.xaml.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
@ -61,6 +63,9 @@
<ClInclude Include="ServiceViewModel.h">
<Filter>ViewModel</Filter>
</ClInclude>
<ClInclude Include="FirmwareAccess.h" />
<ClInclude Include="Scenario6_CustomTrigger.xaml.h" />
<ClInclude Include="Scenario7_FirmwareAccess.xaml.h" />
</ItemGroup>
<ItemGroup>
<Image Include="..\..\..\SharedContent\media\microsoft-sdk.png">
@ -96,8 +101,11 @@
<Page Include="..\shared\Scenario5_DeviceReadWrite.xaml" />
<Page Include="..\..\..\SharedContent\xaml\Styles.xaml" />
<Page Include="..\..\..\SharedContent\cpp\MainPage.xaml" />
<Page Include="..\shared\Scenario6_CustomTrigger.xaml" />
<Page Include="..\shared\Scenario7_FirmwareAccess.xaml" />
</ItemGroup>
<ItemGroup>
<None Include="CustomCapability.SCCD" />
<None Include="CustomCapability_TemporaryKey.pfx" />
</ItemGroup>
</Project>

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

@ -16,9 +16,6 @@ namespace SDKTemplate
ref class Fx2Driver
{
internal:
// The device type value expected by the driver in IO control
// codes. The driver defines this as 0x65500 but the device type
// value is only 16-bits wide, so we truncate here to 0x5500.
static const uint16 DeviceType = 65500U;
static const uint16 FunctionBase = 0x800;
@ -35,4 +32,4 @@ namespace SDKTemplate
private:
static const byte SevenSegmentValues[10];
};
}
}

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

@ -4,7 +4,8 @@
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4"
IgnorableNamespaces="uap mp uap4"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap mp uap4 rescap"
>
<Identity Name="Microsoft.SDKSamples.CustomCapability.CPP" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="26388851-6c33-4124-b1e5-96e859da28bf" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
@ -14,7 +15,7 @@
<Logo>Assets\StoreLogo-sdk.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.15063.0" MaxVersionTested="10.0.17134.0"/>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17134.0" MaxVersionTested="10.0.17134.0"/>
</Dependencies>
<Resources>
<Resource Language="x-generate" />
@ -35,9 +36,21 @@
</uap:ShowNameOnTiles>
</uap:DefaultTile>
</uap:VisualElements>
<Extensions>
<Extension Category="windows.backgroundTasks" EntryPoint="Osrusbfx2Task.ConnectedTask">
<BackgroundTasks>
<Task Type="systemEvent" />
</BackgroundTasks>
</Extension>
</Extensions>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="smbios" />
<!-- Enable "protectedApp" capability before store submission
to access firmware variables in production environment -->
<!-- <rescap:Capability Name="protectedApp" /> -->
<uap4:CustomCapability Name="microsoft.firmwareRead_cw5n1h2txyewy" />
<uap4:CustomCapability Name="microsoft.hsaTestCustomCapability_q536wpkpf5cy2" />
</Capabilities>
</Package>

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

@ -21,5 +21,7 @@ Platform::Array<Scenario>^ MainPage::scenariosInner = ref new Platform::Array<Sc
{ "Connect to the FX2 Device", "SDKTemplate.DeviceConnect" },
{ "Send IOCTLs to the device", "SDKTemplate.DeviceIO" },
{ "Handle asynchronous device events", "SDKTemplate.DeviceEvents" },
{ "Read and Write operations", "SDKTemplate.DeviceReadWrite" }
{ "Read and Write operations", "SDKTemplate.DeviceReadWrite" },
{ "Custom system event trigger", "SDKTemplate.CustomTrigger" },
{ "Firmware access", "SDKTemplate.FirmwareAccess" },
};

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

@ -0,0 +1,113 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
#include "pch.h"
#include "Scenario6_CustomTrigger.xaml.h"
using namespace SDKTemplate;
using namespace Platform;
using namespace Windows::ApplicationModel::Background;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Navigation;
// {C7BDD245-5CDA-4BBD-B68D-B5E36F7911A3}
#define GUID_CUSTOMSYSTEMEVENTTRIGGERID_OSRUSBFX2 L"{C7BDD245-5CDA-4BBD-B68D-B5E36F7911A3}"
static String^ customTriggerTaskName = L"Osrusbfx2Task.ConnectedTask";
CustomTrigger::CustomTrigger()
{
InitializeComponent();
UpdateUI();
}
void CustomTrigger::OnNavigatedFrom(NavigationEventArgs^ e)
{
UnregisterTask();
}
void CustomTrigger::UpdateUI()
{
RegisterCustomTrigger->IsEnabled = (taskRegistration == nullptr);
UnregisterCustomTrigger->IsEnabled = (taskRegistration != nullptr);
}
void CustomTrigger::UnregisterTask()
{
if (taskRegistration != nullptr)
{
taskRegistration->Unregister(true);
taskRegistration = nullptr;
}
}
void CustomTrigger::RegisterCustomTrigger_Click(Object^ sender, RoutedEventArgs^ e)
{
if (IsFx2CustomTriggerTaskRegistered())
{
rootPage->NotifyUser("Osrusbfx2.ConnectedTask background task has already been registered", NotifyType::ErrorMessage);
return;
}
// Create a new background task builder.
BackgroundTaskBuilder^ taskBuilder = ref new BackgroundTaskBuilder();
// Create a new OEM trigger.
CustomSystemEventTrigger^ fx2Trigger = ref new CustomSystemEventTrigger(
GUID_CUSTOMSYSTEMEVENTTRIGGERID_OSRUSBFX2, // Trigger Qualifier
CustomSystemEventTriggerRecurrence::Once); // One-shot trigger
// Associate the fx2Trigger trigger with the background task builder.
taskBuilder->SetTrigger(fx2Trigger);
// Specify the background task to run when the trigger fires.
taskBuilder->TaskEntryPoint = customTriggerTaskName;
// Name the background task.
taskBuilder->Name = customTriggerTaskName;
try
{
// Register the background task.
taskRegistration = taskBuilder->Register();
}
catch (Exception^ ex)
{
rootPage->NotifyUser(ex->ToString(), NotifyType::ErrorMessage);
return;
}
UpdateUI();
}
bool CustomTrigger::IsFx2CustomTriggerTaskRegistered()
{
for (auto task : BackgroundTaskRegistration::AllTasks)
{
String^ taskName = task->Value->Name;
if (taskName == customTriggerTaskName)
{
return true;
}
}
return false;
}
void CustomTrigger::UnregisterCustomTrigger_Click(Object^ sender, RoutedEventArgs^ e)
{
UnregisterTask();
UpdateUI();
}

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

@ -0,0 +1,38 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
#pragma once
#include "Scenario6_CustomTrigger.g.h"
namespace SDKTemplate
{
[Windows::Foundation::Metadata::WebHostHidden]
public ref class CustomTrigger sealed
{
public:
CustomTrigger();
private:
MainPage^ rootPage = MainPage::Current;
Windows::ApplicationModel::Background::BackgroundTaskRegistration^ taskRegistration;
bool IsFx2CustomTriggerTaskRegistered();
void UpdateUI();
void UnregisterTask();
void RegisterCustomTrigger_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
void UnregisterCustomTrigger_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
protected:
void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override;
};
}

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

@ -0,0 +1,64 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
#include "pch.h"
#include "Scenario7_FirmwareAccess.xaml.h"
#include <string>
#include "firmwareaccess.h"
#include <intsafe.h>
using namespace SDKTemplate;
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Xaml;
FirmwareAccess::FirmwareAccess()
{
InitializeComponent();
}
void FirmwareAccess::GetManufacturerName_Click(Object^ sender, RoutedEventArgs^ e)
{
wchar_t name[MANUFACTURER_NAME_LENGTH_MAX] = { 0 };
DWORD error = GetManufacturerNameFromSmbios(name, ARRAYSIZE(name));
if (error == ERROR_SUCCESS)
{
ManufacturerName->Text = ref new String(name);
}
else
{
rootPage->NotifyUser("Failed to retrieve manufacturer name from SMBIOS, error " + error.ToString(), NotifyType::ErrorMessage);
}
}
void FirmwareAccess::SecureBootState_Click(Object^ sender, RoutedEventArgs^ e)
{
bool secureBootEnabled = false;
DWORD error = GetSecureBootEnabledFromUefi(&secureBootEnabled);
switch (error)
{
case ERROR_SUCCESS:
SecureBootState->Text = secureBootEnabled.ToString();
break;
case ERROR_INVALID_FUNCTION:
rootPage->NotifyUser("Windows was installed using legacy BIOS", NotifyType::ErrorMessage);
break;
default:
rootPage->NotifyUser("Failed to retrieve secure boot state from UEFI, error " + error.ToString(), NotifyType::ErrorMessage);
break;
}
}

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

@ -0,0 +1,30 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
#pragma once
#include "Scenario7_FirmwareAccess.g.h"
namespace SDKTemplate
{
[Windows::Foundation::Metadata::WebHostHidden]
public ref class FirmwareAccess sealed
{
public:
FirmwareAccess();
private:
MainPage^ rootPage = MainPage::Current;
void GetManufacturerName_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
void SecureBootState_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
};
}

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

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<CustomCapabilityDescriptor xmlns="http://schemas.microsoft.com/appx/2016/sccd" xmlns:s="http://schemas.microsoft.com/appx/2016/sccd">
<CustomCapabilities>
<CustomCapability Name="microsoft.firmwareRead_cw5n1h2txyewy"></CustomCapability>
<CustomCapability Name="microsoft.hsaTestCustomCapability_q536wpkpf5cy2"></CustomCapability>
</CustomCapabilities>
<AuthorizedEntities>

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

@ -116,6 +116,12 @@
<Compile Include="Scenario5_DeviceReadWrite.xaml.cs">
<DependentUpon>Scenario5_DeviceReadWrite.xaml</DependentUpon>
</Compile>
<Compile Include="Scenario6_CustomTrigger.xaml.cs">
<DependentUpon>Scenario6_CustomTrigger.xaml</DependentUpon>
</Compile>
<Compile Include="Scenario7_FirmwareAccess.xaml.cs">
<DependentUpon>Scenario7_FirmwareAccess.xaml</DependentUpon>
</Compile>
<Compile Include="ServiceViewModel.cs" />
</ItemGroup>
<ItemGroup>
@ -167,6 +173,16 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="..\shared\Scenario6_CustomTrigger.xaml">
<Link>Scenario6_CustomTrigger.xaml</Link>
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="..\shared\Scenario7_FirmwareAccess.xaml">
<Link>Scenario7_FirmwareAccess.xaml</Link>
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<ItemGroup>
<Content Include="..\..\..\SharedContent\cs\Default.rd.xml">
@ -195,6 +211,10 @@
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Service\Osrusbfx2Task\Osrusbfx2Task.csproj">
<Project>{45611270-f6a1-4969-ab74-9a0e1f39111b}</Project>
<Name>Osrusbfx2Task</Name>
</ProjectReference>
<ProjectReference Condition="'$(Platform)' == 'x86' Or '$(Platform)' == 'x64'" Include="..\Service\Client\RpcClient.vcxproj">
<Project>{2c78f411-866b-472d-9c28-75d59f179525}</Project>
<Name>RpcClient</Name>

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

@ -17,65 +17,75 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RpcClient", "..\Service\Cli
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomCapability", "CustomCapability.csproj", "{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Osrusbfx2Task", "..\Service\Osrusbfx2Task\Osrusbfx2Task.csproj", "{8790F5BD-720C-5C15-9A07-D72D4BA3FD35}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|ARM = Release|ARM
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{146F5FC7-B970-588C-A9E1-E33140CECB29}.Debug|ARM.ActiveCfg = Debug|ARM
{146F5FC7-B970-588C-A9E1-E33140CECB29}.Debug|Any CPU.ActiveCfg = Debug|Win32
{146F5FC7-B970-588C-A9E1-E33140CECB29}.Debug|x64.ActiveCfg = Debug|x64
{146F5FC7-B970-588C-A9E1-E33140CECB29}.Debug|x64.Build.0 = Debug|x64
{146F5FC7-B970-588C-A9E1-E33140CECB29}.Debug|x64.Deploy.0 = Debug|x64
{146F5FC7-B970-588C-A9E1-E33140CECB29}.Debug|x86.ActiveCfg = Debug|Win32
{146F5FC7-B970-588C-A9E1-E33140CECB29}.Debug|x86.Build.0 = Debug|Win32
{146F5FC7-B970-588C-A9E1-E33140CECB29}.Release|ARM.ActiveCfg = Release|ARM
{146F5FC7-B970-588C-A9E1-E33140CECB29}.Release|Any CPU.ActiveCfg = Release|Win32
{146F5FC7-B970-588C-A9E1-E33140CECB29}.Release|x64.ActiveCfg = Release|x64
{146F5FC7-B970-588C-A9E1-E33140CECB29}.Release|x64.Build.0 = Release|x64
{146F5FC7-B970-588C-A9E1-E33140CECB29}.Release|x86.ActiveCfg = Release|Win32
{146F5FC7-B970-588C-A9E1-E33140CECB29}.Release|x86.Build.0 = Release|Win32
{2125A674-5E3F-57DC-96EB-DB20C36FF7D3}.Debug|ARM.ActiveCfg = Debug|ARM
{2125A674-5E3F-57DC-96EB-DB20C36FF7D3}.Debug|Any CPU.ActiveCfg = Debug|Win32
{2125A674-5E3F-57DC-96EB-DB20C36FF7D3}.Debug|x64.ActiveCfg = Debug|x64
{2125A674-5E3F-57DC-96EB-DB20C36FF7D3}.Debug|x64.Build.0 = Debug|x64
{2125A674-5E3F-57DC-96EB-DB20C36FF7D3}.Debug|x86.ActiveCfg = Debug|Win32
{2125A674-5E3F-57DC-96EB-DB20C36FF7D3}.Debug|x86.Build.0 = Debug|Win32
{2125A674-5E3F-57DC-96EB-DB20C36FF7D3}.Release|ARM.ActiveCfg = Release|ARM
{2125A674-5E3F-57DC-96EB-DB20C36FF7D3}.Release|Any CPU.ActiveCfg = Release|Win32
{2125A674-5E3F-57DC-96EB-DB20C36FF7D3}.Release|x64.ActiveCfg = Release|x64
{2125A674-5E3F-57DC-96EB-DB20C36FF7D3}.Release|x64.Build.0 = Release|x64
{2125A674-5E3F-57DC-96EB-DB20C36FF7D3}.Release|x86.ActiveCfg = Release|Win32
{2125A674-5E3F-57DC-96EB-DB20C36FF7D3}.Release|x86.Build.0 = Release|Win32
{35C2A506-5CDC-5EAE-B633-2385314CFF17}.Debug|ARM.ActiveCfg = Debug|ARM
{35C2A506-5CDC-5EAE-B633-2385314CFF17}.Debug|Any CPU.ActiveCfg = Debug|Win32
{35C2A506-5CDC-5EAE-B633-2385314CFF17}.Debug|x64.ActiveCfg = Debug|x64
{35C2A506-5CDC-5EAE-B633-2385314CFF17}.Debug|x64.Build.0 = Debug|x64
{35C2A506-5CDC-5EAE-B633-2385314CFF17}.Debug|x86.ActiveCfg = Debug|Win32
{35C2A506-5CDC-5EAE-B633-2385314CFF17}.Debug|x86.Build.0 = Debug|Win32
{35C2A506-5CDC-5EAE-B633-2385314CFF17}.Release|ARM.ActiveCfg = Release|ARM
{35C2A506-5CDC-5EAE-B633-2385314CFF17}.Release|Any CPU.ActiveCfg = Release|Win32
{35C2A506-5CDC-5EAE-B633-2385314CFF17}.Release|x64.ActiveCfg = Release|x64
{35C2A506-5CDC-5EAE-B633-2385314CFF17}.Release|x64.Build.0 = Release|x64
{35C2A506-5CDC-5EAE-B633-2385314CFF17}.Release|x86.ActiveCfg = Release|Win32
{35C2A506-5CDC-5EAE-B633-2385314CFF17}.Release|x86.Build.0 = Release|Win32
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Debug|ARM.ActiveCfg = Debug|ARM
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Debug|ARM.Build.0 = Debug|ARM
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Debug|ARM.Deploy.0 = Debug|ARM
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Debug|Any CPU.ActiveCfg = Debug|x86
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Debug|x64.ActiveCfg = Debug|x64
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Debug|x64.Build.0 = Debug|x64
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Debug|x64.Deploy.0 = Debug|x64
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Debug|x86.ActiveCfg = Debug|x86
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Debug|x86.Build.0 = Debug|x86
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Debug|x86.Deploy.0 = Debug|x86
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Release|ARM.ActiveCfg = Release|ARM
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Release|ARM.Build.0 = Release|ARM
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Release|ARM.Deploy.0 = Release|ARM
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Release|Any CPU.ActiveCfg = Release|x86
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Release|x64.ActiveCfg = Release|x64
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Release|x64.Build.0 = Release|x64
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Release|x64.Deploy.0 = Release|x64
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Release|x86.ActiveCfg = Release|x86
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Release|x86.Build.0 = Release|x86
{F33E1D68-F07A-5273-B28A-3ABA296F0B5C}.Release|x86.Deploy.0 = Release|x86
{8790F5BD-720C-5C15-9A07-D72D4BA3FD35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8790F5BD-720C-5C15-9A07-D72D4BA3FD35}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8790F5BD-720C-5C15-9A07-D72D4BA3FD35}.Debug|x64.ActiveCfg = Debug|x64
{8790F5BD-720C-5C15-9A07-D72D4BA3FD35}.Debug|x64.Build.0 = Debug|x64
{8790F5BD-720C-5C15-9A07-D72D4BA3FD35}.Debug|x86.ActiveCfg = Debug|x86
{8790F5BD-720C-5C15-9A07-D72D4BA3FD35}.Debug|x86.Build.0 = Debug|x86
{8790F5BD-720C-5C15-9A07-D72D4BA3FD35}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8790F5BD-720C-5C15-9A07-D72D4BA3FD35}.Release|Any CPU.Build.0 = Release|Any CPU
{8790F5BD-720C-5C15-9A07-D72D4BA3FD35}.Release|x64.ActiveCfg = Release|x64
{8790F5BD-720C-5C15-9A07-D72D4BA3FD35}.Release|x64.Build.0 = Release|x64
{8790F5BD-720C-5C15-9A07-D72D4BA3FD35}.Release|x86.ActiveCfg = Release|x86
{8790F5BD-720C-5C15-9A07-D72D4BA3FD35}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

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

@ -16,10 +16,7 @@ namespace SDKTemplate
{
static class Fx2Driver
{
// The device type value expected by the driver in IO control
// codes. The driver defines this as 0x65500 but the value gets
// truncated to a ushort. Do the same here.
public const ushort DeviceType = unchecked((ushort)0x65500);
public const ushort DeviceType = 65500;
public const ushort FunctionBase = 0x800;
public static
@ -27,7 +24,7 @@ namespace SDKTemplate
FunctionBase + 7,
IOControlAccessMode.Read,
IOControlBufferingMethod.Buffered);
public static
IOControlCode SetSevenSegmentDisplay = new IOControlCode(DeviceType,
FunctionBase + 8,

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

@ -5,9 +5,11 @@
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4"
IgnorableNamespaces="uap mp uap4">
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap mp uap4 rescap"
>
<Identity
<Identity
Name="Microsoft.SDKSamples.CustomCapability.CS"
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
Version="1.0.0.0" />
@ -21,7 +23,7 @@
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.15063.0" MaxVersionTested="10.0.17134.0" />
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17134.0" MaxVersionTested="10.0.17134.0" />
</Dependencies>
<Resources>
@ -44,11 +46,23 @@
<uap:ShowOn Tile="square150x150Logo" />
</uap:ShowNameOnTiles>
</uap:DefaultTile>
</uap:VisualElements>
</uap:VisualElements>
<Extensions>
<Extension Category="windows.backgroundTasks" EntryPoint="Osrusbfx2Task.ConnectedTask">
<BackgroundTasks>
<Task Type="systemEvent" />
</BackgroundTasks>
</Extension>
</Extensions>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="smbios" />
<!-- Enable "protectedApp" capability before store submission
to access firmware variables in production environment -->
<!-- <rescap:Capability Name="protectedApp" /> -->
<uap4:CustomCapability Name="microsoft.firmwareRead_cw5n1h2txyewy" />
<uap4:CustomCapability Name="microsoft.hsaTestCustomCapability_q536wpkpf5cy2" />
</Capabilities>
</Package>

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

@ -21,11 +21,13 @@ namespace SDKTemplate
List<Scenario> scenarios = new List<Scenario>
{
new Scenario() { Title="Connect to an NT Service", ClassType=typeof(MeteringData)},
new Scenario() { Title="Connect to an NT Service", ClassType=typeof(MeteringData)},
new Scenario() { Title="Connect to the FX2 Device", ClassType=typeof(DeviceConnect) },
new Scenario() { Title="Send IOCTLs to the device", ClassType=typeof(DeviceIO) },
new Scenario() { Title="Handle asynchronous device events", ClassType=typeof(DeviceEvents) },
new Scenario() { Title="Read and Write operations", ClassType=typeof(DeviceReadWrite) }
new Scenario() { Title="Read and Write operations", ClassType=typeof(DeviceReadWrite) },
new Scenario() { Title="Custom system event trigger", ClassType=typeof(CustomTrigger) },
new Scenario() { Title="Firmware access", ClassType=typeof(FirmwareAccess) },
};
}

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

@ -0,0 +1,111 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
using System;
using Windows.ApplicationModel.Background;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Navigation;
namespace SDKTemplate
{
public sealed partial class CustomTrigger
{
MainPage rootPage = MainPage.Current;
BackgroundTaskRegistration taskRegistration;
const string customTriggerTaskName = "Osrusbfx2Task.ConnectedTask";
const string guidCustomSystemEventId_OsrUsbFx2 = "{C7BDD245-5CDA-4BBD-B68D-B5E36F7911A3}";
public CustomTrigger()
{
this.InitializeComponent();
UpdateUI();
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
UnregisterTask();
}
void UpdateUI()
{
RegisterCustomTrigger.IsEnabled = (taskRegistration == null);
UnregisterCustomTrigger.IsEnabled = (taskRegistration != null);
}
void UnregisterTask()
{
if (taskRegistration != null)
{
taskRegistration.Unregister(true);
taskRegistration = null;
}
}
void RegisterCustomTrigger_Click(Object sender, RoutedEventArgs e)
{
if (IsFx2CustomTriggerTaskRegistered())
{
rootPage.NotifyUser("Osrusbfx2.ConnectedTask background task has already been registered", NotifyType.ErrorMessage);
}
// Create a new background task builder.
BackgroundTaskBuilder taskBuilder = new BackgroundTaskBuilder();
// Create a new OEM trigger.
CustomSystemEventTrigger fx2Trigger = new CustomSystemEventTrigger(
guidCustomSystemEventId_OsrUsbFx2, // Trigger Qualifier
CustomSystemEventTriggerRecurrence.Once); // One-shot trigger
// Associate the fx2Trigger trigger with the background task builder.
taskBuilder.SetTrigger(fx2Trigger);
// Specify the background task to run when the trigger fires.
taskBuilder.TaskEntryPoint = customTriggerTaskName;
// Name the background task.
taskBuilder.Name = customTriggerTaskName;
try
{
// Register the background task.
taskRegistration = taskBuilder.Register();
}
catch (Exception ex) {
rootPage.NotifyUser(ex.ToString(), NotifyType.ErrorMessage);
return;
}
UpdateUI();
}
bool IsFx2CustomTriggerTaskRegistered()
{
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
string taskName = task.Value.Name;
if (taskName == customTriggerTaskName)
{
return true;
}
}
return false;
}
void UnregisterCustomTrigger_Click(Object sender, RoutedEventArgs e)
{
UnregisterTask();
UpdateUI();
}
}
}

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

@ -0,0 +1,82 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
using System;
using System.Runtime.InteropServices;
using System.Text;
using Windows.UI.Xaml;
namespace SDKTemplate
{
public sealed partial class FirmwareAccess
{
MainPage rootPage = MainPage.Current;
public FirmwareAccess()
{
this.InitializeComponent();
}
[DllImport("Kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int GetFirmwareEnvironmentVariable(string name, string guid,
[Out, MarshalAs(UnmanagedType.LPArray)] char[] lpszBuffer, int size);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern uint GetLastError();
[DllImport("rpcclient.dll", CharSet = CharSet.Unicode)]
extern static uint GetManufacturerNameFromSmbios(StringBuilder ManufacturerName, uint Size);
[DllImport("rpcclient.dll", CharSet = CharSet.Unicode)]
extern static uint GetSecureBootEnabledFromUefi([MarshalAs(UnmanagedType.U1)] ref bool SecureBootEnabled);
const uint ERROR_SUCCESS = 0;
const uint ERROR_INVALID_FUNCTION = 1;
void GetManufacturerName_Click(Object sender, RoutedEventArgs e)
{
const int maxNameLength = 255;
StringBuilder name = new StringBuilder(maxNameLength);
uint error = GetManufacturerNameFromSmbios(name, (uint)name.Capacity);
if (error == ERROR_SUCCESS)
{
ManufacturerName.Text = name.ToString();
}
else
{
rootPage.NotifyUser($"Failed to retrieve manufacturer name from SMBIOS, error {error}", NotifyType.ErrorMessage);
}
}
void SecureBootState_Click(Object sender, RoutedEventArgs e)
{
bool secureBootEnabled = false;
uint error = GetSecureBootEnabledFromUefi(ref secureBootEnabled);
switch (error)
{
case ERROR_SUCCESS:
SecureBootState.Text = secureBootEnabled.ToString();
break;
case ERROR_INVALID_FUNCTION:
rootPage.NotifyUser("Windows was installed using legacy BIOS", NotifyType.ErrorMessage);
break;
default:
rootPage.NotifyUser($"Failed to retrieve secure boot state from UEFI, error {error}", NotifyType.ErrorMessage);
break;
}
}
}
}

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

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<CustomCapabilityDescriptor xmlns="http://schemas.microsoft.com/appx/2016/sccd" xmlns:s="http://schemas.microsoft.com/appx/2016/sccd">
<CustomCapabilities>
<CustomCapability Name="microsoft.firmwareRead_cw5n1h2txyewy"></CustomCapability>
<CustomCapability Name="microsoft.hsaTestCustomCapability_q536wpkpf5cy2"></CustomCapability>
</CustomCapabilities>
<AuthorizedEntities>

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

@ -163,6 +163,8 @@
<Content Include="html\scenario3_deviceIO.html" />
<Content Include="html\scenario4_deviceEvents.html" />
<Content Include="html\scenario5_deviceReadWrite.html" />
<Content Include="html\scenario6_customTrigger.html" />
<Content Include="html\scenario7_firmwareAccess.html" />
<Content Include="js\deviceList.js" />
<Content Include="js\fx2Driver.js" />
<Content Include="js\sample-configuration.js" />
@ -171,8 +173,11 @@
<Content Include="js\scenario3_deviceIO.js" />
<Content Include="js\scenario4_deviceEvents.js" />
<Content Include="js\scenario5_deviceReadWrite.js" />
<Content Include="js\scenario6_customTrigger.js" />
<Content Include="js\scenario7_firmwareAccess.js" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Service\Osrusbfx2Task\Osrusbfx2Task.csproj" />
<ProjectReference Condition="'$(Platform)' == 'x86' Or '$(Platform)' == 'x64'" Include="RpcClientRt\RpcClientRt.vcxproj" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\$(WMSJSProjectDirectory)\Microsoft.VisualStudio.$(WMSJSProject).targets" />

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

@ -18,76 +18,93 @@ EndProject
Project("{262852C6-CD72-467D-83FE-5EEB1973A190}") = "CustomCapability", "CustomCapability.jsproj", "{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RpcClientRt", "RpcClientRt\RpcClientRt.vcxproj", "{03DB0B89-07A6-58C7-B52A-16FC172BBC93}"
ProjectSection(ProjectDependencies) = postProject
{DA565D01-E248-5913-9DF9-A16EBB6B9C5E} = {DA565D01-E248-5913-9DF9-A16EBB6B9C5E}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Osrusbfx2Task", "..\Service\Osrusbfx2Task\Osrusbfx2Task.csproj", "{6ED16835-4B91-50B2-AA39-2C2955ABD440}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|ARM = Release|ARM
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BA80D389-9C8D-5BBA-932D-05E5C733D657}.Debug|ARM.ActiveCfg = Debug|ARM
{BA80D389-9C8D-5BBA-932D-05E5C733D657}.Debug|Any CPU.ActiveCfg = Debug|Win32
{BA80D389-9C8D-5BBA-932D-05E5C733D657}.Debug|x64.ActiveCfg = Debug|x64
{BA80D389-9C8D-5BBA-932D-05E5C733D657}.Debug|x64.Build.0 = Debug|x64
{BA80D389-9C8D-5BBA-932D-05E5C733D657}.Debug|x64.Deploy.0 = Debug|x64
{BA80D389-9C8D-5BBA-932D-05E5C733D657}.Debug|x86.ActiveCfg = Debug|Win32
{BA80D389-9C8D-5BBA-932D-05E5C733D657}.Debug|x86.Build.0 = Debug|Win32
{BA80D389-9C8D-5BBA-932D-05E5C733D657}.Release|ARM.ActiveCfg = Release|ARM
{BA80D389-9C8D-5BBA-932D-05E5C733D657}.Release|Any CPU.ActiveCfg = Release|Win32
{BA80D389-9C8D-5BBA-932D-05E5C733D657}.Release|x64.ActiveCfg = Release|x64
{BA80D389-9C8D-5BBA-932D-05E5C733D657}.Release|x64.Build.0 = Release|x64
{BA80D389-9C8D-5BBA-932D-05E5C733D657}.Release|x86.ActiveCfg = Release|Win32
{BA80D389-9C8D-5BBA-932D-05E5C733D657}.Release|x86.Build.0 = Release|Win32
{3E0FCE27-35CC-588A-89BF-3408B1FD0645}.Debug|ARM.ActiveCfg = Debug|ARM
{3E0FCE27-35CC-588A-89BF-3408B1FD0645}.Debug|Any CPU.ActiveCfg = Debug|Win32
{3E0FCE27-35CC-588A-89BF-3408B1FD0645}.Debug|x64.ActiveCfg = Debug|x64
{3E0FCE27-35CC-588A-89BF-3408B1FD0645}.Debug|x64.Build.0 = Debug|x64
{3E0FCE27-35CC-588A-89BF-3408B1FD0645}.Debug|x86.ActiveCfg = Debug|Win32
{3E0FCE27-35CC-588A-89BF-3408B1FD0645}.Debug|x86.Build.0 = Debug|Win32
{3E0FCE27-35CC-588A-89BF-3408B1FD0645}.Release|ARM.ActiveCfg = Release|ARM
{3E0FCE27-35CC-588A-89BF-3408B1FD0645}.Release|Any CPU.ActiveCfg = Release|Win32
{3E0FCE27-35CC-588A-89BF-3408B1FD0645}.Release|x64.ActiveCfg = Release|x64
{3E0FCE27-35CC-588A-89BF-3408B1FD0645}.Release|x64.Build.0 = Release|x64
{3E0FCE27-35CC-588A-89BF-3408B1FD0645}.Release|x86.ActiveCfg = Release|Win32
{3E0FCE27-35CC-588A-89BF-3408B1FD0645}.Release|x86.Build.0 = Release|Win32
{DA565D01-E248-5913-9DF9-A16EBB6B9C5E}.Debug|ARM.ActiveCfg = Debug|ARM
{DA565D01-E248-5913-9DF9-A16EBB6B9C5E}.Debug|Any CPU.ActiveCfg = Debug|Win32
{DA565D01-E248-5913-9DF9-A16EBB6B9C5E}.Debug|x64.ActiveCfg = Debug|x64
{DA565D01-E248-5913-9DF9-A16EBB6B9C5E}.Debug|x64.Build.0 = Debug|x64
{DA565D01-E248-5913-9DF9-A16EBB6B9C5E}.Debug|x86.ActiveCfg = Debug|Win32
{DA565D01-E248-5913-9DF9-A16EBB6B9C5E}.Debug|x86.Build.0 = Debug|Win32
{DA565D01-E248-5913-9DF9-A16EBB6B9C5E}.Release|ARM.ActiveCfg = Release|ARM
{DA565D01-E248-5913-9DF9-A16EBB6B9C5E}.Release|Any CPU.ActiveCfg = Release|Win32
{DA565D01-E248-5913-9DF9-A16EBB6B9C5E}.Release|x64.ActiveCfg = Release|x64
{DA565D01-E248-5913-9DF9-A16EBB6B9C5E}.Release|x64.Build.0 = Release|x64
{DA565D01-E248-5913-9DF9-A16EBB6B9C5E}.Release|x86.ActiveCfg = Release|Win32
{DA565D01-E248-5913-9DF9-A16EBB6B9C5E}.Release|x86.Build.0 = Release|Win32
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Debug|ARM.ActiveCfg = Debug|ARM
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Debug|ARM.Build.0 = Debug|ARM
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Debug|ARM.Deploy.0 = Debug|ARM
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Debug|Any CPU.Build.0 = Debug|Any CPU
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Debug|x64.ActiveCfg = Debug|x64
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Debug|x64.Build.0 = Debug|x64
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Debug|x64.Deploy.0 = Debug|x64
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Debug|x86.ActiveCfg = Debug|x86
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Debug|x86.Build.0 = Debug|x86
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Debug|x86.Deploy.0 = Debug|x86
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Release|ARM.ActiveCfg = Release|ARM
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Release|ARM.Build.0 = Release|ARM
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Release|ARM.Deploy.0 = Release|ARM
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Release|Any CPU.ActiveCfg = Release|Any CPU
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Release|Any CPU.Build.0 = Release|Any CPU
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Release|Any CPU.Deploy.0 = Release|Any CPU
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Release|x64.ActiveCfg = Release|x64
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Release|x64.Build.0 = Release|x64
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Release|x64.Deploy.0 = Release|x64
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Release|x86.ActiveCfg = Release|x86
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Release|x86.Build.0 = Release|x86
{945B7C2C-7F47-5F0F-928F-2DDC69F89F31}.Release|x86.Deploy.0 = Release|x86
{03DB0B89-07A6-58C7-B52A-16FC172BBC93}.Debug|ARM.ActiveCfg = Debug|ARM
{03DB0B89-07A6-58C7-B52A-16FC172BBC93}.Debug|Any CPU.ActiveCfg = Debug|Win32
{03DB0B89-07A6-58C7-B52A-16FC172BBC93}.Debug|x64.ActiveCfg = Debug|x64
{03DB0B89-07A6-58C7-B52A-16FC172BBC93}.Debug|x64.Build.0 = Debug|x64
{03DB0B89-07A6-58C7-B52A-16FC172BBC93}.Debug|x86.ActiveCfg = Debug|Win32
{03DB0B89-07A6-58C7-B52A-16FC172BBC93}.Debug|x86.Build.0 = Debug|Win32
{03DB0B89-07A6-58C7-B52A-16FC172BBC93}.Release|ARM.ActiveCfg = Release|ARM
{03DB0B89-07A6-58C7-B52A-16FC172BBC93}.Release|Any CPU.ActiveCfg = Release|Win32
{03DB0B89-07A6-58C7-B52A-16FC172BBC93}.Release|x64.ActiveCfg = Release|x64
{03DB0B89-07A6-58C7-B52A-16FC172BBC93}.Release|x64.Build.0 = Release|x64
{03DB0B89-07A6-58C7-B52A-16FC172BBC93}.Release|x86.ActiveCfg = Release|Win32
{03DB0B89-07A6-58C7-B52A-16FC172BBC93}.Release|x86.Build.0 = Release|Win32
{6ED16835-4B91-50B2-AA39-2C2955ABD440}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6ED16835-4B91-50B2-AA39-2C2955ABD440}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6ED16835-4B91-50B2-AA39-2C2955ABD440}.Debug|x64.ActiveCfg = Debug|x64
{6ED16835-4B91-50B2-AA39-2C2955ABD440}.Debug|x64.Build.0 = Debug|x64
{6ED16835-4B91-50B2-AA39-2C2955ABD440}.Debug|x86.ActiveCfg = Debug|x86
{6ED16835-4B91-50B2-AA39-2C2955ABD440}.Debug|x86.Build.0 = Debug|x86
{6ED16835-4B91-50B2-AA39-2C2955ABD440}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6ED16835-4B91-50B2-AA39-2C2955ABD440}.Release|Any CPU.Build.0 = Release|Any CPU
{6ED16835-4B91-50B2-AA39-2C2955ABD440}.Release|x64.ActiveCfg = Release|x64
{6ED16835-4B91-50B2-AA39-2C2955ABD440}.Release|x64.Build.0 = Release|x64
{6ED16835-4B91-50B2-AA39-2C2955ABD440}.Release|x86.ActiveCfg = Release|x86
{6ED16835-4B91-50B2-AA39-2C2955ABD440}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

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

@ -214,6 +214,7 @@
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="RpcClientRt.h" />
<ClInclude Include="SmbiosRT.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
@ -225,6 +226,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="RpcClientRt.cpp" />
<ClCompile Include="SmbiosRT.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Service\Client\RpcClient.vcxproj">

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

@ -9,9 +9,11 @@
<ItemGroup>
<ClCompile Include="pch.cpp" />
<ClCompile Include="RpcClientRt.cpp" />
<ClCompile Include="SmbiosRT.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="RpcClientRt.h" />
<ClInclude Include="SmbiosRT.h" />
</ItemGroup>
</Project>

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

@ -0,0 +1,36 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
#include "pch.h"
#include "firmwareaccess.h"
#include "SmbiosRt.h"
using namespace RpcClientRt;
using namespace Platform;
/*
WinRT wrapper component to access RpcClient.dll exports
from JavaScript
*/
SmbiosResult^ Smbios::GetManufacturerName()
{
wchar_t nameBuffer[MANUFACTURER_NAME_LENGTH_MAX];
unsigned int errorCode = GetManufacturerNameFromSmbios(nameBuffer, ARRAYSIZE(nameBuffer));
return ref new SmbiosResult(errorCode, errorCode == ERROR_SUCCESS ? ref new String(nameBuffer) : nullptr);
}
SmbiosResult^ Smbios::GetSecureBootEnabled()
{
bool enabled = false;
unsigned int errorCode = GetSecureBootEnabledFromUefi(&enabled);
return ref new SmbiosResult(errorCode, errorCode == ERROR_SUCCESS ? static_cast<Object^>(enabled) : nullptr);
}

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

@ -0,0 +1,49 @@
#pragma once
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
#pragma once
/*
WinRT wrapper component to access smbios exports
from JavaScript
*/
namespace RpcClientRt
{
public ref class SmbiosResult sealed
{
public:
property unsigned int ErrorCode
{
unsigned int get() { return m_errorCode; }
}
property Platform::Object^ Value
{
Platform::Object^ get() { return m_value; }
}
internal:
SmbiosResult(unsigned int errorCode, Platform::Object^ value)
: m_errorCode(errorCode), m_value(value)
{
}
private:
Platform::Object^ m_value;
unsigned int m_errorCode;
};
public ref class Smbios sealed
{
public:
static SmbiosResult^ GetManufacturerName();
static SmbiosResult^ GetSecureBootEnabled();
};
}

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

@ -14,7 +14,7 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<link rel="stylesheet" href="/css/scenario1_deviceConnect.css" />
<link rel="stylesheet" href="/css/scenario2_deviceConnect.css" />
<script src="/js/fx2Driver.js"></script>
<script src="/js/deviceList.js"></script>
<script src="/js/scenario2_deviceConnect.js"></script>

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

@ -14,7 +14,7 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<link rel="stylesheet" href="/css/scenario2_deviceIO.css" />
<link rel="stylesheet" href="/css/scenario3_deviceIO.css" />
<script src="/js/fx2Driver.js"></script>
<script src="/js/deviceList.js"></script>
<script src="/js/scenario3_deviceIO.js"></script>

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

@ -14,7 +14,7 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<link rel="stylesheet" href="/css/scenario3_deviceEvents.css" />
<link rel="stylesheet" href="/css/scenario4_deviceEvents.css" />
<script src="/js/fx2Driver.js"></script>
<script src="/js/deviceList.js"></script>
<script src="/js/scenario4_deviceEvents.js"></script>

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

@ -14,7 +14,7 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<link rel="stylesheet" href="/css/scenario4_deviceReadWrite.css" />
<link rel="stylesheet" href="/css/scenario5_deviceReadWrite.css" />
<script src="/js/fx2Driver.js"></script>
<script src="/js/deviceList.js"></script>
<script src="/js/scenario5_deviceReadWrite.js"></script>

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

@ -0,0 +1,34 @@
<!--
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
-->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="/js/scenario6_customTrigger.js"></script>
</head>
<body>
<div>
<h2 id="sampleHeader" class="win-type-subheader">Description:</h2>
<div id="scenarioDescription">
Custom Trigger Registration
</div>
<p>This scenario demonstrates how to use a custom trigger for a background task.</p>
<p>
<button class="win-button" id="custom-trigger-register">Register</button>
<button class="win-button" id="custom-trigger-unregister">Unregister</button>
</p>
<p>After registering the task, connect a fx2 device. The task will display a device arrival notification toast.</p>
</div>
</body>
</html>

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

@ -0,0 +1,44 @@
<!--
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
-->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="/js/scenario7_firmwareAccess.js"></script>
</head>
<body>
<div>
<h2 id="sampleHeader" class="win-type-subheader">Description:</h2>
<div id="scenarioDescription">
This scenario reads from the system firmware.
</div>
<p>
With the "smbios" restricted capability, you can retrieve SMBIOS data using the
<a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms724379(v=vs.85).aspx">GetSystemFirmwareTable</a>
function.
</p>
<p><button class="win-button" id="manufacturer-name">Get Manufacturer Name</button></p>
<p>Manufacturer Name: <span id="manufacturer-name-output"></span></p>
<p>
With the "microsoft.firmwareRead_cw5n1h2txyewy" custom capability,
you can read UEFI variables using the
<a href="https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-getfirmwareenvironmentvariablew">GetFirmwareEnvironmentVariable</a>
function.
</p>
<p><button class="win-button" id="secure-boot-status">Check secure boot</button></p>
<p>Secure boot state: <span id="secure-boot-status-output"></span></p>
</div>
</body>
</html>

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

@ -4,7 +4,7 @@
"use strict";
var Custom = Windows.Devices.Custom;
var deviceType = 0x5500;
var deviceType = 65500;
var functionBase = 0x800;
var sevenSegmentValues = [
@ -17,7 +17,7 @@
0xF4, // 6
0x07, // 7
0xF7, // 8
0x67, // 9
0x67 // 9
];
//
@ -26,10 +26,10 @@
WinJS.Namespace.define(
"Fx2Driver",
{
//deviceType: deviceType,
//deviceType: deviceType,
//functionBase: functionBase,
getSevenSegmentDisplay: new Custom.IOControlCode(deviceType,
getSevenSegmentDisplay: new Custom.IOControlCode(deviceType,
functionBase + 7,
Custom.IOControlAccessMode.read,
Custom.IOControlBufferingMethod.buffered),
@ -44,7 +44,7 @@
Custom.IOControlAccessMode.read,
Custom.IOControlBufferingMethod.buffered),
getInterruptMessage: new Custom.IOControlCode(deviceType,
getInterruptMessage: new Custom.IOControlCode(deviceType,
functionBase + 9,
Custom.IOControlAccessMode.read,
Custom.IOControlBufferingMethod.directOutput),

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

@ -10,6 +10,8 @@
{ url: "/html/scenario3_deviceIO.html", title: "Getting and Setting device properties" },
{ url: "/html/scenario4_deviceEvents.html", title: "Registering for device events" },
{ url: "/html/scenario5_deviceReadWrite.html", title: "Read and Write operations" },
{ url: "/html/scenario6_customTrigger.html", title: "Custom System Event Trigger" },
{ url: "/html/scenario7_firmwareAccess.html", title: "Firmware Access" },
];
WinJS.Namespace.define("SdkSample", {

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

@ -0,0 +1,75 @@
//// Copyright (c) Microsoft Corporation. All rights reserved
(function () {
"use strict";
var registerButton;
var unregisterButton;
var page = WinJS.UI.Pages.define("/html/scenario6_customTrigger.html", {
ready: function (element, options) {
registerButton = document.getElementById("custom-trigger-register");
unregisterButton = document.getElementById("custom-trigger-unregister");
registerButton.addEventListener("click", onRegister, false);
unregisterButton.addEventListener("click", onUnregister, false);
updateUI();
}
});
var customTriggerTaskName = "Osrusbfx2Task.ConnectedTask";
var guidCustomSystemEventId_OsrUsbFx2 = "{C7BDD245-5CDA-4BBD-B68D-B5E36F7911A3}";
var taskRegistration = null;
function updateUI() {
registerButton.disabled = taskRegistration;
unregisterButton.disabled = !taskRegistration;
}
function IsFx2CustomTriggerTaskRegistered() {
var iter = Windows.ApplicationModel.Background.BackgroundTaskRegistration.allTasks.first();
while (iter.hasCurrent) {
var task = iter.current.value;
if (task.name === customTriggerTaskName) {
return true;
}
iter.moveNext();
}
return false;
}
function onRegister() {
if (IsFx2CustomTriggerTaskRegistered()) {
return;
}
var builder = new Windows.ApplicationModel.Background.BackgroundTaskBuilder();
builder.name = customTriggerTaskName;
builder.taskEntryPoint = customTriggerTaskName;
var customTrigger = new Windows.ApplicationModel.Background.CustomSystemEventTrigger(guidCustomSystemEventId_OsrUsbFx2, // Trigger Qualifier
Windows.ApplicationModel.Background.CustomSystemEventTriggerRecurrence.Once); // One-shot trigger
builder.setTrigger(customTrigger);
taskRegistration = builder.register();
updateUI();
}
function UnregisterTask()
{
if (taskRegistration) {
taskRegistration.unregister(true);
taskRegistration = null;
}
}
function onUnregister() {
UnregisterTask();
updateUI();
}
})();

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

@ -0,0 +1,43 @@
//// Copyright (c) Microsoft Corporation. All rights reserved
(function () {
"use strict";
var ERROR_SUCCESS = 0;
var ERROR_INVALID_FUNCTION = 1;
var page = WinJS.UI.Pages.define("/html/scenario7_firmwareAccess.html", {
ready: function (element, options) {
document.getElementById("manufacturer-name").addEventListener("click", onGetManufacturerName, false);
document.getElementById("secure-boot-status").addEventListener("click", onGetSecureBootStatus, false);
}
});
function onGetManufacturerName() {
var result = RpcClientRt.Smbios.getManufacturerName();
if (result.errorCode == ERROR_SUCCESS) {
document.getElementById("manufacturer-name-output").textContent = result.value;
} else {
WinJS.log && WinJS.log(`Failed to get the manufacturer name from smbios, error ${result.errorCode}`, "sample", "error");
}
}
function onGetSecureBootStatus() {
var result = RpcClientRt.Smbios.getSecureBootEnabled();
switch (result.errorCode) {
case ERROR_SUCCESS:
document.getElementById("secure-boot-status-output").textContent = result.value;
break;
case ERROR_INVALID_FUNCTION:
WinJS.log && WinJS.log("Windows was installed using legacy BIOS", "sample", "error");
break;
default:
WinJS.log && WinJS.log(`Failed to retrieve secure boot state from UEFI, error ${result.errorCode}`, "sample", "error");
break;
}
}
})();

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

@ -4,7 +4,8 @@
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4"
IgnorableNamespaces="uap mp uap4"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap mp uap4 rescap"
>
<Identity Name="Microsoft.SDKSamples.CustomCapability.JS" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" Version="1.0.0.0"/>
<mp:PhoneIdentity PhoneProductId="fc81cb9a-b33f-4520-9048-680ee0dd024b" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
@ -14,7 +15,7 @@
<Logo>images\StoreLogo-sdk.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.15063.0" MaxVersionTested="10.0.17134.0"/>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17134.0" MaxVersionTested="10.0.17134.0"/>
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
@ -35,9 +36,21 @@
</uap:ShowNameOnTiles>
</uap:DefaultTile>
</uap:VisualElements>
<Extensions>
<Extension Category="windows.backgroundTasks" EntryPoint="Osrusbfx2Task.ConnectedTask">
<BackgroundTasks>
<Task Type="systemEvent" />
</BackgroundTasks>
</Extension>
</Extensions>
</Application>
</Applications>
<Capabilities>
<uap4:CustomCapability Name="microsoft.hsaTestCustomCapability_q536wpkpf5cy2"/>
<rescap:Capability Name="smbios" />
<!-- Enable "protectedApp" capability before store submission
to access firmware variables in production environment -->
<!-- <rescap:Capability Name="protectedApp" /> -->
<uap4:CustomCapability Name="microsoft.firmwareRead_cw5n1h2txyewy" />
<uap4:CustomCapability Name="microsoft.hsaTestCustomCapability_q536wpkpf5cy2" />
</Capabilities>
</Package>

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

@ -0,0 +1,42 @@
<!--
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
-->
<Page
x:Class="SDKTemplate.CustomTrigger"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SDKTemplate"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<ScrollViewer Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Padding="12,10,12,12">
<StackPanel>
<TextBlock Text="Description:" Style="{StaticResource SampleHeaderTextStyle}"/>
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap">
This scenario demonstrates how to use a custom trigger for a background task.
</TextBlock>
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" FontWeight="Bold" TextWrapping="Wrap" Margin="0,20,0,0">
Custom Trigger Registration
</TextBlock>
<StackPanel Margin="10,10,10,0" Grid.Row="1">
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<Button x:Name="RegisterCustomTrigger" Content="Register" Margin="0,0,10,0" Click="RegisterCustomTrigger_Click"/>
<Button x:Name="UnregisterCustomTrigger" Content="Unregister" Margin="0,0,10,0" Click="UnregisterCustomTrigger_Click"/>
</StackPanel>
</StackPanel>
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap" Margin="0,10,0,0">
After registering the task, connect a fx2 device. The task will display a device arrival notification toast.
</TextBlock>
</StackPanel>
</ScrollViewer>
</Page>

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

@ -0,0 +1,45 @@
<!--
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
-->
<Page
x:Class="SDKTemplate.FirmwareAccess"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SDKTemplate"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<ScrollViewer Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Padding="12,10,12,12">
<StackPanel>
<TextBlock Text="Description:" Style="{StaticResource SampleHeaderTextStyle}"/>
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap">
This scenario reads from the system firmware.
</TextBlock>
<TextBlock Margin="0,20,0,0">
With the "smbios" restricted capability, you can retrieve SMBIOS data using the
<Hyperlink NavigateUri="https://msdn.microsoft.com/en-us/library/windows/desktop/ms724379(v=vs.85).aspx">GetSystemFirmwareTable</Hyperlink>
function.
</TextBlock>
<Button x:Name="GetManufacturerName" Content="Get Manufacturer Name" Margin="0,0,10,0" Click="GetManufacturerName_Click"/>
<TextBlock>Manufacturer Name: <Run x:Name="ManufacturerName"/></TextBlock>
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" FontWeight="Bold" TextWrapping="Wrap" Margin="0,20,0,0">
With the "microsoft.firmwareRead_cw5n1h2txyewy" custom capability,
you can read UEFI variables using the
<Hyperlink NavigateUri="https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-getfirmwareenvironmentvariablew">GetFirmwareEnvironmentVariable</Hyperlink>
function.
</TextBlock>
<Button x:Name="SecureBootStatus" Content="Check secure boot" Margin="0,0,10,0" Click="SecureBootState_Click"/>
<TextBlock>Secure boot state: <Run x:Name="SecureBootState"/></TextBlock>
</StackPanel>
</ScrollViewer>
</Page>

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

@ -21,8 +21,9 @@ Specifically, this sample shows how to:
- Create and configure an advanced color (FP16) DirectX render pipeline.
- Use WIC to decode a variety of SDR, WCG and HDR image content, including extended-range floating point data.
- Use Direct2D's effect pipeline to correctly perform color management and HDR brightness adjustment.
- Use DXGI to retrieve display color capabilities and adapt the image rendering pipeline to the display.
- Use Windows.Graphics.Display to retrieve display color capabilities and adapt the image rendering pipeline to the display.
- Implement a custom Direct2D effect to perform HDR-to-SDR tonemapping.
- Calculate HDR metadata of an image to assist with tonemapping.
## Sample project files
@ -68,9 +69,9 @@ Direct2D APIs:
[Color management effect](https://msdn.microsoft.com/en-us/library/windows/desktop/hh706318)
[ID2D1DeviceContext2::CreateImageSourceFromWic method](https://msdn.microsoft.com/en-us/library/windows/desktop/dn890793)
DXGI APIs:
Windows.Graphics.Display:
IDXGIOutput6
[AdvancedColorInfo](https://docs.microsoft.com/uwp/api/windows.graphics.display.advancedcolorinfo)
Related APIs:

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

@ -136,20 +136,24 @@
:: Parse the Visual Studio macro into a form usable by fxc.exe.
set INCLUDEPATHS="$(WindowsSDK_IncludePath)"
set INCLUDEPATHS=%INCLUDEPATHS:;=" /I "%
fxc /T lib_5_0 ReinhardEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)ReinhardEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_5_0 ReinhardEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)ReinhardEffect.fxlib" /Fo "$(OutDir)ReinhardEffect.cso" /Fh "$(OutDir)ReinhardEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_5_0 FilmicEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)FilmicEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_5_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)FilmicEffect.fxlib" /Fo "$(OutDir)FilmicEffect.cso" /Fh "$(OutDir)FilmicEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 ReinhardEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)ReinhardEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 ReinhardEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)ReinhardEffect.fxlib" /Fo "$(OutDir)ReinhardEffect.cso" /Fh "$(OutDir)ReinhardEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 FilmicEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)FilmicEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)FilmicEffect.fxlib" /Fo "$(OutDir)FilmicEffect.cso" /Fh "$(OutDir)FilmicEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 SdrOverlayEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)SdrOverlayEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 SdrOverlayEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)SdrOverlayEffect.fxlib" /Fo "$(OutDir)SdrOverlayEffect.cso" /Fh "$(OutDir)SdrOverlayEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 LuminanceHeatmapEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)LuminanceHeatmapEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 LuminanceHeatmapEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)LuminanceHeatmapEffect.fxlib" /Fo "$(OutDir)LuminanceHeatmapEffect.cso" /Fh "$(OutDir)LuminanceHeatmapEffectShader.h" /nologo /I %INCLUDEPATHS%
</Command>
</CustomBuildStep>
<CustomBuildStep>
<Message>Generate a linking compatible pixel shader</Message>
<Message>Generate shader-linking compatible pixel shaders for D2D custom effects</Message>
</CustomBuildStep>
<CustomBuildStep>
<Outputs>$(OutDir)ReinhardEffect.cso;$(OutDir)ReinhardEffectShader.h;$(OutDir)FilmicEffect.cso;$(OutDir)FilmicEffectShader.h</Outputs>
<Outputs>$(OutDir)ReinhardEffect.cso;$(OutDir)ReinhardEffectShader.h;$(OutDir)FilmicEffect.cso;$(OutDir)FilmicEffectShader.h;$(OutDir)SdrOverlayEffect.cso;$(OutDir)SdrOverlayEffectShader.h;$(OutDir)LuminanceHeatmapEffect.cso;$(OutDir)LuminanceHeatmapEffectShader.h</Outputs>
</CustomBuildStep>
<CustomBuildStep>
<Inputs>ReinhardEffect.hlsl,FilmicEffect.hlsl</Inputs>
<Inputs>ReinhardEffect.hlsl,FilmicEffect.hlsl,SdrOverlayEffect.hlsl,LuminanceHeatmapEffect.hlsl</Inputs>
</CustomBuildStep>
<CustomBuildStep>
<TreatOutputAsContent>true</TreatOutputAsContent>
@ -173,20 +177,24 @@ fxc /T ps_5_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /se
:: Parse the Visual Studio macro into a form usable by fxc.exe.
set INCLUDEPATHS="$(WindowsSDK_IncludePath)"
set INCLUDEPATHS=%INCLUDEPATHS:;=" /I "%
fxc /T lib_5_0 ReinhardEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)ReinhardEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_5_0 ReinhardEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)ReinhardEffect.fxlib" /Fo "$(OutDir)ReinhardEffect.cso" /Fh "$(OutDir)ReinhardEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_5_0 FilmicEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)FilmicEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_5_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)FilmicEffect.fxlib" /Fo "$(OutDir)FilmicEffect.cso" /Fh "$(OutDir)FilmicEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 ReinhardEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)ReinhardEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 ReinhardEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)ReinhardEffect.fxlib" /Fo "$(OutDir)ReinhardEffect.cso" /Fh "$(OutDir)ReinhardEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 FilmicEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)FilmicEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)FilmicEffect.fxlib" /Fo "$(OutDir)FilmicEffect.cso" /Fh "$(OutDir)FilmicEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 SdrOverlayEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)SdrOverlayEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 SdrOverlayEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)SdrOverlayEffect.fxlib" /Fo "$(OutDir)SdrOverlayEffect.cso" /Fh "$(OutDir)SdrOverlayEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 LuminanceHeatmapEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)LuminanceHeatmapEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 LuminanceHeatmapEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)LuminanceHeatmapEffect.fxlib" /Fo "$(OutDir)LuminanceHeatmapEffect.cso" /Fh "$(OutDir)LuminanceHeatmapEffectShader.h" /nologo /I %INCLUDEPATHS%
</Command>
</CustomBuildStep>
<CustomBuildStep>
<Message>Generate a linking compatible pixel shader</Message>
<Message>Generate shader-linking compatible pixel shaders for D2D custom effects</Message>
</CustomBuildStep>
<CustomBuildStep>
<Outputs>$(OutDir)ReinhardEffect.cso;$(OutDir)ReinhardEffectShader.h;$(OutDir)FilmicEffect.cso;$(OutDir)FilmicEffectShader.h</Outputs>
<Outputs>$(OutDir)ReinhardEffect.cso;$(OutDir)ReinhardEffectShader.h;$(OutDir)FilmicEffect.cso;$(OutDir)FilmicEffectShader.h;$(OutDir)SdrOverlayEffect.cso;$(OutDir)SdrOverlayEffectShader.h;$(OutDir)LuminanceHeatmapEffect.cso;$(OutDir)LuminanceHeatmapEffectShader.h</Outputs>
</CustomBuildStep>
<CustomBuildStep>
<Inputs>ReinhardEffect.hlsl,FilmicEffect.hlsl</Inputs>
<Inputs>ReinhardEffect.hlsl,FilmicEffect.hlsl,SdrOverlayEffect.hlsl,LuminanceHeatmapEffect.hlsl</Inputs>
</CustomBuildStep>
<CustomBuildStep>
<TreatOutputAsContent>true</TreatOutputAsContent>
@ -210,20 +218,24 @@ fxc /T ps_5_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /se
:: Parse the Visual Studio macro into a form usable by fxc.exe.
set INCLUDEPATHS="$(WindowsSDK_IncludePath)"
set INCLUDEPATHS=%INCLUDEPATHS:;=" /I "%
fxc /T lib_5_0 ReinhardEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)ReinhardEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_5_0 ReinhardEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)ReinhardEffect.fxlib" /Fo "$(OutDir)ReinhardEffect.cso" /Fh "$(OutDir)ReinhardEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_5_0 FilmicEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)FilmicEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_5_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)FilmicEffect.fxlib" /Fo "$(OutDir)FilmicEffect.cso" /Fh "$(OutDir)FilmicEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 ReinhardEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)ReinhardEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 ReinhardEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)ReinhardEffect.fxlib" /Fo "$(OutDir)ReinhardEffect.cso" /Fh "$(OutDir)ReinhardEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 FilmicEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)FilmicEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)FilmicEffect.fxlib" /Fo "$(OutDir)FilmicEffect.cso" /Fh "$(OutDir)FilmicEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 SdrOverlayEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)SdrOverlayEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 SdrOverlayEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)SdrOverlayEffect.fxlib" /Fo "$(OutDir)SdrOverlayEffect.cso" /Fh "$(OutDir)SdrOverlayEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 LuminanceHeatmapEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)LuminanceHeatmapEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 LuminanceHeatmapEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)LuminanceHeatmapEffect.fxlib" /Fo "$(OutDir)LuminanceHeatmapEffect.cso" /Fh "$(OutDir)LuminanceHeatmapEffectShader.h" /nologo /I %INCLUDEPATHS%
</Command>
</CustomBuildStep>
<CustomBuildStep>
<Message>Generate a linking compatible pixel shader</Message>
<Message>Generate shader-linking compatible pixel shaders for D2D custom effects</Message>
</CustomBuildStep>
<CustomBuildStep>
<Outputs>$(OutDir)ReinhardEffect.cso;$(OutDir)ReinhardEffectShader.h;$(OutDir)FilmicEffect.cso;$(OutDir)FilmicEffectShader.h</Outputs>
<Outputs>$(OutDir)ReinhardEffect.cso;$(OutDir)ReinhardEffectShader.h;$(OutDir)FilmicEffect.cso;$(OutDir)FilmicEffectShader.h;$(OutDir)SdrOverlayEffect.cso;$(OutDir)SdrOverlayEffectShader.h;$(OutDir)LuminanceHeatmapEffect.cso;$(OutDir)LuminanceHeatmapEffectShader.h</Outputs>
</CustomBuildStep>
<CustomBuildStep>
<Inputs>ReinhardEffect.hlsl,FilmicEffect.hlsl</Inputs>
<Inputs>ReinhardEffect.hlsl,FilmicEffect.hlsl,SdrOverlayEffect.hlsl,LuminanceHeatmapEffect.hlsl</Inputs>
</CustomBuildStep>
<CustomBuildStep>
<TreatOutputAsContent>true</TreatOutputAsContent>
@ -247,20 +259,24 @@ fxc /T ps_5_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /se
:: Parse the Visual Studio macro into a form usable by fxc.exe.
set INCLUDEPATHS="$(WindowsSDK_IncludePath)"
set INCLUDEPATHS=%INCLUDEPATHS:;=" /I "%
fxc /T lib_5_0 ReinhardEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)ReinhardEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_5_0 ReinhardEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)ReinhardEffect.fxlib" /Fo "$(OutDir)ReinhardEffect.cso" /Fh "$(OutDir)ReinhardEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_5_0 FilmicEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)FilmicEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_5_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)FilmicEffect.fxlib" /Fo "$(OutDir)FilmicEffect.cso" /Fh "$(OutDir)FilmicEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 ReinhardEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)ReinhardEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 ReinhardEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)ReinhardEffect.fxlib" /Fo "$(OutDir)ReinhardEffect.cso" /Fh "$(OutDir)ReinhardEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 FilmicEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)FilmicEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)FilmicEffect.fxlib" /Fo "$(OutDir)FilmicEffect.cso" /Fh "$(OutDir)FilmicEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 SdrOverlayEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)SdrOverlayEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 SdrOverlayEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)SdrOverlayEffect.fxlib" /Fo "$(OutDir)SdrOverlayEffect.cso" /Fh "$(OutDir)SdrOverlayEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 LuminanceHeatmapEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)LuminanceHeatmapEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 LuminanceHeatmapEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)LuminanceHeatmapEffect.fxlib" /Fo "$(OutDir)LuminanceHeatmapEffect.cso" /Fh "$(OutDir)LuminanceHeatmapEffectShader.h" /nologo /I %INCLUDEPATHS%
</Command>
</CustomBuildStep>
<CustomBuildStep>
<Message>Generate a linking compatible pixel shader</Message>
<Message>Generate shader-linking compatible pixel shaders for D2D custom effects</Message>
</CustomBuildStep>
<CustomBuildStep>
<Outputs>$(OutDir)ReinhardEffect.cso;$(OutDir)ReinhardEffectShader.h;$(OutDir)FilmicEffect.cso;$(OutDir)FilmicEffectShader.h</Outputs>
<Outputs>$(OutDir)ReinhardEffect.cso;$(OutDir)ReinhardEffectShader.h;$(OutDir)FilmicEffect.cso;$(OutDir)FilmicEffectShader.h;$(OutDir)SdrOverlayEffect.cso;$(OutDir)SdrOverlayEffectShader.h;$(OutDir)LuminanceHeatmapEffect.cso;$(OutDir)LuminanceHeatmapEffectShader.h</Outputs>
</CustomBuildStep>
<CustomBuildStep>
<Inputs>ReinhardEffect.hlsl,FilmicEffect.hlsl</Inputs>
<Inputs>ReinhardEffect.hlsl,FilmicEffect.hlsl,SdrOverlayEffect.hlsl,LuminanceHeatmapEffect.hlsl</Inputs>
</CustomBuildStep>
<CustomBuildStep>
<TreatOutputAsContent>true</TreatOutputAsContent>
@ -284,20 +300,24 @@ fxc /T ps_5_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /se
:: Parse the Visual Studio macro into a form usable by fxc.exe.
set INCLUDEPATHS="$(WindowsSDK_IncludePath)"
set INCLUDEPATHS=%INCLUDEPATHS:;=" /I "%
fxc /T lib_5_0 ReinhardEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)ReinhardEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_5_0 ReinhardEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)ReinhardEffect.fxlib" /Fo "$(OutDir)ReinhardEffect.cso" /Fh "$(OutDir)ReinhardEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_5_0 FilmicEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)FilmicEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_5_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)FilmicEffect.fxlib" /Fo "$(OutDir)FilmicEffect.cso" /Fh "$(OutDir)FilmicEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 ReinhardEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)ReinhardEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 ReinhardEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)ReinhardEffect.fxlib" /Fo "$(OutDir)ReinhardEffect.cso" /Fh "$(OutDir)ReinhardEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 FilmicEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)FilmicEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)FilmicEffect.fxlib" /Fo "$(OutDir)FilmicEffect.cso" /Fh "$(OutDir)FilmicEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 SdrOverlayEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)SdrOverlayEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 SdrOverlayEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)SdrOverlayEffect.fxlib" /Fo "$(OutDir)SdrOverlayEffect.cso" /Fh "$(OutDir)SdrOverlayEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 LuminanceHeatmapEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)LuminanceHeatmapEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 LuminanceHeatmapEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)LuminanceHeatmapEffect.fxlib" /Fo "$(OutDir)LuminanceHeatmapEffect.cso" /Fh "$(OutDir)LuminanceHeatmapEffectShader.h" /nologo /I %INCLUDEPATHS%
</Command>
</CustomBuildStep>
<CustomBuildStep>
<Message>Generate a linking compatible pixel shader</Message>
<Message>Generate shader-linking compatible pixel shaders for D2D custom effects</Message>
</CustomBuildStep>
<CustomBuildStep>
<Outputs>$(OutDir)ReinhardEffect.cso;$(OutDir)ReinhardEffectShader.h;$(OutDir)FilmicEffect.cso;$(OutDir)FilmicEffectShader.h</Outputs>
<Outputs>$(OutDir)ReinhardEffect.cso;$(OutDir)ReinhardEffectShader.h;$(OutDir)FilmicEffect.cso;$(OutDir)FilmicEffectShader.h;$(OutDir)SdrOverlayEffect.cso;$(OutDir)SdrOverlayEffectShader.h;$(OutDir)LuminanceHeatmapEffect.cso;$(OutDir)LuminanceHeatmapEffectShader.h</Outputs>
</CustomBuildStep>
<CustomBuildStep>
<Inputs>ReinhardEffect.hlsl,FilmicEffect.hlsl</Inputs>
<Inputs>ReinhardEffect.hlsl,FilmicEffect.hlsl,SdrOverlayEffect.hlsl,LuminanceHeatmapEffect.hlsl</Inputs>
</CustomBuildStep>
<CustomBuildStep>
<TreatOutputAsContent>true</TreatOutputAsContent>
@ -321,20 +341,24 @@ fxc /T ps_5_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /se
:: Parse the Visual Studio macro into a form usable by fxc.exe.
set INCLUDEPATHS="$(WindowsSDK_IncludePath)"
set INCLUDEPATHS=%INCLUDEPATHS:;=" /I "%
fxc /T lib_5_0 ReinhardEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)ReinhardEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_5_0 ReinhardEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)ReinhardEffect.fxlib" /Fo "$(OutDir)ReinhardEffect.cso" /Fh "$(OutDir)ReinhardEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_5_0 FilmicEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)FilmicEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_5_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)FilmicEffect.fxlib" /Fo "$(OutDir)FilmicEffect.cso" /Fh "$(OutDir)FilmicEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 ReinhardEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)ReinhardEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 ReinhardEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)ReinhardEffect.fxlib" /Fo "$(OutDir)ReinhardEffect.cso" /Fh "$(OutDir)ReinhardEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 FilmicEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)FilmicEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)FilmicEffect.fxlib" /Fo "$(OutDir)FilmicEffect.cso" /Fh "$(OutDir)FilmicEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 SdrOverlayEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)SdrOverlayEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 SdrOverlayEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)SdrOverlayEffect.fxlib" /Fo "$(OutDir)SdrOverlayEffect.cso" /Fh "$(OutDir)SdrOverlayEffectShader.h" /nologo /I %INCLUDEPATHS%
fxc /T lib_4_0 LuminanceHeatmapEffect.hlsl /D D2D_FUNCTION /D D2D_ENTRY=main /Fl "$(ProjectDir)LuminanceHeatmapEffect.fxlib" /nologo /I %INCLUDEPATHS%
fxc /T ps_4_0 LuminanceHeatmapEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /setprivate "$(ProjectDir)LuminanceHeatmapEffect.fxlib" /Fo "$(OutDir)LuminanceHeatmapEffect.cso" /Fh "$(OutDir)LuminanceHeatmapEffectShader.h" /nologo /I %INCLUDEPATHS%
</Command>
</CustomBuildStep>
<CustomBuildStep>
<Message>Generate a linking compatible pixel shader</Message>
<Message>Generate shader-linking compatible pixel shaders for D2D custom effects</Message>
</CustomBuildStep>
<CustomBuildStep>
<Outputs>$(OutDir)ReinhardEffect.cso;$(OutDir)ReinhardEffectShader.h;$(OutDir)FilmicEffect.cso;$(OutDir)FilmicEffectShader.h</Outputs>
<Outputs>$(OutDir)ReinhardEffect.cso;$(OutDir)ReinhardEffectShader.h;$(OutDir)FilmicEffect.cso;$(OutDir)FilmicEffectShader.h;$(OutDir)SdrOverlayEffect.cso;$(OutDir)SdrOverlayEffectShader.h;$(OutDir)LuminanceHeatmapEffect.cso;$(OutDir)LuminanceHeatmapEffectShader.h</Outputs>
</CustomBuildStep>
<CustomBuildStep>
<Inputs>ReinhardEffect.hlsl,FilmicEffect.hlsl</Inputs>
<Inputs>ReinhardEffect.hlsl,FilmicEffect.hlsl,SdrOverlayEffect.hlsl,LuminanceHeatmapEffect.hlsl</Inputs>
</CustomBuildStep>
<CustomBuildStep>
<TreatOutputAsContent>true</TreatOutputAsContent>
@ -368,10 +392,12 @@ fxc /T ps_5_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /se
<DependentUpon>DirectXPage.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="FilmicEffect.h" />
<ClInclude Include="LuminanceHeatmapEffect.h" />
<ClInclude Include="RenderOptions.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="D2DAdvancedColorImagesRenderer.h" />
<ClInclude Include="ReinhardEffect.h" />
<ClInclude Include="SdrOverlayEffect.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="App.xaml.cpp">
@ -383,6 +409,7 @@ fxc /T ps_5_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /se
<DependentUpon>DirectXPage.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="FilmicEffect.cpp" />
<ClCompile Include="LuminanceHeatmapEffect.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
@ -393,6 +420,7 @@ fxc /T ps_5_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /se
</ClCompile>
<ClCompile Include="D2DAdvancedColorImagesRenderer.cpp" />
<ClCompile Include="ReinhardEffect.cpp" />
<ClCompile Include="SdrOverlayEffect.cpp" />
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
@ -417,6 +445,16 @@ fxc /T ps_5_0 FilmicEffect.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=main /E main /se
<FileType>Document</FileType>
</Text>
</ItemGroup>
<ItemGroup>
<Text Include="SdrOverlayEffect.hlsl">
<FileType>Document</FileType>
</Text>
</ItemGroup>
<ItemGroup>
<Text Include="LuminanceHeatmapEffect.hlsl">
<FileType>Document</FileType>
</Text>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VSINSTALLDIR)\Common7\IDE\Extensions\Microsoft\VsGraphics\ImageContentTask.targets" />

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

@ -8,7 +8,7 @@
<Filter Include="Common">
<UniqueIdentifier>{a6fce137-2822-4f7a-8593-eff13050174b}</UniqueIdentifier>
</Filter>
<Filter Include="Tonemappers">
<Filter Include="RenderEffects">
<UniqueIdentifier>{2696d988-fd48-43de-b313-d0320f662368}</UniqueIdentifier>
</Filter>
</ItemGroup>
@ -27,10 +27,16 @@
</ClCompile>
<ClCompile Include="D2DAdvancedColorImagesRenderer.cpp" />
<ClCompile Include="ReinhardEffect.cpp">
<Filter>Tonemappers</Filter>
<Filter>RenderEffects</Filter>
</ClCompile>
<ClCompile Include="FilmicEffect.cpp">
<Filter>Tonemappers</Filter>
<Filter>RenderEffects</Filter>
</ClCompile>
<ClCompile Include="SdrOverlayEffect.cpp">
<Filter>RenderEffects</Filter>
</ClCompile>
<ClCompile Include="LuminanceHeatmapEffect.cpp">
<Filter>RenderEffects</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
@ -49,10 +55,16 @@
<ClInclude Include="D2DAdvancedColorImagesRenderer.h" />
<ClInclude Include="RenderOptions.h" />
<ClInclude Include="ReinhardEffect.h">
<Filter>Tonemappers</Filter>
<Filter>RenderEffects</Filter>
</ClInclude>
<ClInclude Include="FilmicEffect.h">
<Filter>Tonemappers</Filter>
<Filter>RenderEffects</Filter>
</ClInclude>
<ClInclude Include="SdrOverlayEffect.h">
<Filter>RenderEffects</Filter>
</ClInclude>
<ClInclude Include="LuminanceHeatmapEffect.h">
<Filter>RenderEffects</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
@ -80,10 +92,16 @@
</ItemGroup>
<ItemGroup>
<Text Include="ReinhardEffect.hlsl">
<Filter>Tonemappers</Filter>
<Filter>RenderEffects</Filter>
</Text>
<Text Include="FilmicEffect.hlsl">
<Filter>Tonemappers</Filter>
<Filter>RenderEffects</Filter>
</Text>
<Text Include="SdrOverlayEffect.hlsl">
<Filter>RenderEffects</Filter>
</Text>
<Text Include="LuminanceHeatmapEffect.hlsl">
<Filter>RenderEffects</Filter>
</Text>
</ItemGroup>
</Project>

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

@ -29,21 +29,28 @@ using namespace Windows::Storage::Streams;
using namespace Windows::UI::Input;
using namespace Windows::UI::Xaml;
static const float sc_MaxZoom = 1.0f; // Restrict max zoom to 1:1 scale.
static const unsigned int sc_MaxBytesPerPixel = 16; // Covers all supported image formats.
// 400 bins with gamma of 10 lets us measure luminance to within 10% error for any
// luminance above ~1.5 nits, up to 1 million nits.
static const unsigned int sc_histNumBins = 400;
static const float sc_histGamma = 0.1f;
static const unsigned int sc_histMaxNits = 1000000;
D2DAdvancedColorImagesRenderer::D2DAdvancedColorImagesRenderer(
const std::shared_ptr<DX::DeviceResources>& deviceResources,
IDisplayACStateChanged^ handler
const std::shared_ptr<DX::DeviceResources>& deviceResources
) :
m_deviceResources(deviceResources),
m_tonemapperKind(TonemapperKind::Disabled),
m_userDisabledScaling(false),
m_useTonemapping(true),
m_renderEffectKind(RenderEffectKind::None),
m_imageInfo{},
m_outputDesc{},
m_zoom(1.0f),
m_offset(),
m_imageColorSpace(DXGI_COLOR_SPACE_CUSTOM),
m_whiteLevelScale(1.0f),
m_dispStateChangeHandler(handler)
m_minZoom(1.0f), // Dynamically calculated on window size.
m_imageOffset(),
m_pointerPos(),
m_maxCLL(-1.0f),
m_brightnessAdjust(1.0f),
m_isComputeSupported(false)
{
// Register to be notified if the GPU device is lost or recreated.
m_deviceResources->RegisterDeviceNotify(this);
@ -61,7 +68,7 @@ D2DAdvancedColorImagesRenderer::~D2DAdvancedColorImagesRenderer()
void D2DAdvancedColorImagesRenderer::CreateDeviceIndependentResources()
{
// Register the custom tonemapper effects.
// Register the custom render effects.
DX::ThrowIfFailed(
ReinhardEffect::Register(m_deviceResources->GetD2DFactory())
);
@ -69,6 +76,14 @@ void D2DAdvancedColorImagesRenderer::CreateDeviceIndependentResources()
DX::ThrowIfFailed(
FilmicEffect::Register(m_deviceResources->GetD2DFactory())
);
DX::ThrowIfFailed(
SdrOverlayEffect::Register(m_deviceResources->GetD2DFactory())
);
DX::ThrowIfFailed(
LuminanceHeatmapEffect::Register(m_deviceResources->GetD2DFactory())
);
}
void D2DAdvancedColorImagesRenderer::CreateDeviceDependentResources()
@ -87,43 +102,72 @@ void D2DAdvancedColorImagesRenderer::ReleaseDeviceDependentResources()
void D2DAdvancedColorImagesRenderer::CreateWindowSizeDependentResources()
{
FitImageToWindow();
UpdateAdvancedColorState();
}
// White level scale is used to multiply the color values in the image; allows the user to
// adjust the brightness of the image on an HDR display.
void D2DAdvancedColorImagesRenderer::SetRenderOptions(
bool disableScaling,
TonemapperKind tonemapper,
float whiteLevelScale,
DXGI_COLOR_SPACE_TYPE colorspace
RenderEffectKind effect,
float brightnessAdjustment,
AdvancedColorInfo^ acInfo
)
{
m_userDisabledScaling = disableScaling;
FitImageToWindow();
m_dispInfo = acInfo;
m_renderEffectKind = effect;
m_brightnessAdjust = brightnessAdjustment;
m_tonemapperKind = tonemapper;
UpdateAdvancedColorState();
UpdateWhiteLevelScale(m_brightnessAdjust, m_dispInfo->SdrWhiteLevelInNits);
m_imageColorSpace = colorspace;
UpdateImageColorContext();
// Adjust the Direct2D effect graph based on RenderEffectKind.
// Some RenderEffectKind values require us to apply brightness adjustment
// after the effect as their numerical output is affected by any luminance boost.
switch (m_renderEffectKind)
{
// Effect graph: ImageSource > ColorManagement > WhiteScale > Reinhard
case RenderEffectKind::ReinhardTonemap:
m_finalOutput = m_reinhardEffect.Get();
m_whiteScaleEffect->SetInputEffect(0, m_colorManagementEffect.Get());
break;
// Image colorspace can affect white level scale, so call this last.
m_whiteLevelScale = whiteLevelScale;
UpdateWhiteLevelScale();
// Effect graph: ImageSource > ColorManagement > WhiteScale > FilmicTonemap
case RenderEffectKind::FilmicTonemap:
m_finalOutput = m_filmicEffect.Get();
m_whiteScaleEffect->SetInputEffect(0, m_colorManagementEffect.Get());
break;
// Effect graph: ImageSource > ColorManagement > WhiteScale
case RenderEffectKind::None:
m_finalOutput = m_whiteScaleEffect.Get();
m_whiteScaleEffect->SetInputEffect(0, m_colorManagementEffect.Get());
break;
// Effect graph: ImageSource > ColorManagement > Heatmap > WhiteScale
case RenderEffectKind::LuminanceHeatmap:
m_finalOutput = m_whiteScaleEffect.Get();
m_whiteScaleEffect->SetInputEffect(0, m_heatmapEffect.Get());
break;
// Effect graph: ImageSource > ColorManagement > SdrOverlay > WhiteScale
case RenderEffectKind::SdrOverlay:
m_finalOutput = m_whiteScaleEffect.Get();
m_whiteScaleEffect->SetInputEffect(0, m_sdrOverlayEffect.Get());
break;
default:
throw ref new NotImplementedException();
break;
}
Draw();
}
// Reads the provided data stream and decodes an image from it. Retrieves the
// ICC color profile attached to that image, if any. These resources are device-
// Reads the provided data stream and decodes an image from it using WIC. These resources are device-
// independent.
ImageInfo D2DAdvancedColorImagesRenderer::LoadImage(_In_ IStream* imageStream)
ImageInfo D2DAdvancedColorImagesRenderer::LoadImageFromWic(_In_ IStream* imageStream)
{
auto wicFactory = m_deviceResources->GetWicImagingFactory();
// First, decode the provided image.
// Decode the image using WIC.
ComPtr<IWICBitmapDecoder> decoder;
DX::ThrowIfFailed(
wicFactory->CreateDecoderFromStream(
@ -131,98 +175,44 @@ ImageInfo D2DAdvancedColorImagesRenderer::LoadImage(_In_ IStream* imageStream)
nullptr,
WICDecodeMetadataCacheOnDemand,
&decoder
)
);
));
ComPtr<IWICBitmapFrameDecode> frame;
DX::ThrowIfFailed(
decoder->GetFrame(0, &frame)
);
// Check whether the image data is natively stored in a floating-point format, and
// decode to the appropriate WIC pixel format.
return LoadImageCommon(frame.Get());
}
WICPixelFormatGUID pixelFormat;
DX::ThrowIfFailed(
frame->GetPixelFormat(&pixelFormat)
);
ComPtr<IWICComponentInfo> componentInfo;
DX::ThrowIfFailed(
wicFactory->CreateComponentInfo(
pixelFormat,
&componentInfo
)
);
ComPtr<IWICPixelFormatInfo2> pixelFormatInfo;
DX::ThrowIfFailed(
componentInfo.As(&pixelFormatInfo)
);
WICPixelFormatNumericRepresentation formatNumber;
DX::ThrowIfFailed(
pixelFormatInfo->GetNumericRepresentation(&formatNumber)
);
DX::ThrowIfFailed(pixelFormatInfo->GetBitsPerPixel(&m_imageInfo.bitsPerPixel));
m_imageInfo.isFloat = (WICPixelFormatNumericRepresentationFloat == formatNumber) ? true : false;
// When decoding, preserve the numeric representation (float vs. non-float)
// of the native image data. This avoids WIC performing an implicit gamma conversion
// which occurs when converting between a fixed-point/integer pixel format (sRGB gamma)
// and a float-point pixel format (linear gamma). Gamma adjustment, if specified by
// the ICC profile, will be performed by the Direct2D color management effect.
WICPixelFormatGUID fmt = {};
if (m_imageInfo.isFloat)
// Simplified heuristic to determine what advanced color kind the image is.
// Requires that all fields other than imageKind are populated.
void D2DAdvancedColorImagesRenderer::PopulateImageInfoACKind(_Inout_ ImageInfo* info)
{
if (info->bitsPerPixel == 0 ||
info->bitsPerChannel == 0 ||
info->size.Width == 0 ||
info->size.Height == 0)
{
fmt = GUID_WICPixelFormat64bppPRGBAHalf; // Equivalent to DXGI_FORMAT_R16G16B16A16_FLOAT.
}
else
{
fmt = GUID_WICPixelFormat64bppPRGBA; // Equivalent to DXGI_FORMAT_R16G16B16A16_UNORM.
// Many SDR images (e.g. JPEG) use <=32bpp, so it
// is possible to further optimize this for memory usage.
DX::ThrowIfFailed(E_INVALIDARG);
}
DX::ThrowIfFailed(
wicFactory->CreateFormatConverter(&m_formatConvert)
);
info->imageKind = AdvancedColorKind::StandardDynamicRange;
DX::ThrowIfFailed(
m_formatConvert->Initialize(
frame.Get(),
fmt,
WICBitmapDitherTypeNone,
nullptr,
0.0f,
WICBitmapPaletteTypeCustom
)
);
// Bit depth > 8bpc or color gamut > sRGB signifies a WCG image.
// The presence of a color profile is used as an approximation for wide gamut.
if (info->bitsPerChannel > 8 || info->numProfiles >= 1)
{
info->imageKind = AdvancedColorKind::WideColorGamut;
}
UINT width;
UINT height;
DX::ThrowIfFailed(
m_formatConvert->GetSize(&width, &height)
);
m_imageInfo.size = Size(static_cast<float>(width), static_cast<float>(height));
// Attempt to read the embedded color profile from the image.
DX::ThrowIfFailed(
wicFactory->CreateColorContext(&m_wicColorContext)
);
DX::ThrowIfFailed(
frame->GetColorContexts(
1,
m_wicColorContext.GetAddressOf(),
&m_imageInfo.numProfiles
)
);
return m_imageInfo;
// This application currently only natively supports HDR images with floating point.
// An image encoded using the HDR10 colorspace is also HDR, but this
// is not automatically detected by the application.
if (info->isFloat == true)
{
info->imageKind = AdvancedColorKind::HighDynamicRange;
}
}
// Configures a Direct2D image pipeline, including source, color management,
@ -279,12 +269,13 @@ void D2DAdvancedColorImagesRenderer::CreateImageDependentResources()
// to adjust the brightness of the image on an HDR display.
DX::ThrowIfFailed(context->CreateEffect(CLSID_D2D1ColorMatrix, &m_whiteScaleEffect));
// Input to white level scale may be modified in SetRenderOptions.
m_whiteScaleEffect->SetInputEffect(0, m_colorManagementEffect.Get());
// Set the actual matrix in SetRenderOptions.
// Instantiate and cache all of the tonemapping effects. Selection is performed in Draw().
// Each tonemapper is implemented as a Direct2D custom effect; see the Tonemappers filter in the
// Instantiate and cache all of the tonemapping/render effects.
// Each effect is implemented as a Direct2D custom effect; see the RenderEffects filter in the
// Solution Explorer.
DX::ThrowIfFailed(
context->CreateEffect(CLSID_CustomReinhardEffect, &m_reinhardEffect)
@ -294,8 +285,109 @@ void D2DAdvancedColorImagesRenderer::CreateImageDependentResources()
context->CreateEffect(CLSID_CustomFilmicEffect, &m_filmicEffect)
);
DX::ThrowIfFailed(
context->CreateEffect(CLSID_CustomSdrOverlayEffect, &m_sdrOverlayEffect)
);
DX::ThrowIfFailed(
context->CreateEffect(CLSID_CustomLuminanceHeatmapEffect, &m_heatmapEffect)
);
m_reinhardEffect->SetInputEffect(0, m_whiteScaleEffect.Get());
m_filmicEffect->SetInputEffect(0, m_whiteScaleEffect.Get());
// For the following effects, we want white level scale to be applied after
// tonemapping (otherwise brightness adjustments will affect numerical values).
m_heatmapEffect->SetInputEffect(0, m_colorManagementEffect.Get());
m_sdrOverlayEffect->SetInputEffect(0, m_colorManagementEffect.Get());
// The remainder of the Direct2D effect graph is constructed in SetRenderOptions based on the
// selected RenderEffectKind.
CreateHistogramResources();
}
// Perform histogram pipeline setup; this should occur as part of image resource creation.
// Histogram results in no visual output but is used to calculate HDR metadata for the image.
void D2DAdvancedColorImagesRenderer::CreateHistogramResources()
{
auto context = m_deviceResources->GetD2DDeviceContext();
// We need to preprocess the image data before running the histogram.
// 1. Spatial downscale to reduce the amount of processing needed.
DX::ThrowIfFailed(
context->CreateEffect(CLSID_D2D1Scale, &m_histogramPrescale)
);
DX::ThrowIfFailed(
m_histogramPrescale->SetValue(D2D1_SCALE_PROP_SCALE, D2D1::Vector2F(0.5f, 0.5f))
);
// The right place to compute HDR metadata is after color management to the
// image's native colorspace but before any tonemapping or adjustments for the display.
m_histogramPrescale->SetInputEffect(0, m_colorManagementEffect.Get());
// 2. Convert scRGB data into luminance (nits).
// 3. Normalize color values. Histogram operates on [0-1] numeric range,
// while FP16 can go up to 65504 (5+ million nits).
// Both steps are performed in the same color matrix.
ComPtr<ID2D1Effect> histogramMatrix;
DX::ThrowIfFailed(
context->CreateEffect(CLSID_D2D1ColorMatrix, &histogramMatrix)
);
histogramMatrix->SetInputEffect(0, m_histogramPrescale.Get());
float scale = sc_histMaxNits / 80.0f; // scRGB 1.0 is defined as 80 nits.
D2D1_MATRIX_5X4_F rgbtoYnorm = D2D1::Matrix5x4F(
0.2126f / scale, 0, 0, 0,
0.7152f / scale, 0, 0, 0,
0.0722f / scale, 0, 0, 0,
0 , 0, 0, 1,
0 , 0, 0, 0);
// 1st column: [R] output, contains normalized Y (CIEXYZ).
// 2nd column: [G] output, unused.
// 3rd column: [B] output, unused.
// 4th column: [A] output, alpha passthrough.
// We explicitly calculate Y; this deviates from the CEA 861.3 definition of MaxCLL
// which approximates luminance with max(R, G, B).
DX::ThrowIfFailed(histogramMatrix->SetValue(D2D1_COLORMATRIX_PROP_COLOR_MATRIX, rgbtoYnorm));
// 4. Apply a gamma to allocate more histogram bins to lower luminance levels.
ComPtr<ID2D1Effect> histogramGamma;
DX::ThrowIfFailed(
context->CreateEffect(CLSID_D2D1GammaTransfer, &histogramGamma)
);
histogramGamma->SetInputEffect(0, histogramMatrix.Get());
// Gamma function offers an acceptable tradeoff between simplicity and efficient bin allocation.
// A more sophisticated pipeline would use a more perceptually linear function than gamma.
DX::ThrowIfFailed(histogramGamma->SetValue(D2D1_GAMMATRANSFER_PROP_RED_EXPONENT, sc_histGamma));
// All other channels are passthrough.
DX::ThrowIfFailed(histogramGamma->SetValue(D2D1_GAMMATRANSFER_PROP_GREEN_DISABLE, TRUE));
DX::ThrowIfFailed(histogramGamma->SetValue(D2D1_GAMMATRANSFER_PROP_BLUE_DISABLE, TRUE));
DX::ThrowIfFailed(histogramGamma->SetValue(D2D1_GAMMATRANSFER_PROP_ALPHA_DISABLE, TRUE));
// 5. Finally, the histogram itself.
HRESULT hr = context->CreateEffect(CLSID_D2D1Histogram, &m_histogramEffect);
if (hr == D2DERR_INSUFFICIENT_DEVICE_CAPABILITIES)
{
// The GPU doesn't support compute shaders and we can't run histogram on it.
m_isComputeSupported = false;
}
else
{
DX::ThrowIfFailed(hr);
m_isComputeSupported = true;
DX::ThrowIfFailed(m_histogramEffect->SetValue(D2D1_HISTOGRAM_PROP_NUM_BINS, sc_histNumBins));
m_histogramEffect->SetInputEffect(0, histogramGamma.Get());
}
}
void D2DAdvancedColorImagesRenderer::ReleaseImageDependentResources()
@ -306,40 +398,287 @@ void D2DAdvancedColorImagesRenderer::ReleaseImageDependentResources()
m_whiteScaleEffect.Reset();
m_reinhardEffect.Reset();
m_filmicEffect.Reset();
m_sdrOverlayEffect.Reset();
m_heatmapEffect.Reset();
m_histogramPrescale.Reset();
m_histogramEffect.Reset();
m_finalOutput.Reset();
}
// Update zoom state to keep the image fit to the app window.
void D2DAdvancedColorImagesRenderer::FitImageToWindow()
void D2DAdvancedColorImagesRenderer::UpdateManipulationState(_In_ ManipulationUpdatedEventArgs^ args)
{
Point position = args->Position;
Point positionDelta = args->Delta.Translation;
float zoomDelta = args->Delta.Scale;
m_imageOffset.x += positionDelta.X;
m_imageOffset.y += positionDelta.Y;
// We want to have any zoom operation be "centered" around the pointer position, which
// requires recalculating the view position based on the new zoom and pointer position.
// Step 1: Calculate the absolute pointer position (image position).
D2D1_POINT_2F pointerAbsolutePosition = D2D1::Point2F(
(m_imageOffset.x - position.X) / m_zoom,
(m_imageOffset.y - position.Y) / m_zoom
);
// Step 2: Apply the zoom; do not allow user to go beyond max zoom level.
m_zoom *= zoomDelta;
m_zoom = min(m_zoom, sc_MaxZoom);
// Step 3: Adjust the view position based on the new m_zoom value.
m_imageOffset.x = pointerAbsolutePosition.x * m_zoom + position.X;
m_imageOffset.y = pointerAbsolutePosition.y * m_zoom + position.Y;
// Step 4: Clamp the translation to the window bounds.
Size panelSize = m_deviceResources->GetLogicalSize();
m_imageOffset.x = Clamp(m_imageOffset.x, panelSize.Width - m_imageInfo.size.Width * m_zoom, 0);
m_imageOffset.y = Clamp(m_imageOffset.y, panelSize.Height - m_imageInfo.size.Height * m_zoom, 0);
UpdateImageTransformState();
Draw();
}
// Overrides any pan/zoom state set by the user to fit image to the window size.
// Returns the computed MaxCLL of the image in nits.
float D2DAdvancedColorImagesRenderer::FitImageToWindow()
{
if (m_imageSource)
{
Size panelSize = m_deviceResources->GetLogicalSize();
// Letterbox but never exceed max scale.
m_zoom = min(
min(
panelSize.Width / m_imageInfo.size.Width,
panelSize.Height / m_imageInfo.size.Height
),
1.0f
// Set image to be letterboxed in the window, up to the max allowed scale factor.
float letterboxZoom = min(
panelSize.Width / m_imageInfo.size.Width,
panelSize.Height / m_imageInfo.size.Height);
m_zoom = min(sc_MaxZoom, letterboxZoom);
// Center the image.
m_imageOffset = D2D1::Point2F(
(panelSize.Width - (m_imageInfo.size.Width * m_zoom)) / 2.0f,
(panelSize.Height - (m_imageInfo.size.Height * m_zoom)) / 2.0f
);
// User can disable spatial scaling.
m_zoom = m_userDisabledScaling ? 1.0f : m_zoom;
UpdateImageTransformState();
if (m_userDisabledScaling)
{
m_offset = {};
}
else
{
// Center the image.
m_offset = D2D1::Point2F(
(panelSize.Width - (m_imageInfo.size.Width * m_zoom)) / 2.0f,
(panelSize.Height - (m_imageInfo.size.Height * m_zoom)) / 2.0f
);
}
// HDR metadata is supposed to be independent of any rendering options, but
// we can't compute it until the full effect graph is hooked up, which is here.
ComputeHdrMetadata();
}
return m_maxCLL;
}
// After initial decode, obtain image information and do common setup.
// Populates all members of ImageInfo.
ImageInfo D2DAdvancedColorImagesRenderer::LoadImageCommon(_In_ IWICBitmapSource* source)
{
auto wicFactory = m_deviceResources->GetWicImagingFactory();
m_imageInfo = {};
// Attempt to read the embedded color profile from the image; only valid for WIC images.
ComPtr<IWICBitmapFrameDecode> frame;
if (SUCCEEDED(source->QueryInterface(IID_PPV_ARGS(&frame))))
{
DX::ThrowIfFailed(
wicFactory->CreateColorContext(&m_wicColorContext)
);
DX::ThrowIfFailed(
frame->GetColorContexts(
1,
m_wicColorContext.GetAddressOf(),
&m_imageInfo.numProfiles
)
);
}
// Check whether the image data is natively stored in a floating-point format, and
// decode to the appropriate WIC pixel format.
WICPixelFormatGUID pixelFormat;
DX::ThrowIfFailed(
source->GetPixelFormat(&pixelFormat)
);
ComPtr<IWICComponentInfo> componentInfo;
DX::ThrowIfFailed(
wicFactory->CreateComponentInfo(
pixelFormat,
&componentInfo
)
);
ComPtr<IWICPixelFormatInfo2> pixelFormatInfo;
DX::ThrowIfFailed(
componentInfo.As(&pixelFormatInfo)
);
WICPixelFormatNumericRepresentation formatNumber;
DX::ThrowIfFailed(
pixelFormatInfo->GetNumericRepresentation(&formatNumber)
);
DX::ThrowIfFailed(pixelFormatInfo->GetBitsPerPixel(&m_imageInfo.bitsPerPixel));
// Calculate the bits per channel (bit depth) using GetChannelMask.
// This accounts for nonstandard color channel packing and padding, e.g. 32bppRGB.
unsigned char channelMaskBytes[sc_MaxBytesPerPixel];
ZeroMemory(channelMaskBytes, ARRAYSIZE(channelMaskBytes));
unsigned int maskSize;
DX::ThrowIfFailed(
pixelFormatInfo->GetChannelMask(
0, // Read the first color channel.
ARRAYSIZE(channelMaskBytes),
channelMaskBytes,
&maskSize)
);
// Count up the number of bits set in the mask for the first color channel.
for (unsigned int i = 0; i < maskSize * 8; i++)
{
unsigned int byte = i / 8;
unsigned int bit = i % 8;
if ((channelMaskBytes[byte] & (1 << bit)) != 0)
{
m_imageInfo.bitsPerChannel += 1;
}
}
m_imageInfo.isFloat = (WICPixelFormatNumericRepresentationFloat == formatNumber) ? true : false;
// When decoding, preserve the numeric representation (float vs. non-float)
// of the native image data. This avoids WIC performing an implicit gamma conversion
// which occurs when converting between a fixed-point/integer pixel format (sRGB gamma)
// and a float-point pixel format (linear gamma). Gamma adjustment, if specified by
// the ICC profile, will be performed by the Direct2D color management effect.
WICPixelFormatGUID fmt = {};
if (m_imageInfo.isFloat)
{
fmt = GUID_WICPixelFormat64bppPRGBAHalf; // Equivalent to DXGI_FORMAT_R16G16B16A16_FLOAT.
}
else
{
fmt = GUID_WICPixelFormat64bppPRGBA; // Equivalent to DXGI_FORMAT_R16G16B16A16_UNORM.
// Many SDR images (e.g. JPEG) use <=32bpp, so it
// is possible to further optimize this for memory usage.
}
DX::ThrowIfFailed(
wicFactory->CreateFormatConverter(&m_formatConvert)
);
DX::ThrowIfFailed(
m_formatConvert->Initialize(
source,
fmt,
WICBitmapDitherTypeNone,
nullptr,
0.0f,
WICBitmapPaletteTypeCustom
)
);
UINT width;
UINT height;
DX::ThrowIfFailed(
m_formatConvert->GetSize(&width, &height)
);
m_imageInfo.size = Size(static_cast<float>(width), static_cast<float>(height));
PopulateImageInfoACKind(&m_imageInfo);
return m_imageInfo;
}
// Derive the source color context from the image (embedded ICC profile or metadata).
void D2DAdvancedColorImagesRenderer::UpdateImageColorContext()
{
auto context = m_deviceResources->GetD2DDeviceContext();
ComPtr<ID2D1ColorContext> sourceColorContext;
// For most image types, automatically derive the color context from the image.
if (m_imageInfo.numProfiles >= 1)
{
DX::ThrowIfFailed(
context->CreateColorContextFromWicColorContext(
m_wicColorContext.Get(),
&sourceColorContext
)
);
}
else
{
// Since no embedded color profile/metadata exists, select a default
// based on the pixel format: floating point == scRGB, others == sRGB.
DX::ThrowIfFailed(
context->CreateColorContext(
m_imageInfo.isFloat ? D2D1_COLOR_SPACE_SCRGB : D2D1_COLOR_SPACE_SRGB,
nullptr,
0,
&sourceColorContext
)
);
}
DX::ThrowIfFailed(
m_colorManagementEffect->SetValue(
D2D1_COLORMANAGEMENT_PROP_SOURCE_COLOR_CONTEXT,
sourceColorContext.Get()
)
);
}
// When connected to an HDR display, the OS renders SDR content (e.g. 8888 UNORM) at
// a user configurable white level; this typically is around 200-300 nits. It is the responsibility
// of an advanced color app (e.g. FP16 scRGB) to emulate the OS-implemented SDR white level adjustment,
// BUT only for non-HDR content (SDR or WCG).
void D2DAdvancedColorImagesRenderer::UpdateWhiteLevelScale(float brightnessAdjustment, float sdrWhiteLevel)
{
float scale = 1.0f;
switch (m_imageInfo.imageKind)
{
case AdvancedColorKind::HighDynamicRange:
// HDR content should not be compensated by the SdrWhiteLevel parameter.
scale = 1.0f;
break;
case AdvancedColorKind::StandardDynamicRange:
case AdvancedColorKind::WideColorGamut:
default:
// Nominal reference white of sRGB is 80 nits.
scale = sdrWhiteLevel / 80.0f;
break;
}
// The user may want to manually adjust brightness specifically for this image, on top of any
// white level adjustment for SDR/WCG content. Brightness adjustment using a linear gamma scale
// is mainly useful for HDR displays, but can be useful for HDR content tonemapped to an SDR/WCG display.
scale *= brightnessAdjustment;
// SDR white level scaling is performing by multiplying RGB color values in linear gamma.
// We implement this with a Direct2D matrix effect.
D2D1_MATRIX_5X4_F matrix = D2D1::Matrix5x4F(
scale, 0, 0, 0, // [R] Multiply each color channel
0, scale, 0, 0, // [G] by the scale factor in
0, 0, scale, 0, // [B] linear gamma space.
0, 0, 0 , 1, // [A] Preserve alpha values.
0, 0, 0 , 0); // No offset.
DX::ThrowIfFailed(m_whiteScaleEffect->SetValue(D2D1_COLORMATRIX_PROP_COLOR_MATRIX, matrix));
}
// Call this after updating any spatial transform state to regenerate the effect graph.
void D2DAdvancedColorImagesRenderer::UpdateImageTransformState()
{
if (m_imageSource)
{
// When using ID2D1ImageSource, the recommend method of scaling is to use
// ID2D1TransformedImageSource. It is inexpensive to recreate this object.
D2D1_TRANSFORMED_IMAGE_SOURCE_PROPERTIES props =
@ -364,141 +703,115 @@ void D2DAdvancedColorImagesRenderer::FitImageToWindow()
}
}
// Uses DXGI APIs to query the capabilities of the app's current display, and
// enables HDR-to-SDR tone mapping if the display does not meet a particular
// brightness threshold or is not in advanced color mode.
void D2DAdvancedColorImagesRenderer::UpdateAdvancedColorState()
// Uses a histogram to compute a modified version of MaxCLL (ST.2086 max content light level).
// Performs Begin/EndDraw on the D2D context.
void D2DAdvancedColorImagesRenderer::ComputeHdrMetadata()
{
m_outputDesc = m_deviceResources->GetCurrentOutputDesc1();
// Initialize with a sentinel value.
m_maxCLL = -1.0f;
// Tonemapping is only needed on low dynamic range displays; the user can also force it off.
if (m_tonemapperKind == TonemapperKind::Disabled ||
GetDisplayACKind() == DisplayACKind::AdvancedColor_HighDynamicRange)
if (!m_isComputeSupported)
{
m_useTonemapping = false;
}
else
{
m_useTonemapping = true;
return;
}
if (m_dispStateChangeHandler)
// MaxCLL is nominally calculated for the single brightest pixel in a frame.
// But we take a slightly more conservative definition that takes the 99.99th percentile
// to account for extreme outliers in the image.
float maxCLLPercent = 0.9999f;
auto ctx = m_deviceResources->GetD2DDeviceContext();
if (m_imageInfo.imageKind == AdvancedColorKind::HighDynamicRange)
{
m_dispStateChangeHandler->OnDisplayACStateChanged(
m_outputDesc.MaxLuminance,
m_outputDesc.BitsPerColor,
GetDisplayACKind()
);
}
}
ctx->BeginDraw();
// Based on the user's choice, either derive the source color context from the image
// (embedded ICC profile or metadata), or create a context using the user's specified colorspace.
void D2DAdvancedColorImagesRenderer::UpdateImageColorContext()
{
auto context = m_deviceResources->GetD2DDeviceContext();
ctx->DrawImage(m_histogramEffect.Get());
ComPtr<ID2D1ColorContext> sourceColorContext;
if (m_imageColorSpace == DXGI_COLOR_SPACE_CUSTOM)
{
// Derive the color context from the image.
if (m_imageInfo.numProfiles >= 1)
// We ignore D2DERR_RECREATE_TARGET here. This error indicates that the device
// is lost. It will be handled during the next call to Present.
HRESULT hr = ctx->EndDraw();
if (hr != D2DERR_RECREATE_TARGET)
{
DX::ThrowIfFailed(
context->CreateColorContextFromWicColorContext(
m_wicColorContext.Get(),
&sourceColorContext
)
);
DX::ThrowIfFailed(hr);
}
else
{
// Since no embedded color profile/metadata exists, select a default
// based on the pixel format: floating point == scRGB, others == sRGB.
DX::ThrowIfFailed(
context->CreateColorContext(
m_imageInfo.isFloat ? D2D1_COLOR_SPACE_SCRGB : D2D1_COLOR_SPACE_SRGB,
nullptr,
0,
&sourceColorContext
)
);
}
}
else
{
// Use the user's explicitly defined colorspace.
ComPtr<ID2D1ColorContext1> colorContext1;
float *histogramData = new float[sc_histNumBins];
DX::ThrowIfFailed(
context->CreateColorContextFromDxgiColorSpace(m_imageColorSpace, &colorContext1)
m_histogramEffect->GetValue(D2D1_HISTOGRAM_PROP_HISTOGRAM_OUTPUT,
reinterpret_cast<BYTE*>(histogramData),
sc_histNumBins * sizeof(float)
)
);
DX::ThrowIfFailed(colorContext1.As(&sourceColorContext));
}
unsigned int maxCLLbin = 0;
float runningSum = 0.0f; // Cumulative sum of values in histogram is 1.0.
for (int i = sc_histNumBins - 1; i >= 0; i--)
{
runningSum += histogramData[i];
maxCLLbin = i;
DX::ThrowIfFailed(
m_colorManagementEffect->SetValue(
D2D1_COLORMANAGEMENT_PROP_SOURCE_COLOR_CONTEXT,
sourceColorContext.Get()
)
);
if (runningSum >= 1.0f - maxCLLPercent)
{
break;
}
}
float binNorm = static_cast<float>(maxCLLbin + 1) / static_cast<float>(sc_histNumBins);
m_maxCLL = powf(binNorm, 1 / sc_histGamma) * sc_histMaxNits;
}
else
{
// MaxCLL is not meaningful for SDR or WCG images.
}
}
void D2DAdvancedColorImagesRenderer::UpdateWhiteLevelScale()
// Set HDR10 metadata to allow HDR displays to optimize behavior based on our content.
void D2DAdvancedColorImagesRenderer::EmitHdrMetadata()
{
// If we are viewing an HDR10-encoded image and are using an HDR display,
// we need to map the [0, 1] range of the image pixels to [0, 10000] nits
// of the SMPTE.2084 EOTF. We render in scRGB, which defines 1.0 reference white
// as 80 nits; therefore, we must scale up by 125x (10000 / 80).
switch (m_imageColorSpace)
if (m_dispInfo->CurrentAdvancedColorKind == AdvancedColorKind::HighDynamicRange)
{
case DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020:
case DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020:
if (GetDisplayACKind() == DisplayACKind::AdvancedColor_HighDynamicRange)
DXGI_HDR_METADATA_HDR10 metadata = {};
// This sample doesn't do any chrominance (e.g. xy) gamut mapping, so just use default
// color primaries values; a more sophisticated app will explicitly set these.
// DXGI_HDR_METADATA_HDR10 defines primaries as 1/50000 of a unit in xy space.
metadata.RedPrimary[0] = static_cast<UINT16>(m_dispInfo->RedPrimary.X * 50000.0f);
metadata.RedPrimary[1] = static_cast<UINT16>(m_dispInfo->RedPrimary.Y * 50000.0f);
metadata.GreenPrimary[0] = static_cast<UINT16>(m_dispInfo->GreenPrimary.X * 50000.0f);
metadata.GreenPrimary[1] = static_cast<UINT16>(m_dispInfo->GreenPrimary.Y * 50000.0f);
metadata.BluePrimary[0] = static_cast<UINT16>(m_dispInfo->BluePrimary.X * 50000.0f);
metadata.BluePrimary[1] = static_cast<UINT16>(m_dispInfo->BluePrimary.Y * 50000.0f);
metadata.WhitePoint[0] = static_cast<UINT16>(m_dispInfo->WhitePoint.X * 50000.0f);
metadata.WhitePoint[1] = static_cast<UINT16>(m_dispInfo->WhitePoint.Y * 50000.0f);
float effectiveMaxCLL = 0;
switch (m_renderEffectKind)
{
m_whiteLevelScale = 125.0f;
// Currently only the "None" render effect results in pixel values that exceed
// the OS-specified SDR white level, as it just passes through HDR color values.
case RenderEffectKind::None:
effectiveMaxCLL = max(m_maxCLL, 0.0f) * m_brightnessAdjust;
break;
default:
effectiveMaxCLL = m_dispInfo->SdrWhiteLevelInNits * m_brightnessAdjust;
break;
}
break;
}
D2D1_MATRIX_5X4_F matrix = D2D1::Matrix5x4F(
m_whiteLevelScale, 0, 0, 0, // [R] Multiply each color channel
0, m_whiteLevelScale, 0, 0, // [G] by the scale factor in
0, 0, m_whiteLevelScale, 0, // [B] linear gamma space.
0, 0, 0 , 1, // [A] Preserve alpha values.
0, 0, 0 , 0); // No offset.
DX::ThrowIfFailed(m_whiteScaleEffect->SetValue(D2D1_COLORMATRIX_PROP_COLOR_MATRIX, matrix));
}
// DXGI_HDR_METADATA_HDR10 defines MaxCLL in integer nits.
metadata.MaxContentLightLevel = static_cast<UINT16>(effectiveMaxCLL);
// Determines what class of advanced color capabilities the current display has.
DisplayACKind D2DAdvancedColorImagesRenderer::GetDisplayACKind()
{
switch (m_outputDesc.ColorSpace)
{
case DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709:
return DisplayACKind::NotAdvancedColor;
break;
// The luminance analysis doesn't calculate MaxFrameAverageLightLevel. We also don't have mastering
// information (i.e. reference display in a studio), so Min/MaxMasteringLuminance is not relevant.
// Leave these values as 0.
case DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020:
// 300 nits is considered the cutoff between an HDR and LDR display.
// HDR displays support overbright, i.e. colors brighter than reference white.
// LDR displays are limited to the [0, 1] luminance range.
if (m_outputDesc.MaxLuminance < 300.0f)
{
return DisplayACKind::AdvancedColor_LowDynamicRange;
}
else
{
return DisplayACKind::AdvancedColor_HighDynamicRange;
}
break;
auto sc = m_deviceResources->GetSwapChain();
default:
// DXGI_OUTPUT_DESC1 should only contain one of the above values.
return DisplayACKind::NotAdvancedColor;
break;
ComPtr<IDXGISwapChain4> sc4;
DX::ThrowIfFailed(sc->QueryInterface(IID_PPV_ARGS(&sc4)));
DX::ThrowIfFailed(sc4->SetHDRMetaData(DXGI_HDR_METADATA_TYPE_HDR10, sizeof(metadata), &metadata));
}
}
@ -515,29 +828,9 @@ void D2DAdvancedColorImagesRenderer::Draw()
if (m_scaledImage)
{
if (m_useTonemapping)
{
// Draw the full effect pipeline including the HDR tonemapper.
ComPtr<ID2D1Effect> tonemapper;
switch (m_tonemapperKind)
{
case TonemapperKind::Reinhard:
tonemapper = m_reinhardEffect.Get();
break;
d2dContext->DrawImage(m_finalOutput.Get(), m_imageOffset);
case TonemapperKind::Filmic:
default:
tonemapper = m_filmicEffect.Get();
break;
}
d2dContext->DrawImage(tonemapper.Get(), m_offset);
}
else
{
// Omit the tone mapping effect and just draw the color-managed, scaled image.
d2dContext->DrawImage(m_whiteScaleEffect.Get(), m_offset);
}
EmitHdrMetadata();
}
// We ignore D2DERR_RECREATE_TARGET here. This error indicates that the device
@ -566,4 +859,4 @@ void D2DAdvancedColorImagesRenderer::OnDeviceRestored()
CreateWindowSizeDependentResources();
Draw();
}
}

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

@ -14,73 +14,74 @@
#include "DeviceResources.h"
#include "ReinhardEffect.h"
#include "FilmicEffect.h"
#include "SdrOverlayEffect.h"
#include "LuminanceHeatmapEffect.h"
#include "RenderOptions.h"
namespace D2DAdvancedColorImages
{
public enum class DisplayACKind
{
NotAdvancedColor, // No AC capabilities: dynamic range, color gamut, bit depth
AdvancedColor_LowDynamicRange, // Wide color gamut, high bit depth, but low dynamic range
AdvancedColor_HighDynamicRange // Full high dynamic range, wide color gamut, high bit depth
};
struct ImageInfo
{
unsigned int bitsPerPixel;
bool isFloat;
Windows::Foundation::Size size;
unsigned int numProfiles;
};
// Provides an interface for an application to be notified of changes in the display's
// advanced color state.
public interface class IDisplayACStateChanged
{
virtual void OnDisplayACStateChanged(
float maxLuminance,
unsigned int bitDepth,
DisplayACKind displayKind) = 0;
unsigned int bitsPerPixel;
unsigned int bitsPerChannel;
bool isFloat;
Windows::Foundation::Size size;
unsigned int numProfiles;
Windows::Graphics::Display::AdvancedColorKind imageKind;
};
class D2DAdvancedColorImagesRenderer : public DX::IDeviceNotify
{
public:
D2DAdvancedColorImagesRenderer(
const std::shared_ptr<DX::DeviceResources>& deviceResources,
IDisplayACStateChanged^ handler
);
D2DAdvancedColorImagesRenderer(const std::shared_ptr<DX::DeviceResources>& deviceResources);
~D2DAdvancedColorImagesRenderer();
void CreateDeviceIndependentResources();
void CreateDeviceDependentResources();
void CreateWindowSizeDependentResources();
void ReleaseDeviceDependentResources();
void Draw();
void CreateImageDependentResources();
void ReleaseImageDependentResources();
void FitImageToWindow();
void UpdateManipulationState(_In_ Windows::UI::Input::ManipulationUpdatedEventArgs^ args);
// Returns the computed MaxCLL of the image in nits. While HDR metadata is a
// property of the image (and independent of rendering), our implementation
// can't compute it until this point.
float FitImageToWindow();
void SetRenderOptions(
bool enableScaling,
TonemapperKind tonemapper,
float whiteLevelScale,
DXGI_COLOR_SPACE_TYPE colorspace
RenderEffectKind effect,
float brightnessAdjustment,
Windows::Graphics::Display::AdvancedColorInfo^ acInfo
);
ImageInfo LoadImage(IStream* imageStream);
ImageInfo LoadImageFromWic(_In_ IStream* imageStream);
void PopulateImageInfoACKind(_Inout_ ImageInfo* info);
// IDeviceNotify methods handle device lost and restored.
virtual void OnDeviceLost();
virtual void OnDeviceRestored();
private:
void UpdateAdvancedColorState();
inline static float Clamp(float v, float bound1, float bound2)
{
float low = min(bound1, bound2);
float high = max(bound1, bound2);
return (v < low) ? low : (v > high) ? high : v;
}
ImageInfo LoadImageCommon(_In_ IWICBitmapSource* source);
void CreateHistogramResources();
void UpdateImageColorContext();
void UpdateWhiteLevelScale();
DisplayACKind GetDisplayACKind();
void UpdateWhiteLevelScale(float brightnessAdjustment, float sdrWhiteLevel);
void UpdateImageTransformState();
void ComputeHdrMetadata();
void EmitHdrMetadata();
// Cached pointer to device resources.
std::shared_ptr<DX::DeviceResources> m_deviceResources;
@ -94,20 +95,22 @@ namespace D2DAdvancedColorImages
Microsoft::WRL::ComPtr<ID2D1Effect> m_whiteScaleEffect;
Microsoft::WRL::ComPtr<ID2D1Effect> m_reinhardEffect;
Microsoft::WRL::ComPtr<ID2D1Effect> m_filmicEffect;
Microsoft::WRL::ComPtr<ID2D1Effect> m_sdrOverlayEffect;
Microsoft::WRL::ComPtr<ID2D1Effect> m_heatmapEffect;
Microsoft::WRL::ComPtr<ID2D1Effect> m_histogramPrescale;
Microsoft::WRL::ComPtr<ID2D1Effect> m_histogramEffect;
Microsoft::WRL::ComPtr<ID2D1Effect> m_finalOutput;
// Other renderer members.
TonemapperKind m_tonemapperKind;
bool m_userDisabledScaling;
bool m_useTonemapping;
RenderEffectKind m_renderEffectKind;
float m_zoom;
D2D1_POINT_2F m_offset;
DXGI_COLOR_SPACE_TYPE m_imageColorSpace;
float m_whiteLevelScale;
DXGI_OUTPUT_DESC1 m_outputDesc;
float m_minZoom;
D2D1_POINT_2F m_imageOffset;
D2D1_POINT_2F m_pointerPos;
float m_maxCLL; // In nits.
float m_brightnessAdjust;
Windows::Graphics::Display::AdvancedColorInfo^ m_dispInfo;
ImageInfo m_imageInfo;
// Registered handler for the display's advanced color state changes.
IDisplayACStateChanged^ m_dispStateChangeHandler;
bool m_isComputeSupported;
};
}

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

@ -720,86 +720,4 @@ DXGI_MODE_ROTATION DX::DeviceResources::ComputeDisplayRotation()
break;
}
return rotation;
}
// This method determines the primary DXGI output associated with the app at this
// point in time (using window/display intersection) and returns the display
// capabilities of that particular output.
DXGI_OUTPUT_DESC1 DX::DeviceResources::GetCurrentOutputDesc1()
{
// If the display's advanced color state has changed, then this app's DXGI
// factory is invalidated and must be created anew in order to retrieve
// up-to-date display information.
if (m_dxgiFactory->IsCurrent() == false)
{
DX::ThrowIfFailed(
CreateDXGIFactory2(0, IID_PPV_ARGS(&m_dxgiFactory))
);
}
// First, the method must determine the app's current display. Swap chains created
// with CreateSwapChainForComposition do not support the
// IDXGISwapChain::GetContainingOutput method, so the app must determine its current
// display. For swap chains created with CreateSwapChainForCoreWindow, the
// IDXGISwapChain::GetContainingOutput method can replace the following logic.
// Compute the DPI-adjusted window bounds.
Windows::Foundation::Rect windowBounds = Windows::UI::Xaml::Window::Current->CoreWindow->Bounds;
windowBounds = Windows::Foundation::Rect(
DX::ConvertDipsToPixels(windowBounds.X, m_dpi),
DX::ConvertDipsToPixels(windowBounds.Y, m_dpi),
DX::ConvertDipsToPixels(windowBounds.Width, m_dpi),
DX::ConvertDipsToPixels(windowBounds.Height, m_dpi)
);
// Retrieve the current default adapter.
ComPtr<IDXGIAdapter1> dxgiAdapter;
DX::ThrowIfFailed(m_dxgiFactory->EnumAdapters1(0, &dxgiAdapter));
// Iterate through the DXGI outputs associated with the DXGI adapter,
// and find the output whose bounds have the greatest overlap with the
// app window (i.e. the output for which the intersection area is the
// greatest).
UINT i = 0;
ComPtr<IDXGIOutput> currentOutput;
ComPtr<IDXGIOutput> bestOutput;
float bestIntersectArea = -1;
while (dxgiAdapter->EnumOutputs(i, &currentOutput) != DXGI_ERROR_NOT_FOUND)
{
DXGI_OUTPUT_DESC desc;
DX::ThrowIfFailed(currentOutput->GetDesc(&desc));
RECT r = desc.DesktopCoordinates;
Windows::Foundation::Rect outputBounds = Windows::Foundation::Rect(
(float)r.left,
(float)r.top,
(float)(r.right - r.left),
(float)(r.bottom - r.top)
);
if (windowBounds.IntersectsWith(outputBounds))
{
Windows::Foundation::Rect intersectBounds = windowBounds;
intersectBounds.Intersect(outputBounds);
float intersectArea = intersectBounds.Width * intersectBounds.Height;
if (intersectArea > bestIntersectArea)
{
bestOutput = currentOutput;
bestIntersectArea = intersectArea;
}
}
i++;
}
// Having determined the output (display) upon which the app is primarily being
// rendered, retrieve the capabilities of that display and return them.
ComPtr<IDXGIOutput6> output6;
DX::ThrowIfFailed(bestOutput.As(&output6));
DXGI_OUTPUT_DESC1 desc1;
DX::ThrowIfFailed(output6->GetDesc1(&desc1));
return desc1;
}
}

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

@ -60,9 +60,6 @@ namespace DX
IWICImagingFactory2* GetWicImagingFactory() const { return m_wicFactory.Get(); }
D2D1::Matrix3x2F GetOrientationTransform2D() const { return m_orientationTransform2D; }
// Helper methods for DXGI functionality.
DXGI_OUTPUT_DESC1 GetCurrentOutputDesc1();
private:
void CreateDeviceIndependentResources();
void CreateDeviceResources();

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

@ -23,11 +23,23 @@
<Grid>
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="Margin" Value="8" />
<Setter Property="VerticalAlignment" Value="Center" />
<!-- Margin: left, top, right, bottom -->
<Setter Property="Margin" Value="8, 0, 0, 0" />
</Style>
<Style TargetType="TextBlock" x:Key="SectionTitle">
<Setter Property="Margin" Value="8, 0, 8, 8" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style TargetType="TextBlock" x:Key="TrailingText">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Margin" Value="0, 0, 0, 8" />
</Style>
<Style TargetType="TextBlock" x:Key="InfoLine">
<Setter Property="Margin" Value="16, 0, 0, 0" />
</Style>
<Style TargetType="Button">
<Setter Property="Margin" Value="8" />
<Setter Property="Margin" Value="8, 0, 0, 8" />
</Style>
<Style TargetType="CheckBox">
<Setter Property="Margin" Value="8, 0, 0, 0" />
@ -36,6 +48,12 @@
<Style TargetType="Slider">
<Setter Property="Margin" Value="8, 0, 8, 0" />
</Style>
<Style TargetType="MenuFlyoutSeparator">
<Setter Property="Margin" Value="0, 8, 0, 8" />
</Style>
<Style TargetType="ComboBox">
<Setter Property="Margin" Value="8, 0, 8, 8" />
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
@ -54,44 +72,35 @@
<StackPanel x:Name="ControlsPanel" Grid.Row="1" Grid.Column="0" Background="Black" Opacity="0.8">
<Button Click="LoadImageButtonClick">Open image</Button>
<Button Click="ResetButtonClick">Reset</Button>
<StackPanel Orientation="Horizontal">
<CheckBox x:Name="ScalingCheckBox" Checked="CheckBoxChanged" Unchecked="CheckBoxChanged"></CheckBox>
<TextBlock>Disable scaling</TextBlock>
</StackPanel>
<TextBlock>Image colorspace:</TextBlock>
<ComboBox x:Name="ColorspacesCombo" ItemsSource="{x:Bind ViewModel.Colorspaces}" SelectionChanged="ComboChanged">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="local:ColorspaceOption">
<TextBlock Text="{x:Bind Description}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<StackPanel x:Name="TonemapperPanel">
<TextBlock>Tonemapper:</TextBlock>
<ComboBox x:Name="TonemappersCombo" ItemsSource="{x:Bind ViewModel.Tonemappers}" SelectionChanged="ComboChanged">
<StackPanel x:Name="RenderEffectPanel">
<TextBlock>Render Effect:</TextBlock>
<ComboBox x:Name="RenderEffectCombo" ItemsSource="{x:Bind ViewModel.RenderEffects}" SelectionChanged="ComboChanged">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="local:TonemapperOption">
<DataTemplate x:DataType="local:EffectOption">
<TextBlock Text="{x:Bind Description}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
<StackPanel x:Name="WhiteLevelPanel">
<TextBlock>White level scale:</TextBlock>
<Slider x:Name="WhiteLevelSlider" Minimum="0.5" Maximum="10" SnapsTo="StepValues" StepFrequency="0.5" Value="1.0" ValueChanged="SliderChanged"></Slider>
<StackPanel x:Name="BrightnessAdjustPanel">
<TextBlock>Adjust brightness:</TextBlock>
<Slider x:Name="BrightnessAdjustSlider" Minimum="0.25" Maximum="3" SnapsTo="StepValues" StepFrequency="0.25" Value="1.0" TickFrequency="0.5" TickPlacement="BottomRight" ValueChanged="SliderChanged" Margin="8,0,8,0"/>
</StackPanel>
<MenuFlyoutSeparator />
<TextBlock>Image information</TextBlock>
<TextBlock x:Name="ImageHasColorProfile">Color profile:</TextBlock>
<TextBlock x:Name="ImageBitDepth">Bits per pixel:</TextBlock>
<TextBlock x:Name="ImageIsFloat">Floating point:</TextBlock>
<TextBlock Style="{StaticResource SectionTitle}">Image information</TextBlock>
<TextBlock Style="{StaticResource InfoLine}" x:Name="ImageACKind">Kind:</TextBlock>
<TextBlock Style="{StaticResource InfoLine}" x:Name="ImageHasColorProfile">Color profile:</TextBlock>
<TextBlock Style="{StaticResource InfoLine}" x:Name="ImageBitDepth">Bit depth:</TextBlock>
<TextBlock Style="{StaticResource InfoLine}" x:Name="ImageIsFloat">Floating point:</TextBlock>
<TextBlock Style="{StaticResource InfoLine}" x:Name="ImageMaxCLL">Estimated MaxCLL:</TextBlock>
<MenuFlyoutSeparator />
<TextBlock>Display information</TextBlock>
<TextBlock x:Name="DisplayACState">Advanced color:</TextBlock>
<TextBlock x:Name="DisplayPeakLuminance">Peak luminance:</TextBlock>
<TextBlock x:Name="DisplayBitDepth">Bits per channel:</TextBlock>
<TextBlock Style="{StaticResource SectionTitle}">Display information</TextBlock>
<TextBlock Style="{StaticResource InfoLine}" x:Name="DisplayACState">Kind:</TextBlock>
<TextBlock Style="{StaticResource InfoLine}" x:Name="DisplayPeakLuminance">Peak luminance:</TextBlock>
<MenuFlyoutSeparator />
<TextBlock>Press H to hide UI</TextBlock>
<TextBlock Style="{StaticResource SectionTitle}">More controls</TextBlock>
<TextBlock Style="{StaticResource InfoLine}">H: Toggle UI</TextBlock>
<TextBlock Style="{StaticResource InfoLine}">F: Toggle fullscreen</TextBlock>
</StackPanel>
</Grid>
</SwapChainPanel>

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

@ -40,7 +40,8 @@ using namespace Windows::UI::Xaml::Navigation;
DirectXPage::DirectXPage() :
m_isWindowVisible(true),
m_imageInfo{},
m_dispInfo{}
m_isImageValid(false),
m_imageMaxCLL(-1.0f)
{
InitializeComponent();
@ -53,7 +54,7 @@ DirectXPage::DirectXPage() :
ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &DirectXPage::OnVisibilityChanged);
window->ResizeCompleted +=
ref new TypedEventHandler<CoreWindow ^, Platform::Object ^>(this, &DirectXPage::OnResizeCompleted);
ref new TypedEventHandler<CoreWindow ^, Object ^>(this, &DirectXPage::OnResizeCompleted);
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
@ -66,12 +67,37 @@ DirectXPage::DirectXPage() :
DisplayInformation::DisplayContentsInvalidated +=
ref new TypedEventHandler<DisplayInformation^, Object^>(this, &DirectXPage::OnDisplayContentsInvalidated);
currentDisplayInformation->AdvancedColorInfoChanged +=
ref new TypedEventHandler<DisplayInformation^, Object^>(this, &DirectXPage::OnAdvancedColorInfoChanged);
swapChainPanel->CompositionScaleChanged +=
ref new TypedEventHandler<SwapChainPanel^, Object^>(this, &DirectXPage::OnCompositionScaleChanged);
swapChainPanel->SizeChanged +=
ref new SizeChangedEventHandler(this, &DirectXPage::OnSwapChainPanelSizeChanged);
// Pointer and manipulation events handle image pan and zoom.
swapChainPanel->PointerPressed += ref new PointerEventHandler(this, &DirectXPage::OnPointerPressed);
swapChainPanel->PointerMoved += ref new PointerEventHandler(this, &DirectXPage::OnPointerMoved);
swapChainPanel->PointerReleased += ref new PointerEventHandler(this, &DirectXPage::OnPointerReleased);
swapChainPanel->PointerCanceled += ref new PointerEventHandler(this, &DirectXPage::OnPointerCanceled);
swapChainPanel->PointerWheelChanged += ref new PointerEventHandler(this, &DirectXPage::OnPointerWheelChanged);
m_gestureRecognizer = ref new GestureRecognizer();
m_gestureRecognizer->GestureSettings =
GestureSettings::ManipulationTranslateX |
GestureSettings::ManipulationTranslateY |
GestureSettings::ManipulationScale;
m_gestureRecognizer->ManipulationStarted +=
ref new TypedEventHandler<GestureRecognizer^, ManipulationStartedEventArgs^>(this, &DirectXPage::OnManipulationStarted);
m_gestureRecognizer->ManipulationUpdated +=
ref new TypedEventHandler<GestureRecognizer^, ManipulationUpdatedEventArgs^>(this, &DirectXPage::OnManipulationUpdated);
m_gestureRecognizer->ManipulationCompleted +=
ref new TypedEventHandler<GestureRecognizer^, ManipulationCompletedEventArgs^>(this, &DirectXPage::OnManipulationCompleted);
m_renderOptionsViewModel = ref new RenderOptionsViewModel();
// At this point we have access to the device and
@ -79,7 +105,9 @@ DirectXPage::DirectXPage() :
m_deviceResources = std::make_shared<DX::DeviceResources>();
m_deviceResources->SetSwapChainPanel(swapChainPanel);
m_renderer = std::unique_ptr<D2DAdvancedColorImagesRenderer>(new D2DAdvancedColorImagesRenderer(m_deviceResources, this));
m_renderer = std::unique_ptr<D2DAdvancedColorImagesRenderer>(new D2DAdvancedColorImagesRenderer(m_deviceResources));
UpdateDisplayACState(currentDisplayInformation->GetAdvancedColorInfo());
}
DirectXPage::~DirectXPage()
@ -97,80 +125,89 @@ void DirectXPage::LoadDefaultImage()
void DirectXPage::LoadImage(_In_ StorageFile^ imageFile)
{
create_task(imageFile->OpenAsync(FileAccessMode::Read)).then([=](task<IRandomAccessStream^> previousTask) {
IRandomAccessStream^ ras;
create_task(imageFile->OpenAsync(FileAccessMode::Read)
).then([=](IRandomAccessStream^ ras) {
// If file opening fails, fall through to error handler at the end of task chain.
ComPtr<IStream> iStream;
DX::ThrowIfFailed(CreateStreamOverRandomAccessStream(ras, IID_PPV_ARGS(&iStream)));
return m_renderer->LoadImageFromWic(iStream.Get());
}).then([=](ImageInfo info) {
m_imageInfo = info;
m_renderer->CreateImageDependentResources();
m_imageMaxCLL = m_renderer->FitImageToWindow();
ApplicationView::GetForCurrentView()->Title = imageFile->Name;
ImageACKind->Text = L"Kind: " + ConvertACKindToString(m_imageInfo.imageKind);
ImageHasColorProfile->Text = L"Color profile: " + (m_imageInfo.numProfiles > 0 ? L"Yes" : L"No");
ImageBitDepth->Text = L"Bit depth: " + ref new String(std::to_wstring(m_imageInfo.bitsPerChannel).c_str());
ImageIsFloat->Text = L"Floating point: " + (m_imageInfo.isFloat ? L"Yes" : L"No");
std::wstringstream cllStr;
cllStr << L"Estimated MaxCLL: ";
if (m_imageMaxCLL < 0.0f)
{
cllStr << L"N/A";
}
else
{
cllStr << std::to_wstring(static_cast<int>(m_imageMaxCLL)) << L" nits";
}
ImageMaxCLL->Text = ref new String(cllStr.str().c_str());
// Image loading is done at this point.
m_isImageValid = true;
UpdateDefaultRenderOptions();
// Ensure the preceding continuation runs on the UI thread.
}, task_continuation_context::use_current()).then([=](task<void> previousTask) {
try
{
ras = previousTask.get();
previousTask.get();
}
catch (...)
{
// If the file cannot be opened, then do nothing.
// Errors resulting from failure to load/decode image are ignored.
return;
}
ComPtr<IStream> iStream;
DX::ThrowIfFailed(CreateStreamOverRandomAccessStream(ras, IID_PPV_ARGS(&iStream)));
m_imageInfo = m_renderer->LoadImage(iStream.Get());
ApplicationView::GetForCurrentView()->Title = imageFile->Name;
ImageHasColorProfile->Text = L"Color profile: " + (m_imageInfo.numProfiles > 0 ? L"Yes" : L"No");
ImageBitDepth->Text = L"Bits per pixel: " + ref new String(std::to_wstring(m_imageInfo.bitsPerPixel).c_str());
ImageIsFloat->Text = L"Floating point: " + (m_imageInfo.isFloat ? L"Yes" : L"No");
m_renderer->CreateImageDependentResources();
m_renderer->FitImageToWindow();
// After image is loaded, reset rendering options to defaults.
ScalingCheckBox->IsChecked = false;
TonemappersCombo->SelectedIndex = 0; // See RenderOptions.h for which value this indicates.
ColorspacesCombo->SelectedIndex = 0; // See RenderOptions.h for which value this indicates.
WhiteLevelSlider->Value = 1.0f;
m_renderer->Draw();
});
}
void DirectXPage::OnDisplayACStateChanged(float maxLuminance, unsigned int bitDepth, DisplayACKind displayKind)
void DirectXPage::UpdateDisplayACState(_In_ AdvancedColorInfo^ info)
{
String^ displayString;
switch (displayKind)
// Render options are meaningless when this method is first called, as no image has been loaded yet.
// Therefore it doesn't matter what value we use for oldDispKind in this case.
auto oldDispKind = m_dispInfo ? m_dispInfo->CurrentAdvancedColorKind : AdvancedColorKind::StandardDynamicRange;
auto newDispKind = info->CurrentAdvancedColorKind;
m_dispInfo = info;
DisplayACState->Text = L"Kind: " + ConvertACKindToString(newDispKind);
unsigned int maxcll = static_cast<unsigned int>(info->MaxLuminanceInNits);
if (maxcll == 0)
{
case DisplayACKind::AdvancedColor_LowDynamicRange:
displayString = L"Advanced color, LDR";
break;
case DisplayACKind::AdvancedColor_HighDynamicRange:
displayString = L"Advanced color, HDR";
break;
case DisplayACKind::NotAdvancedColor:
default:
displayString = L"Not advanced color";
break;
}
DisplayACState->Text = L"Kind: " + displayString;
DisplayPeakLuminance->Text = L"Peak luminance: " +
ref new String(std::to_wstring(static_cast<unsigned int>(maxLuminance)).c_str()) + L" nits";
DisplayBitDepth->Text = L"Bits per channel: " + ref new String(std::to_wstring(bitDepth).c_str());
// White level scaling should only be enabled where overbright/high dynamic range is available.
// Tonemapping should only be enabled in the converse situation (low dynamic range); they don't benefit
// from adjusting white level since 1.0 white is simply mapped to the maximum luminance of the display.
if (displayKind == DisplayACKind::AdvancedColor_HighDynamicRange)
{
WhiteLevelPanel->Visibility = Windows::UI::Xaml::Visibility::Visible;
TonemapperPanel->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
// Luminance value of 0 means that no valid data was provided by the display.
DisplayPeakLuminance->Text = L"Peak luminance: Unknown";
}
else
{
WhiteLevelSlider->Value = 1.0f;
WhiteLevelPanel->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
TonemapperPanel->Visibility = Windows::UI::Xaml::Visibility::Visible;
DisplayPeakLuminance->Text = L"Peak luminance: " + ref new String(std::to_wstring(maxcll).c_str()) + L" nits";
}
if (oldDispKind == newDispKind)
{
// Some changes, such as peak luminance or SDR white level, don't need to reset rendering options.
UpdateRenderOptions();
}
else
{
// If display has changed kind between SDR/HDR/WCG, we must reset all rendering options.
UpdateDefaultRenderOptions();
}
}
// UI element event handlers.
@ -208,23 +245,67 @@ void DirectXPage::LoadInternalState(_In_ IPropertySet^ state)
{
}
// Based on image and display parameters, choose the best rendering options.
void DirectXPage::UpdateDefaultRenderOptions()
{
if (!m_isImageValid)
{
// Render options are only meaningful if an image is already loaded.
return;
}
switch (m_imageInfo.imageKind)
{
case AdvancedColorKind::StandardDynamicRange:
case AdvancedColorKind::WideColorGamut:
default:
// SDR and WCG images don't need to be tonemapped.
RenderEffectCombo->SelectedIndex = 2; // See RenderOptions.h for which value this indicates.
// Manual brightness adjustment is only useful for HDR content.
// SDR and WCG content is adjusted by the OS-provided AdvancedColorInfo::SdrWhiteLevel parameter.
BrightnessAdjustSlider->Value = 1.0f;
BrightnessAdjustPanel->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
break;
case AdvancedColorKind::HighDynamicRange:
switch (m_dispInfo->CurrentAdvancedColorKind)
{
case AdvancedColorKind::StandardDynamicRange:
case AdvancedColorKind::WideColorGamut:
default:
// HDR content + non-HDR display: HDR tonemapping is needed for correct rendering.
RenderEffectCombo->SelectedIndex = 0; // See RenderOptions.h for which value this indicates.
break;
case AdvancedColorKind::HighDynamicRange:
// HDR content + HDR display: HDR tonemapping is needed for best results, but this sample's
// tonemappers are very simple and not suitable, so just disable it.
RenderEffectCombo->SelectedIndex = 2; // See RenderOptions.h for which value this indicates.
break;
}
// Manual brightness adjustment is useful for any HDR content.
BrightnessAdjustPanel->Visibility = Windows::UI::Xaml::Visibility::Visible;
break;
}
UpdateRenderOptions();
}
// Common method for updating options on the renderer.
void DirectXPage::UpdateRenderOptions()
{
if ((m_renderer != nullptr) &&
ColorspacesCombo->SelectedItem &&
TonemappersCombo->SelectedItem
)
if ((m_renderer != nullptr) && RenderEffectCombo->SelectedItem)
{
auto cs = static_cast<ColorspaceOption^>(ColorspacesCombo->SelectedItem);
auto tm = static_cast<TonemapperOption^>(TonemappersCombo->SelectedItem);
auto tm = static_cast<EffectOption^>(RenderEffectCombo->SelectedItem);
m_renderer->SetRenderOptions(
ScalingCheckBox->IsChecked->Value,
tm->Tonemapper,
static_cast<float>(WhiteLevelSlider->Value),
static_cast<DXGI_COLOR_SPACE_TYPE>(cs->Colorspace)
);
tm->Kind,
static_cast<float>(BrightnessAdjustSlider->Value),
m_dispInfo
);
}
}
@ -262,6 +343,12 @@ void DirectXPage::OnDisplayContentsInvalidated(_In_ DisplayInformation^ sender,
m_renderer->Draw();
}
void DirectXPage::OnAdvancedColorInfoChanged(_In_ DisplayInformation ^sender, _In_ Object ^args)
{
UpdateDisplayACState(sender->GetAdvancedColorInfo());
}
// Other event handlers.
void DirectXPage::OnCompositionScaleChanged(_In_ SwapChainPanel^ sender, _In_ Object^ args)
@ -278,6 +365,28 @@ void DirectXPage::OnSwapChainPanelSizeChanged(_In_ Object^ sender, _In_ SizeChan
m_renderer->Draw();
}
String^ DirectXPage::ConvertACKindToString(AdvancedColorKind kind)
{
String^ displayString;
switch (kind)
{
case AdvancedColorKind::WideColorGamut:
displayString = L"Wide Color Gamut";
break;
case AdvancedColorKind::HighDynamicRange:
displayString = L"High Dynamic Range";
break;
case AdvancedColorKind::StandardDynamicRange:
default:
displayString = L"Standard Dynamic Range";
break;
}
return displayString;
}
void DirectXPage::OnKeyUp(_In_ CoreWindow ^sender, _In_ KeyEventArgs ^args)
{
if (VirtualKey::H == args->VirtualKey)
@ -293,26 +402,81 @@ void DirectXPage::OnKeyUp(_In_ CoreWindow ^sender, _In_ KeyEventArgs ^args)
ControlsPanel->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
}
}
else if (VirtualKey::F == args->VirtualKey)
{
if (ApplicationView::GetForCurrentView()->IsFullScreenMode)
{
ApplicationView::GetForCurrentView()->ExitFullScreenMode();
}
else
{
ApplicationView::GetForCurrentView()->TryEnterFullScreenMode();
}
}
}
void DirectXPage::SliderChanged(Object ^ sender, RangeBaseValueChangedEventArgs ^ e)
void DirectXPage::SliderChanged(_In_ Object^ sender, _In_ RangeBaseValueChangedEventArgs^ e)
{
UpdateRenderOptions();
}
void DirectXPage::CheckBoxChanged(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
void DirectXPage::CheckBoxChanged(_In_ Object^ sender, _In_ RoutedEventArgs^ e)
{
UpdateRenderOptions();
}
// ResizeCompleted is used to detect when the window has been moved between different displays.
void DirectXPage::OnResizeCompleted(CoreWindow ^sender, Object ^args)
void DirectXPage::OnResizeCompleted(_In_ CoreWindow^ sender, _In_ Object^ args)
{
UpdateRenderOptions();
}
void DirectXPage::ComboChanged(Object^ sender, SelectionChangedEventArgs^ e)
void DirectXPage::ComboChanged(_In_ Object^ sender, _In_ SelectionChangedEventArgs^ e)
{
UpdateRenderOptions();
}
// Send low level pointer events to GestureRecognizer to be interpreted.
void DirectXPage::OnPointerPressed(_In_ Object^ sender, _In_ PointerRoutedEventArgs^ e)
{
swapChainPanel->CapturePointer(e->Pointer);
m_gestureRecognizer->ProcessDownEvent(e->GetCurrentPoint(swapChainPanel));
}
void DirectXPage::OnPointerMoved(_In_ Object^ sender, _In_ PointerRoutedEventArgs^ e)
{
m_gestureRecognizer->ProcessMoveEvents(e->GetIntermediatePoints(swapChainPanel));
}
void DirectXPage::OnPointerReleased(_In_ Object ^sender, _In_ PointerRoutedEventArgs ^e)
{
m_gestureRecognizer->ProcessUpEvent(e->GetCurrentPoint(swapChainPanel));
swapChainPanel->ReleasePointerCapture(e->Pointer);
}
void DirectXPage::OnPointerCanceled(_In_ Object ^sender, _In_ PointerRoutedEventArgs ^e)
{
m_gestureRecognizer->CompleteGesture();
swapChainPanel->ReleasePointerCapture(e->Pointer);
}
void DirectXPage::OnPointerWheelChanged(_In_ Object ^sender, _In_ PointerRoutedEventArgs ^e)
{
// Passing isControlKeyDown = true causes the wheel delta to be treated as scrolling.
m_gestureRecognizer->ProcessMouseWheelEvent(e->GetCurrentPoint(swapChainPanel), false, true);
}
// GestureRecognizer triggers events on user manipulation of the image content.
void DirectXPage::OnManipulationStarted(_In_ GestureRecognizer ^sender, _In_ ManipulationStartedEventArgs ^args)
{
}
void DirectXPage::OnManipulationUpdated(_In_ GestureRecognizer ^sender, _In_ ManipulationUpdatedEventArgs ^args)
{
m_renderer->UpdateManipulationState(args);
}
void DirectXPage::OnManipulationCompleted(_In_ GestureRecognizer ^sender, _In_ ManipulationCompletedEventArgs ^args)
{
}

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

@ -22,7 +22,7 @@ namespace D2DAdvancedColorImages
/// <summary>
/// A page that hosts the Direct2D app in a SwapChainPanel, and app UI in XAML.
/// </summary>
public ref class DirectXPage sealed : public IDisplayACStateChanged
public ref class DirectXPage sealed
{
public:
DirectXPage();
@ -34,12 +34,6 @@ namespace D2DAdvancedColorImages
void LoadDefaultImage();
void LoadImage(_In_ Windows::Storage::StorageFile^ imageFile);
// IAdvancedColorStateChanged implementation.
virtual void OnDisplayACStateChanged(
float maxLuminance,
unsigned int bitDepth,
DisplayACKind displayKind);
property RenderOptionsViewModel^ ViewModel
{
RenderOptionsViewModel^ get() { return m_renderOptionsViewModel; }
@ -52,7 +46,10 @@ namespace D2DAdvancedColorImages
void CheckBoxChanged(_In_ Platform::Object^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs^ e);
void OnKeyUp(_In_ Windows::UI::Core::CoreWindow^ sender, _In_ Windows::UI::Core::KeyEventArgs^ args);
void SliderChanged(_In_ Platform::Object^ sender, _In_ Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs^ e);
void ComboChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e);
void ComboChanged(_In_ Platform::Object^ sender, _In_ Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e);
void UpdateDisplayACState(_In_ Windows::Graphics::Display::AdvancedColorInfo^ info);
void UpdateDefaultRenderOptions();
void UpdateRenderOptions();
// XAML low-level rendering event handler.
@ -66,20 +63,36 @@ namespace D2DAdvancedColorImages
void OnDpiChanged(_In_ Windows::Graphics::Display::DisplayInformation^ sender, _In_ Platform::Object^ args);
void OnOrientationChanged(_In_ Windows::Graphics::Display::DisplayInformation^ sender, _In_ Platform::Object^ args);
void OnDisplayContentsInvalidated(_In_ Windows::Graphics::Display::DisplayInformation^ sender, _In_ Platform::Object^ args);
void OnAdvancedColorInfoChanged(_In_ Windows::Graphics::Display::DisplayInformation ^sender, _In_ Platform::Object ^args);
// Pointer input event handlers (for pan and zoom).
void OnPointerPressed(_In_ Platform::Object ^sender, _In_ Windows::UI::Xaml::Input::PointerRoutedEventArgs ^e);
void OnPointerMoved(_In_ Platform::Object ^sender, _In_ Windows::UI::Xaml::Input::PointerRoutedEventArgs ^e);
void OnPointerReleased(_In_ Platform::Object ^sender, _In_ Windows::UI::Xaml::Input::PointerRoutedEventArgs ^e);
void OnManipulationStarted(_In_ Windows::UI::Input::GestureRecognizer ^sender, _In_ Windows::UI::Input::ManipulationStartedEventArgs ^args);
void OnManipulationUpdated(_In_ Windows::UI::Input::GestureRecognizer ^sender, _In_ Windows::UI::Input::ManipulationUpdatedEventArgs ^args);
void OnManipulationCompleted(_In_ Windows::UI::Input::GestureRecognizer ^sender, _In_ Windows::UI::Input::ManipulationCompletedEventArgs ^args);
void OnPointerCanceled(_In_ Platform::Object ^sender, _In_ Windows::UI::Xaml::Input::PointerRoutedEventArgs ^e);
void OnPointerWheelChanged(_In_ Platform::Object ^sender, _In_ Windows::UI::Xaml::Input::PointerRoutedEventArgs ^e);
// Other event handlers.
void OnCompositionScaleChanged(_In_ Windows::UI::Xaml::Controls::SwapChainPanel^ sender, _In_ Object^ args);
void OnSwapChainPanelSizeChanged(_In_ Platform::Object^ sender, _In_ Windows::UI::Xaml::SizeChangedEventArgs^ e);
Platform::String^ ConvertACKindToString(Windows::Graphics::Display::AdvancedColorKind kind);
// Resources used to draw the DirectX content in the XAML page.
std::shared_ptr<DX::DeviceResources> m_deviceResources;
std::unique_ptr<D2DAdvancedColorImagesRenderer> m_renderer;
bool m_isWindowVisible;
std::shared_ptr<DX::DeviceResources> m_deviceResources;
std::unique_ptr<D2DAdvancedColorImagesRenderer> m_renderer;
Windows::UI::Input::GestureRecognizer^ m_gestureRecognizer;
bool m_isWindowVisible;
// Cached information for UI.
D2DAdvancedColorImages::ImageInfo m_imageInfo;
DXGI_OUTPUT_DESC1 m_dispInfo;
RenderOptionsViewModel^ m_renderOptionsViewModel;
D2DAdvancedColorImages::ImageInfo m_imageInfo;
float m_imageMaxCLL;
bool m_isImageValid;
Windows::Graphics::Display::AdvancedColorInfo^ m_dispInfo;
RenderOptionsViewModel^ m_renderOptionsViewModel;
};
}

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

@ -0,0 +1,270 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
#include "pch.h"
#include <initguid.h>
#include "LuminanceHeatmapEffect.h"
#include "BasicReaderWriter.h"
#define XML(X) TEXT(#X)
LuminanceHeatmapEffect::LuminanceHeatmapEffect() :
m_refCount(1),
m_constants{}
{
}
HRESULT __stdcall LuminanceHeatmapEffect::CreateLuminanceHeatmapImpl(_Outptr_ IUnknown** ppEffectImpl)
{
// Since the object's refcount is initialized to 1, we don't need to AddRef here.
*ppEffectImpl = static_cast<ID2D1EffectImpl*>(new (std::nothrow) LuminanceHeatmapEffect());
if (*ppEffectImpl == nullptr)
{
return E_OUTOFMEMORY;
}
else
{
return S_OK;
}
}
HRESULT LuminanceHeatmapEffect::Register(_In_ ID2D1Factory1* pFactory)
{
// The inspectable metadata of an effect is defined in XML. This can be passed in from an external source
// as well, however for simplicity we just inline the XML.
PCWSTR pszXml =
XML(
<?xml version='1.0'?>
<Effect>
<!-- System Properties -->
<Property name='DisplayName' type='string' value='LuminanceHeatmap'/>
<Property name='Author' type='string' value='Microsoft Corporation'/>
<Property name='Category' type='string' value='Source'/>
<Property name='Description' type='string' value='Emulates SDR behavior on an AC source'/>
<Inputs>
<Input name = 'Source'/>
</Inputs>
<!-- Custom Properties go here -->
</Effect>
);
// This registers the effect with the factory, which will make the effect
// instantiatable.
return pFactory->RegisterEffectFromString(
CLSID_CustomLuminanceHeatmapEffect,
pszXml,
nullptr, // No custom properties
0, // No custom properties
CreateLuminanceHeatmapImpl
);
}
IFACEMETHODIMP LuminanceHeatmapEffect::Initialize(
_In_ ID2D1EffectContext* pEffectContext,
_In_ ID2D1TransformGraph* pTransformGraph
)
{
// To maintain consistency across different DPIs, this effect needs to cover more pixels at
// higher than normal DPIs. The context is saved here so the effect can later retrieve the DPI.
m_effectContext = pEffectContext;
BasicReaderWriter^ reader = ref new BasicReaderWriter();
Platform::Array<unsigned char, 1U>^ data;
try
{
data = reader->ReadData("LuminanceHeatmapEffect.cso");
}
catch (Platform::Exception^ e)
{
// Return error if file can not be read.
return e->HResult;
}
HRESULT hr = pEffectContext->LoadPixelShader(GUID_LuminanceHeatmapPixelShader, data->Data, data->Length);
// This loads the shader into the Direct2D image effects system and associates it with the GUID passed in.
// If this method is called more than once (say by other instances of the effect) with the same GUID,
// the system will simply do nothing, ensuring that only one instance of a shader is stored regardless of how
// many time it is used.
if (SUCCEEDED(hr))
{
// The graph consists of a single transform. In fact, this class is the transform,
// reducing the complexity of implementing an effect when all we need to
// do is use a single pixel shader.
hr = pTransformGraph->SetSingleTransformNode(this);
}
return hr;
}
HRESULT LuminanceHeatmapEffect::UpdateConstants()
{
// Update the DPI if it has changed. This allows the effect to scale across different DPIs automatically.
m_effectContext->GetDpi(&m_dpi, &m_dpi);
m_constants.dpi = m_dpi;
return m_drawInfo->SetPixelShaderConstantBuffer(reinterpret_cast<BYTE*>(&m_constants), sizeof(m_constants));
}
IFACEMETHODIMP LuminanceHeatmapEffect::PrepareForRender(D2D1_CHANGE_TYPE changeType)
{
return UpdateConstants();
}
// SetGraph is only called when the number of inputs changes. This never happens as we publish this effect
// as a single input effect.
IFACEMETHODIMP LuminanceHeatmapEffect::SetGraph(_In_ ID2D1TransformGraph* pGraph)
{
return E_NOTIMPL;
}
// Called to assign a new render info class, which is used to inform D2D on
// how to set the state of the GPU.
IFACEMETHODIMP LuminanceHeatmapEffect::SetDrawInfo(_In_ ID2D1DrawInfo* pDrawInfo)
{
m_drawInfo = pDrawInfo;
return m_drawInfo->SetPixelShader(GUID_LuminanceHeatmapPixelShader);
}
// Calculates the mapping between the output and input rects.
IFACEMETHODIMP LuminanceHeatmapEffect::MapOutputRectToInputRects(
_In_ const D2D1_RECT_L* pOutputRect,
_Out_writes_(inputRectCount) D2D1_RECT_L* pInputRects,
UINT32 inputRectCount
) const
{
// This effect has exactly 1 input.
if (inputRectCount != 1)
{
return E_INVALIDARG;
}
// 1:1 mapping of output to input rect.
pInputRects[0].left = pOutputRect->left;
pInputRects[0].top = pOutputRect->top;
pInputRects[0].right = pOutputRect->right;
pInputRects[0].bottom = pOutputRect->bottom;
return S_OK;
}
IFACEMETHODIMP LuminanceHeatmapEffect::MapInputRectsToOutputRect(
_In_reads_(inputRectCount) CONST D2D1_RECT_L* pInputRects,
_In_reads_(inputRectCount) CONST D2D1_RECT_L* pInputOpaqueSubRects,
UINT32 inputRectCount,
_Out_ D2D1_RECT_L* pOutputRect,
_Out_ D2D1_RECT_L* pOutputOpaqueSubRect
)
{
// This effect has exactly 1 input.
if (inputRectCount != 1)
{
return E_INVALIDARG;
}
// 1:1 mapping of input to output rect.
*pOutputRect = pInputRects[0];
m_inputRect = pInputRects[0];
// This effect always outputs fully opaque pixels.
*pOutputOpaqueSubRect = pInputRects[0];
return S_OK;
}
IFACEMETHODIMP LuminanceHeatmapEffect::MapInvalidRect(
UINT32 inputIndex,
D2D1_RECT_L invalidInputRect,
_Out_ D2D1_RECT_L* pInvalidOutputRect
) const
{
HRESULT hr = S_OK;
// Indicate that the entire output may be invalid.
*pInvalidOutputRect = m_inputRect;
return hr;
}
IFACEMETHODIMP_(UINT32) LuminanceHeatmapEffect::GetInputCount() const
{
return 1;
}
// D2D ensures that that effects are only referenced from one thread at a time.
// To improve performance, we simply increment/decrement our reference count
// rather than use atomic InterlockedIncrement()/InterlockedDecrement() functions.
IFACEMETHODIMP_(ULONG) LuminanceHeatmapEffect::AddRef()
{
m_refCount++;
return m_refCount;
}
IFACEMETHODIMP_(ULONG) LuminanceHeatmapEffect::Release()
{
m_refCount--;
if (m_refCount == 0)
{
delete this;
return 0;
}
else
{
return m_refCount;
}
}
// This enables the stack of parent interfaces to be queried. In the instance
// of the LuminanceHeatmap interface, this method simply enables the developer
// to cast a LuminanceHeatmap instance to an ID2D1EffectImpl or IUnknown instance.
IFACEMETHODIMP LuminanceHeatmapEffect::QueryInterface(
_In_ REFIID riid,
_Outptr_ void** ppOutput
)
{
*ppOutput = nullptr;
HRESULT hr = S_OK;
if (riid == __uuidof(ID2D1EffectImpl))
{
*ppOutput = reinterpret_cast<ID2D1EffectImpl*>(this);
}
else if (riid == __uuidof(ID2D1DrawTransform))
{
*ppOutput = static_cast<ID2D1DrawTransform*>(this);
}
else if (riid == __uuidof(ID2D1Transform))
{
*ppOutput = static_cast<ID2D1Transform*>(this);
}
else if (riid == __uuidof(ID2D1TransformNode))
{
*ppOutput = static_cast<ID2D1TransformNode*>(this);
}
else if (riid == __uuidof(IUnknown))
{
*ppOutput = this;
}
else
{
hr = E_NOINTERFACE;
}
if (*ppOutput != nullptr)
{
AddRef();
}
return hr;
}

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

@ -0,0 +1,87 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
// Not a tonemapper, instead produces a colorized heatmap of the luminance of the image in SDR range.
// See LuminanceHeatmapEffect.hlsl for the nits --> color mapping.
DEFINE_GUID(GUID_LuminanceHeatmapPixelShader, 0xced40834, 0x5bc7, 0x4cc6, 0xbe, 0xe9, 0x4f, 0x94, 0xf, 0xab, 0x7b, 0xc1);
DEFINE_GUID(CLSID_CustomLuminanceHeatmapEffect, 0x52bfa892, 0x4616, 0x4b9f, 0xb6, 0x69, 0x1f, 0x4e, 0xdb, 0xfe, 0x10, 0x72);
// Our effect contains one transform, which is simply a wrapper around a pixel shader. As such,
// we can simply make the effect itself act as the transform.
class LuminanceHeatmapEffect : public ID2D1EffectImpl, public ID2D1DrawTransform
{
public:
// Declare effect registration methods.
static HRESULT Register(_In_ ID2D1Factory1* pFactory);
static HRESULT __stdcall CreateLuminanceHeatmapImpl(_Outptr_ IUnknown** ppEffectImpl);
// Declare ID2D1EffectImpl implementation methods.
IFACEMETHODIMP Initialize(
_In_ ID2D1EffectContext* pContextInternal,
_In_ ID2D1TransformGraph* pTransformGraph
);
IFACEMETHODIMP PrepareForRender(D2D1_CHANGE_TYPE changeType);
IFACEMETHODIMP SetGraph(_In_ ID2D1TransformGraph* pGraph);
// Declare ID2D1DrawTransform implementation methods.
IFACEMETHODIMP SetDrawInfo(_In_ ID2D1DrawInfo* pRenderInfo);
// Declare ID2D1Transform implementation methods.
IFACEMETHODIMP MapOutputRectToInputRects(
_In_ const D2D1_RECT_L* pOutputRect,
_Out_writes_(inputRectCount) D2D1_RECT_L* pInputRects,
UINT32 inputRectCount
) const;
IFACEMETHODIMP MapInputRectsToOutputRect(
_In_reads_(inputRectCount) CONST D2D1_RECT_L* pInputRects,
_In_reads_(inputRectCount) CONST D2D1_RECT_L* pInputOpaqueSubRects,
UINT32 inputRectCount,
_Out_ D2D1_RECT_L* pOutputRect,
_Out_ D2D1_RECT_L* pOutputOpaqueSubRect
);
IFACEMETHODIMP MapInvalidRect(
UINT32 inputIndex,
D2D1_RECT_L invalidInputRect,
_Out_ D2D1_RECT_L* pInvalidOutputRect
) const;
// Declare ID2D1TransformNode implementation methods.
IFACEMETHODIMP_(UINT32) GetInputCount() const;
// Declare IUnknown implementation methods.
IFACEMETHODIMP_(ULONG) AddRef();
IFACEMETHODIMP_(ULONG) Release();
IFACEMETHODIMP QueryInterface(_In_ REFIID riid, _Outptr_ void** ppOutput);
// Declare property getter/setter methods.
private:
LuminanceHeatmapEffect();
HRESULT UpdateConstants();
// This struct defines the constant buffer of our pixel shader.
struct
{
float dpi;
} m_constants;
Microsoft::WRL::ComPtr<ID2D1DrawInfo> m_drawInfo;
Microsoft::WRL::ComPtr<ID2D1EffectContext> m_effectContext;
LONG m_refCount;
D2D1_RECT_L m_inputRect;
float m_dpi;
};

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

@ -0,0 +1,103 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
// Custom effects using pixel shaders should use HLSL helper functions defined in
// d2d1effecthelpers.hlsli to make use of effect shader linking.
#define D2D_INPUT_COUNT 1 // The pixel shader takes exactly 1 input.
// Note that the custom build step must provide the correct path to find d2d1effecthelpers.hlsli when calling fxc.exe.
#include "d2d1effecthelpers.hlsli"
// Nits to color mappings:
// 0.00 Black
// 3.16 Blue
// 10.0 Cyan
// 31.6 Green
// 100.0 Yellow
// 316.0 Orange
// 1000.0 Red
// 3160.0 Magenta
// 10000.0 White
// This approximates a logarithmic plot where two colors represent one order of magnitude in nits.
// Define constants based on above behavior: 9 "stops" for a piecewise linear gradient in scRGB space.
#define STOP0_NITS 0.00f
#define STOP1_NITS 3.16f
#define STOP2_NITS 10.0f
#define STOP3_NITS 31.6f
#define STOP4_NITS 100.f
#define STOP5_NITS 316.f
#define STOP6_NITS 1000.f
#define STOP7_NITS 3160.f
#define STOP8_NITS 10000.f
#define STOP0_COLOR float4(0.0f, 0.0f, 0.0f, 1.0f) // Black
#define STOP1_COLOR float4(0.0f, 0.0f, 1.0f, 1.0f) // Blue
#define STOP2_COLOR float4(0.0f, 1.0f, 1.0f, 1.0f) // Cyan
#define STOP3_COLOR float4(0.0f, 1.0f, 0.0f, 1.0f) // Green
#define STOP4_COLOR float4(1.0f, 1.0f, 0.0f, 1.0f) // Yellow
#define STOP5_COLOR float4(1.0f, 0.2f, 0.0f, 1.0f) // Orange
// Orange isn't a simple combination of primary colors but allows us to have 8 gradient segments,
// which gives us cleaner definitions for the nits --> color mappings.
#define STOP6_COLOR float4(1.0f, 0.0f, 0.0f, 1.0f) // Red
#define STOP7_COLOR float4(1.0f, 0.0f, 1.0f, 1.0f) // Magenta
#define STOP8_COLOR float4(1.0f, 1.0f, 1.0f, 1.0f) // White
cbuffer constants : register(b0)
{
float dpi : packoffset(c0.x); // Ignored - there is no position-dependent behavior in the shader.
};
D2D_PS_ENTRY(main)
{
float4 input = D2DGetInput(0);
// Implement the heatmap with a piecewise linear gradient that maps [0, 10000] nits to scRGB colors.
// This shader is optimized for readability, not performance.
// 1: Calculate luminance in nits.
// Input is in scRGB. First convert to Y from CIEXYZ, then scale by whitepoint of 80 nits.
float nits = dot(float3(0.2126f, 0.7152f, 0.0722f), input.rgb) * 80.0f;
// 2: Determine which gradient segment will be used.
// Only one of useSegmentN will be 1 (true) for a given nits value.
float useSegment0 = sign(nits - STOP0_NITS) - sign(nits - STOP1_NITS);
float useSegment1 = sign(nits - STOP1_NITS) - sign(nits - STOP2_NITS);
float useSegment2 = sign(nits - STOP2_NITS) - sign(nits - STOP3_NITS);
float useSegment3 = sign(nits - STOP3_NITS) - sign(nits - STOP4_NITS);
float useSegment4 = sign(nits - STOP4_NITS) - sign(nits - STOP5_NITS);
float useSegment5 = sign(nits - STOP5_NITS) - sign(nits - STOP6_NITS);
float useSegment6 = sign(nits - STOP6_NITS) - sign(nits - STOP7_NITS);
float useSegment7 = sign(nits - STOP7_NITS) - sign(nits - STOP8_NITS);
// 3: Calculate the interpolated color.
float lerpSegment0 = (nits - STOP0_NITS) / (STOP1_NITS - STOP0_NITS);
float lerpSegment1 = (nits - STOP1_NITS) / (STOP2_NITS - STOP1_NITS);
float lerpSegment2 = (nits - STOP2_NITS) / (STOP3_NITS - STOP2_NITS);
float lerpSegment3 = (nits - STOP3_NITS) / (STOP4_NITS - STOP3_NITS);
float lerpSegment4 = (nits - STOP4_NITS) / (STOP5_NITS - STOP4_NITS);
float lerpSegment5 = (nits - STOP5_NITS) / (STOP6_NITS - STOP5_NITS);
float lerpSegment6 = (nits - STOP6_NITS) / (STOP7_NITS - STOP6_NITS);
float lerpSegment7 = (nits - STOP7_NITS) / (STOP8_NITS - STOP7_NITS);
// Only the "active" gradient segment contributes to the output color.
float4 output =
lerp(STOP0_COLOR, STOP1_COLOR, lerpSegment0) * useSegment0 +
lerp(STOP1_COLOR, STOP2_COLOR, lerpSegment1) * useSegment1 +
lerp(STOP2_COLOR, STOP3_COLOR, lerpSegment2) * useSegment2 +
lerp(STOP3_COLOR, STOP4_COLOR, lerpSegment3) * useSegment3 +
lerp(STOP4_COLOR, STOP5_COLOR, lerpSegment4) * useSegment4 +
lerp(STOP5_COLOR, STOP6_COLOR, lerpSegment5) * useSegment5 +
lerp(STOP6_COLOR, STOP7_COLOR, lerpSegment6) * useSegment6 +
lerp(STOP7_COLOR, STOP8_COLOR, lerpSegment7) * useSegment7;
return output;
}

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

@ -13,7 +13,7 @@
<Logo>Assets\StoreLogo-sdk.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.15063.0" MaxVersionTested="10.0.17134.0"/>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17134.0" MaxVersionTested="10.0.17134.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>

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

@ -16,25 +16,29 @@
namespace D2DAdvancedColorImages
{
/// <summary>
/// Supported HDR to SDR tonemappers. Each tonemapper is implemented as a custom Direct2D effect.
/// Supported render effects which are inserted into the render pipeline.
/// Includes HDR tonemappers and useful visual tools.
/// Each render effect is implemented as a custom Direct2D effect.
/// </summary>
public enum class TonemapperKind
public enum class RenderEffectKind
{
Reinhard,
Filmic,
Disabled,
ReinhardTonemap,
FilmicTonemap,
None,
SdrOverlay,
LuminanceHeatmap
};
/// <summary>
/// Associates a tonemapping type used by the renderer to a descriptive string bound to UI.
/// Associates a effect type used by the renderer to a descriptive string bound to UI.
/// </summary>
public ref class TonemapperOption sealed
public ref class EffectOption sealed
{
public:
TonemapperOption(Platform::String^ description, TonemapperKind type)
EffectOption(Platform::String^ description, RenderEffectKind kind)
{
this->description = description;
this->type = type;
this->kind = kind;
}
property Platform::String^ Description
@ -42,60 +46,18 @@ namespace D2DAdvancedColorImages
Platform::String^ get() { return description; }
}
property TonemapperKind Tonemapper
property RenderEffectKind Kind
{
TonemapperKind get() { return type; }
RenderEffectKind get() { return kind; }
}
private:
Platform::String^ description;
TonemapperKind type;
RenderEffectKind kind;
};
/// <summary>
/// Maps DXGI_COLOR_SPACE_TYPE to a valid WinRT enumeration. Every enum value
/// must be defined as an existing DXGI_COLOR_SPACE_TYPE value to allow for casting.
/// Only the DXGI_COLOR_SPACE_TYPE values needed for this app are defined.
/// </summary>
public enum class DxgiColorspace
{
Custom = DXGI_COLOR_SPACE_CUSTOM,
Srgb_Full = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709,
Srgb_Studio = DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709,
Scrgb_Full = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709,
Hdr10_Full = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020,
Hdr10_Studio = DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020,
};
/// <summary>
/// Associates a DXGI colorspace used by the renderer to a descriptive string bound to UI.
/// </summary>
public ref class ColorspaceOption sealed
{
public:
ColorspaceOption(Platform::String^ description, DxgiColorspace cs)
{
this->description = description;
this->colorspace = cs;
}
property Platform::String^ Description
{
Platform::String^ get() { return description; }
}
property DxgiColorspace Colorspace
{
DxgiColorspace get() { return colorspace; }
}
private:
Platform::String^ description;
DxgiColorspace colorspace;
};
/// <summary>
/// Allows databinding of render options to the UI: image colorspace and tonemapper.
/// <summary>
/// Allows databinding of render options to the UI: image colorspace and render effect/tonemapper.
/// </summary>
public ref class RenderOptionsViewModel sealed
{
@ -103,43 +65,25 @@ namespace D2DAdvancedColorImages
RenderOptionsViewModel()
{
// The first index is chosen by default. Ensure this is in sync with DirectXPage.
colorspaces = ref new Platform::Collections::VectorView<ColorspaceOption^>
renderEffects = ref new Platform::Collections::VectorView<EffectOption^>
{
ref new ColorspaceOption(L"Use image's color profile", DxgiColorspace::Custom),
ref new ColorspaceOption(L"sRGB (full range)", DxgiColorspace::Srgb_Full),
ref new ColorspaceOption(L"sRGB (studio range)", DxgiColorspace::Srgb_Studio),
ref new ColorspaceOption(L"scRGB (full range)", DxgiColorspace::Scrgb_Full),
ref new ColorspaceOption(L"HDR10 (full range)", DxgiColorspace::Hdr10_Full),
ref new ColorspaceOption(L"HDR10 (studio range)", DxgiColorspace::Hdr10_Studio),
};
// The first index is chosen by default. Ensure this is in sync with DirectXPage.
tonemappers = ref new Platform::Collections::VectorView<TonemapperOption^>
{
ref new TonemapperOption(L"ACES Filmic", TonemapperKind::Filmic),
ref new TonemapperOption(L"Reinhard", TonemapperKind::Reinhard),
ref new TonemapperOption(L"Disabled", TonemapperKind::Disabled),
ref new EffectOption(L"ACES Filmic Tonemap", RenderEffectKind::FilmicTonemap),
ref new EffectOption(L"Reinhard Tonemap", RenderEffectKind::ReinhardTonemap),
ref new EffectOption(L"No effect", RenderEffectKind::None),
ref new EffectOption(L"Draw SDR as grayscale", RenderEffectKind::SdrOverlay),
ref new EffectOption(L"Draw luminance as heatmap", RenderEffectKind::LuminanceHeatmap)
};
}
property Windows::Foundation::Collections::IVectorView<ColorspaceOption^>^ Colorspaces
property Windows::Foundation::Collections::IVectorView<EffectOption^>^ RenderEffects
{
Windows::Foundation::Collections::IVectorView<ColorspaceOption^>^ get()
Windows::Foundation::Collections::IVectorView<EffectOption^>^ get()
{
return this->colorspaces;
}
}
property Windows::Foundation::Collections::IVectorView<TonemapperOption^>^ Tonemappers
{
Windows::Foundation::Collections::IVectorView<TonemapperOption^>^ get()
{
return this->tonemappers;
return this->renderEffects;
}
}
private:
Platform::Collections::VectorView<ColorspaceOption^>^ colorspaces;
Platform::Collections::VectorView<TonemapperOption^>^ tonemappers;
Platform::Collections::VectorView<EffectOption^>^ renderEffects;
};
}

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

@ -0,0 +1,270 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
#include "pch.h"
#include <initguid.h>
#include "SdrOverlayEffect.h"
#include "BasicReaderWriter.h"
#define XML(X) TEXT(#X)
SdrOverlayEffect::SdrOverlayEffect() :
m_refCount(1),
m_constants{}
{
}
HRESULT __stdcall SdrOverlayEffect::CreateSdrOverlayImpl(_Outptr_ IUnknown** ppEffectImpl)
{
// Since the object's refcount is initialized to 1, we don't need to AddRef here.
*ppEffectImpl = static_cast<ID2D1EffectImpl*>(new (std::nothrow) SdrOverlayEffect());
if (*ppEffectImpl == nullptr)
{
return E_OUTOFMEMORY;
}
else
{
return S_OK;
}
}
HRESULT SdrOverlayEffect::Register(_In_ ID2D1Factory1* pFactory)
{
// The inspectable metadata of an effect is defined in XML. This can be passed in from an external source
// as well, however for simplicity we just inline the XML.
PCWSTR pszXml =
XML(
<?xml version='1.0'?>
<Effect>
<!-- System Properties -->
<Property name='DisplayName' type='string' value='SdrOverlay'/>
<Property name='Author' type='string' value='Microsoft Corporation'/>
<Property name='Category' type='string' value='Source'/>
<Property name='Description' type='string' value='Emulates SDR behavior on an AC source'/>
<Inputs>
<Input name = 'Source'/>
</Inputs>
<!-- Custom Properties go here -->
</Effect>
);
// This registers the effect with the factory, which will make the effect
// instantiatable.
return pFactory->RegisterEffectFromString(
CLSID_CustomSdrOverlayEffect,
pszXml,
nullptr, // No custom properties
0, // No custom properties
CreateSdrOverlayImpl
);
}
IFACEMETHODIMP SdrOverlayEffect::Initialize(
_In_ ID2D1EffectContext* pEffectContext,
_In_ ID2D1TransformGraph* pTransformGraph
)
{
// To maintain consistency across different DPIs, this effect needs to cover more pixels at
// higher than normal DPIs. The context is saved here so the effect can later retrieve the DPI.
m_effectContext = pEffectContext;
BasicReaderWriter^ reader = ref new BasicReaderWriter();
Platform::Array<unsigned char, 1U>^ data;
try
{
data = reader->ReadData("SdrOverlayEffect.cso");
}
catch (Platform::Exception^ e)
{
// Return error if file can not be read.
return e->HResult;
}
HRESULT hr = pEffectContext->LoadPixelShader(GUID_SdrOverlayPixelShader, data->Data, data->Length);
// This loads the shader into the Direct2D image effects system and associates it with the GUID passed in.
// If this method is called more than once (say by other instances of the effect) with the same GUID,
// the system will simply do nothing, ensuring that only one instance of a shader is stored regardless of how
// many time it is used.
if (SUCCEEDED(hr))
{
// The graph consists of a single transform. In fact, this class is the transform,
// reducing the complexity of implementing an effect when all we need to
// do is use a single pixel shader.
hr = pTransformGraph->SetSingleTransformNode(this);
}
return hr;
}
HRESULT SdrOverlayEffect::UpdateConstants()
{
// Update the DPI if it has changed. This allows the effect to scale across different DPIs automatically.
m_effectContext->GetDpi(&m_dpi, &m_dpi);
m_constants.dpi = m_dpi;
return m_drawInfo->SetPixelShaderConstantBuffer(reinterpret_cast<BYTE*>(&m_constants), sizeof(m_constants));
}
IFACEMETHODIMP SdrOverlayEffect::PrepareForRender(D2D1_CHANGE_TYPE changeType)
{
return UpdateConstants();
}
// SetGraph is only called when the number of inputs changes. This never happens as we publish this effect
// as a single input effect.
IFACEMETHODIMP SdrOverlayEffect::SetGraph(_In_ ID2D1TransformGraph* pGraph)
{
return E_NOTIMPL;
}
// Called to assign a new render info class, which is used to inform D2D on
// how to set the state of the GPU.
IFACEMETHODIMP SdrOverlayEffect::SetDrawInfo(_In_ ID2D1DrawInfo* pDrawInfo)
{
m_drawInfo = pDrawInfo;
return m_drawInfo->SetPixelShader(GUID_SdrOverlayPixelShader);
}
// Calculates the mapping between the output and input rects.
IFACEMETHODIMP SdrOverlayEffect::MapOutputRectToInputRects(
_In_ const D2D1_RECT_L* pOutputRect,
_Out_writes_(inputRectCount) D2D1_RECT_L* pInputRects,
UINT32 inputRectCount
) const
{
// This effect has exactly 1 input.
if (inputRectCount != 1)
{
return E_INVALIDARG;
}
// 1:1 mapping of output to input rect.
pInputRects[0].left = pOutputRect->left;
pInputRects[0].top = pOutputRect->top;
pInputRects[0].right = pOutputRect->right;
pInputRects[0].bottom = pOutputRect->bottom;
return S_OK;
}
IFACEMETHODIMP SdrOverlayEffect::MapInputRectsToOutputRect(
_In_reads_(inputRectCount) CONST D2D1_RECT_L* pInputRects,
_In_reads_(inputRectCount) CONST D2D1_RECT_L* pInputOpaqueSubRects,
UINT32 inputRectCount,
_Out_ D2D1_RECT_L* pOutputRect,
_Out_ D2D1_RECT_L* pOutputOpaqueSubRect
)
{
// This effect has exactly 1 input.
if (inputRectCount != 1)
{
return E_INVALIDARG;
}
// 1:1 mapping of input to output rect.
*pOutputRect = pInputRects[0];
m_inputRect = pInputRects[0];
// This effect always outputs fully opaque pixels.
*pOutputOpaqueSubRect = pInputRects[0];
return S_OK;
}
IFACEMETHODIMP SdrOverlayEffect::MapInvalidRect(
UINT32 inputIndex,
D2D1_RECT_L invalidInputRect,
_Out_ D2D1_RECT_L* pInvalidOutputRect
) const
{
HRESULT hr = S_OK;
// Indicate that the entire output may be invalid.
*pInvalidOutputRect = m_inputRect;
return hr;
}
IFACEMETHODIMP_(UINT32) SdrOverlayEffect::GetInputCount() const
{
return 1;
}
// D2D ensures that that effects are only referenced from one thread at a time.
// To improve performance, we simply increment/decrement our reference count
// rather than use atomic InterlockedIncrement()/InterlockedDecrement() functions.
IFACEMETHODIMP_(ULONG) SdrOverlayEffect::AddRef()
{
m_refCount++;
return m_refCount;
}
IFACEMETHODIMP_(ULONG) SdrOverlayEffect::Release()
{
m_refCount--;
if (m_refCount == 0)
{
delete this;
return 0;
}
else
{
return m_refCount;
}
}
// This enables the stack of parent interfaces to be queried. In the instance
// of the SdrOverlay interface, this method simply enables the developer
// to cast a SdrOverlay instance to an ID2D1EffectImpl or IUnknown instance.
IFACEMETHODIMP SdrOverlayEffect::QueryInterface(
_In_ REFIID riid,
_Outptr_ void** ppOutput
)
{
*ppOutput = nullptr;
HRESULT hr = S_OK;
if (riid == __uuidof(ID2D1EffectImpl))
{
*ppOutput = reinterpret_cast<ID2D1EffectImpl*>(this);
}
else if (riid == __uuidof(ID2D1DrawTransform))
{
*ppOutput = static_cast<ID2D1DrawTransform*>(this);
}
else if (riid == __uuidof(ID2D1Transform))
{
*ppOutput = static_cast<ID2D1Transform*>(this);
}
else if (riid == __uuidof(ID2D1TransformNode))
{
*ppOutput = static_cast<ID2D1TransformNode*>(this);
}
else if (riid == __uuidof(IUnknown))
{
*ppOutput = this;
}
else
{
hr = E_NOINTERFACE;
}
if (*ppOutput != nullptr)
{
AddRef();
}
return hr;
}

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

@ -0,0 +1,88 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
// Not a tonemapper, instead demonstrates visually what would happen in SDR mode:
// - Truncates values to 8 bits per channel
// - Converts out of gamut colors to grayscale
DEFINE_GUID(GUID_SdrOverlayPixelShader, 0xfddf597e, 0x98d4, 0x4aac, 0x83, 0x49, 0x6f, 0xb8, 0x76, 0x67, 0xdc, 0xb5);
DEFINE_GUID(CLSID_CustomSdrOverlayEffect, 0x376c22b8, 0xe6c3, 0x41e7, 0xb1, 0xc1, 0xfb, 0x5f, 0x7e, 0xc9, 0xee, 0x49);
// Our effect contains one transform, which is simply a wrapper around a pixel shader. As such,
// we can simply make the effect itself act as the transform.
class SdrOverlayEffect : public ID2D1EffectImpl, public ID2D1DrawTransform
{
public:
// Declare effect registration methods.
static HRESULT Register(_In_ ID2D1Factory1* pFactory);
static HRESULT __stdcall CreateSdrOverlayImpl(_Outptr_ IUnknown** ppEffectImpl);
// Declare ID2D1EffectImpl implementation methods.
IFACEMETHODIMP Initialize(
_In_ ID2D1EffectContext* pContextInternal,
_In_ ID2D1TransformGraph* pTransformGraph
);
IFACEMETHODIMP PrepareForRender(D2D1_CHANGE_TYPE changeType);
IFACEMETHODIMP SetGraph(_In_ ID2D1TransformGraph* pGraph);
// Declare ID2D1DrawTransform implementation methods.
IFACEMETHODIMP SetDrawInfo(_In_ ID2D1DrawInfo* pRenderInfo);
// Declare ID2D1Transform implementation methods.
IFACEMETHODIMP MapOutputRectToInputRects(
_In_ const D2D1_RECT_L* pOutputRect,
_Out_writes_(inputRectCount) D2D1_RECT_L* pInputRects,
UINT32 inputRectCount
) const;
IFACEMETHODIMP MapInputRectsToOutputRect(
_In_reads_(inputRectCount) CONST D2D1_RECT_L* pInputRects,
_In_reads_(inputRectCount) CONST D2D1_RECT_L* pInputOpaqueSubRects,
UINT32 inputRectCount,
_Out_ D2D1_RECT_L* pOutputRect,
_Out_ D2D1_RECT_L* pOutputOpaqueSubRect
);
IFACEMETHODIMP MapInvalidRect(
UINT32 inputIndex,
D2D1_RECT_L invalidInputRect,
_Out_ D2D1_RECT_L* pInvalidOutputRect
) const;
// Declare ID2D1TransformNode implementation methods.
IFACEMETHODIMP_(UINT32) GetInputCount() const;
// Declare IUnknown implementation methods.
IFACEMETHODIMP_(ULONG) AddRef();
IFACEMETHODIMP_(ULONG) Release();
IFACEMETHODIMP QueryInterface(_In_ REFIID riid, _Outptr_ void** ppOutput);
// Declare property getter/setter methods.
private:
SdrOverlayEffect();
HRESULT UpdateConstants();
// This struct defines the constant buffer of our pixel shader.
struct
{
float dpi;
} m_constants;
Microsoft::WRL::ComPtr<ID2D1DrawInfo> m_drawInfo;
Microsoft::WRL::ComPtr<ID2D1EffectContext> m_effectContext;
LONG m_refCount;
D2D1_RECT_L m_inputRect;
float m_dpi;
};

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

@ -0,0 +1,41 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
// Custom effects using pixel shaders should use HLSL helper functions defined in
// d2d1effecthelpers.hlsli to make use of effect shader linking.
#define D2D_INPUT_COUNT 1 // The pixel shader takes exactly 1 input.
// Note that the custom build step must provide the correct path to find d2d1effecthelpers.hlsli when calling fxc.exe.
#include "d2d1effecthelpers.hlsli"
cbuffer constants : register(b0)
{
float dpi : packoffset(c0.x); // Ignored - there is no position-dependent behavior in the shader.
};
D2D_PS_ENTRY(main)
{
float4 output = D2DGetInput(0);
// Detect if any color component is outside of [0, 1] SDR numeric range.
float4 isOutsideSdrVec = abs(sign(output - saturate(output)));
float isOutsideSdr = max(max(isOutsideSdrVec.r, isOutsideSdrVec.g), isOutsideSdrVec.b); // 1 = out, 0 = in
float isInsideSdr = 1 - isOutsideSdr; // 0 = out, 1 = in
// Convert all sRGB/SDR colors to grayscale.
float lum = dot(float3(0.3f, 0.59f, 0.11f), output.rgb);
float4 insideSdrColor = float4(lum, lum, lum, 1.0f);
// Pass through wide gamut and high dynamic range colors.
float4 outsideSdrColor = float4(output.rgb, 1.0f);
return insideSdrColor * isInsideSdr + outsideSdrColor * isOutsideSdr;
}

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

@ -12,12 +12,15 @@
#pragma once
#include <agile.h>
#include <atlbase.h>
#include <algorithm>
#include <collection.h>
#include <concrt.h>
#include <memory>
#include <ppltasks.h>
#include <shcore.h>
#include <string>
#include <sstream>
#include <wrl.h>
#include <wrl/client.h>

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

@ -23,6 +23,8 @@ using namespace concurrency;
RadioModel::RadioModel(Radio^ radio, UIElement^ parent)
{
this->radio = radio;
// Controlling the mobile broadband radio requires a restricted capability.
this->isEnabled = (radio->Kind != RadioKind::MobileBroadband);
this->parent = parent;
this->radio->StateChanged += ref new TypedEventHandler<Radio^, Object^>(this, &RadioModel::Radio_StateChanged);
}

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

@ -18,7 +18,7 @@ namespace SDKTemplate
{
private:
Windows::Devices::Radios::Radio^ radio;
bool isEnabled = true;
bool isEnabled;
Windows::UI::Xaml::UIElement^ parent;
public:

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

@ -22,12 +22,14 @@ namespace RadioManagerSample
public class RadioModel : INotifyPropertyChanged
{
private Radio radio;
private bool isEnabled = true;
private bool isEnabled;
private UIElement parent;
public RadioModel(Radio radio, UIElement parent)
{
this.radio = radio;
// Controlling the mobile broadband radio requires a restricted capability.
this.isEnabled = (radio.Kind != RadioKind.MobileBroadband);
this.parent = parent;
this.radio.StateChanged += Radio_StateChanged;
}

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 241 B

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 276 B

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 287 B

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 618 B

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 892 B

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 1.0 KiB

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

@ -252,24 +252,30 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
<Image Include="Assets\microsoftLogo.scale-100.png">
<Image Include="..\shared\assets\microsoftLogo.scale-100.png">
<Link>Assets\microsoftLogo.scale-100.png</Link>
</Image>
<Image Include="Assets\microsoftLogo.scale-140.png">
<Image Include="..\shared\assets\microsoftLogo.scale-140.png">
<Link>Assets\microsoftLogo.scale-140.png</Link>
</Image>
<Image Include="Assets\microsoftLogo.scale-180.png">
<Image Include="..\shared\assets\microsoftLogo.scale-180.png">
<Link>Assets\microsoftLogo.scale-180.png</Link>
</Image>
<Image Include="Assets\visualStudioLogo.scale-100.png">
<Image Include="..\shared\assets\microsoftLogo.scale-200.png">
<Link>Assets\microsoftLogo.scale-200.png</Link>
</Image>
<Image Include="..\shared\assets\visualStudioLogo.scale-100.png">
<Link>Assets\visualStudioLogo.scale-100.png</Link>
</Image>
<Image Include="Assets\visualStudioLogo.scale-140.png">
<Image Include="..\shared\assets\visualStudioLogo.scale-140.png">
<Link>Assets\visualStudioLogo.scale-140.png</Link>
</Image>
<Image Include="Assets\visualStudioLogo.scale-180.png">
<Image Include="..\shared\assets\visualStudioLogo.scale-180.png">
<Link>Assets\visualStudioLogo.scale-180.png</Link>
</Image>
<Image Include="..\shared\assets\visualStudioLogo.scale-200.png">
<Link>Assets\visualStudioLogo.scale-200.png</Link>
</Image>
<Image Include="..\..\..\SharedContent\media\microsoft-sdk.png">
<Link>Assets\microsoft-sdk.png</Link>
</Image>

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

@ -31,6 +31,9 @@
<Image Include="..\shared\assets\microsoftLogo.scale-180.png">
<Filter>Assets</Filter>
</Image>
<Image Include="..\shared\assets\microsoftLogo.scale-200.png">
<Filter>Assets</Filter>
</Image>
<Image Include="..\shared\assets\visualStudioLogo.scale-100.png">
<Filter>Assets</Filter>
</Image>
@ -40,6 +43,9 @@
<Image Include="..\shared\assets\visualStudioLogo.scale-180.png">
<Filter>Assets</Filter>
</Image>
<Image Include="..\shared\assets\visualStudioLogo.scale-200.png">
<Filter>Assets</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="..\..\..\SharedContent\xaml\App.xaml" />

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

@ -220,6 +220,9 @@
<Content Include="..\shared\assets\microsoftLogo.scale-180.png">
<Link>Assets\microsoftLogo.scale-180.png</Link>
</Content>
<Content Include="..\shared\assets\microsoftLogo.scale-200.png">
<Link>Assets\microsoftLogo.scale-200.png</Link>
</Content>
<Content Include="..\shared\assets\visualStudioLogo.scale-100.png">
<Link>Assets\visualStudioLogo.scale-100.png</Link>
</Content>
@ -229,6 +232,9 @@
<Content Include="..\shared\assets\visualStudioLogo.scale-180.png">
<Link>Assets\visualStudioLogo.scale-180.png</Link>
</Content>
<Content Include="..\shared\assets\visualStudioLogo.scale-200.png">
<Link>Assets\visualStudioLogo.scale-200.png</Link>
</Content>
<Content Include="..\..\..\SharedContent\media\microsoft-sdk.png">
<Link>Assets\microsoft-sdk.png</Link>
</Content>

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

@ -99,6 +99,9 @@
<Content Include="..\shared\assets\microsoftLogo.scale-180.png">
<Link>images\microsoftLogo.scale-180.png</Link>
</Content>
<Content Include="..\shared\assets\microsoftLogo.scale-200.png">
<Link>images\microsoftLogo.scale-200.png</Link>
</Content>
<Content Include="..\shared\assets\visualStudioLogo.scale-100.png">
<Link>images\visualStudioLogo.scale-100.png</Link>
</Content>
@ -108,6 +111,9 @@
<Content Include="..\shared\assets\visualStudioLogo.scale-180.png">
<Link>images\visualStudioLogo.scale-180.png</Link>
</Content>
<Content Include="..\shared\assets\visualStudioLogo.scale-200.png">
<Link>images\visualStudioLogo.scale-200.png</Link>
</Content>
<Content Include="..\..\..\SharedContent\js\js\default.js">
<Link>js\default.js</Link>
</Content>

Двоичные данные
Samples/ShareSource/shared/assets/microsoftLogo.scale-200.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 398 B

Двоичные данные
Samples/ShareSource/shared/assets/visualStudioLogo.scale-200.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.3 KiB

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

@ -35,13 +35,16 @@
<ScrollViewer Grid.Row="1" VerticalScrollMode="Auto" VerticalScrollBarVisibility="Auto">
<StackPanel Orientation="Vertical" VerticalAlignment="Top">
<TextBlock Style="{StaticResource BasicTextStyle}">Use these SID values to register the app with Facebook.</TextBlock>
<TextBlock Style="{StaticResource BasicTextStyle}">Windows Store SID: <Run x:Name="WindowsStoreSidTextBlock"/></TextBlock>
<TextBlock Style="{StaticResource BasicTextStyle}">Windows Phone Store SID: <Run x:Name="WindowsPhoneStoreSidTextBlock"/></TextBlock>
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<TextBlock Style="{StaticResource BasicTextStyle}" Text="App ID: " VerticalAlignment="Center" Width="125"/>
<TextBox x:Name="FacebookClientID" Height="14" Width="200" Text=""/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<TextBlock Style="{StaticResource BasicTextStyle}" Text="Site URL: " VerticalAlignment="Center" Width="125"/>
<TextBox x:Name="FacebookCallbackUrl" Height="14" Width="200" Text=""/>
<TextBox x:Name="FacebookCallbackUrl" Height="14" Width="200" Text="https://www.facebook.com/connect/login_success.html"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<TextBox x:Name="FacebookReturnedToken" Width="325" Text="Press Launch to view returned token..." IsEnabled="False"/>

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

@ -22,6 +22,10 @@ using namespace Windows::UI::Xaml::Navigation;
Scenario2_oAuthFacebook::Scenario2_oAuthFacebook()
{
InitializeComponent();
// Use these SIDs to register the app with Facebook.
WindowsStoreSidTextBlock->Text = WebAuthenticationBroker::GetCurrentApplicationCallbackUri()->Host;
WindowsPhoneStoreSidTextBlock->Text = "f48e0417-873f-476c-97a2-2d25c5fa2dc7"; // copied from Package.appxmanifest
}
void Scenario2_oAuthFacebook::Launch_Click(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
@ -31,14 +35,15 @@ void Scenario2_oAuthFacebook::Launch_Click(Object^ sender, Windows::UI::Xaml::Ro
String^ facebookURL = "https://www.facebook.com/dialog/oauth?client_id=";
auto clientID = FacebookClientID->Text;
if (clientID == nullptr || clientID->IsEmpty())
if (clientID->IsEmpty())
{
MainPage::Current->NotifyUser("Enter a ClientID", NotifyType::ErrorMessage);
return;
}
if(FacebookCallbackUrl->Text == "")
if(FacebookCallbackUrl->Text->IsEmpty())
{
MainPage::Current->NotifyUser("Enter a Callback URL", NotifyType::ErrorMessage);
return;
}
facebookURL += clientID + "&redirect_uri=" + Uri::EscapeComponent(FacebookCallbackUrl->Text) + "&scope=read_stream&display=popup&response_type=token";
@ -48,7 +53,7 @@ void Scenario2_oAuthFacebook::Launch_Click(Object^ sender, Windows::UI::Xaml::Ro
auto facebookToken = FacebookReturnedToken;
auto startURI = ref new Uri(facebookURL);
auto endURI = ref new Uri("https://www.facebook.com/connect/login_success.html");
auto endURI = ref new Uri(FacebookCallbackUrl->Text);
MainPage::Current->NotifyUser("Navigating to: " + facebookURL + "\n", NotifyType::StatusMessage);
create_task(WebAuthenticationBroker::AuthenticateAsync(WebAuthenticationOptions::None, startURI, endURI)).then([this](WebAuthenticationResult^ result)

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

@ -34,4 +34,20 @@ namespace SDKTemplate
public string Title { get; set; }
public Type ClassType { get; set; }
}
public static class FormDecoderExtensions
{
public static string TryGetValue(this Windows.Foundation.WwwFormUrlDecoder decoder, string name)
{
try
{
return decoder.GetFirstValueByName(name);
}
catch (ArgumentException)
{
return null;
}
}
}
}

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

@ -19,43 +19,27 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="RootGrid" Margin="12,20,12,12">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Margin="0,0,0,10">
<TextBlock Text="Description:" Style="{StaticResource SampleHeaderTextStyle}"/>
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap">
Connect to Facebook using the OAuth 2.0 protocol for authentication and authorization.
</TextBlock>
<ScrollViewer Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Padding="12,20,12,12">
<StackPanel Margin="0,0,0,10">
<TextBlock Text="Description:" Style="{StaticResource SampleHeaderTextStyle}"/>
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap">
Connect to Facebook using the OAuth 2.0 protocol for authentication and authorization.
</TextBlock>
<TextBlock Style="{StaticResource BasicTextStyle}">Use these SID values to register the app with Facebook.</TextBlock>
<TextBlock>Windows Store SID: <Run x:Name="WindowsStoreSidTextBlock"/></TextBlock>
<TextBlock>Windows Phone Store SID: <Run x:Name="WindowsPhoneStoreSidTextBlock"/></TextBlock>
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<TextBlock Style="{StaticResource BasicTextStyle}" Text="App ID: " VerticalAlignment="Center" Width="85"/>
<TextBox x:Name="FacebookClientID" Height="14" Width="200" Text=""/>
</StackPanel>
<ScrollViewer Grid.Row="1" VerticalScrollMode="Auto" VerticalScrollBarVisibility="Auto">
<StackPanel Orientation="Vertical" VerticalAlignment="Top">
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<TextBlock Style="{StaticResource BasicTextStyle}" Text="App ID: " VerticalAlignment="Center" Width="85"/>
<TextBox x:Name="FacebookClientID" Height="14" Width="200" Text=""/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<TextBlock Style="{StaticResource BasicTextStyle}" Text="Site URL: " VerticalAlignment="Center" Width="85"/>
<TextBox x:Name="FacebookCallbackUrl" Height="14" Width="200" Text=""/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<TextBox x:Name="FacebookReturnedToken" Width="285" Text="Press Launch to view returned token..." IsEnabled="False"/>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0,10,0,0">
<Button x:Name="Launch" Content="Launch" Width="285" Click="Launch_Click"/>
</StackPanel>
</StackPanel>
</ScrollViewer>
<!-- Status Block for providing messages to the user. Use the
NotifyUser() method to populate the message -->
<Border x:Name="ErrorBorder" Background="Red" Grid.Row="2"/>
<TextBlock x:Name="StatusBlock" Grid.Row="2" Margin="12, 10, 12, 10" Visibility="Collapsed"/>
</Grid>
</Grid>
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<TextBlock Style="{StaticResource BasicTextStyle}" Text="Site URL: " VerticalAlignment="Center" Width="85"/>
<TextBox x:Name="FacebookCallbackUrl" Height="14" Width="200" Text="https://www.facebook.com/connect/login_success.html"/>
</StackPanel>
<Button x:Name="Launch" Content="Launch" Click="Launch_Click" Margin="0,10,0,0"/>
<TextBlock Margin="0,10,0,0">Token: <Run x:Name="FacebookReturnedToken"/></TextBlock>
<TextBlock Margin="0,10,0,0">User Name: <Run x:Name="FacebookUserName"/></TextBlock>
</StackPanel>
</ScrollViewer>
</Page>

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

@ -13,6 +13,7 @@ using SDKTemplate;
using System;
using System.Threading.Tasks;
using Windows.Data.Json;
using Windows.Foundation;
using Windows.Security.Authentication.Web;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
@ -23,50 +24,60 @@ namespace WebAuthentication
public sealed partial class Scenario1_Facebook : Page
{
private MainPage rootPage = MainPage.Current;
bool authzInProgress = false;
public Scenario1_Facebook()
{
this.InitializeComponent();
}
private void OutputToken(String TokenUri)
{
FacebookReturnedToken.Text = TokenUri;
// Use these SIDs to register the app with Facebook.
WindowsStoreSidTextBlock.Text = WebAuthenticationBroker.GetCurrentApplicationCallbackUri().Host;
WindowsPhoneStoreSidTextBlock.Text = "feaebe20-b974-4857-a51c-3525e4dfe2a8"; // copied from Package.appxmanifest
}
private async void Launch_Click(object sender, RoutedEventArgs e)
{
if (FacebookClientID.Text == "")
if (authzInProgress)
{
rootPage.NotifyUser("Please enter an Client ID.", NotifyType.StatusMessage);
}
else if (FacebookCallbackUrl.Text == "")
{
rootPage.NotifyUser("Please enter an Callback URL.", NotifyType.StatusMessage);
return;
}
FacebookReturnedToken.Text = "";
FacebookUserName.Text = "";
if (String.IsNullOrEmpty(FacebookClientID.Text))
{
rootPage.NotifyUser("Please enter a Client ID.", NotifyType.StatusMessage);
return;
}
Uri callbackUri;
if (!Uri.TryCreate(FacebookCallbackUrl.Text, UriKind.Absolute, out callbackUri))
{
rootPage.NotifyUser("Please enter a Callback URL.", NotifyType.StatusMessage);
return;
}
Uri facebookStartUri = new Uri($"https://www.facebook.com/dialog/oauth?client_id={Uri.EscapeDataString(FacebookClientID.Text)}&redirect_uri={Uri.EscapeDataString(callbackUri.AbsoluteUri)}&scope=email&display=popup&response_type=token");
rootPage.NotifyUser($"Navigating to {facebookStartUri}", NotifyType.StatusMessage);
authzInProgress = true;
try
{
String FacebookURL = "https://www.facebook.com/dialog/oauth?client_id=" + Uri.EscapeDataString(FacebookClientID.Text) + "&redirect_uri=" + Uri.EscapeDataString(FacebookCallbackUrl.Text) + "&scope=read_stream&display=popup&response_type=token";
System.Uri StartUri = new Uri(FacebookURL);
System.Uri EndUri = new Uri(FacebookCallbackUrl.Text);
rootPage.NotifyUser("Navigating to: " + FacebookURL, NotifyType.StatusMessage);
WebAuthenticationResult WebAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None, StartUri, EndUri);
WebAuthenticationResult WebAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None, facebookStartUri, callbackUri);
if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.Success)
{
OutputToken(WebAuthenticationResult.ResponseData.ToString());
await GetFacebookUserNameAsync(WebAuthenticationResult.ResponseData.ToString());
FacebookReturnedToken.Text = WebAuthenticationResult.ResponseData;
await GetFacebookUserNameAsync(WebAuthenticationResult.ResponseData);
}
else if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.ErrorHttp)
{
OutputToken("HTTP Error returned by AuthenticateAsync() : " + WebAuthenticationResult.ResponseErrorDetail.ToString());
FacebookReturnedToken.Text = $"HTTP error: {WebAuthenticationResult.ResponseErrorDetail}";
}
else
{
OutputToken("Error returned by AuthenticateAsync() : " + WebAuthenticationResult.ResponseStatus.ToString());
FacebookReturnedToken.Text = $"Error: {WebAuthenticationResult.ResponseStatus}";
}
}
@ -74,42 +85,41 @@ namespace WebAuthentication
{
rootPage.NotifyUser(Error.Message, NotifyType.ErrorMessage);
}
authzInProgress = false;
}
/// <summary>
/// This function extracts access_token from the response returned from web authentication broker
/// and uses that token to get user information using facebook graph api.
/// </summary>
/// <param name="webAuthResultResponseData">responseData returned from AuthenticateAsync result.</param>
private async Task GetFacebookUserNameAsync(string webAuthResultResponseData)
/// <param name="responseData">responseData returned from AuthenticateAsync result.</param>
private async Task GetFacebookUserNameAsync(string responseData)
{
//Get Access Token first
string responseData = webAuthResultResponseData.Substring(webAuthResultResponseData.IndexOf("access_token"));
String[] keyValPairs = responseData.Split('&');
string access_token = null;
string expires_in = null;
for (int i = 0; i < keyValPairs.Length; i++)
var decoder = new WwwFormUrlDecoder(responseData);
var error = decoder.TryGetValue("error");
if (error != null)
{
String[] splits = keyValPairs[i].Split('=');
switch (splits[0])
{
case "access_token":
access_token = splits[1]; //you may want to store access_token for further use. Look at Scenario 5 (Account Management).
break;
case "expires_in":
expires_in = splits[1];
break;
}
FacebookUserName.Text = $"Error: {error}";
return;
}
rootPage.NotifyUser("access_token = " + access_token, NotifyType.StatusMessage);
//Request User info.
HttpClient httpClient = new HttpClient();
string response = await httpClient.GetStringAsync(new Uri("https://graph.facebook.com/me?access_token=" + access_token));
JsonObject value = JsonValue.Parse(response).GetObject();
string facebookUserName = value.GetNamedString("name");
// You can store access token locally for further use.
string access_token = decoder.GetFirstValueByName("access_token");
string expires_in = decoder.TryGetValue("expires_in"); // expires_in is optional
rootPage.NotifyUser(facebookUserName + " is connected!", NotifyType.StatusMessage);
HttpClient httpClient = new HttpClient();
Uri uri = new Uri($"https://graph.facebook.com/me?access_token={Uri.EscapeDataString(access_token)}");
try
{
string response = await httpClient.GetStringAsync(uri);
JsonObject userInfo = JsonObject.Parse(response).GetObject();
FacebookUserName.Text = userInfo.GetNamedString("name");
}
catch (Exception)
{
FacebookUserName.Text = "Error contacting Facebook";
}
}
}
}

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

@ -19,21 +19,24 @@ Copyright (c) Microsoft Corporation. All rights reserved
</div>
</div>
<div id="scenarioContent">
<div>Use these SID values to register the app with Facebook.</div>
<div>Windows Store SID: <span id="windowsStoreSidText"></span></div>
<div>Windows Phone Store SID: <span id="windowsPhoneStoreSidText"></span></div>
<table>
<tr>
<td>
<label for="FacebookClientID">Facebook App ID: </label>
<label for="facebookClientID">Facebook App ID: </label>
</td>
<td>
<input type="text" id="FacebookClientID" value="" class="win-textbox">
<input type="text" id="facebookClientID" value="" class="win-textbox">
</td>
</tr>
<tr>
<td>
<label for="FacebookCallbackURL">Callback URL: </label>
<label for="facebookCallbackURL">Callback URL: </label>
</td>
<td>
<input type="text" id="FacebookCallbackURL" value="https://www.facebook.com/connect/login_success.html" class="win-textbox">
<input type="text" id="facebookCallbackURL" value="https://www.facebook.com/connect/login_success.html" class="win-textbox">
</td>
</tr>
<tr>
@ -44,10 +47,16 @@ Copyright (c) Microsoft Corporation. All rights reserved
</tr>
<tr>
<td class="labelTD">
<label for="FacebookReturnedToken">Token: </label>
<label for="facebookReturnedToken">Token: </label>
</td>
<td id="facebookReturnedToken">
</td>
</tr>
<tr>
<td>
<input type="text" size="106" id="FacebookReturnedToken" class="win-textbox">
<label for="facebookUserName">User Name: </label>
</td>
<td id="facebookUserName">
</td>
</tr>
</table>

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

@ -12,8 +12,17 @@
{ url: "/html/scenario4.html", title: "Connect to Google Services" }
];
function tryGetFormValue(decoder, name) {
try {
return decoder.getFirstValueByName(name);
} catch (e) {
return null;
}
}
WinJS.Namespace.define("SdkSample", {
sampleTitle: sampleTitle,
scenarios: new WinJS.Binding.List(scenarios)
scenarios: new WinJS.Binding.List(scenarios),
tryGetFormValue: tryGetFormValue
});
})();

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

@ -2,125 +2,109 @@
(function () {
"use strict";
var WebAuthenticationBroker = Windows.Security.Authentication.Web.WebAuthenticationBroker;
var WebAuthenticationOptions = Windows.Security.Authentication.Web.WebAuthenticationOptions;
var WebAuthenticationStatus = Windows.Security.Authentication.Web.WebAuthenticationStatus;
var facebookUserName;
var facebookClientID;
var facebookCallbackURL;
var facebookReturnedToken;
var page = WinJS.UI.Pages.define("/html/scenario1.html", {
ready: function (element, options) {
facebookUserName = document.getElementById("facebookUserName");
facebookClientID = document.getElementById("facebookClientID");
facebookCallbackURL = document.getElementById("facebookCallbackURL");
facebookReturnedToken = document.getElementById("facebookReturnedToken");
document.getElementById("oAuthFacebookLaunch").addEventListener("click", launchFacebookWebAuth, false);
// Continuation handlers are specific to Windows Phone.
if (options && options.activationKind === Windows.ApplicationModel.Activation.ActivationKind.webAuthenticationBrokerContinuation) {
continueWebAuthentication(options.activatedEventArgs);
}
// Use these SIDs to register the app with Facebook.
document.getElementById("windowsStoreSidText").textValue = WebAuthenticationBroker.getCurrentApplicationCallbackUri().host;
document.getElementById("windowsPhoneStoreSidText").textValue = "5119c4a4-bfe3-404f-981b-9ad93ac49802"; // copied from Package.appxmanifest
}
});
function isValidUriString(uriString) {
var uri = null;
function tryParseUri(uriString) {
try {
uri = new Windows.Foundation.Uri(uriString);
return new Windows.Foundation.Uri(uriString);
} catch (err) {
return null;
}
catch (err) {
}
return uri !== null;
}
var authzInProgress = false;
function launchFacebookWebAuth() {
var facebookURL = "https://www.facebook.com/dialog/oauth?client_id=";
if (authzInProgress) {
return;
}
var clientID = document.getElementById("FacebookClientID").value;
facebookUserName.textContent = "";
facebookReturnedToken.textContent = "";
var clientID = facebookClientID.value;
if (clientID === null || clientID === "") {
WinJS.log("Enter a ClientID", "Web Authentication SDK Sample", "error");
return;
}
var callbackURL = document.getElementById("FacebookCallbackURL").value;
if (!isValidUriString(callbackURL)) {
var callbackUri = tryParseUri(facebookCallbackURL.value);
if (!callbackUri) {
WinJS.log("Enter a valid Callback URL for Facebook", "Web Authentication SDK Sample", "error");
return;
}
facebookURL += clientID + "&redirect_uri=" + encodeURIComponent(callbackURL) + "&scope=read_stream&display=popup&response_type=token";
var facebookStartUri = new Windows.Foundation.Uri(`https://www.facebook.com/dialog/oauth?` +
`client_id=${encodeURIComponent(clientID)}&redirect_uri=${encodeURIComponent(callbackUri)}` +
`&scope=read_stream&display=popup&response_type=token`);
if (authzInProgress) {
WinJS.log("Authorization already in Progress...", "Web Authentication SDK Sample", "status");
return;
}
var startURI = new Windows.Foundation.Uri(facebookURL);
var endURI = new Windows.Foundation.Uri(callbackURL);
WinJS.log("Navigating to: " + facebookURL, "Web Authentication SDK Sample", "status");
WinJS.log(`Navigating to ${facebookStartUri}`, "Web Authentication SDK Sample", "status");
authzInProgress = true;
if (Windows.Security.Authentication.Web.WebAuthenticationBroker.authenticateAndContinue) {
Windows.Security.Authentication.Web.WebAuthenticationBroker.authenticateAndContinue(startURI, endURI, null, Windows.Security.Authentication.Web.WebAuthenticationOptions.none);
}
else {
Windows.Security.Authentication.Web.WebAuthenticationBroker.authenticateAsync(
Windows.Security.Authentication.Web.WebAuthenticationOptions.none, startURI, endURI)
.done(function (result) {
document.getElementById("FacebookReturnedToken").value = result.responseData;
WinJS.log("Status returned by WebAuth broker: " + result.responseStatus, "Web Authentication SDK Sample", "status");
getfacebookUserName(result.responseData);
if (result.responseStatus === Windows.Security.Authentication.Web.WebAuthenticationStatus.errorHttp) {
WinJS.log("Error returned: " + result.responseErrorDetail, "Web Authentication SDK Sample", "error");
}
authzInProgress = false;
}, function (err) {
WinJS.log("Error returned by WebAuth broker: " + err, "Web Authentication SDK Sample", "error");
authzInProgress = false;
});
}
}
//
//This function is Continuation handler for Windows Phone App
//
function continueWebAuthentication(args) {
var result = args[0].webAuthenticationResult;
if (result.responseStatus === Windows.Security.Authentication.Web.WebAuthenticationStatus.success) {
document.getElementById("FacebookReturnedToken").value = result.responseData;
}
else if (result.responseStatus === Windows.Security.Authentication.Web.WebAuthenticationStatus.errorHttp) {
document.getElementById("FacebookDebugArea").value += "Error returned: " + result.responseErrorDetail + "\r\n";
}
else {
document.getElementById("FacebookDebugArea").value += "Status returned by WebAuth broker: " + result.responseStatus + "\r\n";
}
authzInProgress = false;
WebAuthenticationBroker.authenticateAsync(WebAuthenticationOptions.none, facebookStartUri, callbackUri)
.then(function (result) {
facebookReturnedToken.textValue = result.responseData;
if (result.responseStatus === WebAuthenticationStatus.success) {
return getFacebookUserNameAsync(result.responseData);
} else if (result.responseStatus === WebAuthenticationStatus.errorHttp) {
WinJS.log(`HTTP error: ${result.responseErrorDetail}`, "Web Authentication SDK Sample", "error");
} else {
WinJS.log(`Error: ${result.responseStatus}`, "Web Authentication SDK Sample", "status");
}
}, function (err) {
WinJS.log("Error returned by WebAuth broker: " + err, "Web Authentication SDK Sample", "error");
}).done(function () {
authzInProgress = false;
});
}
/// <summary>
/// This function extracts access_token from the response returned from web authentication broker
/// and uses that token to get user information using facebook graph api.
/// </summary>
function getfacebookUserName(webAuthResultResponseData) {
var responseData = webAuthResultResponseData.substring(webAuthResultResponseData.indexOf("access_token"));
var keyValPairs = responseData.split("&");
var access_token;
var expires_in;
for (var i = 0; i < keyValPairs.length; i++) {
var splits = keyValPairs[i].split("=");
switch (splits[0]) {
case "access_token":
access_token = splits[1]; //You can store access token locally for further use. See "Account Management" scenario for usage.
break;
case "expires_in":
expires_in = splits[1];
break;
}
function getFacebookUserNameAsync(responseData) {
var decoder = new Windows.Foundation.WwwFormUrlDecoder(responseData);
var error = SdkSample.tryGetFormValue(decoder, "error");
if (error) {
facebookUserName.textContent = `Error: ${error}`;
return;
}
document.getElementById("FacebookDebugArea").value += "\r\naccess_token = " + access_token + "\r\n";
// You can store access token locally for further use.
var access_token = decoder.getFirstValueByName("access_token");
var expires_in = SdkSample.tryGetFormValue(decoder, "expires_in"); // expires_in is optional
var client = new Windows.Web.Http.HttpClient();
client.getStringAsync(new Windows.Foundation.Uri("https://graph.facebook.com/me?access_token=" + access_token)).done(function (result) {
var uri = new Windows.Foundation.Uri(`https://graph.facebook.com/me?access_token=${encodeURIComponent(access_token)}`);
return client.getStringAsync(uri).then(function (result) {
var userInfo = JSON.parse(result);
document.getElementById("FacebookDebugArea").value += userInfo.name + " is connected!! \r\n";
facebookUserName.textContent = userInfo.name;
}, function (err) {
facebookUserName.textContent = "Error contacting Facebook";
});
}
})();

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

@ -29,15 +29,19 @@ namespace AppUIBasics.ControlPages
{
this.InitializeComponent();
List<string> calendarIdentifiers = new List<string>();
var cidmethods = typeof(CalendarIdentifiers).GetRuntimeMethods();
foreach (var m in cidmethods)
List<string> calendarIdentifiers = new List<string>()
{
if (m.Name.Substring(0, 4) == "get_")
{
calendarIdentifiers.Add(m.Invoke(null, null).ToString());
}
}
CalendarIdentifiers.Gregorian,
CalendarIdentifiers.Hebrew,
CalendarIdentifiers.Hijri,
CalendarIdentifiers.Japanese,
CalendarIdentifiers.Julian,
CalendarIdentifiers.Korean,
CalendarIdentifiers.Persian,
CalendarIdentifiers.Taiwan,
CalendarIdentifiers.Thai,
CalendarIdentifiers.UmAlQura,
};
calendarIdentifier.ItemsSource = calendarIdentifiers;
calendarIdentifier.SelectedItem = CalendarIdentifiers.Gregorian;

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

@ -8,8 +8,8 @@
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.16299.0</WindowsTargetPlatformMinVersion>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.17134.0</WindowsTargetPlatformMinVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<ItemGroup Label="ProjectConfigurations">

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

@ -11,8 +11,8 @@
<AssemblyName>$safeprojectname$</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.16299.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
<TargetPlatformVersion>10.0.17134.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.17134.0</TargetPlatformMinVersion>
<MinimumVisualStudioVersion>15</MinimumVisualStudioVersion>
<EnableDotNetNativeCompatibleProfile>true</EnableDotNetNativeCompatibleProfile>
<FileAlignment>512</FileAlignment>

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

@ -45,8 +45,8 @@
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\$(WMSJSProjectDirectory)\Microsoft.VisualStudio.$(WMSJSProject).props" />
<PropertyGroup>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.16299.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
<TargetPlatformVersion>10.0.17134.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.17134.0</TargetPlatformMinVersion>
<MinimumVisualStudioVersion>$(VersionNumberMajor).$(VersionNumberMinor)</MinimumVisualStudioVersion>
<DefaultLanguage>en-US</DefaultLanguage>
</PropertyGroup>