Windows 10 Version 1803 - July 2018 Update
|
@ -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)' < '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, ¤tOutput) != 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;
|
||||
}
|
||||
|
|
Двоичные данные
Samples/ShareSource/cpp/Assets/microsoftLogo.scale-100.png
До Ширина: | Высота: | Размер: 241 B |
Двоичные данные
Samples/ShareSource/cpp/Assets/microsoftLogo.scale-140.png
До Ширина: | Высота: | Размер: 276 B |
Двоичные данные
Samples/ShareSource/cpp/Assets/microsoftLogo.scale-180.png
До Ширина: | Высота: | Размер: 287 B |
Двоичные данные
Samples/ShareSource/cpp/Assets/visualStudioLogo.scale-100.png
До Ширина: | Высота: | Размер: 618 B |
Двоичные данные
Samples/ShareSource/cpp/Assets/visualStudioLogo.scale-140.png
До Ширина: | Высота: | Размер: 892 B |
Двоичные данные
Samples/ShareSource/cpp/Assets/visualStudioLogo.scale-180.png
До Ширина: | Высота: | Размер: 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>
|
||||
|
|
После Ширина: | Высота: | Размер: 398 B |
После Ширина: | Высота: | Размер: 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>
|
||||
|
|