Windows Information Protection (WIP) developer guide (C++)

An enlightened app differentiates between corporate and personal data and knows which to protect based on Windows Information Protection (WIP) policies defined by the administrator.

In this guide, we'll show you how to build one. When you're done, policy administrators will be able to trust your app to consume their organization's data. And employees will love that you've kept their personal data intact on their device even if they un-enroll from the organization's mobile device management (MDM) or leave the organization entirely.

You'll do these things to enlighten your app:

Note

This guide helps you enlighten a C++ Windows desktop app. If you want to enlighten a UWP app, see Windows Information Protection developer guide (UWP).

 

You can read more about WIP and enlightened apps here: Windows Information Protection (WIP).

If you're ready, let's start.

Gather what you need

You'll need these:

  • A test Virtual Machine (VM) that runs Windows 10, version 1607. You'll debug your app against this test VM.
  • A development computer that runs Windows 10, version 1607. This could be your test VM if you have Visual Studio installed on it.

Setup your development environment

You'll do these things:

Install the WIP Setup Developer Assistant onto your test VM

Use this tool to setup a Windows Information Protection policy on your test VM.

Download the tool here: WIP Setup Developer Assistant.

Create a protection policy by using the WIP Setup Developer Assistant

Define your policy by adding information to each section in the WIP setup developer assistant. Choose the help icon next to any setting to learn more about how to use it.

For more general guidance about how to use this tool, see the Version notes section on the app download page.

Setup a Visual Studio project (C++/CX only)

If you plan to use C++/CX, you'll have to configure a few things in your project. If you're planing to use standard C++, you can skip this section.

  1. On your development computer, open your project.

  2. Open the properties pages for your project.

  3. In the General settings of the C/C++ settings group, set the Consume Windows Runtime Extension setting to Yes(/ZW). enable c++ app to consume winrt extensions.

  4. In the Code Generation settings of the C/C++ settings group, set the Enable Minimal Rebuild setting to No(/GM-). disable minimal rebuild.

  5. Add the path to the Windows.winmd and Platform.winmd files to the Additional #using Directories location.

    By default, you'll find the Windows.winmd file in the C:\Program Files (x86)\Windows Kits\10\UnionMetadata directory and the Platform.winmd file in the C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcpackages directory.

    add the paths to windows.winmd and platform.winmd

  6. Decorate the main function of your app with an attribute that indicates which threading apartment model you're using.

    Single-threaded apartment model

    [Platform::STAThread]
    int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                         _In_opt_ HINSTANCE hPrevInstance,
                         _In_ LPWSTR    lpCmdLine,
                         _In_ int       nCmdShow)
    

    Multi-threaded apartment model

    [Platform::MTAThread]
    int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                         _In_opt_ HINSTANCE hPrevInstance,
                         _In_ LPWSTR    lpCmdLine,
                         _In_ int       nCmdShow)
    

Setup remote debugging

Install Visual Studio Remote Tools on your test VM only if you are developing your app on a computer other than your VM. Then, on your development computer start the remote debugger and see if your app runs on the target computer.

See Remote PC instructions.

Include the right header files

C++ projects

#include <string>
#include "ppltasks.h"
#include "stdafx.h"

#include <cstdlib>
#include <stdio.h>
#include <efswrtinterop.h>
#include <Windows.Foundation.h>
#include <Windows.Security.EnterpriseData.h>
#include <windows.web.h>
#include <windows.web.http.h>
#include <windows.web.http.filters.h>
#include <windows.web.http.headers.h>
#include <Windows.Foundation.Metadata.h>
#include <windows.security.cryptography.h>
#include <Windows.System.Threading.h>
#include <windows.ui.h>
#include <windows.ui.xaml.h>
#include <wrl\wrappers\corewrappers.h>
#include <wrl\client.h>
#include <wrl\event.h>

C++/CX projects

#include "stdafx.h"
#include "ppltasks.h"

#include <string>
#include <stdio.h>
#include <cstdlib>
#include <new>

Add the right namespaces

C++ projects

using namespace Concurrency;
using namespace ABI::Windows::ApplicationModel::Activation;
using namespace ABI::Windows::ApplicationModel::DataTransfer;
using namespace ABI::Windows::Data::Xml::Dom;
using namespace ABI::Windows::Devices::Enumeration;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Foundation::Metadata;
using namespace ABI::Windows::Networking;
using namespace ABI::Windows::Security::Cryptography;
using namespace ABI::Windows::Security::EnterpriseData;
using namespace ABI::Windows::System::Threading;
using namespace ABI::Windows::Storage;
using namespace ABI::Windows::Web::Http;
using namespace ABI::Windows::Web::Http::Filters;
using namespace ABI::Windows::Web::Http::Headers;
using namespace ABI::Windows::Storage::Streams;
using namespace ABI::Windows::UI::Xaml;
using namespace ABI::Windows::UI::Xaml::Controls;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;

C++/ CX projects

using namespace Concurrency;
using namespace Windows;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::ApplicationModel::DataTransfer;
using namespace Windows::Data::Xml::Dom;
using namespace Windows::Devices::Enumeration;
using namespace Windows::Foundation;
using namespace Windows::Networking;
using namespace Windows::Security::Cryptography;
using namespace Windows::Security::EnterpriseData;
using namespace Windows::Storage;
using namespace Windows::Storage::Streams;
using namespace Windows::System::Threading;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml;
using namespace Windows::Web::Http;
using namespace Windows::Web::Http::Headers;
using namespace Windows::Web::Http::Filters;
using namespace Windows::Web::Http::Headers;

Determine whether to use WIP APIs in your app

Ensure that the operating system that runs your app supports WIP and that WIP is enabled on the device.

C++ snippet

RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);

ComPtr<IApiInformationStatics> apiStatics;

Windows::Foundation::GetActivationFactory
 (HStringReference(RuntimeClass_Windows_Foundation_Metadata_ApiInformation).Get(), &amp;apiStatics);

boolean operating_System_Support;

HString contractName;
  contractName.Set(L"Windows.Security.EnterpriseData.EnterpriseDataContract");

apiStatics->IsApiContractPresentByMajor(contractName.Get(), 3, &amp;operating_System_Support);

ComPtr<IProtectionPolicyManagerStatics2> ppmStatics;

ABI::Windows::Foundation::GetActivationFactory
   (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmStatics);

boolean WIP_Enabled_On_Device;

ppmStatics->get_IsProtectionEnabled(&amp;WIP_Enabled_On_Device);

if (operating_System_Support &amp;&amp; WIP_Enabled_On_Device
{
    // WIP is supported on the platform
}
else
{
    // WIP is not supported on the platform
}

C++/CX snippet

bool use_WIP_APIs = false;
if ((Windows::Foundation::Metadata::ApiInformation::IsApiContractPresent("Windows.Security.EnterpriseData.EnterpriseDataContract", 3)       &amp;&amp; ProtectionPolicyManager::IsProtectionEnabled))
{
    use_WIP_APIs = true;    
}
else
{
    use_WIP_APIs = false;
}

Don't call WIP APIs if the operating system doesn't support WIP or if WIP is not enabled on the device.

Read enterprise data

To read protected files, network endpoints, clipboard data and data that you accept from a Share contract, your app will have to request access.

Windows Information Protection gives your app permission if your app is on the protection policy's allowed list.

To read data from any of those sources, your app will have to verify that the enterprise ID is managed by policy.

You'll do these things:

Let's start with files.

Read data from a file

File, network endpoints, and clipboard data all have an enterprise ID.

To read data from any of those sources, your app will have to verify that the enterprise ID is managed by policy.

Let's start with files.

STEP 1: GET THE FILE HANDLE

C++ snippet

int WIP::GetFileHandle(HSTRING fileName, IStorageFile **file)
{
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);

    HString hstrKnownFolders;
    hstrKnownFolders.Set(RuntimeClass_Windows_Storage_KnownFolders);

    ComPtr<IActivationFactory> pKnownFoldersActivationFactory;
    Windows::Foundation::GetActivationFactory(hstrKnownFolders.Get(), &amp;pKnownFoldersActivationFactory);

    ComPtr<IKnownFoldersStatics> pKnownFolders;
    pKnownFoldersActivationFactory.As(&amp;pKnownFolders);

    ComPtr<IStorageFolder> pStorageFolder;
    pKnownFolders->get_DocumentsLibrary(&amp;pStorageFolder);

    __FIAsyncOperation_1_Windows__CStorage__CStorageFile_t* operation;
    pStorageFolder->GetFileAsync(fileName, &amp;operation);

    Event operationCompleted(CreateEvent(nullptr, true, false, nullptr));

    operation->put_Completed(Callback<IAsyncOperationCompletedHandler<StorageFile*>>
    ([&amp;](IAsyncOperation<StorageFile*> *pHandler, AsyncStatus status) -> HRESULT
    {
        SetEvent(operationCompleted.Get());
        return S_OK;
    }).Get());

    WaitForSingleObject(operationCompleted.Get(), INFINITE);

    HRESULT hr = operation->GetResults(file);

    return 0;
}

C++/CX snippet

Windows::Storage::StorageFolder ^storageFolder = KnownFolders::DocumentsLibrary;

auto getFileTask = create_task(storageFolder->GetFileAsync(fileName));

STEP 2: DETERMINE WHETHER YOUR APP CAN OPEN THE FILE

Determine whether the file is protected. If it is, your app can open that file if these two things are true:

  • The file's identity is managed by policy.
  • Your app is on the allowed list of that policy.

If either of these conditions aren't true, ProtectionPolicyManager.IsIdentityManaged returns false and you can't open that file.

C++ snippet

int WIP::GetProtectionInfo(HSTRING identity, IStorageFile * file, bool **canRead)
{
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);

    ComPtr<IFileProtectionManagerStatics> fpmStatics;

    Windows::Foundation::GetActivationFactory
        (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_FileProtectionManager).Get(), &amp;fpmStatics);

    __FIAsyncOperation_1_Windows__CSecurity__CEnterpriseData__CFileProtectionInfo_t *operation;

    ComPtr<IStorageItem> storageItem;
    ComPtr<IStorageFile> x(file);
    x.As(&amp;storageItem);

    fpmStatics->GetProtectionInfoAsync(storageItem.Get(), &amp;operation);

    Event operationCompleted(CreateEvent(nullptr, true, false, nullptr));

    operation->put_Completed(Callback<IAsyncOperationCompletedHandler<FileProtectionInfo*>>
        ([&amp;](IAsyncOperation<FileProtectionInfo*> *pHandler, AsyncStatus status) -> HRESULT
    {
        SetEvent(operationCompleted.Get());
        return S_OK;

    }).Get());

    WaitForSingleObject(operationCompleted.Get(), INFINITE);

    IFileProtectionInfo * fileProtectionInfo;
    FileProtectionStatus fileProtectionStatus;

    operation->GetResults(&amp;fileProtectionInfo);

    fileProtectionInfo->get_Status(&amp;fileProtectionStatus);

    bool readable = true;

    if ((fileProtectionStatus != FileProtectionStatus::FileProtectionStatus_Protected)
        &amp;&amp; fileProtectionStatus != FileProtectionStatus::FileProtectionStatus_Unprotected)
    {
        ComPtr<IProtectionPolicyManagerStatics> ppmStatics;
        ABI::Windows::Foundation::GetActivationFactory
        (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmStatics);
        
        readable = false;
    }

    *canRead = &amp;readable;

    return 0;
}

C++/CX snippet

getFileTask.then([](StorageFile ^file)
{
auto getProtectionInfoTask = create_task(FileProtectionManager::GetProtectionInfoAsync(file));

getProtectionInfoTask.then([file](FileProtectionInfo ^protectionInfo)
{
   if (protectionInfo->Status != FileProtectionStatus::Protected &amp;&amp;
      (protectionInfo->Status != FileProtectionStatus::Unprotected))
   {
      // Can't read file. Inform the user, log a message, perform some other action.
   }
   else 
   {
      // Next snippet goes here.
   }

  });
});

APIs:

FileProtectionManager.GetProtectionInfoAsync
FileProtectionInfo
FileProtectionStatus
ProtectionPolicyManager.IsIdentityManaged

STEP 3: READ THE FILE INTO A STREAM OR BUFFER

Read the file into a stream

C++ snippet

int WIP::ReadFileIntoStream(IStorageFile * file)
{
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);

    __FIAsyncOperation_1_Windows__CStorage__CStreams__CIRandomAccessStream_t *operation;
    file->OpenAsync(FileAccessMode::FileAccessMode_ReadWrite, &amp;operation);

    Event operationCompleted(CreateEvent(nullptr, true, false, nullptr));

    operation->put_Completed(Callback<IAsyncOperationCompletedHandler<IRandomAccessStream*>>
    ([&amp;](IAsyncOperation<IRandomAccessStream*> *pHandler, AsyncStatus status) -> HRESULT
    {
        SetEvent(operationCompleted.Get());
        return S_OK;

    }).Get());

    WaitForSingleObject(operationCompleted.Get(), INFINITE);

    IRandomAccessStream * pRandomAccessStream;

    operation->GetResults(&amp;pRandomAccessStream);

    // Do something with the stream here.

    return 0;
}

C++/CX snippet

   auto fileStreamTask = create_task(file->OpenAsync(Windows::Storage::FileAccessMode::ReadWrite))
   
   fileStreamTask.then([](auto stream)
   {
      // Do something with the file stream.
   });

Read the file into a buffer

C++ snippet

