Jekyll2019-06-15T18:10:59-04:00https://blog.neteril.org/feed.xmlYet Another [à compléter]Random thoughts of Jérémie LavalJérémie LavalEditing advancements for Xamarin in Visual Studio for Mac2019-06-15T14:12:00-04:002019-06-15T14:12:00-04:00https://blog.neteril.org/blog/2019/06/15/vsmac-android-editor-extensions<p>We released this week <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-for-mac-version-8-1-is-now-available-and-a-preview-for-8-2/">the first 8.2 preview</a> of Visual Studio for Mac. This release is important for us as it’s the first one to contain our improved editor experience for Android XML resources and Xamarin Forms XAML files both enabled by the port of the Visual Studio editor to the Mac.</p>
<p>You can read through the announcement above for the high-level improvements. In this post I want to focus on how we got there with specifically the Android side (I will speak about XAML in a future entry).</p>
<p>Now if you have read some of my <a href="/blog/2018/05/20/android-designer-retrospective-and-future/">previous</a> <a href="/blog/2019/01/27/visual-studio-2019-android-designer/">posts</a>, we started making heavy investment improving our editing experience for Android XML resources (originally only layout files) last year which first got delivered in the <a href="https://docs.microsoft.com/en-us/visualstudio/releasenotes/vs2017-relnotes-v15.8#androiddesigner">Visual Studio 2017 15.8 release</a> and kept being improved in Visual Studio 2019.</p>
<p>At the time the landscape was quite different, Visual Studio for Mac and Visual Studio had only a few shared APIs (Roslyn mainly) and developing certain features (like editor extensions) required rewriting portion of the same code twice. Worse, on Windows the base XML editor that we were using as our editing canvas did not have many extensibility points.</p>
<p>One of the horror story of that time was around IntelliSense. Because the Visual Studio XML editor does not have an API to extend the completion list directly, we had to resort to generating on-the-fly XSD (XML Schema Definition) files that the XML language service would consume to provide the autocompletion experience.</p>
<p>This was alright at best with very basic elements and attributes completions but providing a comprehensive list that included all your resource references implied generating massive XSD files with a terrible performance cost.</p>
<p>On Visual Studio for Mac, we had the benefit of an existing and extensible XML pipeline complete with an incremental XML parser and a straightforward interface to inject our own completions depending on the caret location (elements, attributes or attributes values). This is the reason why our experience there was so much better and faster at the time.</p>
<p>When maintaining the previous XSD logic on Windows became untenable we went looking for other solutions. To implement an autocompletion experience at the time you had 3 possibilities:</p>
<ul>
<li>Use a bespoke system like the XSD files we were using (which in turn is based on a legacy Visual Studio API for language services)</li>
<li>Use Roslyn editor features layer. Unfortunately this implied having an XML parser that could output Roslyn trees which we didn’t have.</li>
<li>Use the low-level, MEF-based, synchronous completion API from the Visual Studio editor. This is what Roslyn would use under the hood but had extensively improved to be more asynchronous.</li>
</ul>
<p>Fortunately for us, we asked ourselves that question right at the time when the Visual Studio editor team were developing a new <a href="https://github.com/Microsoft/vs-editor-api/issues/9">more modern IntelliSense API</a> that was <code class="highlighter-rouge">async</code>-friendly. It represented the best of both the older API (no semantic dependencies) and Roslyn (asynchronous capabilities).</p>
<p>We made a proof-of-concept by porting part of the Visual Studio for Mac XML service to be layered on top of this new API with great help from the editor team. The result was so much better that we decided this was the way to go. As one of the earliest adopter of this new editor feature we also (hopefully) influenced it positively (Roslyn now <a href="https://github.com/dotnet/roslyn/pull/29016">uses it too</a>).</p>
<p>Thanks to this newfound knowledge of editor extensibility, we continued implementing more features: syntax highlighting (classification in Visual Studio jargon), semantic operations, go-to-definition and others. It came to the point that we provided enough functionality to simply drop the original XML editor altogether.</p>
<p>We also took advantage of our other work to employ a <a href="/blog/2018/03/21/xml-parsing-roslyn/">better XML parsing pipeline</a> in the designer itself to make the interactions between the design surface and the text editor more seamless.</p>
<p>Together, all those improvements switched things around and Visual Studio was now leading in terms of editor experience. We were keeping watch on Visual Studio for Mac though and we knew that, at the very least, work was on-going to provide those same editor extensibility API there to enable other teams at Microsoft to port their existing Visual Studio code over to the Mac.</p>
<p>As it turns out, the team decided to bite the bullet even further and ported the <strong>entire</strong> <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-for-mac-preview-3/">Visual Studio editor to the Mac</a> (with its whole extensibility API coming for the ride). This was a boon for us and, from that point on, we started making sure all our Android extension code was portable across both IDEs.</p>
<p>Excitingly, we didn’t have to do much work to make this happen. Most of the available Visual Studio editor extensibility is actually cross-platform (meaning do not depend on a Visual Studio-specific API or a UI toolkit like WPF) and thus our extensions were easy to simply share in our common codebase.</p>
<p>(There is actually enough of that type of code aside from the WPF frontend that it was possible to create <a href="/blog/2019/04/11/cross-platform-testing-visual-studio-editor-extensions/">a unit-testing library</a> with <a href="https://github.com/Microsoft/vs-editor-api">all of the open-source code available</a> that was also shareable across both Windows and Mac)</p>
<p>The extensions that couldn’t be ported straightaway usually fell into two categories: they either used Visual Studio specific APIs or they referenced WPF. Here are a few example of how we solved those issues:</p>
<ul>
<li>For code depending on Visual Studio-specific API we looked to see why. In our case it turns out a lot of it boiled down to initializing various part of the code on-demand. Instead we moved that initialization into a single <code class="highlighter-rouge">ITextViewCreationListener</code> part that was IDE-specific and thus were able to remove the equivalent calls in our other extensions to make them agnostic.</li>
<li>Another solution was to isolate the offending functionality behind another interface. We had this case with our go-to-definition service where opening a document in the IDE required platform-specific calls. What we did is hide that code behind an extremely simple interface that we could <code class="highlighter-rouge">[Import]</code> from the now shareable service and only <code class="highlighter-rouge">[Export]</code> the much smaller implementation in each IDE layers.</li>
<li>One last case was where we used <code class="highlighter-rouge">JoinableTaskFactory</code> from the <a href="https://github.com/Microsoft/vs-threading">vs-threading library</a> by querying it directly from Visual Studio. Rather than doing that, we simply <code class="highlighter-rouge">[Import]</code>’ed in our parts the <code class="highlighter-rouge">JoinableTaskContext</code> that is already exported by both IDEs and thus severed that dependency.</li>
<li>For some extensions you may end up providing some UI adornments. In this case, you can leverage the <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.text.adornments.iviewelementfactoryservice?view=visualstudiosdk-2019">IViewElementFactoryService API</a> to reference a data object from the shared code and only provide the UI-specific portion in your IDE layer.</li>
<li>Finally, as part of porting the editor to Cocoa, a number of public interfaces had to be de-WPF-ized and new types introduced to replace them. That work is expected to be shared back to Visual Studio but in the meantime you may have to do some creative subclassing to share functionality. A good example of this are adornment tags (think of the inline color previews in our editor).</li>
</ul>
<p>As a testament of the hard work from the Visual Studio for Mac team to integrate the editor, we expect that by the final 8.2 release we will have ported 100% of our originally Windows-only extensions to be shared on both IDEs.</p>
<p>If you are yourself interested in doing that kind of work, the team <a href="https://docs.microsoft.com/en-us/visualstudio/mac/extending-visual-studio-mac?view=vsmac-2019#extending-the-new-editor">has started publishing documentation</a>. Keep an eye out for new content showing up there in the near future.</p>Jérémie LavalWe released this week the first 8.2 preview of Visual Studio for Mac. This release is important for us as it’s the first one to contain our improved editor experience for Android XML resources and Xamarin Forms XAML files both enabled by the port of the Visual Studio editor to the Mac.Cross-platform testing of Visual Studio editor extensions2019-04-11T09:12:00-04:002019-04-11T09:12:00-04:00https://blog.neteril.org/blog/2019/04/11/cross-platform-testing-visual-studio-editor-extensions<p>One of the highest impact change that went into <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2019-for-mac-is-now-available/">the new version of Visual Studio for Mac</a> (2019 or 8.0 depending if you talk marketing or engineering) is a completely new implementation of the source editor.</p>
<p>What the team<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup> did is take the Visual Studio editor from Windows (with <a href="https://github.com/Microsoft/vs-editor-api">large swath of it opensource</a> by the way) that had already been designed with portability in mind and bring that dream to fruition by implementing a state-of-the-art CALayer-backed, CoreText powered, native Cocoa frontend.</p>
<p>Not only does it make the editing experience much faster and more pleasing, the implications for extension authors are tremendous as the editor is not only text data structures and the UI on top of it but also a <a href="https://docs.microsoft.com/en-us/visualstudio/extensibility/language-service-and-editor-extension-points?view=vs-2019">wide range of exposed and extendable facilities</a> all easily implementable <a href="https://docs.microsoft.com/en-us/visualstudio/extensibility/managed-extensibility-framework-in-the-editor?view=vs-2019">thanks to its use of MEF</a> (Managed Extensibility Framework).</p>
<p>There is one extender in particular that everyone should be familiar with and that’s <a href="https://github.com/dotnet/roslyn">Roslyn</a>. Not only is Roslyn your favorite compiler and analyzer framework, it’s also what powers all the editing smartness in the IDE for C# and VB.</p>
<p>How do they do it? Simple, every bit of editing feature you enjoy in Visual Studio is ultimately implemented as an MEF extension of the editor (including syntax highlighting, intellisense, code fixes, lightbulbs, info bubbles, etc…) that takes advantage of Roslyn syntactic and semantic models.</p>
<p>Want to know why the C# experience in the new editor also seems better? They are simply reusing those same exact Roslyn editor extensions than on Windows with absolutely no changes. Thus instead of re-doing all that integration ourselves and adding our own layer of bugs, we are now in the same boat than Visual Studio Windows itself.</p>
<p>That last point is the most ground-breaking part in my opinion. With the new editor in Visual Studio Mac, we now have a single, easy to use, easy to extend API to bring all and any improvements we wish to the editor experience in the IDE no matter if its on Windows or on Mac.</p>
<p>In my team we are embracing this fully by bringing <a href="/blog/2019/01/27/visual-studio-2019-android-designer/">all</a> <a href="/blog/2018/05/20/android-designer-retrospective-and-future/">the work</a> we have done over the past months to improve the experience of editing mobile UI markups in Visual Studio Windows to Visual Studio for Mac as well (stay tuned for that).</p>
<p>I wish I could say it was a complex process for self-congratulatory purposes but, as it turns out, we have been able to <strong>share and port 95% of our code</strong> to Visual Studio for Mac by only doing a tiny amount of refactoring with the crux of the changes being around splitting the UI and IDE specific parts of the extensions into their own, MEF importable parts.</p>
<h3 id="introducing-minieditor">Introducing MiniEditor</h3>
<p>That last bit is actually what brings me to write this article. One difficulty of being an extender that has to work on two IDE fronts is that it makes it more complicated to unit-test our work because we need to make it function in a fashion that’s both IDE-agnostic and UI-toolkit agnostic.</p>
<p>Since the (now) two existing implementations are both platform specific, we needed to go fill that void with essentially a third one that would only carry the truly cross-platform pieces of the puzzle. Thus <a href="https://github.com/garuma/MiniEditor">MiniEditor was born</a>.</p>
<p>In a nutshell, MiniEditor is a project that assembles a subset of code from the open-sourced editor bits (<a href="https://github.com/Microsoft/vs-editor-api">that I already mentioned above</a>) and a minimal amount of glue code and mocks so that you can easily test your editor extensions (provided they are themselves platform-agnostic).</p>
<p>More specifically the two key testing objectives that we had for MiniEditor (for now) were:</p>
<ul>
<li>Being able to test our low-level infrastructure code that uses interfaces such as <code class="highlighter-rouge">ITextDocument</code>, <code class="highlighter-rouge">ITextBuffer</code>, <code class="highlighter-rouge">ITextSnapshot</code> and so on with the real implementation of those interfaces</li>
<li>Ensure the correctness of our <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.language.intellisense.asynccompletion?view=visualstudiosdk-2017">async completion</a> Intellisense providers</li>
</ul>
<p>The <a href="https://github.com/garuma/MiniEditor/blob/master/README.md">README on the GitHub project page</a> gives a good run down of how to setup the library and use it.</p>
<p>Hopefully this gives you an appetite to start porting (or creating) your own editor extensions to Visual Studio for Mac today!</p>
<div class="footnotes">
<ol>
<li id="fn:1">
<p>Including and in no specific order: <a href="https://twitter.com/abock">Aaron</a>, <a href="https://twitter.com/sandyarmstrong">Sandy</a>, <a href="https://twitter.com/davidkarlas">David</a>, <a href="https://twitter.com/KirillOsenkov">Kirill</a>, <a href="https://twitter.com/cl_beyer">Cody</a>. <a href="#fnref:1" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>Jérémie LavalOne of the highest impact change that went into the new version of Visual Studio for Mac (2019 or 8.0 depending if you talk marketing or engineering) is a completely new implementation of the source editor.Using DirectManipulation with WPF2019-03-30T22:16:00-04:002019-03-30T22:16:00-04:00https://blog.neteril.org/blog/2019/03/30/using-directmanipulation-with-wpf<p>Or said differently, how to enjoy smooth pinch-to-zoom gestures on a legacy platform that’s not UWP (no pun intended).</p>
<p>If you have done any UI developement on Windows, chances are you have used a <code class="highlighter-rouge">ScrollViewer</code> at some point. If you use the UWP version of <code class="highlighter-rouge">ScrollViewer</code> you will notice that in addition to, well, scroll events the control also natively handles zooming. In the case of WPF however, this capability is completely absent.</p>
<p>The main reason for this is that WPF was created at a time where neither precision trackpad nor touchscreen were ubiquitous (touch was just starting with Windows 8 after all). Rather it was designed with stylus support in mind and some initial iteration for inking recognition. Since WPF has been put on ice <a href="https://devblogs.microsoft.com/dotnet/net-core-3-and-support-for-windows-desktop-applications/">until recently</a>, it never got a fresh coat of paint on its input APIs and things have indeed quite changed since then.</p>
<p>For starter, the low-level input strategy on Windows is now different. Under the hood of Win32, input events coming from trackpad, touch, stylus and others are now all unified under a single <code class="highlighter-rouge">WM_POINTER</code> event type where previously they were separate. If the app doesn’t have support for it however, the OS will try to convert those events and gestures into a somewhat equivalent combination that the app might recognize.</p>
<p>For our case (zooming and more precisely pinch to zoom gestures), that compatibility combination is a “Ctrl + Mouse Wheel Up/Down” event which is a standard pattern that apps could implement before. The trouble is that the mouse wheel event that’s sent is only in increment/decrement of <a href="https://docs.microsoft.com/en-us/dotnet/api/system.windows.input.mouse.mousewheeldeltaforoneline?view=netframework-4.7.2">a default value</a> which means you can only implement “jagged” zoom behaviors (least you feel like animating everything yourself). This would look a little bit like this:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">container</span><span class="p">.</span><span class="n">PreviewMouseWheel</span> <span class="p">+=</span> <span class="n">HandleZoomGesture</span><span class="p">;</span>
<span class="k">void</span> <span class="nf">HandleZoomGesture</span> <span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">MouseWheelEventArgs</span> <span class="n">e</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">// Input emulation will make it look like the Ctrl key is pressed</span>
<span class="c1">// when converting the pinch-to-zoom gesture</span>
<span class="k">if</span> <span class="p">((</span><span class="n">Keyboard</span><span class="p">.</span><span class="n">Modifiers</span> <span class="p">&</span> <span class="n">ModifierKeys</span><span class="p">.</span><span class="n">Control</span><span class="p">)</span> <span class="p">==</span> <span class="m">0</span><span class="p">)</span>
<span class="k">return</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">zoomDelta</span> <span class="p">=</span> <span class="n">ZoomGestureDelta</span> <span class="p">*</span> <span class="p">(((</span><span class="kt">double</span><span class="p">)</span><span class="n">e</span><span class="p">.</span><span class="n">Delta</span><span class="p">)</span> <span class="p">/</span> <span class="n">Mouse</span><span class="p">.</span><span class="n">MouseWheelDeltaForOneLine</span><span class="p">);</span>
<span class="nf">SetZoom</span> <span class="p">(</span><span class="n">currentZoom</span> <span class="p">+</span> <span class="n">zoomDelta</span><span class="p">);</span>
<span class="n">e</span><span class="p">.</span><span class="n">Handled</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This compatibility behavior might work for your case and, as an example, is what some browsers still implement (at least Firefox as I’m writing this) or also the Visual Studio text editor. If you would like something better however read on.</p>
<p>As it turns out, WPF <em>did</em> have <a href="https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/mitigation-pointer-based-touch-and-stylus-support">its input subsystem updated</a> to use this new unified <code class="highlighter-rouge">WM_POINTER</code> event type but it was never enabled by default and still today sits under an appcontext switch (<code class="highlighter-rouge">Switch.System.Windows.Input.Stylus.EnablePointerSupport</code>). Despite using the new events, that updated stack also willingly filters out scenario that are not strictly coming from touch or stylus thus completely bypassing the added support for precision trackpad.</p>
<p>Fortunately, there is a way out. Likely to allow external apps that are not UWP based to still benefit from this gesture support (aka browsers), a generic low-level API does exists going by the name of <a href="https://docs.microsoft.com/en-us/windows/desktop/api/_directmanipulation/">DirectManipulation</a>. This API operates at the HWND level and works by having you pass on those <code class="highlighter-rouge">WM_POINTER</code> messages who then get processed on a different thread with DirectManipulation handling all the heavy lifting of recognizing gestures and calculating the right transformation to apply.</p>
<p>It’s normally supposed to be used together with <a href="https://docs.microsoft.com/en-us/windows/desktop/directcomp/directcomposition-concepts">DirectComposition</a> which is another low-level API to interact with Windows compositor but you can still make it work manually by simply extracting the values you need (aka content scale).</p>
<p>The DirectManipulation API is not provided out of the box on the framework but you can use <a href="https://github.com/sharpdx/SharpDX">SharpDX</a> which has bindings for it or a tool like <code class="highlighter-rouge">tlbimp</code> on the IDL of the library. Or you can trust me with <a href="https://gist.github.com/garuma/0c25992777c19f5239c73e5b6d66a074">this binding I made</a>.</p>
<p>For your convenience, here is a “minimal” wrapper class, inspired from <a href="https://github.com/chromium/chromium/blob/master/content/browser/renderer_host/direct_manipulation_win.cc">Chrome’s usage</a>, that implements and use a subset of DirectManipulation so that you can plug it into your WPF application (including the support to understand <code class="highlighter-rouge">WM_POINTER</code> events):</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Runtime.InteropServices</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Windows</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Windows.Interop</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">DirectManipulation</span><span class="p">;</span>
<span class="k">class</span> <span class="nc">PointerBasedManipulationHandler</span> <span class="p">:</span> <span class="n">IDirectManipulationViewportEventHandler</span><span class="p">,</span> <span class="n">IDisposable</span>
<span class="p">{</span>
<span class="k">const</span> <span class="kt">int</span> <span class="n">ContentMatrixSize</span> <span class="p">=</span> <span class="m">6</span><span class="p">;</span>
<span class="c1">// Actual values don't matter</span>
<span class="k">static</span> <span class="n">tagRECT</span> <span class="n">DefaultViewport</span> <span class="p">=</span> <span class="k">new</span> <span class="n">tagRECT</span> <span class="p">{</span> <span class="n">top</span> <span class="p">=</span> <span class="m">0</span><span class="p">,</span> <span class="n">left</span> <span class="p">=</span> <span class="m">0</span><span class="p">,</span> <span class="n">right</span> <span class="p">=</span> <span class="m">1000</span><span class="p">,</span> <span class="n">bottom</span> <span class="p">=</span> <span class="m">1000</span> <span class="p">};</span>
<span class="n">HwndSource</span> <span class="n">hwndSource</span><span class="p">;</span>
<span class="n">IDirectManipulationManager</span> <span class="n">manager</span><span class="p">;</span>
<span class="n">IDirectManipulationViewport</span> <span class="n">viewport</span><span class="p">;</span>
<span class="n">Size</span> <span class="n">viewportSize</span><span class="p">;</span>
<span class="kt">uint</span> <span class="n">viewportEventHandlerRegistration</span><span class="p">;</span>
<span class="kt">float</span> <span class="n">lastScale</span><span class="p">;</span>
<span class="kt">float</span><span class="p">[]</span> <span class="n">matrix</span> <span class="p">=</span> <span class="k">new</span> <span class="kt">float</span><span class="p">[</span><span class="n">ContentMatrixSize</span><span class="p">];</span>
<span class="n">IntPtr</span> <span class="n">matrixContent</span><span class="p">;</span>
<span class="kt">float</span> <span class="n">lastTranslationX</span><span class="p">,</span> <span class="n">lastTranslationY</span><span class="p">;</span>
<span class="k">public</span> <span class="nf">PointerBasedManipulationHandler</span> <span class="p">()</span>
<span class="p">{</span>
<span class="n">matrixContent</span> <span class="p">=</span> <span class="n">Marshal</span><span class="p">.</span><span class="nf">AllocCoTaskMem</span> <span class="p">(</span><span class="k">sizeof</span> <span class="p">(</span><span class="kt">float</span><span class="p">)</span> <span class="p">*</span> <span class="n">ContentMatrixSize</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">event</span> <span class="n">Action</span><span class="p"><</span><span class="kt">float</span><span class="p">></span> <span class="n">ScaleUpdated</span><span class="p">;</span>
<span class="k">public</span> <span class="k">event</span> <span class="n">Action</span><span class="p"><</span><span class="kt">float</span><span class="p">,</span> <span class="kt">float</span><span class="p">></span> <span class="n">TranslationUpdated</span><span class="p">;</span>
<span class="k">public</span> <span class="n">HwndSource</span> <span class="n">HwndSource</span> <span class="p">{</span>
<span class="k">get</span> <span class="p">=></span> <span class="n">hwndSource</span><span class="p">;</span>
<span class="k">set</span> <span class="p">{</span>
<span class="kt">var</span> <span class="n">first</span> <span class="p">=</span> <span class="n">hwndSource</span> <span class="p">==</span> <span class="k">null</span> <span class="p">&&</span> <span class="k">value</span> <span class="p">!=</span> <span class="k">null</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">oldHwndSource</span> <span class="p">=</span> <span class="n">hwndSource</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">oldHwndSource</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
<span class="n">oldHwndSource</span><span class="p">.</span><span class="nf">RemoveHook</span> <span class="p">(</span><span class="n">WndProcHook</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="k">value</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
<span class="k">value</span><span class="p">.</span><span class="nf">AddHook</span> <span class="p">(</span><span class="n">WndProcHook</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="n">hwndSource</span> <span class="p">=</span> <span class="k">value</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">first</span> <span class="p">&&</span> <span class="k">value</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
<span class="nf">InitializeDirectManipulation</span> <span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="n">IntPtr</span> <span class="n">Window</span> <span class="p">=></span> <span class="n">hwndSource</span><span class="p">.</span><span class="n">Handle</span><span class="p">;</span>
<span class="k">void</span> <span class="nf">InitializeDirectManipulation</span> <span class="p">()</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">manager</span> <span class="p">=</span> <span class="p">(</span><span class="n">IDirectManipulationManager</span><span class="p">)</span><span class="n">Activator</span><span class="p">.</span><span class="nf">CreateInstance</span> <span class="p">(</span><span class="k">typeof</span> <span class="p">(</span><span class="n">DirectManipulationManagerClass</span><span class="p">));</span>
<span class="kt">var</span> <span class="n">riid</span> <span class="p">=</span> <span class="k">typeof</span> <span class="p">(</span><span class="n">IDirectManipulationUpdateManager</span><span class="p">).</span><span class="n">GUID</span><span class="p">;</span>
<span class="n">riid</span> <span class="p">=</span> <span class="k">typeof</span> <span class="p">(</span><span class="n">IDirectManipulationViewport</span><span class="p">).</span><span class="n">GUID</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="n">viewport</span> <span class="p">=</span> <span class="n">manager</span><span class="p">.</span><span class="nf">CreateViewport</span> <span class="p">(</span><span class="k">null</span><span class="p">,</span> <span class="n">Window</span><span class="p">,</span> <span class="k">ref</span> <span class="n">riid</span><span class="p">)</span> <span class="k">as</span> <span class="n">IDirectManipulationViewport</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">configuration</span> <span class="p">=</span> <span class="n">DIRECTMANIPULATION_CONFIGURATION</span><span class="p">.</span><span class="n">DIRECTMANIPULATION_CONFIGURATION_INTERACTION</span>
<span class="p">|</span> <span class="n">DIRECTMANIPULATION_CONFIGURATION</span><span class="p">.</span><span class="n">DIRECTMANIPULATION_CONFIGURATION_SCALING</span>
<span class="p">|</span> <span class="n">DIRECTMANIPULATION_CONFIGURATION</span><span class="p">.</span><span class="n">DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_X</span>
<span class="p">|</span> <span class="n">DIRECTMANIPULATION_CONFIGURATION</span><span class="p">.</span><span class="n">DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_Y</span>
<span class="p">|</span> <span class="n">DIRECTMANIPULATION_CONFIGURATION</span><span class="p">.</span><span class="n">DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_INERTIA</span><span class="p">;</span>
<span class="n">viewport</span><span class="p">.</span><span class="nf">ActivateConfiguration</span> <span class="p">(</span><span class="n">configuration</span><span class="p">);</span>
<span class="n">viewportEventHandlerRegistration</span> <span class="p">=</span> <span class="n">viewport</span><span class="p">.</span><span class="nf">AddEventHandler</span> <span class="p">(</span><span class="n">Window</span><span class="p">,</span> <span class="k">this</span><span class="p">);</span>
<span class="n">viewport</span><span class="p">.</span><span class="nf">SetViewportRect</span> <span class="p">(</span><span class="k">ref</span> <span class="n">DefaultViewport</span><span class="p">);</span>
<span class="n">viewport</span><span class="p">.</span><span class="nf">Enable</span> <span class="p">();</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">Dispose</span> <span class="p">()</span>
<span class="p">{</span>
<span class="n">viewport</span><span class="p">.</span><span class="nf">RemoveEventHandler</span> <span class="p">(</span><span class="n">viewportEventHandlerRegistration</span><span class="p">);</span>
<span class="n">Marshal</span><span class="p">.</span><span class="nf">FreeCoTaskMem</span> <span class="p">(</span><span class="n">matrixContent</span><span class="p">);</span>
<span class="n">HwndSource</span> <span class="p">=</span> <span class="k">null</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">SetSize</span> <span class="p">(</span><span class="n">Size</span> <span class="n">size</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">viewportSize</span> <span class="p">=</span> <span class="n">size</span><span class="p">;</span>
<span class="n">viewport</span><span class="p">.</span><span class="nf">Stop</span> <span class="p">();</span>
<span class="kt">var</span> <span class="n">rect</span> <span class="p">=</span> <span class="k">new</span> <span class="n">tagRECT</span> <span class="p">{</span>
<span class="n">left</span> <span class="p">=</span> <span class="m">0</span><span class="p">,</span>
<span class="n">top</span> <span class="p">=</span> <span class="m">0</span><span class="p">,</span>
<span class="n">right</span> <span class="p">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">size</span><span class="p">.</span><span class="n">Width</span><span class="p">,</span>
<span class="n">bottom</span> <span class="p">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">size</span><span class="p">.</span><span class="n">Height</span>
<span class="p">};</span>
<span class="n">viewport</span><span class="p">.</span><span class="nf">SetViewportRect</span> <span class="p">(</span><span class="k">ref</span> <span class="n">rect</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// Our custom hook to process WM_POINTER event</span>
<span class="n">IntPtr</span> <span class="nf">WndProcHook</span> <span class="p">(</span><span class="n">IntPtr</span> <span class="n">hwnd</span><span class="p">,</span> <span class="kt">int</span> <span class="n">msg</span><span class="p">,</span> <span class="n">IntPtr</span> <span class="n">wParam</span><span class="p">,</span> <span class="n">IntPtr</span> <span class="n">lParam</span><span class="p">,</span> <span class="k">ref</span> <span class="kt">bool</span> <span class="n">handled</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">msg</span> <span class="p">==</span> <span class="n">WM_POINTERDOWN</span> <span class="p">||</span> <span class="n">msg</span> <span class="p">==</span> <span class="n">DM_POINTERHITTEST</span><span class="p">)</span> <span class="p">{</span>
<span class="kt">var</span> <span class="n">pointerID</span> <span class="p">=</span> <span class="nf">GetPointerId</span> <span class="p">(</span><span class="n">wParam</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">pointerInfo</span> <span class="p">=</span> <span class="k">default</span> <span class="p">(</span><span class="n">POINTER_INFO</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(!</span><span class="nf">GetPointerInfo</span> <span class="p">(</span><span class="n">pointerID</span><span class="p">,</span> <span class="k">ref</span> <span class="n">pointerInfo</span><span class="p">))</span>
<span class="k">return</span> <span class="n">IntPtr</span><span class="p">.</span><span class="n">Zero</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">pointerInfo</span><span class="p">.</span><span class="n">pointerType</span> <span class="p">!=</span> <span class="n">POINTER_INPUT_TYPE</span><span class="p">.</span><span class="n">PT_TOUCHPAD</span> <span class="p">&&</span>
<span class="n">pointerInfo</span><span class="p">.</span><span class="n">pointerType</span> <span class="p">!=</span> <span class="n">POINTER_INPUT_TYPE</span><span class="p">.</span><span class="n">PT_TOUCH</span><span class="p">)</span>
<span class="k">return</span> <span class="n">IntPtr</span><span class="p">.</span><span class="n">Zero</span><span class="p">;</span>
<span class="n">viewport</span><span class="p">.</span><span class="nf">SetContact</span> <span class="p">(</span><span class="n">pointerID</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">msg</span> <span class="p">==</span> <span class="n">WM_SIZE</span> <span class="p">&&</span> <span class="n">manager</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">wParam</span> <span class="p">==</span> <span class="n">SIZE_MAXHIDE</span>
<span class="p">||</span> <span class="n">wParam</span> <span class="p">==</span> <span class="n">SIZE_MINIMIZED</span><span class="p">)</span>
<span class="n">manager</span><span class="p">.</span><span class="nf">Deactivate</span> <span class="p">(</span><span class="n">Window</span><span class="p">);</span>
<span class="k">else</span>
<span class="n">manager</span><span class="p">.</span><span class="nf">Activate</span> <span class="p">(</span><span class="n">Window</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">IntPtr</span><span class="p">.</span><span class="n">Zero</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">void</span> <span class="nf">ResetViewport</span> <span class="p">(</span><span class="n">IDirectManipulationViewport</span> <span class="n">viewport</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">viewport</span><span class="p">.</span><span class="nf">ZoomToRect</span> <span class="p">(</span><span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="p">(</span><span class="kt">float</span><span class="p">)</span><span class="n">viewportSize</span><span class="p">.</span><span class="n">Width</span><span class="p">,</span> <span class="p">(</span><span class="kt">float</span><span class="p">)</span><span class="n">viewportSize</span><span class="p">.</span><span class="n">Height</span><span class="p">,</span> <span class="m">0</span><span class="p">);</span>
<span class="n">lastScale</span> <span class="p">=</span> <span class="m">1.0f</span><span class="p">;</span>
<span class="n">lastTranslationX</span> <span class="p">=</span> <span class="n">lastTranslationY</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">OnViewportStatusChanged</span> <span class="p">([</span><span class="n">In</span><span class="p">,</span> <span class="nf">MarshalAs</span> <span class="p">(</span><span class="n">UnmanagedType</span><span class="p">.</span><span class="n">Interface</span><span class="p">)]</span> <span class="n">IDirectManipulationViewport</span> <span class="n">viewport</span><span class="p">,</span> <span class="p">[</span><span class="n">In</span><span class="p">]</span> <span class="n">DIRECTMANIPULATION_STATUS</span> <span class="n">current</span><span class="p">,</span> <span class="p">[</span><span class="n">In</span><span class="p">]</span> <span class="n">DIRECTMANIPULATION_STATUS</span> <span class="n">previous</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">previous</span> <span class="p">==</span> <span class="n">current</span><span class="p">)</span>
<span class="k">return</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">current</span> <span class="p">==</span> <span class="n">DIRECTMANIPULATION_STATUS</span><span class="p">.</span><span class="n">DIRECTMANIPULATION_READY</span><span class="p">)</span>
<span class="nf">ResetViewport</span> <span class="p">(</span><span class="n">viewport</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">OnViewportUpdated</span> <span class="p">([</span><span class="n">In</span><span class="p">,</span> <span class="nf">MarshalAs</span> <span class="p">(</span><span class="n">UnmanagedType</span><span class="p">.</span><span class="n">Interface</span><span class="p">)]</span> <span class="n">IDirectManipulationViewport</span> <span class="n">viewport</span><span class="p">)</span>
<span class="p">{</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">OnContentUpdated</span> <span class="p">([</span><span class="n">In</span><span class="p">,</span> <span class="nf">MarshalAs</span> <span class="p">(</span><span class="n">UnmanagedType</span><span class="p">.</span><span class="n">Interface</span><span class="p">)]</span> <span class="n">IDirectManipulationViewport</span> <span class="n">viewport</span><span class="p">,</span> <span class="p">[</span><span class="n">In</span><span class="p">,</span> <span class="nf">MarshalAs</span> <span class="p">(</span><span class="n">UnmanagedType</span><span class="p">.</span><span class="n">Interface</span><span class="p">)]</span> <span class="n">IDirectManipulationContent</span> <span class="n">content</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">content</span><span class="p">.</span><span class="nf">GetContentTransform</span> <span class="p">(</span><span class="n">matrixContent</span><span class="p">,</span> <span class="n">ContentMatrixSize</span><span class="p">);</span>
<span class="n">Marshal</span><span class="p">.</span><span class="nf">Copy</span> <span class="p">(</span><span class="n">matrixContent</span><span class="p">,</span> <span class="n">matrix</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">ContentMatrixSize</span><span class="p">);</span>
<span class="kt">float</span> <span class="n">scale</span> <span class="p">=</span> <span class="n">matrix</span><span class="p">[</span><span class="m">0</span><span class="p">];</span>
<span class="kt">float</span> <span class="n">newX</span> <span class="p">=</span> <span class="n">matrix</span><span class="p">[</span><span class="m">4</span><span class="p">];</span>
<span class="kt">float</span> <span class="n">newY</span> <span class="p">=</span> <span class="n">matrix</span><span class="p">[</span><span class="m">5</span><span class="p">];</span>
<span class="k">if</span> <span class="p">(</span><span class="n">scale</span> <span class="p">==</span> <span class="m">0.0f</span><span class="p">)</span>
<span class="k">return</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">deltaX</span> <span class="p">=</span> <span class="p">(</span><span class="n">newX</span> <span class="p">-</span> <span class="n">lastTranslationX</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">deltaY</span> <span class="p">=</span> <span class="p">(</span><span class="n">newY</span> <span class="p">-</span> <span class="n">lastTranslationY</span><span class="p">);</span>
<span class="kt">bool</span> <span class="nf">ShallowFloatEquals</span> <span class="p">(</span><span class="kt">float</span> <span class="n">f1</span><span class="p">,</span> <span class="kt">float</span> <span class="n">f2</span><span class="p">)</span>
<span class="p">=></span> <span class="n">Math</span><span class="p">.</span><span class="nf">Abs</span> <span class="p">(</span><span class="n">f2</span> <span class="p">-</span> <span class="n">f1</span><span class="p">)</span> <span class="p"><</span> <span class="kt">float</span><span class="p">.</span><span class="n">Epsilon</span><span class="p">;</span>
<span class="k">if</span> <span class="p">((</span><span class="nf">ShallowFloatEquals</span> <span class="p">(</span><span class="n">scale</span><span class="p">,</span> <span class="m">1.0f</span><span class="p">)</span> <span class="p">||</span> <span class="nf">ShallowFloatEquals</span> <span class="p">(</span><span class="n">scale</span><span class="p">,</span> <span class="n">lastScale</span><span class="p">))</span>
<span class="p">&&</span> <span class="p">(</span><span class="n">Math</span><span class="p">.</span><span class="nf">Abs</span> <span class="p">(</span><span class="n">deltaX</span><span class="p">)</span> <span class="p">></span> <span class="m">1.0f</span> <span class="p">||</span> <span class="n">Math</span><span class="p">.</span><span class="nf">Abs</span> <span class="p">(</span><span class="n">deltaY</span><span class="p">)</span> <span class="p">></span> <span class="m">1.0f</span><span class="p">))</span> <span class="p">{</span>
<span class="n">TranslationUpdated</span><span class="p">?.</span><span class="nf">Invoke</span> <span class="p">(-</span><span class="n">deltaX</span><span class="p">,</span> <span class="p">-</span><span class="n">deltaY</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(!</span><span class="nf">ShallowFloatEquals</span> <span class="p">(</span><span class="n">lastScale</span><span class="p">,</span> <span class="n">scale</span><span class="p">))</span> <span class="p">{</span>
<span class="n">ScaleUpdated</span><span class="p">?.</span><span class="nf">Invoke</span> <span class="p">(</span><span class="n">scale</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">lastScale</span> <span class="p">=</span> <span class="n">scale</span><span class="p">;</span>
<span class="n">lastTranslationX</span> <span class="p">=</span> <span class="n">newX</span><span class="p">;</span>
<span class="n">lastTranslationY</span> <span class="p">=</span> <span class="n">newY</span><span class="p">;</span>
<span class="p">}</span>
<span class="err">#</span><span class="n">region</span> <span class="n">Native</span> <span class="n">methods</span>
<span class="k">const</span> <span class="kt">int</span> <span class="n">WM_POINTERDOWN</span> <span class="p">=</span> <span class="m">0x0246</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">int</span> <span class="n">DM_POINTERHITTEST</span> <span class="p">=</span> <span class="m">0x0250</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">int</span> <span class="n">WM_SIZE</span> <span class="p">=</span> <span class="m">0x0005</span><span class="p">;</span>
<span class="k">static</span> <span class="k">readonly</span> <span class="n">IntPtr</span> <span class="n">SIZE_MAXHIDE</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">IntPtr</span> <span class="p">(</span><span class="m">4</span><span class="p">);</span>
<span class="k">static</span> <span class="k">readonly</span> <span class="n">IntPtr</span> <span class="n">SIZE_MINIMIZED</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">IntPtr</span> <span class="p">(</span><span class="m">1</span><span class="p">);</span>
<span class="kt">uint</span> <span class="nf">GetPointerId</span> <span class="p">(</span><span class="n">IntPtr</span> <span class="n">wParam</span><span class="p">)</span> <span class="p">=></span> <span class="p">(</span><span class="kt">uint</span><span class="p">)(</span><span class="k">unchecked</span><span class="p">((</span><span class="kt">int</span><span class="p">)</span><span class="n">wParam</span><span class="p">.</span><span class="nf">ToInt64</span> <span class="p">())</span> <span class="p">&</span> <span class="m">0xFFFF</span><span class="p">);</span>
<span class="p">[</span><span class="nf">DllImport</span> <span class="p">(</span><span class="s">"user32.dll"</span><span class="p">,</span> <span class="n">EntryPoint</span> <span class="p">=</span> <span class="s">"GetPointerInfo"</span><span class="p">,</span> <span class="n">SetLastError</span> <span class="p">=</span> <span class="k">true</span><span class="p">)]</span>
<span class="k">internal</span> <span class="k">static</span> <span class="k">extern</span> <span class="kt">bool</span> <span class="nf">GetPointerInfo</span> <span class="p">([</span><span class="n">In</span><span class="p">]</span> <span class="kt">uint</span> <span class="n">pointerId</span><span class="p">,</span> <span class="p">[</span><span class="n">In</span><span class="p">,</span> <span class="n">Out</span><span class="p">]</span> <span class="k">ref</span> <span class="n">POINTER_INFO</span> <span class="n">pointerInfo</span><span class="p">);</span>
<span class="p">[</span><span class="nf">StructLayout</span> <span class="p">(</span><span class="n">LayoutKind</span><span class="p">.</span><span class="n">Sequential</span><span class="p">,</span> <span class="n">CharSet</span> <span class="p">=</span> <span class="n">CharSet</span><span class="p">.</span><span class="n">Unicode</span><span class="p">)]</span>
<span class="k">internal</span> <span class="k">struct</span> <span class="nc">POINTER_INFO</span>
<span class="p">{</span>
<span class="k">internal</span> <span class="n">POINTER_INPUT_TYPE</span> <span class="n">pointerType</span><span class="p">;</span>
<span class="k">internal</span> <span class="kt">uint</span> <span class="n">pointerId</span><span class="p">;</span>
<span class="k">internal</span> <span class="kt">uint</span> <span class="n">frameId</span><span class="p">;</span>
<span class="k">internal</span> <span class="n">POINTER_FLAGS</span> <span class="n">pointerFlags</span><span class="p">;</span>
<span class="k">internal</span> <span class="n">IntPtr</span> <span class="n">sourceDevice</span><span class="p">;</span>
<span class="k">internal</span> <span class="n">IntPtr</span> <span class="n">hwndTarget</span><span class="p">;</span>
<span class="k">internal</span> <span class="n">POINT</span> <span class="n">ptPixelLocation</span><span class="p">;</span>
<span class="k">internal</span> <span class="n">POINT</span> <span class="n">ptHimetricLocation</span><span class="p">;</span>
<span class="k">internal</span> <span class="n">POINT</span> <span class="n">ptPixelLocationRaw</span><span class="p">;</span>
<span class="k">internal</span> <span class="n">POINT</span> <span class="n">ptHimetricLocationRaw</span><span class="p">;</span>
<span class="k">internal</span> <span class="kt">uint</span> <span class="n">dwTime</span><span class="p">;</span>
<span class="k">internal</span> <span class="kt">uint</span> <span class="n">historyCount</span><span class="p">;</span>
<span class="k">internal</span> <span class="kt">int</span> <span class="n">inputData</span><span class="p">;</span>
<span class="k">internal</span> <span class="kt">uint</span> <span class="n">dwKeyStates</span><span class="p">;</span>
<span class="k">internal</span> <span class="kt">ulong</span> <span class="n">PerformanceCount</span><span class="p">;</span>
<span class="k">internal</span> <span class="n">POINTER_BUTTON_CHANGE_TYPE</span> <span class="n">ButtonChangeType</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">[</span><span class="nf">StructLayout</span> <span class="p">(</span><span class="n">LayoutKind</span><span class="p">.</span><span class="n">Sequential</span><span class="p">,</span> <span class="n">CharSet</span> <span class="p">=</span> <span class="n">CharSet</span><span class="p">.</span><span class="n">Unicode</span><span class="p">)]</span>
<span class="k">internal</span> <span class="k">struct</span> <span class="nc">POINT</span>
<span class="p">{</span>
<span class="k">internal</span> <span class="kt">int</span> <span class="n">X</span><span class="p">;</span>
<span class="k">internal</span> <span class="kt">int</span> <span class="n">Y</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">internal</span> <span class="k">enum</span> <span class="n">POINTER_INPUT_TYPE</span> <span class="p">:</span> <span class="kt">uint</span>
<span class="p">{</span>
<span class="n">PT_POINTER</span> <span class="p">=</span> <span class="m">0x00000001</span><span class="p">,</span>
<span class="n">PT_TOUCH</span> <span class="p">=</span> <span class="m">0x00000002</span><span class="p">,</span>
<span class="n">PT_PEN</span> <span class="p">=</span> <span class="m">0x00000003</span><span class="p">,</span>
<span class="n">PT_MOUSE</span> <span class="p">=</span> <span class="m">0x00000004</span><span class="p">,</span>
<span class="n">PT_TOUCHPAD</span> <span class="p">=</span> <span class="m">0x00000005</span>
<span class="p">}</span>
<span class="p">[</span><span class="n">Flags</span><span class="p">]</span>
<span class="k">internal</span> <span class="k">enum</span> <span class="n">POINTER_FLAGS</span> <span class="p">:</span> <span class="kt">uint</span>
<span class="p">{</span>
<span class="n">POINTER_FLAG_NONE</span> <span class="p">=</span> <span class="m">0x00000000</span><span class="p">,</span>
<span class="n">POINTER_FLAG_NEW</span> <span class="p">=</span> <span class="m">0x00000001</span><span class="p">,</span>
<span class="n">POINTER_FLAG_INRANGE</span> <span class="p">=</span> <span class="m">0x00000002</span><span class="p">,</span>
<span class="n">POINTER_FLAG_INCONTACT</span> <span class="p">=</span> <span class="m">0x00000004</span><span class="p">,</span>
<span class="n">POINTER_FLAG_FIRSTBUTTON</span> <span class="p">=</span> <span class="m">0x00000010</span><span class="p">,</span>
<span class="n">POINTER_FLAG_SECONDBUTTON</span> <span class="p">=</span> <span class="m">0x00000020</span><span class="p">,</span>
<span class="n">POINTER_FLAG_THIRDBUTTON</span> <span class="p">=</span> <span class="m">0x00000040</span><span class="p">,</span>
<span class="n">POINTER_FLAG_FOURTHBUTTON</span> <span class="p">=</span> <span class="m">0x00000080</span><span class="p">,</span>
<span class="n">POINTER_FLAG_FIFTHBUTTON</span> <span class="p">=</span> <span class="m">0x00000100</span><span class="p">,</span>
<span class="n">POINTER_FLAG_PRIMARY</span> <span class="p">=</span> <span class="m">0x00002000</span><span class="p">,</span>
<span class="n">POINTER_FLAG_CONFIDENCE</span> <span class="p">=</span> <span class="m">0x000004000</span><span class="p">,</span>
<span class="n">POINTER_FLAG_CANCELED</span> <span class="p">=</span> <span class="m">0x000008000</span><span class="p">,</span>
<span class="n">POINTER_FLAG_DOWN</span> <span class="p">=</span> <span class="m">0x00010000</span><span class="p">,</span>
<span class="n">POINTER_FLAG_UPDATE</span> <span class="p">=</span> <span class="m">0x00020000</span><span class="p">,</span>
<span class="n">POINTER_FLAG_UP</span> <span class="p">=</span> <span class="m">0x00040000</span><span class="p">,</span>
<span class="n">POINTER_FLAG_WHEEL</span> <span class="p">=</span> <span class="m">0x00080000</span><span class="p">,</span>
<span class="n">POINTER_FLAG_HWHEEL</span> <span class="p">=</span> <span class="m">0x00100000</span><span class="p">,</span>
<span class="n">POINTER_FLAG_CAPTURECHANGED</span> <span class="p">=</span> <span class="m">0x00200000</span><span class="p">,</span>
<span class="n">POINTER_FLAG_HASTRANSFORM</span> <span class="p">=</span> <span class="m">0x00400000</span><span class="p">,</span>
<span class="p">}</span>
<span class="k">internal</span> <span class="k">enum</span> <span class="n">POINTER_BUTTON_CHANGE_TYPE</span> <span class="p">:</span> <span class="kt">uint</span>
<span class="p">{</span>
<span class="n">POINTER_CHANGE_NONE</span><span class="p">,</span>
<span class="n">POINTER_CHANGE_FIRSTBUTTON_DOWN</span><span class="p">,</span>
<span class="n">POINTER_CHANGE_FIRSTBUTTON_UP</span><span class="p">,</span>
<span class="n">POINTER_CHANGE_SECONDBUTTON_DOWN</span><span class="p">,</span>
<span class="n">POINTER_CHANGE_SECONDBUTTON_UP</span><span class="p">,</span>
<span class="n">POINTER_CHANGE_THIRDBUTTON_DOWN</span><span class="p">,</span>
<span class="n">POINTER_CHANGE_THIRDBUTTON_UP</span><span class="p">,</span>
<span class="n">POINTER_CHANGE_FOURTHBUTTON_DOWN</span><span class="p">,</span>
<span class="n">POINTER_CHANGE_FOURTHBUTTON_UP</span><span class="p">,</span>
<span class="n">POINTER_CHANGE_FIFTHBUTTON_DOWN</span><span class="p">,</span>
<span class="n">POINTER_CHANGE_FIFTHBUTTON_UP</span>
<span class="p">}</span>
<span class="err">#</span><span class="n">endregion</span>
<span class="p">}</span>
</code></pre></div></div>
<p>To use the helper, instantiate it somewhere and pass it the <code class="highlighter-rouge">HwndSource</code> where your zoomable content is hosted. You can do so using the <a href="https://docs.microsoft.com/en-us/dotnet/api/system.windows.presentationsource.addsourcechangedhandler?view=netframework-4.7.2">PresentationSource.AddSourceChangedHandler</a> method like so:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">PointerBasedManipulationHandler</span> <span class="n">manipulationHandler</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">PointerBasedManipulationHandler</span> <span class="p">();</span>
<span class="n">PresentationSource</span><span class="p">.</span><span class="nf">AddSourceChangedHandler</span> <span class="p">(</span><span class="n">container</span><span class="p">,</span> <span class="n">HandleSourceUpdated</span><span class="p">);</span>
<span class="k">void</span> <span class="nf">HandleSourceUpdated</span> <span class="p">(</span><span class="kt">object</span> <span class="n">sender</span><span class="p">,</span> <span class="n">SourceChangedEventArgs</span> <span class="n">e</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">manipulationHandler</span> <span class="p">!=</span> <span class="k">null</span> <span class="p">&&</span> <span class="n">e</span><span class="p">.</span><span class="n">NewSource</span> <span class="k">is</span> <span class="n">System</span><span class="p">.</span><span class="n">Windows</span><span class="p">.</span><span class="n">Interop</span><span class="p">.</span><span class="n">HwndSource</span> <span class="n">newHwnd</span><span class="p">)</span>
<span class="n">manipulationHandler</span><span class="p">.</span><span class="n">HwndSource</span> <span class="p">=</span> <span class="n">newHwnd</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Finally, subscribe to the handler’s <code class="highlighter-rouge">ScaleUpdated</code> / <code class="highlighter-rouge">TranslationUpdated</code> events to react to DirectManipulation changes. For instance you can use a <a href="https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.scaletransform?view=netframework-4.7.2">ScaleTransform</a> as your container <a href="https://docs.microsoft.com/en-us/dotnet/api/system.windows.uielement.rendertransform?view=netframework-4.7.2">RenderTransform</a> and set the corresponding values when you receive the event. Also don’t forget to set the size of your canvas by calling the <code class="highlighter-rouge">SetSize</code> method (for instance wired up from a <code class="highlighter-rouge">SizeChanged</code> event).</p>
<p><strong>Now (at the end of the post) here is the final important caveat</strong>. If you want any of this DirectManipulation integration to work you are going to have to do one of two things. Because of the way DirectManipulation employs input delegation, you cannot have the legacy WPF stylus input stack run inside your application (which is the default). As such you have two options:</p>
<ul>
<li>Disable native stylus/touch support and instead only rely on DirectManipulation: set the <code class="highlighter-rouge">Switch.System.Windows.Input.Stylus.DisableStylusAndTouchSupport=true</code> switch in you app.config or programmatically.</li>
<li>Enable the pointer-based stylus/touch input stack which is compatible with DirectManipulation: set the <code class="highlighter-rouge">Switch.System.Windows.Input.Stylus.EnablePointerSupport=true</code> switch in your app.config or programmatically (early on).</li>
</ul>Jérémie LavalOr said differently, how to enjoy smooth pinch-to-zoom gestures on a legacy platform that’s not UWP (no pun intended).What’s new with the Android Designer in Visual Studio 20192019-01-27T08:00:00-05:002019-01-27T08:00:00-05:00https://blog.neteril.org/blog/2019/01/27/visual-studio-2019-android-designer<p>With Visual Studio 2019 Preview 2 <a href="https://docs.microsoft.com/en-us/visualstudio/releases/2019/release-notes-preview#VS2019_Preview2">released a few days ago</a>, I figured I would do another little more in-depth post (similar to <a href="/blog/2018/05/20/android-designer-retrospective-and-future/">last time</a>) on what the team has been doing.</p>
<p>⚙️ <strong>Themed and accessible</strong></p>
<p>For this release, we strived to make our designer compliant with our internal accessibility standards (<a href="https://www.microsoft.com/en-us/accessibility/approach">which is a big deal for us</a>).</p>
<p>As a side effect of this work, we now follow more closely the general theming of Visual Studio including properly adapting to its dark color scheme (no more light colored design surface in dark mode).</p>
<p><img src="/wp-content/uploads/new-in-designer-2019/theme.png" alt="Dark Theme" class="center" /></p>
<p>⚙️ <strong>Doubling down on our source editor experience</strong></p>
<p>This release packs a lot of new stuff for people who like editing layout files by hand.</p>
<p>In addition to generally improving our intellisense and other capabilities that we introduced in Visual Studio 2017 15.8, we have added a few more niceties like being able to drag&drop elements from the toolbox to the source editor, synchronization between caret position/surface selection and inline color previews on resource URLs.</p>
<p><img src="/wp-content/uploads/new-in-designer-2019/color-previews.png" alt="Color previews" height="70" class="center" /></p>
<p>We also put a layer of smartness on some of our operations as well. For instance when trying to comment parts of your layout, we will always ensure that your selection is syntactically correct XML and automatically expand it if it’s not.</p>
<p><video controls="" autoplay="" loop=""><source src="/wp-content/uploads/new-in-designer-2019/smart-comment.mp4" type="video/mp4" /></video></p>
<p>In the same vein, the drag&drop to the source editor I mentioned above will try to understand your intention and properly insert the new element as if you had dropped it on the design surface so that it never results in invalid XML.</p>
<p><video controls="" autoplay="" loop=""><source src="/wp-content/uploads/new-in-designer-2019/smart-dnd.mp4" type="video/mp4" /></video></p>
<p>⚙️ <strong>Supporting all Android XML resources</strong></p>
<p>When talking to customers, we could sense a confusion as to why editing layout files had all those nice extra features but editing other Android XML resources did not.</p>
<p>In Visual Studio 2019 we decided to tackle this by extending our language service to all XML resources. This means that you will now get improved syntax highlighting, autocompletion, quickinfo in any resource XML files and your Android manifest.</p>
<p><img src="/wp-content/uploads/new-in-designer-2019/editor-xml-resources.png" alt="Editor XML resources" class="center" /></p>
<p>⚙️ <strong>Resource navigation</strong></p>
<p>Talking about supporting more Android XML files, we have also added navigation support between resources so that if you Ctrl+Click on a resource url in a document (e.g. <code class="highlighter-rouge">@string/myString</code>) you will be brought to its definition.</p>
<p><video controls="" autoplay="" loop=""><source src="/wp-content/uploads/new-in-designer-2019/resource-navigate.mp4" type="video/mp4" /></video></p>
<p>⚙️ <strong>Performance and memory optimizations</strong></p>
<p>We have improved the startup time of the designer in addition to general improvements to speed and memory usage. We still have a lot of work to do in that area (especially on our cold startup time) and it will be one of our zone of focus this year.</p>
<p>That’s about it for this release. This post mainly focused on our Visual Studio Windows specific improvements but we will have exciting news to share with Visual Studio for Mac as well soon.</p>Jérémie LavalWith Visual Studio 2019 Preview 2 released a few days ago, I figured I would do another little more in-depth post (similar to last time) on what the team has been doing.Android Designer Retrospective and Future2018-05-20T00:10:00-04:002018-05-20T00:10:00-04:00https://blog.neteril.org/blog/2018/05/20/android-designer-retrospective-and-future<p>In the spirit of Matt series of <a href="http://lastexitcode.com/blog/2018/05/20/NetCoreSupportInVisualStudioMac7-5/">excellent</a> <a href="http://lastexitcode.com/blog/2018/05/19/NuGetSupportInVisualStudioMac7-5/">posts</a>, this one will cover some of the work we have been doing in the Android Designer in the last 6 months or so and what’s about to come.</p>
<h3 id="the-past">The past</h3>
<p>Improvements we have been making over the last few releases.</p>
<p>⚙️ <strong>A new Android resources subsystem</strong></p>
<p>Previously our way of handling an Android project resources used a complex system spanning Java and C# so that we could support both layout rendering and querying data from your resources (like what’s the value of <code class="highlighter-rouge">@string/app_name</code>).</p>
<p>We since have developed a complete API very similar in spirit to what Roslyn offers for C# that allows us to completely understand resources without involving any Java code.</p>
<p>This new library now drives all resources operations we do from rendering to theme manipulation or autocompletion of resource names. It’s also much more efficient than before thanks to faster parsing, aggressive caching and a better data model for querying.</p>
<p>In the future, that same API will also allow us to expose refactoring operations much like what you can do today in C# (renaming, extracting values to resource or style, …)</p>
<p>⚙️ <strong>Revamped property panel</strong></p>
<p><img src="/wp-content/uploads/new-in-designer/new-property-panel.png" alt="New Property Panel" height="400" /> <img src="/wp-content/uploads/new-in-designer/new-property-panel2.png" alt="New Property Panel" height="400" /></p>
<p>While we always had our own custom property panel on Visual Studio Mac, it was unfortunately not easy to port it over to Visual Studio. For this reason, we had been using the default property panel implementation offered by the IDE there.</p>
<p>Since this property panel was tailored for Windows Forms development, it suffered from a lot of usability problems and poor integration with our Android capabilities.</p>
<p>In the last release of Visual Studio, we have developed a new property panel with a much better design foundation and code-sharing strategy that we plan to streamline on all our designers with a native UI and experience for each IDE.</p>
<p>⚙️ <strong>Indirect rendering</strong></p>
<p>For a few releases now we have enabled a new mode we call indirect rendering that allows us to process graphic updates when rendering your layout in a fully asynchronous manner.</p>
<p>The concept is very similar to what modern browsers are doing today (pioneered by Chrome initially) where rendering is achieved out-of-process and efficiently composited by the GPU in the main window.</p>
<p>In most cases simple layout modifications now render quasi-instantaneously.</p>
<p>⚙️ <strong>Support for new Android features</strong></p>
<p><img src="/wp-content/uploads/new-in-designer/custom-fonts.png" alt="Custom Fonts" /></p>
<p>Among the new Android features that arrived with the <a href="https://developer.android.com/about/versions/oreo/#whats-in-android-oreo">latest release of Oreo</a>, we have specifically added support for things like <a href="https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml">custom fonts</a> and <a href="https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive">adaptative icons</a> rendering.</p>
<p>⚙️ <strong>Leveraging the XAML designer shell on Visual Studio</strong></p>
<p>Thanks to the collaboration of the XAML experiences team (in charge of both the WPF and UWP designer), we are now reusing the same designer UI shell to host the Android designer on Visual Studio Windows thus benefiting from the same solid foundation and familiar user-experience.</p>
<p>⚙️ <strong>Updated Android Studio</strong></p>
<p><a href="/blog/2016/12/17/custom-controls-xamarin-android-designer/">As I have explained previously</a> in my designer architecture primer, we share pieces of code from Android Studio’s layout renderer thanks to the fact that it’s part of the Android Open-Source Project (AOSP) umbrella.</p>
<p>As such we have been continuously following the different releases (2.3, 3.0 and recently 3.1) to bring in the best of the fixes and performance improvements done by Google.</p>
<h3 id="the-near-term">The near term</h3>
<p>What we have in stock for the next release of Visual Studio</p>
<p>⚙️ <strong>Reworked XML parsing</strong></p>
<p>Historically we have been using the framework System.Xml.Linq API to do most of our XML parsing. Despite this API being very expressive and a pleasure to use, it has several shortcomings in an editor scenario that <a href="/blog/2018/03/21/xml-parsing-roslyn/">I documented in a previous blog post</a>.</p>
<p>Long story short, we are now using the <a href="https://github.com/KirillOsenkov/XmlParser">XmlParser project</a> across the board. The biggest user visible feature of this (in addition to all the internal advantages it provides) is that we will no longer continuously reformat your AXML source and instead only apply the minimum subset of necessary changes when you use the designer.</p>
<p>⚙️ <strong>Split-view editor</strong></p>
<video controls="" autoplay="" loop=""><source src="/wp-content/uploads/new-in-designer/android-designer-newstuff.mp4" type="video/mp4" /></video>
<p><em>Notice how modifications done outside the editor only affect their own regions</em></p>
<p>A long requested feature, we will provide a split-view experience where you can simultaneously edit your layout with the designer surface/property panel and the source editor.</p>
<p>To be able to do this we had to completely overhaul our internals to better fit the <a href="https://docs.microsoft.com/en-us/visualstudio/extensibility/inside-the-editor#textmodel">Visual Studio text model</a> . This went hand in hand with the previous XML rework (for instance allowing incremental parsing of source changes).</p>
<p>You can try this in the next upcoming Visual Studio preview release. We will of course strive to bring the same experience to Visual Studio for Mac as well.</p>
<p>⚙️ <strong>Improved source experience</strong></p>
<p><img src="/wp-content/uploads/new-in-designer/vseditor-integration.png" alt="Visual Studio Editor Integration" width="500" /></p>
<p>Another great example of collaboration we had is with the Visual Studio Platform team responsible among others for the text editor and all the language services extensibility.</p>
<p>Over the past months, they have been <a href="https://github.com/Microsoft/vs-editor-api/wiki">improving the APIs</a> of common intellisense features such as autocompletion and quick info (the popover shown when you hover some text) to make them faster and <code class="highlighter-rouge">async</code> friendly.</p>
<p>We will take advantage of these new functionalities to provide an even better source experience for layout editing.</p>
<p>⚙️ <strong>Sample data</strong></p>
<p><img src="/wp-content/uploads/new-in-designer/sample-data.png" alt="Sample data" /></p>
<p>Sample data allows you to inject mock data source in your layout so that you can preview what a running version would look like. In the screenshot above for instance, we reference sample data in a list item layout and see how it would look like when hosted in a <code class="highlighter-rouge">RecyclerView</code> widget.</p>
<p>In the next Visual Studio preview we will support those default set of sample data sources:</p>
<ul>
<li><code class="highlighter-rouge">@tools:sample/cities</code></li>
<li><code class="highlighter-rouge">@tools:sample/names</code></li>
<li><code class="highlighter-rouge">@tools:sample/street_types</code></li>
<li><code class="highlighter-rouge">@tools:sample/surnames</code></li>
<li><code class="highlighter-rouge">@tools:sample/full_names</code></li>
<li><code class="highlighter-rouge">@tools:sample/avatars</code></li>
</ul>
<p>In a subsequent preview release we will also let you define your own source of data.</p>
<h3 id="future-plans">Future plans</h3>
<p>Among the list of the things we are planning to do next, here are a few of the big ticket items in no special order (some of those just announced at Google I/O this year):</p>
<ul>
<li><a href="https://developer.android.com/topic/libraries/architecture/navigation/navigation-implementing#Tour">Navigation editor</a></li>
<li><a href="https://developer.android.com/training/constraint-layout/">Constraint layout</a> editing</li>
<li><a href="https://www.youtube.com/watch?v=ytZteMo4ETk#t=28m58">MotionLayout</a> and more animation tools</li>
<li>Faster designer startup</li>
<li>More <code class="highlighter-rouge">tools:</code> attributes support</li>
<li>Easier use of Android Jetpacks/support libraries</li>
</ul>Jérémie LavalIn the spirit of Matt series of excellent posts, this one will cover some of the work we have been doing in the Android Designer in the last 6 months or so and what’s about to come.XML parsing in the Roslyn era2018-03-21T09:00:00-04:002018-03-21T09:00:00-04:00https://blog.neteril.org/blog/2018/03/21/xml-parsing-roslyn<p>Roslyn was a revolution in the .NET world when it came out. For the first time we had Microsoft release their compiler implementation of C# under an open-source license. Not only that, the way in which this compiler had been constructed would open the doors to numerous improvements in the ecosystem in the forms of:</p>
<ul>
<li>A complete API to manipulate code as data</li>
<li>A compiler platform that is easy to hack on</li>
<li>A backend that is adapted for editor/language service usage</li>
</ul>
<p>This enabled faster evolutions of the C# language, a plethora of tools and analyzers that can fully understand your code and intellisense that’s better than ever.</p>
<p>In my day to day job I work on visual tools at Microsoft for our Xamarin platform. As part of this we integrate with both Visual Studio Mac and Visual Studio where we, of course, use Roslyn for most of our user code interactions.</p>
<p>However, those visual tools all have another thing in common: they work on some dialect of XML (be it XAML, Android layout XML, XML resources or others). In a lot of ways working with that XML medium in the context of an editor presents the same challenges than Roslyn solved for code:</p>
<ul>
<li>You need high-fidelity parsing of your document preserving user modifications</li>
<li>You need to react to and create changes applied to specific text subsets</li>
<li>You need a representation that is easy to manipulate and pass around</li>
</ul>
<p>Existing XML solutions (<code class="highlighter-rouge">System.Xml</code>, <code class="highlighter-rouge">System.Xml.Linq</code>, …) tend to fall short because they weren’t created with an editor usage in mind. Their use case is more about exposing a document content than caring much about the way it’s written and evolved.</p>
<p>So basically what we need is Roslyn but for XML. Fortunately <a href="https://twitter.com/KirillOsenkov">Kirill</a> thought the same and a few years ago started working on bringing an existing morsel of Roslyn, namely the VB XML literal parser, and transform it into a fully fledged XML parser and syntax representation.</p>
<p>That project is (originally) named <a href="https://github.com/KirillOsenkov/XmlParser">XmlParser</a></p>
<p>In a nutshell, XmlParser brings the Roslyn SyntaxTree AST model (immutable, full-fidelity, error-tolerant) and the parsing infrastructure that can create it to the point that its usage should feel familiar to someone who is used to work with Roslyn already.</p>
<p>As part of ongoing work, I spent a bit of time myself during the last few weeks bringing some improvements to the project to make it even better for an editor use case:</p>
<ul>
<li>Proper <a href="https://blogs.msdn.microsoft.com/ericlippert/2012/06/08/persistence-facades-and-roslyns-red-green-trees/">red-green node separation</a> which is a key to Roslyn performance while retaining immutability</li>
<li>Parsing incrementality: the ability to reuse existing syntax tree nodes when only a portion of the text buffer has changed</li>
<li>The start of proper syntax factories and modification APIs</li>
<li>More Roslyn code import where it made sense (common utilities, caching, …)</li>
</ul>
<p>Albeit part of this is still a work-in-progress, we published updated NuGet packages (now under the <a href="https://www.nuget.org/packages/GuiLabs.Language.Xml">GuiLabs.Language.Xml</a> NuGet ID) with the latest code so that you can try it for yourself.</p>Jérémie LavalRoslyn was a revolution in the .NET world when it came out. For the first time we had Microsoft release their compiler implementation of C# under an open-source license. Not only that, the way in which this compiler had been constructed would open the doors to numerous improvements in the ecosystem in the forms of:Computation Expressions in C# using async/await2018-01-11T08:30:21-05:002018-01-11T08:30:21-05:00https://blog.neteril.org/blog/2018/01/11/computation-expressions-csharp-async-await<p>I have had some fun already using C# 7.1 new customizable async/await pipeline to do interesting things:</p>
<ul>
<li><a href="/blog/2017/05/22/activitytask-async-await-android-cornercases/">ActivityTask, an helper for async/await on Android</a></li>
<li><a href="/blog/2017/04/26/maybe-computation-expression-csharp/">Recreating F# maybe computation expression in C#</a></li>
</ul>
<p>In this post I’ll be describing how I took on those past experiences and generalized the core idea of the second entry to provide a somewhat equivalent construct to F# computation expressions in C# by (ab)using the async/await machinery.</p>
<p>If you have never heard of F# computations expressions before I recommend reading the <a href="https://fsharpforfunandprofit.com/posts/computation-expressions-intro/">F# for fun and profit serie</a> on it. Otherwise the TL;DR is that, without the monadic baggage, computation expressions essentially allow you to customize how a series of “statement” are chained together and plug your own logic in-between.</p>
<p>A famous example of such computation expression is the <a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/asynchronous-workflows">async workflow</a> that lead to the creation of C# async/await in the first place (C# async/await being a more specialized/optimized form of its computation expression parent).</p>
<p>In a way what I’m describing in this post is basically how we can manage to return to the original definition of F# computation expressions using the more specialized C# async/await interface that was derived from it.</p>
<p>If you want to jump straight to the code <a href="https://github.com/garuma/Neteril.ComputationExpression">grab it on GitHub</a>. The repository also contains a <a href="https://github.com/garuma/Neteril.ComputationExpression/blob/master/Examples.workbook">Workbook file</a> with a few examples utilizing the API so that you can get a feel of what it allows you to do.</p>
<p>For the others, here is the example given in the repository README of what the API looks like:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Option</span><span class="p"><</span><span class="kt">int</span><span class="p">></span> <span class="nf">TryDivide</span> <span class="p">(</span><span class="kt">int</span> <span class="n">up</span><span class="p">,</span> <span class="kt">int</span> <span class="n">down</span><span class="p">)</span>
<span class="p">=></span> <span class="n">down</span> <span class="p">==</span> <span class="m">0</span> <span class="p">?</span> <span class="n">None</span><span class="p"><</span><span class="kt">int</span><span class="p">>.</span><span class="n">Value</span> <span class="p">:</span> <span class="n">Some</span><span class="p">.</span><span class="nf">Of</span> <span class="p">(</span><span class="n">up</span> <span class="p">/</span> <span class="n">down</span><span class="p">);</span>
<span class="k">class</span> <span class="nc">MaybeBuilder</span> <span class="p">:</span> <span class="n">IMonadExpressionBuilder</span>
<span class="p">{</span>
<span class="n">IMonad</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">IMonadExpressionBuilder</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">U</span><span class="p">,</span> <span class="n">T</span><span class="p">></span> <span class="p">(</span><span class="n">IMonad</span><span class="p"><</span><span class="n">U</span><span class="p">></span> <span class="n">m</span><span class="p">,</span> <span class="n">Func</span><span class="p"><</span><span class="n">U</span><span class="p">,</span> <span class="n">IMonad</span><span class="p"><</span><span class="n">T</span><span class="p">>></span> <span class="n">f</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">switch</span> <span class="p">((</span><span class="n">Option</span><span class="p"><</span><span class="n">U</span><span class="p">>)</span><span class="n">m</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="n">Some</span><span class="p"><</span><span class="n">U</span><span class="p">></span> <span class="n">some</span><span class="p">:</span> <span class="k">return</span> <span class="nf">f</span> <span class="p">(</span><span class="n">some</span><span class="p">.</span><span class="n">Item</span><span class="p">);</span>
<span class="k">case</span> <span class="n">None</span><span class="p"><</span><span class="n">U</span><span class="p">></span> <span class="n">none</span><span class="p">:</span>
<span class="k">default</span><span class="p">:</span> <span class="k">return</span> <span class="n">None</span><span class="p"><</span><span class="n">T</span><span class="p">>.</span><span class="n">Value</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">public</span> <span class="n">IMonad</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">Return</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">(</span><span class="n">T</span> <span class="n">v</span><span class="p">)</span> <span class="p">=></span> <span class="n">Some</span><span class="p">.</span><span class="nf">Of</span> <span class="p">(</span><span class="n">v</span><span class="p">);</span>
<span class="k">public</span> <span class="n">IMonad</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">Zero</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">()</span> <span class="p">=></span> <span class="n">None</span><span class="p"><</span><span class="n">T</span><span class="p">>.</span><span class="n">Value</span><span class="p">;</span>
<span class="c1">// We don't have optional interface methods in C# quite yet</span>
<span class="k">public</span> <span class="n">IMonad</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">Combine</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">(</span><span class="n">IMonad</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">m</span><span class="p">,</span> <span class="n">IMonad</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">n</span><span class="p">)</span> <span class="p">=></span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">NotSupportedException</span> <span class="p">();</span>
<span class="p">}</span>
<span class="c1">// Returns `Some 15`</span>
<span class="n">ComputationExpression</span><span class="p">.</span><span class="n">Run</span><span class="p"><</span><span class="kt">int</span><span class="p">,</span> <span class="n">Option</span><span class="p"><</span><span class="kt">int</span><span class="p">>></span> <span class="p">(</span><span class="k">new</span> <span class="nf">OptionExpressionBuilder</span> <span class="p">(),</span> <span class="k">async</span> <span class="p">()</span> <span class="p">=></span> <span class="p">{</span>
<span class="kt">var</span> <span class="n">val1</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">TryDivide</span> <span class="p">(</span><span class="m">120</span><span class="p">,</span> <span class="m">2</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">val2</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">TryDivide</span> <span class="p">(</span><span class="n">val1</span><span class="p">,</span> <span class="m">2</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">val3</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">TryDivide</span> <span class="p">(</span><span class="n">val2</span><span class="p">,</span> <span class="m">2</span><span class="p">);</span>
<span class="k">return</span> <span class="n">val3</span><span class="p">;</span>
<span class="p">})</span>
<span class="c1">// Returns `None`</span>
<span class="n">ComputationExpression</span><span class="p">.</span><span class="n">Run</span><span class="p"><</span><span class="kt">int</span><span class="p">,</span> <span class="n">Option</span><span class="p"><</span><span class="kt">int</span><span class="p">>></span> <span class="p">(</span><span class="k">new</span> <span class="nf">OptionExpressionBuilder</span> <span class="p">(),</span> <span class="k">async</span> <span class="p">()</span> <span class="p">=></span> <span class="p">{</span>
<span class="kt">var</span> <span class="n">val1</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">TryDivide</span> <span class="p">(</span><span class="m">120</span><span class="p">,</span> <span class="m">2</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">val2</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">TryDivide</span> <span class="p">(</span><span class="n">val1</span><span class="p">,</span> <span class="m">0</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">val3</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">TryDivide</span> <span class="p">(</span><span class="n">val2</span><span class="p">,</span> <span class="m">2</span><span class="p">);</span>
<span class="k">return</span> <span class="n">val3</span><span class="p">;</span>
<span class="p">})</span>
</code></pre></div></div>
<p>In this snippet I’m lifting <a href="/blog/2017/04/26/maybe-computation-expression-csharp/">the example of the Maybe/Option monad</a> I had talked about previously and encoding it via the computation expression mechanism to arrive at the same result. In that case the <code class="highlighter-rouge">await</code> keyword is used to represent the equivalent F# <code class="highlighter-rouge">let!</code> keyword which is a shortand for the <code class="highlighter-rouge">Bind</code> method of the computation expression builder (<code class="highlighter-rouge">Bind</code> is the core monadic operation that allows all those “statements” to be chained together).</p>
<p>To implement a custom computation expression you have to do two things:</p>
<ol>
<li>Define a type that implements the empty <code class="highlighter-rouge">IMonad</code> interface. This simply acts as a marker to be able to use the custom async machinery of the library.</li>
<li>More interestingly, provide an implementation of the <code class="highlighter-rouge">IMonadExpressionBuilder</code> interface which is where you can put the code to customize the execution behavior of the computation expression block.</li>
</ol>
<p>In the example above, the main customization is in the <code class="highlighter-rouge">Bind</code> method where we grab the result of executing the previous statement and then depending on the outcome either pass the result down the chain or short-circuit everything by returning <code class="highlighter-rouge">None</code>.</p>
<p>Another case where C# did a specialized implementation of what in F# is also encoded as a computation expression is <code class="highlighter-rouge">IEnumerable<T></code> state machines via the <code class="highlighter-rouge">yield</code> operator.</p>
<p>With the library we can instead express this using the <code class="highlighter-rouge">Combine</code> method of the builder to achieve something like this (lifted from the examples workbook):</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">static</span> <span class="n">Neteril</span><span class="p">.</span><span class="n">ComputationExpression</span><span class="p">.</span><span class="n">ComputationExpression</span><span class="p">;</span>
<span class="c1">// The Enumerable monad is given in the library</span>
<span class="k">using</span> <span class="nn">Neteril.ComputationExpression.Instances</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="n">ComputationExpression</span><span class="p">.</span><span class="n">Run</span><span class="p"><</span><span class="kt">int</span><span class="p">,</span> <span class="n">EnumerableMonad</span><span class="p"><</span><span class="kt">int</span><span class="p">>></span> <span class="p">(</span><span class="k">new</span> <span class="nf">EnumerableExpressionBuilder</span> <span class="p">(),</span> <span class="k">async</span> <span class="p">()</span> <span class="p">=></span> <span class="p">{</span>
<span class="kt">var</span> <span class="n">item</span> <span class="p">=</span> <span class="k">await</span> <span class="p">(</span><span class="n">EnumerableMonad</span><span class="p"><</span><span class="kt">int</span><span class="p">>)</span><span class="k">new</span> <span class="p">[]</span> <span class="p">{</span> <span class="m">1</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">3</span> <span class="p">};</span>
<span class="kt">var</span> <span class="n">item2</span> <span class="p">=</span> <span class="k">await</span> <span class="p">(</span><span class="n">EnumerableMonad</span><span class="p"><</span><span class="kt">int</span><span class="p">>)</span><span class="k">new</span> <span class="p">[]</span> <span class="p">{</span> <span class="m">100</span><span class="p">,</span> <span class="m">200</span> <span class="p">};</span>
<span class="c1">// We want back a enumeration containing the concatenation of (item, item2, item1 * item2)</span>
<span class="c1">// for all successive values of item1 and item2</span>
<span class="k">await</span> <span class="nf">Yield</span> <span class="p">(</span><span class="n">item</span><span class="p">);</span>
<span class="k">await</span> <span class="nf">Yield</span> <span class="p">(</span><span class="n">item2</span><span class="p">);</span>
<span class="k">return</span> <span class="n">item</span> <span class="p">*</span> <span class="n">item2</span><span class="p">;</span>
<span class="p">});</span>
<span class="kt">string</span><span class="p">.</span><span class="nf">Join</span> <span class="p">(</span><span class="s">", "</span><span class="p">,</span> <span class="n">result</span><span class="p">.</span><span class="nf">Select</span> <span class="p">(</span><span class="n">i</span> <span class="p">=></span> <span class="n">i</span><span class="p">.</span><span class="nf">ToString</span> <span class="p">()));</span>
<span class="c1">// => [ 1, 100, 100, 1, 200, 200, 2, 100, 200, 2, 200, 400, 3, 100, 300, 3, 200, 600 ]</span>
</code></pre></div></div>
<p>In this new sample, the monad is implemented in a way that the first <code class="highlighter-rouge">await</code> (again equivalent to F# <code class="highlighter-rouge">let!</code>) binds to each successive element of the given collections. The result is a <code class="highlighter-rouge">EnumerableMonad<T></code> that is itself a <code class="highlighter-rouge">IEnumerable<T></code> (i.e. you can further use LINQ on it).</p>
<p>Because in this case there is no way to hijack the C# <code class="highlighter-rouge">yield</code> operator directly (like F# would) this is instead represented here with the expression <code class="highlighter-rouge">await Yield</code> for intermediary values and <code class="highlighter-rouge">return</code> for the last one.</p>
<p>Here is the implementation of the builder for the sample to work (note the now implemented <code class="highlighter-rouge">Combine</code> method):</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">EnumerableExpressionBuilder</span> <span class="p">:</span> <span class="n">IMonadExpressionBuilder</span>
<span class="p">{</span>
<span class="n">IMonad</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">IMonadExpressionBuilder</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">U</span><span class="p">,</span> <span class="n">T</span><span class="p">></span> <span class="p">(</span><span class="n">IMonad</span><span class="p"><</span><span class="n">U</span><span class="p">></span> <span class="n">m</span><span class="p">,</span> <span class="n">Func</span><span class="p"><</span><span class="n">U</span><span class="p">,</span> <span class="n">IMonad</span><span class="p"><</span><span class="n">T</span><span class="p">>></span> <span class="n">f</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">previousEnumerableMonad</span> <span class="p">=</span> <span class="p">(</span><span class="n">EnumerableMonad</span><span class="p"><</span><span class="n">U</span><span class="p">>)</span><span class="n">m</span><span class="p">;</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">EnumerableMonad</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">(</span><span class="n">previousEnumerableMonad</span><span class="p">.</span><span class="nf">SelectMany</span> <span class="p">(</span><span class="n">u</span> <span class="p">=></span> <span class="p">(</span><span class="n">EnumerableMonad</span><span class="p"><</span><span class="n">T</span><span class="p">>)</span><span class="nf">f</span> <span class="p">(</span><span class="n">u</span><span class="p">)));</span>
<span class="p">}</span>
<span class="n">IMonad</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">IMonadExpressionBuilder</span><span class="p">.</span><span class="n">Return</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">(</span><span class="n">T</span> <span class="n">v</span><span class="p">)</span> <span class="p">=></span> <span class="k">new</span> <span class="n">EnumerableMonad</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">(</span><span class="n">Enumerable</span><span class="p">.</span><span class="nf">Repeat</span> <span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="m">1</span><span class="p">));</span>
<span class="n">IMonad</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">IMonadExpressionBuilder</span><span class="p">.</span><span class="n">Zero</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">()</span> <span class="p">=></span> <span class="k">new</span> <span class="n">EnumerableMonad</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">(</span><span class="n">Enumerable</span><span class="p">.</span><span class="n">Empty</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">());</span>
<span class="n">IMonad</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">IMonadExpressionBuilder</span><span class="p">.</span><span class="n">Combine</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">(</span><span class="n">IMonad</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">m</span><span class="p">,</span> <span class="n">IMonad</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">n</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">enumerableMonad1</span> <span class="p">=</span> <span class="p">(</span><span class="n">EnumerableMonad</span><span class="p"><</span><span class="n">T</span><span class="p">>)</span><span class="n">m</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">enumerableMonad2</span> <span class="p">=</span> <span class="p">(</span><span class="n">EnumerableMonad</span><span class="p"><</span><span class="n">T</span><span class="p">>)</span><span class="n">n</span><span class="p">;</span>
<span class="c1">// Simply use LINQ Concat method</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">EnumerableMonad</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">(</span><span class="n">enumerableMonad1</span><span class="p">.</span><span class="nf">Concat</span> <span class="p">(</span><span class="n">enumerableMonad2</span><span class="p">));</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Interestingly of the early writings I remember reading about Monads and how it related to C#, the LINQ <code class="highlighter-rouge">SelectMany</code> operator was given as an example of a <code class="highlighter-rouge">Bind</code> operation in the monadic sense. With this we have the proof it’s indeed true.</p>
<p>The actual code enabling all of this is a fairly straightforward <a href="https://github.com/garuma/Neteril.ComputationExpression/blob/master/Neteril.ComputationExpression/MonadAsyncMethodBuilder.cs">async method builder implementation</a>. If you have read any of my previous articles I mentioned at the beginning of this post, it’s essentially doing the same thing with a bunch more hacks to cope with the added indirection of generic types in the <code class="highlighter-rouge">IMonad<T></code> interface.</p>
<p>It also peeks a bit deeper into the internal structure of the async state machine generated by the compiler via the <a href="https://github.com/garuma/Neteril.ComputationExpression/blob/master/Neteril.ComputationExpression/Machinist.cs"><code class="highlighter-rouge">Machinist</code> class</a> so that it can control the actual stepping and awaiter values that are stored in it. This for instance allows the same state machine to be “rewinded” which is essential to support cases like the above Enumerable sample.</p>Jérémie LavalI have had some fun already using C# 7.1 new customizable async/await pipeline to do interesting things:ActivityTask, an helper for async/await on Android2017-05-22T09:30:21-04:002017-05-22T09:30:21-04:00https://blog.neteril.org/blog/2017/05/22/activitytask-async-await-android-cornercases<p>While at I/O last week, we happened to attend the <a href="https://events.google.com/io/schedule/?section=may-18&sid=006961f0-030f-4dca-8277-a479083c208d">Architecture Component talk on Android lifecycle</a> (which I recommend you watch). While the solutions presented there are definitely interesting and, in some cases, map to patterns we already have in .NET, it definitely resonated with us present on how those Android lifecycle nitpicks make one specific C# feature more cumbersome to use: async/await.</p>
<p>With async/await, the two main nitpicks that are pertaining to Android developers are:</p>
<ul>
<li>Because of Android resource system works, a change of configuration (e.g. screen rotation) will recreate <code class="highlighter-rouge">Activity</code> instances by default</li>
<li>Because <code class="highlighter-rouge">await</code> is oblivious to an <code class="highlighter-rouge">Activity</code> lifecycle, it may execute continuations while in an undesired state causing an <code class="highlighter-rouge">IllegateStateException</code></li>
</ul>
<p>Note that we already introduced something that partially address those qualms in the form of the <a href="https://forums.xamarin.com/discussion/84221/announcing-android-activity-controller-preview">ActivityController</a> with the added bonus of providing convenient asynchronous wrapper methods for <code class="highlighter-rouge">StartActivityForResult</code>-based workflows.</p>
<p>In this case, based on some <a href="/blog/2017/04/26/maybe-computation-expression-csharp/">other fun I had previously</a>, I figured there was potentially a way to leverage C# 7 new customizable async state machines drivers to achieve something that could help mitigate those two issues without requiring too much changes in your code.</p>
<p>Enter <a href="https://github.com/garuma/LibActivityTask">ActivityTask</a> (also on <a href="https://www.nuget.org/packages/Neteril.ActivityTask">NuGet</a>).</p>
<p>This little library has two main primitives:</p>
<ul>
<li><code class="highlighter-rouge">ActivityScope</code> allows to track the most recent instance of one of your Activity subclass so that potential underlying re-creations are transparent to you</li>
<li><code class="highlighter-rouge">ActivityTask</code> acts as a standard <code class="highlighter-rouge">Task</code> return value in an async method but customize the state machine driver (in cooperation with <code class="highlighter-rouge">ActivityScope</code>) to make continuation scheduling aware of the activity lifecycle.</li>
</ul>
<p>Under the hood, <code class="highlighter-rouge">ActivityScope</code> simply registers a listener at the <code class="highlighter-rouge">Application</code> level to listen to global activity lifecycle events. When it detects the activity it’s tracking is about to die, it will mark it so that when it’s respawned it can re-associate with it. Because it implements an implicit conversion operator to <code class="highlighter-rouge">Activity</code>, you can pass the scope wherever an activity instance is needed to ensure you always use a valid value.</p>
<p>As for <code class="highlighter-rouge">ActivityTask</code> the implementation is pretty boring (it pretty much defers to a <code class="highlighter-rouge">TaskCompletionSource</code>), the interesting portion is with <code class="highlighter-rouge">ActivityScopeMethodBuilder</code> that drives the async state machine. For all intent and purpose, it will behave like the default driver for <code class="highlighter-rouge">Task</code>. However, thanks to the extra <code class="highlighter-rouge">ActivityScope</code> method argument, it will additionally make sure that any continuation is only executed when the activity tracked by the scope is in a usable state at that moment. If not, it will simply keep the continuation queued up until the tracked activity is resumed.</p>
<p>To see how all of this fits together, here is the code for the activity of the test app in the GitHub repository:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">[Activity(Label = "ActivityTaskTest", MainLauncher = true, Icon = "@mipmap/icon")]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">MainActivity</span> <span class="p">:</span> <span class="n">Activity</span>
<span class="p">{</span>
<span class="k">static</span> <span class="kt">bool</span> <span class="n">launched</span> <span class="p">=</span> <span class="k">false</span><span class="p">;</span>
<span class="k">protected</span> <span class="k">override</span> <span class="k">async</span> <span class="k">void</span> <span class="nf">OnCreate</span><span class="p">(</span><span class="n">Bundle</span> <span class="n">savedInstanceState</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">base</span><span class="p">.</span><span class="nf">OnCreate</span><span class="p">(</span><span class="n">savedInstanceState</span><span class="p">);</span>
<span class="c1">// Set our view from the "main" layout resource</span>
<span class="nf">SetContentView</span><span class="p">(</span><span class="n">Resource</span><span class="p">.</span><span class="n">Layout</span><span class="p">.</span><span class="n">Main</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(!</span><span class="n">launched</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">launched</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
<span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">scope</span> <span class="p">=</span> <span class="n">ActivityScope</span><span class="p">.</span><span class="nf">Of</span><span class="p">(</span><span class="k">this</span><span class="p">))</span>
<span class="k">await</span> <span class="nf">DoAsyncStuff</span><span class="p">(</span><span class="n">scope</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="n">TextView</span> <span class="nf">MyLabel</span><span class="p">(</span><span class="n">Activity</span> <span class="n">activity</span><span class="p">)</span> <span class="p">=></span> <span class="n">activity</span><span class="p">.</span><span class="n">FindViewById</span><span class="p"><</span><span class="n">TextView</span><span class="p">>(</span><span class="n">Resource</span><span class="p">.</span><span class="n">Id</span><span class="p">.</span><span class="n">myLabel</span><span class="p">);</span>
<span class="k">async</span> <span class="n">ActivityTask</span> <span class="nf">DoAsyncStuff</span><span class="p">(</span><span class="n">ActivityScope</span> <span class="n">scope</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">await</span> <span class="n">Task</span><span class="p">.</span><span class="nf">Delay</span><span class="p">(</span><span class="m">3000</span><span class="p">);</span> <span class="c1">// Medium network call</span>
<span class="nf">MyLabel</span><span class="p">(</span><span class="n">scope</span><span class="p">).</span><span class="n">Text</span> <span class="p">=</span> <span class="s">"Step 1"</span><span class="p">;</span>
<span class="k">await</span> <span class="n">Task</span><span class="p">.</span><span class="nf">Delay</span><span class="p">(</span><span class="m">5000</span><span class="p">);</span> <span class="c1">// Big network call</span>
<span class="nf">MyLabel</span><span class="p">(</span><span class="n">scope</span><span class="p">).</span><span class="n">Text</span> <span class="p">=</span> <span class="s">"Step 2"</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This example simulates launching a series of asynchronous operations the very first time an activity is created. Beforehand though, it creates an <code class="highlighter-rouge">ActivityScope</code> to track the lifetime of the current activity and pass it down. Between each asynchronous substep, the activity instance is used to fetch the label onscreen and update its text.</p>
<p>The idea is to trigger a damaging event during one of those <code class="highlighter-rouge">Task.Delay</code> calls. Some that you can test are rotating your device (thus killing and re-creating the activity) or pressing the home button to pause the activity and reopen it after the delay expired.</p>
<p>For instance, if rotating the screen after “Step 1” is shown, you should see the original text of the label briefly re-appears (because the layout was inflated from scratch) and soon after see “Step 2” be set meaning the async method used the correct new activity instance to locate the label.</p>
<p>If pausing the activity after “Step 1” is shown, resuming the activity after the second delay expires should result in “Step 2” being displayed immediately as the callback got executed during the resume process instead of running while the activity was in the background.</p>Jérémie LavalWhile at I/O last week, we happened to attend the Architecture Component talk on Android lifecycle (which I recommend you watch). While the solutions presented there are definitely interesting and, in some cases, map to patterns we already have in .NET, it definitely resonated with us present on how those Android lifecycle nitpicks make one specific C# feature more cumbersome to use: async/await.Recreating F# maybe computation expression in C#2017-04-26T13:00:21-04:002017-04-26T13:00:21-04:00https://blog.neteril.org/blog/2017/04/26/maybe-computation-expression-csharp<p>For the past few nights I have been reading up on F# from <a href="https://fsharpforfunandprofit.com">fsharpforfunandprofit.com</a> specifically on things like monads, bind functions and the language support for them, <a href="https://fsharpforfunandprofit.com/series/computation-expressions.html">computation expressions</a> (which I encourage you to read to help understand what’s going on here).</p>
<p>Computation expressions are a nice syntactic sugar provided by the language to easily be able to chain up continuations together using a imperative looking meta-language that gets translated to pre-defined function calls.</p>
<p>One of such computation expression is <code class="highlighter-rouge">maybe</code> which allows to specify a serie of operation that can potentially individually fail and, if so, short-circuit the rest of the computation automatically (without having to throw an exception or return early with a bunch of <code class="highlighter-rouge">if</code> statements)</p>
<p>As an example of what a <code class="highlighter-rouge">maybe</code> workflow (shamelessly borrowed from the website) looks like, given the following <code class="highlighter-rouge">divideBy</code> function that leverage the <code class="highlighter-rouge">Option<T></code> type to model divide-by-zero errors:</p>
<div class="language-fsharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">divideBy</span> <span class="n">bottom</span> <span class="n">top</span> <span class="p">=</span>
<span class="k">if</span> <span class="n">bottom</span> <span class="p">=</span> <span class="mi">0</span>
<span class="k">then</span> <span class="nc">None</span>
<span class="k">else</span> <span class="nc">Some</span><span class="p">(</span><span class="n">top</span><span class="o">/</span><span class="n">bottom</span><span class="p">)</span>
</code></pre></div></div>
<p>You could do a manual series of bind expressions like the following in F#:</p>
<div class="language-fsharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nc">Bind</span> <span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">f</span><span class="p">)</span> <span class="p">=</span> <span class="nn">Option</span><span class="p">.</span><span class="n">bind</span> <span class="n">f</span> <span class="n">m</span>
<span class="k">let</span> <span class="nc">Return</span> <span class="n">x</span> <span class="p">=</span> <span class="nc">Some</span> <span class="n">x</span>
<span class="k">let</span> <span class="n">divideByWorkflow</span> <span class="n">x</span> <span class="n">y</span> <span class="n">w</span> <span class="n">z</span> <span class="p">=</span>
<span class="nc">Bind</span> <span class="p">(</span><span class="n">x</span> <span class="p">|></span> <span class="n">divideBy</span> <span class="n">y</span> <span class="n">x</span><span class="p">,</span> <span class="k">fun</span> <span class="n">a</span> <span class="p">-></span>
<span class="nc">Bind</span> <span class="p">(</span><span class="n">a</span> <span class="p">|></span> <span class="n">divideBy</span> <span class="n">w</span> <span class="n">a</span><span class="p">,</span> <span class="k">fun</span> <span class="n">b</span> <span class="p">-></span>
<span class="nc">Bind</span> <span class="p">(</span><span class="n">b</span> <span class="p">|></span> <span class="n">divideBy</span> <span class="n">z</span> <span class="n">b</span><span class="p">,</span> <span class="k">fun</span> <span class="n">c</span> <span class="p">-></span>
<span class="nc">Return</span> <span class="n">c</span>
<span class="o">)))</span>
</code></pre></div></div>
<p>Or instead defines the <code class="highlighter-rouge">Bind</code> and <code class="highlighter-rouge">Return</code> as member methods of a type and use it to create the <code class="highlighter-rouge">maybe</code> computation expression like this:</p>
<div class="language-fsharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="nc">MaybeBuilder</span><span class="bp">()</span> <span class="p">=</span>
<span class="k">member</span> <span class="n">this</span><span class="p">.</span><span class="nc">Bind</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="n">f</span><span class="p">)</span> <span class="p">=</span> <span class="nn">Option</span><span class="p">.</span><span class="n">bind</span> <span class="n">f</span> <span class="n">m</span>
<span class="k">member</span> <span class="n">this</span><span class="p">.</span><span class="nc">Return</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="p">=</span> <span class="nc">Some</span> <span class="n">x</span>
<span class="k">let</span> <span class="n">maybe</span> <span class="p">=</span> <span class="k">new</span> <span class="nc">MaybeBuilder</span><span class="bp">()</span>
<span class="k">let</span> <span class="n">divideByWorkflow</span> <span class="n">x</span> <span class="n">y</span> <span class="n">w</span> <span class="n">z</span> <span class="p">=</span>
<span class="n">maybe</span> <span class="p">{</span>
<span class="k">let</span><span class="o">!</span> <span class="n">a</span> <span class="p">=</span> <span class="n">x</span> <span class="p">|></span> <span class="n">divideBy</span> <span class="n">y</span>
<span class="k">let</span><span class="o">!</span> <span class="n">b</span> <span class="p">=</span> <span class="n">a</span> <span class="p">|></span> <span class="n">divideBy</span> <span class="n">w</span>
<span class="k">let</span><span class="o">!</span> <span class="n">c</span> <span class="p">=</span> <span class="n">b</span> <span class="p">|></span> <span class="n">divideBy</span> <span class="n">z</span>
<span class="k">return</span> <span class="n">c</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The two forms are equivalent, the second one just being more imperative looking and nicer to read.</p>
<p>Computation expressions are pretty powerful and can be used to express all sorts of things in F#. One of the most popular is the <code class="highlighter-rouge">async</code> computation expression that lead to the creation of <code class="highlighter-rouge">async</code>/<code class="highlighter-rouge">await</code> in C# as a specialized form of it.</p>
<p>Although <code class="highlighter-rouge">async</code>/<code class="highlighter-rouge">await</code> is definitely geared towards asynchronous programming, the fundamental idea it shares with computation expression is the same: convert a stream of “statements” into a serie of chained up continuations. The difference being that C# does so using a state machine versus F# use of a more generic function paradigm.</p>
<p>With the advent of <a href="https://github.com/dotnet/roslyn/blob/master/docs/features/task-types.md">generalized async task types</a> in C# 7 (and its main user, <a href="https://github.com/dotnet/corefx/issues/4708">ValueTask</a>), we now have much more flexibility in tuning the async/await pipeline than ever before when it was hardcoded to use <code class="highlighter-rouge">Task<T></code>.</p>
<p>Knowing this, the more I thought about that <code class="highlighter-rouge">maybe</code> computation expression the more I figured it should now be possible to implement something very similar in C# by re-purposing the async/await machinery.</p>
<p>Without further ado, here it is:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Add the System.Threading.Tasks.Extensions NuGet to get AsyncMethodBuilderAttribute</span>
<span class="na">[AsyncMethodBuilder (typeof (MaybeAsyncMethodBuilder<>))]</span>
<span class="k">interface</span> <span class="nc">Option</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">{</span> <span class="p">}</span>
<span class="c1">// Could use the closed type hierarchy Roslyn feature</span>
<span class="c1">// to be an approximation of a discriminated union</span>
<span class="c1">// https://github.com/dotnet/csharplang/issues/485</span>
<span class="k">sealed</span> <span class="k">class</span> <span class="nc">None</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">:</span> <span class="n">Option</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">{</span> <span class="k">public</span> <span class="k">static</span> <span class="k">readonly</span> <span class="n">None</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">Value</span> <span class="p">=</span> <span class="k">new</span> <span class="n">None</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">();</span> <span class="p">}</span>
<span class="k">sealed</span> <span class="k">class</span> <span class="nc">Some</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">:</span> <span class="n">Option</span><span class="p"><</span><span class="n">T</span><span class="p">></span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">readonly</span> <span class="n">T</span> <span class="n">Item</span><span class="p">;</span>
<span class="k">public</span> <span class="nf">Some</span> <span class="p">(</span><span class="n">T</span> <span class="n">item</span><span class="p">)</span> <span class="p">=></span> <span class="n">Item</span> <span class="p">=</span> <span class="n">item</span><span class="p">;</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">explicit</span> <span class="k">operator</span> <span class="nf">T</span> <span class="p">(</span><span class="n">Some</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">maybe</span><span class="p">)</span> <span class="p">=></span> <span class="n">maybe</span><span class="p">.</span><span class="n">Item</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">static</span> <span class="k">class</span> <span class="nc">Some</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">static</span> <span class="n">Some</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">Of</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">(</span><span class="n">T</span> <span class="k">value</span><span class="p">)</span> <span class="p">=></span> <span class="k">new</span> <span class="n">Some</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">(</span><span class="k">value</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">class</span> <span class="nc">MaybeAsyncMethodBuilder</span><span class="p"><</span><span class="n">T</span><span class="p">></span>
<span class="p">{</span>
<span class="n">Option</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">result</span> <span class="p">=</span> <span class="n">None</span><span class="p"><</span><span class="n">T</span><span class="p">>.</span><span class="n">Value</span><span class="p">;</span>
<span class="k">public</span> <span class="k">static</span> <span class="n">MaybeAsyncMethodBuilder</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="nf">Create</span> <span class="p">()</span> <span class="p">=></span> <span class="k">new</span> <span class="n">MaybeAsyncMethodBuilder</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">();</span>
<span class="k">public</span> <span class="k">void</span> <span class="n">Start</span><span class="p"><</span><span class="n">TStateMachine</span><span class="p">></span> <span class="p">(</span><span class="k">ref</span> <span class="n">TStateMachine</span> <span class="n">stateMachine</span><span class="p">)</span> <span class="k">where</span> <span class="n">TStateMachine</span> <span class="p">:</span> <span class="n">IAsyncStateMachine</span>
<span class="p">{</span>
<span class="c1">// Simply start the state machine which will execute our code</span>
<span class="n">stateMachine</span><span class="p">.</span><span class="nf">MoveNext</span> <span class="p">();</span>
<span class="p">}</span>
<span class="k">public</span> <span class="n">Option</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">Task</span> <span class="p">=></span> <span class="n">result</span><span class="p">;</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">SetResult</span> <span class="p">(</span><span class="n">T</span> <span class="n">result</span><span class="p">)</span> <span class="p">=></span> <span class="k">this</span><span class="p">.</span><span class="n">result</span> <span class="p">=</span> <span class="n">Some</span><span class="p">.</span><span class="nf">Of</span> <span class="p">(</span><span class="n">result</span><span class="p">);</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">SetException</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span> <span class="p">{</span> <span class="cm">/* We leave the result to None */</span> <span class="p">}</span>
<span class="c1">// Unused methods</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">SetStateMachine</span> <span class="p">(</span><span class="n">IAsyncStateMachine</span> <span class="n">stateMachine</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="k">public</span> <span class="k">void</span> <span class="n">AwaitOnCompleted</span><span class="p"><</span><span class="n">TAwaiter</span><span class="p">,</span> <span class="n">TStateMachine</span><span class="p">></span> <span class="p">(</span><span class="k">ref</span> <span class="n">TAwaiter</span> <span class="n">awaiter</span><span class="p">,</span> <span class="k">ref</span> <span class="n">TStateMachine</span> <span class="n">stateMachine</span><span class="p">)</span>
<span class="k">where</span> <span class="n">TAwaiter</span> <span class="p">:</span> <span class="n">INotifyCompletion</span>
<span class="k">where</span> <span class="n">TStateMachine</span> <span class="p">:</span> <span class="n">IAsyncStateMachine</span>
<span class="p">{</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">void</span> <span class="n">AwaitUnsafeOnCompleted</span><span class="p"><</span><span class="n">TAwaiter</span><span class="p">,</span> <span class="n">TStateMachine</span><span class="p">></span> <span class="p">(</span><span class="k">ref</span> <span class="n">TAwaiter</span> <span class="n">awaiter</span><span class="p">,</span> <span class="k">ref</span> <span class="n">TStateMachine</span> <span class="n">stateMachine</span><span class="p">)</span>
<span class="k">where</span> <span class="n">TAwaiter</span> <span class="p">:</span> <span class="n">ICriticalNotifyCompletion</span>
<span class="k">where</span> <span class="n">TStateMachine</span> <span class="p">:</span> <span class="n">IAsyncStateMachine</span>
<span class="p">{</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">class</span> <span class="nc">MaybeAwaiter</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">:</span> <span class="n">INotifyCompletion</span>
<span class="p">{</span>
<span class="n">Option</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">maybe</span><span class="p">;</span>
<span class="k">public</span> <span class="nf">MaybeAwaiter</span> <span class="p">(</span><span class="n">Option</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">maybe</span><span class="p">)</span> <span class="p">=></span> <span class="k">this</span><span class="p">.</span><span class="n">maybe</span> <span class="p">=</span> <span class="n">maybe</span><span class="p">;</span>
<span class="k">public</span> <span class="kt">bool</span> <span class="n">IsCompleted</span> <span class="p">=></span> <span class="n">maybe</span> <span class="k">is</span> <span class="n">Some</span><span class="p"><</span><span class="n">T</span><span class="p">>;</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">OnCompleted</span> <span class="p">(</span><span class="n">Action</span> <span class="n">continuation</span><span class="p">)</span>
<span class="p">{</span>
<span class="cm">/* We never need to execute the continuation cause
* we only reach here when the result is None which
* means we are trying to short-circuit everything
* else
*/</span>
<span class="p">}</span>
<span class="k">public</span> <span class="n">T</span> <span class="nf">GetResult</span> <span class="p">()</span> <span class="p">=></span> <span class="p">((</span><span class="n">Some</span><span class="p"><</span><span class="n">T</span><span class="p">>)</span><span class="n">maybe</span><span class="p">).</span><span class="n">Item</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">static</span> <span class="k">class</span> <span class="nc">OptionExtensions</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">static</span> <span class="n">MaybeAwaiter</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">GetAwaiter</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">(</span><span class="k">this</span> <span class="n">Option</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">maybe</span><span class="p">)</span> <span class="p">=></span> <span class="k">new</span> <span class="n">MaybeAwaiter</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">(</span><span class="n">maybe</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The top part of the code re-implements a form of <code class="highlighter-rouge">Option<T></code> type and some helpers (nothing new here). The two more interesting things that pertains to async/await are the corresponding <code class="highlighter-rouge">MaybeAwaiter</code> and <code class="highlighter-rouge">MaybeAsyncMethodBuilder</code> types that allow us to plug into that pipeline.</p>
<p>The trick is to reuse an optimization baked into the <code class="highlighter-rouge">async</code>/<code class="highlighter-rouge">await</code> state machine where if the awaiter has its <code class="highlighter-rouge">IsCompleted</code> property equal to true after it’s created, the rest of the computation is immediately executed. If that’s not the case, the same computation remainder is (theorically) transformed into a continuation and fed into <code class="highlighter-rouge">OnCompleted</code>.</p>
<p>In our case, we use that fact to propagate successful <code class="highlighter-rouge">Some</code>-producing operation immediately and stop as soon as the first <code class="highlighter-rouge">None</code> is returned by never executing the continuation that’s passed to <code class="highlighter-rouge">OnCompleted</code>.</p>
<p>If our computation expression successfully and eagerly executes until the end, the <code class="highlighter-rouge">SetResult</code> method of the <code class="highlighter-rouge">MaybeAsyncMethodBuilder</code> type will be called thus setting the final result in a nicely wrapped <code class="highlighter-rouge">Some</code>. Otherwise the default <code class="highlighter-rouge">None</code> will be returned by the <code class="highlighter-rouge">Task</code> property.</p>
<p>Roughly speaking in this example, the <code class="highlighter-rouge">Bind</code> of F# is here implemented by <code class="highlighter-rouge">MaybeAwaiter</code> while <code class="highlighter-rouge">MaybeAsyncMethodBuilder</code> is the equivalent of <code class="highlighter-rouge">Return</code>.</p>
<p>Armed with this toolkit, here is how you would be able to code the same F# division workflow in C# using <code class="highlighter-rouge">async</code>/<code class="highlighter-rouge">await</code>:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Main</span> <span class="p">(</span><span class="kt">string</span> <span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">resultGood</span> <span class="p">=</span> <span class="nf">TestMaybeGood</span> <span class="p">();</span>
<span class="nf">PrintResult</span> <span class="p">(</span><span class="n">resultGood</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">resultBad</span> <span class="p">=</span> <span class="nf">TestMaybeBad</span> <span class="p">();</span>
<span class="nf">PrintResult</span> <span class="p">(</span><span class="n">resultBad</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">static</span> <span class="k">async</span> <span class="n">Option</span><span class="p"><</span><span class="kt">int</span><span class="p">></span> <span class="nf">TestMaybeGood</span> <span class="p">()</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">val1</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">TryDivide</span> <span class="p">(</span><span class="m">120</span><span class="p">,</span> <span class="m">2</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">val2</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">TryDivide</span> <span class="p">(</span><span class="n">val1</span><span class="p">,</span> <span class="m">2</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">val3</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">TryDivide</span> <span class="p">(</span><span class="n">val2</span><span class="p">,</span> <span class="m">2</span><span class="p">);</span>
<span class="k">return</span> <span class="n">val3</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">static</span> <span class="k">async</span> <span class="n">Option</span><span class="p"><</span><span class="kt">int</span><span class="p">></span> <span class="nf">TestMaybeBad</span> <span class="p">()</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">val1</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">TryDivide</span> <span class="p">(</span><span class="m">120</span><span class="p">,</span> <span class="m">2</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">val2</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">TryDivide</span> <span class="p">(</span><span class="n">val1</span><span class="p">,</span> <span class="m">0</span><span class="p">);</span> <span class="c1">// Should stop execution there</span>
<span class="kt">var</span> <span class="n">val3</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">TryDivide</span> <span class="p">(</span><span class="n">val2</span><span class="p">,</span> <span class="m">2</span><span class="p">);</span>
<span class="k">return</span> <span class="n">val3</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">static</span> <span class="n">Option</span><span class="p"><</span><span class="kt">int</span><span class="p">></span> <span class="nf">TryDivide</span> <span class="p">(</span><span class="kt">int</span> <span class="n">top</span><span class="p">,</span> <span class="kt">int</span> <span class="n">bottom</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span> <span class="p">(</span><span class="s">$"Trying to execute division </span><span class="p">{</span><span class="n">top</span><span class="p">}</span><span class="s">/</span><span class="p">{</span><span class="n">bottom</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">bottom</span> <span class="p">==</span> <span class="m">0</span><span class="p">)</span>
<span class="k">return</span> <span class="n">None</span><span class="p"><</span><span class="kt">int</span><span class="p">>.</span><span class="n">Value</span><span class="p">;</span>
<span class="k">return</span> <span class="n">Some</span><span class="p">.</span><span class="nf">Of</span> <span class="p">(</span><span class="n">top</span> <span class="p">/</span> <span class="n">bottom</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">static</span> <span class="k">void</span> <span class="n">PrintResult</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="p">(</span><span class="n">Option</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">maybe</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">switch</span> <span class="p">(</span><span class="n">maybe</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="n">None</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">n</span><span class="p">:</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span> <span class="p">(</span><span class="s">"None"</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="n">Some</span><span class="p"><</span><span class="n">T</span><span class="p">></span> <span class="n">s</span><span class="p">:</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span> <span class="p">(</span><span class="s">$"Some </span><span class="p">{(</span><span class="n">T</span><span class="p">)</span><span class="n">s</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In the above code, <code class="highlighter-rouge">await</code> has absolutely nothing to do with asynchronous programming but is instead closer to the F# <code class="highlighter-rouge">let!</code> syntax which unwraps the value of a successful computation and names it for the next phase (basically <code class="highlighter-rouge">var val1 = await TryDivide (120, 2);</code> ⬄ <code class="highlighter-rouge">let! val1 = tryDivide 120 2</code>).</p>
<p>Executing the snippet gives the following output (if you want to play with this code using Mono you will have to use a recent version to have the Roslyn-based C# compiler):</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>% mono --debug MaybeComputationExpression.exe
Trying to execute division 120/2
Trying to execute division 60/2
Trying to execute division 30/2
Some 15
Trying to execute division 120/2
Trying to execute division 60/0
None
</code></pre></div></div>
<p>As you can see, in the first case all three divisions execute properly and we get back the result wrapped in a <code class="highlighter-rouge">Some<int></code> while in the second case, as soon as the error case is detected (at the second statement) the rest of the computation is pre-empted and <code class="highlighter-rouge">None</code> is returned instead.</p>Jérémie LavalFor the past few nights I have been reading up on F# from fsharpforfunandprofit.com specifically on things like monads, bind functions and the language support for them, computation expressions (which I encourage you to read to help understand what’s going on here).Diverting functions in Windows with IAT patching2016-12-23T05:00:21-05:002016-12-23T05:00:21-05:00https://blog.neteril.org/blog/2016/12/23/diverting-functions-windows-iat-patching<p>Recently I was stuck with a blocking issue that was putting a feature I worked on in jeopardy. To summarize the problem, the entire feature relied on a specific way a library is initialized, the library in question providing two different functions (that we will call <code class="highlighter-rouge">Init</code> and <code class="highlighter-rouge">InitExtended</code>) to initialize itself.</p>
<p>The code responsible for this initialization hardcodes calling one of the variant and is in a DLL that is not modifiable. To make things harder, the two initialization functions I mentioned have slightly different parameters which complicated things as it can’t be a simple function pointer swap.</p>
<p>For exploitation purposes, an important aspect is that the initialization function is not actually referenced directly in the DLL but instead it is located dynamically using the standard <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms684175.aspx">LoadLibrary</a>/<a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms683212.aspx">GetProcAddress</a> combo.</p>
<p>When something is using <code class="highlighter-rouge">LoadLibrary</code>, the obvious thing to try first is to take advantage of the DLL loader lookup mechanism and provide a modified DLL that can be loaded instead of the original one. In this case though, <code class="highlighter-rouge">LoadLibrary</code> was used with a hardcoded path in a system directory which made this option impossible.</p>
<p>Which leaves trying to use <code class="highlighter-rouge">GetProcAddress</code> to masquerade things up. To do this there is a more exotic technique called IAT patching that relies on the way the PE (Portable Executable) format work for dynamic libraries.</p>
<h2 id="whats-in-a-dll">What’s in a DLL</h2>
<p>Like most other dynamically loadable libraries format, a DLL contains more than just the code that’s executed. The file is split between different sections that references several other type of data in addition to the code section.</p>
<p><img src="/wp-content/uploads/iat_patching/pe_format.png" alt="PE format diagram" /></p>
<p>For instance the data section will contain a bunch of interesting tables, things like strings literals, the constant data in the program, thread local storage and so on.</p>
<p>When a DLL is loaded, those tables and sections are mapped into the calling process memory space and are accessible from user code although in practice you will always be using some system API instead of querying those parts of the memory yourself.</p>
<h2 id="the-import-table">The Import Table</h2>
<p>The table we are going to be interested in here is the <strong>Import Address Table</strong> (abbreviated IAT). The role of this table is to list all the external functions a DLL references from other libraries in a dictionary form keyed by library name (e.g. “user32.dll”) and values as function pointer thunks.</p>
<p>For instance, here is a snippet of the content of this table from a random DLL (the hint/ordinal values are used by the loader for faster processing):</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span> pedump <span class="nt">-I</span> freetype.dll
<span class="go">
=== IMPORTS ===
MODULE_NAME HINT ORD FUNCTION_NAME
KERNEL32.dll 1cb GetCurrentThreadId
KERNEL32.dll 15b FlsSetValue
KERNEL32.dll 18c GetCommandLineA
KERNEL32.dll 425 RtlUnwindEx
KERNEL32.dll 2d3 HeapAlloc
KERNEL32.dll 208 GetLastError
KERNEL32.dll 2da HeapReAlloc
KERNEL32.dll 2d7 HeapFree
KERNEL32.dll ee EncodePointer
KERNEL32.dll 15a FlsGetValue
KERNEL32.dll 159 FlsFree
KERNEL32.dll 480 SetLastError
KERNEL32.dll 158 FlsAlloc
KERNEL32.dll 4c0 Sleep
</span></code></pre></div></div>
<p>In our case, both of <code class="highlighter-rouge">LoadLibrary</code> and <code class="highlighter-rouge">GetProcAddress</code> would be in this table keyed under the library they come from aka <strong>kernel32.dll</strong>.</p>
<p>The reason for this table is explained by the way dynamic libraries and the Windows DLL loader works. When compiling code to a DLL that depends on some other libraries, the actual memory layout where the dependencies are going to be loaded is not known in advance. Maybe that dependency has already been loaded by the program, maybe the DLL will be the one to load it, in any case the real locations for all those functions will ultimately be determined by the running context.</p>
<p>Thus, when some code references an external function, what the compiler will do is insert a <code class="highlighter-rouge">call</code> instruction that is not pointing directly to the real address of the function but instead will load the address pointed to by the thunk I mentioned earlier from the Import Address Table.</p>
<p>By doing so, the code contained inside the DLL is always valid and the Windows loader simply has to modify one piece of the overall loaded DLL (the IAT thunk) to point to the right function address at runtime instead of going throughout the entire code section and patch one-by-one every <code class="highlighter-rouge">call</code> instructions.</p>
<p>Below is an example of how the same DLL we saw earlier is calling the <code class="highlighter-rouge">GetCommandLineA</code> Win32 function contained in kernel32. Notice how the address for the call instruction is retrieved (<code class="highlighter-rouge">qword</code>) from a location in the data segment (<code class="highlighter-rouge">ds</code>) and how the disassembler is smart enough to name the thunk with a <code class="highlighter-rouge">imp_</code> prefix:</p>
<p><img src="/wp-content/uploads/iat_patching/hopper-call.png" alt="Indirect IAT calling" /></p>
<p>And here is a view of the actual array containing all the thunks for kernel32 functions that will be patched by the Windows loader when the DLL is processed at run-time:</p>
<p><img src="/wp-content/uploads/iat_patching/hopper-datasegment.png" alt="IAT thunks" /></p>
<h2 id="patching-the-import-address-table">Patching the Import Address Table</h2>
<p><em>Reminder:</em> we are trying to influence a program execution by manipulating <code class="highlighter-rouge">GetProcAddress</code> so that instead of calling an <code class="highlighter-rouge">Init</code> function it calls a different <code class="highlighter-rouge">InitExtended</code> function.</p>
<p>Now that we know how external functions are called it’s easy to see that taking control of this IAT indirection is the key to do what we want. By patching the IAT thunk for the function we want to modify, we ensure the relevant code will be redirected to use our modifications.</p>
<p>Provided you have already the ability to load custom code in the process via another mean (if not lookup DLL injection techniques), the recipe to hijack a IAT thunk is as follow:</p>
<ul>
<li>Create your custom function in your own code that mimics the prototype of the real one</li>
<li>Prevent or delay the codepath you are trying to change from accessing the function before your patching is done</li>
<li>Retrieve a pointer to the module (containing all the tables) of the DLL/executable that you are trying to hijack</li>
<li>Locate the Import Address Table</li>
<li>Iterate over it to find the right thunk</li>
<li>Overwrite the value given by the DLL loader with your own custom function address</li>
</ul>
<p>Below is the translated and annotated version of this recipe in C using the imagehlp library (that defines all the right C structs to modelize the IAT table layout):</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Our custom Init function that will now internally</span>
<span class="c1">// call the InitExtended function we wanted to use</span>
<span class="k">static</span> <span class="kt">void</span> <span class="nf">MyCustomInitFunction</span> <span class="p">(</span><span class="cm">/* parameters */</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">InitExtended</span> <span class="p">(</span><span class="cm">/* other parameters */</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// Our hooked version of GetProcAddress with the</span>
<span class="c1">// same prototype (and same calling convention)</span>
<span class="k">static</span> <span class="n">FARPROC</span> <span class="nf">MyGetProcAddress</span> <span class="p">(</span><span class="n">HMODULE</span> <span class="n">hModule</span><span class="p">,</span> <span class="n">LPCSTR</span> <span class="n">lpProcName</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">strcmp</span> <span class="p">(</span><span class="n">lpProcName</span><span class="p">,</span> <span class="s">"Init"</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
<span class="k">return</span> <span class="p">(</span><span class="n">FARPROC</span><span class="p">)</span><span class="n">MyCustomInitFunction</span><span class="p">;</span>
<span class="k">return</span> <span class="n">GetProcAddress</span> <span class="p">(</span><span class="n">hModule</span><span class="p">,</span> <span class="n">lpProcName</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">static</span> <span class="n">BOOL</span> <span class="nf">HackGetProcAddress</span> <span class="p">()</span>
<span class="p">{</span>
<span class="c1">// Get the handle to the module we want to divert </span>
<span class="n">HMODULE</span> <span class="n">module</span> <span class="o">=</span> <span class="n">GetModuleHandle</span> <span class="p">(</span><span class="s">L"TheDllToHijack.dll"</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">module</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>
<span class="k">return</span> <span class="n">FALSE</span><span class="p">;</span>
<span class="c1">// Get a reference to the import table to locate the kernel32 entry</span>
<span class="n">ULONG</span> <span class="n">size</span><span class="p">;</span>
<span class="n">PIMAGE_IMPORT_DESCRIPTOR</span> <span class="n">importDescriptor</span> <span class="o">=</span> <span class="p">(</span><span class="n">PIMAGE_IMPORT_DESCRIPTOR</span><span class="p">)</span><span class="n">ImageDirectoryEntryToDataEx</span> <span class="p">(</span><span class="n">module</span><span class="p">,</span> <span class="n">TRUE</span><span class="p">,</span> <span class="n">IMAGE_DIRECTORY_ENTRY_IMPORT</span><span class="p">,</span> <span class="o">&</span><span class="n">size</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
<span class="c1">// In the import table find the entry that corresponds to kernel32</span>
<span class="n">BOOL</span> <span class="n">found</span> <span class="o">=</span> <span class="n">FALSE</span><span class="p">;</span>
<span class="k">while</span> <span class="p">(</span><span class="n">importDescriptor</span><span class="o">-></span><span class="n">Characteristics</span> <span class="o">&&</span> <span class="n">importDescriptor</span><span class="o">-></span><span class="n">Name</span><span class="p">)</span> <span class="p">{</span>
<span class="n">PSTR</span> <span class="n">importName</span> <span class="o">=</span> <span class="p">(</span><span class="n">PSTR</span><span class="p">)((</span><span class="n">PBYTE</span><span class="p">)</span><span class="n">module</span> <span class="o">+</span> <span class="n">importDescriptor</span><span class="o">-></span><span class="n">Name</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">_stricmp</span> <span class="p">(</span><span class="n">importName</span><span class="p">,</span> <span class="s">"kernel32.dll"</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="n">found</span> <span class="o">=</span> <span class="n">TRUE</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">importDescriptor</span><span class="o">++</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">found</span><span class="p">)</span>
<span class="k">return</span> <span class="n">FALSE</span><span class="p">;</span>
<span class="c1">// We use this value as a comparison</span>
<span class="n">PROC</span> <span class="n">baseGetProcAddress</span> <span class="o">=</span> <span class="p">(</span><span class="n">PROC</span><span class="p">)</span><span class="n">GetProcAddress</span> <span class="p">(</span><span class="n">GetModuleHandle</span> <span class="p">(</span><span class="s">L"kernel32.dll"</span><span class="p">),</span> <span class="s">"GetProcAddress"</span><span class="p">);</span>
<span class="c1">// From the kernel32 import descriptor, go over its IAT thunks to</span>
<span class="c1">// find the one used by the rest of the code to call GetProcAddress</span>
<span class="n">PIMAGE_THUNK_DATA</span> <span class="n">thunk</span> <span class="o">=</span> <span class="p">(</span><span class="n">PIMAGE_THUNK_DATA</span><span class="p">)((</span><span class="n">PBYTE</span><span class="p">)</span><span class="n">module</span> <span class="o">+</span> <span class="n">importDescriptor</span><span class="o">-></span><span class="n">FirstThunk</span><span class="p">);</span>
<span class="k">while</span> <span class="p">(</span><span class="n">thunk</span><span class="o">-></span><span class="n">u1</span><span class="p">.</span><span class="n">Function</span><span class="p">)</span> <span class="p">{</span>
<span class="n">PROC</span><span class="o">*</span> <span class="n">funcStorage</span> <span class="o">=</span> <span class="p">(</span><span class="n">PROC</span><span class="o">*</span><span class="p">)</span><span class="o">&</span><span class="n">thunk</span><span class="o">-></span><span class="n">u1</span><span class="p">.</span><span class="n">Function</span><span class="p">;</span>
<span class="c1">// Found it, now let's patch it</span>
<span class="k">if</span> <span class="p">(</span><span class="o">*</span><span class="n">funcStorage</span> <span class="o">==</span> <span class="n">baseGetProcAddress</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Get the memory page where the info is stored</span>
<span class="n">MEMORY_BASIC_INFORMATION</span> <span class="n">mbi</span><span class="p">;</span>
<span class="n">VirtualQuery</span> <span class="p">(</span><span class="n">funcStorage</span><span class="p">,</span> <span class="o">&</span><span class="n">mbi</span><span class="p">,</span> <span class="k">sizeof</span> <span class="p">(</span><span class="n">MEMORY_BASIC_INFORMATION</span><span class="p">));</span>
<span class="c1">// Try to change the page to be writable if it's not already</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">VirtualProtect</span> <span class="p">(</span><span class="n">mbi</span><span class="p">.</span><span class="n">BaseAddress</span><span class="p">,</span> <span class="n">mbi</span><span class="p">.</span><span class="n">RegionSize</span><span class="p">,</span> <span class="n">PAGE_READWRITE</span><span class="p">,</span> <span class="o">&</span><span class="n">mbi</span><span class="p">.</span><span class="n">Protect</span><span class="p">))</span>
<span class="k">return</span> <span class="n">FALSE</span><span class="p">;</span>
<span class="c1">// Store our hook</span>
<span class="o">*</span><span class="n">funcStorage</span> <span class="o">=</span> <span class="p">(</span><span class="n">PROC</span><span class="p">)</span><span class="n">MyGetProcAddress</span><span class="p">;</span>
<span class="c1">// Restore the old flag on the page</span>
<span class="n">DWORD</span> <span class="n">dwOldProtect</span><span class="p">;</span>
<span class="n">VirtualProtect</span> <span class="p">(</span><span class="n">mbi</span><span class="p">.</span><span class="n">BaseAddress</span><span class="p">,</span> <span class="n">mbi</span><span class="p">.</span><span class="n">RegionSize</span><span class="p">,</span> <span class="n">mbi</span><span class="p">.</span><span class="n">Protect</span><span class="p">,</span> <span class="o">&</span><span class="n">dwOldProtect</span><span class="p">);</span>
<span class="c1">// Profit</span>
<span class="k">return</span> <span class="n">TRUE</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">thunk</span><span class="o">++</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">FALSE</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="conclusion">Conclusion</h2>
<p>This was an example of how you can use IAT patching to circumvent legacy code without having to recompile or otherwise damage the original binary.</p>
<p>This technique is well known so if you want to do something more complicated/reliable you can always use an existing library like <a href="https://easyhook.github.io/">EasyHook</a> or something as full-featured as Microsoft’s Detours.</p>
<p>References:</p>
<ul>
<li><a href="http://www.dematte.org/2006/03/04/InterceptingWindowsAPIs.aspx">Intercepting Windows APIs - Coding for fun</a></li>
<li><a href="https://www.codeproject.com/Articles/2082/API-hooking-revealed">API hooking revealed - CodeProject</a></li>
<li><a href="http://sandsprite.com/CodeStuff/Understanding_imports.html">Understanding the Import Address Table</a></li>
<li><a href="https://msdn.microsoft.com/en-us/library/ms809762.aspx">Peering inside the PE - Matt Pietrek</a></li>
</ul>Jérémie LavalRecently I was stuck with a blocking issue that was putting a feature I worked on in jeopardy. To summarize the problem, the entire feature relied on a specific way a library is initialized, the library in question providing two different functions (that we will call Init and InitExtended) to initialize itself.