Skip to content

Commit 0cad9c8

Browse files
Merge pull request #6056 from MicrosoftDocs/jken_move_from_winai
Move content from WinAI
2 parents edb6e88 + 9adf6e5 commit 0cad9c8

10 files changed

Lines changed: 1156 additions & 0 deletions

File tree

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
title: Click to Do overview
3+
description: Learn how to use the AI-assisted Click to Do feature in Windows.
4+
ms.author: mattwoj
5+
author: mattwojo
6+
ms.date: 12/01/2025
7+
ms.topic: overview
8+
no-loc: [Click to Do, Windows Copilot Runtime, Phi Silica]
9+
---
10+
11+
# Click to Do overview
12+
13+
**Click to Do** is an AI-supported feature that utilizes the local Phi Silica model in Copilot+ PCs or [eligible Cloud PCs](https://learn.microsoft.com/windows-365/enterprise/ai-enabled-cloud-pcs) to connect actions to the content (text or images) on the screen.
14+
15+
Click to Do analyzes what's on screen and then you can choose the text or image you want to take action on. Once selected, Click to Do will suggest actions that you can take based on the content. For example, if you select a piece of text, it might suggest summarizing or rewriting it. If you select an image, it might suggest blurring the background, erasing objects in the image, or searching the web for related information.
16+
17+
Developers can launch Click to Do from their app using the URI scheme `ms-clicktodo://`. This allows the app users to interact with the Click to Do feature directly from their application, enhancing the user experience by providing quick access to AI-assisted actions.
18+
19+
Learn more about [Click to Do](https://support.microsoft.com/windows/click-to-do-in-recall-do-more-with-what-s-on-your-screen-967304a8-32d1-4812-a904-fad59b5e6abf).
20+
21+
## Launch Click to Do
22+
23+
To launch the Click to Do feature on a Copilot+ PC from your app, you use the following URI scheme: `ms-clicktodo://`
24+
25+
The `ms-clicktodo://` URI enables your app to programmatically launch Click to Do, placing an interactive overlay on top of the PC screen. This overlay suggests quick actions to appear for images or text. The analysis of the screen is always performed locally on the device. Content is only shared if the user chooses to complete an action. Content is not saved, nor is it automatically passed back to the app used to open the overlay. This URI does not accept any additional parameters.
26+
27+
The following code samples open Click to Do from the user's app:
28+
29+
### [C#](#tab/csharp)
30+
31+
```csharp
32+
var clickToDoUri = new Windows.Foundation.Uri(L"ms-clicktodo://");
33+
34+
Windows.System.Launcher.LaunchUriAsync(clickToDoUri)
35+
```
36+
37+
### [C++/WinRT](#tab/cpp)
38+
39+
```cppwinrt
40+
winrt::Windows::Foundation::Uri clickToDoUri(L"ms-clicktodo://");
41+
42+
winrt::Windows::System::Launcher::LaunchUriAsync(clickToDoUri);
43+
```
44+
45+
---
46+
47+
## Related content
48+
49+
- [Recall](./recall/index.md)
89.6 KB
Loading

hub/apps/develop/windows-integration/index.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ The following table lists the Windows system components that support integration
2222
| [Search providers](../search/search-providers.md) | Learn how to integrate into the Windows Search experience. |
2323
| [Widget providers](../widgets/widget-providers.md) | Learn how to implement a Windows widget service provider to support your app. |
2424

25+
## Windows features using AI
26+
27+
| Feature | Description |
28+
|--|--|
29+
| [Recall](./recall/index.md) | Learn how to use the AI-assisted Recall feature with the User Activity API in Windows. |
30+
| [Click to Do](./click-to-do.md) | Learn how to use the AI-assisted Click to Do feature in Windows. |
31+
2532
## Other Windows integration features
2633

2734
The following table lists other Windows integration features that support 3rd party developers.
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
---
2+
title: Decrypt exported snapshots from Recall
3+
description: Learn how to decrypt exported snapshot data from Windows Recall. This feature is only available to users located in the European Economic Area (EEA).
4+
ms.author: mattwoj
5+
author: mattwojo
6+
ms.date: 12/01/2025
7+
ms.topic: article
8+
no-loc: [Recall]
9+
---
10+
11+
# Decrypt exported snapshots from Recall
12+
13+
This guide shows developers how to decrypt exported Recall snapshots for use in applications. You'll learn the complete decryption process with working code samples that you can implement immediately.
14+
15+
**Exporting Recall snapshots is only supported on devices in the European Economic Area (EEA).** Export of Recall snapshots is a user-initiated process and is per user. Exported snapshots are encrypted.
16+
17+
Learn more about how to [Export Recall snapshots](https://support.microsoft.com/windows/export-recall-snapshots-680bd134-4aaa-4bf5-8548-a8e2911c8069) or see the [Recall overview](index.md) for more about how this AI-backed feature works.
18+
19+
## Prerequisites
20+
21+
The option to export Recall snapshots is only available on [Copilot+ PC devices](https://www.microsoft.com/windows/copilot-plus-pcs) in the European Economic Area (EEA) that are running the latest [Windows Insider Program preview build](https://www.microsoft.com/windowsinsider).
22+
23+
Before you begin, you'll need:
24+
25+
- **Exported snapshots**: The user must first [export Recall snapshots](https://support.microsoft.com/windows/export-recall-snapshots-680bd134-4aaa-4bf5-8548-a8e2911c8069) and provide the folder path where they're saved.
26+
- **Export code**: The 32-character Recall export code provided during snapshot export.
27+
- **Output folder**: A destination folder path where the decrypted .jpg and .json files associated with the exported snapshots will be saved.
28+
29+
## How to decrypt exported Recall snapshots
30+
31+
Get started with sample code for decrypting exported Recall snapshots in the [RecallSnapshotsExport GitHub repository](https://github.com/microsoft/RecallSnapshotsExport). Follow the step-by-step process below to understand how the decryption works.
32+
33+
### Compute Export Key
34+
35+
The user will need to provide the location (folder path) where their exported Recall snapshots have been saved, in addition to the Recall export code that they were asked to save during the initial Recall setup. The Recall export code looks something like: `0a0a-0a0a-1111-bbbb-2222-3c3c-3c3c-3c3c`
36+
37+
First, remove the dash – to result in a 32-character string: `0a0a0a0a1111bbbb22223c3c3c3c3c3c`
38+
39+
```cpp
40+
std::wstring UnexpandExportCode(std::wstring code)
41+
{
42+
if (code.size() > 32)
43+
{
44+
code.erase(std::remove(code.begin(), code.end(), ' '), code.end()); // Remove spaces
45+
code.erase(std::remove(code.begin(), code.end(), '-'), code.end()); // Remove hyphens
46+
}
47+
48+
49+
if (code.size() != 32)
50+
{
51+
std::wcout << L"The export code has incorrect number of characters."<< std::endl;
52+
}
53+
54+
55+
return code;
56+
}
57+
```
58+
59+
[See sample code](https://github.com/microsoft/RecallSnapshotsExport/blob/5442b3a90aed91888a67c283c3132290ecddb044/RecallSnapshotsExport.cpp#L307-L321)
60+
61+
Next, build an array containing the byte value for each pair of hex digits in turn.
62+
63+
```cpp
64+
std::vector<uint8_t> HexStringToBytes(const std::wstring& hexString)
65+
{
66+
std::vector<uint8_t> bytes;
67+
if (hexString.length() % 2 != 0)
68+
{
69+
throw std::invalid_argument("Hex string must have an even length");
70+
}
71+
72+
73+
for (size_t i = 0; i < hexString.length(); i += 2)
74+
{
75+
std::wstring byteString = hexString.substr(i, 2);
76+
uint8_t byte = static_cast<uint8_t>(std::stoi(byteString, nullptr, 16));
77+
bytes.push_back(byte);
78+
}
79+
80+
81+
return bytes;
82+
}
83+
```
84+
85+
[See sample code](https://github.com/microsoft/RecallSnapshotsExport/blob/5442b3a90aed91888a67c283c3132290ecddb044/RecallSnapshotsExport.cpp#L171-L187)
86+
87+
Then, take that array and compute the SHA256 hash, which results in a 32-byte value, which is the export key. Now any number of snapshots can be decrypted using the resulting export key.
88+
89+
```cpp
90+
std::vector<uint8_t> exportKeyBytes(c_keySizeInBytes);
91+
THROW_IF_NTSTATUS_FAILED(BCryptHash(
92+
BCRYPT_SHA256_ALG_HANDLE,
93+
nullptr,
94+
0,
95+
exportCodeBytes.data(),
96+
static_cast<ULONG>(exportCodeBytes.size()),
97+
exportKeyBytes.data(),
98+
c_keySizeInBytes));
99+
```
100+
101+
[See sample code.](https://github.com/microsoft/RecallSnapshotsExport/blob/5442b3a90aed91888a67c283c3132290ecddb044/RecallSnapshotsExport.cpp#L200-L208)
102+
103+
### Decrypt the encrypted snapshots
104+
105+
The layout of a snapshot (in little-endian format): `| uint32_t version | uint32_t encryptedKeySize | uint32_t encryptedContentSize | uint32_t contentType | uint8_t[KeySIze] encryptedContentKey | uint8_t[ContentSize] encryptedContent |`
106+
107+
First, read the four [uint32_t values](/cpp/c-runtime-library/standard-types#fixed-width-integral-types-stdinth).
108+
109+
```cpp
110+
EncryptedSnapshotHeader header{};
111+
reader.ByteOrder(winrt::ByteOrder::LittleEndian);
112+
113+
114+
header.Version = reader.ReadUInt32();
115+
header.KeySize = reader.ReadUInt32();
116+
header.ContentSize = reader.ReadUInt32();
117+
header.ContentType = reader.ReadUInt32();
118+
```
119+
120+
[See sample code.](https://github.com/microsoft/RecallSnapshotsExport/blob/5442b3a90aed91888a67c283c3132290ecddb044/RecallSnapshotsExport.cpp#L222-L228)
121+
122+
Next, verify that version has the value, 2.
123+
124+
```cpp
125+
if (header.Version != 2)
126+
{
127+
throw std::runtime_error("Insufficient data header version.");
128+
}
129+
```
130+
131+
[See sample code.](https://github.com/microsoft/RecallSnapshotsExport/blob/5442b3a90aed91888a67c283c3132290ecddb044/RecallSnapshotsExport.cpp#L230-L233)
132+
133+
Then, read the encryptedKeyContent.
134+
135+
```cpp
136+
std::vector<uint8_t> keybytes(header.KeySize);
137+
reader.ReadBytes(keybytes);
138+
```
139+
140+
[See sample code.](https://github.com/microsoft/RecallSnapshotsExport/blob/5442b3a90aed91888a67c283c3132290ecddb044/RecallSnapshotsExport.cpp#L235-L236)
141+
142+
Decrypt the encryptedKeyContent
143+
144+
```cpp
145+
wil::unique_bcrypt_key DecryptExportKey(BCRYPT_KEY_HANDLE key, std::span<uint8_t const> encryptedKey)
146+
{
147+
THROW_HR_IF(E_INVALIDARG, encryptedKey.size() != c_totalSizeInBytes);
148+
149+
150+
BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO AuthInfo{};
151+
BCRYPT_INIT_AUTH_MODE_INFO(AuthInfo);
152+
AuthInfo.pbNonce = const_cast<uint8_t*>(encryptedKey.data());
153+
AuthInfo.cbNonce = c_nonceSizeInBytes;
154+
AuthInfo.pbTag = const_cast<uint8_t*>(encryptedKey.data() + c_nonceSizeInBytes + c_childKeySizeInBytes);
155+
AuthInfo.cbTag = c_tagSizeInBytes;
156+
157+
158+
uint8_t decryptedKey[c_childKeySizeInBytes] = { 0 };
159+
160+
161+
ULONG decryptedByteCount{};
162+
THROW_IF_FAILED(HResultFromBCryptStatus(BCryptDecrypt(
163+
key,
164+
const_cast<uint8_t*>(encryptedKey.data() + c_nonceSizeInBytes),
165+
c_childKeySizeInBytes,
166+
&AuthInfo,
167+
nullptr,
168+
0,
169+
decryptedKey,
170+
sizeof(decryptedKey),
171+
&decryptedByteCount,
172+
0)));
173+
174+
175+
wil::unique_bcrypt_key childKey;
176+
THROW_IF_NTSTATUS_FAILED(
177+
BCryptGenerateSymmetricKey(BCRYPT_AES_GCM_ALG_HANDLE, &childKey, nullptr, 0, decryptedKey, c_childKeySizeInBytes, 0));
178+
179+
180+
return childKey;
181+
}
182+
```
183+
184+
[See sample code.](https://github.com/microsoft/RecallSnapshotsExport/blob/5442b3a90aed91888a67c283c3132290ecddb044/RecallSnapshotsExport.cpp#L138-L169)
185+
186+
using the exportKey
187+
188+
```cpp
189+
wil::unique_bcrypt_key exportKey;
190+
THROW_IF_NTSTATUS_FAILED(BCryptGenerateSymmetricKey(
191+
BCRYPT_AES_GCM_ALG_HANDLE, &exportKey, nullptr, 0, exportKeyBytes.data(), static_cast<ULONG>(exportKeyBytes.size()), 0));
192+
```
193+
194+
[See sample code](https://github.com/microsoft/RecallSnapshotsExport/blob/5442b3a90aed91888a67c283c3132290ecddb044/RecallSnapshotsExport.cpp#L210-L212)
195+
196+
To get the contentKey (crypto algorithm is AES_GCM)
197+
198+
```cpp
199+
wil::unique_bcrypt_key contentKey = DecryptExportKey(exportKey.get(), keybytes);
200+
```
201+
202+
[See sample code.](https://github.com/microsoft/RecallSnapshotsExport/blob/5442b3a90aed91888a67c283c3132290ecddb044/RecallSnapshotsExport.cpp#L237)
203+
204+
Read the encryptedContent
205+
206+
```cpp
207+
std::vector<uint8_t> contentbytes(header.ContentSize);
208+
reader.ReadBytes(contentbytes);
209+
```
210+
211+
[See sample code.](https://github.com/microsoft/RecallSnapshotsExport/blob/5442b3a90aed91888a67c283c3132290ecddb044/RecallSnapshotsExport.cpp#L239-L240)
212+
213+
Decrypt the encryptedContent
214+
215+
```cpp
216+
std::vector<uint8_t> DecryptPackedData(BCRYPT_KEY_HANDLE key, std::span<uint8_t const> payload)
217+
{
218+
THROW_HR_IF(E_INVALIDARG, payload.size() < c_tagSizeInBytes);
219+
const auto dataSize = payload.size() - c_tagSizeInBytes;
220+
const auto data = payload.data();
221+
222+
223+
uint8_t zeroNonce[c_nonceSizeInBytes] = { 0 };
224+
BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo{};
225+
BCRYPT_INIT_AUTH_MODE_INFO(authInfo);
226+
authInfo.pbNonce = zeroNonce;
227+
authInfo.cbNonce = c_nonceSizeInBytes;
228+
authInfo.pbTag = const_cast<uint8_t*>(payload.data() + dataSize);
229+
authInfo.cbTag = c_tagSizeInBytes;
230+
231+
232+
std::vector<uint8_t> decryptedContent(dataSize);
233+
ULONG decryptedSize = 0;
234+
const auto result = BCryptDecrypt(
235+
key, const_cast<uint8_t*>(data), static_cast<ULONG>(dataSize), &authInfo, nullptr, 0, decryptedContent.data(), static_cast<ULONG>(dataSize), &decryptedSize, 0);
236+
decryptedContent.resize(decryptedSize);
237+
238+
239+
THROW_IF_FAILED(HResultFromBCryptStatus(result));
240+
241+
242+
return decryptedContent;
243+
}
244+
```
245+
246+
[See sample code.](https://github.com/microsoft/RecallSnapshotsExport/blob/5442b3a90aed91888a67c283c3132290ecddb044/RecallSnapshotsExport.cpp#L113-L136)
247+
248+
with the contentKey (crypto algorithm is AES_GCM)
249+
250+
```cpp
251+
std::vector<uint8_t> decryptedContent = DecryptPackedData(contentKey.get(), contentbytes);
252+
```
253+
254+
[See sample code.](https://github.com/microsoft/RecallSnapshotsExport/blob/5442b3a90aed91888a67c283c3132290ecddb044/RecallSnapshotsExport.cpp#L241)
255+
256+
Output decrypted Recall snapshot content in the form of a .jpg image with corresponding .json metadata into the designated folder path
257+
258+
```cpp
259+
void WriteSnapshotToOutputFolder(winrt::StorageFolder const& outputFolder, winrt::hstring const& fileName, winrt::IRandomAccessStream const& decryptedStream)
260+
```
261+
262+
[See sample code.](https://github.com/microsoft/RecallSnapshotsExport/blob/5442b3a90aed91888a67c283c3132290ecddb044/RecallSnapshotsExport.cpp#L251)
263+
264+
The expected output will include:
265+
266+
- Decrypted snapshots saved as .jpg files.
267+
- Corresponding metadata saved as .json files.
268+
269+
Both file types will share the same filename and be found in the specified output folder.
270+
271+
## Learn more about Recall
272+
273+
- [Learn more about Windows Recall](index.md).
274+
- [Export Recall snapshots with an export code](https://support.microsoft.com/topic/680bd134-4aaa-4bf5-8548-a8e2911c8069)
275+
- [Manage Recall: Allow export of Recall and snapshot information](/windows/client-management/manage-recall#allow-export-of-recall-and-snapshot-information): IT Administrator guidance on how to manage Recall settings for users within your company, including the ability to export Recall snapshot data.
276+
- [Configuration Service Provider (CSP) Policy for Windows AI: Allow Recall Export](/windows/client-management/mdm/policy-csp-windowsai#allowrecallexport): Guidance for IT administrators to establish the policy settings that determine whether the optional Recall feature is available for end users to enable on their device, including the policy for enabling the export of snapshot data.

0 commit comments

Comments
 (0)