int WIP::GetFileHandle(HSTRING fileName, IStorageFile **file)
{
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);

    HString hstrKnownFolders;
    hstrKnownFolders.Set(RuntimeClass_Windows_Storage_KnownFolders);

    ComPtr<IActivationFactory> pKnownFoldersActivationFactory;
    Windows::Foundation::GetActivationFactory(hstrKnownFolders.Get(), &amp;pKnownFoldersActivationFactory);

    ComPtr<IKnownFoldersStatics> pKnownFolders;
    pKnownFoldersActivationFactory.As(&amp;pKnownFolders);

    ComPtr<IStorageFolder> pStorageFolder;
    pKnownFolders->get_DocumentsLibrary(&amp;pStorageFolder);

    __FIAsyncOperation_1_Windows__CStorage__CStorageFile_t* operation;
    
    pStorageFolder->GetFileAsync(fileName, &amp;operation);

    Event operationCompleted(CreateEvent(nullptr, true, false, nullptr));

    operation->put_Completed(Callback<IAsyncOperationCompletedHandler<StorageFile*>>
    ([&amp;](IAsyncOperation<StorageFile*> *pHandler, AsyncStatus status) -> HRESULT
    {
        SetEvent(operationCompleted.Get());
        return S_OK;
    }).Get());

    WaitForSingleObject(operationCompleted.Get(), INFINITE);
   
    operation->GetResults(file);

    return 0;
}

C++/CX snippet

auto fileBufferTask = create_task(Windows::Storage::FileIO::ReadBufferAsync(file));

fileBufferTask.then([&amp;](auto buffer)
{
    // do whatever with the buffer.
});

Read data from a network endpoint

Create a protected thread context to read from an enterprise endpoint.

STEP 1: GET THE IDENTITY OF THE NETWORK ENDPOINT

C++ snippet

RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);

// --------------
// Get URI object.
// --------------

ComPtr<IUriRuntimeClassFactory> uriFactory;

ABI::Windows::Foundation::GetActivationFactory
(HStringReference(RuntimeClass_Windows_Foundation_Uri).Get(), &amp;uriFactory);

ComPtr<IUriRuntimeClass> uriRuntime;

uriFactory->CreateUri(resourceURI, &amp;uriRuntime);

// --------------
// Get host name.
// --------------

HSTRING hostNameString;

uriRuntime->get_Host(&amp;hostNameString);

ComPtr<IHostNameFactory> hostNameFactory;

ABI::Windows::Foundation::GetActivationFactory
(HStringReference(RuntimeClass_Windows_Networking_HostName).Get(), &amp;hostNameFactory);

ComPtr<IHostName> hostName;

hostNameFactory->CreateHostName(hostNameString, &amp;hostName);

// --------------------------------
// Get identity of network endpoint
// --------------------------------

ComPtr<IProtectionPolicyManagerStatics> ppmStatics;

ABI::Windows::Foundation::GetActivationFactory
(HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmStatics);

__FIAsyncOperation_1_HSTRING_t * result;

ppmStatics->GetPrimaryManagedIdentityForNetworkEndpointAsync(hostName.Get(), &amp;result);

Event operationCompleted(CreateEvent(nullptr, true, false, nullptr));

result->put_Completed(Callback<IAsyncOperationCompletedHandler<HSTRING>>
    ([&amp;](IAsyncOperation<HSTRING> *pHandler, AsyncStatus status) -> HRESULT
{
    SetEvent(operationCompleted.Get());
    return S_OK;

}).Get());

WaitForSingleObject(operationCompleted.Get(), INFINITE);

C++/CX snippet

Windows::Networking::HostName ^hostName = ref new Windows::Networking::HostName(resourceURI->Host);

auto getNetworkEndPointTask = create_task
(ProtectionPolicyManager::GetPrimaryManagedIdentityForNetworkEndpointAsync(hostName));

If the endpoint isn't managed by policy, you'll get back an empty string.

APIs:

ProtectionPolicyManager.GetPrimaryManagedIdentityForNetworkEndpointAsync

STEP 2: CREATE A PROTECTED THREAD CONTEXT

If the endpoint is managed by policy, create a protected thread context. This tags any network connections that you make on the same thread to the identity.

It also gives you access to enterprise network resources that are managed by that policy.

C++ snippet

// --------------------------
// Read from network endpoint
// --------------------------

HSTRING identity;
result->GetResults(&amp;identity);

if (identity != NULL)
{
    IThreadNetworkContext * result;

    ppmStatics->CreateCurrentThreadNetworkContext(identity, &amp;result);

    return GetDataFromNetworkHelperMethod(uriRuntime);
}
else
{
    return GetDataFromNetworkHelperMethod(uriRuntime);
}

C++/CX snippet

getNetworkEndPointTask.then([resourceURI](Platform::String ^identity)
{  
    if ((identity) &amp;&amp; !(identity->IsEmpty()))
    {
        {
            ThreadNetworkContext ^threadNetworkContext = 
            ProtectionPolicyManager::CreateCurrentThreadNetworkContext(identity);

            GetDataFromRedirectHelperMethod(resourceURI);
        }
    }
    else
          {
                GetDataFromRedirectHelperMethod(resourceURI);
    }
});

This example encloses socket calls in a {} block. If you don't do this, make sure that you close the thread context after you've retrieved your resource. See ThreadNetworkContext::Close.

Don't create any personal files on that protected thread because those files will be automatically encrypted.

The ProtectionPolicyManager.CreateCurrentThreadNetworkContext method returns a ThreadNetworkContext object whether or not the endpoint is being managed by policy. If your app handles both personal and enterprise resources, call ProtectionPolicyManager.CreateCurrentThreadNetworkContext for all identities. After you get the resource, dispose the ThreadNetworkContext to clear any identity tag from the current thread.

APIs:

ProtectionPolicyManager.Identity
ProtectionPolicyManager.CreateCurrentThreadNetworkContext

STEP 3: READ THE RESOURCE INTO A BUFFER

C++ snippet

int WIP::GetDataFromNetworkHelperMethod(ComPtr<IUriRuntimeClass> uriRuntime)
{
    //----------------------
    // Get HttpClient object
    //----------------------

    ComPtr<IHttpClientFactory> httpClientFactory;

    ABI::Windows::Foundation::GetActivationFactory
    (HStringReference(RuntimeClass_Windows_Web_Http_HttpClient).Get(), &amp;httpClientFactory);
    
    ComPtr<IHttpFilter> filter;

    RoActivateInstance
    (HStringReference(RuntimeClass_Windows_Web_Http_Filters_HttpBaseProtocolFilter).Get(), &amp;filter);

    ComPtr<IHttpClient> httpClient;

    httpClientFactory->Create(filter.Get(), &amp;httpClient);

    //--------------------------------
    // Read network file into a buffer
    //--------------------------------

    __FIAsyncOperationWithProgress_2_Windows__CStorage__CStreams__CIBuffer_Windows__CWeb__CHttp__CHttpProgress_t *operation;

    HRESULT hr = httpClient->GetBufferAsync(uriRuntime.Get(), &amp;operation);

    Event operationCompleted(CreateEvent(nullptr, true, false, nullptr));
    
    operation->put_Completed(Callback<IAsyncOperationWithProgressCompletedHandler<IBuffer*, HttpProgress>>
        ([&amp;](IAsyncOperationWithProgress<IBuffer*, HttpProgress> *pHandler, AsyncStatus status) -> HRESULT
    {
        SetEvent(operationCompleted.Get());
        return S_OK;

    }).Get());

    WaitForSingleObject(operationCompleted.Get(), INFINITE);

    IBuffer * pBuffer;

    operation->GetResults(&amp;pBuffer);

    return 0;
}

C++/CX snippet

void GetDataFromNetworkHelperMethod(Uri ^ resourceURI)
{
    HttpClient ^client = nullptr;

    client = ref new HttpClient();
    
    try
    {
        auto getBufferTask = create_task(
        client->GetBufferAsync(resourceURI));

        getBufferTask.then([](IBuffer ^data)
        {
            // Add code to work with the buffer here.
        });
    }
    catch (Platform::Exception ^ exception) {}
}

(Optional) USE A HEADER TOKEN INSTEAD OF CREATING A PROTECTED THREAD CONTEXT

Instead of creating a protected thread context, you can provide the enterprise ID by using an HTTP request header.

C++ snippet

...

if (identity != NULL)
{
    IHttpRequestHeaderCollection * headerCollection;

    httpClient->get_DefaultRequestHeaders(&amp;headerCollection);
        
    headerCollection->Append(HStringReference(L"X-MS-Windows-HttpClient-EnterpriseId").Get(), identity);

    return GetDataFromNetworkbyUsingHeaderHelperMethod(httpClient, uriRuntime);
}

...
int WIP::GetDataFromNetworkbyUsingHeaderHelperMethod(ComPtr<IHttpClient> httpClient, ComPtr<IUriRuntimeClass> uriRuntime)
{
    //--------------------------------
    // Read network file into a buffer
    //--------------------------------

    __FIAsyncOperationWithProgress_2_Windows__CStorage__CStreams__CIBuffer_Windows__CWeb__CHttp__CHttpProgress_t *operation;

    httpClient->GetBufferAsync(uriRuntime.Get(), &amp;operation);

    Event operationCompleted(CreateEvent(nullptr, true, false, nullptr));


    operation->put_Completed(Callback<IAsyncOperationWithProgressCompletedHandler<IBuffer*, HttpProgress>>
        ([&amp;](IAsyncOperationWithProgress<IBuffer*, HttpProgress> *pHandler, AsyncStatus status) -> HRESULT
    {
        SetEvent(operationCompleted.Get());
        return S_OK;

    }).Get());

    WaitForSingleObject(operationCompleted.Get(), INFINITE);

    IBuffer * pBuffer;

    operation->GetResults(&amp;pBuffer);

    return 0;
}

C++ / CX snippet

...

if ((identity) &amp;&amp; !(identity->IsEmpty()))
{
    client = ref new HttpClient();

    HttpRequestHeaderCollection ^ headerCollection =
        client->DefaultRequestHeaders;

    headerCollection->Append("X-MS-Windows-HttpClient-EnterpriseId", identity);
            
    GetDataFromNetworkbyUsingHeaderHelperMethod(client, resourceURI);
}

...
void GetDataFromNetworkbyUsingHeaderHelperMethod(HttpClient ^ client, Uri ^resourceURI)
{
    try
    {
        auto getBufferTask = create_task(
            client->GetBufferAsync(resourceURI));

        getBufferTask.then([resourceURI](IBuffer ^data)
        {
            // Add code to work with the buffer here.
        });
    }
    catch (Platform::Exception ^ exception) {   }
}

HANDLE PAGE REDIRECTS

Sometimes a web server will redirect traffic to a more current version of a resource.

To handle this, make requests until the response status of your request has a value of OK.

Then use the URI of that response to get the identity of the endpoint. Here's one way to do this:

C++ snippet

