webring 1.1.2 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1029 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
2
- xmlns:content="http://purl.org/rss/1.0/modules/content/"
3
- xmlns:wfw="http://wellformedweb.org/CommentAPI/"
4
- xmlns:dc="http://purl.org/dc/elements/1.1/"
5
- xmlns:atom="http://www.w3.org/2005/Atom"
6
- xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
7
- xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
8
- >
9
-
10
- <channel>
11
- <title>The Old New Thing</title>
12
- <atom:link href="https://devblogs.microsoft.com/oldnewthing/feed" rel="self" type="application/rss+xml" />
13
- <link>https://devblogs.microsoft.com/oldnewthing</link>
14
- <description></description>
15
- <lastBuildDate>Mon, 24 Jun 2024 17:38:17 +0000</lastBuildDate>
16
- <language>en-US</language>
17
- <sy:updatePeriod>
18
- hourly </sy:updatePeriod>
19
- <sy:updateFrequency>
20
- 1 </sy:updateFrequency>
21
-
22
-
23
- <image>
24
- <url>https://devblogs.microsoft.com/oldnewthing/wp-content/uploads/sites/38/2021/03/Microsoft-Favicon.png</url>
25
- <title>The Old New Thing</title>
26
- <link>https://devblogs.microsoft.com/oldnewthing</link>
27
- <width>32</width>
28
- <height>32</height>
29
- </image>
30
- <item>
31
- <title>Creating an already-completed asynchronous activity in C++/WinRT, part 4</title>
32
- <link>https://devblogs.microsoft.com/oldnewthing/20240712-00/?p=109967</link>
33
- <comments>https://devblogs.microsoft.com/oldnewthing/20240712-00/?p=109967#comments</comments>
34
-
35
- <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
36
- <pubDate>Fri, 12 Jul 2024 14:00:00 +0000</pubDate>
37
- <category><![CDATA[Old New Thing]]></category>
38
- <category><![CDATA[Code]]></category>
39
- <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=109967</guid>
40
-
41
- <description><![CDATA[<p>Failing is easy. Failing correctly is hard.</p>
42
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240712-00/?p=109967">Creating an already-completed asynchronous activity in C++/WinRT, part 4</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
43
- ]]></description>
44
- <content:encoded><![CDATA[<p>Last time, we <a title="Creating an already-completed asynchronous activity in C++/WinRT, part 3" href="https://devblogs.microsoft.com/oldnewthing/20240711-00/?p=109965"> created a generalized <code>Make­Completed</code> for creating an already-completed asynchronous activity in C++/WinRT</a>. Today, we&#8217;ll try to do the same for <code>Make­Failed</code>.</p>
45
- <p>In one sense, <code>Make­Failed</code> is easier because the body is the same regardless of which of the four types of asynchronous activities you&#8217;re making.</p>
46
- <pre>winrt::Windows::Foundation::IAsyncAction
47
- MakeFailedAsyncAction(winrt::hresult_error error)
48
- {
49
- (void) co_await winrt::get_cancellation_token();
50
- throw error;
51
- }
52
-
53
- template&lt;typename Progress&gt;
54
- winrt::Windows::Foundation::IAsyncActionWithProgress&lt;Progress&gt;
55
- MakeFailedAsyncActionWithProgress(winrt::hresult_error error)
56
- {
57
- (void) co_await winrt::get_cancellation_token();
58
- throw error;
59
- }
60
-
61
- template&lt;typename Result, typename Progress&gt;
62
- winrt::Windows::Foundation::IAsyncOperation&lt;Result&gt;
63
- MakeFailedAsyncOperation(winrt::hresult_error error)
64
- {
65
- (void) co_await winrt::get_cancellation_token();
66
- throw error;
67
- }
68
-
69
- template&lt;typename Result, typename Progress&gt;
70
- winrt::Windows::Foundation::IAsyncOperationWithProgress&lt;Result, Progress&gt;
71
- MakeFailedAsyncOperationWithProgress(winrt::hresult_error error)
72
- {
73
- (void) co_await winrt::get_cancellation_token();
74
- throw error;
75
- }
76
-
77
- // Sample usage
78
- winrt::Windows::Foundation::IAsyncOperation&lt;int&gt;
79
- GetSizeAsync()
80
- {
81
- return MakeFailedAsyncOperation&lt;int&gt;(
82
- winrt::hresult_not_implemented());
83
- }
84
- </pre>
85
- <p>This easily generalizes:</p>
86
- <pre>template&lt;typename Async&gt;
87
- Async MakeFailed(winrt::hresult_error error)
88
- {
89
- (void) co_await winrt::get_cancellation_token();
90
- throw error;
91
- }
92
- </pre>
93
- <p>Unfortunately, it&#8217;s also wrong.</p>
94
- <p>Since we receive the exception in the form of a <code>hresult_<wbr />error</code> by value, anybody who passes a derived exception like <code>hresult_<wbr />access_<wbr />denied</code> will be subjected to <a href="https://en.wikipedia.org/wiki/Object_slicing"> slicing</a>. You might think to avoid slicing by taking the parameter by reference, but that runs into two problems. First, you are carrying a reference across a <code>co_await</code>, which may cause static analysis tools to get upset at you. Worse is that receiving the parameter as a reference doesn&#8217;t resolve the slicing because the <code>throw</code> throws only the <code>hresult_<wbr />error</code> portion of the exception. Fortunately, this second problem is a non-issue in this specific case because it is captured and reported at the ABI to the coroutine consumer as an <code>HRESULT</code> failure code from the <code>GetResults()</code> method, and the consumer will realize that the <code>HRESULT</code> is, say, <code>E_INVALIDARG</code> and reconstruct a <code>hresult_<wbr />invalid_<wbr />argument</code>.¹</p>
95
- <p>The real problem is that <!-- backref: C++/WinRT gotcha: Not all exceptions derive from hresult_error --> not all C++/WinRT exceptions derive from <code>hresult_error</code>. What if somebody wants to make a <code>IAsyncAction</code> that failed with <code>std::<wbr />bad_<wbr />alloc</code>?</p>
96
- <p>So we&#8217;ll accept anything that C++/WinRT supports, which is anything derived from <code>std::<wbr />exception</code> or <code>winrt::<wbr />hresult_<wbr />error</code>.</p>
97
- <pre>template&lt;typename Async, typename Error,
98
- typename = std::enable_if_t&lt;
99
- std::is_base_of_v&lt;std::exception, Error&gt; ||
100
- std::is_base_of_v&lt;winrt::hresult_error, Error&gt;&gt;&gt;
101
- Async MakeFailed(Error error)
102
- {
103
- (void) co_await winrt::get_cancellation_token();
104
- throw error;
105
- }
106
- </pre>
107
- <p>When dealing with coroutines or exceptions (and especially in our case here, which is coroutines <i>and</i> exceptions), you need to think about debuggability. Exceptions are nonlocal transfer, so it can be difficult to debug where an exception originated. And coroutines break up function execution into chunks, and most of the chunks run after the original call stack is lost, so that makes it even more frustrating. We&#8217;ll look into this next time.</p>
108
- <p>¹ Related reading: <a href="https://devblogs.microsoft.com/oldnewthing/20231116-00/?p=109023"> What happened to the custom exception description I threw from a C++/WinRT <code>IAsyncAction</code></a>? <a href="https://devblogs.microsoft.com/oldnewthing/20231102-00/?p=108956"> How come my custom exception message is lost when it is thrown from a <code>IAsyncAction</code>^</a>?</p>
109
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240712-00/?p=109967">Creating an already-completed asynchronous activity in C++/WinRT, part 4</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
110
- ]]></content:encoded>
111
-
112
- <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20240712-00/?p=109967/feed</wfw:commentRss>
113
- <slash:comments>1</slash:comments>
114
-
115
-
116
- </item>
117
- <item>
118
- <title>Creating an already-completed asynchronous activity in C++/WinRT, part 3</title>
119
- <link>https://devblogs.microsoft.com/oldnewthing/20240711-00/?p=109965</link>
120
- <comments>https://devblogs.microsoft.com/oldnewthing/20240711-00/?p=109965#respond</comments>
121
-
122
- <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
123
- <pubDate>Thu, 11 Jul 2024 14:00:00 +0000</pubDate>
124
- <category><![CDATA[Old New Thing]]></category>
125
- <category><![CDATA[Code]]></category>
126
- <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=109965</guid>
127
-
128
- <description><![CDATA[<p>Generalizing to the four kinds of Windows Runtime asynchronous activities.</p>
129
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240711-00/?p=109965">Creating an already-completed asynchronous activity in C++/WinRT, part 3</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
130
- ]]></description>
131
- <content:encoded><![CDATA[<p>Last time, we figured out how to <a title="Creating an already-completed asynchronous activity in C++/WinRT, part 2" href="https://devblogs.microsoft.com/oldnewthing/20240710-00/?p=109963"> create an already-completed asynchronous activity in C++/WinRT</a>. Today we&#8217;ll try to generalize it to cover the four kinds of Windows Runtime asynchronous activities.</p>
132
- <table class="cp3" style="border-collapse: collapse;" border="1" cellspacing="0" cellpadding="3">
133
- <tbody>
134
- <tr>
135
- <td>&nbsp;</td>
136
- <th>No progress</th>
137
- <th>Progres</th>
138
- </tr>
139
- <tr>
140
- <th>No result</th>
141
- <td><code>IAsyncAction</code></td>
142
- <td><code>IAsyncActionWithProgress&lt;P&gt;</code></td>
143
- </tr>
144
- <tr>
145
- <th>Result</th>
146
- <td><code>IAsyncOperation</code></td>
147
- <td><code>IAsyncOperationWithProgress&lt;T, P&gt;</code></td>
148
- </tr>
149
- </tbody>
150
- </table>
151
- <p>One way to do this is to write four different functions for each category, similar to how we dealt with <i>cv</i>-qualifiers before we had <a title="C++23's Deducing this: what it is, why it is, how to use it" href="https://devblogs.microsoft.com/cppblog/cpp23-deducing-this/"> deducing this</a>.</p>
152
- <pre>winrt::Windows::Foundation::IAsyncAction
153
- MakeCompletedAsyncAction()
154
- {
155
- co_return;
156
- }
157
-
158
- template&lt;typename Progress&gt;
159
- winrt::Windows::Foundation::IAsyncActionWithProgress&lt;Progress&gt;
160
- MakeCompletedAsyncActionWithProgress()
161
- {
162
- co_return;
163
- }
164
-
165
- template&lt;typename Result, typename Progress&gt;
166
- winrt::Windows::Foundation::IAsyncOperation&lt;Result&gt;
167
- MakeCompletedAsyncOperation(Result result)
168
- {
169
- co_return result;
170
- }
171
-
172
- template&lt;typename Result, typename Progress&gt;
173
- winrt::Windows::Foundation::IAsyncOperationWithProgress&lt;Result, Progress&gt;
174
- MakeCompletedAsyncOperationWithProgress(Result result)
175
- {
176
- co_return result;
177
- }
178
-
179
- // Sample usage:
180
-
181
- winrt::Windows::Foundation::IAsyncOperation&lt;int&gt;
182
- GetHeightAsync()
183
- {
184
- return MakeCompletedAsyncOperation(42);
185
- }
186
-
187
- winrt::Windows::Foundation::
188
- IAsyncOperationWithProgress&lt;int, HeightProgress&gt;
189
- GetHeightAsync()
190
- {
191
- return MakeCompletedAsyncOperationWithProgress&lt;
192
- int, HeightProgress&gt;(42);
193
- }
194
- </pre>
195
- <p>Explicit specialization is required for the <code>WithProgress</code> versions, since there is no opportunity to deduce the progress type.</p>
196
- <p>We could combine the four flavors into a single function, though this means that specialization is mandatory.</p>
197
- <pre>template&lt;typename Async, typename... Result&gt;
198
- Async MakeCompleted(Result... result)
199
- {
200
- if constexpr (sizeof...(Result) == 0) {
201
- co_return;
202
- } else {
203
- static_assert(sizeof...(Result) == 1);
204
- co_return std::get&lt;0&gt;(
205
- std::forward_as_tuple(result...));
206
- }
207
- }
208
- </pre>
209
- <p>We use a trick in <code>Make­Completed</code> by formally accepting any number of arguments, although we check inside the function body that it is zero or one. In the case where there is one parameter, we use the <code>forward_<wbr />as_<wbr />tuple</code> + <code>get</code> technique to <a title="Pulling a single item from a C++ parameter pack by its index" href="https://devblogs.microsoft.com/oldnewthing/20240516-00/?p=109771"> pull a single item from a parameter pack</a>.</p>
210
- <p>Next time, we&#8217;ll try to write <code>MakeFailed</code>.</p>
211
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240711-00/?p=109965">Creating an already-completed asynchronous activity in C++/WinRT, part 3</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
212
- ]]></content:encoded>
213
-
214
- <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20240711-00/?p=109965/feed</wfw:commentRss>
215
- <slash:comments>0</slash:comments>
216
-
217
-
218
- </item>
219
- <item>
220
- <title>Creating an already-completed asynchronous activity in C++/WinRT, part 2</title>
221
- <link>https://devblogs.microsoft.com/oldnewthing/20240710-00/?p=109963</link>
222
- <comments>https://devblogs.microsoft.com/oldnewthing/20240710-00/?p=109963#comments</comments>
223
-
224
- <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
225
- <pubDate>Wed, 10 Jul 2024 14:00:00 +0000</pubDate>
226
- <category><![CDATA[Old New Thing]]></category>
227
- <category><![CDATA[Code]]></category>
228
- <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=109963</guid>
229
-
230
- <description><![CDATA[<p>Making our function a coroutine.</p>
231
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240710-00/?p=109963">Creating an already-completed asynchronous activity in C++/WinRT, part 2</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
232
- ]]></description>
233
- <content:encoded><![CDATA[<p>Last time, we tried to <a title="Creating an already-completed asynchronous activity in C++/WinRT, part 1" href="https://devblogs.microsoft.com/oldnewthing/20240709-00/?p=109961"> create an already-completed asynchronous activity in C++/WinRT</a>. We were able to create a coroutine that represented a successful already-completed operation:</p>
234
- <pre>winrt::Windows::Foundation::IAsyncOperation&lt;int&gt;
235
- ComputeAsync()
236
- {
237
- co_return 42;
238
- }
239
- </pre>
240
- <p>But the analogous function for creating a failed already-completed operation didn&#8217;t work because its lack of any <code>co_await</code> or <code>co_return</code> statement means that it wasn&#8217;t a coroutine at all!</p>
241
- <pre>winrt::Windows::Foundation::IAsyncOperation&lt;int&gt;
242
- ComputeAsync()
243
- {
244
- throw winrt::hresult_access_denied();
245
- }
246
- </pre>
247
- <p>To make the function a coroutine, we need to put a <code>co_await</code> or <code>co_return</code> in the body somewhere. We have a few options.</p>
248
- <p>One is to put the <code>co_await</code> after the <code>throw</code>, so it is physically present in the function body (thereby making it a coroutine), but is unreachable. A safe thing to await is <code>std::suspend_never()</code>, which is a built-in awaitable that never awaits.</p>
249
- <pre>winrt::Windows::Foundation::IAsyncOperation&lt;int&gt;
250
- ComputeAsync()
251
- {
252
- throw winrt::hresult_access_denied();
253
- <span style="border: solid 1px currentcolor;">co_await std::suspend_never();</span>
254
- }
255
- </pre>
256
- <p>Perhaps a more reasonable thing is to actually try to <code>co_return</code> something.</p>
257
- <pre>winrt::Windows::Foundation::IAsyncOperation&lt;int&gt;
258
- ComputeAsync()
259
- {
260
- throw winrt::hresult_access_denied();
261
- <span style="border: solid 1px currentcolor;">co_return 0;</span>
262
- }
263
- </pre>
264
- <p>Both of these work, and it appears that the major compilers (gcc, clang, msvc) all optimize out the code that follows a <code>throw</code>. And as of this writing, they also do not raise a dead code diagnostic, though that&#8217;s the thing that worries me: It&#8217;s possible that a future version of the compiler will decide to produce dead code diagnostics, and then this code will cause problems when used in code bases that treat warnings as errors.</p>
265
- <p>We can put a <code>co_await</code> in front of the <code>throw</code>, but again, if we put it in a dead code block, we risk a diagnostic:</p>
266
- <pre>winrt::Windows::Foundation::IAsyncOperation&lt;int&gt;
267
- ComputeAsync()
268
- {
269
- <span style="border: solid 1px currentcolor;">if (false) co_return 0;</span>
270
- throw winrt::hresult_access_denied();
271
- }
272
- </pre>
273
- <p>So maybe the thing to do is actually <code>co_await</code> something, but await something that does nothing. That&#8217;s where we can use the built-in <code>suspend_never</code>.</p>
274
- <pre>winrt::Windows::Foundation::IAsyncOperation&lt;int&gt;
275
- ComputeAsync()
276
- {
277
- <span style="border: solid 1px currentcolor;">co_await std::suspend_never{};</span>
278
- throw winrt::hresult_access_denied();
279
- }
280
- </pre>
281
- <p>The major compilers recognize this pattern, and it&#8217;s not dead code, so we don&#8217;t risk an unreachable code diagnostic.</p>
282
- <p>But wait, it&#8217;s still a problem, thanks to our pal <code>await_<wbr />transform</code>. The C++/WinRT implementation of <code>await_<wbr />transform</code> for Windows Runtime <code>IAsyncXxx</code> interfaces wraps all awaitables inside an awaiter that check whether the <code>IAsyncXxx</code> has been cancelled and throws an <code>hresult_canceled</code> exception if so.</p>
283
- <p>Now, we know that the coroutine is never cancelled before it completes, but the compilers&#8217; escape analysis can&#8217;t see that, so in practice, they will include that extra check. The <code>co_await std::suspend_never{}</code> cannot be optimized out entirely.</p>
284
- <p>At this point, you have to go looking for a rabbit to pull out of your hat. And in this case, the rabbit is <code>winrt::<wbr />cancellation_<wbr />token</code>.</p>
285
- <p>The <code>winrt::<wbr />cancellation_<wbr />token</code> is a sentinel object that is not generally awaitable, but C++/WinRT&#8217;s implementation of <code>IAsyncXxx</code> recognizes it as as a special awaitable in its <code>await_<wbr />transform</code> and (here&#8217;s where the rabbit comes from) the custom awaiter returns an object (which is just a wrapper around a pointer to the promise) without any other fanfare.</p>
286
- <p>The trick, therefore, is to await the cancellation token and <a title="How can I tell C++ that I want to discard a nodiscard value?" href="https://devblogs.microsoft.com/oldnewthing/20240329-00/?p=109592"> discard the resulting object</a>.</p>
287
- <pre>winrt::Windows::Foundation::IAsyncOperation&lt;int&gt;
288
- ComputeAsync()
289
- {
290
- <span style="border: solid 1px currentcolor;">(void)co_await winrt::get_cancellation_token();</span>
291
-
292
- throw winrt::hresult_access_denied();
293
- }
294
- </pre>
295
- <p>We explicitly discard the result of the <code>co_await</code>, just in case some future version of C++/WinRT adds the <code>[[nodiscard]]</code> attribute.</p>
296
- <p>Now that we know how to code up this specific case, we&#8217;ll work on generalizing it next time.</p>
297
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240710-00/?p=109963">Creating an already-completed asynchronous activity in C++/WinRT, part 2</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
298
- ]]></content:encoded>
299
-
300
- <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20240710-00/?p=109963/feed</wfw:commentRss>
301
- <slash:comments>2</slash:comments>
302
-
303
-
304
- </item>
305
- <item>
306
- <title>Creating an already-completed asynchonous activity in C++/WinRT, part 1</title>
307
- <link>https://devblogs.microsoft.com/oldnewthing/20240709-00/?p=109961</link>
308
- <comments>https://devblogs.microsoft.com/oldnewthing/20240709-00/?p=109961#comments</comments>
309
-
310
- <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
311
- <pubDate>Tue, 09 Jul 2024 14:00:00 +0000</pubDate>
312
- <category><![CDATA[Old New Thing]]></category>
313
- <category><![CDATA[Code]]></category>
314
- <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=109961</guid>
315
-
316
- <description><![CDATA[<p>The simplest version.</p>
317
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240709-00/?p=109961">Creating an already-completed asynchonous activity in C++/WinRT, part 1</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
318
- ]]></description>
319
- <content:encoded><![CDATA[<p>When working with asynchronous code, you may need to create an asynchronous activity that has already completed, because you already know the answer. For example, you may be implementing a method whose signature is</p>
320
- <pre>IAsyncOperation&lt;int&gt; ComputeAsync();
321
- </pre>
322
- <p>but you already have the result and don&#8217;t need to compute it. How can you return an <code>IAsyncOperation&lt;int&gt;</code> that represents the already-computed result?</p>
323
- <p>C# has <code>Task.FromResult()</code> and <code>Task.CompletedTask</code>. JavaScript has <code>Promise.resolve()</code>. The Parallel Patterns Library (PPL) has <code>task_<wbr />from_<wbr />result()</code>. What about C++/WinRT?</p>
324
- <p>The simplest way is to just <code>co_return</code> the result into a coroutine.</p>
325
- <pre>winrt::Windows::Foundation::IAsyncOperation&lt;int&gt;
326
- ComputeAsync()
327
- {
328
- co_return 42;
329
- }
330
- </pre>
331
- <p>Similarly, C# has <code>Task.FromException()</code>, JavaScript has <code>Promise.reject()</code>, and PPL has <code>task_<wbr />from_<wbr />exception()</code>. The simple C++/WinRT version is to throw the exception from the coroutine.</p>
332
- <p>But wait, this doesn&#8217;t do what you think:</p>
333
- <pre>winrt::Windows::Foundation::IAsyncOperation&lt;int&gt;
334
- ComputeAsync()
335
- {
336
- throw winrt::hresult_access_denied();
337
- }
338
- </pre>
339
- <p>There is no <code>co_await</code> or <code>co_return</code> statement in the function body, so this is not a coroutine: Instead of returning a failed coroutine, this function fails to return a coroutine! When you call it, it throws an exception.</p>
340
- <p>We&#8217;ll look at ways of making this a coroutine next time.</p>
341
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240709-00/?p=109961">Creating an already-completed asynchonous activity in C++/WinRT, part 1</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
342
- ]]></content:encoded>
343
-
344
- <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20240709-00/?p=109961/feed</wfw:commentRss>
345
- <slash:comments>2</slash:comments>
346
-
347
-
348
- </item>
349
- <item>
350
- <title>What&#8217;s the point of std::monostate? You can&#8217;t do anything with it!</title>
351
- <link>https://devblogs.microsoft.com/oldnewthing/20240708-00/?p=109959</link>
352
- <comments>https://devblogs.microsoft.com/oldnewthing/20240708-00/?p=109959#comments</comments>
353
-
354
- <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
355
- <pubDate>Mon, 08 Jul 2024 14:00:00 +0000</pubDate>
356
- <category><![CDATA[Old New Thing]]></category>
357
- <category><![CDATA[Code]]></category>
358
- <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=109959</guid>
359
-
360
- <description><![CDATA[<p>Not doing anything with it is exactly the point.</p>
361
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240708-00/?p=109959">What&#8217;s the point of &lt;CODE&gt;std::&lt;WBR&gt;monostate&lt;/CODE&gt;? You can&#8217;t do anything with it!</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
362
- ]]></description>
363
- <content:encoded><![CDATA[<p>C++17 introduced <code>std::<wbr />monostate</code>, and I used it <a title="In C++/WinRT, how can I await multiple coroutines and capture the results?, part 3" href="https://devblogs.microsoft.com/oldnewthing/20240112-00/?p=109267"> as a placeholder to represent the results of a coroutine that produces nothing</a>. In the comments, Neil Rashbrook asked <a href="https://devblogs.microsoft.com/oldnewthing/20240112-00/?p=109267#comment-141049"> what you are expected to do with a <code>std::<wbr />monostate</code></a>, seeing as has no members and only trivial member functions.</p>
364
- <p>The answer is &#8220;nothing&#8221;.</p>
365
- <p>The purpose of <code>std::<wbr />monostate</code> is to be a dummy type that does nothing. All instances are considered equal to each other. It is basically this:</p>
366
- <pre>struct monostate {};
367
- // plus relational operators and a hash specialization
368
- </pre>
369
- <p>You can see it in <a href="https://github.com/llvm/llvm-project/blob/22f6e97d24f6e7190a447fd60e11e8ea03fd8356/libcxx/include/__variant/monostate.h#L26C42-L26C42"> libcxx (LLVM/clang)</a>, <a href="https://github.com/gcc-mirror/gcc/blob/5d2a360f0a541646abb11efdbabc33c6a04de7ee/libstdc%2B%2B-v3/include/std/variant#L1237"> libstdc++ (gcc)</a>, and <a href="https://github.com/microsoft/STL/blob/3eac329d1f614ecf138d96c22a3b02f87076bc4a/stl/inc/xutility#L7126"> stl (msvc)</a>.</p>
370
- <p>But what&#8217;s the point of a class that does nothing, and which you can do nothing with?</p>
371
- <p>You don&#8217;t use <code>monostate</code> because you want to do something. You use <code>monostate</code> when you <i>don&#8217;t want to do anything</i>.</p>
372
- <p>Its original purpose was to be used as the initial type in a <code>std::<wbr />variant</code> to allow it to be default-constructed in an empty state.</p>
373
- <pre>struct Widget
374
- {
375
- // no default constructor
376
- Widget(std::string const&amp; id);
377
-
378
- ⟦ other members ⟧
379
- };
380
-
381
- struct PortListener
382
- {
383
- // default constructor has unwanted side effects
384
- PortListener(int port = 80);
385
-
386
- ⟦ other members ⟧
387
- };
388
-
389
- std::variant&lt;Widget, PortListener&gt; thingie; // can't do this
390
- </pre>
391
- <p>The <code>std::variant</code>&#8216;s default constructor default-constructs its first alternative. Since <code>Widget</code> doesn&#8217;t have a default constructor, you can&#8217;t put it first. And <code>Port­Listener</code>&#8216;s default constructor has unwanted side effects, so we don&#8217;t want to put it first.</p>
392
- <p>Enter <code>std::<wbr />monostate</code>. You can put that guy first.</p>
393
- <pre>std::variant&lt;std::monostate, Widget, PortListener&gt; thingie;
394
- </pre>
395
- <p>The <code>thingie</code> default-constructs into a <code>monostate</code>. What can you do with a <code>monostate</code>? Nothing! Its job is just to be a dummy type that you can use when you are forced to provide a default-constructible type but don&#8217;t want to.</p>
396
- <p>In the case of a <code>std::<wbr />variant</code>, you can think of inserting <code>std::<wbr />monostate</code> as a way to add an &#8220;empty&#8221; state to a <code>variant</code>,¹ saving you the trouble of having to create a <code>std::<wbr />optional&lt;std::<wbr />variant&lt;...&gt;&gt;</code>. You can treat the <code>std::<wbr />monostate</code> as the &#8220;empty&#8221; state.</p>
397
- <p>In our usage of <code>std::<wbr />monostate</code>, we used it as just a dummy type that stands in for <code>void</code>.²</p>
398
- <p>¹ More precisely, a way to add <i>another</i> &#8220;empty&#8221; state to a <code>variant</code>. There is already an &#8220;empty&#8221; state for a <code>std::<wbr />variant</code>, known as <code>valueless_<wbr />by_<wbr />exception</code>. This state is wacky, though, so you want to avoid it as much as possible. Another topic for another day.</p>
399
- <p>² Bonus reading: <a href="https://wg21.link/p0146r1"> Regular Void</a>, which has stalled.</p>
400
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240708-00/?p=109959">What&#8217;s the point of &lt;CODE&gt;std::&lt;WBR&gt;monostate&lt;/CODE&gt;? You can&#8217;t do anything with it!</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
401
- ]]></content:encoded>
402
-
403
- <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20240708-00/?p=109959/feed</wfw:commentRss>
404
- <slash:comments>5</slash:comments>
405
-
406
-
407
- </item>
408
- <item>
409
- <title>How do I produce a Windows Runtime asynchronous activity from C++/WinRT?</title>
410
- <link>https://devblogs.microsoft.com/oldnewthing/20240705-00/?p=109957</link>
411
- <comments>https://devblogs.microsoft.com/oldnewthing/20240705-00/?p=109957#respond</comments>
412
-
413
- <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
414
- <pubDate>Fri, 05 Jul 2024 14:00:00 +0000</pubDate>
415
- <category><![CDATA[Old New Thing]]></category>
416
- <category><![CDATA[Code]]></category>
417
- <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=109957</guid>
418
-
419
- <description><![CDATA[<p>Somebody that deals with them natively.</p>
420
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240705-00/?p=109957">How do I produce a Windows Runtime asynchronous activity from C++/WinRT?</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
421
- ]]></description>
422
- <content:encoded><![CDATA[<p>We&#8217;ve looked at how to produce a Windows Runtime asynchronous activity <a title="How do I produce a Windows Runtime asynchronous activity from C++/CX?" href="https://devblogs.microsoft.com/oldnewthing/?p=109953"> in C++/CX</a> and <a title="How" href="https://devblogs.microsoft.com/oldnewthing/?p=109955"> in C#</a>, and they both involved passing a lambda to a helper function, where the lambda received special parameters for detecting cancellation and report progress. Fortunately, C++/WinRT integrates Windows Runtime asynchrony natively. You just write a function or method that returns an <code>IAsyncSomething</code>, and inside the body, you can <code>co_await</code> and <code>co_return</code>. If you want to check for cancellation, you can request a cancellation token, and if you want to report progress, you can request a progress token.</p>
423
- <pre>winrt::IAsyncOperation&lt;winrt::Widget&gt; GetWidgetAsync(winrt::hstring);
424
- winrt::IAsyncAction EnableWidgetAsync(winrt::Widget, bool);
425
-
426
- winrt::IAsyncActionWithProgress&lt;int&gt;
427
- EnableWidgetByIdAsync(winrt::hstring id, bool enable)
428
- {
429
- // If this is an instance member function
430
- auto lifetime = get_strong();
431
- // If this is a global function or static member function
432
- auto lifetime = wil::winrt_module_reference();
433
-
434
- <span style="border: solid 1px currentcolor; border-bottom: none;">auto cancel = co_await winrt::get_cancellation_token();</span>
435
- <span style="border: solid 1px currentcolor; border-top: none;">auto progress = co_await winrt::get_progress_token(); </span>
436
-
437
- <span style="border: solid 1px currentcolor;">progress(0);</span>
438
- auto widget = co_await GetWidgetAsync(id);
439
- <span style="border: solid 1px currentcolor; border-bottom: none;">progress(1); </span>
440
- <span style="border: 1px currentcolor; border-style: none solid;">if (cancel()) throw winrt::hresult_canceled();</span>
441
- <span style="border: solid 1px currentcolor; border-top: none;">if (!widget) co_return false; </span>
442
- co_await EnableWidgetAsync(widget, enable);
443
- co_return true;
444
- }
445
- </pre>
446
- <p>C++/WinRT automatically checks for cancellation after every <code>co_await</code>,¹ so we didn&#8217;t really need a cancellation token in this example, but I showed it for completeness.</p>
447
- <p>¹ Except the special awaitables <code>co_await winrt::<wbr />get_<wbr />cancellation_<wbr />token()</code> and <code>co_await winrt::<wbr />get_<wbr />progress_<wbr />token()</code>.</p>
448
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240705-00/?p=109957">How do I produce a Windows Runtime asynchronous activity from C++/WinRT?</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
449
- ]]></content:encoded>
450
-
451
- <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20240705-00/?p=109957/feed</wfw:commentRss>
452
- <slash:comments>0</slash:comments>
453
-
454
-
455
- </item>
456
- <item>
457
- <title>How do I produce a Windows Runtime asynchronous activity from C#?</title>
458
- <link>https://devblogs.microsoft.com/oldnewthing/20240704-00/?p=109955</link>
459
- <comments>https://devblogs.microsoft.com/oldnewthing/20240704-00/?p=109955#comments</comments>
460
-
461
- <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
462
- <pubDate>Thu, 04 Jul 2024 14:00:00 +0000</pubDate>
463
- <category><![CDATA[Old New Thing]]></category>
464
- <category><![CDATA[Code]]></category>
465
- <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=109955</guid>
466
-
467
- <description><![CDATA[<p>The AsyncInfo helper class converts Tasks to Windows Runtime asynchronous activities.</p>
468
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240704-00/?p=109955">How do I produce a Windows Runtime asynchronous activity from C#?</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
469
- ]]></description>
470
- <content:encoded><![CDATA[<p>Last time, we looked at <a title="How do I produce a Windows Runtime asynchronous activity from C++/CX?" href="https://devblogs.microsoft.com/oldnewthing/?p=109953"> how to produce a Windows Runtime asynchronous activity in C++/CX</a>. Doing it in C# is similar: The method that converts a C# <code>Task</code> to a Windows Runtime asynchronous activity is <code>AsyncInfo.<wbr />Run</code>, and just like PPL&#8217;s <code>create_<wbr />async</code>, it infers the resulting asynchronous activity from the signature of the object you pass to it.</p>
471
- <p>Given a lambda that returns a type <code>R</code> and takes the parameters <code>Params...</code>, the <code>AsyncInfo.<wbr />Run</code> method returns the following Windows Runtime interface:</p>
472
- <table class="cp3" style="border-collapse: collapse;" border="1" cellspacing="0" cellpadding="3">
473
- <tbody>
474
- <tr>
475
- <th rowspan="2"> </th>
476
- <th colspan="2">Params&#8230;</th>
477
- </tr>
478
- <tr>
479
- <td><code>(Cancellation­Token)</code></td>
480
- <td><code>(Cancellation­Token, IProgress&lt;P&gt;)</code></td>
481
- </tr>
482
- <tr>
483
- <td><code>R</code> = <code>Task</code></td>
484
- <td><code>IAsyncAction</code></td>
485
- <td><code>IAsyncActionWithProgress&lt;P&gt;</code></td>
486
- </tr>
487
- <tr>
488
- <td><code>R</code> = <code>Task&lt;T&gt;</code></td>
489
- <td><code>IAsyncOperation&lt;T&gt;</code></td>
490
- <td><code>IAsyncOperationWithProgress&lt;T, P&gt;</code></td>
491
- </tr>
492
- </tbody>
493
- </table>
494
- <p>This is basically the same table that we had for <code>create_<wbr />async</code>, but with three significant changes:</p>
495
- <ol>
496
- <li>The lambda must accept at least a <code>Cancellation­Token</code>. (It was optional for <code>create_<wbr />async</code>.)</li>
497
- <li>The lambda must return a <code>Task</code> or <code>Task&lt;T&gt;</code>. (The <code>create_<wbr />async</code> allowed you to return <code>void</code> or <code>T</code>.)</li>
498
- <li>The lambda&#8217;s cancellation token and progress reporter parameters are in opposite order!</li>
499
- </ol>
500
- <p>As with <code>create_<wbr />async</code>, the lambda can use the <code>IProgress&lt;P&amp;gt</code> <code>progress_<wbr />reporter&lt;P&gt;</code> to produce progress reports, and the <code>Cancellation­Token</code> to detect whether the asynchronous activity has been canceled.</p>
501
- <p>Here&#8217;s the simplest case: An <code>IAsyncAction</code>.</p>
502
- <pre>Task&lt;Widget&gt; GetWidgetAsync(string id);
503
- Task EnableWidgetAsync(Widget widget, bool enable);
504
-
505
- IAsyncAction EnableWidgetByIdAsync(string id, bool enable)
506
- {
507
- return AsyncInfo.Run(async (cancel) =&gt; {
508
- var widget = await GetWidgetAsync(id);
509
- cancel.ThrowIfCancellationRequested();
510
- await EnableWidgetAsync(widget, enable);
511
- });
512
- }
513
- </pre>
514
- <p>And with progress:</p>
515
- <pre>IAsyncActionWithProgress&lt;int&gt; EnableWidgetByIdAsync(string id, bool enable)
516
- {
517
- return AsyncInfo.Run(async (CancellationToken cancel,
518
- IProgress&lt;int&gt; progress) =&gt; {
519
- progress.Report(0);
520
- var widget = await GetWidgetAsync(id);
521
- cancel.ThrowIfCancellationRequested();
522
- progress.Report(1);
523
- await EnableWidgetAsync(widget, enable);
524
- });
525
- }
526
- </pre>
527
- <p>The compiler can&#8217;t infer what the <code>P</code> is for the <code>IProgress&lt;P&gt;</code> parameter, so you have to specify it explicitly. And then you run into another rule that says that if you provide an explicit type for one lambda parameter, you must do so for all of them, so we&#8217;re stuck typing <code>Cancellation­Token</code> again.</p>
528
- <p>But wait, there&#8217;s an easier way: Instead of helping the compiler infer <code>IProgress&lt;P&gt;</code>, we explicitly specialize the <code>Run</code> method.</p>
529
- <pre>IAsyncActionWithProgress&lt;int&gt; EnableWidgetByIdAsync(string id, bool enable)
530
- {
531
- return AsyncInfo.Run<span style="border: solid 1px currentcolor;">&lt;int&gt;</span>(async (cancel, progress) =&gt; {
532
- progress.Report(0);
533
- var widget = await GetWidgetAsync(id);
534
- cancel.ThrowIfCancellationRequested();
535
- progress.Report(1);
536
- await EnableWidgetAsync(widget, enable);
537
- });
538
- }
539
- </pre>
540
- <p>May as well do the async operations, too.</p>
541
- <pre>IAsyncOperation&lt;bool&gt; EnableWidgetByIdAsync(string id, bool enable)
542
- {
543
- return AsyncInfo.Run(async (cancel) =&gt; {
544
- var widget = await GetWidgetAsync(id);
545
- cancel.ThrowIfCancellationRequested();
546
- <span style="border: solid 1px currentcolor; border-bottom: none;">if (widget == null) return false; </span>
547
- <span style="border: 1px currentcolor; border-style: none solid;">await EnableWidgetAsync(widget, enable);</span>
548
- <span style="border: solid 1px currentcolor; border-top: none;">return true; </span>
549
- });
550
- }
551
-
552
- IAsyncOperationWithProgress&lt;bool, int&gt; EnableWidgetByIdAsync(string id, bool enable)
553
- {
554
- return AsyncInfo.Run&lt;bool, int&gt;(async (cancel, progress) =&gt; {
555
- progress.Report(0);
556
- var widget = await GetWidgetAsync(id);
557
- cancel.ThrowIfCancellationRequested();
558
- progress.Report(1);
559
- <span style="border: solid 1px currentcolor; border-bottom: none;">if (widget == null) return false; </span>
560
- <span style="border: 1px currentcolor; border-style: none solid;">await EnableWidgetAsync(widget, enable);</span>
561
- <span style="border: solid 1px currentcolor; border-top: none;">return true; </span>
562
- });
563
- }
564
- </pre>
565
- <p>Now, in the case where you don&#8217;t support cancellation or progress, you have an alternative: For the case of <code>IAsyncAction</code>, you can create a <code>Task</code> and then call its <code>AsAsyncAction</code> method, and in the case of <code>IAsyncOperation&lt;T&gt;</code>, you call its its <code>AsAsyncOperation</code> method. These aren&#8217;t true methods on <code>Task</code> but rather extension methods provided by the <code>System.<wbr />Windows­Runtime­System­Extensions</code> namespace, so you may need to add a <code>using System.<wbr />Windows­Runtime­System­Extensions;</code> to your file.</p>
566
- <pre>using System.WindowsRuntimeSystemExtensions;
567
-
568
- IAsyncAction EnableWidgetByIdAsync(string id, bool enable)
569
- {
570
- Func&lt;Task&gt; taskMaker = async () =&gt; {
571
- var widget = await GetWidgetAsync(id);
572
- await EnableWidgetAsync(widget, enable);
573
- };
574
- return taskMaker().AsAsyncAction();
575
- }
576
-
577
- IAsyncOperation&lt;int&gt; EnableWidgetByIdAsync(string id, bool enable)
578
- {
579
- Func&lt;Task&lt;int&gt;&gt; taskMaker = async () =&gt; {
580
- var widget = await GetWidgetAsync(id);
581
- if (widget == null) return false;
582
- await EnableWidgetAsync(widget, enable);
583
- return true;
584
- };
585
- return taskMaker().AsAsyncOperation();
586
- }
587
- </pre>
588
- <p>These conversions are more convenient to use if you just turn the lambda into its own named function:</p>
589
- <pre>// IAsyncAction version
590
- async Task EnableWidgetByIdTaskAsync(string id, bool enable)
591
- {
592
- var widget = await GetWidgetAsync(id);
593
- await EnableWidgetAsync(widget, enable);
594
- }
595
-
596
- IAsyncAction EnableWidgetByIdAsync(string id, bool enable)
597
- {
598
- return EnableWidgetByIdTaskAsync(id, enable).AsAsyncAction();
599
- }
600
-
601
- // IAsyncOperation version
602
- async Task&lt;bool&gt; EnableWidgetByIdTaskAsync(string id, bool enable)
603
- {
604
- var widget = await GetWidgetAsync(id);
605
- if (widget == null) return false;
606
- await EnableWidgetAsync(widget, enable);
607
- return true;
608
- }
609
-
610
- IAsyncOperation&lt;int&gt; EnableWidgetByIdAsync(string id, bool enable)
611
- {
612
- return EnableWidgetByIdTaskAsync(id, enable).AsAsyncOperation();
613
- }
614
- </pre>
615
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240704-00/?p=109955">How do I produce a Windows Runtime asynchronous activity from C#?</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
616
- ]]></content:encoded>
617
-
618
- <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20240704-00/?p=109955/feed</wfw:commentRss>
619
- <slash:comments>2</slash:comments>
620
-
621
-
622
- </item>
623
- <item>
624
- <title>How do I produce a Windows Runtime asynchronous activity from C++/CX?</title>
625
- <link>https://devblogs.microsoft.com/oldnewthing/20240703-00/?p=109953</link>
626
- <comments>https://devblogs.microsoft.com/oldnewthing/20240703-00/?p=109953#respond</comments>
627
-
628
- <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
629
- <pubDate>Wed, 03 Jul 2024 14:00:00 +0000</pubDate>
630
- <category><![CDATA[Old New Thing]]></category>
631
- <category><![CDATA[Code]]></category>
632
- <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=109953</guid>
633
-
634
- <description><![CDATA[<p>The Parallel Patterns Library has special support for C++/CX.</p>
635
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240703-00/?p=109953">How do I produce a Windows Runtime asynchronous activity from C++/CX?</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
636
- ]]></description>
637
- <content:encoded><![CDATA[<p>You might be working in a code base written in C++/CX.</p>
638
- <p>First, I&#8217;m sorry.</p>
639
- <p>Second, maybe you need to produce an <code>IAsyncAction^</code> or one of its relatives. How do you do that?</p>
640
- <p>You <a href="https://learn.microsoft.com/archive/msdn-magazine/2012/february/asynchronous-programming-asynchronous-programming-in-c-using-ppl"> use the <code>Concurrency::<wbr />create_<wbr />async</code> method</a>.</p>
641
- <p>The <code>Concurrency::<wbr />create_<wbr />async</code> method studies its parameter and infers what kind of Windows Runtime asynchronous activity to produce based on the signature of the lambda.</p>
642
- <p>Given a lambda whose function call operator has the signature <code>R(Params...)</code>, the <code>create_<wbr />async</code> function returns the following Windows Runtime interface:</p>
643
- <table class="cp3" style="border-collapse: collapse;" border="1" cellspacing="0" cellpadding="3">
644
- <tbody>
645
- <tr>
646
- <th rowspan="2"> </th>
647
- <th colspan="2">Params&#8230;</th>
648
- </tr>
649
- <tr>
650
- <td><code>()</code><br />
651
- <code>(cancellation_token)</code></td>
652
- <td><code>(progress_reporter&lt;P&gt;)</code><br />
653
- <code>(progress_reporter&lt;P&gt;, cancellation_token)</code></td>
654
- </tr>
655
- <tr>
656
- <td><code>R</code> = <code>void</code><br />
657
- <code>R</code> = <code>task&lt;void&gt;</code></td>
658
- <td><code>IAsyncAction^</code></td>
659
- <td><code>IAsyncActionWithProgress&lt;P&gt;^</code></td>
660
- </tr>
661
- <tr>
662
- <td><code>R</code> = <code>T</code><br />
663
- <code>R</code> = <code>task&lt;T&gt;</code></td>
664
- <td><code>IAsyncOperation&lt;T&gt;^</code></td>
665
- <td><code>IAsyncOperationWithProgress&lt;T, P&gt;^</code></td>
666
- </tr>
667
- </tbody>
668
- </table>
669
- <p>Inside the lambda, you can use the <code>progress_<wbr />reporter&lt;P&gt;</code> to produce progress reports, and you can use the optional <code>cancellation_<wbr />token</code> to detect whether the asynchronous activity has been canceled.</p>
670
- <p>Here&#8217;s the simplest case: An <code>IAsyncAction^</code> with no cancellation.</p>
671
- <pre>task&lt;Widget^&gt; GetWidgetAsync(String^);
672
- task&lt;void&gt; EnableWidgetAsync(Widget^, bool);
673
-
674
- // Old school: Task chain
675
- IAsyncAction^ EnableWidgetByIdAsync(String^ id, bool enable)
676
- {
677
- return create_async([=]()
678
- -&gt; task&lt;void&gt; {
679
- return GetWidgetAsync(id).then(
680
- [=](Widget^ widget) {
681
- return EnableWidgetAsync(widget, enable);
682
- });
683
- });
684
- }
685
-
686
- // New hotness: co_await
687
- IAsyncAction^ EnableWidgetByIdAsync(String^ id, bool enable)
688
- {
689
- return create_async([=]()
690
- -&gt; task&lt;void&gt; {
691
- Widget^ widget = co_await GetWidgetAsync(id);
692
- co_await EnableWidgetAsync(widget, enable);
693
- });
694
- }
695
- </pre>
696
- <p>With cancellation but no progress:</p>
697
- <pre>void ThrowIfCanceled(cancellation_token const&amp; cancel)
698
- {
699
- if (cancel.is_canceled()) cancel_current_task();
700
- }
701
-
702
- // Old school: Task chain
703
- IAsyncAction^ EnableWidgetByIdAsync(String^ id, bool enable)
704
- {
705
- return create_async([=](<span style="border: solid 1px currentcolor;">cancellation_token cancel</span>)
706
- -&gt; task&lt;void&gt; {
707
- return GetWidgetAsync(id).then(
708
- [=](Widget^ widget) { // explicitly: [enable, <span style="border: solid 1px currentcolor;">cancel</span>]
709
- <span style="border: solid 1px currentcolor;">ThrowIfCanceled(cancel);</span>
710
- return EnableWidgetAsync(widget, enable);
711
- });
712
- });
713
- }
714
-
715
- // New hotness: co_await
716
- IAsyncAction^ EnableWidgetByIdAsync(String^ id, bool enable)
717
- {
718
- return create_async([=](<span style="border: solid 1px currentcolor;">cancellation_token cancel</span>)
719
- -&gt; task&lt;void&gt; {
720
- Widget^ widget = co_await GetWidgetAsync(id);
721
- <span style="border: solid 1px currentcolor;">ThrowIfCanceled(cancel);</span>
722
- co_await EnableWidgetAsync(widget, enable);
723
- });
724
- }
725
- </pre>
726
- <p>With progress but no cancellation:</p>
727
- <pre>// Old school: Task chain
728
- IAsyncActionWithProgress&lt;int&gt;^
729
- EnableWidgetByIdAsync(String^ id, bool enable)
730
- {
731
- return create_async([=](<span style="border: solid 1px currentcolor;">progress_reporter&lt;int&gt; progress</span>)
732
- -&gt; task&lt;void&gt; {
733
- <span style="border: solid 1px currentcolor;">progress.report(0);</span>
734
- return GetWidgetAsync(id).then(
735
- [=](Widget^ widget) { // explicitly: [enable, <span style="border: solid 1px currentcolor;">progress</span>]
736
- <span style="border: solid 1px currentcolor;">progress.report(1);</span>
737
- return EnableWidgetAsync(widget, enable);
738
- });
739
- });
740
- }
741
-
742
- // New hotness: co_await
743
- IAsyncAction^ EnableWidgetByIdAsync(String^ id, bool enable)
744
- {
745
- return create_async([=](<span style="border: solid 1px currentcolor;">progress_reporter&lt;int&gt; progress</span>))
746
- -&gt; task&lt;void&gt; {
747
- <span style="border: solid 1px currentcolor;">progress.report(0);</span>
748
- Widget^ widget = co_await GetWidgetAsync(id);
749
- <span style="border: solid 1px currentcolor;">progress.report(1);</span>
750
- co_await EnableWidgetAsync(widget, enable);
751
- });
752
- }
753
- </pre>
754
- <p>And with both progress and cancellation:</p>
755
- <pre>// Old school: Task chain
756
- IAsyncActionWithProgress&lt;int&gt;^
757
- EnableWidgetByIdAsync(String^ id, bool enable)
758
- {
759
- return create_async([=](<span style="border: 1px currentcolor; border-style: solid none none solid;">progress_reporter&lt;int&gt; pr</span><span style="border: 1px currentcolor; border-style: solid solid solid none;">ogress,</span>
760
- <span style="border: solid 1px currentcolor; border-top: none;">cancellation_token cancel</span>)
761
- -&gt; task&lt;void&gt; {
762
- <span style="border: solid 1px currentcolor;">progress.report(0);</span>
763
- return GetWidgetAsync(id).then(
764
- [=](Widget^ widget) { // explicitly: [enable, <span style="border: solid 1px currentcolor;">progress, cancel</span>]
765
- <span style="border: solid 1px currentcolor; border-bottom: none;">ThrowIfCanceled(cancel);</span>
766
- <span style="border: solid 1px currentcolor; border-top: none;">progress.report(1); </span>
767
- return EnableWidgetAsync(widget, enable);
768
- });
769
- });
770
- }
771
-
772
- // New hotness: co_await
773
- IAsyncAction^ EnableWidgetByIdAsync(String^ id, bool enable)
774
- {
775
- return create_async([=](<span style="border: 1px currentcolor; border-style: solid none none solid;">progress_reporter&lt;int&gt; pr</span><span style="border: 1px currentcolor; border-style: solid solid solid none;">ogress,</span>
776
- <span style="border: solid 1px currentcolor; border-top: none;">cancellation_token cancel</span>)
777
- -&gt; task&lt;void&gt; {
778
- <span style="border: solid 1px currentcolor;">progress.report(0);</span>
779
- Widget^ widget = co_await GetWidgetAsync(id);
780
- <span style="border: solid 1px currentcolor; border-bottom: none;">ThrowIfCanceled(cancel);</span>
781
- <span style="border: solid 1px currentcolor; border-top: none;">progress.report(1); </span>
782
- co_await EnableWidgetAsync(widget, enable);
783
- });
784
- }
785
- </pre>
786
- <p>We can generalize into a single pattern:</p>
787
- <pre>IAsyncSomething^
788
- DoSomethingAsync(Arg1 arg1, Arg2, arg2, ...)
789
- {
790
- return create_async([=](
791
- progress_reporter&lt;P&gt; progress<sub>[optional]</sub>,
792
- cancellation_token cancel<sub>[optional]</sub>)
793
- -&gt; task&lt;P&gt; {
794
- ⟦ async stuff which may include...
795
- progress.report(value);<sub>[optional]</sub>
796
- ThrowIfCanceled(cancel);<sub>[optional]</sub>
797
-
798
- });
799
- }
800
- </pre>
801
- <p>You can also register a callback function on the <code>cancellation_<wbr />token</code> that will be invoked when the activity is canceled. I leave using the cancellation callback as an exercise.</p>
802
- <p>There are also variants for <code>IAsync­Operation</code>. I&#8217;ll show just one of them and let you figure out the others:</p>
803
- <pre>// Old school: Task chain
804
- IAsyncOperationWithProgress&lt;bool, int&gt;^
805
- EnableWidgetByIdAsync(String^ id, bool enable)
806
- {
807
- return create_async([=](progress_reporter&lt;int&gt; progress,
808
- cancellation_token cancel)
809
- -&gt; task&lt;<span style="border: solid 1px currentcolor;">bool</span>&gt; {
810
- progress.report(0);
811
- return GetWidgetAsync(id).then(
812
- [=](Widget^ widget) { // explicitly: [enable, progress, cancel]
813
- ThrowIfCanceled(cancel);
814
- progress.report(1);
815
- <span style="border: solid 1px currentcolor; border-bottom: none;">if (!widget) { </span>
816
- <span style="border: 1px currentcolor; border-style: none solid;"> return task_from_result(false); // widget not found</span>
817
- <span style="border: 1px currentcolor; border-style: none solid;">} </span>
818
- <span style="border: 1px currentcolor; border-style: none solid;">return EnableWidgetAsync(widget, enable).then( </span>
819
- <span style="border: solid 1px currentcolor; border-top: none;"> []() { return true; }); </span>
820
- });
821
- });
822
- }
823
-
824
- // New hotness: co_await
825
- IAsyncAction^ EnableWidgetByIdAsync(String^ id, bool enable)
826
- {
827
- return create_async([=](progress_reporter&lt;int&gt; progress,
828
- cancellation_token cancel)
829
- -&gt; task&lt;<span style="border: solid 1px currentcolor;">bool</span>&gt; {
830
- progress.report(0);
831
- Widget^ widget = co_await GetWidgetAsync(id);
832
- ThrowIfCanceled(cancel);
833
- progress.report(1);
834
- <span style="border: solid 1px currentcolor; border-bottom: none;">if (!widget) { </span>
835
- <span style="border: 1px currentcolor; border-style: none solid;"> co_return false; </span>
836
- <span style="border: 1px currentcolor; border-style: none solid;">} </span>
837
- <span style="border: 1px currentcolor; border-style: none solid;">co_await EnableWidgetAsync(widget, enable);</span>
838
- <span style="border: solid 1px currentcolor; border-top: none;">co_return true; </span>
839
- });
840
- }
841
- </pre>
842
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240703-00/?p=109953">How do I produce a Windows Runtime asynchronous activity from C++/CX?</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
843
- ]]></content:encoded>
844
-
845
- <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20240703-00/?p=109953/feed</wfw:commentRss>
846
- <slash:comments>0</slash:comments>
847
-
848
-
849
- </item>
850
- <item>
851
- <title>The history of Alt+number sequences, and why Alt+9731 sometimes gives you a heart and sometimes a snowman</title>
852
- <link>https://devblogs.microsoft.com/oldnewthing/20240702-00/?p=109951</link>
853
- <comments>https://devblogs.microsoft.com/oldnewthing/20240702-00/?p=109951#comments</comments>
854
-
855
- <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
856
- <pubDate>Tue, 02 Jul 2024 14:00:00 +0000</pubDate>
857
- <category><![CDATA[Old New Thing]]></category>
858
- <category><![CDATA[Tips/Support]]></category>
859
- <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=109951</guid>
860
-
861
- <description><![CDATA[<p>Code pages and custom keyboard handling.</p>
862
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240702-00/?p=109951">The history of &lt;KBD&gt;Alt&lt;/KBD&gt;+number sequences, and why &lt;KBD&gt;Alt&lt;/KBD&gt;+&lt;KBD&gt;9731&lt;/KBD&gt; sometimes gives you a heart and sometimes a snowman</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
863
- ]]></description>
864
- <content:encoded><![CDATA[<p>Once upon a time, the IBM PC was released.</p>
865
- <p>In the IBM PC BIOS, you could enter characters that weren&#8217;t present on the keyboard by holding the <kbd>Alt</kbd> key and typing the decimal value on the numeric keypad. For example, you could enter ñ by holding <kbd>Alt</kbd> and typing <kbd>Numpad1</kbd> <kbd>Numpad6</kbd> <kbd>Numpad4</kbd>, then releasing the <kbd>Alt</kbd> key.</p>
866
- <p>For expository simplicity, I will henceforth use the notation <kbd>Alt</kbd>+<kbd>164</kbd> to indicate that you press the <kbd>Alt</kbd> key, then type the specified digits in sequence on the numeric keypad, then release the <kbd>Alt</kbd> key.</p>
867
- <p>Okay, so in the IBM PC BIOS, when you typed <kbd>Alt</kbd>+<kbd>…</kbd>, the code numbers were treated as decimal byte values, and the result on the screen came from your video card&#8217;s character generator. In the United States, the character generator&#8217;s ROM showed what we today call <a href="https://en.wikipedia.org/wiki/Code_page_437"> Code Page 437</a>.</p>
868
- <p>When it was introduced, Windows in the United States used <a href="https://en.wikipedia.org/wiki/Windows-1252"> Code Page 1252</a> as its 8-bit character set, which it called the &#8220;ANSI character set&#8221;; the old BIOS character set was retroactively named the OEM character set. To preserve compatibility with MS-DOS, if you used the <kbd>Alt</kbd> key in conjunction with the numeric keypad, the number you typed was still looked up in OEM character set, so that your muscle-memory code numbers still worked. You could still type <kbd>Alt</kbd>+<kbd>164</kbd> to get your ñ, even though the code number for ñ in Code Page 1252 is 241, not 164.</p>
869
- <p>If you wanted to type a character that had no OEM equivalent, you could prefix a numeric keypad <kbd>0</kbd> to indicate that you wanted the value looked up in the ANSI code page. Therefore, you could type <kbd>Alt</kbd>+<kbd>0169</kbd> to get a ©, which did not exist in the OEM code page. You could also type <kbd>Alt</kbd>+<kbd>0241</kbd> to get your precious ñ, using the ANSI code point number rather than the OEM code point number.</p>
870
- <p>If you entered a number larger than 255, both Windows and the IBM PC BIOS took your value mod 256, so typing <kbd>Alt</kbd>+<kbd>259</kbd> was the same as typing <kbd>Alt</kbd>+<kbd>3</kbd>. Both gave you OEM code point 3, which for Code Page 437 is a heart <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/2665.png" alt="♥" class="wp-smiley" style="height: 1em; max-height: 1em;" />.</p>
871
- <p>If you ask the Internet how to type some of these non-ASCII characters on Windows, you may see people (and large language models) that tell you to type, say, <kbd>Alt</kbd>+<kbd>9731</kbd> to get a Unicode snowman <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/2603.png" alt="☃" class="wp-smiley" style="height: 1em; max-height: 1em;" />. Unfortunately, from what we&#8217;ve learned above, this doesn&#8217;t work. You instead get the OEM character whose value is 9731 mod 256 = 3, or the aforementioned heart <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/2665.png" alt="♥" class="wp-smiley" style="height: 1em; max-height: 1em;" />.</p>
872
- <p>A customer reported that a recent Windows update broke their ability to type a snowman by using <kbd>Alt</kbd>+<kbd>9731</kbd>. We explained that the update was not at fault; rather, <kbd>Alt</kbd>+<kbd>9731</kbd> was never supposed to produce a snowman at all! But the customer insisted that it used to work.</p>
873
- <p>A closer investigation of the issue revealed the reason.</p>
874
- <p>You see, while it&#8217;s true that the <kbd>Alt</kbd>+<kbd>…</kbd> decimal value is taken mod 256, that is just the default behavior of the Windows input system. But some controls (most notably the RichEdit control) override the default handling of the <kbd>Alt</kbd>+<kbd>…</kbd> sequence and parse out the decimal value <i>mod 65536</i> rather than <i>mod 256</i>.</p>
875
- <p>This means that whether the <kbd>Alt</kbd>+<kbd>…</kbd> value is taken mod 256 depends on what kind of control you are typing into.</p>
876
- <p>By default, the value is taken mod 256, and <kbd>Alt</kbd>+<kbd>9731</kbd> gives you a heart.</p>
877
- <p>But if you happen to be using a RichEdit control, then the <kbd>Alt</kbd>+<kbd>…</kbd> value is taken mod 65536, and <kbd>Alt</kbd>+<kbd>9731</kbd> gives you a snowman.</p>
878
- <p>(I don&#8217;t know of anybody who takes the value mod 2097151, to support direct entry of code points outside the Basic Multilingual Plane.)</p>
879
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240702-00/?p=109951">The history of &lt;KBD&gt;Alt&lt;/KBD&gt;+number sequences, and why &lt;KBD&gt;Alt&lt;/KBD&gt;+&lt;KBD&gt;9731&lt;/KBD&gt; sometimes gives you a heart and sometimes a snowman</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
880
- ]]></content:encoded>
881
-
882
- <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20240702-00/?p=109951/feed</wfw:commentRss>
883
- <slash:comments>22</slash:comments>
884
-
885
-
886
- </item>
887
- <item>
888
- <title>If I register the same shell extension as both a context menu extension and a drag/drop extension, how do I know which one the system is using?</title>
889
- <link>https://devblogs.microsoft.com/oldnewthing/20240701-00/?p=109947</link>
890
- <comments>https://devblogs.microsoft.com/oldnewthing/20240701-00/?p=109947#comments</comments>
891
-
892
- <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
893
- <pubDate>Mon, 01 Jul 2024 14:00:00 +0000</pubDate>
894
- <category><![CDATA[Old New Thing]]></category>
895
- <category><![CDATA[Code]]></category>
896
- <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=109947</guid>
897
-
898
- <description><![CDATA[<p>Who forced you to register the same shell extension for both?</p>
899
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240701-00/?p=109947">If I register the same shell extension as both a context menu extension and a drag/drop extension, how do I know which one the system is using?</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
900
- ]]></description>
901
- <content:encoded><![CDATA[<p>A customer was developing a shell extension that implemented <code>IContextMenu</code>. This extension interface is used for both context menu extensions and drag/drop extensions, and they registered their extension&#8217;s CLSID in both places. When the user right-clicked on a file, their extension was called to add menu items to the file&#8217;s context menu. And when the user did a right-mouse drag/drop, their extension was called to add menu items to the drag/drop context menu.</p>
902
- <p>But they wanted their shell extension to know whether it is being used as a context menu extension or a drag/drop extension. How can their extension detect which scenario is active? Other combination shell extensions can detect the scenario by seeing which interface&#8217;s methods are called. For example, if <code>IShellPropSheetExt::<wbr />AddPages</code> is called, then it knows that it&#8217;s being used as a property sheet extension. But both context menu extensions and drag/drop extensions use the same interface <code>IContextMenu</code>, so they can&#8217;t use that to detect the scenario.</p>
903
- <p>My kids have a pretend store called &#8220;Fred Tire&#8221;, a pun on <a title="Fred Meyer" href="https://en.wikipedia.org/wiki/Fred_Meyer"> Fred Meyer</a>, a local chain of grocery/department stores. When you call Fred Tire, you can order automobile tires, or you can order a pizza.¹</p>
904
- <p>This customer basically wrote their own Fred Tire.</p>
905
- <p>When a customer calls the store, you can answer the phone &#8220;Hello, this is Fred Tire. How can I help you?&#8221; If the customer says, &#8220;I&#8217;d like to buy some tires,&#8221; then you take down their tire order. If they say, &#8220;I&#8217;d like to order a pizza,&#8221; then you take down their pizza order. This is the Fred Tire version of using the interface to detect which scenario is being used. Furthermore, after the customer places their tire order, they might say, &#8220;And I&#8217;d also like to order a pizza,&#8221; and you can take their pizza order too. The same order-taker can handle both tires and pizzas. They just follow the customer&#8217;s lead as to which order form to fill out.</p>
906
- <p>This customer, however, wanted to answer the phone in a different way depending on what the customer wants. They want to know whether to say &#8220;Hello, this is Fred Tire, what kind of tire do you need?&#8221; Or whether they should say, &#8220;Hello, this is Fred Tire, what kind of pizza would you like?&#8221; How can they answer the phone correctly?</p>
907
- <p>If you want to answer the phone differently, what you can do is get two telephone numbers. Put one phone number on your tire flyers and another number on your pizza flyers. Both numbers ring the same phone, but you can see which line is ringing. That way, when somebody calls the tire number, you say, &#8220;Hello, this is Fred Tire, what kind of tire do you need?&#8221; And if somebody calls the pizzeria number, you say, &#8220;Hello, this is Fred Tire, what kind of pizza would you like?&#8221;</p>
908
- <p>For shell extensions, this means that you register two different CLSIDs, one for the context menu extension and another for the drag/drop extension. Creating either of the CLSIDs produces the same object, but also passes the CLSID to the constructor so that the object knows which scenario is active.</p>
909
- <pre>// sketch
910
- class MyShellExtension : IContextMenu, ⟦ other interfaces ⟧
911
- {
912
- MyShellExtension(<span style="border: solid 1px currentcolor;">REFCLSID clsid</span>) :
913
- <span style="border: solid 1px currentcolor;">m_clsid(clsid)</span> {}
914
-
915
- CLSID const m_clsid;
916
-
917
- bool IsCreatedForContextMenu()
918
- { return m_clsid == CLSID_MyContextMenu; }
919
- bool IsCreatedForDragDrop()
920
- { return m_clsid == CLSID_MyDragDrop; }
921
-
922
- ⟦ ... other methods ... ⟧
923
- };
924
-
925
- class MyShellExtensionFactory : IClassFactory
926
- {
927
- MyShellExtensionFactory(<span style="border: solid 1px currentcolor;">REFCLSID clsid</span>) :
928
- <span style="border: solid 1px currentcolor;">m_clsid(clsid)</span> {}
929
-
930
- <span style="border: solid 1px currentcolor;">CLSID const m_clsid;</span>
931
-
932
- STDMETHODIMP CreateInstance(IUnknown* outer, REFIID iid, void** ppv)
933
- {
934
- *ppv = nullptr;
935
- if (outer) return CLASS_E_NOAGGREGATION;
936
- auto instance = new (std::nothrow) MyShellExtension(<span style="border: solid 1px currentcolor;">clsid</span>);
937
- if (!instance) return E_OUTOFMEMORY;
938
- auto hr = instance-&gt;QueryInterface(iid, ppv);
939
- factory-&gt;Release();
940
- return hr;
941
- }
942
-
943
- ⟦ ... other methods ... ⟧
944
- };
945
-
946
- STDAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void** ppv)
947
- {
948
- *ppv = nullptr;
949
- if (clsid == CLSID_MyContextMenu || clsid == CLSID_MyDragDrop)
950
- {
951
- auto factory = new(std::nothrow) MyShellExtensionFactory(<span style="border: solid 1px currentcolor;">clsid</span>);
952
- if (!factory) return E_OUTOFMEMORY;
953
- auto hr = factory-&gt;QueryInterface(iid, ppv);
954
- factory-&gt;Release();
955
- return hr;
956
- }
957
- return REGDB_E_CLASSNOTREG;
958
- }
959
- </pre>
960
- <p>You can pass the <code>clsid</code> to the factory, who in turn passes it to the <code>MyShellExtension</code>, who can then use it to figure out which kind of shell extension it was created for.</p>
961
- <p>If your framework doesn&#8217;t let you pass parameters to factories, you can just create separate factories.</p>
962
- <pre><span style="border: solid 1px currentcolor; border-bottom: none;">enum class ExtensionKind</span>
963
- <span style="border: 1px currentcolor; border-style: none solid;">{ </span>
964
- <span style="border: 1px currentcolor; border-style: none solid;"> ContextMenu, </span>
965
- <span style="border: 1px currentcolor; border-style: none solid;"> DragDrop, </span>
966
- <span style="border: solid 1px currentcolor; border-top: none;">}; </span>
967
-
968
- class MyShellExtension : IContextMenu, ⟦ other interfaces ⟧
969
- {
970
- MyShellExtension(<span style="border: solid 1px currentcolor;">ExtensionKind kind</span>) : <span style="border: solid 1px currentcolor;">m_kind(kind)</span> {}
971
-
972
- <span style="border: solid 1px currentcolor; border-bottom: none;">ExtensionKind const m_kind = kind; </span>
973
-
974
- <span style="border: 1px currentcolor; border-style: none solid;">bool IsCreatedForContextMenu() </span>
975
- <span style="border: 1px currentcolor; border-style: none solid;"> { return m_kind == ExtensionKind::ContextMenu; }</span>
976
- <span style="border: 1px currentcolor; border-style: none solid;">bool IsCreatedForDragDrop() </span>
977
- <span style="border: solid 1px currentcolor; border-top: none;"> { return m_clsid == ExtensionKind::DragDrop; } </span>
978
-
979
- ⟦ ... other methods ... ⟧
980
- };
981
-
982
- class MyContextMenuShellExtension : MyShellExtension
983
- {
984
- MyContextMenuShellExtension() :
985
- <span style="border: solid 1px currentcolor;">MyShellExtension(ExtensionKind::ContextMenu)</span> {}
986
- };
987
-
988
- class MyDragDropShellExtension : MyShellExtension
989
- {
990
- MyDragDropShellExtension() :
991
- <span style="border: solid 1px currentcolor;">MyShellExtension(ExtensionKind::DragDrop)</span> {}
992
- };
993
-
994
- CoCreatableClass(MyContextMenuShellExtension)
995
- CoCreatableClass(MyDragDropShellExtension)
996
- </pre>
997
- <p>If your framework doesn&#8217;t even allow that, then you could templatize the class.</p>
998
- <pre>template&lt;ExtensionKind kind&gt;
999
- class MyShellExtension : IContextMenu, ⟦ other interfaces ⟧
1000
- {
1001
- MyShellExtension() = default;
1002
-
1003
- <span style="border: solid 1px currentcolor; border-bottom: none;">ExtensionKind const m_kind = kind; </span>
1004
- <span style="border: 1px currentcolor; border-style: none solid;">  </span>
1005
- <span style="border: 1px currentcolor; border-style: none solid;">bool IsCreatedForContextMenu() </span>
1006
- <span style="border: 1px currentcolor; border-style: none solid;"> { return m_kind == ExtensionKind::ContextMenu; }</span>
1007
- <span style="border: 1px currentcolor; border-style: none solid;">bool IsCreatedForDragDrop() </span>
1008
- <span style="border: solid 1px currentcolor; border-top: none;"> { return m_clsid == ExtensionKind::DragDrop; } </span>
1009
-
1010
- ⟦ ... other methods ... ⟧
1011
- };
1012
-
1013
-
1014
- <span style="border: solid 1px currentcolor; border-bottom: none;">using MyContextMenuShellExtension = </span>
1015
- <span style="border: 1px currentcolor; border-style: none solid;"> MyShellExtension&lt;ExtensionKind::ContextMenu&gt;</span>
1016
- <span style="border: 1px currentcolor; border-style: none solid;">using MyDragDropShellExtension = </span>
1017
- <span style="border: solid 1px currentcolor; border-top: none;"> MyShellExtension&lt;ExtensionKind::DragDrop&gt; </span>
1018
- </pre>
1019
- <p>¹Or (and this is where things get fun) you can order a &#8220;tire pizza&#8221;. I always order the pineapple tire pizza.</p>
1020
- <p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20240701-00/?p=109947">If I register the same shell extension as both a context menu extension and a drag/drop extension, how do I know which one the system is using?</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
1021
- ]]></content:encoded>
1022
-
1023
- <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20240701-00/?p=109947/feed</wfw:commentRss>
1024
- <slash:comments>5</slash:comments>
1025
-
1026
-
1027
- </item>
1028
- </channel>
1029
- </rss>