int WIP::ReadNetworkResourceWithRedirects(HSTRING resourceURL, HWND hWnd)
{
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);

    bool finalURL = false;

    HttpResponseMessage * response = nullptr;

    ComPtr<IUriRuntimeClassFactory> uriFactory;

    ABI::Windows::Foundation::GetActivationFactory
           (HStringReference(RuntimeClass_Windows_Foundation_Uri).Get(), &amp;uriFactory);

    ComPtr<IUriRuntimeClass> uriRuntime;

    uriFactory->CreateUri(resourceURL, &amp;uriRuntime);

    while (!finalURL)
    {   
        ComPtr<IHostNameFactory> hostNameFactory;

        ABI::Windows::Foundation::GetActivationFactory
            (HStringReference(RuntimeClass_Windows_Networking_HostName).Get(), &amp;hostNameFactory);

        ComPtr<IHostName> hostName;

        HSTRING hostNameString;

        uriRuntime->get_Host(&amp;hostNameString);
   
        hostNameFactory->CreateHostName(hostNameString, &amp;hostName);

        ComPtr<IProtectionPolicyManagerStatics> ppmStatics;

        ABI::Windows::Foundation::GetActivationFactory

        (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmStatics);

        __FIAsyncOperation_1_HSTRING_t * result;

        ppmStatics->GetPrimaryManagedIdentityForNetworkEndpointAsync(hostName.Get(), &amp;result);

        Event operationCompleted(CreateEvent(nullptr, true, false, nullptr));

        result->put_Completed(Callback<IAsyncOperationCompletedHandler<HSTRING>>

        ([&amp;](IAsyncOperation<HSTRING> *pHandler, AsyncStatus status) -> HRESULT
        {

            SetEvent(operationCompleted.Get());
            return S_OK;
        }).Get());

        WaitForSingleObject(operationCompleted.Get(), INFINITE);

        ComPtr<IProtectionPolicyManagerInterop> ppmInterop;

        ABI::Windows::Foundation::GetActivationFactory
            (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmInterop);

        ComPtr<IProtectionPolicyManager> ppmInstance;

        ppmInterop->GetForWindow(hWnd, IID_PPV_ARGS(&amp;ppmInstance));

        ComPtr<IHttpClientFactory> httpClientFactory;

        HSTRING identity;

        result->GetResults(&amp;identity);

        if (identity == NULL)
        {
            ppmInstance->put_Identity(NULL);

            ABI::Windows::Foundation::GetActivationFactory
            (HStringReference(RuntimeClass_Windows_Web_Http_HttpClient).Get(), &amp;httpClientFactory);
        }
        else
        {
            ppmInstance->put_Identity(identity);

            IThreadNetworkContext * ThreadNetworkContextResult;

            ppmStatics->CreateCurrentThreadNetworkContext(identity, &amp;ThreadNetworkContextResult);

            ABI::Windows::Foundation::GetActivationFactory
                (HStringReference(RuntimeClass_Windows_Web_Http_HttpClient).Get(), &amp;httpClientFactory);
        }

        ComPtr<IHttpBaseProtocolFilter> baseProtocolFilter;
        
        RoActivateInstance
        (HStringReference(RuntimeClass_Windows_Web_Http_Filters_HttpBaseProtocolFilter).Get(), &amp;baseProtocolFilter);

        ComPtr<IHttpFilter> filter;

        baseProtocolFilter.As(&amp;filter);

        ComPtr<IHttpClient> httpClient;

        httpClientFactory->Create(filter.Get(), &amp;httpClient);

        ComPtr<IHttpRequestMessageFactory> requestMessageFactory;

        ABI::Windows::Foundation::GetActivationFactory
                  (HStringReference(RuntimeClass_Windows_Web_Http_HttpRequestMessage).Get(), &amp;requestMessageFactory);

        ComPtr<IHttpMethodFactory> requestMethodFactory;

        ABI::Windows::Foundation::GetActivationFactory
            (HStringReference(RuntimeClass_Windows_Web_Http_HttpMethod).Get(), &amp;requestMethodFactory);

        ComPtr<IHttpMethod> httpMethod;

        HString str;
        str.Set(L"GET");

        requestMethodFactory->Create(str.Get(), &amp;httpMethod);

        IHttpRequestMessage * requestMessage;

        requestMessageFactory->Create(httpMethod.Get(), uriRuntime.Get(), &amp;requestMessage);

        __FIAsyncOperationWithProgress_2_Windows__CWeb__CHttp__CHttpResponseMessage_Windows__CWeb__CHttp__CHttpProgress_t * requestOperation;

        httpClient->SendRequestAsync(requestMessage, &amp;requestOperation);

        Event requestOperationCompleted(CreateEvent(nullptr, true, false, nullptr));

        requestOperation->put_Completed(Callback<IAsyncOperationWithProgressCompletedHandler<HttpResponseMessage*, HttpProgress>>
            ([&amp;](IAsyncOperationWithProgress<HttpResponseMessage*, HttpProgress> *pHandler, AsyncStatus status) -> HRESULT
        {
            SetEvent(requestOperationCompleted.Get());
            return S_OK;
        }).Get());

        WaitForSingleObject(requestOperationCompleted.Get(), INFINITE);

        IHttpResponseMessage * response;

        requestOperation->GetResults(&amp;response);

        HttpStatusCode value;

        response->get_StatusCode(&amp;value);

        if (value == HttpStatusCode::HttpStatusCode_MultipleChoices &amp;&amp;
            value == HttpStatusCode::HttpStatusCode_MovedPermanently &amp;&amp;
            value == HttpStatusCode::HttpStatusCode_Found &amp;&amp;
            value == HttpStatusCode::HttpStatusCode_SeeOther &amp;&amp;
            value == HttpStatusCode::HttpStatusCode_NotModified &amp;&amp;
            value == HttpStatusCode::HttpStatusCode_UseProxy &amp;&amp;
            value == HttpStatusCode::HttpStatusCode_TemporaryRedirect &amp;&amp;
            value == HttpStatusCode::HttpStatusCode_PermanentRedirect)
        {
            requestMessage->get_RequestUri(&amp;uriRuntime);
        }
        else
        {
            finalURL = true;
        }
  }
  return 0;
}

C++/CX snippet

void GetDataFromRedirectHelperMethod(Uri ^resourceURI)
{
    HttpClient ^client = nullptr;
  
    HttpBaseProtocolFilter ^filter = ref new HttpBaseProtocolFilter();
    filter->AllowAutoRedirect = false;

    HttpResponseMessage ^response = nullptr;

    client = ref new HttpClient(filter);

    HttpRequestMessage ^message = ref new HttpRequestMessage(HttpMethod::Get, resourceURI);

    auto sendAsyncRequestTask = create_task(client->SendRequestAsync(message));

    sendAsyncRequestTask.then([resourceURI, client](Windows::Web::Http::HttpResponseMessage ^response)
    {
        if (response->StatusCode == HttpStatusCode::MultipleChoices ||
            response->StatusCode == HttpStatusCode::MovedPermanently ||
            response->StatusCode == HttpStatusCode::Found ||
            response->StatusCode == HttpStatusCode::SeeOther ||
            response->StatusCode == HttpStatusCode::NotModified ||
            response->StatusCode == HttpStatusCode::UseProxy ||
            response->StatusCode == HttpStatusCode::TemporaryRedirect ||
            response->StatusCode == HttpStatusCode::PermanentRedirect)
        {
            HttpRequestMessage ^message = ref new HttpRequestMessage(HttpMethod::Get, message->RequestUri);

            auto sendAsyncRequestTask = create_task(client->SendRequestAsync(message));

            sendAsyncRequestTask.then([&amp;](Windows::Web::Http::HttpResponseMessage ^response)
            {
                auto readBufferTask = create_task(response->Content->ReadAsBufferAsync());

                readBufferTask.then([&amp;](IBuffer ^data)
                {
                    // Add code to work with the buffer here.           
                });
         });
     }
     else
     {
         auto readBufferTask = create_task(response->Content->ReadAsBufferAsync());

         readBufferTask.then([&amp;](IBuffer ^data)
         {
             // Add code to work with the buffer here.
         });
       }
    });
}

APIs:

ProtectionPolicyManager.GetPrimaryManagedIdentityForNetworkEndpointAsync
ProtectionPolicyManager.CreateCurrentThreadNetworkContext
ProtectionPolicyManager.Identity

CONFIGURE YOUR APP TO RUN IN PERMISSIVE MODE

Permissive mode eliminates the need for your app to call the ProtectionPolicyManager.GetPrimaryManagedIdentityForNetworkEndpointAsync or the ProtectionPolicyManager.CreateCurrentThreadNetworkContext method. In certain situations, this can make it easier for you to debug your app. You can also publish an app that runs in permissive mode if your app does not show users data retrieved from network endpoints.

To configure your app to run in permissive mode, open the resource file of your project and add the following flag.

MICROSOFTEDPPERMISSIVEAPPINFO EDPPERMISSIVEAPPINFOID
BEGIN
   0X0001
END

Read data from the clipboard

GET PERMISSION TO USE DATA FROM THE CLIPBOARD

To get data from the clipboard, ask Windows for permission. Use DataPackageView.RequestAccessAsync to do that.

C++ snippet

int WIP::PasteText(void)
{
    ComPtr<IClipboardStatics> pClipboardStatics;

    ABI::Windows::Foundation::GetActivationFactory
        (HStringReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_Clipboard).Get(), &amp;pClipboardStatics);

    ComPtr<IDataPackageView> pDataPackageView;

    pClipboardStatics->GetContent(&amp;pDataPackageView);

    boolean containsText = false;

    pDataPackageView->Contains(HStringReference(L"Text").Get(), &amp;containsText);
 
    if (containsText)
    {
        ComPtr<IDataPackageView3> pDataPackageView3;
        pDataPackageView.As(&amp;pDataPackageView3);

        __FIAsyncOperation_1_Windows__CSecurity__CEnterpriseData__CProtectionPolicyEvaluationResult_t * protectionPolicyOperation;

        pDataPackageView3->RequestAccessAsync(&amp;protectionPolicyOperation);

        Event operationCompleted(CreateEvent(nullptr, true, false, nullptr));

        protectionPolicyOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<ProtectionPolicyEvaluationResult>>
            ([&amp;](IAsyncOperation<ProtectionPolicyEvaluationResult> *pHandler, AsyncStatus status) -> HRESULT
        {
            SetEvent(operationCompleted.Get());
            return S_OK;
        }).Get());

        WaitForSingleObject(operationCompleted.Get(), INFINITE);

        ProtectionPolicyEvaluationResult result;

        protectionPolicyOperation->GetResults(&amp;result);

        if (result == ProtectionPolicyEvaluationResult::ProtectionPolicyEvaluationResult_Allowed) 
        {
            __FIAsyncOperation_1_HSTRING_t * stringOperation;

            Event stringOperationCompleted(CreateEvent(nullptr, true, false, nullptr));

            stringOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<HSTRING>>
                ([&amp;](IAsyncOperation<HSTRING> *pHandler, AsyncStatus status) -> HRESULT
            {
                SetEvent(stringOperationCompleted.Get());
                return S_OK;
            }).Get());

            pDataPackageView->GetTextAsync(&amp;stringOperation);

            WaitForSingleObject(stringOperationCompleted.Get(), INFINITE);

            HSTRING clipBoardText;

            stringOperation->GetResults(&amp;clipBoardText);
         }
     }

    return 0;
}

C++/ CX snippet

void PasteText(TextBox ^textBox)
{
    DataPackageView ^dataPackageView = Clipboard::GetContent();

    if (dataPackageView->Contains(StandardDataFormats::Text))
    {
        auto requestAccessTask = create_task(dataPackageView->RequestAccessAsync());
        requestAccessTask.then([dataPackageView, textBox](ProtectionPolicyEvaluationResult result)
        {
            if (result == ProtectionPolicyEvaluationResult::Allowed) 
            {
                auto getTextTask = create_task(dataPackageView->GetTextAsync());

                getTextTask.then([textBox](Platform::String ^contentsOfClipboard)
                {
                    textBox->Text = contentsOfClipboard;
                });
             }
         });
     }
}

APIs:

DataPackageView.RequestAccessAsync

HIDE OR DISABLE FEATURES THAT USE CLIPBOARD DATA

Determine whether your current view has permission to get data that is on the clipboard.

If it doesn't, you can disable or hide controls that let users paste information from the clipboard or preview its contents.

C++ snippet

int WIP::IsClipboardAllowedAsync(ProtectionPolicyEvaluationResult **evalResult, HWND hWnd)
{
    ComPtr<IClipboardStatics> pClipboardStatics;

    ABI::Windows::Foundation::GetActivationFactory
        (HStringReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_Clipboard).Get(), &amp;pClipboardStatics);

    ComPtr<IDataPackageView> pDataPackageView;

    HRESULT hr = pClipboardStatics->GetContent(&amp;pDataPackageView);

    boolean containsText = false;

    hr = pDataPackageView->Contains(HStringReference(L"Text").Get(), &amp;containsText);

    if (containsText)
    {
        ComPtr<IProtectionPolicyManagerStatics> ppmStatics;

        hr = ABI::Windows::Foundation::GetActivationFactory
            (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmStatics);

        ComPtr<IDataPackagePropertySetView> dataPackagePropertySetView;

        hr = pDataPackageView->get_Properties(&amp;dataPackagePropertySetView);

        ComPtr<IDataPackagePropertySetView3> dataPackagePropertySetView3;

        dataPackagePropertySetView.As(&amp;dataPackagePropertySetView3);

        ComPtr<IProtectionPolicyManagerInterop> ppmInterop;

        hr = ABI::Windows::Foundation::GetActivationFactory
          (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmInterop);

         ComPtr<IProtectionPolicyManager> ppmInstance;

         HSTRING identity;

         if (SUCCEEDED(ppmInterop->GetForWindow(hWnd, IID_PPV_ARGS(&amp;ppmInstance))))
         {
            HRESULT hRet = ppmInstance->get_Identity(&amp;identity);
         }

         ProtectionPolicyEvaluationResult evaluationResult;

         HSTRING enterpriseID;

         dataPackagePropertySetView3->get_EnterpriseId(&amp;enterpriseID);

         hr = ppmStatics->CheckAccess(enterpriseID, identity, &amp;evaluationResult);

        *evalResult = &amp;evaluationResult;
    }

   return 0;
}

C++/ CX snippet

bool IsClipboardAllowedAsync(Platform::String ^identity)
{
    ProtectionPolicyEvaluationResult protectionPolicyEvaluationResult = ProtectionPolicyEvaluationResult::Blocked;

    DataPackageView ^dataPackageView = Clipboard::GetContent();

    if (dataPackageView->Contains(StandardDataFormats::Text))
       {
        protectionPolicyEvaluationResult = ProtectionPolicyManager::CheckAccess
            (dataPackageView->Properties->EnterpriseId, identity);
    }

    return (protectionPolicyEvaluationResult == ProtectionPolicyEvaluationResult::Allowed |
        
    protectionPolicyEvaluationResult == ProtectionPolicyEvaluationResult::ConsentRequired);
}

APIs:

ProtectionPolicyEvaluationResult
ProtectionPolicyManager.Identity

PREVENT USERS FROM BEING PROMPTED WITH A CONSENT DIALOG BOX

A new document isn't personal or enterprise. It's just new. If a user pastes enterprise data into it, Windows enforces policy and the user is prompted with a consent dialog. This code prevents that from happening. This task is not about helping to protect data. It's more about keeping users from receiving the consent dialog box in cases where your app creates a brand new item.

C++ snippet

int WIP::PasteText(bool isNewEmptyDocument)
{
    ComPtr<IClipboardStatics> pClipboardStatics;
  
    ABI::Windows::Foundation::GetActivationFactory
      (HStringReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_Clipboard).Get(), &amp;pClipboardStatics);

    ComPtr<IDataPackageView> pDataPackageView;

    pClipboardStatics->GetContent(&amp;pDataPackageView);

    boolean containsText = false;

    pDataPackageView->Contains(HStringReference(L"Text").Get(), &amp;containsText);

    if (containsText)
    {
        ComPtr<IDataPackagePropertySetView> dataPackagePropertySetView;

              pDataPackageView->get_Properties(&amp;dataPackagePropertySetView);

        ComPtr<IDataPackagePropertySetView3> dataPackagePropertySetView3;
        dataPackagePropertySetView.As(&amp;dataPackagePropertySetView3);

        HSTRING enterpriseID;

        dataPackagePropertySetView3->get_EnterpriseId(&amp;enterpriseID);

        if (enterpriseID != NULL) 
        {
            ComPtr<IProtectionPolicyManagerStatics> ppmStatics;

            ABI::Windows::Foundation::GetActivationFactory
               (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmStatics);
            
            boolean result;

            ppmStatics->TryApplyProcessUIPolicy(enterpriseID, &amp;result);

            // Call the GetTextAsync method of the IDataPackageView interface. See earlier example.
            // Then, add text to the new item or document.
        }
        else 
        {
            ComPtr<IDataPackageView3> pDataPackageView3;
            pDataPackageView.As(&amp;pDataPackageView3);

            __FIAsyncOperation_1_Windows__CSecurity__CEnterpriseData__CProtectionPolicyEvaluationResult_t * protectionPolicyOperation;

            pDataPackageView3->RequestAccessAsync(&amp;protectionPolicyOperation);

            Event operationCompleted(CreateEvent(nullptr, true, false, nullptr));

            protectionPolicyOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<ProtectionPolicyEvaluationResult>>
               ([&amp;](IAsyncOperation<ProtectionPolicyEvaluationResult> *pHandler, AsyncStatus status) -> HRESULT
            {
                SetEvent(operationCompleted.Get());
                return S_OK;
            }).Get());

            WaitForSingleObject(operationCompleted.Get(), INFINITE);

            ProtectionPolicyEvaluationResult result;

            protectionPolicyOperation->GetResults(&amp;result);

            if (result == ProtectionPolicyEvaluationResult::ProtectionPolicyEvaluationResult_Allowed)
            {
                // Call the GetTextAsync method of the IDataPackageView interface. See earlier example.
                // Then, add text to the new item or document.
            }
       }
   }

  return 0;
}

C++/ CX snippet

void PasteText(bool isNewEmptyDocument)
{
    DataPackageView ^dataPackageView = Clipboard::GetContent();

    if (dataPackageView->Contains(StandardDataFormats::Text))
    {
        if ((dataPackageView->Properties->EnterpriseId) &amp;&amp;
                       !(dataPackageView->Properties->EnterpriseId->IsEmpty()))
        {
            if (isNewEmptyDocument)
            {
                ProtectionPolicyManager::TryApplyProcessUIPolicy(dataPackageView->Properties->EnterpriseId);

                auto getTextTask = create_task(dataPackageView->GetTextAsync());

                getTextTask.then([](Platform::String ^contentsOfClipboard)
                {
                    // add this string to the item.
                });       
            }
            else
            {
                auto requestAccessTask = create_task(dataPackageView->RequestAccessAsync());
                requestAccessTask.then([&amp;](ProtectionPolicyEvaluationResult policyResult)
                {
                    if (policyResult == ProtectionPolicyEvaluationResult::Allowed)
                    {
                        auto getTextTask = create_task(dataPackageView->GetTextAsync());

                        getTextTask.then([](Platform::String ^contentsOfClipboard)
                        {
                            // add this string to the item.
                        });
                    }
                });
             }
         }
    }
}

APIs:

DataPackageView.RequestAccessAsync
ProtectionPolicyEvaluationResult
ProtectionPolicyManager.TryApplyProcessUIPolicy

Read data from an OLE clipboard

If your app makes use of the OLE Component Object Model, you can use the OleGetClipboardWithEnterpriseInfo function instead of having to use a DataPackageView object.

C++ snippet

int WIP::OLEPasteText(void) 
{
    IDataObject *pDataObject;
    
    PWSTR enterpriseID;
    PWSTR sourceDescription;
    PWSTR targetDescription;
    PWSTR dataDescription;

    HRESULT hr = OleGetClipboardWithEnterpriseInfo
(&amp;pDataObject, &amp;enterpriseID, &amp;sourceDescription, &amp;targetDescription, &amp;dataDescription);

    if (hr == S_OK)
    {
        FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
        STGMEDIUM stgmed;

        hr = pDataObject->GetData(&amp;fmtetc, &amp;stgmed);

        if (hr == S_OK)
        {
            char *charData = (char*)GlobalLock(stgmed.hGlobal);

            GlobalUnlock(stgmed.hGlobal);
            ReleaseStgMedium(&amp;stgmed);
        }

        pDataObject->Release();
    }

    return 0;
}

APIs:

OleGetClipboardWithEnterpriseInfo

Read data that is dragged into your application

If you want your app to take over policy evaluation for data that users drag into your application, implement the IEnterpriseDropTarget interface and two methods.

IMPLEMENT THE IENTERPRISEDROPTARGET INTERFACE

class CDropTarget : public IDropTarget, IEnterpriseDropTarget 
{ 
// IDropTarget methods 

// IEnterpriseDropTarget methods

    PWSTR m_enterpriseId; // A variable to cache the enterprise ID for the current drag operation.
}; 

INDICATE THAT YOU WANT TO HANDLE WIP POLICY EVALUATION

HRESULT CDropTarget::IsEvaluatingEdpPolicy(_Out_ BOOL *isEvaluatingEdpPolicy) 
{
    *isEvaluatingEdpPolicy = TRUE; 

    return S_OK;

} 

CACHE THE ENTERPISE ID OF THE DRAG OPERATION

HRESULT CDropTarget::SetDropSourceEnterpriseId(_In_ PCWSTR enterpriseId) 
{
    return SHStrDup(enterpriseId, &amp;m_enterpriseId); 
} 

MAKE WIP POLICY DECISIONS ON THE DATA THAT THE USER DRAGS INTO YOUR APPLICATION

HRESULT CDropTarget::Drop(_In_ LPDATAOBJECT /* pDataObject */, _In_ DWORD /* dwKeyState */, _In_ POINTL /* pt */, _Inout_ LPDWORD /* pdwEffect */) 
{
    if (m_enterpriseId) 
    { 
        // Make EDP policy decisions using m_enterpriseId. 
        
        // Clear the current enterprise id so that it is reset 
        // for the next drag operation. 
        
        CoTaskMemFree(m_enterpriseId);
    }
    return S_OK;
} 

Protect enterprise data

Protect enterprise data that leaves your app.

Data leaves your app when you show it in a page, save it to a file or network endpoint.

In this section, we'll show you how to do these things:

Protect data that appears in pages

When you show data in a page, let Windows know what type of data it is (personal or enterprise). To do that, tag the current app view or tag the entire app process.

When you tag the view or the process, Windows enforces policy on it. This helps prevent data leaks that result from actions that your app doesn't control. For example, on a computer, a user could use CTRL-V to copy enterprise information from a view and then paste that information to another app. Windows protects against that. Windows also helps to enforce share contracts.

TAG THE CURRENT VIEW

Do this if your app has multiple views where some views consume enterprise data and some consume personal data.

int WIP::TagWindow(HSTRING identity, HWND hWnd, bool tagAsEnterprise)
{
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
    
    ComPtr<IProtectionPolicyManagerInterop> ppmInterop;

    ABI::Windows::Foundation::GetActivationFactory
        (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmInterop);

    ComPtr<IProtectionPolicyManager> ppmInstance;

    ppmInterop->GetForWindow(hWnd, IID_PPV_ARGS(&amp;ppmInstance));

    if (tagAsEnterprise)
    {
        // tag as enterprise data. "identity" the string that contains the enterprise ID.
        // You'd get that from a file, network endpoint, or clipboard data package.
        ppmInstance->put_Identity(identity);
    }
    else  
    {
        // tag as personal data.

        ppmInstance->put_Identity(NULL);
    }
    return 0;
}

APIs:

ProtectionPolicyManager.Identity

TAG THE PROCESS

Do this if all views in your app will work with only one type of data (personal or enterprise).

This prevents you from having to manage independently tagged views.

C++ snippet

int WIP::TagProcess(HSTRING identity, bool tagAsEnterprise)
{
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);

    ComPtr<IProtectionPolicyManagerStatics> ppmStatics;

    ABI::Windows::Foundation::GetActivationFactory
        (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmStatics);

    boolean result;

    if (tagAsEnterprise) 
    {
        // tag as enterprise data. "identity" the string that contains the enterprise ID.
        // You'd get that from a file, network endpoint, or clipboard data package.

        ppmStatics->TryApplyProcessUIPolicy(identity, &amp;result);
    }
    else 
    {
        // tag as personal data.
        ppmStatics->TryApplyProcessUIPolicy(HStringReference(L"").Get(), &amp;result);
    }
    return 0;
}

C++/ CX snippet


// tag as enterprise data. "identity" the string that contains the enterprise ID.
// You'd get that from a file, network endpoint, or clipboard data package.

bool result = ProtectionPolicyManager::TryApplyProcessUIPolicy(identity);

// tag as personal data.
bool result = ProtectionPolicyManager::TryApplyProcessUIPolicy("");

APIs:

ProtectionPolicyManager.TryApplyProcessUIPolicy

Protect data to a file

Create a protected file and then write to it.

This prevents you from having to manage independently tagged views.

STEP 1: DETERMINE IF YOUR APP CAN CREATE AN ENTERPRISE FILE

Your app can create an enterprise file if the identity string is managed by policy and your app is on the Allowed list of that policy.

C++ snippet

ComPtr<IProtectionPolicyManagerStatics> ppmStatics;

ABI::Windows::Foundation::GetActivationFactory
    (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmStatics);

boolean result;

ppmStatics->IsIdentityManaged(identity, &amp;result);

if (!result)
    return -1;

C++/ CX snippet

if (!ProtectionPolicyManager::IsIdentityManaged(identity))
{
    // Identity is not managed so no need to protect the file.
    // Prompt the user, log a message, or perform some other action.
}

APIs:

ProtectionPolicyManager.IsIdentityManaged

STEP 2: CREATE THE FILE AND PROTECT IT TO THE ENTITY

C++ snippet

HString hstrKnownFolders;

hstrKnownFolders.Set(RuntimeClass_Windows_Storage_KnownFolders);

ComPtr<IActivationFactory> pKnownFoldersActivationFactory;

ABI::Windows::Foundation::GetActivationFactory(hstrKnownFolders.Get(), &amp;pKnownFoldersActivationFactory);

ComPtr<IKnownFoldersStatics> pKnownFolders;

pKnownFoldersActivationFactory.As(&amp;pKnownFolders);

ComPtr<IStorageFolder> pStorageFolder;

pKnownFolders->get_DocumentsLibrary(&amp;pStorageFolder);

__FIAsyncOperation_1_Windows__CStorage__CStorageFile_t *operation;

pStorageFolder->CreateFileAsync(HStringReference(L"sample.txt").Get(),

CreationCollisionOption::CreationCollisionOption_ReplaceExisting, &amp;operation);

Event operationCompleted(CreateEvent(nullptr, true, false, nullptr));

operation->put_Completed(Callback<IAsyncOperationCompletedHandler<StorageFile*>>
  ([&amp;](IAsyncOperation<StorageFile*> *pHandler, AsyncStatus status) -> HRESULT
  {
     SetEvent(operationCompleted.Get());
     return S_OK;

  }).Get());

WaitForSingleObject(operationCompleted.Get(), INFINITE);

ComPtr<IStorageFile> pFile;

operation->GetResults(&amp;pFile);

ComPtr<IFileProtectionManagerStatics> fpmStatics;

ABI::Windows::Foundation::GetActivationFactory
   (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_FileProtectionManager).Get(), &amp;fpmStatics);

__FIAsyncOperation_1_Windows__CSecurity__CEnterpriseData__CFileProtectionInfo_t * protectOperation;

ComPtr<IStorageItem> storageItem;
pFile.As(&amp;storageItem);

fpmStatics->ProtectAsync(storageItem.Get(), identity, &amp;protectOperation);

Event protectOperationCompleted(CreateEvent(nullptr, true, false, nullptr));

protectOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<FileProtectionInfo*>>
    ([&amp;](IAsyncOperation<FileProtectionInfo*> *pHandler, AsyncStatus status) -> HRESULT
    {
        SetEvent(protectOperationCompleted.Get());
        return S_OK;

    }).Get());

WaitForSingleObject(protectOperationCompleted.Get(), INFINITE);

ComPtr<IFileProtectionInfo> fileProtectionInfo;

protectOperation->GetResults(&amp;fileProtectionInfo);

FileProtectionStatus status;

fileProtectionInfo->get_Status(&amp;status);

if (status == FileProtectionStatus::FileProtectionStatus_Protected)
{
    // write to stream or buffer
}

C++/ CX snippet

StorageFolder ^storageFolder = KnownFolders::DocumentsLibrary;

auto createFileTask = create_task(storageFolder->CreateFileAsync
    ("sample.txt", CreationCollisionOption::ReplaceExisting));

createFileTask.then([identity, enterpriseData](StorageFile ^storageFile)
{
    auto protectTask = create_task(FileProtectionManager::ProtectAsync(storageFile, identity));
});

STEP 3: WRITE THAT STREAM OR BUFFER TO A FILE

Write to a stream

C++ snippet

int WIP::SaveDataToAStream(HSTRING enterpriseData, IStorageFile * filePtr)
{
    __FIAsyncOperation_1_Windows__CStorage__CStreams__CIRandomAccessStream_t * operation;

    filePtr->OpenAsync(FileAccessMode::FileAccessMode_ReadWrite, &amp;operation);

    Event operationCompleted(CreateEvent(nullptr, true, false, nullptr));

    operation->put_Completed(Callback<IAsyncOperationCompletedHandler<IRandomAccessStream*>>
    ([&amp;](IAsyncOperation<IRandomAccessStream*> *pHandler, AsyncStatus status) -> HRESULT
    {
        SetEvent(operationCompleted.Get());
        return S_OK;
    }).Get());

    WaitForSingleObject(operationCompleted.Get(), INFINITE);

    ComPtr<IRandomAccessStream> stream;

    operation->GetResults(&amp;stream);

    IOutputStream * outputStream;

    stream->GetOutputStreamAt(0, &amp;outputStream);

    ComPtr<IDataWriter> dataWriter;

    ComPtr<IDataWriterFactory> dataWriterFactory;

    Windows::Foundation::GetActivationFactory
        (HStringReference(RuntimeClass_Windows_Storage_Streams_DataWriter).Get(), &amp;dataWriterFactory);

    dataWriterFactory->CreateDataWriter(outputStream, &amp;dataWriter);

    UINT32 byteCount;

    dataWriter->WriteString(enterpriseData, &amp;byteCount);

    __FIAsyncOperation_1_UINT32_t * storeOperation;

    Event storeOperationCompleted(CreateEvent(nullptr, true, false, nullptr));

    dataWriter->StoreAsync(&amp;storeOperation);

    storeOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<UINT32>>
        ([&amp;](IAsyncOperation<UINT32> *pHandler, AsyncStatus status) -> HRESULT
    {
        SetEvent(storeOperationCompleted.Get());
        return S_OK;
    }).Get());

    WaitForSingleObject(storeOperationCompleted.Get(), INFINITE);

    return 0;
}

C++/ CX snippet

protectTask.then([storageFile, enterpriseData](FileProtectionInfo ^fileProtectionInfo)
{
    if (fileProtectionInfo->Status == FileProtectionStatus::Protected)
    {
        auto openTask = create_task(storageFile->OpenAsync(FileAccessMode::ReadWrite));

        openTask.then([enterpriseData](IRandomAccessStream ^stream)
        {
            {
                 auto outputStream = stream->GetOutputStreamAt(0);
                 { 
                     auto dataWriter = ref new DataWriter(outputStream);
                     dataWriter->WriteString(enterpriseData);
                     delete dataWriter;
                 }
            }
        }); 
    } 
});

Write to a buffer

C++ snippet

int WIP::SaveDataToABuffer(HSTRING enterpriseData, IStorageFile * filePtr)
{
    ComPtr<ICryptographicBufferStatics> cryptographicBuffer;

    ABI::Windows::Foundation::GetActivationFactory
        (HStringReference(RuntimeClass_Windows_Security_Cryptography_CryptographicBuffer).Get(), &amp;cryptographicBuffer);

    ComPtr<IBufferFactory> bufferFactory;

    ABI::Windows::Foundation::GetActivationFactory
        (HStringReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(), &amp;bufferFactory);

    ComPtr<IBuffer> buffer;

    bufferFactory->Create(sizeof(enterpriseData), &amp;buffer);

    cryptographicBuffer->ConvertBinaryToString(BinaryStringEncoding::BinaryStringEncoding_Utf8, buffer.Get(), &amp;enterpriseData);

    ComPtr<IFileIOStatics> fileIOStatics;

    ABI::Windows::Foundation::GetActivationFactory
        (HStringReference(RuntimeClass_Windows_Storage_FileIO).Get(), &amp;fileIOStatics);

    IAsyncAction *operation;

    fileIOStatics->WriteBufferAsync(filePtr, buffer.Get(), &amp;operation);

    Event operationCompleted(CreateEvent(nullptr, true, false, nullptr));

    operation->put_Completed(Callback<IAsyncActionCompletedHandler>
        ([&amp;](IAsyncAction *pHandler, AsyncStatus status) -> HRESULT
    {
        SetEvent(operationCompleted.Get());
        return S_OK;

    }).Get());

    WaitForSingleObject(operationCompleted.Get(), INFINITE);

    operation->GetResults();

    return 0;
}

C++/ CX snippet

if (fileProtectionInfo->Status == FileProtectionStatus::Protected)
{
    auto buffer = Windows::Security::Cryptography::CryptographicBuffer::ConvertStringToBinary
        (enterpriseData, Windows::Security::Cryptography::BinaryStringEncoding::Utf8);

    auto writeTask = create_task(FileIO::WriteBufferAsync(storageFile, buffer));

    writeTask.then([]()
    {
        // Successfully wrote file.
    });
}

APIs:

FileProtectionInfo
FileProtectionStatus

Protect data that users save by using a file save dialog box

If your app opens a file save as dialog box, add code that collects the EncrptionOwners property from the user.

In the dialog box, a file protection button appears next to the file name. Users choose that button to select an enterprise ID.

After the user saves the file, your app can get the enterprise ID that the user chooses by retrieving the PKEY_Security_EncryptionOwners property of the dialog's property collection.

Then, you can protect the file by using that enterprise ID.

STEP 1: SET THE INITIAL ENCRYPTION SETTING

HRESULT InvokeSaveDialog(HWND hwnd, PCWSTR pszDefaultFileName, _Outptr_ LPWSTR *ppszNewFileName)
{
    // Set the initial encryption setting to false

    IFileSaveDialog *pfsd = NULL;

    ComPtr<IPropertyDescriptionList> propertyDescriptionList;

    if (SUCCEEDED(PSGetPropertyDescriptionListFromString
        (L"prop:System.Security.EncryptionOwners", IID_PPV_ARGS(&amp;propertyDescriptionList))))

    pfsd->SetCollectedProperties(propertyDescriptionList.Get(), false);
}

STEP 2: GET THE ENTEPRISE ID THAT THE USER CHOOSES IN THE DIALOG BOX

WCHAR enterpriseId[22] = { L'\0' };
        
if (pfsd != NULL)
{
    *enterpriseId = L'\0';

    ComPtr<IPropertyStore> propertyStore;

    FAILED(pfsd->GetProperties(&amp;propertyStore));

    PROPVARIANT pv;

    PropVariantInit(&amp;pv);

    PWSTR enterpriseId = nullptr;

    if (SUCCEEDED(propertyStore->GetValue(PKEY_Security_EncryptionOwners, &amp;pv)) &amp;&amp;

    (pv.vt == (VT_VECTOR | VT_LPWSTR)) &amp;&amp; (pv.calpwstr.cElems > 0))
    {
        enterpriseId = pv.calpwstr.pElems[0];
    }
  }

STEP 3: PROTECT THE DATA TO A FILE

See Protect data to a file.

Protect data to a file as a background process

This code can run while the screen of the device is locked. If the administrator configured a secure "Data protection under lock" (DPL) policy, Windows removes the encryption keys required to access protected resources from device memory. This prevents data leaks if the device is lost. This same feature also removes keys associated with protected files when their handles are closed.

You'll have to use an approach that keeps the file handle open when you create a file.

STEP 1: DETERMINE IF YOU CAN CREATE AN ENTERPRISE FILE

You can create an enterprise file if the identity that you're using is managed by policy and your app is on the allowed list of that policy.

C++ snippet

ComPtr<IProtectionPolicyManagerStatics> ppmStatics;

ABI::Windows::Foundation::GetActivationFactory
    (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmStatics);

boolean result;

ppmStatics->IsIdentityManaged(identity, &amp;result);

if (!result)
    return -1;

C++/ CX snippet

if (!ProtectionPolicyManager::IsIdentityManaged(identity))
{
    // Identity is not managed so no need to protect the file.
    // Prompt the user, log a message, or perform some other action.
}

APIs:

ProtectionPolicyManager.IsIdentityManaged

STEP 2: CREATE A FILE AND PROTECT IT TO THE ENTITY

The FileProtectionManager.CreateProtectedAndOpenAsync creates a protected file and keeps the file handle open while you write to it.

C++ snippet

HString hstrKnownFolders;

hstrKnownFolders.Set(RuntimeClass_Windows_Storage_KnownFolders);

ComPtr<IActivationFactory> pKnownFoldersActivationFactory;
ABI::Windows::Foundation::GetActivationFactory(hstrKnownFolders.Get(), &amp;pKnownFoldersActivationFactory);

ComPtr<IKnownFoldersStatics> pKnownFolders;
pKnownFoldersActivationFactory.As(&amp;pKnownFolders);

ComPtr<IStorageFolder> pStorageFolder;
pKnownFolders->get_DocumentsLibrary(&amp;pStorageFolder);

ComPtr<IFileProtectionManagerStatics> fpmStatics;

ABI::Windows::Foundation::GetActivationFactory
    (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_FileProtectionManager).Get(), &amp;fpmStatics);

__FIAsyncOperation_1_Windows__CSecurity__CEnterpriseData__CProtectedFileCreateResult_t * protectOperation;

fpmStatics->CreateProtectedAndOpenAsync(pStorageFolder.Get(), HStringReference(L"sample.txt").Get(), identity,
    CreationCollisionOption::CreationCollisionOption_ReplaceExisting, &amp;protectOperation);

Event protectOperationCompleted(CreateEvent(nullptr, true, false, nullptr));

protectOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<ProtectedFileCreateResult*>>
    ([&amp;](IAsyncOperation<ProtectedFileCreateResult*> *pHandler, AsyncStatus status) -> HRESULT
{
    SetEvent(protectOperationCompleted.Get());
    return S_OK;

}).Get());

WaitForSingleObject(protectOperationCompleted.Get(), INFINITE);

ComPtr<IProtectedFileCreateResult> fileProtectionResult;

protectOperation->GetResults(&amp;fileProtectionResult);

IFileProtectionInfo * fileProtectionInfo;

fileProtectionResult->get_ProtectionInfo(&amp;fileProtectionInfo);

FileProtectionStatus status;

fileProtectionInfo->get_Status(&amp;status);

if (status == FileProtectionStatus::FileProtectionStatus_Protected)
{
    SaveDataToAStreamInBackground(enterpriseData, fileProtectionResult.Get());
}
else if (status == FileProtectionStatus::FileProtectionStatus_AccessSuspended)
{
    // Perform any special processing for the access suspended case.
}

C++/ CX snippet

StorageFolder ^storageFolder = KnownFolders::DocumentsLibrary;

auto createProtectedTask = create_task(FileProtectionManager::CreateProtectedAndOpenAsync
(storageFolder, "sample.txt", identity, CreationCollisionOption::ReplaceExisting));

APIs:

FileProtectionManager.CreateProtectedAndOpenAsync

STEP 3: WRITE A STREAM OR BUFFER TO THE FILE

This example writes a stream to a file.

C++ snippet

int WIP::SaveDataToAStreamInBackground(HSTRING enterpriseData, IProtectedFileCreateResult * protectedFileCreateResult)
{
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);

    ComPtr<IRandomAccessStream> stream;

    IOutputStream * outputStream;

    protectedFileCreateResult->get_Stream(&amp;stream);

    stream->GetOutputStreamAt(0, &amp;outputStream);

    ComPtr<IDataWriter> dataWriter;

    ComPtr<IDataWriterFactory> dataWriterFactory;

    Windows::Foundation::GetActivationFactory
        (HStringReference(RuntimeClass_Windows_Storage_Streams_DataWriter).Get(), &amp;dataWriterFactory);

    dataWriterFactory->CreateDataWriter(outputStream, &amp;dataWriter);

    UINT32 byteCount;

    dataWriter->WriteString(enterpriseData, &amp;byteCount);

    __FIAsyncOperation_1_UINT32_t * storeOperation;

    Event storeOperationCompleted(CreateEvent(nullptr, true, false, nullptr));

    dataWriter->StoreAsync(&amp;storeOperation);

    storeOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<UINT32>>
        ([&amp;](IAsyncOperation<UINT32> *pHandler, AsyncStatus status) -> HRESULT
    {
        SetEvent(storeOperationCompleted.Get());
        return S_OK;
    }).Get());

    WaitForSingleObject(storeOperationCompleted.Get(), INFINITE);

    __FIAsyncOperation_1_boolean_t * flushOperation;

    dataWriter->FlushAsync(&amp;flushOperation);

    Event flushOperationCompleted(CreateEvent(nullptr, true, false, nullptr));

    flushOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<bool>>
        ([&amp;](IAsyncOperation<bool> *pHandler, AsyncStatus status) -> HRESULT
    {
        SetEvent(flushOperationCompleted.Get());
        return S_OK;
    }).Get());

    WaitForSingleObject(flushOperationCompleted.Get(), INFINITE);

    return 0;
}

C++/ CX snippet

createProtectedTask.then([enterpriseData](ProtectedFileCreateResult ^protectedFileCreateResult)
{
    if (protectedFileCreateResult->ProtectionInfo->Status == FileProtectionStatus::Protected)
    {
        IOutputStream ^outputStream = protectedFileCreateResult->Stream->GetOutputStreamAt(0);
        {
            DataWriter ^writer = ref new DataWriter(outputStream);
            writer->WriteString(enterpriseData);

            auto storeTask = create_task(writer->StoreAsync());

            storeTask.then([writer](task<unsigned int>bytesWritten)
            {
                auto flushTask = create_task(writer->FlushAsync());

                flushTask.then([&amp;](task<bool>result)
                {
                    delete writer;
                });
            });
        }
        delete outputStream;
     }
     else if (protectedFileCreateResult->ProtectionInfo->Status == FileProtectionStatus::AccessSuspended)
     {
         // Perform any special processing for the access suspended case.
     }
});

APIs:

ProtectedFileCreateResult.ProtectionInfo
FileProtectionStatus
ProtectedFileCreateResult.Stream

Protect part of a file

In most cases, it's cleaner to store enterprise and personal data separately but you can store them to the same file if you want. For example, Microsoft Outlook can store enterprise mails alongside of personal mails in a single archive file.

Encrypt the enterprise data but not the entire file. That way, users can continue using that file even if they un-enroll from MDM or their enterprise data access rights are revoked. Also, your app should keep track of what data it encrypts so that it knows what data to protect when it reads the file back into memory.

STEP 1: ADD ENTERPRISE DATA TO AN ENCRYPTED STREAM OR BUFFER

C++ snippet

RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);

HSTRING enterpriseDataString = HStringReference(L"<employees><employee><name>Bill</name><social>xxx-xxx-xxxx</social></employee></employees>").Get();

ComPtr<ICryptographicBufferStatics> cryptographicBuffer;

ABI::Windows::Foundation::GetActivationFactory
    (HStringReference(RuntimeClass_Windows_Security_Cryptography_CryptographicBuffer).Get(), &amp;cryptographicBuffer);

ComPtr<IBufferFactory> bufferFactory;

ABI::Windows::Foundation::GetActivationFactory
(HStringReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(), &amp;bufferFactory);

ComPtr<IBuffer> buffer;

bufferFactory->Create(sizeof(enterpriseDataString), &amp;buffer);

cryptographicBuffer->ConvertStringToBinary(enterpriseDataString, BinaryStringEncoding::BinaryStringEncoding_Utf8, &amp;buffer);

ComPtr<IDataProtectionManagerStatics> pdpStatics;

HRESULT hr = ABI::Windows::Foundation::GetActivationFactory
    (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_DataProtectionManager).Get(), &amp;pdpStatics);

__FIAsyncOperation_1_Windows__CSecurity__CEnterpriseData__CBufferProtectUnprotectResult_t *operation;

// This is enterprise data - encrypt it.

pdpStatics->ProtectAsync(buffer.Get(), identity, &amp;operation);

Event operationCompleted(CreateEvent(nullptr, true, false, nullptr));

operation->put_Completed(Callback<IAsyncOperationCompletedHandler<BufferProtectUnprotectResult*>>
    ([&amp;](IAsyncOperation<BufferProtectUnprotectResult*> *pHandler, AsyncStatus status) -> HRESULT
{
    SetEvent(operationCompleted.Get());
    return S_OK;

}).Get());

WaitForSingleObject(operationCompleted.Get(), INFINITE);

IBufferProtectUnprotectResult * pIBProtectUnprotectResult;

operation->GetResults(&amp;pIBProtectUnprotectResult);

IBuffer * enterpriseBuffer;

pIBProtectUnprotectResult->get_Buffer(&amp;enterpriseBuffer);

C++/ CX snippet

Platform::String ^enterpriseDataString = 
    "<employees><employee><name>Bill</name><social>xxx-xxx-xxxx</social></employee></employees>";

auto enterpriseData = Windows::Security::Cryptography::CryptographicBuffer::ConvertStringToBinary
(enterpriseDataString, Windows::Security::Cryptography::BinaryStringEncoding::Utf8);


auto protectTask = create_task(DataProtectionManager::ProtectAsync(enterpriseData, identity));

protectTask.then([enterpriseData](BufferProtectUnprotectResult ^result)
{
    enterpriseData = result->Buffer;

    // next snippet goes in here.

});

APIs:

DataProtectionManager.ProtectAsync
BufferProtectUnprotectResult.buffer

STEP 2: ADD PERSONAL DATA TO AN UNENCRYPTED STREAM OR BUFFER

C++snippet

HSTRING personalDataString = HStringReference(L"<recipies><recipe><name>BillsCupCakes</name><cooktime>30</cooktime></recipe></recipies>").Get();

IBuffer * personalBuffer;

bufferFactory->Create(sizeof(personalDataString), &amp;personalBuffer);

cryptographicBuffer->ConvertStringToBinary(personalDataString, BinaryStringEncoding::BinaryStringEncoding_Utf8, &amp;personalBuffer);

C++/ CX snippet

Platform::String ^personalDataString = 
    "<recipies><recipe><name>BillsCupCakes</name><cooktime>30</cooktime></recipe></recipies>";

auto personalData = Windows::Security::Cryptography::CryptographicBuffer::ConvertStringToBinary
(personalDataString, Windows::Security::Cryptography::BinaryStringEncoding::Utf8);

STEP 3: WRITE BOTH STREAMS OR BUFFERS TO THE FILE

C++ snippet

__FIAsyncOperation_1_Windows__CStorage__CStreams__CIRandomAccessStream_t * openOperation;

pFile->OpenAsync(FileAccessMode::FileAccessMode_ReadWrite, &amp;openOperation);

Event OpenOperationCompleted(CreateEvent(nullptr, true, false, nullptr));

openOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<IRandomAccessStream*>>
    ([&amp;](IAsyncOperation<IRandomAccessStream*> *pHandler, AsyncStatus status) -> HRESULT
{
    SetEvent(OpenOperationCompleted.Get());
    return S_OK;

}).Get());

WaitForSingleObject(OpenOperationCompleted.Get(), INFINITE);

ComPtr<IRandomAccessStream> stream;

openOperation->GetResults(&amp;stream);

IOutputStream * outputStream;

stream->GetOutputStreamAt(0, &amp;outputStream);

ComPtr<IDataWriter> dataWriter;

ComPtr<IDataWriterFactory> dataWriterFactory;

Windows::Foundation::GetActivationFactory
    (HStringReference(RuntimeClass_Windows_Storage_Streams_DataWriter).Get(), &amp;dataWriterFactory);

dataWriterFactory->CreateDataWriter(outputStream, &amp;dataWriter);

UINT32 byteCount;

dataWriter->WriteBuffer(enterpriseBuffer);

dataWriter->WriteBuffer(personalBuffer);

__FIAsyncOperation_1_UINT32_t * storeOperation;

Event storeOperationCompleted(CreateEvent(nullptr, true, false, nullptr));

dataWriter->StoreAsync(&amp;storeOperation);

storeOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<UINT32>>
([&amp;](IAsyncOperation<UINT32> *pHandler, AsyncStatus status) -> HRESULT
{
    SetEvent(storeOperationCompleted.Get());
    return S_OK;

}).Get());

WaitForSingleObject(storeOperationCompleted.Get(), INFINITE);

__FIAsyncOperation_1_boolean_t * flushOperation;

dataWriter->FlushAsync(&amp;flushOperation);

Event flushOperationCompleted(CreateEvent(nullptr, true, false, nullptr));

flushOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<bool>>
    ([&amp;](IAsyncOperation<bool> *pHandler, AsyncStatus status) -> HRESULT
{
    SetEvent(flushOperationCompleted.Get());
    return S_OK;

}).Get());

WaitForSingleObject(flushOperationCompleted.Get(), INFINITE);

C++/ CX snippet

StorageFolder ^storageFolder = KnownFolders::DocumentsLibrary;

auto createFileTask = create_task(storageFolder->CreateFileAsync("data.xml", CreationCollisionOption::ReplaceExisting));

createFileTask.then([enterpriseDataResult, personalData](StorageFile ^storageFile)
{
    // Write both buffers to the file and save the file.
    auto openTask = create_task(storageFile->OpenAsync(FileAccessMode::ReadWrite));

    openTask.then([enterpriseDataResult, personalData](IRandomAccessStream ^stream)
    {
        {
            auto outputStream = stream->GetOutputStreamAt(0);
            {
                auto dataWriter = ref new DataWriter(outputStream);
                dataWriter->WriteBuffer(enterpriseData);
                dataWriter->WriteBuffer(personalData);

                auto storeTask = create_task(dataWriter->StoreAsync());

                storeTask.then([dataWriter](task<unsigned int>bytesWritten)
                {
                    auto flushTask = create_task(dataWriter->FlushAsync());
                    flushTask.then([dataWriter](task<bool>result)
                    {
                        delete dataWriter;
                    });
                 });
            }
    }
  
    
});

STEP 4: KEEP TRACK OF THE LOCATION OF YOUR ENTERPRISE DATA IN THE FILE

It's the responsibility of your app to keep track of which data in that file that is enterprise owned.

You can store that information in a property associated with the file, in a database, or in some header text in the file.

Read the protected part of a file

Here's how you'd read the enterprise data out of that file.

STEP 1: OPEN THE DATA FILE AND MAKE SURE IT'S NOT PROTECTED

C++ snippet

int WIP::OpenDataFile(IStorageFolder * pStorageFolder)
{
    __FIAsyncOperation_1_Windows__CStorage__CStorageFile_t* dataFileOperation;

    pStorageFolder->GetFileAsync(HStringReference(L"data.xml").Get(), &amp;dataFileOperation);

    Event dataFileOperationCompleted(CreateEvent(nullptr, true, false, nullptr));

    dataFileOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<StorageFile*>>
        ([&amp;](IAsyncOperation<StorageFile*> *pHandler, AsyncStatus status) -> HRESULT
    {
        SetEvent(dataFileOperationCompleted.Get());
        return S_OK;
    }).Get());

    WaitForSingleObject(dataFileOperationCompleted.Get(), INFINITE);

    IStorageFile * dataFile;

    dataFileOperation->GetResults(&amp;dataFile);

    return 0;
}

int WIP::GetProtectionInfo(HSTRING identity, IStorageFile * file, bool **canRead)
{
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);

    ComPtr<IFileProtectionManagerStatics> fpmStatics;

    Windows::Foundation::GetActivationFactory
        (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_FileProtectionManager).Get(), &amp;fpmStatics);

    __FIAsyncOperation_1_Windows__CSecurity__CEnterpriseData__CFileProtectionInfo_t *operation;

    ComPtr<IStorageItem> storageItem;
    ComPtr<IStorageFile> x(file);
    x.As(&amp;storageItem);

    fpmStatics->GetProtectionInfoAsync(storageItem.Get(), &amp;operation);

    Event operationCompleted(CreateEvent(nullptr, true, false, nullptr));

    operation->put_Completed(Callback<IAsyncOperationCompletedHandler<FileProtectionInfo*>>
        ([&amp;](IAsyncOperation<FileProtectionInfo*> *pHandler, AsyncStatus status) -> HRESULT
    {
        SetEvent(operationCompleted.Get());
        return S_OK;

    }).Get());

    WaitForSingleObject(operationCompleted.Get(), INFINITE);

    IFileProtectionInfo * fileProtectionInfo;
    FileProtectionStatus fileProtectionStatus;

    operation->GetResults(&amp;fileProtectionInfo);

    fileProtectionInfo->get_Status(&amp;fileProtectionStatus);

    bool readable = true;

    if (fileProtectionStatus == FileProtectionStatus::FileProtectionStatus_Protected) 
    {
        ComPtr<IProtectionPolicyManagerStatics> ppmStatics;

        Windows::Foundation::GetActivationFactory
        (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmStatics);

        boolean result;

        ppmStatics->IsIdentityManaged(identity, &amp;result);

        if (result == 0) 
            readable = false;
    }

    *canRead = &amp;readable;

    return 0;
}

C++/ CX snippet

auto getFileTask = create_task(storageFolder->GetFileAsync("data.xml"));

getFileTask.then([&amp;](Windows::Storage::StorageFile ^dataFile)
{
    auto getProtectionInfoTask = create_task(FileProtectionManager::GetProtectionInfoAsync(dataFile));

    getProtectionInfoTask.then([dataFile, startPosition, endPosition](FileProtectionInfo ^protectionInfo)
    {
              if (protectionInfo->Status == FileProtectionStatus::Protected)
        {
            // Prompt the user, log an error, or perform some other action.
        }

    // Next snippet goes in here.

});

APIs:

FileProtectionManager.GetProtectionInfoAsync
FileProtectionInfo
FileProtectionStatus

STEP 2: READ THE ENTERPRISE DATA FROM THE FILE

C++ snippet

RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);

__FIAsyncOperation_1_Windows__CStorage__CStreams__CIRandomAccessStream_t *operation;

file->OpenAsync(FileAccessMode::FileAccessMode_ReadWrite, &amp;operation);

Event operationCompleted(CreateEvent(nullptr, true, false, nullptr));

operation->put_Completed(Callback<IAsyncOperationCompletedHandler<IRandomAccessStream*>>
    ([&amp;](IAsyncOperation<IRandomAccessStream*> *pHandler, AsyncStatus status) -> HRESULT
    {
        SetEvent(operationCompleted.Get());
        return S_OK;
    }).Get());

WaitForSingleObject(operationCompleted.Get(), INFINITE);

IRandomAccessStream * pRandomAccessStream;

operation->GetResults(&amp;pRandomAccessStream);

IInputStream * inputStream;

pRandomAccessStream->GetInputStreamAt(0, &amp;inputStream);

ComPtr<IBufferFactory> bufferFactory;

ABI::Windows::Foundation::GetActivationFactory
    (HStringReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(), &amp;bufferFactory);

ComPtr<IBuffer> buffer;

bufferFactory->Create(50000, &amp;buffer);

__FIAsyncOperationWithProgress_2_Windows__CStorage__CStreams__CIBuffer_UINT32_t * readOperation;

// endposition is an unsigned int that you provide. It identifies the position of the enterprise data in the file.

inputStream->ReadAsync(buffer.Get(), endPosition, InputStreamOptions_None, &amp;readOperation);

Event readOperationCompleted(CreateEvent(nullptr, true, false, nullptr));

readOperation->put_Completed(Callback<IAsyncOperationWithProgressCompletedHandler<IBuffer*, UINT32>>
    ([&amp;](IAsyncOperationWithProgress<IBuffer*, UINT32> *pHandler, AsyncStatus status) -> HRESULT
{
    SetEvent(readOperationCompleted.Get());
    return S_OK;
}).Get());

WaitForSingleObject(readOperationCompleted.Get(), INFINITE);

ComPtr<IBuffer> enterpriseBuffer;

readOperation->GetResults(&amp;enterpriseBuffer);

ComPtr<IDataProtectionManagerStatics> pdpStatics;

HRESULT hr = ABI::Windows::Foundation::GetActivationFactory
    (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_DataProtectionManager).Get(), &amp;pdpStatics);

__FIAsyncOperation_1_Windows__CSecurity__CEnterpriseData__CDataProtectionInfo_t * dataProtectionInfoOperation;

hr = pdpStatics->GetProtectionInfoAsync(enterpriseBuffer.Get(), &amp;dataProtectionInfoOperation);

Event dataProtectionInfoOperationCompleted(CreateEvent(nullptr, true, false, nullptr));

dataProtectionInfoOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<DataProtectionInfo*>>
    ([&amp;](IAsyncOperation<DataProtectionInfo*> *pHandler, AsyncStatus status) -> HRESULT
{
    SetEvent(dataProtectionInfoOperationCompleted.Get());
    return S_OK;

}).Get());

WaitForSingleObject(dataProtectionInfoOperationCompleted.Get(), INFINITE);

C++/ CX snippet

auto streamTask = create_task(dataFile->OpenAsync(Windows::Storage::FileAccessMode::ReadWrite));

streamTask.then([startPosition, endPosition](IRandomAccessStream ^stream)
{
    stream->Seek(startPosition);
  
    Windows::Storage::Streams::Buffer ^tempBuffer = ref new Windows::Storage::Streams::Buffer(50000);
 
   // endposition is an unsigned int that you provide. It identifies the position of the enterprise data in the file.

    auto readTask = create_task(stream->ReadAsync(tempBuffer, endPosition, InputStreamOptions::None));

    readTask.then([](IBuffer ^enterpriseData)
    {

        // Next snippet goes in here.

    });
}

STEP 3: DECRYPT THE BUFFER THAT CONTAINS ENTERPRISE DATA

C++ snippet

ComPtr<IDataProtectionInfo> info;

hr = dataProtectionInfoOperation->GetResults(&amp;info);

DataProtectionStatus status;

info->get_Status(&amp;status);

if (status == DataProtectionStatus::DataProtectionStatus_Protected)
{
    __FIAsyncOperation_1_Windows__CSecurity__CEnterpriseData__CBufferProtectUnprotectResult_t *unProtectOperation;

    pdpStatics->UnprotectAsync(enterpriseBuffer.Get(), &amp;unProtectOperation);

    Event unProtectOperationCompleted(CreateEvent(nullptr, true, false, nullptr));

    unProtectOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<BufferProtectUnprotectResult*>>
    ([&amp;](IAsyncOperation<BufferProtectUnprotectResult*> *pHandler, AsyncStatus status) -> HRESULT
    {
        SetEvent(unProtectOperationCompleted.Get());
        return S_OK;

    }).Get());

    WaitForSingleObject(unProtectOperationCompleted.Get(), INFINITE);

    IBufferProtectUnprotectResult * unProtectResults;

    unProtectOperation->GetResults(&amp;unProtectResults);
}

C++/ CX snippet

auto dataProtectionManagerTask = create_task(DataProtectionManager::GetProtectionInfoAsync(enterpriseData));

dataProtectionManagerTask.then([enterpriseData](DataProtectionInfo ^dataProtectionInfo)
{
    if (dataProtectionInfo->Status == DataProtectionStatus::Protected)
    {
        auto unprotectTask = create_task(DataProtectionManager::UnprotectAsync(enterpriseData));
        unprotectTask.then([](BufferProtectUnprotectResult ^result)
        {
            IBuffer ^ decryptedEnterpriseData = result->Buffer;
        });
    }
}

APIs:

DataProtectionInfo
DataProtectionManager.GetProtectionInfoAsync

Protect data to a folder

You can create a folder and protect it. That way any items that you add to that folder are automatically protected.

C++ snippet

int WIP::CreateANewFolderAndProtectAsync(HSTRING folderName, HSTRING identity)
{
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);

    ComPtr<IProtectionPolicyManagerStatics> ppmStatics;

    ABI::Windows::Foundation::GetActivationFactory
        (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmStatics);

    boolean result;

    ppmStatics->IsIdentityManaged(identity, &amp;result);

    HString hstrKnownFolders;
    hstrKnownFolders.Set(RuntimeClass_Windows_Storage_KnownFolders);

    ComPtr<IActivationFactory> pKnownFoldersActivationFactory;
    ABI::Windows::Foundation::GetActivationFactory(hstrKnownFolders.Get(), &amp;pKnownFoldersActivationFactory);

    ComPtr<IKnownFoldersStatics> pKnownFolders;
    pKnownFoldersActivationFactory.As(&amp;pKnownFolders);

    ComPtr<IStorageFolder> pStorageFolder;
    pKnownFolders->get_DocumentsLibrary(&amp;pStorageFolder);

    __FIAsyncOperation_1_Windows__CStorage__CStorageFolder_t * folderOperation;

    pStorageFolder->CreateFolderAsync(folderName, CreationCollisionOption_OpenIfExists, &amp;folderOperation);

    Event folderOperationCompleted(CreateEvent(nullptr, true, false, nullptr));

    folderOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<StorageFolder*>>
    ([&amp;](IAsyncOperation<StorageFolder*> *pHandler, AsyncStatus status) -> HRESULT
    {
        SetEvent(folderOperationCompleted.Get());
        return S_OK;
    }).Get());

    WaitForSingleObject(folderOperationCompleted.Get(), INFINITE);

    ComPtr<IStorageFolder> pNewFolder;

    HRESULT hr = folderOperation->GetResults(&amp;pNewFolder);

    ComPtr<IFileProtectionManagerStatics> fpmStatics;

    ABI::Windows::Foundation::GetActivationFactory
        (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_FileProtectionManager).Get(), &amp;fpmStatics);

    __FIAsyncOperation_1_Windows__CSecurity__CEnterpriseData__CFileProtectionInfo_t * protectOperation;

    ComPtr<IStorageItem> storageItem;

    pNewFolder.As(&amp;storageItem);

    fpmStatics->ProtectAsync(storageItem.Get(), identity, &amp;protectOperation);

    Event protectOperationCompleted(CreateEvent(nullptr, true, false, nullptr));

    protectOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<FileProtectionInfo*>>
        ([&amp;](IAsyncOperation<FileProtectionInfo*> *pHandler, AsyncStatus status) -> HRESULT
    {
        SetEvent(protectOperationCompleted.Get());
        return S_OK;
    }).Get());

    WaitForSingleObject(protectOperationCompleted.Get(), INFINITE);

    ComPtr<IFileProtectionInfo> fileProtectionInfo;

    protectOperation->GetResults(&amp;fileProtectionInfo);

    FileProtectionStatus status;

    fileProtectionInfo->get_Status(&amp;status);

    if (status != FileProtectionStatus::FileProtectionStatus_Protected)
    {
        // Protection failed.

        return -1;

    }

    return 0;
}

C++/ CX snippet

task<bool> CreateANewFolderAndProtectItAsync(Platform::String ^folderName, Platform::String ^identity)
{
    if (!ProtectionPolicyManager::IsIdentityManaged(identity))
    {
        // Identity is not managed so no need to protect the file.
        // Prompt the user, log a message, or perform some other action.
    }

    StorageFolder ^storageFolder = KnownFolders::DocumentsLibrary;

    auto createFolderTask = create_task(storageFolder->CreateFolderAsync(folderName));

    createFolderTask.then([identity](StorageFolder ^newStorageFolder)
    {
        auto protectTask = create_task(FileProtectionManager::ProtectAsync(newStorageFolder, identity));

        protectTask.then([](FileProtectionInfo ^fileProtectionInfo)
        {
            if (fileProtectionInfo->Status != FileProtectionStatus::Protected)
            {
                // Protection failed.
            }
        });
    });
    return task_from_result<bool>(true);
}

APIs:

ProtectionPolicyManager.IsIdentityManaged
FileProtectionManager.ProtectAsync
FileProtectionInfo.Identity
FileProtectionInfo.Status

Protect data to a network end point

Create a protected thread context to send data to an enterprise endpoint.

STEP 1: GET THE IDENTITY OF THE NETWORK ENDPOINT

C++ snippet

RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);

ComPtr<IHostNameFactory> hostNameFactory;

ABI::Windows::Foundation::GetActivationFactory
 (HStringReference(RuntimeClass_Windows_Networking_HostName).Get(), &amp;hostNameFactory);
  
ComPtr<IHostName> hostName;

hostNameFactory->CreateHostName(resourceURL, &amp;hostName);

ComPtr<IProtectionPolicyManagerStatics> ppmStatics;

ABI::Windows::Foundation::GetActivationFactory
 (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmStatics);

__FIAsyncOperation_1_HSTRING_t * result;

ppmStatics->GetPrimaryManagedIdentityForNetworkEndpointAsync(hostName.Get(), &amp;result);
Event operationCompleted(CreateEvent(nullptr, true, false, nullptr));

result->put_Completed(Callback<IAsyncOperationCompletedHandler<HSTRING>>
 ([&amp;](IAsyncOperation<HSTRING> *pHandler, AsyncStatus status) -> HRESULT
{
  SetEvent(operationCompleted.Get());
  return S_OK;

}).Get());

WaitForSingleObject(operationCompleted.Get(), INFINITE);

C++/ CX snippet

Windows::Networking::HostName ^hostName = ref new Windows::Networking::HostName(resourceURI->Host);

auto getPrimaryNetworkEndPointTask = 
    create_task(ProtectionPolicyManager::GetPrimaryManagedIdentityForNetworkEndpointAsync(hostName));

// "resourceURI is a URI object and "dataToWrite" is an IInputStream.
getPrimaryNetworkEndPointTask.then([resourceURI, dataToWrite](Platform::String ^identity)
{

    // Next snippet goes in here.

});

APIs:

ProtectionPolicyManager.GetPrimaryManagedIdentityForNetworkEndpointAsync

STEP 2: CREATE A PROTECTED THREAD CONTEXT AND SEND DATA TO THE NETWORK ENDPOINT

C++ snippet

ComPtr<IProtectionPolicyManagerInterop> ppmInterop;

ABI::Windows::Foundation::GetActivationFactory
    (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmInterop);

ComPtr<IProtectionPolicyManager> ppmInstance;

ppmInterop->GetForWindow(hWnd, IID_PPV_ARGS(&amp;ppmInstance));

ppmInstance->put_Identity(identity);

ComPtr<IHttpClientFactory> httpClientFactory;

ABI::Windows::Foundation::GetActivationFactory
    (HStringReference(RuntimeClass_Windows_Web_Http_HttpClient).Get(), &amp;httpClientFactory);
    
IThreadNetworkContext * threadNetworkContextResult;

ppmStatics->CreateCurrentThreadNetworkContext(identity, &amp;threadNetworkContextResult);

ComPtr<IHttpBaseProtocolFilter> baseProtocolFilter;

RoActivateInstance
    (HStringReference(RuntimeClass_Windows_Web_Http_Filters_HttpBaseProtocolFilter).Get(), &amp;baseProtocolFilter);

ComPtr<IHttpFilter> filter;

baseProtocolFilter.As(&amp;filter);

ComPtr<IHttpClient> httpClient;

httpClientFactory->Create(filter.Get(), &amp;httpClient);

ComPtr<IHttpRequestMessageFactory> requestMessageFactory;

ABI::Windows::Foundation::GetActivationFactory
    (HStringReference(RuntimeClass_Windows_Web_Http_HttpRequestMessage).Get(), &amp;requestMessageFactory);

ComPtr<IHttpMethodFactory> requestMethodFactory;

ABI::Windows::Foundation::GetActivationFactory
    (HStringReference(RuntimeClass_Windows_Web_Http_HttpMethod).Get(), &amp;requestMethodFactory);

ComPtr<IHttpMethod> httpMethod;

HString str;
str.Set(L"PUT");

requestMethodFactory->Create(str.Get(), &amp;httpMethod);

IHttpRequestMessage * requestMessage;

ComPtr<IUriRuntimeClassFactory> uriFactory;

ABI::Windows::Foundation::GetActivationFactory
    (HStringReference(RuntimeClass_Windows_Foundation_Uri).Get(), &amp;uriFactory)

ComPtr<IUriRuntimeClass> uriRuntime;

uriFactory->CreateUri(resourceURL, &amp;uriRuntime);

requestMessageFactory->Create(httpMethod.Get(), uriRuntime.Get(), &amp;requestMessage);

ComPtr<IHttpStreamContentFactory> streamContentFactory;

ABI::Windows::Foundation::GetActivationFactory
    (HStringReference(RuntimeClass_Windows_Web_Http_HttpStreamContent).Get(), &amp;streamContentFactory);

ComPtr<IHttpContent> content;

streamContentFactory->CreateFromInputStream(dataToWrite, &amp;content); // dataToWrite variable is an IInputStream

requestMessage->put_Content(content.Get());

__FIAsyncOperationWithProgress_2_Windows__CWeb__CHttp__CHttpResponseMessage_Windows__CWeb__CHttp__CHttpProgress_t * requestOperation;

httpClient->SendRequestAsync(requestMessage, &amp;requestOperation);

Event requestOperationCompleted(CreateEvent(nullptr, true, false, nullptr));

requestOperation->put_Completed(Callback<IAsyncOperationWithProgressCompletedHandler<HttpResponseMessage*, HttpProgress>>
([&amp;](IAsyncOperationWithProgress<HttpResponseMessage*, HttpProgress> *pHandler, AsyncStatus status) -> HRESULT
{
    SetEvent(requestOperationCompleted.Get());
    return S_OK;

}).Get());

WaitForSingleObject(requestOperationCompleted.Get(), INFINITE);

C++/ CX snippet

HttpClient ^client = nullptr;

if ((identity) &amp;&amp; !(identity->IsEmpty()))
{

    ThreadNetworkContext ^threadNetworkContext = 
        ProtectionPolicyManager::CreateCurrentThreadNetworkContext(identity);
    client = ref new HttpClient();

    HttpRequestMessage ^message = ref new HttpRequestMessage(HttpMethod::Put, resourceURI);
    message->Content = ref new HttpStreamContent(dataToWrite);

    auto sendRequestTask = create_task(client->SendRequestAsync(message));

    sendRequestTask.then([](HttpResponseMessage ^response)
    {
        if (response->StatusCode == HttpStatusCode::Ok)
        {
            // write successful
        }
        else
        {
            // write not successful
        }
    });

}
else
{
    // Can't write the network location.
}

APIs:

ProtectionPolicyManager.Identity
ProtectionPolicyManager.CreateCurrentThreadNetworkContext

Protect files that you copy to another location

C++ snippet

int WIP::ProtectFromOneFileToAnother(IStorageFile * sourceFile, IStorageFile * targetFile)
{
    ComPtr<IFileProtectionManagerStatics> fpmStatics;

    ABI::Windows::Foundation::GetActivationFactory
        (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_FileProtectionManager).Get(), &amp;fpmStatics);

    __FIAsyncOperation_1_boolean_t * protectOperation;

    ComPtr<IStorageFile> comPtrSourceFile(sourceFile);
    ComPtr<IStorageItem> sourceStorageItem;
    comPtrSourceFile.As(&amp;sourceStorageItem);
   
    ComPtr<IStorageFile> comPtrTargetFile(targetFile);
    ComPtr<IStorageItem> targetStorageItem;
    comPtrTargetFile.As(&amp;targetStorageItem);

    fpmStatics->CopyProtectionAsync(sourceStorageItem.Get(), targetStorageItem.Get(), &amp;protectOperation);

    Event protectOperationCompleted(CreateEvent(nullptr, true, false, nullptr));

    protectOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<bool>>
        ([&amp;](IAsyncOperation<bool> *pHandler, AsyncStatus status) -> HRESULT
    {
        SetEvent(protectOperationCompleted.Get());
        return S_OK;

    }).Get());

    WaitForSingleObject(protectOperationCompleted.Get(), INFINITE);

    boolean results;

    protectOperation->GetResults(&amp;results);

    if (results)
        return 0;
    else
        return -1;
}

C++/ CX snippet

void CopyProtectionFromOneFileToAnother
    (StorageFile ^  ^sourceStorageFile, StorageFile ^  ^targetStorageFile)
{
    auto ^copyProtectionTask = 
        create_task(FileProtectionManager::CopyProtectionAsync(sourceStorageFile, targetStorageFile));

    copyProtectionTask->then([](bool copyResult) {
        if (!copyResult) 
        {
             // Copying failed. To diagnose, you could check the file's status.
             // (call FileProtectionManager.GetProtectionInfoAsync and
             // check FileProtectionInfo.Status).
    }});

}

APIs:

FileProtectionManager.CopyProtectionAsync

Protect enterprise data when the screen is locked

Remove all sensitive data in memory when the device is locked. When the user unlocks the device, your app can safely add that data back.

Handle the ProtectionPolicyManager.ProtectedAccessSuspending event so that your app knows when the screen is locked. This event is raised only if the administrator configures a secure data protection under lock policy. Windows temporarily removes the data protection keys that are provisioned on the device. Windows removes these keys to ensure that there is no unauthorized access to encrypted data while the device is locked and possibly not in possession of its owner.

Handle the ProtectionPolicyManager.ProtectedAccessResumed event so that your app knows when the screen is unlocked. This event is raised regardless of whether the administrator configures a secure data protection under lock policy.

Remove sensitive data in memory when the screen is locked

Protect sensitive data, and close any file streams that your app has opened on protected files to help ensure that the system doesn't cache any sensitive data in memory.

This example saves content from a text block to an encrypted buffer and removes the content from that text block.

C++ snippet

int WIP::HandleProtectedAccessSuspending(HWND hWnd, HSTRING ** textBoxString, IProtectedAccessSuspendingEventArgs * e)
{
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);

    ComPtr<IDeferral> deferral;

    ABI::Windows::Foundation::GetActivationFactory
      (HStringReference(RuntimeClass_Windows_Foundation_Deferral).Get(), &amp;deferral);

    e->GetDeferral(&amp;deferral);

    ComPtr<IProtectionPolicyManagerStatics> ppmStatics;

    ABI::Windows::Foundation::GetActivationFactory
       (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmStatics);

    ComPtr<IProtectionPolicyManagerInterop> ppmInterop;

    ABI::Windows::Foundation::GetActivationFactory
       (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmInterop);

    ComPtr<IProtectionPolicyManager> ppmInstance;

    HSTRING identity;

    if (SUCCEEDED(ppmInterop->GetForWindow(hWnd, IID_PPV_ARGS(&amp;ppmInstance))))
    {
        HRESULT hRet = ppmInstance->get_Identity(&amp;identity);

        if (identity != NULL) 
        {
            ComPtr<ICryptographicBufferStatics> cryptographicBuffer;

            ABI::Windows::Foundation::GetActivationFactory
                (HStringReference(RuntimeClass_Windows_Security_Cryptography_CryptographicBuffer).Get(), &amp;cryptographicBuffer);

            // "protectedDocumentBuffer is a global IBuffer. 
            cryptographicBuffer->ConvertStringToBinary(**textBoxString, BinaryStringEncoding::BinaryStringEncoding_Utf8, &amp;protectedDocumentBuffer);

            ComPtr<IDataProtectionManagerStatics> pdpStatics;

            HRESULT hr = ABI::Windows::Foundation::GetActivationFactory
                (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_DataProtectionManager).Get(), &amp;pdpStatics);

            __FIAsyncOperation_1_Windows__CSecurity__CEnterpriseData__CBufferProtectUnprotectResult_t *operation;

            pdpStatics->ProtectAsync(protectedDocumentBuffer.Get(), identity, &amp;operation);

            Event operationCompleted(CreateEvent(nullptr, true, false, nullptr));

            operation->put_Completed(Callback<IAsyncOperationCompletedHandler<BufferProtectUnprotectResult*>>
                ([&amp;](IAsyncOperation<BufferProtectUnprotectResult*> *pHandler, AsyncStatus status) -> HRESULT
            {
                SetEvent(operationCompleted.Get());
                return S_OK;
            }).Get());

            WaitForSingleObject(operationCompleted.Get(), INFINITE);

            IBufferProtectUnprotectResult * pIBProtectUnprotectResult;

            operation->GetResults(&amp;pIBProtectUnprotectResult);

            IDataProtectionInfo * protectionValue;

            pIBProtectUnprotectResult->get_ProtectionInfo(&amp;protectionValue);

            DataProtectionStatus  status;

            protectionValue->get_Status(&amp;status);

            if (status == DataProtectionStatus_Protected)
            {
                IBuffer * protectedBuffer;
                pIBProtectUnprotectResult->get_Buffer(&amp;protectedBuffer);
                protectedDocumentBuffer = protectedBuffer;
            }
       }
}


    // Close any open streams that you are actively working with
    // to make sure that we have no unprotected content in memory.

    // Optionally, code goes here to use e.Deadline to determine whether we have more
    // than 15 seconds left before the suspension deadline. If we do then process any
    // messages queued up for sending while we are still able to access them.

    deferral.Get()->Complete();

    return 0;
}

C++/ CX snippet

void OnProtectedAccessSuspending
    (Platform::Object ^sender, Windows::Security::EnterpriseData::ProtectedAccessSuspendingEventArgs ^args)
{
    Deferral ^deferral = args->GetDeferral();

     
    IBuffer ^documentBodyBuffer = 
         CryptographicBuffer::ConvertStringToBinary(string_in_UI, BinaryStringEncoding::Utf8);

     auto protectTask = 
         create_task(DataProtectionManager::ProtectAsync
              (documentBodyBuffer, "contoso.com"));

     protectTask.then([](BufferProtectUnprotectResult ^result) 
     {
         if (result->ProtectionInfo->Status == DataProtectionStatus::Protected)
         {
             protectedDocumentBuffer = result->Buffer;
             string_in_UI = nullptr;
         }
     });
 deferral->Complete();
}

APIs:

ProtectionPolicyManager.ProtectedAccessSuspending
ProtectionPolicyManager.Identity
DataProtectionManager.ProtectAsync
BufferProtectUnprotectResult.buffer
ProtectedAccessSuspendingEventArgs.GetDeferral
Deferral.Complete

Add back sensitive data when the device is unlocked

ProtectionPolicyManager.ProtectedAccessResumed is raised when the device is unlocked and the keys are available on the device again.

ProtectedAccessResumedEventArgs.Identities is an empty collection if the administrator hasn't configured a secure data protection under lock policy.

This example does the reverse of the previous example. It decrypts the buffer, adds information from that buffer back to the text box and then disposes of the buffer.

C++ snippet

int WIP::HandleProtectedAccessResumed(HWND hWnd, HSTRING * textBoxSting, IProtectedAccessSuspendingEventArgs * e)
{
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);

    ComPtr<IProtectionPolicyManagerStatics> ppmStatics;

    ABI::Windows::Foundation::GetActivationFactory
        (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmStatics);

    ComPtr<IProtectionPolicyManagerInterop> ppmInterop;

    ABI::Windows::Foundation::GetActivationFactory
        (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_ProtectionPolicyManager).Get(), &amp;ppmInterop);

    ComPtr<IProtectionPolicyManager> ppmInstance;

    HSTRING identity;

    if (SUCCEEDED(ppmInterop->GetForWindow(hWnd, IID_PPV_ARGS(&amp;ppmInstance))))
    {
        HRESULT hRet = ppmInstance->get_Identity(&amp;identity);

        if (identity != NULL)
        {
            ComPtr<IDataProtectionManagerStatics> pdpStatics;

            HRESULT hr = ABI::Windows::Foundation::GetActivationFactory
                (HStringReference(RuntimeClass_Windows_Security_EnterpriseData_DataProtectionManager).Get(), &amp;pdpStatics);

            __FIAsyncOperation_1_Windows__CSecurity__CEnterpriseData__CBufferProtectUnprotectResult_t *operation;

            pdpStatics->ProtectAsync(protectedDocumentBuffer.Get(), identity, &amp;operation);

            Event operationCompleted(CreateEvent(nullptr, true, false, nullptr));

            operation->put_Completed(Callback<IAsyncOperationCompletedHandler<BufferProtectUnprotectResult*>>
                ([&amp;](IAsyncOperation<BufferProtectUnprotectResult*> *pHandler, AsyncStatus status) -> HRESULT
            {
                SetEvent(operationCompleted.Get());
                return S_OK;

            }).Get());

            WaitForSingleObject(operationCompleted.Get(), INFINITE);

            IBufferProtectUnprotectResult * pIBProtectUnprotectResult;

            operation->GetResults(&amp;pIBProtectUnprotectResult);

            IDataProtectionInfo * protectionValue;

            pIBProtectUnprotectResult->get_ProtectionInfo(&amp;protectionValue);

            DataProtectionStatus  status;
            protectionValue->get_Status(&amp;status);

            if (status == DataProtectionStatus_Protected)
            {
                ComPtr<ICryptographicBufferStatics> cryptographicBuffer;

                ABI::Windows::Foundation::GetActivationFactory
                   (HStringReference(RuntimeClass_Windows_Security_Cryptography_CryptographicBuffer).Get(), &amp;cryptographicBuffer);

                // "protectedDocumentBuffer is a global IBuffer.
                cryptographicBuffer->ConvertBinaryToString(BinaryStringEncoding::BinaryStringEncoding_Utf8, protectedDocumentBuffer.Get(), textBoxSting);

                protectedDocumentBuffer = nullptr;
             }
    }

  }
return 0;
}

C++/ CX snippet

void OnProtectedAccessResumed(Platform::Object ^sender, Windows::Security::EnterpriseData::ProtectedAccessResumedEventArgs ^args)
{
    auto unProtectTask = create_task(DataProtectionManager::UnprotectAsync(protectedDocumentBuffer));

    unProtectTask.then([](BufferProtectUnprotectResult ^result)
    {
        if (result->ProtectionInfo->Status == DataProtectionStatus::Unprotected)
        {
            string_in_UI = CryptographicBuffer::ConvertBinaryToString(BinaryStringEncoding::Utf8, result->Buffer);
            protectedDocumentBuffer = nullptr;
        }
    });
}

APIs:

ProtectionPolicyManager.ProtectedAccessResumed
ProtectionPolicyManager.Identity
DataProtectionManager.UnprotectAsync
BufferProtectUnprotectResult.Status

Handle enterprise data when protected content is revoked

If you want your app to be notified when the device is un-enrolled from MDM or when the policy administrator explicitly revokes access to enterprise data, handle the ProtectionPolicyManager_ProtectedContentRevoked event.

Indicate that your app is enlightened

To indicate that your app is enlightened, open the resource file of your project, add the following flag, and then recompile your app.

MICROSOFTEDPENLIGHTENEDAPPINFO EDPENLIGHTENEDAPPINFOID
BEGIN
   0x0001
END